gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[libmicrohttpd] branch master updated: expand tutorial on connection pha


From: gnunet
Subject: [libmicrohttpd] branch master updated: expand tutorial on connection phases, thanks to Igor for pointing out that the text was incomplete
Date: Tue, 02 Feb 2021 18:41:15 +0100

This is an automated email from the git hooks/post-receive script.

grothoff pushed a commit to branch master
in repository libmicrohttpd.

The following commit(s) were added to refs/heads/master by this push:
     new e0669386 expand tutorial on connection phases, thanks to Igor for 
pointing out that the text was incomplete
e0669386 is described below

commit e06693862812597b14b4eccd2c06f71dff6ca846
Author: Christian Grothoff <christian@grothoff.org>
AuthorDate: Tue Feb 2 18:40:10 2021 +0100

    expand tutorial on connection phases, thanks to Igor for pointing out that 
the text was incomplete
---
 doc/chapters/basicauthentication.inc | 132 ++++++++++++++++++++++-------------
 doc/libmicrohttpd-tutorial.texi      |   2 +-
 2 files changed, 83 insertions(+), 51 deletions(-)

diff --git a/doc/chapters/basicauthentication.inc 
b/doc/chapters/basicauthentication.inc
index ec606f3e..ca48403a 100644
--- a/doc/chapters/basicauthentication.inc
+++ b/doc/chapters/basicauthentication.inc
@@ -1,7 +1,7 @@
-With the small exception of IP address based access control, 
+With the small exception of IP address based access control,
 requests from all connecting clients where served equally until now.
 This chapter discusses a first method of client's authentication and
-its limits. 
+its limits.
 
 A very simple approach feasible with the means already discussed would
 be to expect the password in the @emph{URI} string before granting access to
@@ -12,68 +12,102 @@ GET /picture.png?mypassword
 @end verbatim
 @noindent
 
-In the rare situation where the client is customized enough and the connection 
occurs
-through secured lines (e.g., a embedded device directly attached to another 
via wire)
-and where the ability to embed a password in the URI or to pass on a URI with a
-password are desired, this can be a reasonable choice. 
+In the rare situation where the client is customized enough and the connection
+occurs through secured lines (e.g., a embedded device directly attached to
+another via wire) and where the ability to embed a password in the URI or to
+pass on a URI with a password are desired, this can be a reasonable choice.
 
-But when it is assumed that the user connecting does so with an ordinary 
Internet browser,
-this implementation brings some problems about. For example, the URI including 
the password
-stays in the address field or at least in the history of the browser for 
anybody near enough to see. 
-It will also be inconvenient to add the password manually to any new URI when 
the browser does
+But when it is assumed that the user connecting does so with an ordinary
+Internet browser, this implementation brings some problems about. For example,
+the URI including the password stays in the address field or at least in the
+history of the browser for anybody near enough to see.  It will also be
+inconvenient to add the password manually to any new URI when the browser does
 not know how to compose this automatically.
 
-At least the convenience issue can be addressed by employing the simplest 
built-in password
-facilities of HTTP compliant browsers, hence we want to start there. It will 
however turn out
-to have still severe weaknesses in terms of security which need consideration.
+At least the convenience issue can be addressed by employing the simplest
+built-in password facilities of HTTP compliant browsers, hence we want to
+start there. It will, however, turn out to have still severe weaknesses in
+terms of security which need consideration.
 
-Before we will start implementing @emph{Basic Authentication} as described in 
@emph{RFC 2617},
-we should finally abandon the bad practice of responding every request the 
first time our callback
-is called for a given connection. This is becoming more important now because 
the client and 
-the server will have to talk in a more bi-directional way than before to 
+Before we will start implementing @emph{Basic Authentication} as described in
+@emph{RFC 2617}, we will also abandon the simplistic and generally
+problematic practice of responding every request the first time our callback
+is called for a given connection. Queuing a response upon the first request
+is akin to generating an error response (even if it is a "200 OK" reply!).
+The reason is that MHD usually calls the callback in three phases:
 
