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