libmicrohttpd

HTTP/1.x server C library (MHD 1.x, stable)
Log | Files | Refs | Submodules | README | LICENSE

processingpost.inc (9150B)


      1 The previous chapters already have demonstrated a variety of possibilities to send information
      2 to the HTTP server, but it is not recommended that the @emph{GET} method is used to alter the way
      3 the server operates. To induce changes on the server, the @emph{POST} method is preferred over
      4 and is much more powerful than @emph{GET} and will be introduced in this chapter.
      5 
      6 We are going to write an application that asks for the visitor's name and, after the user has posted it,
      7 composes an individual response text. Even though it was not mandatory to use the @emph{POST} method here,
      8 as there is no permanent change caused by the POST, it is an illustrative example on how to share data
      9 between different functions for the same connection. Furthermore, the reader should be able to extend
     10 it easily.
     11 
     12 @heading GET request
     13 When the first @emph{GET} request arrives, the server shall respond with a HTML page containing an
     14 edit field for the name.
     15 
     16 @verbatim
     17 const char* askpage = "<html><body>\
     18                        What's your name, Sir?<br>\
     19                        <form action=\"/namepost\" method=\"post\">\
     20                        <input name=\"name\" type=\"text\">\
     21                        <input type=\"submit\" value=\" Send \"></form>\
     22                        </body></html>";
     23 @end verbatim
     24 @noindent
     25 
     26 The @code{action} entry is the @emph{URI} to be called by the browser when posting, and the
     27 @code{name} will be used later to be sure it is the editbox's content that has been posted.
     28 
     29 We also prepare the answer page, where the name is to be filled in later, and an error page
     30 as the response for anything but proper @emph{GET} and @emph{POST} requests:
     31 
     32 @verbatim
     33 const char* greetingpage="<html><body><h1>Welcome, %s!</h1></body></html>";
     34 
     35 const char* errorpage="<html><body>This doesn't seem to be right.</body></html>";
     36 @end verbatim
     37 @noindent
     38 
     39 Whenever we need to send a page, we use an extra function
     40 @code{int send_page(struct MHD_Connection *connection, const char* page)}
     41 for this, which does not contain anything new and whose implementation is therefore
     42 not discussed further in the tutorial.
     43 
     44 
     45 @heading POST request
     46 Posted data can be of arbitrary and considerable size; for example, if a user uploads a big
     47 image to the server. Similar to the case of the header fields, there may also be different streams
     48 of posted data, such as one containing the text of an editbox and another the state of a button.
     49 Likewise, we will have to register an iterator function that is going to be called maybe several times
     50 not only if there are different POSTs but also if one POST has only been received partly yet and
     51 needs processing before another chunk can be received.
     52 
     53 Such an iterator function is called by a @emph{postprocessor}, which must be created upon arriving
     54 of the post request.  We want the iterator function to read the first post data which is tagged
     55 @code{name} and to create an individual greeting string based on the template and the name.
     56 But in order to pass this string to other functions and still be able to differentiate different
     57 connections, we must first define a structure to share the information, holding the most import entries.
     58 
     59 @verbatim
     60 struct connection_info_struct
     61 {
     62   int connectiontype;
     63   char *answerstring;
     64   struct MHD_PostProcessor *postprocessor;
     65 };
     66 @end verbatim
     67 @noindent
     68 
     69 With these information available to the iterator function, it is able to fulfill its task.
     70 Once it has composed the greeting string, it returns @code{MHD_YES} so that the post processor
     71 keeps parsing the remainder of the upload. Returning @code{MHD_NO} would instead abort the
     72 parsing and make the next call to @code{MHD_post_process} fail. Note that this function does not
     73 handle processing of data for the same @code{key}. If we were to expect that the name will be
     74 posted in several chunks, we had to expand the namestring dynamically as additional parts of it
     75 with the same @code{key} came in. But in this example, the name is assumed to fit entirely inside
     76 one single packet.
     77 
     78 @verbatim
     79 static enum MHD_Result
     80 iterate_post (void *coninfo_cls, enum MHD_ValueKind kind, const char *key,
     81               const char *filename, const char *content_type,
     82               const char *transfer_encoding, const char *data,
     83 	      uint64_t off, size_t size)
     84 {
     85   struct connection_info_struct *con_info = coninfo_cls;
     86 
     87   if (0 == strcmp (key, "name"))
     88     {
     89       if ((size > 0) && (size <= MAXNAMESIZE))
     90         {
     91           char *answerstring;
     92           answerstring = malloc (MAXANSWERSIZE);
     93           if (!answerstring) return MHD_NO;
     94 
     95           snprintf (answerstring, MAXANSWERSIZE, greetingpage, data);
     96           con_info->answerstring = answerstring;
     97         }
     98       else con_info->answerstring = NULL;
     99     }
    100 
    101   return MHD_YES;
    102 }
    103 @end verbatim
    104 @noindent
    105 
    106 Once a connection has been established, it can be terminated for many reasons. As these
    107 reasons include unexpected events, we have to register another function that cleans up any resources
    108 that might have been allocated for that connection by us, namely the post processor and the greetings
    109 string. This cleanup function must take into account that it will also be called for finished
    110 requests other than @emph{POST} requests.
    111 
    112 @verbatim
    113 static void
    114 request_completed (void *cls, struct MHD_Connection *connection,
    115      		        void **req_cls,
    116                         enum MHD_RequestTerminationCode toe)
    117 {
    118   struct connection_info_struct *con_info = *req_cls;
    119 
    120   if (NULL == con_info)
    121     return;
    122   if (con_info->connectiontype == POST)
    123     {
    124       MHD_destroy_post_processor (con_info->postprocessor);
    125       if (con_info->answerstring) free (con_info->answerstring);
    126     }
    127 
    128   free (con_info);
    129   *req_cls = NULL;
    130 }
    131 @end verbatim
    132 @noindent
    133 
    134 @emph{GNU libmicrohttpd} is informed that it shall call the above function when the daemon is started
    135 in the main function.
    136 
    137 @verbatim
    138 ...
    139 daemon = MHD_start_daemon (MHD_USE_AUTO | MHD_USE_INTERNAL_POLLING_THREAD,
    140                            PORT, NULL, NULL,
    141                            &answer_to_connection, NULL,
    142 			   MHD_OPTION_NOTIFY_COMPLETED, &request_completed, NULL,
    143 			   MHD_OPTION_END);
    144 ...
    145 @end verbatim
    146 @noindent
    147 
    148 @heading Request handling
    149 With all other functions prepared, we can now discuss the actual request handling.
    150 
    151 On the first iteration for a new request, we start by allocating a new instance of a
    152 @code{struct connection_info_struct} structure, which will store all necessary information for later
    153 iterations and other functions.
    154 
    155 @verbatim
    156 static enum MHD_Result
    157 answer_to_connection (void *cls, struct MHD_Connection *connection,
    158 		      const char *url,
    159                       const char *method, const char *version,
    160 		      const char *upload_data,
    161                       size_t *upload_data_size, void **req_cls)
    162 {
    163   if(NULL == *req_cls)
    164     {
    165       struct connection_info_struct *con_info;
    166 
    167       con_info = malloc (sizeof (struct connection_info_struct));
    168       if (NULL == con_info) return MHD_NO;
    169       con_info->answerstring = NULL;
    170 @end verbatim
    171 @noindent
    172 
    173 If the new request is a @emph{POST}, the postprocessor must be created now. In addition, the type
    174 of the request is stored for convenience.
    175 @verbatim
    176       if (0 == strcmp (method, "POST"))
    177         {
    178           con_info->postprocessor
    179 	    = MHD_create_post_processor (connection, POSTBUFFERSIZE,
    180                                          iterate_post, (void*) con_info);
    181 
    182           if (NULL == con_info->postprocessor)
    183             {
    184               free (con_info);
    185               return MHD_NO;
    186             }
    187           con_info->connectiontype = POST;
    188         }
    189       else con_info->connectiontype = GET;
    190 @end verbatim
    191 @noindent
    192 
    193 The address of our structure will both serve as the indicator for successive iterations and to remember
    194 the particular details about the connection.
    195 @verbatim
    196       *req_cls = (void*) con_info;
    197       return MHD_YES;
    198     }
    199 @end verbatim
    200 @noindent
    201 
    202 The rest of the function will not be executed on the first iteration. A @emph{GET} request is easily
    203 satisfied by sending the question form.
    204 @verbatim
    205   if (0 == strcmp (method, "GET"))
    206     {
    207       return send_page (connection, askpage);
    208     }
    209 @end verbatim
    210 @noindent
    211 
    212 In case of @emph{POST}, we invoke the post processor for as long as data keeps incoming, setting
    213 @code{*upload_data_size} to zero in order to indicate that we have processed---or at least have
    214 considered---all of it.
    215 @verbatim
    216   if (0 == strcmp (method, "POST"))
    217     {
    218       struct connection_info_struct *con_info = *req_cls;
    219 
    220       if (*upload_data_size != 0)
    221         {
    222           if (MHD_YES !=
    223               MHD_post_process (con_info->postprocessor, upload_data,
    224 	                        *upload_data_size))
    225             return MHD_NO;
    226           *upload_data_size = 0;
    227 
    228           return MHD_YES;
    229         }
    230       else if (NULL != con_info->answerstring)
    231         return send_page (connection, con_info->answerstring);
    232     }
    233 @end verbatim
    234 @noindent
    235 
    236 Finally, if they are neither @emph{GET} nor @emph{POST} requests, the error page is returned.
    237 @verbatim
    238   return send_page(connection, errorpage);
    239 }
    240 @end verbatim
    241 @noindent
    242 
    243 These were the important parts of the program @code{simplepost.c}.