-But how can we tell whether the callback has been called before for the 
particular connection?
-Initially, the pointer this parameter references is set by @emph{MHD} in the 
callback. But it will 
-also be "remembered" on the next call (for the same connection).
-Thus, we will generate no response until the parameter is non-null---implying 
the callback was
-called before at least once. We do not need to share information between 
different calls of the callback,
-so we can set the parameter to any address that is assured to be not null. The 
pointer to the 
-@code{connection} structure will be pointing to a legal address, so we take 
this.
+@enumerate
+@item
+First, to initially tell the application about the connection and inquire 
whether
+it is OK to proceed. This call typically happens before the client could upload
+the request body, and can be used to tell the client to not proceed with the
+upload (if the client requested "Expect: 100 Continue"). Applications may queue
+a reply at this point, but it will force the connection to be closed and thus
+prevent keep-alive / pipelining, which is generally a bad idea. Applications
+wanting to proceed with the request throughout the other phases should just 
return
+"MHD_YES" and not queue any response.  Note that when an application suspends
+a connection in this callback, the phase does not advance and the application
+will be called again in this first phase.
+@item
+Next, to tell the application about upload data provided by the client.
+In this phase, the application may not queue replies, and trying to do so
+will result in MHD returning an error code from @code{MHD_queue_response}.
+If there is no upload data, this phase is skipped.
+@item
+Finally, to obtain a regular response from the application. This can be
+almost any type of response, including ones indicating failures. The
+one exception is a "100 Continue" response, which applications must never
+generate: MHD generates that response automatically when necessary in the
+first phase.  If the application does not queue a response, MHD may call
+the callback repeatedly (depending a bit on the threading model, the
+application should suspend the connection).
+@end enumerate
+
+But how can we tell whether the callback has been called before for the
+particular connection?  Initially, the pointer this parameter references is
+set by @emph{MHD} in the callback. But it will also be "remembered" on the
+next call (for the same connection).  Thus, we can use the @code{con_cls}
+location to keep track of the connection state.  For now, we will simply
+generate no response until the parameter is non-null---implying the callback
+was called before at least once. We do not need to share information between
+different calls of the callback, so we can set the parameter to any address
+that is assured to be not null. The pointer to the @code{connection} structure
+will be pointing to a legal address, so we take this.
 
 The first time @code{answer_to_connection} is called, we will not even look at 
the headers.
 
 @verbatim
-static int 
+static int
 answer_to_connection (void *cls, struct MHD_Connection *connection,
-                      const char *url, const char *method, const char 
*version, 
+                      const char *url, const char *method, const char *version,
                       const char *upload_data, size_t *upload_data_size,
                       void **con_cls)
 {
   if (0 != strcmp(method, "GET")) return MHD_NO;
   if (NULL == *con_cls) {*con_cls = connection; return MHD_YES;}
 
-  ... 
+  ...
   /* else respond accordingly */
   ...
 }
 @end verbatim
 @noindent
 
-Note how we lop off the connection on the first condition (no "GET" request), 
but return asking for more on 
-the other one with @code{MHD_YES}.
-With this minor change, we can proceed to implement the actual authentication 
process.
-
-@heading Request for authentication 
-
-Let us assume we had only files not intended to be handed out without the 
correct username/password,
-so every "GET" request will be challenged.
-@emph{RFC 2617} describes how the server shall ask for authentication by 
adding a
-@emph{WWW-Authenticate} response header with the name of the @emph{realm} 
protected.
-MHD can generate and queue such a failure response for you using
-the @code{MHD_queue_basic_auth_fail_response} API.  The only thing you need to 
do
-is construct a response with the error page to be shown to the user
-if he aborts basic authentication.  But first, you should check if the
-proper credentials were already supplied using the
+Note how we lop off the connection on the first condition (no "GET" request),
+but return asking for more on the other one with @code{MHD_YES}.  With this
+minor change, we can proceed to implement the actual authentication process.
+
+@heading Request for authentication
+
+Let us assume we had only files not intended to be handed out without the
+correct username/password, so every "GET" request will be challenged.
+@emph{RFC 2617} describes how the server shall ask for authentication by
+adding a @emph{WWW-Authenticate} response header with the name of the
+@emph{realm} protected.  MHD can generate and queue such a failure response
+for you using the @code{MHD_queue_basic_auth_fail_response} API.  The only
+thing you need to do is construct a response with the error page to be shown
+to the user if he aborts basic authentication.  But first, you should check if
+the proper credentials were already supplied using the
 @code{MHD_basic_auth_get_username_password} call.
 
 Your code would then look like this:
