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}.