gnunet-svn
[Top][All Lists]
Advanced

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

[GNUnet-SVN] r7545 - in libmicrohttpd: . doc doc/examples


From: gnunet
Subject: [GNUnet-SVN] r7545 - in libmicrohttpd: . doc doc/examples
Date: Tue, 12 Aug 2008 13:49:42 -0600 (MDT)

Author: grothoff
Date: 2008-08-12 13:49:42 -0600 (Tue, 12 Aug 2008)
New Revision: 7545

Added:
   libmicrohttpd/doc/basicauthentication.inc
   libmicrohttpd/doc/bibliography.inc
   libmicrohttpd/doc/examples/
   libmicrohttpd/doc/examples/basicauthentication.c
   libmicrohttpd/doc/examples/hellobrowser.c
   libmicrohttpd/doc/examples/logging.c
   libmicrohttpd/doc/examples/responseheaders.c
   libmicrohttpd/doc/examples/simplepost.c
   libmicrohttpd/doc/exploringrequests.inc
   libmicrohttpd/doc/hellobrowser.inc
   libmicrohttpd/doc/introduction.inc
   libmicrohttpd/doc/processingpost.inc
   libmicrohttpd/doc/responseheaders.inc
   libmicrohttpd/doc/tutorial.texi
Modified:
   libmicrohttpd/AUTHORS
Log:
tutorial

Modified: libmicrohttpd/AUTHORS
===================================================================
--- libmicrohttpd/AUTHORS       2008-08-12 19:37:49 UTC (rev 7544)
+++ libmicrohttpd/AUTHORS       2008-08-12 19:49:42 UTC (rev 7545)
@@ -13,3 +13,4 @@
 
 Documentation contributions also came from:
 Marco Maggi <address@hidden>
+Sebastian Gerhardt <address@hidden>

Added: libmicrohttpd/doc/basicauthentication.inc
===================================================================
--- libmicrohttpd/doc/basicauthentication.inc                           (rev 0)
+++ libmicrohttpd/doc/basicauthentication.inc   2008-08-12 19:49:42 UTC (rev 
7545)
@@ -0,0 +1,208 @@
+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. 
+
+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
+the secured areas. The password could be separated from the actual resource 
identifier
+by a certain character, thus the request line might look like
address@hidden
+GET /picture.png?mypassword
address@hidden verbatim
address@hidden
+
+In a 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),
+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
+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.
+
+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 
+
+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 adress that is assured to be not null. The 
pointer to the 
address@hidden structure will be pointing to a legal adress, so we take this.
+
+Not even the headers will be looked at on the first iteration.
+
address@hidden
+int AnswerToConnection(void *cls, struct MHD_Connection *connection, 
+    const char *url, const char *method, const char *version, 
+    const char *upload_data, unsigned int *upload_data_size, void **con_cls)
+{
+  if (0 != strcmp(method, "GET")) return MHD_NO;
+  if(*con_cls==NULL) {*con_cls=connection; return MHD_YES;}
+
+  ... 
+  /* else respond accordingly */
+  ...
+}
address@hidden verbatim
address@hidden
+
+Note how we lop off the connection on the first condition, but return asking 
for more on 
+the other one with @code{MHD_YES}.
+With the framework improved, we can proceed to implement the actual 
authentication process.
+
address@hidden 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.
address@hidden 2617} describes how the server shall ask for authentication by 
adding a
address@hidden response header with the name of the @emph{realm} protected.
+
+We let an extra function function do this.
address@hidden
+int AskForAuthentication(struct MHD_Connection *connection, const char *realm)
+{
+  int ret;
+  struct MHD_Response *response;
+  char *headervalue;
+  const char *strbase = "Basic realm=";
+  
+  response = MHD_create_response_from_data(0, NULL, MHD_NO, MHD_NO);
+  if (!response) return MHD_NO;
+  
+  headervalue = malloc( strlen(strbase) + strlen(realm) + 1);
+  if (!headervalue) return MHD_NO;  
+
+  strcpy(headervalue, strbase);
+  strcat(headervalue, realm);
+  
+  ret = MHD_add_response_header(response, "WWW-Authenticate", headervalue);
+  free(headervalue);  
+  if (!ret) {MHD_destroy_response (response); return MHD_NO;}
+
+  ret = MHD_queue_response (connection, MHD_HTTP_UNAUTHORIZED, response);
+  
+  MHD_destroy_response (response);
+
+  return ret;
+}
address@hidden verbatim
address@hidden
+
address@hidden the realm name according to your own taste, e.g. "Maintenance" 
or "Area51" but
+it will need to have extra quotes.
+
+But the client may send the authentication right away, so it would be wrong to 
ask for
+it without checking the request's header--where the authentication is expected 
to be found.
+
address@hidden Authentication in detail
+Checking @emph{RFC 2617} again, we find that the client will pack the username 
and password, by
+whatever means he might have obtained them, in a line separated by a 
colon---and then encodes
+them to @emph{Base64}. The actual implementation of this encoding are not 
within the scope of
+this tutorial although a working function is included in the complete source 
file of the example.
+
+An unencoded word describing the authentication method (here "Basic") will 
precede the code
+and the resulting line is the value of a request header of the type 
"Authorization".  
+
+This header line thus is of interest to the function checking a connection for 
a given username/password:
address@hidden
+int IsAuthenticated(struct MHD_Connection *connection, 
+                    const char *username, const char *password)
+{
+  const char *headervalue;
+  ...
+
+  headervalue = MHD_lookup_connection_value (connection, 
+                                             MHD_HEADER_KIND, "Authorization");
+
+  if(headervalue == NULL) return 0;
address@hidden verbatim
address@hidden
+
+where, firstly, the authentication method will be checked.
address@hidden
+const char *strbase = "Basic ";
+...
+if (strncmp(headervalue, strbase, strlen(strbase))!=0) return 0;
address@hidden verbatim
address@hidden
+
+Of course, we could decode the passed credentials in the next step and compare 
them directly to
+the given strings. But as this would involve string parsing, which is more 
complicated then string
+composing, it is done the other way around---the clear text credentials will 
be encoded to @emph{Base64}
+and then compared against the headerline. The authentication method string 
will be left out here as
+it has been checked already at this point.
address@hidden
+  char *expected_b64, *expected;
+  int authenticated;
+
+  ...
+  strcpy(expected, username);
+  strcat(expected, ":");
+  strcat(expected, password);  
+
+  expected_b64 = StringToBase64(expected);
+  if(expected_b64 == NULL) return 0;
+ 
+  strcpy(expected, strbase);
+
+  authenticated = (strcmp(headervalue+strlen(strbase), expected_b64) == 0);
+
+  free(expected_b64);
+
+  return authenticated;
+}
address@hidden verbatim
address@hidden
+
+These two functions---together with a response function in case of positive 
authentication doing little 
+new---allow the rest of the callback function to be rather short. 
address@hidden
+  if (!IsAuthenticated(connection, USER, PASSWORD)) 
+    return AskForAuthentication(connection, REALM); 
+  
+  return SecretPage(connection);
+}
address@hidden verbatim
address@hidden
+
+See the @code{examples} directory for the complete example file.
+
address@hidden Remarks
+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 
+authentication methods as @emph{400 bad request}.
+
address@hidden Exercises
address@hidden @bullet
address@hidden
+Make the server respond to wrong credentials (but else correct requests) with 
the recommended
address@hidden 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 whose 
entries the 
address@hidden function denies connection (temporally).
+
address@hidden
+With the network utility @emph{netcat} connect and log the response of a "GET" 
request as you
+did in the exercise of the first example, this time to a file. Now stop the 
server and let @emph{netcat}
+listen on the same port the server used to listen on and have it fake being 
the proper server by giving
+the file's content as the response (e.g. @code{cat log | nc -l -p 8888}). 
Pretending to think your were
+connecting to the actual server, browse to the eavesdropper and give the 
correct credentials.
+
+Copy and paste the encoded string you see in netcat's output to some of the 
Base64 decode tools available online
+and see how both the user's name and password could be completely restored.
+
address@hidden itemize
+
+

