libmicrohttpd2

HTTP server C library (MHD 2.x, alpha)
Log | Files | Refs | README | LICENSE

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