processingpost.inc 8.8 KB

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