Added: libmicrohttpd/doc/bibliography.inc
===================================================================
--- libmicrohttpd/doc/bibliography.inc                          (rev 0)
+++ libmicrohttpd/doc/bibliography.inc  2008-08-12 19:49:42 UTC (rev 7545)
@@ -0,0 +1,30 @@
address@hidden @bullet
address@hidden API reference
address@hidden
+The @emph{GNU libmicrohttpd} manual by Christian Grothoff 2008 
address@hidden://gnunet.org/libmicrohttpd/microhttpd.html}
+
address@hidden Requests for comments 
+All referenced RFCs can be found on the website of @emph{The Internet 
Engineering Task Force}
address@hidden://www.ietf.org/}
+
address@hidden
address@hidden 2616}: Fielding, R., Gettys, J., Mogul, J., Frystyk, H., and T. 
Berners-Lee,
+"Hypertext Transfer Protocol -- HTTP/1.1", RFC 2016, January 1997.
+
address@hidden
address@hidden 2617}: Franks, J., Hallam-Baker, P., Hostetler, J., Lawrence, 
S., Leach, P.,
+Luotonen, A., and L. Stewart, "HTTP Authentication: Basic and Digest Access 
Authentication", RFC 2617, June 1999.
+
+
address@hidden Recommended readings
address@hidden 
+A well--structured @emph{HTML} reference can be found on
address@hidden://www.echoecho.com/html.htm}
+
+For those readers understanding German or French, there is an excellent 
document both for learning
address@hidden and for reference, whose English version unfortunately has been 
discontinued.
address@hidden://de.selfhtml.org/} and @uref{http://fr.selfhtml.org/}
+
+
address@hidden itemize

Added: libmicrohttpd/doc/examples/basicauthentication.c
===================================================================
--- libmicrohttpd/doc/examples/basicauthentication.c                            
(rev 0)
+++ libmicrohttpd/doc/examples/basicauthentication.c    2008-08-12 19:49:42 UTC 
(rev 7545)
@@ -0,0 +1,152 @@
+#include <microhttpd.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+
+#define PORT 8888
+
+#define REALM     "\"Maintenance\""
+#define USER      "a legitimate user"
+#define PASSWORD  "and his password"
+
+
+char* StringToBase64(const char *message);
+
+
+int AskForAuthentication(struct MHD_Connection *connection, const char *realm)
+{
+  int ret;
+  struct MHD_Response *response;
+  char *headervalue;
+  const char *strbase = "Basic realm=";
+  
+  response = MHD_create_response_from_data(0, NULL, MHD_NO, MHD_NO);
+  if (!response) return MHD_NO;
+  
+  headervalue = malloc( strlen(strbase) + strlen(realm) + 1);
+  if (!headervalue) return MHD_NO;  
+
+  strcpy(headervalue, strbase);
+  strcat(headervalue, realm);
+  
+  ret = MHD_add_response_header(response, "WWW-Authenticate", headervalue);
+  free(headervalue);  
+  if (!ret) {MHD_destroy_response (response); return MHD_NO;}
+
+  ret = MHD_queue_response (connection, MHD_HTTP_UNAUTHORIZED, response);
+  
+  MHD_destroy_response (response);
+
+  return ret;
+}
+
+int IsAuthenticated(struct MHD_Connection *connection, const char *username, 
+                    const char *password)
+{
+  const char *headervalue;
+  char *expected_b64, *expected;
+  const char *strbase = "Basic ";  
+  int authenticated;
+
+  headervalue = MHD_lookup_connection_value (connection, MHD_HEADER_KIND, 
"Authorization");
+  if(headervalue == NULL) return 0;
+  if (strncmp(headervalue, strbase, strlen(strbase))!=0) return 0;
+
+  expected = malloc(strlen(username) + 1 + strlen(password) + 1);
+  if(expected == NULL) return 0;
+
+  strcpy(expected, username);
+  strcat(expected, ":");
+  strcat(expected, password);  
+
+  expected_b64 = StringToBase64(expected);
+  if(expected_b64 == NULL) return 0;
+ 
+  strcpy(expected, strbase);
+
+  authenticated = (strcmp(headervalue+strlen(strbase), expected_b64) == 0);
+
+  free(expected_b64);
+
+  return authenticated;
+}
+
+
+int SecretPage(struct MHD_Connection *connection)
+{
+  int ret;
+  struct MHD_Response *response;
+  const char *page = "<html><body>A secret.</body></html>";
+  
+  response = MHD_create_response_from_data(strlen(page), (void*)page, MHD_NO, 
MHD_NO);
+  if (!response) return MHD_NO;
+ 
+  ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
+  
+  MHD_destroy_response (response);
+
+  return ret;
+}
+
+
+int AnswerToConnection(void *cls, struct MHD_Connection *connection,
+    const char *url, const char *method, const char *version, 
+    const char *upload_data, unsigned int *upload_data_size, void **con_cls)
+{
+  if (0 != strcmp(method, "GET")) return MHD_NO;
+  if(*con_cls==NULL) {*con_cls=connection; return MHD_YES;}
+
+  if (!IsAuthenticated(connection, USER, PASSWORD)) 
+    return AskForAuthentication(connection, REALM); 
+  
+  return SecretPage(connection);
+}
+
+
+int main ()
+{
+  struct MHD_Daemon *daemon;
+
+  daemon = MHD_start_daemon(MHD_USE_SELECT_INTERNALLY, PORT, NULL, NULL,
+                            &AnswerToConnection, NULL, MHD_OPTION_END);
+
+  if (daemon == NULL) return 1;
+
+  getchar(); 
+
+  MHD_stop_daemon(daemon);
+  return 0;
+}
+
+
+char* StringToBase64(const char *message)
+{
+  const char *lookup = 
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+  unsigned long l;
+  int i;
+  char *tmp;
+  size_t length = strlen(message);
+  
+  tmp = malloc(length*2);
+  if (tmp==NULL) return tmp;
+  tmp[0]=0;
+
+  for(i=0; i<length; i+=3) 
+  {
+    l = ( ((unsigned long)message[i])<<16 ) |
+                 (((i+1) < length) ? (((unsigned long)message[i+1])<<8 ) : 0 ) 
|
+                 (((i+2) < length) ? ( (unsigned long)message[i+2] ) : 0 );
+
+
+    strncat(tmp, &lookup[(l>>18) & 0x3F], 1);
+    strncat(tmp, &lookup[(l>>12) & 0x3F], 1);
+ 
+    if (i+1 < length) strncat(tmp, &lookup[(l>> 6) & 0x3F], 1);
+    if (i+2 < length) strncat(tmp, &lookup[(l ) & 0x3F], 1);
+  }
+
+  if (length%3) strncat(tmp, "===", 3-length%3) ;
+  
+  return tmp;
+}

