postprocessor.inc (13605B)
1 @cindex POST 2 MHD provides the post processor API to make it easier for applications to 3 parse the data of a client's @code{POST} request that is encoded 4 in one of the typical formats for HTML form data. 5 6 POST data can be processed in two main ways with MHD: 7 @itemize 8 @item incrementally, as it is received over the network 9 @item from memory with random access 10 @end itemize 11 12 Incremental processing is necessary if the POSTed data does 13 not fit into main memory, while processing from memory with 14 random access is often more convenient and generally preferrable 15 for developers if the data fits into memory. MHD's API allows 16 the application to do both, even for the same request: the 17 application can specify how large of an in-memory buffer to 18 use with @var{buffer_size}, and then to provide a threshold 19 @var{max_nonstream_size} above which records will be processed 20 incementally. 21 22 @node libmicrohttpd-postprocessor-start 23 @section Starting POST processing 24 25 POST handling using this style is initiated by returning an action 26 created via @code{MHD_action_parse_post()} from 27 @ref{MHD_RequestCallback,,@code{MHD_RequestCallback}}. 28 29 @anchor{MHD_action_parse_post} 30 @deftypefun {const struct MHD_Action *} MHD_action_parse_post (struct MHD_Request *request, size_t buffer_size, size_t max_nonstream_size, enum MHD_HTTP_PostEncoding enc, MHD_PostDataReader stream_reader, void *reader_cls, MHD_PostDataFinished done_cb, void *done_cb_cls) 31 32 Creates an action to parse the POSTed content from the client. 33 The action starts parsing of the POST data. Any record that is larger 34 than @var{buffer_size} or @var{max_nonstream_size} is given to 35 the @var{stream_reader} (unless @var{stream_reader} is @code{NULL}). 36 37 If @var{buffer_size} is zero, then buffers will be limited to the 38 connection's memory pool. To force all POST records to be processed 39 incrementally via @var{stream_reader} set @var{max_nonstream_size} to 40 zero. 41 42 @table @var 43 @item request 44 the request to create a POST processing action for 45 46 @item buffer_size 47 the maximum size allowed for the buffers to parse this 48 request POST data. Within the set limit the buffer is 49 allocated automatically from the @ref{shared memory pool} 50 if necessary. 51 52 @item max_nonstream_size 53 the size of the field (in encoded form) above which 54 values are not buffered and provided for 55 the @var{steam_reader} automatically; 56 useful to have large data (like file uploads) 57 processed incrementally, while keeping buffer space 58 for small fields only; 59 ignored if @var{stream_reader} is @code{NULL} 60 61 @item enc 62 the data encoding to use, 63 @code{MHD_HTTP_POST_ENCODING_OTHER} to tell MHD 64 to detect the encoding automatically (based on HTTP headers); 65 66 @item stream_reader 67 a function to call for ``oversize'' records in 68 the stream; can be @code{NULL} if @var{max_nonstream_size} 69 is not zero; 70 71 @item reader_cls 72 the closure for the @var{stream_reader}; 73 74 @item done_cb called once all data has been processed, returning 75 control back to the application to determine the next action; values 76 smaller than @var{max_nonstream_size} that fit into @var{buffer_size} 77 will be available during @var{done_cb} via 78 @ref{MHD_request_get_values_cb,,@code{MHD_request_get_values_cb()}} 79 and 80 @ref{MHD_request_get_values_list,,@code{MHD_request_get_values_list()}}, 81 @ref{MHD_request_get_post_data_cb,,@code{MHD_request_get_post_data_cb()}} 82 and 83 @ref{MHD_request_get_post_data_list,,@code{MHD_request_get_post_data_list()}}. 84 85 @item done_cb_cls 86 the closure for the @var{done_cb} 87 88 @end table 89 90 Returns a pointer to the action, @code{NULL} if creating the action 91 failed (insufficient memory) or if any action has been already created 92 for the @var{request}. 93 94 @end deftypefun 95 96 @node libmicrohttpd-postprocessor-incremental 97 @section Incremental record processing 98 99 100 After returning the action created via @code{MHD_action_parse_post} 101 MHD will first call the given @code{MHD_PostDataReader} for incremental 102 processing of all records that exceed the length threshold. 103 104 @anchor{MHD_PostDataReader} 105 @deftypefn {Function Pointer} {enum MHD_Bool} (*MHD_PostDataReader) (void *cls, struct MHD_Request *req, const struct MHD_String *name, const struct MHD_StringNullable *filename, const struct MHD_StringNullable *content_type, const struct MHD_StringNullable *encoding, size_t size, const void *data, uint_fast64_t off, enum MHD_Bool final_data) 106 107 Stream reader for incremental processing of POST records. This 108 callback is called to incrementally process parsed POST records sent 109 by the client. The pointers to the @code{struct MHD_String} and 110 @code{struct MHD_StringNullable} are valid @emph{only} until the 111 application returns from this callback. 112 113 @table @var 114 @item cls 115 custom value provided by the application with the callback; 116 117 @item request 118 the request to get data for; 119 120 @item name 121 the name of the POST record; 122 123 @item filename 124 the name of the uploaded file, @code{NULL} if not provided; 125 126 @item content_type 127 the mime-type of the data, @code{NULL} if not provided; 128 129 @item encoding 130 the encoding of the data, @code{NULL} if not provided; 131 132 @item size 133 the number of bytes in @var{data}, may be zero if @var{final_data} 134 is @code{MHD_YES}; 135 136 @item data 137 a pointer to @var{size} bytes of data at the specified 138 offset @var{off}, @strong{not} zero-terminated; 139 140 @item off 141 the offset of @var{data} in the overall value, always equal to 142 the sum of all @var{size} values of previous calls for the same 143 record; however, note that a client may provide more than one 144 record with the same @var{name} and the same @var{filename}! Thus 145 the next record (or file) may be indicated by a zero 146 value in @var{off} (and the end is indicated by @var{final_data}); 147 148 @item final_data 149 set to @code{MHD_YES} when this is the last call for the given 150 record, set to @code{MHD_NO} if additional callbacks for the same 151 record will be made; 152 153 @end table 154 155 The incremental callback must specify how to continue processing 156 the upload. The choices are: 157 158 @itemize 159 @item @code{MHD_upload_action_continue()} if all is well, 160 @item @code{MHD_upload_action_suspend()} to stop reading from the client 161 until the request is explicitly resumed by the application, 162 @item @code{MHD_upload_action_abort_request()} to close the socket, or 163 @item an action with a response to @emph{discard} the rest of the 164 upload and transmit the response. 165 @end itemize 166 167 @end deftypefn 168 169 @node libmicrohttpd-postprocessor-final 170 @section Final in-memory processing of parsing status and records 171 172 After all large records have been provided to the 173 @code{MHD_PostDataReader} and MHD has concluded parsing the entire 174 body sent by the client, MHD will call the @var{done_cb} to give the 175 application a chance to inspect the records that were small enough to 176 fit fully into memory and to decide the next action. 177 178 @anchor{MHD_PostDataFinished} 179 @deftypefn {Function Pointer} {struct MHD_UploadAction} (*MHD_PostDataFinished) (void *cls, struct MHD_Request *req, const struct MHD_PostParseResult *parsing_result) 180 181 The callback to be called when MHD is finished with parsing 182 all of the body. The @var{stream_reader} will not be called 183 after this call. Implementations of this function can 184 use 185 @ref{MHD_request_get_values_cb,,@code{MHD_request_get_values_cb()}} 186 and 187 @ref{MHD_request_get_values_list,,@code{MHD_request_get_values_list()}}, 188 @ref{MHD_request_get_post_data_cb,,@code{MHD_request_get_post_data_cb()}} 189 and 190 @ref{MHD_request_get_post_data_list,,@code{MHD_request_get_post_data_list()}} 191 to inspect the non-incremental POST data and must ultimately 192 return an action that determines how to continue handling the 193 request. 194 195 @table @var 196 @item cls 197 custom value provided by the application with the callback; 198 199 @item request 200 the request to get data for; 201 202 @item parsing_result 203 status of parsing the request body. 204 @end table 205 @end deftypefn 206 207 @deftp {Enumeration} MHD_PostParseResult 208 209 Represents possible outcomes of parsing a client's body. 210 211 @table @code 212 @item MHD_POST_PARSE_RES_OK 213 The POST data parsed successfully and completely. 214 215 @item MHD_POST_PARSE_RES_REQUEST_EMPTY 216 The request had no content or zero-length content. 217 218 @item MHD_POST_PARSE_RES_OK_BAD_TERMINATION 219 The POST data parsed successfully, but has missing or incorrect 220 termination. The last record parsed may thus have incorrect 221 or incomplete data. 222 223 @c FIXME: did I get the distinction right? It is a bit fuzzy. Do we need to distinguish this from the previous case? 224 @item MHD_POST_PARSE_RES_PARTIAL_INVALID_POST_FORMAT 225 Parsing of the POST data is definitively incomplete because the client 226 sent an incorrectly formatted body. The last record parsed has 227 incorrect or incomplete data. 228 Some POST data is available or has been provided via callback. 229 230 @item MHD_POST_PARSE_RES_FAILED_NO_POOL_MEM 231 The POST data cannot be parsed completely because the stream has 232 not enough free memory in the pool. Some POST data may have been parsed. 233 234 @item MHD_POST_PARSE_RES_FAILED_NO_LARGE_BUF_MEM 235 The POST data could not be parsed completely because not 236 enough large shared buffer space was available. 237 Some POST data may have been parsed. 238 239 @item MHD_POST_PARSE_RES_FAILED_UNKNOWN_CNTN_TYPE 240 The POST data could not be parsed because the 241 ``Content-Type:'' specified is not understood by MHD. 242 243 @item MHD_POST_PARSE_RES_FAILED_NO_CNTN_TYPE 244 The POST data cannot be parsed because the 245 ``Content-Type:'' header was not set by the clients. 246 Applications can sometimes work around this by explicitly 247 setting @var{enc} when calling @code{MHD_action_parse_post()} 248 if they see that the ``Content-Type'' was omitted and 249 they know what it is. 250 251 @item MHD_POST_PARSE_RES_FAILED_HEADER_NO_BOUNDARY 252 The POST data cannot be parsed because ``Content-Type:'' 253 request header lacks the required ``boundary'' parameter for 254 ``multipart/form-data''. 255 256 @item MHD_POST_PARSE_RES_FAILED_HEADER_MISFORMED 257 The POST data cannot be parsed because 258 ``Content-Type: multipart/form-data'' 259 request header is malformed. 260 261 @item MHD_POST_PARSE_RES_FAILED_HEADER_NOT_MPART 262 The application set POST encoding to ``multipart/form-data'' 263 via @var{enc}, but the request has no ``Content-Type: multipart/form-data'' 264 header which is required to find the ``boundary'' used in this encoding. 265 266 @item MHD_POST_PARSE_RES_FAILED_INVALID_POST_FORMAT 267 The POST data cannot be parsed because the client's upload 268 did not abide by the format specified for the POST encoding. 269 270 @end table 271 @end deftp 272 273 Once the @code{MHD_action_parse_post()} has called the @var{done_cb}, 274 the application can use the following functions to access the records 275 that MHD could fit into memory. 276 277 @anchor{MHD_request_get_post_data_cb} 278 @deftypefun size_t MHD_request_get_post_data_cb (struct MHD_Request *request, struct MHD_PostDataIterator *iterator, void *iterator_cls) 279 280 Call @var{iterator} on all of the post data from the @var{request}. 281 282 @table @var 283 @item request 284 the request to get data for 285 286 @item iterator 287 callback to call on each header; 288 can be @code{NULL} (then this function will simply just count the records); 289 290 @item iterator_cls 291 extra argument to pass to @var{iterator} 292 @end table 293 294 Returns the number of entries iterated over, zero if no records were 295 available or a postprocessor was not used with @var{request}. 296 @end deftypefun 297 298 @c FIXME: "Field" is probably a bad name, I think we should change it to "Record" everywhere in the API 299 @anchor{MHD_PostDataIterator} 300 @deftypefn {Function Pointer} {enum MHD_Bool} (*MHD_PostDataIterator) (void *cls, const struct MHD_PostField *data) 301 302 Iterator over POST data. The @var{data} pointer is valid only until 303 the application returns from this function. However, the pointers to 304 the strings in @var{data} remain valid until any @code{struct 305 MHD_UploadAction} is provided. If any data is needed beyond this 306 point, it should be copied into an application-managed buffer. 307 308 @table @var 309 @item cls 310 custom value provided by the application with the callback; 311 312 @item data 313 one data record from the body 314 @end table 315 316 The callback must return @code{MHD_YES} to continue iterating 317 or @code{MHD_NO} to abort the iteration. 318 @end deftypefn 319 320 321 @deftp {C Struct} MHD_PostField name value filename content_type transfer_encoding 322 323 Post data record. If any member is not provided/set then pointer to C string is @code{NULL}. If any member is set to empty string then pointer to C string not @code{NULL}, but the @var{len} is zero. 324 325 @table @var 326 @item @code{struct MHD_String} name 327 The name of the record; 328 329 @item @code{struct MHD_StringNullable} value 330 The record's main value; 331 332 @item @code{struct MHD_StringNullable} filename 333 The filename if provided (only for ``multipart/form-data''); 334 335 @item @code{struct MHD_StringNullable} content_type 336 The Content-Type if provided (only for "multipart/form-data"); 337 338 @item @code{struct MHD_StringNullable} transfer_encoding 339 The Transfer-Encoding if provided (only for ``multipart/form-data''). 340 341 @end table 342 @end deftp 343 344 Alternatively, the application can use 345 @code{MHD_request_get_post_data_cb} to just count the number of 346 records and obtain all records without iterating by providing 347 space for the @var{elements} itself and using 348 @code{MHD_request_get_post_data_list()}. 349 350 351 @anchor{MHD_request_get_post_data_list} 352 @deftypefun size_t MHD_request_get_post_data_list (struct MHD_Request *request, size_t num_elements, struct MHD_PostField elements[num_elements]) 353 354 Stores all of the post records from the @var{request} in @var{elements}. 355 356 @table @var 357 @item request 358 the request to get data for 359 360 @item num_elements 361 the number of elements in the @var{elements} array 362 363 @item elements 364 an array of @var{num_elements} where to store the POST records 365 @end table 366 367 Returns the number of elements stored in @var{elements}, 368 zero if no data was stored or a postprocessor was not 369 used with @var{request}. 370 @end deftypefun