@@ -101,14 +135,14 @@ answer_to_connection (void *cls, struct MHD_Connection 
*connection,
   user = MHD_basic_auth_get_username_password (connection, &pass);
   fail = ( (user == NULL) ||
           (0 != strcmp (user, "root")) ||
-          (0 != strcmp (pass, "pa$$w0rd") ) );  
+          (0 != strcmp (pass, "pa$$w0rd") ) );
   if (user != NULL) free (user);
   if (pass != NULL) free (pass);
   if (fail)
     {
       const char *page = "<html><body>Go away.</body></html>";
       response =
-       MHD_create_response_from_buffer (strlen (page), (void *) page, 
+       MHD_create_response_from_buffer (strlen (page), (void *) page,
                                       MHD_RESPMEM_PERSISTENT);
       ret = MHD_queue_basic_auth_fail_response (connection,
                                                "my realm",
@@ -118,7 +152,7 @@ answer_to_connection (void *cls, struct MHD_Connection 
*connection,
     {
       const char *page = "<html><body>A secret.</body></html>";
       response =
-       MHD_create_response_from_buffer (strlen (page), (void *) page, 
+       MHD_create_response_from_buffer (strlen (page), (void *) page,
                                       MHD_RESPMEM_PERSISTENT);
       ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
     }
@@ -130,9 +164,9 @@ answer_to_connection (void *cls, struct MHD_Connection 
*connection,
 See the @code{examples} directory for the complete example file.
 
 @heading Remarks
-For a proper server, the conditional statements leading to a return of 
@code{MHD_NO} should yield a 
+For a proper server, the conditional statements leading to a return of 
@code{MHD_NO} should yield a
 response with a more precise status code instead of silently closing the 
connection. For example,
-failures of memory allocation are best reported as @emph{internal server 
error} and unexpected 
+failures of memory allocation are best reported as @emph{internal server 
error} and unexpected
 authentication methods as @emph{400 bad request}.
 
 @heading Exercises
@@ -142,7 +176,7 @@ Make the server respond to wrong credentials (but otherwise 
well-formed requests
 @emph{401 unauthorized} status code. If the client still does not authenticate 
correctly within the
 same connection, close it and store the client's IP address for a certain 
time. (It is OK to check for
 expiration not until the main thread wakes up again on the next connection.) 
If the client fails
-authenticating three times during this period, add it to another list for 
which the 
+authenticating three times during this period, add it to another list for 
which the
 @code{AcceptPolicyCallback} function denies connection (temporally).
 
 @item
@@ -156,5 +190,3 @@ Copy and paste the encoded string you see in 
@code{netcat}'s output to some of t
 and see how both the user's name and password could be completely restored.
 
 @end itemize
-
-
diff --git a/doc/libmicrohttpd-tutorial.texi b/doc/libmicrohttpd-tutorial.texi
index 8fd7b566..de040fe8 100644
--- a/doc/libmicrohttpd-tutorial.texi
+++ b/doc/libmicrohttpd-tutorial.texi
@@ -24,7 +24,7 @@ updated @value{UPDATED}.
 
 Copyright (c)  2008  Sebastian Gerhardt.
 
-Copyright (c)  2010, 2011, 2012, 2013, 2016  Christian Grothoff.
+Copyright (c)  2010, 2011, 2012, 2013, 2016, 2021  Christian Grothoff.
 @quotation
 Permission is granted to copy, distribute and/or modify this document
 under the terms of the GNU Free Documentation License, Version 1.3

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]