Added: libmicrohttpd/doc/examples/hellobrowser.c
===================================================================
--- libmicrohttpd/doc/examples/hellobrowser.c                           (rev 0)
+++ libmicrohttpd/doc/examples/hellobrowser.c   2008-08-12 19:49:42 UTC (rev 
7545)
@@ -0,0 +1,34 @@
+#include <microhttpd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#define PORT 8888
+
+int AnswerToConnection(void *cls, struct MHD_Connection *connection, const 
char *url, 
+    const char *method, const char *version, const char *upload_data, 
+    unsigned int *upload_data_size, void **con_cls)
+{
+  const char *page  = "<html><body>Hello, browser!</body></html>";
+  struct MHD_Response *response;
+  int ret;
+
+  response = MHD_create_response_from_data (strlen (page), (void*) page, 
MHD_NO, MHD_NO);
+  ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
+  MHD_destroy_response (response);
+  return ret;
+}
+
+int main ()
+{
+  struct MHD_Daemon *daemon;
+
+  daemon = MHD_start_daemon(MHD_USE_SELECT_INTERNALLY, PORT, NULL, NULL, 
+                            &AnswerToConnection, NULL, MHD_OPTION_END);
+  if (daemon == NULL) return 1;
+
+  getchar(); 
+
+  MHD_stop_daemon(daemon);
+  return 0;
+}

Added: libmicrohttpd/doc/examples/logging.c
===================================================================
--- libmicrohttpd/doc/examples/logging.c                                (rev 0)
+++ libmicrohttpd/doc/examples/logging.c        2008-08-12 19:49:42 UTC (rev 
7545)
@@ -0,0 +1,39 @@
+#include <microhttpd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#define PORT 8888
+
+
+int PrintOutKey(void *cls, enum MHD_ValueKind kind, const char *key, const 
char *value)
+{
+  printf("%s = %s\n", key, value);
+  return MHD_YES;
+}
+
+int AnswerToConnection(void *cls, struct MHD_Connection *connection, const 
char *url, 
+    const char *method, const char *version, const char *upload_data, 
+    unsigned int *upload_data_size, void **con_cls)
+{
+  
+  printf("New request %s for %s using version %s\n", method, url, version);
+
+  MHD_get_connection_values(connection, MHD_HEADER_KIND, PrintOutKey, NULL);
+
+  return MHD_NO;
+}
+
+int main ()
+{
+  struct MHD_Daemon *daemon;
+
+  daemon = MHD_start_daemon(MHD_USE_SELECT_INTERNALLY, PORT, NULL, NULL,
+                            &AnswerToConnection, NULL, MHD_OPTION_END);
+  if (daemon == NULL) return 1;
+
+  getchar(); 
+
+  MHD_stop_daemon(daemon);
+  return 0;
+}

Added: libmicrohttpd/doc/examples/responseheaders.c
===================================================================
--- libmicrohttpd/doc/examples/responseheaders.c                                
(rev 0)
+++ libmicrohttpd/doc/examples/responseheaders.c        2008-08-12 19:49:42 UTC 
(rev 7545)
@@ -0,0 +1,94 @@
+#include <microhttpd.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+
+#define PORT 8888
+#define FILENAME "picture.png"
+#define MIMETYPE "image/png"
+
+
+long GetFileSize(const char *filename)
+{
+  FILE *fp;
+  
+  fp = fopen(filename, "rb");
+  if (fp) 
+  {
+    long size;
+
+    if ( (0!=fseek(fp, 0, SEEK_END)) || (-1==(size=ftell(fp))) )
+      size = 0;
+   
+    fclose(fp);
+    return size;
+  } else return 0;
+}
+
+
+int AnswerToConnection(void *cls, struct MHD_Connection *connection, const 
char *url, 
+    const char *method, const char *version, const char *upload_data, 
+    unsigned int *upload_data_size, void **con_cls)
+{
+  unsigned char *buffer;
+  struct MHD_Response *response;
+  long size;
+  FILE *fp;
+  int ret=0;
+
+  if (0 != strcmp(method, "GET")) return MHD_NO;
+
+  size = GetFileSize(FILENAME);
+  if (size != 0)
+  {
+    fp = fopen(FILENAME, "rb");
+    if (fp) 
+    {
+      buffer = malloc(size);
+      if (buffer)
+        if (size == fread(buffer, 1, size, fp)) ret=1;
+    }  
+      
+    fclose(fp);
+  }
+
+  if (!ret) 
+  {
+    const char *errorstr = "<html><body>An internal server error has occured!\
+                            </body></html>";
+
+    if (buffer) free(buffer);
+    response = MHD_create_response_from_data(strlen(errorstr), (void*)errorstr,
+                                             MHD_NO, MHD_NO);
+
+    ret = MHD_queue_response (connection, MHD_HTTP_INTERNAL_SERVER_ERROR, 
response);
+    MHD_destroy_response (response);
+    return MHD_YES;    
+  }
+
+  response = MHD_create_response_from_data(size, (void*)buffer, MHD_YES, 
MHD_NO);
+
+  MHD_add_response_header(response, "Content-Type", MIMETYPE);
+
+  ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
+  MHD_destroy_response (response);
+  return ret;
+}
+
+
+int main ()
+{
+  struct MHD_Daemon *daemon;
+
+  daemon = MHD_start_daemon(MHD_USE_SELECT_INTERNALLY, PORT, NULL, NULL, 
+                            &AnswerToConnection, NULL, MHD_OPTION_END);
+
+  if (daemon == NULL) return 1;
+
+  getchar(); 
+
+  MHD_stop_daemon(daemon);
+  return 0;
+}
+

Added: libmicrohttpd/doc/examples/simplepost.c
===================================================================
--- libmicrohttpd/doc/examples/simplepost.c                             (rev 0)
+++ libmicrohttpd/doc/examples/simplepost.c     2008-08-12 19:49:42 UTC (rev 
7545)
@@ -0,0 +1,157 @@
+#include <microhttpd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#define PORT            8888
+#define POSTBUFFERSIZE  512
+#define MAXNAMESIZE     20
+#define MAXANSWERSIZE   512
+
+#define GET             0
+#define POST            1
+
+struct ConnectionInfoStruct
+{
+  int connectiontype;
+  char *answerstring;
+  struct MHD_PostProcessor *postprocessor; 
+};
+
+const char* askpage="<html><body>\
+                     What's your name, Sir?<br>\
+                     <form action=\"/namepost\" method=\"post\">\
+                     <input name=\"name\" type=\"text\"\
+                     <input type=\"submit\" value=\" Send \"></form>\
+                     </body></html>";
+
+const char* greatingpage="<html><body><h1>Welcome, 
%s!</center></h1></body></html>";
+
+const char* errorpage="<html><body>This doesn't seem to be 
right.</body></html>";
+
+
+int SendPage(struct MHD_Connection *connection, const char* page)
+{
+  int ret;
+  struct MHD_Response *response;
+  
+
+  response = MHD_create_response_from_data(strlen(page), (void*)page, MHD_NO, 
MHD_NO);
+  if (!response) return MHD_NO;
+ 
+  ret = MHD_queue_response(connection, MHD_HTTP_OK, response);
+  
+  MHD_destroy_response(response);
+
+  return ret;
+}
+
+
+int IteratePost(void *coninfo_cls, enum MHD_ValueKind kind, const char *key,
+                const char *filename, const char *content_type,
+                const char *transfer_encoding, const char *data, size_t off, 
size_t size)
+{
+  struct ConnectionInfoStruct *con_info = (struct 
ConnectionInfoStruct*)(coninfo_cls);
+  
+
+  if (0 == strcmp(key, "name"))
+  {
+    if ((size>0) && (size<=MAXNAMESIZE))
+    {
+      char *answerstring;
+      answerstring = malloc(MAXANSWERSIZE);
+      if (!answerstring) return MHD_NO;
+      
+      snprintf(answerstring, MAXANSWERSIZE, greatingpage, data);
+      con_info->answerstring = answerstring;      
+    } else con_info->answerstring=NULL;
+
+    return MHD_NO;
+  }
+
+  return MHD_YES;
+}
+
+void RequestCompleted(void *cls, struct MHD_Connection *connection, void 
**con_cls,
+                      enum MHD_RequestTerminationCode toe)
+{
+  struct ConnectionInfoStruct *con_info = (struct 
ConnectionInfoStruct*)(*con_cls);
+
+
+  if (NULL == con_info) return;
+
+  if (con_info->connectiontype == POST)
+  {
+    MHD_destroy_post_processor(con_info->postprocessor);        
+    if (con_info->answerstring) free(con_info->answerstring);
+  }
+  
+  free(con_info);      
+}
+
+
+int AnswerToConnection(void *cls, struct MHD_Connection *connection, const 
char *url, 
+    const char *method, const char *version, const char *upload_data, 
+    unsigned int *upload_data_size, void **con_cls)
+{
+  if(*con_cls==NULL) 
+  {
+    struct ConnectionInfoStruct *con_info;
+
+    con_info = malloc(sizeof(struct ConnectionInfoStruct));
+    if (NULL == con_info) return MHD_NO;
+
+    if (0 == strcmp(method, "POST")) 
+    {      
+      con_info->postprocessor = MHD_create_post_processor(connection, 
POSTBUFFERSIZE, 
+                                                          IteratePost, 
(void*)con_info);   
+
+      if (NULL == con_info->postprocessor) 
+      {
+        free(con_info); 
+        return MHD_NO;
+      }
+
+      con_info->connectiontype = POST;
+    } else con_info->connectiontype = GET;
+
+    *con_cls = (void*)con_info;
+    return MHD_YES;
+  }
+
+  if (0 == strcmp(method, "GET")) 
+  {
+    return SendPage(connection, askpage);     
+  } 
+    
+  if (0 == strcmp(method, "POST")) 
+  {
+    struct ConnectionInfoStruct *con_info = *con_cls;
+
+    if (*upload_data_size != 0) 
+    {
+      MHD_post_process(con_info->postprocessor, upload_data, 
*upload_data_size);
+      *upload_data_size = 0;
+      return MHD_YES;
+    } else return SendPage(connection, con_info->answerstring);
+  } 
+
+  return SendPage(connection, errorpage); 
+}
+
+int main ()
+{
+  struct MHD_Daemon *daemon;
+
+
+  daemon = MHD_start_daemon(MHD_USE_SELECT_INTERNALLY, PORT, NULL, NULL,
+                            &AnswerToConnection, NULL, 
MHD_OPTION_NOTIFY_COMPLETED,
+                            RequestCompleted, NULL, MHD_OPTION_END);
+
+  if (NULL == daemon) return 1;
+
+  getchar(); 
+
+  MHD_stop_daemon(daemon);
+  return 0;
+}

Added: libmicrohttpd/doc/exploringrequests.inc
===================================================================
--- libmicrohttpd/doc/exploringrequests.inc                             (rev 0)
+++ libmicrohttpd/doc/exploringrequests.inc     2008-08-12 19:49:42 UTC (rev 
7545)
@@ -0,0 +1,104 @@
+This chapter will deal with the information which the client sends to the
+server at every request. We are going to examine the most useful fields of 
such an request
+and print them out in a readable manner. This could be useful for logging 
facilities.
+
+The starting point is the @emph{hellobrowser} program with the former response 
removed.
+
+This time, we just want to collect information in the callback function, thus 
we will
+just return MHD_NO after we have probed the request. This way, the connection 
is closed
+without much ado by the server.
+
address@hidden
+int AnswerToConnection(void *cls, struct MHD_Connection *connection,
+    const char *url, const char *method, const char *version,
+    const char *upload_data, unsigned int *upload_data_size, void **con_cls)
+{
+  ...  
+  return MHD_NO;
+}
address@hidden verbatim
address@hidden
+The ellipsis marks the position where the following instructions shall be 
inserted.
+
+
+We begin with the most obvious information available to the server, the 
request line. You should
+already have noted that a request consists of a command (or "method") and a 
URI (e.g. a filename).
+It also contains a string for the version of the protocol which can be found 
in @code{version}.
+To call it a "new request" is justified because we return only @code{MHD_NO}, 
thus ensuring the 
+function will not be called again for this connection. 
address@hidden
+printf("New request %s for %s using version %s\n", method, url, version);
address@hidden verbatim
address@hidden
+
+The rest of the information is a bit more hidden. Nevertheless, there is lot 
of it sent from common
+Internet browsers. It is stored in "key-name" pairs and we want to list what 
we find in the header. 
+As there is no mandatory set of keys a client has to send, each key--name pair 
is printed out one by
+one until there are no more left. We do this by writing a separate function 
which will be called for
+each pair just like the above function is called for each HTTP request. 
+It can then print out the content of this pair.
address@hidden
+int PrintOutKey(void *cls, enum MHD_ValueKind kind, const char *key, 
+    const char *value)
+{
+  printf("%s = %s\n", key, value);
+  return MHD_YES;
+}
address@hidden verbatim
address@hidden
+
+To start the iteration process that calls our new function for every key, the 
line
address@hidden
+MHD_get_connection_values(connection, MHD_HEADER_KIND, PrintOutKey, NULL);
address@hidden verbatim
address@hidden
+needs to be inserted in the connection callback function too. The second 
parameter tells the function 
+that we are only interested in keys from the general HTTP header of the 
request. Our iterating
+function @code{PrintOutKey} does not rely on any additional information to 
fulfill its duties
+so the last parameter can be NULL.
+
+All in all, this constitutes the complete @code{logger.c} program for this 
chapter which can be 
+found in the @code{examples} section.
+
+Connecting with any modern Internet browser should yield a handful of keys. 
You should try to 
+interpret them with the aid of @emph{RFC 2616}.
+Especially worth mentioning is the host key which is often used to serve 
several different websites
+hosted under one single IP address but reachable by different domain names.
+
address@hidden Conclusion
+The introduced capabilities to itemize the content of a simple GET 
request---especially the
+URI---should already allow the server to satisfy clients' requests for small 
specific resources
+(e.g. files) or even induce alteration of how the server operates. However, 
the latter is not
+recommended as the GET method (including its header data) is by convention 
considered a "SAFE"
+operation, which should not change the server's state in a significant way, 
but temporally actions
+like searching for a passed string is fine.
+
+Of course, no transmission can occur while the return value is still set to 
@code{MHD_NO} in the
+callback function.
+
address@hidden Exercises
address@hidden @bullet
address@hidden
+By parsing the @code{url} string and delivering responses accordingly, 
implement a small server for
+"virtual" files. When asked for @code{/address@hidden@}}, let the response 
consist of a HTML page
+containing a link to @code{/another.html} page which is also to be created "on 
the fly" in case of
+being requested. If neither of these two pages are requested, 
@code{MHD_HTTP_NOT_FOUND} shall be
+returned accompanied by an informative message.
+
address@hidden
+A very interesting information has still been ignored by our logger---the 
client's IP address. 
+Implement a callback function 
address@hidden
+int OnClientConnect(void *cls,
+                    const struct sockaddr *addr,socklen_t addrlen)
address@hidden verbatim
address@hidden
+that prints out the IP address in an appropriate format. You might want to use 
the posix function
address@hidden but bear in mind that @code{addr} is actually just a structure 
containing other
+substructures and is @emph{not} the variable this function expects. 
+Make sure to return @code{MHD_YES} so that the library knows the client is 
allowed to connect
+(and to request). If one wanted to limit access basing on IP addresses, this 
would be the place
+to do it. The address of your function will then be passed as the third 
parameter of the
address@hidden call.
+
address@hidden itemize

Added: libmicrohttpd/doc/hellobrowser.inc
===================================================================
--- libmicrohttpd/doc/hellobrowser.inc                          (rev 0)
+++ libmicrohttpd/doc/hellobrowser.inc  2008-08-12 19:49:42 UTC (rev 7545)
@@ -0,0 +1,201 @@
+The most basic task for a HTTP server is to deliver a static text message to 
any client connecting to it.
+Given that this is also very easy to implement, it is an excellent problem to 
start with.
+
+For now, the particular filename the client asks for shall have no effect on 
the message that will 
+be returned. In addition, the server shall end the connection after the 
message has been sent so that
+the client will know there is nothing more to expect.
+
+The C program @code{hellobrowser.c}, which is to be found in the examples 
section, does just that.
+If you are very eager, you can compile and start it right away but it is 
advisable to type the
+lines in by yourself as they will be discussed and explained in detail. 
+
+After the unexciting includes and the definition of the port which our server 
should listen on
address@hidden
+#include <microhttpd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
address@hidden verbatim
address@hidden
+the desired behaviour of our server when HTTP request arrive have to be 
implemented. We already have
+agreed that it should not care about the particular details of the request, 
such as who is requesting
+what. The server will respond merely with the same small HTML page to every 
request. 
+
+The function we are going to write now will be called by @emph{GNU 
libmicrohttpd} every time an
+appropriate request comes in. While the name of this callback function is 
arbitrary, its parameter
+list has to follow a certain layout. So please, ignore the lot of parameters 
for now, they will be
+explained at the point they are needed. We have to use only one of them,
address@hidden MHD_Connection *connection}, for the minimalistic functionality 
we want to archive at the moment.
+
+This parameter is set by the @emph{libmicrohttpd} daemon and holds the 
necessary information to
+relate the call with a certain connection. Keep in mind that a server might 
have to satisfy hundreds
+of concurrent connections and we have to make sure that the correct data is 
sent to the destined
+client. Therefore, this variable is a means to refer to a particular 
connection if we ask the
+daemon to sent the reply.
+
+Talking about the reply, it is defined as a string right after the function 
header
address@hidden
+int AnswerToConnection(void *cls, struct MHD_Connection *connection, 
+    const char *url, const char *method, const char *version,
+    const char *upload_data, unsigned int *upload_data_size, void **con_cls)
+{
+  const char *page  = "<html><body>Hello, browser!</body></html>";
address@hidden verbatim
address@hidden
+HTTP is a rather strict protocol and the client would certainly consider it 
"inappropriate" if we
+just sent the answer string "as is". Instead, it has to be wrapped in certain 
layers, called headers,
+of additional information. Luckily, most of the work in this area is done by 
the library for us---we
+just have to ask. Our reply string packed in the necessary layers will be 
called a "response".
+To obtain such a response we hand our data (the reply--string) and its size 
over to the 
address@hidden function. The last two parameters basically tell @emph{MHD}
+that we do not want it to dispose the message data for us when it has been 
sent and there also needs
+no internal copy to be done because the @emph{constant} string won't change 
anyway.
+
address@hidden
+  struct MHD_Response *response;
+  int ret;
+
+  response = MHD_create_response_from_data(strlen(page),
+             (void*)page, MHD_NO, MHD_NO);
address@hidden verbatim
address@hidden
+Now that the the response has been laced up, it is ready for delivery and can 
be queued for sending. 
+This is done by passing it to another @emph{GNU libmicrohttpd} function. As 
all our work was done in
+the scope of one function, the recipient is without doubt the one associated 
with the
+local variable @code{connection} and consequently this variable is given to 
the queue function. 
+Every HTTP response is accompanied by a status code, here "OK", so that the 
client knows 
+this response is the intended result of his request and not due to some error 
or malfunction.
+
+Finally, the packet is destroyed and the return value from the queue returned,
+already being set at this point to either MHD_YES or MHD_NO in case of success 
or failure.
+
address@hidden
+  ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
+  MHD_destroy_response (response);
+  return ret;
+}
address@hidden verbatim
address@hidden
+With the primary task of our server implemented, we can start the actual 
server daemon which will listen 
+on @code{PORT} for connections. This is done in the main function.
address@hidden
+int main ()
+{
+  struct MHD_Daemon *d;
+
+  d = MHD_start_daemon(MHD_USE_SELECT_INTERNALLY, PORT, NULL, NULL, 
+                      &AnswerToConnection, NULL, MHD_OPTION_END);
+  if (d == NULL) return 1;
address@hidden verbatim
address@hidden
+The first parameter is one of three possible modes of operation. Here we want 
the daemon to run in
+a separate thread and to manage all incoming connections in the same thread. 
This means that while
+producing the response for one connection, the other connections will be put 
on hold. In this
+chapter, where the reply is already known and therefore the request is served 
quickly, this poses no problem.
+
+We will allow all clients to connect regardless of their name or location, 
therefore we do not check
+them on connection and set the forth and fifth parameter to NULL.
+
+Parameter six is the address of the function we want to be called whenever a 
new connection has been
+established. Our @code{AnswerToConnection} knows best what the client wants 
and needs no additional
+information (which could be passed via the next parameter) so the next 
parameter is NULL. Likewise,
+we do not need to pass extra options to the daemon so we just write the 
MHD_OPTION_END as the last parameter.
+
+As the server daemon runs in the background in its own thread, the execution 
flow in our main
+function will contine right after the call. Because of this, we must delay the 
execution flow in the
+main thread or else the program will terminate prematurely. We let it pause in 
a processing-time
+friendly manner by waiting for the enter key to be pressed. In the end, we 
stop the daemon so it can
+do its cleanup tasks.
address@hidden
+  getchar(); 
+
+  MHD_stop_daemon(d);
+  return 0;
+}
address@hidden verbatim
address@hidden
+The first example is now complete.
+
+Compile it with 
address@hidden
+cc hellobrowser.c -o hellobrowser -I$PATH_TO_LIBMHD_INCLUDES 
+  -L$PATH_TO_LIBMHD_INCLUDES -static -lmicrohttpd -pthread
address@hidden verbatim
+with the two paths set accordingly and run it.
+
+Now open your favorite Internet browser and go to the address 
@code{localhost:8888}, provided that
+is the port you chose. If everything works as expected, the browser will 
present the message of the
+static HTML page it got from our minimal server.
+
address@hidden Remarks
+To keep this first example as small as possible, some drastic shortcuts were 
taken and are to be
+discussed now. 
+
+Firstly, there is no distinction made between the kinds of requests a client 
could send. We implied
+that the client sends a GET request, that means, that he actually asked for 
some data. Even when
+it is not intended to accept POST requests, a good server should at least 
recognize that this
+request does not constitute a legal request and answer with an error code. 
This can be easily
+implemented by checking if the parameter @code{method} equals the string "GET" 
and returning a
address@hidden if not so.
+
+Secondly, the above practice of queuing a response upon the first call of the 
callback function
+brings with it some limitations. This is because the content of the message 
body will not be
+received if a response is queued in the first iteration. Furthermore, the 
connection will be closed
+right after the response has been transferred then.
+
+Both of these issues you will find addressed in the official 
@code{minimal_example.c} residing in
+the @code{src/examples} directory of the @emph{GNU libmicrohttpd} package. The 
source code of this
+program should look very familiar to you by now and easy to understand.
+
+For our example, the @code{must_copy} and @code{must_free} parameter at the 
response construction
+function could be set to @code{MHD_NO}. In the usual case, responses cannot be 
sent immediately
+after being queued. For example, there might be other data on the system that 
needs to be sent with
+a higher priority. Nevertheless, the queue function will return 
successfully---raising the problem
+that the data we have pointed to may be invalid by the time it is about being 
sent. This is not an
+issue here because we can expect the @code{page} string, which is a constant 
@emph{string literal}
+here, to be static. That means it will be present and unchanged for as long as 
the program runs. 
+For dynamic data, one could choose to either have @emph{MHD} free the memory 
@code{page} points 
+to itself when it is not longer needed or, alternatively, have the library to 
make and manage 
+its own copy of it.
+
address@hidden Exercises
address@hidden @bullet
address@hidden
+While the server is running, use a program like telnet or netcat to connect to 
it. Try to form a
+valid HTTP1.1 request yourself like
address@hidden
+GET /dontcare HTTP1.1
+Host: itsme
+<enter>
address@hidden verbatim
address@hidden
+and see what the server returns to you.
+     
+
address@hidden
+Also, try other requests, like POST, and see how our server does not mind and 
why.
+How far in malforming a request can you go before the builtin functionality of 
@emph{MHD} intervenes
+and an altered response is sent? Make sure you read about the status codes in 
the @emph{RFC}.
+
+
address@hidden
+Add the option @code{MHD_USE_PEDANTIC_CHECKS} to the start function of the 
daemon in @code{main}.
+Mind the special format of the parameter list here which is described in the 
manual. How indulgent
+is the server now to your input?
+
+
address@hidden
+Let the main function take a string as the first command line argument and 
pass @code{argv[1]} to
+the @code{MHD_start_daemon} function as the sixth parameter. The address of 
this string will be
+passed to the callback function via the @code{cls} variable. Decorate the text 
given at the command
+line when the server is started with proper HTML tags and send it as the 
response instead of the
+former static string.
+
+
address@hidden
address@hidden:} Write a separate function returning a string containing some 
useful information, 
+for example, the time. Pass the function's address as the sixth parameter and 
evaluate this function
+on every request anew in @code{AnswerToConnection}. Remember to free the 
memory of the string
+every time after satisfying the request.
+
address@hidden itemize

Added: libmicrohttpd/doc/introduction.inc
===================================================================
--- libmicrohttpd/doc/introduction.inc                          (rev 0)
+++ libmicrohttpd/doc/introduction.inc  2008-08-12 19:49:42 UTC (rev 7545)
@@ -0,0 +1,19 @@
+This tutorial is aimed at developers who want to learn how they can add HTTP 
serving 
+capabilities to their applications with the @emph{GNU libmicrohttpd} library,
+abbreviated @emph{MHD}, and who do not know how to start. It tries to help 
these
+developers to implement common basic HTTP serving tasks by discussing 
executable
+sample programs implementing different features. 
+
+The text is supposed to be a supplement to the API reference manual of 
address@hidden libmicrohttpd} and for that reason does not explain many of the 
parameters.
+Therefore, the reader should always consult the manual to find the exact 
meaning
+of the functions used in the tutorial. In the same sense, the tutorial seeks to
+encourage the use of the @emph{RFCs}, which document the conventions the 
Internet
+is built upon. 
+
address@hidden libmicrohttpd} is assumed to be already installed and it has been
+written with respect to version @value{VERSION}. As the library is still in 
its 
+beta stages, later versions may show different behaviour. At the time being, 
+this tutorial has only been tested on @emph{GNU/Linux} machines even though
+efforts were made not to rely on anything that would prevent the samples from 
being
+built on similar systems.

Added: libmicrohttpd/doc/processingpost.inc
===================================================================
--- libmicrohttpd/doc/processingpost.inc                                (rev 0)
+++ libmicrohttpd/doc/processingpost.inc        2008-08-12 19:49:42 UTC (rev 
7545)
@@ -0,0 +1,225 @@
+The previous chapters already have demonstrated a variety of possibilities to 
send information 
+to the HTTP server, but it is not recommended that the @emph{GET} method is 
used to alter the way
+the server operates. To induce changes on the server, the @emph{POST} method 
is preferred over
+and is much more powerful than @emph{GET} and will be introduced in this 
chapter.
+
+We are going to write an application that asks for the visitor's name and, 
after the user has posted it,
+composes an individual response text. Even though it was not mandatory to use 
the @emph{post} method here,
+as there is no permanent change caused by the post, it is an illustrative 
example on how to share data
+between different functions for the same connection. Furthermore, the reader 
should be able to extend
+it easily.
+
address@hidden GET request
+When the first @emph{GET} request arrives, the server shall respond with a 
HTML page containing an
+edit field for the name.
+
address@hidden
+const char* askpage="<html><body>\
+                     What's your name, Sir?<br>\
+                     <form action=\"/namepost\" method=\"post\">\
+                     <input name=\"name\" type=\"text\"\
+                     <input type=\"submit\" value=\" Send \"></form>\
+                     </body></html>";
address@hidden verbatim
address@hidden
+
+The @code{action} entry is the @emph{URI} to be called by the browser when 
posting, and the
address@hidden will be used later to be sure it is the editbox's content that 
has been posted.
+
+We also prepare the answer page, where the name is to be filled in later, and 
an error page 
+as the response for anything but proper @emph{GET} and @emph{POST} requests:
+
address@hidden
+const char* greatingpage="<html><body><h1>Welcome, 
%s!</center></h1></body></html>";
+
+const char* errorpage="<html><body>This doesn't seem to be 
right.</body></html>";
address@hidden verbatim
address@hidden
+
+Whenever we need to send a page, we use an extra function
address@hidden SendPage(struct MHD_Connection *connection, const char* page)}
+for this, which does not contain anything new and whose implementation is 
therefore left out here. 
+
+
address@hidden POST request
+Posted data can be of arbitrary and considerable size; for example, if a user 
uploads a big
+image to the server. Similar to the case of the header fields, there may also 
be different streams
+of posted data, such as one containing the text of an editbox and another the 
state of a button.
+Likewise, we will have to register an iterator function that is going to be 
called maybe several times 
+not only if there are different POSTs but also if one POST has only been 
received partly yet and
+needs processing before another chunk can be received.
+
+Such an iterator function is called by a @emph{postprocessor}, which must be 
created upon arriving
+of the post request.  We want the iterator function to read the first post 
data which is tagged
address@hidden and to create an individual greeting string based on the 
template and the name. 
+But in order to pass this string to other functions and still be able to 
differentiate different
+connections, we must first define a structure to share the information, 
holding the most import entries.
+
address@hidden
+struct ConnectionInfoStruct
+{
+  int connectiontype;
+  char *answerstring;
+  struct MHD_PostProcessor *postprocessor; 
+};
address@hidden verbatim
address@hidden
+
+With these information available to the iterator function, it is able to 
fulfill its task. 
+Once it has composed the greeting string, it returns @code{MHD_NO} to inform 
the post processor
+that it does not need to be called again. Note that this function does not 
handle processing
+of data for the same @code{key}. If we were to expect that the name will be 
posted in several
+chunks, we had to expand the namestring dynamically as additional parts of it 
with the same @code{key}
+came in. But in this example, the name is assumed to fit entirely inside one 
single packet.
+
address@hidden
+int IteratePost(void *coninfo_cls, enum MHD_ValueKind kind, const char *key,
+                const char *filename, const char *content_type,
+                const char *transfer_encoding, const char *data, size_t off, 
size_t size)
+{
+  struct ConnectionInfoStruct *con_info = (struct 
ConnectionInfoStruct*)(coninfo_cls);
+  
+
+  if (0 == strcmp(key, "name"))
+  {
+    if ((size>0) && (size<=MAXNAMESIZE))
+    {
+      char *answerstring;
+      answerstring = malloc(MAXANSWERSIZE);
+      if (!answerstring) return MHD_NO;
+      
+      snprintf(answerstring, MAXANSWERSIZE, greatingpage, data);
+      con_info->answerstring = answerstring;      
+    } else con_info->answerstring=NULL;
+
+    return MHD_NO;
+  }
+
+  return MHD_YES;
+}
address@hidden verbatim
address@hidden
+
+Once a connection has been established, it can be terminated for many reasons. 
As these
+reasons include unexpected events, we have to register another function that 
cleans up any resources
+that might have been allocated for that connection by us, namely the post 
processor and the greetings
+string. This cleanup function must take into account that it will also be 
called for finished 
+requests other than @emph{POST} requests.
+
address@hidden
+void RequestCompleted(void *cls, struct MHD_Connection *connection, void 
**con_cls,
+                      enum MHD_RequestTerminationCode toe)
+{
+  struct ConnectionInfoStruct *con_info = (struct 
ConnectionInfoStruct*)(*con_cls);
+
+
+  if (NULL == con_info) return;
+
+  if (con_info->connectiontype == POST)
+  {
+    MHD_destroy_post_processor(con_info->postprocessor);        
+    if (con_info->answerstring) free(con_info->answerstring);
+  }
+  
+  free(con_info);      
+}
address@hidden verbatim
address@hidden
+
address@hidden libmicrohttpd} is informed that it shall call the above function 
when the daemon is started
+in the main function.
+
address@hidden
+...
+daemon = MHD_start_daemon(MHD_USE_SELECT_INTERNALLY, PORT, NULL, NULL,
+                            &AnswerToConnection, NULL, 
MHD_OPTION_NOTIFY_COMPLETED,
+                            RequestCompleted, NULL, MHD_OPTION_END);
+...
address@hidden verbatim
address@hidden
+
address@hidden Request handling
+With all other functions prepared, we can now discuss the actual request 
handling.
+
+On the first iteration for a new request, we start by allocating a new 
instance of a 
address@hidden structure, which will store all necessary information for later
+iterations and other functions.
+
address@hidden
+int AnswerToConnection(void *cls, struct MHD_Connection *connection, const 
char *url, 
+    const char *method, const char *version, const char *upload_data, 
+    unsigned int *upload_data_size, void **con_cls)
+{
+  if(*con_cls==NULL) 
+  {
+    struct ConnectionInfoStruct *con_info;
+
+    con_info = malloc(sizeof(struct ConnectionInfoStruct));
+    if (NULL == con_info) return MHD_NO;
address@hidden verbatim
address@hidden
+
+If the new request is a @emph{POST}, the postprocessor must be created now. In 
addition, the type
+of the request is stored for convenience.
address@hidden
+  if (0 == strcmp(method, "POST")) 
+    {      
+      con_info->postprocessor = MHD_create_post_processor(connection, 
POSTBUFFERSIZE, 
+                                                          IteratePost, 
(void*)con_info);   
+
+      if (NULL == con_info->postprocessor) 
+      {
+        free(con_info); 
+        return MHD_NO;
+      }
+
+      con_info->connectiontype = POST;
+    } else con_info->connectiontype = GET;
address@hidden verbatim
address@hidden
+
+The address of our structure will both serve as the indicator for successive 
iterations and to remember
+the particular details about the connection.
address@hidden
+ *con_cls = (void*)con_info;
+    return MHD_YES;
+  }
address@hidden verbatim
address@hidden
+
+The rest of the function will not be executed on the first iteration. A 
@emph{GET} request is easily
+satisfied by sending the question form.
address@hidden
+  if (0 == strcmp(method, "GET")) 
+  {
+    return SendPage(connection, askpage);     
+  } 
address@hidden verbatim
address@hidden
+
+In case of @emph{POST}, we invoke the post processor for as long as data keeps 
incoming, setting
address@hidden to zero in order to indicate that we have processed---or at 
least have
+considered---all of it.
address@hidden
+  if (0 == strcmp(method, "POST")) 
+  {
+    struct ConnectionInfoStruct *con_info = *con_cls;
+
+    if (*upload_data_size != 0) 
+    {
+      MHD_post_process(con_info->postprocessor, upload_data, 
*upload_data_size);
+      *upload_data_size = 0;
+      return MHD_YES;
+    } else return SendPage(connection, con_info->answerstring);
+  } 
address@hidden verbatim
address@hidden
+
+If they are neither @emph{GET} nor @emph{POST} requests, the error page is 
returned finally.
address@hidden
+  return SendPage(connection, errorpage); 
+}
address@hidden verbatim
address@hidden
+
+These were the important parts of the program @code{simplepost.c}.

Added: libmicrohttpd/doc/responseheaders.inc
===================================================================
--- libmicrohttpd/doc/responseheaders.inc                               (rev 0)
+++ libmicrohttpd/doc/responseheaders.inc       2008-08-12 19:49:42 UTC (rev 
7545)
@@ -0,0 +1,171 @@
+Now that we are able to inspect the incoming request in great detail,
+this chapter discusses the means to enrich the outgoing responses likewise.
+
+As you have learned in the @emph{Hello, Browser} chapter, some obligatory 
+header fields are added and set automatically for simple responses by the 
library
+itself but if more advanced features are desired, additional fields have to be 
created.
+One of the possible fields is the content type field and an example will be 
developed around it.
+This will lead to an application capable of correctly serving different types 
of files.
+
+
+When we responded with HTML page packed in the static string previously, the 
client had no choice
+but guessing about how to handle the response, because the server hadn't told 
him. 
+What if we had sent a picture or a sound file?  Would the message have been 
understood
+or merely been displayed as an endless stream of random characters in the 
browser?
+This is what the mime content types are for. The header of the response is 
extended
+by certain information about how the data is to be interpreted. 
+
+To introduce the concept, a picture of the format @emph{PNG} will be sent to 
the client 
+and labeled accordingly with @code{image/png}.
+Once again, we can base the new example on the @code{hellobrowser} program.
+
address@hidden
+#define FILENAME "picture.png"
+#define MIMETYPE "image/png"
+
+int AnswerToConnection(void *cls, struct MHD_Connection *connection, 
+    const char *url, const char *method, const char *version,
+    const char *upload_data, unsigned int *upload_data_size, void **con_cls)
+{
+  struct MHD_Response *response;
+  int ret=0;
address@hidden verbatim
address@hidden
+ 
+We want the program to load the graphics file into memory:
address@hidden
+long size;
+  FILE *fp;
+  int ret=0;
+
+  if (0 != strcmp(method, "GET")) return MHD_NO;
+
+  size = GetFileSize(FILENAME);
+  if (size != 0)
+  {
+    fp = fopen(FILENAME, "rb");
+    if (fp) 
+    {
+      buffer = malloc(size);
+      if (buffer)
+        if (size == fread(buffer, 1, size, fp)) ret=1;
+    }  
+      
+    fclose(fp);
+  }
address@hidden verbatim
address@hidden
+
+The @code{GetFileSize} function, which returns a size of zero if the file 
could not be opened or
+found, is left out on this page for tidiness. 
+
+When dealing with files and allocating memory, there is a lot that could go 
wrong on the
+sider side and if so, the client should be informed with 
@code{MHD_HTTP_INTERNAL_SERVER_ERROR}.
+
address@hidden
+  if (!ret) 
+  {
+    const char *errorstr = "<html><body>An internal server error\
+                            has occured!</body></html>";
+
+    if (buffer) free(buffer);
+    response = MHD_create_response_from_data(strlen(errorstr),
+                                            (void*)errorstr, MHD_NO, MHD_NO);
+
+    ret = MHD_queue_response (connection, 
+                              MHD_HTTP_INTERNAL_SERVER_ERROR, response);
+
+    return MHD_YES;    
+  }
address@hidden verbatim
address@hidden
+
+Note that we nevertheless have to create an response object even for sending a 
simple error code.
+Otherwise, the connection would just be closed without comment, leaving the 
client curious about
+what has happened.
+
+But in the case of success a response will be constructed that contains the 
buffer filled with the
+file's content. 
+
address@hidden
+response = MHD_create_response_from_data(size, (void*)buffer, MHD_YES, MHD_NO);
address@hidden verbatim
address@hidden
+
+Contrary to the above case where a static string will be sent, this time we 
have to 
+keep track of the dynamically allocated buffer. As discussed in the @ref{Hello 
browser example}, 
+the buffer cannot be safely freed as soon as the function call returns. 
Instead, we ask the function
+to keep charge of freeing the buffer itself when it is not longer needed. 
Thus, no further @code{free}
+command is invoked by us.
+
+Up to this point, there was little new. The actual novelty is that we enhance 
the header with the
+meta data about the content. Aware of the field's name we want to add, it is 
as easy as that:
address@hidden
+MHD_add_response_header(response, "Content-Type", MIMETYPE);
address@hidden verbatim
address@hidden
+We do not have to append a colon expected by the protocol hehind the first 
address@hidden libhttpdmicro} will take care of this. 
+
+The function finishes with the well-known lines
address@hidden
+  ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
+  MHD_destroy_response (response);
+  return ret;
+}
address@hidden verbatim
address@hidden
+
+The complete program @code{responseheaders.c} is in the @code{examples} 
section as usual.
+Find a @emph{PNG} file you like and save it to the directory the example is 
run from under the name
address@hidden You should find the image displayed on your browser if 
everything worked well.
+
address@hidden Remarks
+The include file of the @emph{MHD} library comes with the header types 
mentioned in @emph{RFC 2616}
+already defined as macros. Thus, we could have written 
@code{MHD_HTTP_HEADER_CONTENT_TYPE} instead
+of @code{"Content-Type"} as well. However, one is not limited to these 
standard headers and could
+add custom response headers without violated the protocol. Whether and how the 
client would react
+to these custom header is up to the receiver. Likewise, the client is allowed 
to send custom request
+headers to the server as well, opening up yet more possibilities how client 
and server could 
+communicate with each other.
+
+The method of creating the response from one big chunk of data is only 
feasible for smaller files.
+A public file server satisfying many request at the same time would be choking 
under these high
+demands on memory very soon. Serving responses in smaller parts would be more 
adequate here and
+will be a topic of a future chapter.
+
address@hidden Exercises
address@hidden @bullet
+
address@hidden
+Remember that the original program was written under a few assumptions---a 
small, static response
+being one of them. In order to simulate a very large or hard to reach file 
that cannot be provided
+instantly, postpone the queuing in the callback with the @code{sleep} function 
for 30 seconds 
address@hidden the file @code{/big.png} is requested (but deliver the same as 
above). A request for
address@hidden/picture.png} should provide just the same but without any 
artificial delays.
+
+Now start two instances of your browser (or even use two machines) and see how 
the second client
+is put on hold while the first waits for his request on the slow file to be 
fulfilled.
+
+Finally, change the sourcecode to use @code{MHD_USE_THREAD_PER_CONNECTION} 
when the daemon is 
+started and try again.
+
+
address@hidden
+Did you succeed in implementing the clock exercise yet? This time, let the 
server save the 
+program's start time @code{t} and implement a response simulating a countdown 
that reaches 0 at
address@hidden Returning a message saying on which point the countdown is, the 
response should
+ultimately be to reply "Done" if the program has been running long enough,
+
+A non official, but widely understood, response header line is @code{Refresh: 
DELAY; url=URL} with
+the uppercase words substituted to tell the client it should request the given 
resource after 
+the given delay again. Improve your program in that the browser (any modern 
browser should work)
+automatically reconnects and asks for the status again every 5 seconds or so. 
The URL would have
+to be composed so that it begins with "http://";, followed by the @emph{URI} 
the server is reachable
+from the client's point of view.
+
+Maybe you want also to visualize the countdown as a status bar by creating a 
address@hidden<table>} consisting of one row and @code{n} columns whose fields 
contain small images of either
+a red or a green light.
+
address@hidden itemize

Added: libmicrohttpd/doc/tutorial.texi
===================================================================
--- libmicrohttpd/doc/tutorial.texi                             (rev 0)
+++ libmicrohttpd/doc/tutorial.texi     2008-08-12 19:49:42 UTC (rev 7545)
@@ -0,0 +1,119 @@
+\input texinfo  @c -*-texinfo-*-
address@hidden
address@hidden libmicrohttpdtutorial
address@hidden A tutorial for GNU libmicrohttpd
address@hidden
+
address@hidden VERSION 0.3.1 beta
+
address@hidden
address@hidden A Tutorial for GNU libmicrohttpd
address@hidden written for version @value{VERSION}
address@hidden Sebastian Gerhardt (@email{sebgerhardt@@gmx.net})
address@hidden
address@hidden 0pt plus 1filll
address@hidden titlepage
+
address@hidden
+Copyright (c)  2008  Sebastian Gerhardt.
+Permission is granted to copy, distribute and/or modify this document
+under the terms of the GNU Free Documentation License, Version 1.2
+or any later version published by the Free Software Foundation;
+with no Invariant Sections, no Front-Cover Texts, and no Back-Cover
+Texts.  A copy of the license is included in the section entitled "GNU
+Free Documentation License".
address@hidden verbatim
+
address@hidden
+
address@hidden
address@hidden Top
address@hidden Top
address@hidden ifnottex     
+
address@hidden
+* Introduction::
+* Hello browser example::
+* Exploring requests::
+* Response headers::
+* A basic authentication::
+* Processing post data::
+* Bibliography::
+* License text::
+* Example programs::
address@hidden menu
+
address@hidden Introduction
address@hidden Introduction
address@hidden introduction.inc
+
address@hidden Hello browser example
address@hidden Hello browser example
address@hidden hellobrowser.inc
+
address@hidden Exploring requests
address@hidden Exploring requests
address@hidden exploringrequests.inc
+
address@hidden Response headers
address@hidden Response headers
address@hidden responseheaders.inc
+
address@hidden A basic authentication
address@hidden A basic authentication
address@hidden basicauthentication.inc
+
address@hidden Processing post data
address@hidden Processing post data
address@hidden processingpost.inc
+
+
address@hidden Bibliography
address@hidden Bibliography
address@hidden bibliography.inc
+
address@hidden License text
address@hidden GNU Free Documentation License
address@hidden fdl-1.2.texi
+
address@hidden Example programs
address@hidden Example programs
address@hidden
+* hellobrowser.c::
+* logging.c::
+* responseheaders.c::
+* basicauthentication.c::
+* simplepost.c::
address@hidden menu
+
address@hidden hellobrowser.c
address@hidden hellobrowser.c
address@hidden
address@hidden examples/hellobrowser.c
address@hidden smalldisplay
+
address@hidden logging.c
address@hidden logging.c
address@hidden
address@hidden examples/logging.c
address@hidden smalldisplay
+
address@hidden responseheaders.c
address@hidden responseheaders.c
address@hidden
address@hidden examples/responseheaders.c
address@hidden smalldisplay
+
address@hidden basicauthentication.c
address@hidden basicauthentication.c
address@hidden
address@hidden examples/basicauthentication.c
address@hidden smalldisplay
+
address@hidden simplepost.c
address@hidden simplepost.c
address@hidden
address@hidden examples/simplepost.c
address@hidden smalldisplay
+
address@hidden





reply via email to

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