mirror of
https://git.gnunet.org/libmicrohttpd.git
synced 2026-09-26 04:09:30 +03:00
WIP POST parser
This commit is contained in:
+184
-28
@@ -147,6 +147,8 @@
|
||||
*/
|
||||
#define MHD_VERSION 0x01990001
|
||||
|
||||
#ifndef MHD_BOOL_DEFINED
|
||||
|
||||
/**
|
||||
* Representation of 'bool' in the public API as stdbool.h may not
|
||||
* always be available and presence of 'bool' keyword may depend on
|
||||
@@ -171,6 +173,10 @@ enum MHD_Bool
|
||||
MHD_YES = 1
|
||||
};
|
||||
|
||||
|
||||
#define MHD_BOOL_DEFINED 1
|
||||
#endif /* ! MHD_BOOL_DEFINED */
|
||||
|
||||
#ifndef MHD_STRINGS_DEFINED
|
||||
|
||||
|
||||
@@ -638,16 +644,46 @@ enum MHD_FIXED_ENUM_MHD_SET_ MHD_StatusCode
|
||||
*/
|
||||
MHD_SC_REQ_COOKIE_INVALID = 40163
|
||||
,
|
||||
/**
|
||||
* Parsing of the POST data is incomplete because client used incorrect
|
||||
* format of POST encoding.
|
||||
* Some POST data is available or has been provided via callback.
|
||||
*/
|
||||
MHD_SC_REQ_POST_PARSE_PARTIAL_INVALID_POST_FORMAT = 40202
|
||||
,
|
||||
/**
|
||||
* The request does not have "Content-Type:" header and POST data cannot
|
||||
* be parsed
|
||||
*/
|
||||
MHD_SC_REQ_POST_PARSE_FAILED_NO_CNTN_TYPE = 40180
|
||||
MHD_SC_REQ_POST_PARSE_FAILED_NO_CNTN_TYPE = 40280
|
||||
,
|
||||
/**
|
||||
* The request has unknown POST encoding specified by "Content-Type:" header
|
||||
*/
|
||||
MHD_SC_REQ_POST_PARSE_FAILED_UNKNOWN_CNTN_TYPE = 40281
|
||||
,
|
||||
/**
|
||||
* The request has "Content-Type: multipart/form-data" header without
|
||||
* "boundary" parameter
|
||||
*/
|
||||
MHD_SC_REQ_POST_PARSE_FAILED_HEADER_NO_BOUNDARY = 40282
|
||||
,
|
||||
/**
|
||||
* The request has "Content-Type: multipart/form-data" header with misformed
|
||||
* data
|
||||
*/
|
||||
MHD_SC_REQ_POST_PARSE_FAILED_HEADER_MISFORMED = 40283
|
||||
,
|
||||
/**
|
||||
* The POST data cannot be parsed because client used incorrect format
|
||||
* of POST encoding.
|
||||
*/
|
||||
MHD_SC_REQ_POST_PARSE_FAILED_INVALID_POST_FORMAT = 40290
|
||||
,
|
||||
/**
|
||||
* The request cannot be processed. Sending error reply.
|
||||
*/
|
||||
MHD_SC_REQ_PROCCESSING_ERR_REPLY = 40200
|
||||
MHD_SC_REQ_PROCCESSING_ERR_REPLY = 41000
|
||||
,
|
||||
|
||||
/* 50000-level errors are because of an error internal
|
||||
@@ -1109,6 +1145,26 @@ enum MHD_FIXED_ENUM_MHD_SET_ MHD_StatusCode
|
||||
*/
|
||||
MHD_SC_ERR_RESPONSE_ALLOCATION_FAILURE = 50250
|
||||
,
|
||||
/**
|
||||
* The request POST data cannot be parsed because stream has not enough
|
||||
* pool memory free.
|
||||
*/
|
||||
MHD_SC_REQ_POST_PARSE_FAILED_NO_POOL_MEM = 50260
|
||||
,
|
||||
/**
|
||||
* The POST data cannot be parsed completely because no "large shared buffer"
|
||||
* space is available.
|
||||
* Some POST data may be parsed.
|
||||
*/
|
||||
MHD_SC_REQ_POST_PARSE_FAILED_NO_LARGE_BUF_MEM = 50261
|
||||
,
|
||||
/**
|
||||
* The application set POST encoding to "multipart/form-data", but the request
|
||||
* has no "Content-Type: multipart/form-data" header which is required
|
||||
* to find "boundary" used in this encoding
|
||||
*/
|
||||
MHD_SC_REQ_POST_PARSE_FAILED_HEADER_NOT_MPART = 50284
|
||||
,
|
||||
/**
|
||||
* The feature is not supported by this MHD build (either
|
||||
* disabled by configure parameters or build platform
|
||||
@@ -4912,7 +4968,8 @@ struct MHD_NameValueKind
|
||||
* is queued. If the data is needed beyond this point, it should be copied.
|
||||
*
|
||||
* @param cls closure
|
||||
* @param nvt the name, the value and the kind of the element
|
||||
* @param nv the name and the value of the element
|
||||
* @param kind the type (kind) of the element
|
||||
* @return #MHD_YES to continue iterating,
|
||||
* #MHD_NO to abort the iteration
|
||||
* @ingroup request
|
||||
@@ -4920,7 +4977,8 @@ struct MHD_NameValueKind
|
||||
typedef enum MHD_Bool
|
||||
(MHD_FN_PAR_NONNULL_ (2)
|
||||
*MHD_NameValueIterator)(void *cls,
|
||||
const struct MHD_NameValueKind *nvt);
|
||||
enum MHD_ValueKind kind,
|
||||
const struct MHD_NameAndValue *nv);
|
||||
|
||||
|
||||
/**
|
||||
@@ -6173,6 +6231,81 @@ MHD_FN_PAR_NONNULL_ (1);
|
||||
#define MHD_action_process_upload_inc(request,uc,uc_cls) \
|
||||
MHD_action_process_upload (request, 0, NULL, NULL, uc, uc_cls)
|
||||
|
||||
#ifndef MHD_POST_PARSE_RESULT_DEFINED
|
||||
|
||||
enum MHD_FIXED_ENUM_MHD_SET_ MHD_PostParseResult
|
||||
{
|
||||
/**
|
||||
* The POST data parse successfully and completely.
|
||||
*/
|
||||
MHD_POST_PARSE_RES_OK = 0
|
||||
,
|
||||
/**
|
||||
* The POST request has no content or zero-length content.
|
||||
*/
|
||||
MHD_POST_PARSE_RES_REQUEST_EMPTY = 1
|
||||
,
|
||||
/**
|
||||
* Parsing of the POST data is incomplete because client used incorrect
|
||||
* format of POST encoding.
|
||||
* Some POST data is available or has been provided via callback.
|
||||
*/
|
||||
MHD_POST_PARSE_RES_PARTIAL_INVALID_POST_FORMAT = 2
|
||||
,
|
||||
/**
|
||||
* The POST data cannot be parsed completely because the stream has
|
||||
* no free pool memory.
|
||||
* Some POST data may be parsed.
|
||||
*/
|
||||
MHD_POST_PARSE_RES_FAILED_NO_POOL_MEM = 60
|
||||
,
|
||||
/**
|
||||
* The POST data cannot be parsed completely because no "large shared buffer"
|
||||
* space is available.
|
||||
* Some POST data may be parsed.
|
||||
*/
|
||||
MHD_POST_PARSE_RES_FAILED_NO_LARGE_BUF_MEM = 61
|
||||
,
|
||||
/**
|
||||
* The POST data cannot be parsed because 'Content-Type:' is unknown.
|
||||
*/
|
||||
MHD_POST_PARSE_RES_FAILED_UNKNOWN_CNTN_TYPE = 80
|
||||
,
|
||||
/**
|
||||
* The POST data cannot be parsed because 'Content-Type:' header is not set.
|
||||
*/
|
||||
MHD_POST_PARSE_RES_FAILED_NO_CNTN_TYPE = 81
|
||||
,
|
||||
/**
|
||||
* The POST data cannot be parsed because "Content-Type:" request header has
|
||||
* no "boundary" parameter for "multipart/form-data"
|
||||
*/
|
||||
MHD_POST_PARSE_RES_FAILED_HEADER_NO_BOUNDARY = 82
|
||||
,
|
||||
/**
|
||||
* The POST data cannot be parsed because "Content-Type: multipart/form-data"
|
||||
* request header is misformed
|
||||
*/
|
||||
MHD_POST_PARSE_RES_FAILED_HEADER_MISFORMED = 83
|
||||
,
|
||||
/**
|
||||
* The application set POST encoding to "multipart/form-data", but the request
|
||||
* has no "Content-Type: multipart/form-data" header which is required
|
||||
* to find "boundary" used in this encoding
|
||||
*/
|
||||
MHD_POST_PARSE_RES_FAILED_HEADER_NOT_MPART = 84
|
||||
,
|
||||
/**
|
||||
* The POST data cannot be parsed because client used incorrect format
|
||||
* of POST encoding.
|
||||
*/
|
||||
MHD_POST_PARSE_RES_FAILED_INVALID_POST_FORMAT = 90
|
||||
|
||||
};
|
||||
|
||||
#define MHD_POST_PARSE_RESULT_DEFINED 1
|
||||
#endif /* ! MHD_POST_PARSE_RESULT_DEFINED */
|
||||
|
||||
#ifndef MHD_POST_DATA_READER_DEFINED
|
||||
|
||||
/**
|
||||
@@ -6182,15 +6315,24 @@ MHD_FN_PAR_NONNULL_ (1);
|
||||
*
|
||||
* @param req the request
|
||||
* @param cls user-specified closure
|
||||
* @param name 0-terminated key for the value
|
||||
* @param filename name of the uploaded file, NULL if not known
|
||||
* @param content_type mime-type of the data, NULL if not known
|
||||
* @param encoding the encoding of the data
|
||||
* @param data pointer to @a size bytes of data at the
|
||||
* specified @a off offset,
|
||||
* NOT zero-terminated
|
||||
* @param off offset of data in the overall value
|
||||
* @param size number of bytes in @a data available
|
||||
* @param name the name of the POST field
|
||||
* @param filename the name of the uploaded file, @a cstr member is NULL if not
|
||||
* known / not provided
|
||||
* @param content_type the mime-type of the data, cstr member is NULL if not
|
||||
* known / not provided
|
||||
* @param encoding the encoding of the data, cstr member is NULL if not known /
|
||||
* not provided
|
||||
* @param size the number of bytes in @a data available, may be zero if
|
||||
* the @a final_data is #MHD_YES
|
||||
* @param data the pointer to @a size bytes of data at the specified
|
||||
* @a off offset, NOT zero-terminated
|
||||
* @param off the offset of @a data in the overall value, always equal to
|
||||
* the sum of sizes of previous calls for the same field / file;
|
||||
* client may provide more than one field with the same name and
|
||||
* the same filename, the new filed (or file) is indicated by zero
|
||||
* value of @a off (and the end is indicated by @a final_data)
|
||||
* @param final_data if set to #MHD_YES then full field data is provided,
|
||||
* if set to #MHD_NO then more field data may be provided
|
||||
* @return action specifying how to proceed:
|
||||
* #MHD_upload_action_continue() if all is well,
|
||||
* #MHD_upload_action_suspend() to stop reading the upload until
|
||||
@@ -6209,9 +6351,10 @@ typedef const struct MHD_UploadAction *
|
||||
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,
|
||||
size_t size);
|
||||
enum MHD_Bool final_data);
|
||||
|
||||
|
||||
/**
|
||||
@@ -6219,15 +6362,14 @@ typedef const struct MHD_UploadAction *
|
||||
* of the postprocessor upload data.
|
||||
* @param req the request
|
||||
* @param cls the closure
|
||||
* @param parsing_result the result of POST data parsing: MHD_SC_OK,
|
||||
MHD_SC_REQ_POST_PARSE_FAILED_NO_CNTN_TYPE or ...
|
||||
* @param parsing_result the result of POST data parsing
|
||||
* @return the action to proceed
|
||||
*/
|
||||
typedef const struct MHD_UploadAction *
|
||||
(MHD_FN_PAR_NONNULL_ (1)
|
||||
*MHD_PostDataFinished) (struct MHD_Request *req,
|
||||
void *cls,
|
||||
enum MHD_StatusCode parsing_result);
|
||||
enum MHD_PostParseResult parsing_result);
|
||||
|
||||
#define MHD_POST_DATA_READER_DEFINED 1
|
||||
#endif /* ! MHD_POST_DATA_READER_DEFINED */
|
||||
@@ -6250,8 +6392,12 @@ typedef const struct MHD_UploadAction *
|
||||
* request POST data. Within the set limit the buffer is
|
||||
* allocated automatically from the "large" shared memory
|
||||
* pool if necessary.
|
||||
* @param auto_stream_size the size above which values are not buffered and
|
||||
* processed by the @a steam_reader automatically,
|
||||
* @param auto_stream_size the size of the field (in encoded form) above which
|
||||
* values are not buffered and processed by
|
||||
* the @a steam_reader automatically;
|
||||
* useful to have large data (like file uploads)
|
||||
* processed incrementally, while keeping buffer space
|
||||
* for small fields only;
|
||||
* ignored if @a stream_reader is NULL
|
||||
* @param enc the data encoding to use,
|
||||
* use #MHD_HTTP_POST_ENCODING_OTHER to detect automatically
|
||||
@@ -6283,44 +6429,54 @@ MHD_action_parse_post (struct MHD_Request *request,
|
||||
MHD_FN_PAR_NONNULL_ (1);
|
||||
|
||||
|
||||
#ifndef MHD_POSTFILED_DEFINED
|
||||
|
||||
/**
|
||||
* Post data element.
|
||||
* If any member is not provided/set then pointer to C string is NULL.
|
||||
* If any member is set to empty string then pointer to C string not NULL,
|
||||
* but the length is zero.
|
||||
*/
|
||||
struct MHD_PostData
|
||||
struct MHD_PostField
|
||||
{
|
||||
/**
|
||||
* The name of the field
|
||||
*/
|
||||
struct MHD_String name;
|
||||
/**
|
||||
* The field data
|
||||
* If not set or defined then to C string is NULL.
|
||||
* If set to empty string then pointer to C string not NULL,
|
||||
* but the length is zero.
|
||||
*/
|
||||
struct MHD_StringNullable value;
|
||||
/**
|
||||
* The filename if provided (only for "multipart/form-data")
|
||||
* If not set or defined then to C string is NULL.
|
||||
* If set to empty string then pointer to C string not NULL,
|
||||
* but the length is zero.
|
||||
*/
|
||||
struct MHD_StringNullable filename;
|
||||
/**
|
||||
* The Content-Type if provided (only for "multipart/form-data")
|
||||
* If not set or defined then to C string is NULL.
|
||||
* If set to empty string then pointer to C string not NULL,
|
||||
* but the length is zero.
|
||||
*/
|
||||
struct MHD_StringNullable content_type;
|
||||
/**
|
||||
* The Transfer-Encoding if provided (only for "multipart/form-data")
|
||||
* If not set or defined then to C string is NULL.
|
||||
* If set to empty string then pointer to C string not NULL,
|
||||
* but the length is zero.
|
||||
*/
|
||||
struct MHD_StringNullable transfer_encoding;
|
||||
/**
|
||||
* The field data
|
||||
* If not set or defined then to C string is NULL.
|
||||
* If set to empty string then pointer to C string not NULL,
|
||||
*/
|
||||
struct MHD_StringNullable value;
|
||||
};
|
||||
|
||||
#define MHD_POSTFILED_DEFINED 1
|
||||
#endif /* ! MHD_POSTFILED_DEFINED */
|
||||
|
||||
|
||||
/**
|
||||
* Iterator over POST data.
|
||||
*
|
||||
@@ -6336,7 +6492,7 @@ struct MHD_PostData
|
||||
typedef enum MHD_Bool
|
||||
(MHD_FN_PAR_NONNULL_ (2)
|
||||
*MHD_PostDataIterator)(void *cls,
|
||||
const struct MHD_PostData *data);
|
||||
const struct MHD_PostField *data);
|
||||
|
||||
/**
|
||||
* Get all of the post data from the request via request.
|
||||
@@ -6372,7 +6528,7 @@ MHD_EXTERN_ size_t
|
||||
MHD_request_get_post_data_list (
|
||||
struct MHD_Request *request,
|
||||
size_t num_elements,
|
||||
struct MHD_PostData elements[MHD_FN_PAR_DYN_ARR_SIZE_ (num_elements)])
|
||||
struct MHD_PostField elements[MHD_FN_PAR_DYN_ARR_SIZE_ (num_elements)])
|
||||
MHD_FN_PAR_NONNULL_ (1)
|
||||
MHD_FN_PAR_NONNULL_ (3) MHD_FN_PAR_OUT_SIZE_ (3,2);
|
||||
|
||||
|
||||
@@ -611,7 +611,8 @@ struct MHD_NameValueKind
|
||||
* is queued. If the data is needed beyond this point, it should be copied.
|
||||
*
|
||||
* @param cls closure
|
||||
* @param nvt the name, the value and the kind of the element
|
||||
* @param nv the name and the value of the element
|
||||
* @param kind the type (kind) of the element
|
||||
* @return #MHD_YES to continue iterating,
|
||||
* #MHD_NO to abort the iteration
|
||||
* @ingroup request
|
||||
@@ -619,7 +620,8 @@ struct MHD_NameValueKind
|
||||
typedef enum MHD_Bool
|
||||
(MHD_FN_PAR_NONNULL_ (2)
|
||||
*MHD_NameValueIterator)(void *cls,
|
||||
const struct MHD_NameValueKind *nvt);
|
||||
enum MHD_ValueKind kind,
|
||||
const struct MHD_NameAndValue *nv);
|
||||
|
||||
|
||||
/**
|
||||
@@ -1872,6 +1874,81 @@ MHD_FN_PAR_NONNULL_ (1);
|
||||
#define MHD_action_process_upload_inc(request,uc,uc_cls) \
|
||||
MHD_action_process_upload (request, 0, NULL, NULL, uc, uc_cls)
|
||||
|
||||
#ifndef MHD_POST_PARSE_RESULT_DEFINED
|
||||
|
||||
enum MHD_FIXED_ENUM_MHD_SET_ MHD_PostParseResult
|
||||
{
|
||||
/**
|
||||
* The POST data parse successfully and completely.
|
||||
*/
|
||||
MHD_POST_PARSE_RES_OK = 0
|
||||
,
|
||||
/**
|
||||
* The POST request has no content or zero-length content.
|
||||
*/
|
||||
MHD_POST_PARSE_RES_REQUEST_EMPTY = 1
|
||||
,
|
||||
/**
|
||||
* Parsing of the POST data is incomplete because client used incorrect
|
||||
* format of POST encoding.
|
||||
* Some POST data is available or has been provided via callback.
|
||||
*/
|
||||
MHD_POST_PARSE_RES_PARTIAL_INVALID_POST_FORMAT = 2
|
||||
,
|
||||
/**
|
||||
* The POST data cannot be parsed completely because the stream has
|
||||
* no free pool memory.
|
||||
* Some POST data may be parsed.
|
||||
*/
|
||||
MHD_POST_PARSE_RES_FAILED_NO_POOL_MEM = 60
|
||||
,
|
||||
/**
|
||||
* The POST data cannot be parsed completely because no "large shared buffer"
|
||||
* space is available.
|
||||
* Some POST data may be parsed.
|
||||
*/
|
||||
MHD_POST_PARSE_RES_FAILED_NO_LARGE_BUF_MEM = 61
|
||||
,
|
||||
/**
|
||||
* The POST data cannot be parsed because 'Content-Type:' is unknown.
|
||||
*/
|
||||
MHD_POST_PARSE_RES_FAILED_UNKNOWN_CNTN_TYPE = 80
|
||||
,
|
||||
/**
|
||||
* The POST data cannot be parsed because 'Content-Type:' header is not set.
|
||||
*/
|
||||
MHD_POST_PARSE_RES_FAILED_NO_CNTN_TYPE = 81
|
||||
,
|
||||
/**
|
||||
* The POST data cannot be parsed because "Content-Type:" request header has
|
||||
* no "boundary" parameter for "multipart/form-data"
|
||||
*/
|
||||
MHD_POST_PARSE_RES_FAILED_HEADER_NO_BOUNDARY = 82
|
||||
,
|
||||
/**
|
||||
* The POST data cannot be parsed because "Content-Type: multipart/form-data"
|
||||
* request header is misformed
|
||||
*/
|
||||
MHD_POST_PARSE_RES_FAILED_HEADER_MISFORMED = 83
|
||||
,
|
||||
/**
|
||||
* The application set POST encoding to "multipart/form-data", but the request
|
||||
* has no "Content-Type: multipart/form-data" header which is required
|
||||
* to find "boundary" used in this encoding
|
||||
*/
|
||||
MHD_POST_PARSE_RES_FAILED_HEADER_NOT_MPART = 84
|
||||
,
|
||||
/**
|
||||
* The POST data cannot be parsed because client used incorrect format
|
||||
* of POST encoding.
|
||||
*/
|
||||
MHD_POST_PARSE_RES_FAILED_INVALID_POST_FORMAT = 90
|
||||
|
||||
};
|
||||
|
||||
#define MHD_POST_PARSE_RESULT_DEFINED 1
|
||||
#endif /* ! MHD_POST_PARSE_RESULT_DEFINED */
|
||||
|
||||
#ifndef MHD_POST_DATA_READER_DEFINED
|
||||
|
||||
/**
|
||||
@@ -1881,15 +1958,24 @@ MHD_FN_PAR_NONNULL_ (1);
|
||||
*
|
||||
* @param req the request
|
||||
* @param cls user-specified closure
|
||||
* @param name 0-terminated key for the value
|
||||
* @param filename name of the uploaded file, NULL if not known
|
||||
* @param content_type mime-type of the data, NULL if not known
|
||||
* @param encoding the encoding of the data
|
||||
* @param data pointer to @a size bytes of data at the
|
||||
* specified @a off offset,
|
||||
* NOT zero-terminated
|
||||
* @param off offset of data in the overall value
|
||||
* @param size number of bytes in @a data available
|
||||
* @param name the name of the POST field
|
||||
* @param filename the name of the uploaded file, @a cstr member is NULL if not
|
||||
* known / not provided
|
||||
* @param content_type the mime-type of the data, cstr member is NULL if not
|
||||
* known / not provided
|
||||
* @param encoding the encoding of the data, cstr member is NULL if not known /
|
||||
* not provided
|
||||
* @param size the number of bytes in @a data available, may be zero if
|
||||
* the @a final_data is #MHD_YES
|
||||
* @param data the pointer to @a size bytes of data at the specified
|
||||
* @a off offset, NOT zero-terminated
|
||||
* @param off the offset of @a data in the overall value, always equal to
|
||||
* the sum of sizes of previous calls for the same field / file;
|
||||
* client may provide more than one field with the same name and
|
||||
* the same filename, the new filed (or file) is indicated by zero
|
||||
* value of @a off (and the end is indicated by @a final_data)
|
||||
* @param final_data if set to #MHD_YES then full field data is provided,
|
||||
* if set to #MHD_NO then more field data may be provided
|
||||
* @return action specifying how to proceed:
|
||||
* #MHD_upload_action_continue() if all is well,
|
||||
* #MHD_upload_action_suspend() to stop reading the upload until
|
||||
@@ -1908,9 +1994,10 @@ typedef const struct MHD_UploadAction *
|
||||
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,
|
||||
size_t size);
|
||||
enum MHD_Bool final_data);
|
||||
|
||||
|
||||
/**
|
||||
@@ -1918,15 +2005,14 @@ typedef const struct MHD_UploadAction *
|
||||
* of the postprocessor upload data.
|
||||
* @param req the request
|
||||
* @param cls the closure
|
||||
* @param parsing_result the result of POST data parsing: MHD_SC_OK,
|
||||
MHD_SC_REQ_POST_PARSE_FAILED_NO_CNTN_TYPE or ...
|
||||
* @param parsing_result the result of POST data parsing
|
||||
* @return the action to proceed
|
||||
*/
|
||||
typedef const struct MHD_UploadAction *
|
||||
(MHD_FN_PAR_NONNULL_ (1)
|
||||
*MHD_PostDataFinished) (struct MHD_Request *req,
|
||||
void *cls,
|
||||
enum MHD_StatusCode parsing_result);
|
||||
enum MHD_PostParseResult parsing_result);
|
||||
|
||||
#define MHD_POST_DATA_READER_DEFINED 1
|
||||
#endif /* ! MHD_POST_DATA_READER_DEFINED */
|
||||
@@ -1949,8 +2035,12 @@ typedef const struct MHD_UploadAction *
|
||||
* request POST data. Within the set limit the buffer is
|
||||
* allocated automatically from the "large" shared memory
|
||||
* pool if necessary.
|
||||
* @param auto_stream_size the size above which values are not buffered and
|
||||
* processed by the @a steam_reader automatically,
|
||||
* @param auto_stream_size the size of the field (in encoded form) above which
|
||||
* values are not buffered and processed by
|
||||
* the @a steam_reader automatically;
|
||||
* useful to have large data (like file uploads)
|
||||
* processed incrementally, while keeping buffer space
|
||||
* for small fields only;
|
||||
* ignored if @a stream_reader is NULL
|
||||
* @param enc the data encoding to use,
|
||||
* use #MHD_HTTP_POST_ENCODING_OTHER to detect automatically
|
||||
@@ -1982,44 +2072,54 @@ MHD_action_parse_post (struct MHD_Request *request,
|
||||
MHD_FN_PAR_NONNULL_ (1);
|
||||
|
||||
|
||||
#ifndef MHD_POSTFILED_DEFINED
|
||||
|
||||
/**
|
||||
* Post data element.
|
||||
* If any member is not provided/set then pointer to C string is NULL.
|
||||
* If any member is set to empty string then pointer to C string not NULL,
|
||||
* but the length is zero.
|
||||
*/
|
||||
struct MHD_PostData
|
||||
struct MHD_PostField
|
||||
{
|
||||
/**
|
||||
* The name of the field
|
||||
*/
|
||||
struct MHD_String name;
|
||||
/**
|
||||
* The field data
|
||||
* If not set or defined then to C string is NULL.
|
||||
* If set to empty string then pointer to C string not NULL,
|
||||
* but the length is zero.
|
||||
*/
|
||||
struct MHD_StringNullable value;
|
||||
/**
|
||||
* The filename if provided (only for "multipart/form-data")
|
||||
* If not set or defined then to C string is NULL.
|
||||
* If set to empty string then pointer to C string not NULL,
|
||||
* but the length is zero.
|
||||
*/
|
||||
struct MHD_StringNullable filename;
|
||||
/**
|
||||
* The Content-Type if provided (only for "multipart/form-data")
|
||||
* If not set or defined then to C string is NULL.
|
||||
* If set to empty string then pointer to C string not NULL,
|
||||
* but the length is zero.
|
||||
*/
|
||||
struct MHD_StringNullable content_type;
|
||||
/**
|
||||
* The Transfer-Encoding if provided (only for "multipart/form-data")
|
||||
* If not set or defined then to C string is NULL.
|
||||
* If set to empty string then pointer to C string not NULL,
|
||||
* but the length is zero.
|
||||
*/
|
||||
struct MHD_StringNullable transfer_encoding;
|
||||
/**
|
||||
* The field data
|
||||
* If not set or defined then to C string is NULL.
|
||||
* If set to empty string then pointer to C string not NULL,
|
||||
*/
|
||||
struct MHD_StringNullable value;
|
||||
};
|
||||
|
||||
#define MHD_POSTFILED_DEFINED 1
|
||||
#endif /* ! MHD_POSTFILED_DEFINED */
|
||||
|
||||
|
||||
/**
|
||||
* Iterator over POST data.
|
||||
*
|
||||
@@ -2035,7 +2135,7 @@ struct MHD_PostData
|
||||
typedef enum MHD_Bool
|
||||
(MHD_FN_PAR_NONNULL_ (2)
|
||||
*MHD_PostDataIterator)(void *cls,
|
||||
const struct MHD_PostData *data);
|
||||
const struct MHD_PostField *data);
|
||||
|
||||
/**
|
||||
* Get all of the post data from the request via request.
|
||||
@@ -2071,7 +2171,7 @@ MHD_EXTERN_ size_t
|
||||
MHD_request_get_post_data_list (
|
||||
struct MHD_Request *request,
|
||||
size_t num_elements,
|
||||
struct MHD_PostData elements[MHD_FN_PAR_DYN_ARR_SIZE_ (num_elements)])
|
||||
struct MHD_PostField elements[MHD_FN_PAR_DYN_ARR_SIZE_ (num_elements)])
|
||||
MHD_FN_PAR_NONNULL_ (1)
|
||||
MHD_FN_PAR_NONNULL_ (3) MHD_FN_PAR_OUT_SIZE_ (3,2);
|
||||
|
||||
|
||||
@@ -147,6 +147,8 @@
|
||||
*/
|
||||
#define MHD_VERSION 0x01990001
|
||||
|
||||
#ifndef MHD_BOOL_DEFINED
|
||||
|
||||
/**
|
||||
* Representation of 'bool' in the public API as stdbool.h may not
|
||||
* always be available and presence of 'bool' keyword may depend on
|
||||
@@ -171,6 +173,10 @@ enum MHD_Bool
|
||||
MHD_YES = 1
|
||||
};
|
||||
|
||||
|
||||
#define MHD_BOOL_DEFINED 1
|
||||
#endif /* ! MHD_BOOL_DEFINED */
|
||||
|
||||
#ifndef MHD_STRINGS_DEFINED
|
||||
|
||||
|
||||
@@ -638,16 +644,46 @@ enum MHD_FIXED_ENUM_MHD_SET_ MHD_StatusCode
|
||||
*/
|
||||
MHD_SC_REQ_COOKIE_INVALID = 40163
|
||||
,
|
||||
/**
|
||||
* Parsing of the POST data is incomplete because client used incorrect
|
||||
* format of POST encoding.
|
||||
* Some POST data is available or has been provided via callback.
|
||||
*/
|
||||
MHD_SC_REQ_POST_PARSE_PARTIAL_INVALID_POST_FORMAT = 40202
|
||||
,
|
||||
/**
|
||||
* The request does not have "Content-Type:" header and POST data cannot
|
||||
* be parsed
|
||||
*/
|
||||
MHD_SC_REQ_POST_PARSE_FAILED_NO_CNTN_TYPE = 40180
|
||||
MHD_SC_REQ_POST_PARSE_FAILED_NO_CNTN_TYPE = 40280
|
||||
,
|
||||
/**
|
||||
* The request has unknown POST encoding specified by "Content-Type:" header
|
||||
*/
|
||||
MHD_SC_REQ_POST_PARSE_FAILED_UNKNOWN_CNTN_TYPE = 40281
|
||||
,
|
||||
/**
|
||||
* The request has "Content-Type: multipart/form-data" header without
|
||||
* "boundary" parameter
|
||||
*/
|
||||
MHD_SC_REQ_POST_PARSE_FAILED_HEADER_NO_BOUNDARY = 40282
|
||||
,
|
||||
/**
|
||||
* The request has "Content-Type: multipart/form-data" header with misformed
|
||||
* data
|
||||
*/
|
||||
MHD_SC_REQ_POST_PARSE_FAILED_HEADER_MISFORMED = 40283
|
||||
,
|
||||
/**
|
||||
* The POST data cannot be parsed because client used incorrect format
|
||||
* of POST encoding.
|
||||
*/
|
||||
MHD_SC_REQ_POST_PARSE_FAILED_INVALID_POST_FORMAT = 40290
|
||||
,
|
||||
/**
|
||||
* The request cannot be processed. Sending error reply.
|
||||
*/
|
||||
MHD_SC_REQ_PROCCESSING_ERR_REPLY = 40200
|
||||
MHD_SC_REQ_PROCCESSING_ERR_REPLY = 41000
|
||||
,
|
||||
|
||||
/* 50000-level errors are because of an error internal
|
||||
@@ -1109,6 +1145,26 @@ enum MHD_FIXED_ENUM_MHD_SET_ MHD_StatusCode
|
||||
*/
|
||||
MHD_SC_ERR_RESPONSE_ALLOCATION_FAILURE = 50250
|
||||
,
|
||||
/**
|
||||
* The request POST data cannot be parsed because stream has not enough
|
||||
* pool memory free.
|
||||
*/
|
||||
MHD_SC_REQ_POST_PARSE_FAILED_NO_POOL_MEM = 50260
|
||||
,
|
||||
/**
|
||||
* The POST data cannot be parsed completely because no "large shared buffer"
|
||||
* space is available.
|
||||
* Some POST data may be parsed.
|
||||
*/
|
||||
MHD_SC_REQ_POST_PARSE_FAILED_NO_LARGE_BUF_MEM = 50261
|
||||
,
|
||||
/**
|
||||
* The application set POST encoding to "multipart/form-data", but the request
|
||||
* has no "Content-Type: multipart/form-data" header which is required
|
||||
* to find "boundary" used in this encoding
|
||||
*/
|
||||
MHD_SC_REQ_POST_PARSE_FAILED_HEADER_NOT_MPART = 50284
|
||||
,
|
||||
/**
|
||||
* The feature is not supported by this MHD build (either
|
||||
* disabled by configure parameters or build platform
|
||||
|
||||
@@ -36,6 +36,7 @@ libmicrohttpd2_la_SOURCES = \
|
||||
mhd_sockets_funcs.c mhd_sockets_funcs.h \
|
||||
mhd_socket_error.c mhd_socket_error.h \
|
||||
mhd_atomic_counter.c mhd_atomic_counter.h \
|
||||
mhd_bool.h \
|
||||
mhd_str.c mhd_str.h \
|
||||
mhd_str_macros.h mhd_str_types.h \
|
||||
mhd_buffer.h \
|
||||
@@ -90,6 +91,15 @@ libmicrohttpd2_la_SOURCES += \
|
||||
compat_calloc.c
|
||||
endif
|
||||
|
||||
post_parser_files = \
|
||||
http_post_enc.h \
|
||||
mhd_post_parser.h mhd_post_result.h mhd_postfield.h \
|
||||
post_parser_funcs.c post_parser_funcs.h
|
||||
|
||||
if HAVE_POST_PARSER
|
||||
libmicrohttpd2_la_SOURCES += $(post_parser_files)
|
||||
endif
|
||||
|
||||
|
||||
libmicrohttpd2_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) $(MHD_LIB_CPPFLAGS) $(MHD_TLS_LIB_CPPFLAGS) \
|
||||
|
||||
+11
-11
@@ -120,11 +120,11 @@ mhd_daemon_get_lbuf (struct MHD_Daemon *restrict d,
|
||||
if (! mhd_daemon_claim_lbuf (d, requested_size))
|
||||
{
|
||||
buf->size = 0;
|
||||
buf->buf = NULL;
|
||||
buf->data = NULL;
|
||||
return false;
|
||||
}
|
||||
buf->buf = (char *) malloc (requested_size);
|
||||
if (NULL == buf->buf)
|
||||
buf->data = (char *) malloc (requested_size);
|
||||
if (NULL == buf->data)
|
||||
{
|
||||
buf->size = 0;
|
||||
mhd_daemon_reclaim_lbuf (d, requested_size);
|
||||
@@ -142,23 +142,23 @@ mhd_daemon_grow_lbuf (struct MHD_Daemon *restrict d,
|
||||
struct mhd_Buffer *restrict buf)
|
||||
{
|
||||
void *new_alloc;
|
||||
mhd_assert (NULL != buf->buf || 0 == buf->size);
|
||||
mhd_assert (0 != buf->size || NULL == buf->buf);
|
||||
mhd_assert (NULL != buf->data || 0 == buf->size);
|
||||
mhd_assert (0 != buf->size || NULL == buf->data);
|
||||
|
||||
if (! mhd_daemon_claim_lbuf (d, grow_size))
|
||||
return false;
|
||||
|
||||
if (NULL == buf->buf)
|
||||
if (NULL == buf->data)
|
||||
new_alloc = malloc (grow_size);
|
||||
else
|
||||
new_alloc = realloc (buf->buf, buf->size + grow_size);
|
||||
new_alloc = realloc (buf->data, buf->size + grow_size);
|
||||
if (NULL == new_alloc)
|
||||
{
|
||||
mhd_daemon_reclaim_lbuf (d, grow_size);
|
||||
return false;
|
||||
}
|
||||
|
||||
buf->buf = (char *) new_alloc;
|
||||
buf->data = (char *) new_alloc;
|
||||
buf->size += grow_size;
|
||||
|
||||
return true;
|
||||
@@ -172,11 +172,11 @@ mhd_daemon_free_lbuf (struct MHD_Daemon *restrict d,
|
||||
{
|
||||
if (0 == buf->size)
|
||||
{
|
||||
mhd_assert (NULL == buf->buf);
|
||||
mhd_assert (NULL == buf->data);
|
||||
return;
|
||||
}
|
||||
free (buf->buf);
|
||||
buf->buf = NULL;
|
||||
free (buf->data);
|
||||
buf->data = NULL;
|
||||
mhd_daemon_reclaim_lbuf (d, buf->size);
|
||||
buf->size = 0;
|
||||
}
|
||||
|
||||
@@ -264,6 +264,7 @@ close_all_daemon_conns (struct MHD_Daemon *d)
|
||||
c = mhd_DLINKEDL_GET_LAST (&(d->conns),all_conn))
|
||||
{
|
||||
mhd_conn_pre_close_d_shutdown (c);
|
||||
mhd_conn_pre_clean (c);
|
||||
mhd_conn_close_final (c);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
This file is part of GNU libmicrohttpd
|
||||
Copyright (C) 2024 Evgeny Grin (Karlson2k)
|
||||
|
||||
GNU libmicrohttpd is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
GNU libmicrohttpd is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file src/mhd2/http_post_enc.h
|
||||
* @brief The definition of the enum for POST encoding types
|
||||
* @author Karlson2k (Evgeny Grin)
|
||||
*/
|
||||
|
||||
#ifndef MHD_HTTP_POST_ENC_H
|
||||
#define MHD_HTTP_POST_ENC_H 1
|
||||
|
||||
#include "mhd_sys_options.h"
|
||||
|
||||
|
||||
#ifndef MHD_HTTP_POSTENCODING_DEFINED
|
||||
|
||||
/**
|
||||
* @brief Possible encodings for HTML forms submitted as HTTP POST requests
|
||||
*
|
||||
* @defgroup postenc HTTP POST encodings
|
||||
* See also: https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#form-submission-2
|
||||
* @{
|
||||
*/
|
||||
enum MHD_FIXED_ENUM_MHD_APP_SET_ MHD_HTTP_PostEncoding
|
||||
{
|
||||
/**
|
||||
* No post encoding / broken data / unknown encoding
|
||||
*/
|
||||
MHD_HTTP_POST_ENCODING_OTHER = 0
|
||||
,
|
||||
/**
|
||||
* "application/x-www-form-urlencoded"
|
||||
* See https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#url-encoded-form-data
|
||||
* See https://url.spec.whatwg.org/#application/x-www-form-urlencoded
|
||||
* See https://datatracker.ietf.org/doc/html/rfc3986#section-2
|
||||
*/
|
||||
MHD_HTTP_POST_ENCODING_FORM_URLENCODED = 1
|
||||
,
|
||||
/**
|
||||
* "multipart/form-data"
|
||||
* See https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#multipart-form-data
|
||||
* See https://www.rfc-editor.org/rfc/rfc7578.html
|
||||
*/
|
||||
MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA = 2
|
||||
,
|
||||
/**
|
||||
* "text/plain"
|
||||
* Introduced by HTML5
|
||||
* See https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#plain-text-form-data
|
||||
* @warning Format is ambiguous. Do not use unless there is a very strong reason.
|
||||
*/
|
||||
MHD_HTTP_POST_ENCODING_TEXT_PLAIN = 3
|
||||
};
|
||||
|
||||
|
||||
/** @} */ /* end of group postenc */
|
||||
|
||||
# define MHD_HTTP_POSTENCODING_DEFINED 1
|
||||
#endif /* ! MHD_HTTP_POSTENCODING_DEFINED */
|
||||
|
||||
|
||||
|
||||
#endif /* ! MHD_HTTP_POST_ENC_H */
|
||||
@@ -36,7 +36,8 @@
|
||||
#include "http_post_enc.h"
|
||||
|
||||
#ifdef HAVE_POST_PARSER
|
||||
# include "mhd_public_api.h"
|
||||
# include "mhd_bool.h"
|
||||
# include "mhd_post_result.h"
|
||||
#endif
|
||||
|
||||
|
||||
@@ -146,16 +147,16 @@ typedef const struct MHD_UploadAction *
|
||||
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,
|
||||
size_t size);
|
||||
|
||||
enum MHD_Bool final_data);
|
||||
|
||||
typedef const struct MHD_UploadAction *
|
||||
(MHD_FN_PAR_NONNULL_ (1)
|
||||
*MHD_PostDataFinished) (struct MHD_Request *req,
|
||||
void *cls,
|
||||
enum MHD_StatusCode parsing_result);
|
||||
enum MHD_PostParseResult parsing_result);
|
||||
|
||||
#define MHD_POST_DATA_READER_DEFINED 1
|
||||
#endif /* ! MHD_POST_DATA_READER_DEFINED */
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
This file is part of GNU libmicrohttpd
|
||||
Copyright (C) 2024 Christian Grothoff
|
||||
Copyright (C) 2024 Evgeny Grin (Karlson2k)
|
||||
|
||||
GNU libmicrohttpd is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
GNU libmicrohttpd is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file src/mhd2/mhd_bool.h
|
||||
* @brief The definition of the enum MHD_Bool, which is used in public API
|
||||
* @author Karlson2k (Evgeny Grin)
|
||||
*/
|
||||
|
||||
#ifndef MHD_BOOL_H
|
||||
#define MHD_BOOL_H 1
|
||||
|
||||
#include "mhd_sys_options.h"
|
||||
|
||||
#ifndef MHD_BOOL_DEFINED
|
||||
|
||||
enum MHD_Bool
|
||||
{
|
||||
/**
|
||||
* MHD-internal return code for "NO".
|
||||
*/
|
||||
MHD_NO = 0
|
||||
,
|
||||
/**
|
||||
* MHD-internal return code for "YES". All non-zero values
|
||||
* will be interpreted as "YES", but MHD will only ever
|
||||
* return #MHD_YES or #MHD_NO.
|
||||
*/
|
||||
MHD_YES = 1
|
||||
};
|
||||
|
||||
|
||||
#define MHD_BOOL_DEFINED 1
|
||||
#endif /* ! MHD_BOOL_DEFINED */
|
||||
|
||||
#endif /* ! MHD_BOOL_H */
|
||||
+20
-4
@@ -31,19 +31,35 @@
|
||||
#include "sys_base_types.h"
|
||||
|
||||
/**
|
||||
* The buffer with size
|
||||
* The buffer with the size
|
||||
*/
|
||||
struct mhd_Buffer
|
||||
{
|
||||
/**
|
||||
* The size of the allocated @a buf buffer
|
||||
* The size of the data or the allocation pointed by @a buf buffer
|
||||
*/
|
||||
size_t size;
|
||||
|
||||
/**
|
||||
* The pointer to the allocation
|
||||
* The pointer to the data or the allocation
|
||||
*/
|
||||
char *buf;
|
||||
char *data;
|
||||
};
|
||||
|
||||
/**
|
||||
* The data with the size
|
||||
*/
|
||||
struct mhd_BufferConst
|
||||
{
|
||||
/**
|
||||
* The size of the data pointed by @a buf buffer
|
||||
*/
|
||||
size_t size;
|
||||
|
||||
/**
|
||||
* The pointer to the data
|
||||
*/
|
||||
const char *data;
|
||||
};
|
||||
|
||||
#endif /* ! MHD_BUFFER_H */
|
||||
|
||||
+52
-46
@@ -201,133 +201,139 @@ enum MHD_FIXED_ENUM_ MHD_CONNECTION_STATE
|
||||
* Connection just started (no headers received).
|
||||
* Waiting for the line with the request type, URL and version.
|
||||
*/
|
||||
MHD_CONNECTION_INIT = 0,
|
||||
|
||||
MHD_CONNECTION_INIT = 0
|
||||
,
|
||||
/**
|
||||
* Part of the request line was received.
|
||||
* Wait for complete line.
|
||||
*/
|
||||
MHD_CONNECTION_REQ_LINE_RECEIVING,
|
||||
|
||||
MHD_CONNECTION_REQ_LINE_RECEIVING
|
||||
,
|
||||
/**
|
||||
* We got the URL (and request type and version). Wait for a header line.
|
||||
*
|
||||
* A milestone state. No received data is processed in this state.
|
||||
*/
|
||||
MHD_CONNECTION_REQ_LINE_RECEIVED,
|
||||
|
||||
MHD_CONNECTION_REQ_LINE_RECEIVED
|
||||
,
|
||||
/**
|
||||
* Receiving request headers. Wait for the rest of the headers.
|
||||
*/
|
||||
MHD_CONNECTION_REQ_HEADERS_RECEIVING,
|
||||
|
||||
MHD_CONNECTION_REQ_HEADERS_RECEIVING
|
||||
,
|
||||
/**
|
||||
* We got the request headers. Process them.
|
||||
*/
|
||||
MHD_CONNECTION_HEADERS_RECEIVED,
|
||||
|
||||
MHD_CONNECTION_HEADERS_RECEIVED
|
||||
,
|
||||
/**
|
||||
* We have processed the request headers. Call application callback.
|
||||
*/
|
||||
MHD_CONNECTION_HEADERS_PROCESSED,
|
||||
|
||||
MHD_CONNECTION_HEADERS_PROCESSED
|
||||
,
|
||||
/**
|
||||
* We have processed the headers and need to send 100 CONTINUE.
|
||||
*/
|
||||
MHD_CONNECTION_CONTINUE_SENDING,
|
||||
|
||||
MHD_CONNECTION_CONTINUE_SENDING
|
||||
,
|
||||
/**
|
||||
* We have sent 100 CONTINUE (or do not need to). Read the message body.
|
||||
*/
|
||||
MHD_CONNECTION_BODY_RECEIVING,
|
||||
|
||||
MHD_CONNECTION_BODY_RECEIVING
|
||||
,
|
||||
/**
|
||||
* We got the request body.
|
||||
*
|
||||
* A milestone state. No received data is processed in this state.
|
||||
*/
|
||||
MHD_CONNECTION_BODY_RECEIVED,
|
||||
|
||||
MHD_CONNECTION_BODY_RECEIVED
|
||||
,
|
||||
/**
|
||||
* We are reading the request footers.
|
||||
*/
|
||||
MHD_CONNECTION_FOOTERS_RECEIVING,
|
||||
|
||||
MHD_CONNECTION_FOOTERS_RECEIVING
|
||||
,
|
||||
/**
|
||||
* We received the entire footer.
|
||||
*
|
||||
* A milestone state. No data is receiving in this state.
|
||||
*/
|
||||
MHD_CONNECTION_FOOTERS_RECEIVED,
|
||||
|
||||
MHD_CONNECTION_FOOTERS_RECEIVED
|
||||
,
|
||||
/**
|
||||
* We received the entire request.
|
||||
*
|
||||
* A milestone state. No data is receiving in this state.
|
||||
*/
|
||||
MHD_CONNECTION_FULL_REQ_RECEIVED,
|
||||
|
||||
MHD_CONNECTION_FULL_REQ_RECEIVED
|
||||
,
|
||||
/**
|
||||
* Finished receiving request data: either complete request received or
|
||||
* MHD is going to send reply early, without getting full request.
|
||||
*/
|
||||
MHD_CONNECTION_REQ_RECV_FINISHED,
|
||||
|
||||
MHD_CONNECTION_REQ_RECV_FINISHED
|
||||
,
|
||||
/**
|
||||
* Finished reading of the request and the response is ready.
|
||||
* Switch internal logic from receiving to sending, prepare connection
|
||||
* sending the reply and build the reply header.
|
||||
*/
|
||||
MHD_CONNECTION_START_REPLY,
|
||||
|
||||
MHD_CONNECTION_START_REPLY
|
||||
,
|
||||
/**
|
||||
* We have prepared the response headers in the write buffer.
|
||||
* Send the response headers.
|
||||
*/
|
||||
MHD_CONNECTION_HEADERS_SENDING,
|
||||
|
||||
MHD_CONNECTION_HEADERS_SENDING
|
||||
,
|
||||
/**
|
||||
* We have sent the response headers. Get ready to send the body.
|
||||
*/
|
||||
MHD_CONNECTION_HEADERS_SENT,
|
||||
|
||||
MHD_CONNECTION_HEADERS_SENT
|
||||
,
|
||||
/**
|
||||
* We are waiting for the client to provide more
|
||||
* data of a non-chunked body.
|
||||
*/
|
||||
MHD_CONNECTION_UNCHUNKED_BODY_UNREADY,
|
||||
|
||||
MHD_CONNECTION_UNCHUNKED_BODY_UNREADY
|
||||
,
|
||||
/**
|
||||
* We are ready to send a part of a non-chunked body. Send it.
|
||||
*/
|
||||
MHD_CONNECTION_UNCHUNKED_BODY_READY,
|
||||
|
||||
MHD_CONNECTION_UNCHUNKED_BODY_READY
|
||||
,
|
||||
/**
|
||||
* We are waiting for the client to provide a chunk of the body.
|
||||
*/
|
||||
MHD_CONNECTION_CHUNKED_BODY_UNREADY,
|
||||
|
||||
MHD_CONNECTION_CHUNKED_BODY_UNREADY
|
||||
,
|
||||
/**
|
||||
* We are ready to send a chunk.
|
||||
*/
|
||||
MHD_CONNECTION_CHUNKED_BODY_READY,
|
||||
|
||||
MHD_CONNECTION_CHUNKED_BODY_READY
|
||||
,
|
||||
/**
|
||||
* We have sent the chunked response body. Prepare the footers.
|
||||
*/
|
||||
MHD_CONNECTION_CHUNKED_BODY_SENT,
|
||||
|
||||
MHD_CONNECTION_CHUNKED_BODY_SENT
|
||||
,
|
||||
/**
|
||||
* We have prepared the response footer. Send it.
|
||||
*/
|
||||
MHD_CONNECTION_FOOTERS_SENDING,
|
||||
|
||||
MHD_CONNECTION_FOOTERS_SENDING
|
||||
,
|
||||
/**
|
||||
* We have sent the entire reply.
|
||||
* Shutdown connection or restart processing to get a new request.
|
||||
*/
|
||||
MHD_CONNECTION_FULL_REPLY_SENT,
|
||||
|
||||
MHD_CONNECTION_FULL_REPLY_SENT
|
||||
,
|
||||
/**
|
||||
* Finished regular connection processing.
|
||||
* Initial buffers cleanup and freeing.
|
||||
*/
|
||||
MHD_CONNECTION_PRE_CLOSING
|
||||
,
|
||||
/**
|
||||
* This connection is to be closed.
|
||||
*/
|
||||
|
||||
@@ -831,6 +831,15 @@ struct mhd_DaemonRequestProcessingSettings
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get whether bare LF in HTTP header and other protocol elements
|
||||
* should be treated as the line termination depending on the configured
|
||||
* strictness level.
|
||||
* RFC 9112, section 2.2
|
||||
*/
|
||||
#define mhd_ALLOW_BARE_LF_AS_CRLF(discp_lvl) (0 >= discp_lvl)
|
||||
|
||||
|
||||
#ifndef NDEBUG
|
||||
/**
|
||||
* Various debugging data
|
||||
|
||||
@@ -0,0 +1,281 @@
|
||||
/*
|
||||
This file is part of GNU libmicrohttpd
|
||||
Copyright (C) 2024 Evgeny Grin (Karlson2k)
|
||||
|
||||
GNU libmicrohttpd is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
GNU libmicrohttpd is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file src/mhd2/mhd_post_parser.h
|
||||
* @brief The definition of the post parsers data structures
|
||||
* @author Karlson2k (Evgeny Grin)
|
||||
*/
|
||||
|
||||
#ifndef MHD_POST_PARSER_H
|
||||
#define MHD_POST_PARSER_H 1
|
||||
|
||||
#include "mhd_sys_options.h"
|
||||
|
||||
#include "sys_base_types.h"
|
||||
#include "sys_bool_type.h"
|
||||
|
||||
#include "http_post_enc.h"
|
||||
#include "mhd_post_result.h"
|
||||
#include "mhd_buffer.h"
|
||||
|
||||
/**
|
||||
* The "application/x-www-form-urlencoded" parsing data
|
||||
*/
|
||||
struct mhd_PostParserUrlEncData
|
||||
{
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* The "multipart/form-data" parsing data
|
||||
*/
|
||||
struct mhd_PostParserMPartFormData
|
||||
{
|
||||
/**
|
||||
* The boundary marker.
|
||||
* Allocated in the stream pool
|
||||
*/
|
||||
struct mhd_BufferConst bound;
|
||||
};
|
||||
|
||||
|
||||
// TODO: describe
|
||||
enum MHD_FIXED_ENUM_ mhd_PostTextState
|
||||
{
|
||||
/**
|
||||
* The line processing has not been started yet
|
||||
*/
|
||||
mhd_POST_TEXT_ST_NOT_STARTED = 0
|
||||
,
|
||||
/**
|
||||
* Processing name of the field
|
||||
*/
|
||||
mhd_POST_TEXT_ST_NAME
|
||||
,
|
||||
/**
|
||||
* At the '=' character after the name.
|
||||
* This is an intermediate state, should be processed and switched to the next
|
||||
* state immediately.
|
||||
* Should not be used outside processing loop.
|
||||
*/
|
||||
mhd_POST_TEXT_ST_AT_EQ
|
||||
,
|
||||
/**
|
||||
* The '=' character after the name has been found.
|
||||
* Looking for the first value character.
|
||||
*/
|
||||
mhd_POST_TEXT_ST_EQ_FOUND
|
||||
,
|
||||
/**
|
||||
* Processing the value of the field.
|
||||
*/
|
||||
mhd_POST_TEXT_ST_VALUE
|
||||
,
|
||||
/**
|
||||
* At the CR character.
|
||||
* This is an intermediate state, should be processed and switched to the next
|
||||
* state immediately.
|
||||
* Should not be used outside processing loop.
|
||||
*/
|
||||
mhd_POST_TEXT_ST_AT_CR
|
||||
,
|
||||
/**
|
||||
* Looking for LF character after CR character.
|
||||
*/
|
||||
mhd_POST_TEXT_ST_CR_FOUND
|
||||
,
|
||||
/**
|
||||
* At the LF character without preceding CR character.
|
||||
* This is an intermediate state, should be processed and switched to the next
|
||||
* state immediately.
|
||||
* Should not be used outside processing loop.
|
||||
*/
|
||||
mhd_POST_TEXT_ST_AT_LF_BARE
|
||||
,
|
||||
/**
|
||||
* End of the line found.
|
||||
* This is an intermediate state, should be processed and switched to the next
|
||||
* state immediately.
|
||||
* Should not be used outside processing loop.
|
||||
*/
|
||||
mhd_POST_TEXT_ST_FULL_LINE_FOUND
|
||||
};
|
||||
|
||||
/**
|
||||
* The "text/plain" parsing data
|
||||
*/
|
||||
struct mhd_PostParserTextData
|
||||
{
|
||||
/**
|
||||
* The parsing state
|
||||
*/
|
||||
enum mhd_PostTextState st;
|
||||
|
||||
/**
|
||||
* The index of the start of the name.
|
||||
*/
|
||||
size_t name_idx;
|
||||
|
||||
/**
|
||||
* The length of the name of the current field, not including
|
||||
* the terminating zero.
|
||||
* Zero until the length is found.
|
||||
*/
|
||||
size_t name_len;
|
||||
|
||||
/**
|
||||
* The index of the start of the value.
|
||||
* Zero until the value is found.
|
||||
* Cannot be zero if any (including zero-length) value available.
|
||||
*/
|
||||
size_t value_idx;
|
||||
|
||||
/**
|
||||
* The length of the value of the current field, not including
|
||||
* the terminating zero.
|
||||
* Zero until the length is found.
|
||||
*/
|
||||
size_t value_len;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* The encoding-specific parsing data
|
||||
*/
|
||||
union mhd_PostParserDetailedData
|
||||
{
|
||||
/**
|
||||
* The "application/x-www-form-urlencoded" parsing data
|
||||
*/
|
||||
struct mhd_PostParserUrlEncData u_enc;
|
||||
|
||||
/**
|
||||
* The "multipart/form-data" parsing data
|
||||
*/
|
||||
struct mhd_PostParserMPartFormData m_form;
|
||||
|
||||
/**
|
||||
* The "text/plain" parsing data
|
||||
*/
|
||||
struct mhd_PostParserTextData text;
|
||||
};
|
||||
|
||||
// TODO: remove?
|
||||
/**
|
||||
* The type of partially processed data in the buffer
|
||||
*/
|
||||
enum MHD_FIXED_ENUM_ mhd_PostParserPartProcType
|
||||
{
|
||||
/**
|
||||
* No data in the buffer
|
||||
*/
|
||||
mhd_POST_PARSER_PART_PROC_TYPE_NONE = 0
|
||||
,
|
||||
/**
|
||||
* The data is partially processed name
|
||||
*/
|
||||
mhd_POST_PARSER_PART_PROC_TYPE_NAME
|
||||
,
|
||||
/**
|
||||
* The data is partially processed value
|
||||
*/
|
||||
mhd_POST_PARSER_PART_PROC_TYPE_VALUE
|
||||
};
|
||||
|
||||
// TODO: remove?
|
||||
/**
|
||||
* Buffered partially processed data
|
||||
*/
|
||||
struct mhd_PostParserPartProcessedData
|
||||
{
|
||||
/**
|
||||
* Partially processed data, left from previous upload data portion
|
||||
*/
|
||||
struct mhd_Buffer data;
|
||||
|
||||
/**
|
||||
* The type of partially processed data in the @a data buffer
|
||||
*/
|
||||
enum mhd_PostParserPartProcType d_type;
|
||||
};
|
||||
|
||||
/**
|
||||
* The POST parsing data
|
||||
*/
|
||||
struct mhd_PostParserData
|
||||
{
|
||||
/**
|
||||
* The result of parsing POST data
|
||||
*/
|
||||
enum MHD_PostParseResult parse_result;
|
||||
|
||||
/**
|
||||
* The type of POSE encoding is used.
|
||||
* Active member of @a e_d depends on this type.
|
||||
*/
|
||||
enum MHD_HTTP_PostEncoding enc;
|
||||
|
||||
/**
|
||||
* The encoding-specific parsing data
|
||||
*/
|
||||
union mhd_PostParserDetailedData e_d;
|
||||
|
||||
/**
|
||||
* The "large" buffer for POST parsing and POST upload values
|
||||
*/
|
||||
struct mhd_Buffer lbuf;
|
||||
|
||||
/**
|
||||
* The size of the data currently in the @a lbuf
|
||||
*/
|
||||
size_t lbuf_used;
|
||||
|
||||
/**
|
||||
* The remaining size of "large shared buffer" allowed to allocate for this
|
||||
* POST parsing
|
||||
*/
|
||||
size_t lbuf_left; // TODO: Remove? Rename to 'lbuf_limit'?
|
||||
|
||||
/**
|
||||
* True if any POST data was parsed successfully.
|
||||
*/
|
||||
bool some_data_provided;
|
||||
|
||||
/**
|
||||
* The start index of the current field.
|
||||
* If the field is processed by incremental callback, buffer can be freed or
|
||||
* reused up to this position (inclusive).
|
||||
*/
|
||||
size_t field_start;
|
||||
|
||||
/**
|
||||
* The offset in the value data.
|
||||
* Used when value is processed incrementally otherwise it is zero.
|
||||
*/
|
||||
size_t value_off;
|
||||
|
||||
/**
|
||||
* The position of the next character to be parsed
|
||||
*/
|
||||
size_t next_parse_pos;
|
||||
};
|
||||
|
||||
#endif /* ! MHD_POST_PARSER_H */
|
||||
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
This file is part of GNU libmicrohttpd
|
||||
Copyright (C) 2024 Evgeny Grin (Karlson2k)
|
||||
|
||||
GNU libmicrohttpd is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
GNU libmicrohttpd is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file src/mhd2/mhd_post_result.h
|
||||
* @brief The definition of enum for POST parsing result
|
||||
* @author Karlson2k (Evgeny Grin)
|
||||
*/
|
||||
|
||||
#ifndef MHD_POST_RESULT_H
|
||||
#define MHD_POST_RESULT_H 1
|
||||
|
||||
#include "mhd_sys_options.h"
|
||||
|
||||
// TODO: describe and copy to the main header
|
||||
|
||||
#ifndef MHD_POST_PARSE_RESULT_DEFINED
|
||||
|
||||
enum MHD_FIXED_ENUM_MHD_SET_ MHD_PostParseResult
|
||||
{
|
||||
/**
|
||||
* The POST data parse successfully and completely.
|
||||
*/
|
||||
MHD_POST_PARSE_RES_OK = 0
|
||||
,
|
||||
/**
|
||||
* The POST request has no content or zero-length content.
|
||||
*/
|
||||
MHD_POST_PARSE_RES_REQUEST_EMPTY = 1
|
||||
,
|
||||
/**
|
||||
* Parsing of the POST data is incomplete because client used incorrect
|
||||
* format of POST encoding.
|
||||
* Some POST data is available or has been provided via callback.
|
||||
*/
|
||||
MHD_POST_PARSE_RES_PARTIAL_INVALID_POST_FORMAT = 2
|
||||
,
|
||||
/**
|
||||
* The POST data cannot be parsed completely because the stream has
|
||||
* no free pool memory.
|
||||
* Some POST data may be parsed.
|
||||
*/
|
||||
MHD_POST_PARSE_RES_FAILED_NO_POOL_MEM = 60
|
||||
,
|
||||
/**
|
||||
* The POST data cannot be parsed completely because no "large shared buffer"
|
||||
* space is available.
|
||||
* Some POST data may be parsed.
|
||||
*/
|
||||
MHD_POST_PARSE_RES_FAILED_NO_LARGE_BUF_MEM = 61
|
||||
,
|
||||
/**
|
||||
* The POST data cannot be parsed because 'Content-Type:' is unknown.
|
||||
*/
|
||||
MHD_POST_PARSE_RES_FAILED_UNKNOWN_CNTN_TYPE = 80
|
||||
,
|
||||
/**
|
||||
* The POST data cannot be parsed because 'Content-Type:' header is not set.
|
||||
*/
|
||||
MHD_POST_PARSE_RES_FAILED_NO_CNTN_TYPE = 81
|
||||
,
|
||||
/**
|
||||
* The POST data cannot be parsed because "Content-Type:" request header has
|
||||
* no "boundary" parameter for "multipart/form-data"
|
||||
*/
|
||||
MHD_POST_PARSE_RES_FAILED_HEADER_NO_BOUNDARY = 82
|
||||
,
|
||||
/**
|
||||
* The POST data cannot be parsed because "Content-Type: multipart/form-data"
|
||||
* request header is misformed
|
||||
*/
|
||||
MHD_POST_PARSE_RES_FAILED_HEADER_MISFORMED = 83
|
||||
,
|
||||
/**
|
||||
* The application set POST encoding to "multipart/form-data", but the request
|
||||
* has no "Content-Type: multipart/form-data" header which is required
|
||||
* to find "boundary" used in this encoding
|
||||
*/
|
||||
MHD_POST_PARSE_RES_FAILED_HEADER_NOT_MPART = 84
|
||||
,
|
||||
/**
|
||||
* The POST data cannot be parsed because client used incorrect format
|
||||
* of POST encoding.
|
||||
*/
|
||||
MHD_POST_PARSE_RES_FAILED_INVALID_POST_FORMAT = 90
|
||||
|
||||
};
|
||||
|
||||
#define MHD_POST_PARSE_RESULT_DEFINED 1
|
||||
#endif /* ! MHD_POST_PARSE_RESULT_DEFINED */
|
||||
|
||||
|
||||
#endif /* ! MHD_POST_RESULT_H */
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
This file is part of GNU libmicrohttpd
|
||||
Copyright (C) 2024 Evgeny Grin (Karlson2k)
|
||||
|
||||
GNU libmicrohttpd is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
GNU libmicrohttpd is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file src/mhd2/mhd_postfield.h
|
||||
* @brief The definition of the struct MHD_PostField
|
||||
* @author Karlson2k (Evgeny Grin)
|
||||
*/
|
||||
|
||||
#ifndef MHD_POSTFIELD_H
|
||||
#define MHD_POSTFIELD_H 1
|
||||
|
||||
#include "mhd_sys_options.h"
|
||||
|
||||
#ifndef MHD_POSTFILED_DEFINED
|
||||
|
||||
struct MHD_PostField
|
||||
{
|
||||
/**
|
||||
* The name of the field
|
||||
*/
|
||||
struct MHD_String name;
|
||||
/**
|
||||
* The field data
|
||||
* If not set or defined then to C string is NULL.
|
||||
* If set to empty string then pointer to C string not NULL,
|
||||
* but the length is zero.
|
||||
*/
|
||||
struct MHD_StringNullable value;
|
||||
/**
|
||||
* The filename if provided (only for "multipart/form-data")
|
||||
* If not set or defined then to C string is NULL.
|
||||
* If set to empty string then pointer to C string not NULL,
|
||||
* but the length is zero.
|
||||
*/
|
||||
struct MHD_StringNullable filename;
|
||||
/**
|
||||
* The Content-Type if provided (only for "multipart/form-data")
|
||||
* If not set or defined then to C string is NULL.
|
||||
* If set to empty string then pointer to C string not NULL,
|
||||
* but the length is zero.
|
||||
*/
|
||||
struct MHD_StringNullable content_type;
|
||||
/**
|
||||
* The Transfer-Encoding if provided (only for "multipart/form-data")
|
||||
* If not set or defined then to C string is NULL.
|
||||
* If set to empty string then pointer to C string not NULL,
|
||||
* but the length is zero.
|
||||
*/
|
||||
struct MHD_StringNullable transfer_encoding;
|
||||
};
|
||||
|
||||
#define MHD_POSTFILED_DEFINED 1
|
||||
#endif /* ! MHD_POSTFILED_DEFINED */
|
||||
|
||||
#endif /* ! MHD_POSTFIELD_H */
|
||||
+59
-2
@@ -41,6 +41,11 @@
|
||||
#include "mhd_action.h"
|
||||
#include "mhd_buffer.h"
|
||||
|
||||
#ifdef HAVE_POST_PARSER
|
||||
# include "mhd_postfield.h"
|
||||
# include "mhd_post_parser.h"
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* The action set by the application
|
||||
@@ -200,6 +205,33 @@ struct mhd_RequestField
|
||||
|
||||
mhd_DLINKEDL_LIST_DEF (mhd_RequestField);
|
||||
|
||||
#ifdef HAVE_POST_PARSER
|
||||
|
||||
struct mhd_RequestPostField; /* forward declarations */
|
||||
|
||||
mhd_DLINKEDL_LINKS_DEF (mhd_RequestPostField);
|
||||
|
||||
/**
|
||||
* The data for POST request fields
|
||||
*/
|
||||
struct mhd_RequestPostField
|
||||
{
|
||||
/**
|
||||
* The field data
|
||||
*/
|
||||
struct MHD_PostField field;
|
||||
|
||||
/**
|
||||
* Headers are kept in a double-linked list.
|
||||
*/
|
||||
mhd_DLNKDL_LINKS (mhd_RequestPostField,post_fields);
|
||||
};
|
||||
|
||||
mhd_DLINKEDL_LIST_DEF (mhd_RequestPostField);
|
||||
|
||||
|
||||
#endif /* HAVE_POST_PARSER */
|
||||
|
||||
|
||||
/**
|
||||
* The request content data
|
||||
@@ -219,17 +251,30 @@ struct mhd_ReqContentData
|
||||
uint_fast64_t cntn_size;
|
||||
|
||||
/**
|
||||
* The size of the received content
|
||||
* The size of the received content.
|
||||
* Excluding chunked encoding framing.
|
||||
*/
|
||||
uint_fast64_t recv_size;
|
||||
|
||||
/**
|
||||
* The size of the processed content
|
||||
* The size of the processed content.
|
||||
* Excluding chunked encoding framing.
|
||||
*/
|
||||
uint_fast64_t proc_size;
|
||||
};
|
||||
|
||||
|
||||
union mhd_ReqContentParsingData
|
||||
{
|
||||
#ifdef HAVE_POST_PARSER
|
||||
/**
|
||||
* The POST parsing data
|
||||
*/
|
||||
struct mhd_PostParserData post;
|
||||
#endif /* HAVE_POST_PARSER */
|
||||
// TODO: move "raw" upload processing data here
|
||||
};
|
||||
|
||||
/**
|
||||
* Request-specific values.
|
||||
*
|
||||
@@ -242,6 +287,13 @@ struct MHD_Request
|
||||
*/
|
||||
mhd_DLNKDL_LIST (mhd_RequestField,fields);
|
||||
|
||||
#ifdef HAVE_POST_PARSER
|
||||
/**
|
||||
* Linked list of parsed POST fields.
|
||||
*/
|
||||
mhd_DLNKDL_LIST (mhd_RequestPostField,post_fields);
|
||||
#endif /* HAVE_POST_PARSER */
|
||||
|
||||
/**
|
||||
* The action set by the application
|
||||
*/
|
||||
@@ -257,6 +309,11 @@ struct MHD_Request
|
||||
*/
|
||||
bool too_large;
|
||||
|
||||
/**
|
||||
* Upload processing data
|
||||
*/
|
||||
union mhd_ReqContentParsingData u_proc;
|
||||
|
||||
/**
|
||||
* HTTP version string (i.e. http/1.1). Allocated
|
||||
* in pool.
|
||||
|
||||
+216
-2
@@ -2003,6 +2003,10 @@ mhd_str_equal_caseless_quoted_bin_n (const char *quoted,
|
||||
}
|
||||
|
||||
|
||||
#endif /* DAUTH_SUPPORT */
|
||||
|
||||
#if defined(DAUTH_SUPPORT) || defined(HAVE_POST_PARSER)
|
||||
|
||||
MHD_INTERNAL size_t
|
||||
mhd_str_unquote (const char *quoted,
|
||||
size_t quoted_len,
|
||||
@@ -2027,8 +2031,7 @@ mhd_str_unquote (const char *quoted,
|
||||
return w;
|
||||
}
|
||||
|
||||
|
||||
#endif /* DAUTH_SUPPORT */
|
||||
#endif /* DAUTH_SUPPORT HAVE_POST_PARSER */
|
||||
|
||||
#if defined(DAUTH_SUPPORT) || defined(BAUTH_SUPPORT)
|
||||
|
||||
@@ -2326,3 +2329,214 @@ MHD_DATA_TRUNCATION_RUNTIME_CHECK_RESTORE_
|
||||
#undef mhd_base64_map_type
|
||||
|
||||
#endif /* BAUTH_SUPPORT */
|
||||
|
||||
|
||||
MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ bool
|
||||
mhd_str_starts_with_token_opt_param (const struct MHD_String *restrict str,
|
||||
const struct MHD_String *restrict token)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
mhd_assert (0 != token->len);
|
||||
mhd_assert (NULL == memchr(token->cstr, '=', token->len));
|
||||
mhd_assert (NULL == memchr(token->cstr, ' ', token->len));
|
||||
mhd_assert (NULL == memchr(token->cstr, '\t', token->len));
|
||||
|
||||
if (str->len < token->len)
|
||||
return false; /* The string is too short to match */
|
||||
|
||||
if (! mhd_str_equal_caseless_bin_n (str->cstr,
|
||||
token->cstr,
|
||||
token->len))
|
||||
return false; /* The string does not start with the token */
|
||||
|
||||
for (i = token->len; i < str->len; ++i)
|
||||
{
|
||||
const char c = str->cstr[i];
|
||||
if ((' ' == c) || ('\t' == c))
|
||||
continue;
|
||||
if (';' == c)
|
||||
return true; /* Found the start of the token parameters */
|
||||
return false; /* The initial part of the string does not fully match the token */
|
||||
}
|
||||
mhd_assert (0 && "The string should not have whitespace at the end");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_OUT_(4)
|
||||
MHD_FN_PAR_OUT_(5) enum mhd_StingStartsWithTokenResult
|
||||
mhd_str_starts_with_token_req_param (
|
||||
const struct MHD_String *restrict str,
|
||||
const struct MHD_String *restrict token,
|
||||
const struct MHD_String *restrict par,
|
||||
struct mhd_BufferConst *restrict par_value,
|
||||
bool *restrict par_value_needs_unquote)
|
||||
{
|
||||
size_t i;
|
||||
const char *const restrict cstr = str->cstr;
|
||||
bool token_found;
|
||||
bool param_found;
|
||||
|
||||
mhd_assert (0 != token->len);
|
||||
mhd_assert (NULL == memchr(token->cstr, '=', token->len));
|
||||
mhd_assert (NULL == memchr(token->cstr, ' ', token->len));
|
||||
mhd_assert (NULL == memchr(token->cstr, '\t', token->len));
|
||||
mhd_assert (NULL == memchr(par->cstr, '=', par->len));
|
||||
mhd_assert (NULL == memchr(par->cstr, ' ', par->len));
|
||||
mhd_assert (NULL == memchr(par->cstr, '\t', par->len));
|
||||
|
||||
par_value->data = NULL;
|
||||
par_value->size = 0;
|
||||
|
||||
if (str->len < token->len)
|
||||
return false; /* The string is too short to match */
|
||||
|
||||
if (! mhd_str_equal_caseless_bin_n (cstr,
|
||||
token->cstr,
|
||||
token->len))
|
||||
return mhd_STR_STARTS_W_TOKEN_NO_TOKEN; /* The string does not start with the token */
|
||||
token_found = false;
|
||||
param_found = false;
|
||||
|
||||
i = token->len;
|
||||
do
|
||||
{
|
||||
/* Find start of the next parameter */
|
||||
for ((void) 0; i < str->len; ++i)
|
||||
{
|
||||
const char c = cstr[i];
|
||||
if ((' ' == c) || ('\t' == c))
|
||||
continue;
|
||||
if (';' == c)
|
||||
{
|
||||
/* Found the start of the next token parameter */
|
||||
if (param_found)
|
||||
return mhd_STR_STARTS_W_TOKEN_HAS_TOKEN;
|
||||
break;
|
||||
}
|
||||
if (',' == c)
|
||||
return mhd_STR_STARTS_W_TOKEN_HAS_TOKEN; /* Found the start of the next token */
|
||||
|
||||
if (! token_found)
|
||||
{
|
||||
if (i == token->len)
|
||||
{
|
||||
/* The initial part of the string does not fully match the token or
|
||||
formatting is not correct */
|
||||
return mhd_STR_STARTS_W_TOKEN_NO_TOKEN;
|
||||
}
|
||||
/* The string has garbage after the token and whitespace */
|
||||
return mhd_STR_STARTS_W_TOKEN_HAS_TOKEN_BAD_FORMAT;
|
||||
}
|
||||
/* The garbage after the parameter */
|
||||
return mhd_STR_STARTS_W_TOKEN_HAS_TOKEN_BAD_FORMAT;
|
||||
}
|
||||
token_found = true;
|
||||
|
||||
if (i == str->len)
|
||||
return mhd_STR_STARTS_W_TOKEN_HAS_TOKEN;
|
||||
|
||||
/* 'i' is at the start of the parameter name */
|
||||
|
||||
if (par->len > str->len - i - 1)
|
||||
return mhd_STR_STARTS_W_TOKEN_HAS_TOKEN; /* the token is found, but the parameter is not */
|
||||
else
|
||||
{ /* Check the parameter */
|
||||
bool val_needs_unquote;
|
||||
size_t j;
|
||||
const char *const prm_str = cstr + i;
|
||||
|
||||
for (j = 0; j < par->len; ++j)
|
||||
if (! charsequalcaseless (prm_str[j],
|
||||
par->cstr[j]))
|
||||
break;
|
||||
i += j;
|
||||
mhd_assert (str->len > i);
|
||||
if ((j == par->len) &&
|
||||
('=' == cstr[i]))
|
||||
{
|
||||
/* The parameter name matches required parameter */
|
||||
param_found = true;
|
||||
par_value->data = cstr + i + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* i points to the char in the parameter name */
|
||||
while ('=' != cstr[i])
|
||||
{
|
||||
if ((';' == cstr[i]) /* end of the parameter */
|
||||
|| (',' == cstr[i]) /* end of the token */
|
||||
|| (str->len == ++i)) /* end of the field string */
|
||||
{
|
||||
/* parameter without the value */
|
||||
return mhd_STR_STARTS_W_TOKEN_HAS_TOKEN_BAD_FORMAT;
|
||||
}
|
||||
}
|
||||
}
|
||||
mhd_assert (str->len > i);
|
||||
mhd_assert ('=' == cstr[i]);
|
||||
|
||||
/* 'i' points to '=' between parameter name and parameter value */
|
||||
|
||||
++i; /* Advance to the first char in the parameter value */
|
||||
if (str->len == i)
|
||||
return mhd_STR_STARTS_W_TOKEN_HAS_TOKEN; /* Zero-length parameter value */
|
||||
|
||||
val_needs_unquote = false;
|
||||
|
||||
/* 'i' points to the char after '=' */
|
||||
|
||||
if ('"' == cstr[i])
|
||||
{
|
||||
/* The value is quoted */
|
||||
++(par_value->data); /* Point to the first quoted char */
|
||||
do
|
||||
{
|
||||
++i; /* Advance to the next char */
|
||||
if (str->len == i)
|
||||
return mhd_STR_STARTS_W_TOKEN_HAS_TOKEN_BAD_FORMAT; /* No closing quote */
|
||||
if ('\\' == cstr[i])
|
||||
{
|
||||
val_needs_unquote = true;
|
||||
++i; /* Skip quoted char */
|
||||
if (str->len == i)
|
||||
return mhd_STR_STARTS_W_TOKEN_HAS_TOKEN_BAD_FORMAT; /* No closing quote */
|
||||
}
|
||||
} while ('"' != cstr[i]);
|
||||
if (param_found)
|
||||
{
|
||||
par_value->size = (size_t) ((cstr + i) - par_value->data);
|
||||
*par_value_needs_unquote = val_needs_unquote;
|
||||
}
|
||||
/* Complete value found */
|
||||
/* Check for the garbage data at the end */
|
||||
++i; /* Advance to the next char */
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The value is not quoted */
|
||||
while ((' ' != cstr[i]) &&
|
||||
('\t' != cstr[i]))
|
||||
{
|
||||
if ((';' == cstr[i]) /* end of the parameter */
|
||||
|| (',' == cstr[i]) /* end of the token */
|
||||
|| (str->len == ++i)) /* end of the field string */
|
||||
break;
|
||||
}
|
||||
/* The end parameter value */
|
||||
if (param_found)
|
||||
{
|
||||
par_value->size = (size_t) ((cstr + i) - par_value->data);
|
||||
*par_value_needs_unquote = false;
|
||||
}
|
||||
/* Check for the garbage data at the end */
|
||||
}
|
||||
|
||||
/* 'i' points to the next char after end of the parameter value */
|
||||
}
|
||||
} while (i < str->len);
|
||||
|
||||
mhd_assert (token_found);
|
||||
return mhd_STR_STARTS_W_TOKEN_HAS_TOKEN;
|
||||
}
|
||||
|
||||
+86
-1
@@ -27,12 +27,19 @@
|
||||
#define MHD_STR_H 1
|
||||
|
||||
#include "mhd_sys_options.h"
|
||||
|
||||
#include "sys_base_types.h"
|
||||
#include "sys_bool_type.h"
|
||||
|
||||
#include "mhd_str_types.h"
|
||||
#include "mhd_buffer.h"
|
||||
|
||||
#include "mhd_str_macros.h"
|
||||
|
||||
#ifdef MHD_FAVOR_SMALL_CODE
|
||||
# include "mhd_limits.h"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Block of functions/macros that use US-ASCII charset as required by HTTP
|
||||
* standards. Not affected by current locale settings.
|
||||
@@ -682,6 +689,10 @@ mhd_str_equal_caseless_quoted_bin_n (const char *quoted,
|
||||
#define mhd_str_equal_caseless_quoted_s_bin_n(q,l,u) \
|
||||
mhd_str_equal_caseless_quoted_bin_n (q,l,u,mhd_SSTR_LEN (u))
|
||||
|
||||
#endif /* DAUTH_SUPPORT */
|
||||
|
||||
#if defined(DAUTH_SUPPORT) || defined(HAVE_POST_PARSER)
|
||||
|
||||
/**
|
||||
* Convert string from quoted to unquoted form as specified by
|
||||
* RFC7230#section-3.2.6 and RFC7694#quoted.strings.
|
||||
@@ -702,7 +713,7 @@ mhd_str_unquote (const char *quoted,
|
||||
size_t quoted_len,
|
||||
char *result);
|
||||
|
||||
#endif /* DAUTH_SUPPORT */
|
||||
#endif /* DAUTH_SUPPORT HAVE_POST_PARSER */
|
||||
|
||||
#if defined(DAUTH_SUPPORT) || defined(BAUTH_SUPPORT)
|
||||
|
||||
@@ -766,4 +777,78 @@ mhd_base64_to_bin_n (const char *base64,
|
||||
|
||||
#endif /* BAUTH_SUPPORT */
|
||||
|
||||
|
||||
/**
|
||||
* Check whether the given field value string starts with given token.
|
||||
* Token matched case-insensitive.
|
||||
*
|
||||
* Matched considered successful if string has given token at the first
|
||||
* position. The token may be followed by optional whitespaces and the semicolon
|
||||
* symbol. The string is not checked after the semicolon (if any).
|
||||
*
|
||||
* @param str the string to check
|
||||
* @param token the token to find, must not be empty
|
||||
* @return 'true' if match is successful,
|
||||
* 'false' otherwise
|
||||
*/
|
||||
MHD_INTERNAL bool
|
||||
mhd_str_starts_with_token_opt_param (const struct MHD_String *restrict str,
|
||||
const struct MHD_String *restrict token)
|
||||
MHD_FN_PAR_NONNULL_ALL_;
|
||||
|
||||
|
||||
/**
|
||||
* The result of check for token with parameter
|
||||
*/
|
||||
enum MHD_FIXED_ENUM_ mhd_StingStartsWithTokenResult
|
||||
{
|
||||
/**
|
||||
* The string does not start with the specified token
|
||||
*/
|
||||
mhd_STR_STARTS_W_TOKEN_NO_TOKEN = 0
|
||||
,
|
||||
/**
|
||||
* The string has specified token at the initial position
|
||||
* @note While formatting problems are not detected, it does not guarantee
|
||||
* that string has a perfect format.
|
||||
*/
|
||||
mhd_STR_STARTS_W_TOKEN_HAS_TOKEN = 1
|
||||
,
|
||||
/**
|
||||
* The string has specified token at the initial position, but broken
|
||||
* formatting is detected.
|
||||
*/
|
||||
mhd_STR_STARTS_W_TOKEN_HAS_TOKEN_BAD_FORMAT = -1
|
||||
};
|
||||
|
||||
/**
|
||||
* Check whether the given field value string starts with given token, find
|
||||
* required parameter.
|
||||
* Token and parameter matched case-insensitive.
|
||||
*
|
||||
* Matched considered successful if string has given token at the first
|
||||
* position. The token should be followed by optional whitespaces and
|
||||
* one or more parameters, delimited by the semicolon symbol.
|
||||
*
|
||||
* @param str the string to check
|
||||
* @param token the token to find, must not be empty
|
||||
* @param par the name of the parameter, must not be empty
|
||||
* @param[out] par_value set to the found parameter value or @a data member
|
||||
* set to NULL if parameter is not found
|
||||
* @param par_value_needs_unquote set to 'true' if @a par_value
|
||||
* needs to be "unquoted"
|
||||
* @return result of token detection and string parsing; if token is found
|
||||
* the presence of the required parameter is indicated only
|
||||
* by @a par_value
|
||||
*
|
||||
*/
|
||||
MHD_INTERNAL enum mhd_StingStartsWithTokenResult
|
||||
mhd_str_starts_with_token_req_param (
|
||||
const struct MHD_String *restrict str,
|
||||
const struct MHD_String *restrict token,
|
||||
const struct MHD_String *restrict par,
|
||||
struct mhd_BufferConst *restrict par_value,
|
||||
bool *restrict par_value_needs_unquote)
|
||||
MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_OUT_(4) MHD_FN_PAR_OUT_(5);
|
||||
|
||||
#endif /* MHD_STR_H */
|
||||
|
||||
@@ -0,0 +1,1165 @@
|
||||
/*
|
||||
This file is part of GNU libmicrohttpd
|
||||
Copyright (C) 2024 Evgeny Grin (Karlson2k)
|
||||
|
||||
GNU libmicrohttpd is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
GNU libmicrohttpd is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file src/mhd2/post_parser_funcs.c
|
||||
* @brief The implementation of internal POST parser functions
|
||||
* @author Karlson2k (Evgeny Grin)
|
||||
*/
|
||||
|
||||
|
||||
#include "mhd_sys_options.h"
|
||||
|
||||
#include "post_parser_funcs.h"
|
||||
|
||||
#include "mhd_post_parser.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "mhd_action.h"
|
||||
#include "mhd_request.h"
|
||||
#include "mhd_connection.h"
|
||||
|
||||
#include "mhd_str_macros.h"
|
||||
|
||||
#include "mhd_str.h"
|
||||
#include "daemon_logger.h"
|
||||
#include "stream_funcs.h"
|
||||
#include "stream_process_request.h"
|
||||
|
||||
#include "daemon_funcs.h"
|
||||
#include "request_get_value.h"
|
||||
|
||||
/**
|
||||
* The result of 'multipart/form-data' processing
|
||||
*/
|
||||
enum MHD_FIXED_ENUM_ mhd_ProcessMPartResult
|
||||
{
|
||||
/**
|
||||
* Sting processed successfully, boundary detected
|
||||
*/
|
||||
mhd_PROC_MPART_OK = 0
|
||||
,
|
||||
/**
|
||||
* Error processing string, the error result is set
|
||||
*/
|
||||
mhd_PROC_MPART_ERROR_SET
|
||||
,
|
||||
/**
|
||||
* The string is not 'multipart/form-data' header
|
||||
*/
|
||||
mhd_PROC_MPART_NO_MPART
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Process 'Content-Type:' header value as 'multipart/form-data' data to
|
||||
* prepare POST parsing data, including setting correct 'boundary' value
|
||||
* @param c the stream to use
|
||||
* @param h_cnt_tp the 'Content-Type:' header value string
|
||||
* @return 'mhd_PROC_MPART_OK' if processed successfully and boundary has been
|
||||
* detected and set,
|
||||
* 'mhd_PROC_MPART_ERROR_SET' is has some error in processing which
|
||||
* resulted in specific error set in
|
||||
* the stream,
|
||||
* 'mhd_PROC_MPART_NO_MPART' is string is not 'multipart/form-data' data
|
||||
*/
|
||||
static MHD_FN_PAR_NONNULL_ALL_ enum mhd_MPartDetectResult
|
||||
process_mpart_header (struct MHD_Connection *restrict c,
|
||||
const struct MHD_String *restrict h_cnt_tp)
|
||||
{
|
||||
static const struct MHD_String mpart_token =
|
||||
mhd_MSTR_INIT ("multipart/form-data");
|
||||
static const struct MHD_String mpart_bound_par =
|
||||
mhd_MSTR_INIT ("boundary");
|
||||
struct mhd_BufferConst mpart_bound;
|
||||
bool mpart_bound_quoted;
|
||||
enum mhd_StingStartsWithTokenResult res;
|
||||
|
||||
mhd_assert (NULL != h_cnt_tp->cstr);
|
||||
|
||||
res = mhd_str_starts_with_token_req_param (h_cnt_tp,
|
||||
&mpart_token,
|
||||
&mpart_bound_par,
|
||||
&mpart_bound,
|
||||
&mpart_bound_quoted);
|
||||
|
||||
if (mhd_STR_STARTS_W_TOKEN_NO_TOKEN == res)
|
||||
return mhd_PROC_MPART_NO_MPART;
|
||||
|
||||
if (mhd_STR_STARTS_W_TOKEN_HAS_TOKEN_BAD_FORMAT == res)
|
||||
{
|
||||
mhd_LOG_PRINT (c->daemon, \
|
||||
MHD_SC_REQ_POST_PARSE_FAILED_HEADER_MISFORMED, \
|
||||
mhd_LOG_FMT ("The request POST data cannot be parsed " \
|
||||
"because 'Content-Type: " \
|
||||
"multipart/form-data' header is " \
|
||||
"misformed: %.*s%s"), \
|
||||
(int) ((h_cnt_tp->len <= 127) ? h_cnt_tp->len : 127),
|
||||
h_cnt_tp->cstr,
|
||||
(h_cnt_tp->len <= 127) ? "" : "...");
|
||||
c->rq.u_proc.post.parse_result =
|
||||
MHD_POST_PARSE_RES_FAILED_HEADER_MISFORMED;
|
||||
return mhd_PROC_MPART_ERROR_SET;
|
||||
}
|
||||
|
||||
mhd_assert (mhd_STR_STARTS_W_TOKEN_HAS_TOKEN == res);
|
||||
|
||||
if (0 != mpart_bound.size)
|
||||
{
|
||||
mhd_LOG_MSG (c->daemon, \
|
||||
MHD_SC_REQ_POST_PARSE_FAILED_HEADER_NO_BOUNDARY, \
|
||||
"The request POST data cannot be parsed because " \
|
||||
"'Content-Type: multipart/form-data' header has " \
|
||||
"no 'boundary' parameter value.");
|
||||
c->rq.u_proc.post.parse_result =
|
||||
MHD_POST_PARSE_RES_FAILED_HEADER_NO_BOUNDARY;
|
||||
return mhd_PROC_MPART_ERROR_SET;
|
||||
}
|
||||
|
||||
mhd_assert (NULL != mpart_bound.data);
|
||||
|
||||
if (! mpart_bound_quoted)
|
||||
{
|
||||
c->rq.u_proc.post.enc = MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA;
|
||||
c->rq.u_proc.post.e_d.m_form.bound = mpart_bound;
|
||||
}
|
||||
else
|
||||
{
|
||||
char *buf;
|
||||
|
||||
mhd_assert (2 <= mpart_bound.size); /* At least one char and at least one '\' */
|
||||
|
||||
buf = mhd_stream_alloc_memory (c, mpart_bound.size);
|
||||
if (NULL == buf)
|
||||
{
|
||||
/* It is very low probability that pool would not have memory just
|
||||
* to held the small boundary string. While it could be possible
|
||||
* to allocate memory from "large buffer", it would over-complicate
|
||||
* code here and at freeing part. */
|
||||
mhd_LOG_MSG (c->daemon, MHD_SC_REQ_POST_PARSE_FAILED_NO_POOL_MEM, \
|
||||
"The request POST data cannot be parsed because " \
|
||||
"there is not enough pool memory.");
|
||||
c->rq.u_proc.post.parse_result = MHD_POST_PARSE_RES_FAILED_NO_POOL_MEM;
|
||||
return mhd_PROC_MPART_ERROR_SET;
|
||||
}
|
||||
c->rq.u_proc.post.enc = MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA;
|
||||
c->rq.u_proc.post.e_d.m_form.bound.size =
|
||||
mhd_str_unquote (mpart_bound.data,
|
||||
mpart_bound.size,
|
||||
buf);
|
||||
mhd_assert (0 != c->rq.u_proc.post.e_d.m_form.bound.size);
|
||||
}
|
||||
return mhd_PROC_MPART_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Detect used POST encoding and 'boundary' for 'multipart/form-data'.
|
||||
* @param c the stream to use
|
||||
* @return 'true' if detected successfully,
|
||||
* 'false' if POST encoding cannot be detected
|
||||
*/
|
||||
static MHD_FN_PAR_NONNULL_(1) bool
|
||||
detect_post_enc (struct MHD_Connection *restrict c)
|
||||
{
|
||||
const struct MHD_StringNullable *h_cnt_tp;
|
||||
|
||||
mhd_assert (MHD_CONNECTION_BODY_RECEIVING > c->state);
|
||||
|
||||
h_cnt_tp = mhd_request_get_value_st (&(c->rq),
|
||||
MHD_VK_HEADER,
|
||||
MHD_HTTP_HEADER_CONTENT_TYPE);
|
||||
if (NULL == h_cnt_tp)
|
||||
{
|
||||
mhd_LOG_MSG (c->daemon, MHD_SC_REQ_POST_PARSE_FAILED_NO_CNTN_TYPE, \
|
||||
"The request POST data cannot be parsed because " \
|
||||
"the request has no 'Content-Type:' header and no " \
|
||||
"explicit POST encoding is set.");
|
||||
c->rq.u_proc.post.parse_result = MHD_POST_PARSE_RES_FAILED_NO_CNTN_TYPE;
|
||||
return false; /* The "Content-Type:" is not defined by the client */
|
||||
}
|
||||
|
||||
mhd_assert (NULL != h_cnt_tp->cstr);
|
||||
|
||||
if (mhd_str_equal_caseless_n_st ("application/x-www-form-urlencoded",
|
||||
h_cnt_tp->cstr,
|
||||
h_cnt_tp->len))
|
||||
{
|
||||
c->rq.u_proc.post.enc = MHD_HTTP_POST_ENCODING_FORM_URLENCODED;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (1)
|
||||
{
|
||||
enum mhd_MPartDetectResult res;
|
||||
|
||||
res = process_mpart_header (c,
|
||||
(const struct MHD_String *) (const void *)
|
||||
h_cnt_tp);
|
||||
|
||||
if (mhd_PROC_MPART_OK == res)
|
||||
return true;
|
||||
|
||||
if (mhd_PROC_MPART_ERROR_SET == res)
|
||||
return false;
|
||||
|
||||
mhd_assert (mhd_PROC_MPART_NO_MPART == res);
|
||||
}
|
||||
|
||||
if (1)
|
||||
{
|
||||
static const struct MHD_String txt_tkn = mhd_MSTR_INIT("text/plain");
|
||||
|
||||
if (mhd_str_starts_with_token_opt_param (h_cnt_tp,
|
||||
&txt_tkn))
|
||||
{
|
||||
c->rq.u_proc.post.enc = MHD_HTTP_POST_ENCODING_TEXT_PLAIN;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
mhd_LOG_MSG (c->daemon, \
|
||||
MHD_SC_REQ_POST_PARSE_FAILED_UNKNOWN_CNTN_TYPE, \
|
||||
"The request POST data cannot be parsed because " \
|
||||
"'Content-Type' header value is unknown or unsupported.");
|
||||
c->rq.u_proc.post.parse_result =
|
||||
MHD_POST_PARSE_RES_FAILED_UNKNOWN_CNTN_TYPE;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect 'boundary' for 'multipart/form-data' POST encoding.
|
||||
* @param c the stream to use
|
||||
* @return 'true' if succeed,
|
||||
* 'false' if failed and error result is set
|
||||
*/
|
||||
static MHD_FN_PAR_NONNULL_ALL_ bool
|
||||
detect_mpart_boundary_from_the_header (struct MHD_Connection *restrict c)
|
||||
{
|
||||
const struct MHD_StringNullable *h_cnt_tp;
|
||||
|
||||
mhd_assert (MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA == \
|
||||
c->rq.app_act.head_act.data.post_parse.enc);
|
||||
|
||||
h_cnt_tp = mhd_request_get_value_st (&(c->rq),
|
||||
MHD_VK_HEADER,
|
||||
MHD_HTTP_HEADER_CONTENT_TYPE);
|
||||
if (NULL == h_cnt_tp)
|
||||
{
|
||||
mhd_LOG_MSG (c->daemon, MHD_SC_REQ_POST_PARSE_FAILED_NO_CNTN_TYPE, \
|
||||
"The request POST data cannot be parsed because " \
|
||||
"'multipart/form-data' requires 'boundary' parameter, but " \
|
||||
"the request has no 'Content-Type:' header.");
|
||||
c->rq.u_proc.post.parse_result = MHD_POST_PARSE_RES_FAILED_NO_CNTN_TYPE;
|
||||
return false;
|
||||
}
|
||||
|
||||
mhd_assert (NULL != h_cnt_tp->cstr);
|
||||
|
||||
enum mhd_MPartDetectResult res;
|
||||
|
||||
res = process_mpart_header (c,
|
||||
(const struct MHD_String *) (const void *)
|
||||
h_cnt_tp);
|
||||
|
||||
if (mhd_PROC_MPART_OK == res)
|
||||
return true;
|
||||
|
||||
if (mhd_PROC_MPART_NO_MPART == res)
|
||||
{
|
||||
mhd_LOG_MSG (c->daemon, MHD_SC_REQ_POST_PARSE_FAILED_HEADER_NOT_MPART, \
|
||||
"The request POST data cannot be parsed because " \
|
||||
"'multipart/form-data' requires 'boundary' parameter, but " \
|
||||
"the request has no 'Content-Type: multipart/form-data' " \
|
||||
"header.");
|
||||
c->rq.u_proc.post.parse_result = MHD_POST_PARSE_RES_FAILED_HEADER_NOT_MPART;
|
||||
return false;
|
||||
}
|
||||
|
||||
mhd_assert (mhd_PROC_MPART_ERROR_SET == res);
|
||||
return false;
|
||||
}
|
||||
|
||||
static MHD_FN_PAR_NONNULL_(1) void
|
||||
reset_text_parse_field_data (struct mhd_PostParserData *pdata)
|
||||
{
|
||||
mhd_assert (MHD_HTTP_POST_ENCODING_TEXT_PLAIN == pdata->enc);
|
||||
memset (&(pdata->e_d.text), 0, sizeof(pdata->e_d.text));
|
||||
#ifndef HAVE_NULL_PTR_ALL_ZEROS
|
||||
pdata->e_d.text.name_ptr = NULL;
|
||||
pdata->e_d.text.value_ptr = NULL;
|
||||
#endif
|
||||
pdata->field_start = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finish initialisation of data for POST parsing
|
||||
* @param c the stream to use
|
||||
*/
|
||||
static MHD_FN_PAR_NONNULL_(1) void
|
||||
init_post_parse_data (struct MHD_Connection *restrict c)
|
||||
{
|
||||
struct mhd_PostParserData *const pdata =
|
||||
&(c->rq.u_proc.post);
|
||||
|
||||
mhd_assert (mhd_ACTION_POST_PARSE == c->rq.app_act.head_act.act);
|
||||
mhd_assert (MHD_HTTP_POST_ENCODING_OTHER != \
|
||||
c->rq.u_proc.post.enc);
|
||||
|
||||
pdata->lbuf_left = c->rq.app_act.head_act.data.post_parse.buffer_size;
|
||||
|
||||
switch (pdata->enc)
|
||||
{
|
||||
case MHD_HTTP_POST_ENCODING_FORM_URLENCODED:
|
||||
// TODO:
|
||||
break;
|
||||
case MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA:
|
||||
// TODO
|
||||
break;
|
||||
case MHD_HTTP_POST_ENCODING_TEXT_PLAIN:
|
||||
reset_text_parse_field_data (pdata);
|
||||
break;
|
||||
case MHD_HTTP_POST_ENCODING_OTHER:
|
||||
default:
|
||||
mhd_assert (0 && "Impossible value");
|
||||
MHD_UNREACHABLE_;
|
||||
}
|
||||
}
|
||||
|
||||
MHD_INTERNAL MHD_FN_PAR_NONNULL_(1) bool
|
||||
mhd_stream_prepare_for_post_parse (struct MHD_Connection *restrict c)
|
||||
{
|
||||
mhd_assert (mhd_ACTION_POST_PARSE == c->rq.app_act.head_act.act);
|
||||
if (MHD_HTTP_POST_ENCODING_OTHER ==
|
||||
c->rq.app_act.head_act.data.post_parse.enc)
|
||||
{
|
||||
if (! detect_post_enc (c))
|
||||
{
|
||||
mhd_assert (MHD_POST_PARSE_RES_OK != c->rq.u_proc.post.parse_result);
|
||||
c->discard_request = true;
|
||||
c->state = MHD_CONNECTION_FULL_REQ_RECEIVED;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA ==
|
||||
c->rq.app_act.head_act.data.post_parse.enc)
|
||||
{
|
||||
if (! detect_mpart_boundary_from_the_header (c))
|
||||
{
|
||||
mhd_assert (MHD_POST_PARSE_RES_OK != c->rq.u_proc.post.parse_result);
|
||||
c->discard_request = true;
|
||||
c->state = MHD_CONNECTION_FULL_REQ_RECEIVED;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
mhd_assert (MHD_HTTP_POST_ENCODING_OTHER != \
|
||||
c->rq.u_proc.post.enc);
|
||||
mhd_assert ((MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA != \
|
||||
c->rq.u_proc.post.enc) || \
|
||||
(0 != c->rq.u_proc.post.e_d.m_form.bound.size));
|
||||
|
||||
init_post_parse_data (c);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate memory from "large shared buffer" for POST parsing
|
||||
* @param c the stream to use
|
||||
* @param alloc_size the size to allocate
|
||||
* @param[out] buf the buffer to allocate
|
||||
* @return 'true' if succeed,
|
||||
* 'false' otherwise
|
||||
*/
|
||||
static MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_OUT_(3) bool
|
||||
get_lbuf_fixed_size (struct MHD_Connection *restrict c,
|
||||
size_t alloc_size,
|
||||
struct mhd_Buffer *restrict buf)
|
||||
{
|
||||
mhd_assert (mhd_ACTION_POST_PARSE == c->rq.app_act.head_act.act);
|
||||
|
||||
if (alloc_size > c->rq.u_proc.post.lbuf_left)
|
||||
return NULL;
|
||||
|
||||
if (! mhd_daemon_get_lbuf (c->daemon,
|
||||
alloc_size,
|
||||
buf))
|
||||
return false;
|
||||
|
||||
c->rq.u_proc.post.lbuf_left -= alloc_size;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Grow the allocated memory from "large shared buffer" for POST parsing
|
||||
* @param c the stream to use
|
||||
* @param grow_size the size to grow
|
||||
* @param[in,out] buf the buffer to grow
|
||||
* @return 'true' if succeed,
|
||||
* 'false' otherwise
|
||||
*/
|
||||
static MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_INOUT_(3) bool
|
||||
grow_lbuf_fixed_size (struct MHD_Connection *restrict c,
|
||||
size_t grow_size,
|
||||
struct mhd_Buffer *restrict buf)
|
||||
{
|
||||
mhd_assert (mhd_ACTION_POST_PARSE == c->rq.app_act.head_act.act);
|
||||
|
||||
if (grow_size > c->rq.u_proc.post.lbuf_left)
|
||||
return NULL;
|
||||
|
||||
if (! mhd_daemon_grow_lbuf (c->daemon,
|
||||
grow_size,
|
||||
buf))
|
||||
return false;
|
||||
|
||||
c->rq.u_proc.post.lbuf_left -= grow_size;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add parsed POST field to the list of request's fields
|
||||
* @param c the stream to use
|
||||
* @param name the name of the field
|
||||
* @param filename the filename of the filed
|
||||
* @param content_type the "Content-Type:" of the field
|
||||
* @param transfer_encoding the "Transfer-Encoding:" of the field
|
||||
* @param value the value of the field
|
||||
* @return 'true' if succeed,
|
||||
* 'false' if memory allocation failed (no pool memory in the stream)
|
||||
*/
|
||||
static MHD_FN_PAR_NONNULL_ALL_ bool
|
||||
add_parsed_post_field (struct MHD_Connection *restrict c,
|
||||
struct MHD_String *restrict name,
|
||||
struct MHD_StringNullable *restrict filename,
|
||||
struct MHD_StringNullable *restrict content_type,
|
||||
struct MHD_StringNullable *restrict transfer_encoding,
|
||||
struct MHD_StringNullable *restrict value)
|
||||
{
|
||||
struct mhd_RequestPostField *pfield;
|
||||
|
||||
mhd_assert (NULL != name->cstr);
|
||||
mhd_assert ((NULL != filename->cstr) || (0 == filename->len));
|
||||
mhd_assert ((NULL != content_type->cstr) || (0 == content_type->len));
|
||||
mhd_assert ((NULL != transfer_encoding->cstr) || \
|
||||
(0 == transfer_encoding->len));
|
||||
mhd_assert ((NULL != value->cstr) || (0 == value->len));
|
||||
|
||||
pfield = (struct mhd_RequestPostField *)
|
||||
mhd_stream_alloc_memory (c,
|
||||
sizeof (struct mhd_RequestPostField));
|
||||
if (NULL == pfield)
|
||||
return false;
|
||||
|
||||
pfield->field.name = *name;
|
||||
pfield->field.value = *value;
|
||||
pfield->field.filename = *filename;
|
||||
pfield->field.content_type = *content_type;
|
||||
pfield->field.transfer_encoding = *transfer_encoding;
|
||||
|
||||
mhd_DLINKEDL_INIT_LINKS (pfield, post_fields);
|
||||
|
||||
mhd_DLINKEDL_INS_FIRST (&(c->rq), pfield, post_fields);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
MHD_static_inline_ MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_IN_(1)
|
||||
MHD_FN_PAR_OUT_(10) MHD_FN_PAR_OUT_(11)
|
||||
MHD_FN_PAR_OUT_(12) MHD_FN_PAR_OUT_(13) void
|
||||
make_post_strings_from_buf_and_indices (const char *restrict buf,
|
||||
size_t name_start,
|
||||
size_t name_len,
|
||||
size_t filename_start,
|
||||
size_t filename_len,
|
||||
size_t cntn_type_start,
|
||||
size_t cntn_type_len,
|
||||
size_t enc_start,
|
||||
size_t enc_len,
|
||||
struct MHD_String *name,
|
||||
struct MHD_StringNullable *filename,
|
||||
struct MHD_StringNullable *content_type,
|
||||
struct MHD_StringNullable *encoding)
|
||||
{
|
||||
name->len = name_len;
|
||||
name->cstr = buf + name_start;
|
||||
|
||||
if (0 != filename_start)
|
||||
{
|
||||
filename->len = filename_len;
|
||||
filename->cstr = buf + filename_start;
|
||||
}
|
||||
else
|
||||
{
|
||||
filename->len = 0;
|
||||
filename->cstr = NULL;
|
||||
}
|
||||
if (0 != cntn_type_start)
|
||||
{
|
||||
content_type->len = cntn_type_len;
|
||||
content_type->cstr = buf + cntn_type_start;
|
||||
}
|
||||
else
|
||||
{
|
||||
content_type->len = 0;
|
||||
content_type->cstr = NULL;
|
||||
}
|
||||
if (0 != enc_start)
|
||||
{
|
||||
encoding->len = enc_len;
|
||||
encoding->cstr = buf + enc_start;
|
||||
}
|
||||
else
|
||||
{
|
||||
encoding->len = 0;
|
||||
encoding->cstr = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Process new full parsed POST filed
|
||||
* @param c the stream to use
|
||||
* @param buf the buffer, where the data is
|
||||
* @param pnext_pos the pointer to variable holding index on the next position
|
||||
* to be parsed
|
||||
* @param pdata_size the pointer to variable holding the size of the data
|
||||
* @param field_start the start of the current field in the @a buf
|
||||
* @param name_start the start of the name of the filed in the @a buf
|
||||
* @param name_len the length of the name, not including mandatory terminating
|
||||
* zero
|
||||
* @param filename_start the start of the filename of the field in the @a buf,
|
||||
* zero if no filename is provided
|
||||
* @param filename_len the length of the filename, not including mandatory
|
||||
* terminating zero
|
||||
* @param cntn_type_start the start of the Content-Type value of the field in
|
||||
* the @a buf, zero if no Content-Type is provided
|
||||
* @param cntn_type_len the length of the Content-Type value, not including
|
||||
* mandatory terminating zero
|
||||
* @param enc_start the start of the Content-Encoding value of the field in
|
||||
* the @a buf, zero if no Content-Encoding is provided
|
||||
* @param enc_len the length of the Content-Encoding value, not including
|
||||
* mandatory terminating zero
|
||||
* @param value_start the start of the field value in the @a buf, zero if
|
||||
* no value is provided
|
||||
* @param value_len the length of the field value, not including mandatory
|
||||
* terminating zero
|
||||
* @return 'true' if stream state has been changed,
|
||||
* 'false' to continue parsing
|
||||
*/
|
||||
static MHD_FN_PAR_NONNULL_ALL_ bool
|
||||
process_complete_field_all (struct MHD_Connection *restrict c,
|
||||
const char *restrict buf,
|
||||
size_t *restrict pnext_pos,
|
||||
size_t *restrict pdata_size,
|
||||
size_t field_start,
|
||||
size_t name_start,
|
||||
size_t name_len,
|
||||
size_t filename_start,
|
||||
size_t filename_len,
|
||||
size_t cntn_type_start,
|
||||
size_t cntn_type_len,
|
||||
size_t enc_start,
|
||||
size_t enc_len,
|
||||
size_t value_start,
|
||||
size_t value_len)
|
||||
{
|
||||
struct mhd_PostParseActionData *const p_par =
|
||||
&(c->rq.app_act.head_act.data.post_parse);
|
||||
struct mhd_PostParserData *const p_data = &(c->rq.u_proc.post);
|
||||
|
||||
struct MHD_String name;
|
||||
struct MHD_StringNullable filename;
|
||||
struct MHD_StringNullable content_type;
|
||||
struct MHD_StringNullable encoding;
|
||||
struct MHD_StringNullable value;
|
||||
|
||||
mhd_assert (mhd_ACTION_POST_PARSE == c->rq.app_act.head_act.act);
|
||||
|
||||
mhd_assert ((0 == filename_start) || \
|
||||
(MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA == p_data->enc));
|
||||
mhd_assert ((0 == cntn_type_start) || \
|
||||
(MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA == p_data->enc));
|
||||
mhd_assert ((0 == enc_start) || \
|
||||
(MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA == p_data->enc));
|
||||
|
||||
mhd_assert (*pnext_pos < *pdata_size);
|
||||
mhd_assert (value_start + value_len < *pnext_pos);
|
||||
mhd_assert ((name_start + name_len < value_start) || \
|
||||
(0 == value_start));
|
||||
mhd_assert (name_start + name_len < *pnext_pos);
|
||||
mhd_assert ((filename_start + filename_len < value_start) || \
|
||||
(0 == value_start));
|
||||
mhd_assert (filename_start + filename_len < *pnext_pos);
|
||||
mhd_assert ((cntn_type_start + cntn_type_len < value_start) || \
|
||||
(0 == value_start));
|
||||
mhd_assert (cntn_type_start + cntn_type_len < *pnext_pos);
|
||||
mhd_assert ((enc_start + enc_len < value_start) || \
|
||||
(0 == value_start));
|
||||
mhd_assert (enc_start + enc_len < *pnext_pos);
|
||||
mhd_assert (field_start <= name_start);
|
||||
mhd_assert ((field_start <= filename_start) || (0 == filename_start));
|
||||
mhd_assert ((field_start <= cntn_type_start) || (0 == cntn_type_start));
|
||||
mhd_assert ((field_start <= enc_start) || (0 == enc_start));
|
||||
mhd_assert ((field_start <= value_start) || (0 == value_start));
|
||||
mhd_assert ((0 != filename_start) || (0 == filename_len));
|
||||
mhd_assert ((0 != cntn_type_start) || (0 == cntn_type_len));
|
||||
mhd_assert ((0 != enc_start) || (0 == enc_len));
|
||||
mhd_assert ((0 != value_start) || (0 == value_len));
|
||||
|
||||
p_data->some_data_provided = true;
|
||||
|
||||
make_post_strings_from_buf_and_indices (buf,
|
||||
name_start,
|
||||
name_len,
|
||||
filename_start,
|
||||
filename_len,
|
||||
cntn_type_start,
|
||||
cntn_type_len,
|
||||
enc_start,
|
||||
enc_len,
|
||||
&name,
|
||||
&filename,
|
||||
&content_type,
|
||||
&encoding);
|
||||
|
||||
if (NULL != p_par->stream_reader)
|
||||
{
|
||||
if ((p_par->auto_stream_size < (*pnext_pos - field_start))
|
||||
|| (0 != p_data->value_off))
|
||||
{
|
||||
bool res;
|
||||
struct mhd_PostParseActionData *act;
|
||||
const size_t field_size = *pnext_pos - field_start;
|
||||
|
||||
act = p_par->stream_reader (&(c->rq),
|
||||
p_par->reader_cls,
|
||||
&name,
|
||||
&filename,
|
||||
&content_type,
|
||||
&encoding,
|
||||
value_len,
|
||||
buf + value_start,
|
||||
p_data->value_off,
|
||||
MHD_YES);
|
||||
res = mhd_stream_process_upload_action (c, act, false);
|
||||
if (c->suspended)
|
||||
return true;
|
||||
p_data->value_off = 0;
|
||||
if (*pdata_size > *pnext_pos)
|
||||
{
|
||||
memmove (buf + field_start,
|
||||
buf + *pnext_pos,
|
||||
*pdata_size - *pnext_pos);
|
||||
}
|
||||
*pnext_pos -= field_size;
|
||||
*pdata_size -= field_size;
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
if (0 != value_start)
|
||||
{
|
||||
value.len = value_len;
|
||||
value.cstr = buf + value_start;
|
||||
}
|
||||
|
||||
if (! add_parsed_post_field (c,
|
||||
name,
|
||||
filename,
|
||||
content_type,
|
||||
encoding,
|
||||
value))
|
||||
{
|
||||
c->discard_request = true;
|
||||
c->state = MHD_CONNECTION_FULL_REQ_RECEIVED;
|
||||
mhd_LOG_MSG (c->daemon, MHD_SC_REQ_POST_PARSE_FAILED_NO_POOL_MEM, \
|
||||
"The request POST data cannot be parsed completely " \
|
||||
"because there is not enough pool memory.");
|
||||
c->rq.u_proc.post.parse_result = MHD_POST_PARSE_RES_FAILED_NO_POOL_MEM;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false; /* Continue parsing */
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Process new full parsed POST filed
|
||||
* @param c the stream to use
|
||||
* @param buf the buffer, where the data is
|
||||
* @param pnext_pos the pointer to variable holding index on the next position
|
||||
* to be parsed
|
||||
* @param pdata_size the pointer to variable holding the size of the data
|
||||
* @param field_start the start of the current field in the @a buf
|
||||
* @param name_start the start of the name of the filed in the @a buf
|
||||
* @param name_len the length of the name, not including mandatory terminating
|
||||
* zero
|
||||
* @param value_start the start of the field value in the @a buf, zero if
|
||||
* no value is provided
|
||||
* @param value_len the length of the field value, not including mandatory
|
||||
* terminating zero
|
||||
* @return 'true' if stream state has been changed,
|
||||
* 'false' to continue parsing
|
||||
*/
|
||||
static MHD_FN_PAR_NONNULL_ALL_ bool
|
||||
process_complete_field (struct MHD_Connection *restrict c,
|
||||
const char *restrict buf,
|
||||
size_t *restrict *pnext_pos,
|
||||
size_t *restrict *pdata_size,
|
||||
size_t field_start,
|
||||
size_t name_start,
|
||||
size_t name_len,
|
||||
size_t value_start,
|
||||
size_t value_len)
|
||||
{
|
||||
mhd_assert (value_start + value_len < *pnext_pos);
|
||||
mhd_assert ((name_start + name_len < value_start) || \
|
||||
(0 == value_start));
|
||||
mhd_assert (name_start + name_len < *pnext_pos);
|
||||
mhd_assert (field_start <= name_start);
|
||||
mhd_assert ((field_start <= value_start) || (0 == value_start));
|
||||
|
||||
mhd_assert (MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA != \
|
||||
c->rq.u_proc.post.enc);
|
||||
|
||||
return process_complete_field_all (c,
|
||||
buf,
|
||||
pnext_pos,
|
||||
pdata_size,
|
||||
field_start,
|
||||
name_start,
|
||||
name_len,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
value_start,
|
||||
value_len);
|
||||
}
|
||||
|
||||
|
||||
static MHD_FN_PAR_NONNULL_ALL_ bool
|
||||
process_partial_value_all (struct MHD_Connection *restrict c,
|
||||
const char *restrict buf,
|
||||
size_t *restrict pnext_pos,
|
||||
size_t *restrict pdata_size,
|
||||
size_t field_start,
|
||||
size_t name_start,
|
||||
size_t name_len,
|
||||
size_t filename_start,
|
||||
size_t filename_len,
|
||||
size_t cntn_type_start,
|
||||
size_t cntn_type_len,
|
||||
size_t enc_start,
|
||||
size_t enc_len,
|
||||
size_t part_value_start,
|
||||
size_t part_value_len)
|
||||
{
|
||||
struct mhd_PostParseActionData *const p_par =
|
||||
&(c->rq.app_act.head_act.data.post_parse);
|
||||
struct mhd_PostParserData *const p_data = &(c->rq.u_proc.post);
|
||||
|
||||
mhd_assert (*pnext_pos < *pdata_size);
|
||||
mhd_assert (part_value_start + part_value_len == *pnext_pos);
|
||||
mhd_assert (0 != part_value_start);
|
||||
mhd_assert (name_start + name_len < *pnext_pos);
|
||||
mhd_assert (filename_start + filename_len < part_value_start);
|
||||
mhd_assert (filename_start + filename_len < *pnext_pos);
|
||||
mhd_assert (cntn_type_start + cntn_type_len < part_value_start);
|
||||
mhd_assert (cntn_type_start + cntn_type_len < *pnext_pos);
|
||||
mhd_assert (enc_start + enc_len < part_value_start);
|
||||
mhd_assert (enc_start + enc_len < *pnext_pos);
|
||||
mhd_assert ((0 != filename_start) || (0 == filename_len));
|
||||
mhd_assert ((0 != cntn_type_start) || (0 == cntn_type_len));
|
||||
mhd_assert ((0 != enc_start) || (0 == enc_len));
|
||||
|
||||
p_data->some_data_provided = true;
|
||||
|
||||
if (NULL == p_par->stream_reader)
|
||||
return false; /* Continue parsing */
|
||||
|
||||
if ((p_par->auto_stream_size < (*pnext_pos - field_start))
|
||||
|| (0 != p_data->value_off))
|
||||
{
|
||||
struct MHD_String name;
|
||||
struct MHD_StringNullable filename;
|
||||
struct MHD_StringNullable content_type;
|
||||
struct MHD_StringNullable encoding;
|
||||
struct MHD_StringNullable value;
|
||||
struct mhd_PostParseActionData *act;
|
||||
bool res;
|
||||
|
||||
make_post_strings_from_buf_and_indices (buf,
|
||||
name_start,
|
||||
name_len,
|
||||
filename_start,
|
||||
filename_len,
|
||||
cntn_type_start,
|
||||
cntn_type_len,
|
||||
enc_start,
|
||||
enc_len,
|
||||
&name,
|
||||
&filename,
|
||||
&content_type,
|
||||
&encoding);
|
||||
|
||||
act = p_par->stream_reader (&(c->rq),
|
||||
p_par->reader_cls,
|
||||
&name,
|
||||
&filename,
|
||||
&content_type,
|
||||
&encoding,
|
||||
part_value_len,
|
||||
buf + part_value_start,
|
||||
p_data->value_off,
|
||||
MHD_NO);
|
||||
res = mhd_stream_process_upload_action(c, act, false);
|
||||
if (c->suspended)
|
||||
return true;
|
||||
|
||||
p_data->value_off += part_value_len;
|
||||
if (*pdata_size > *pnext_pos)
|
||||
{
|
||||
memmove (buf + part_value_start,
|
||||
buf + part_value_start + part_value_len,
|
||||
part_value_len);
|
||||
}
|
||||
*pnext_pos -= part_value_len;
|
||||
*pdata_size -= part_value_len;
|
||||
return res;
|
||||
}
|
||||
return false; /* Continue parsing */
|
||||
|
||||
|
||||
static MHD_FN_PAR_NONNULL_ALL_ bool
|
||||
process_partial_value (struct MHD_Connection *restrict c,
|
||||
const char *restrict buf,
|
||||
size_t *restrict *pnext_pos,
|
||||
size_t *restrict *pdata_size,
|
||||
size_t field_start,
|
||||
size_t name_start,
|
||||
size_t name_len,
|
||||
size_t part_value_start,
|
||||
size_t part_value_len)
|
||||
{
|
||||
mhd_assert (part_value_start + part_value_len < *pnext_pos);
|
||||
mhd_assert (name_start + name_len < part_value_start);
|
||||
mhd_assert (0 != part_value_start);
|
||||
mhd_assert (name_start + name_len < *pnext_pos);
|
||||
|
||||
mhd_assert (MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA != \
|
||||
c->rq.u_proc.post.enc);
|
||||
|
||||
return process_partial_value_all (c,
|
||||
buf,
|
||||
pnext_pos,
|
||||
pdata_size,
|
||||
field_start,
|
||||
name_start,
|
||||
name_len,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
part_value_start,
|
||||
part_value_len);
|
||||
}
|
||||
|
||||
static MHD_FN_PAR_NONNULL_ALL_
|
||||
MHD_FN_PAR_INOUT_(2) MHD_FN_PAR_INOUT_(3) bool
|
||||
parse_post_text (struct MHD_Connection *restrict c,
|
||||
size_t *restrict pdata_size,
|
||||
char *restrict buf)
|
||||
{
|
||||
const int discp_lvl = c->daemon->req_cfg.strictnees;
|
||||
/* Treat bare LF as the end of the line.
|
||||
The same logic used here as for parsing HTTP headers.
|
||||
Bare LF is processed as the end of the line or rejected as broken
|
||||
request. */
|
||||
const bool bare_lf_as_crlf = mhd_ALLOW_BARE_LF_AS_CRLF (discp_lvl);
|
||||
struct mhd_PostParserData *const p_data = &(c->rq.u_proc.post);
|
||||
struct mhd_PostParserTextData *const tf = &(p_data->e_d.text); /**< the current "text" field */
|
||||
size_t i;
|
||||
bool enc_broken;
|
||||
|
||||
mhd_assert (MHD_POST_PARSE_RES_OK == c->rq.u_proc.post.parse_result);
|
||||
mhd_assert (! c->discard_request);
|
||||
mhd_assert (p_data->next_parse_pos < *pdata_size);
|
||||
|
||||
enc_broken = false;
|
||||
i = p_data->next_parse_pos;
|
||||
while (*pdata_size > i)
|
||||
{
|
||||
switch (tf->st)
|
||||
{
|
||||
case mhd_POST_TEXT_ST_NOT_STARTED:
|
||||
mhd_assert (0 == p_data->field_start);
|
||||
mhd_assert (0 == p_data->value_off);
|
||||
p_data->field_start = i;
|
||||
tf->name_idx = i;
|
||||
tf->st = mhd_POST_TEXT_ST_NAME;
|
||||
/* Intentional fall-through */
|
||||
case mhd_POST_TEXT_ST_NAME:
|
||||
do /* Fast local loop */
|
||||
{
|
||||
if ('=' == buf[i])
|
||||
{
|
||||
tf->st = mhd_POST_TEXT_ST_AT_EQ;
|
||||
break;
|
||||
}
|
||||
else if ('\r' == buf[i])
|
||||
{
|
||||
tf->st = mhd_POST_TEXT_ST_AT_CR;
|
||||
break;
|
||||
}
|
||||
else if ('\n' == buf[i])
|
||||
{
|
||||
tf->st = mhd_POST_TEXT_ST_AT_LF_BARE;
|
||||
break;
|
||||
}
|
||||
} while (*pdata_size > ++i);
|
||||
mhd_assert ((*pdata_size == i) || \
|
||||
(mhd_POST_TEXT_ST_NAME != tf->st));
|
||||
continue;
|
||||
case mhd_POST_TEXT_ST_AT_EQ:
|
||||
mhd_assert (i > tf->name_idx);
|
||||
mhd_assert (0 == tf->name_len);
|
||||
mhd_assert (0 == tf->value_len);
|
||||
buf[i] = 0; /* Zero-terminate the name */
|
||||
tf->name_len = i - tf->name_idx;
|
||||
tf->st = mhd_POST_TEXT_ST_EQ_FOUND;
|
||||
++i; /* Process the next char */
|
||||
continue;
|
||||
case mhd_POST_TEXT_ST_EQ_FOUND:
|
||||
mhd_assert (0 == p_data->value_off);
|
||||
mhd_assert (0 == tf->value_idx);
|
||||
mhd_assert (0 == tf->value_len);
|
||||
tf->value_idx = i;
|
||||
tf->st = mhd_POST_TEXT_ST_VALUE;
|
||||
/* Intentional fall-through */
|
||||
case mhd_POST_TEXT_ST_VALUE:
|
||||
do /* Fast local loop */
|
||||
{
|
||||
if ('\r' == buf[i])
|
||||
{
|
||||
tf->st = mhd_POST_TEXT_ST_AT_CR;
|
||||
break;
|
||||
}
|
||||
else if ('\n' == buf[i])
|
||||
{
|
||||
tf->st = mhd_POST_TEXT_ST_AT_LF_BARE;
|
||||
break;
|
||||
}
|
||||
} while (*pdata_size > ++i);
|
||||
mhd_assert ((*pdata_size == i) || \
|
||||
(mhd_POST_TEXT_ST_VALUE != tf->st));
|
||||
continue;
|
||||
case mhd_POST_TEXT_ST_AT_LF_BARE:
|
||||
if (! bare_lf_as_crlf)
|
||||
{
|
||||
enc_broken = true;
|
||||
break;
|
||||
}
|
||||
/* Intentional fall-through */
|
||||
case mhd_POST_TEXT_ST_AT_CR:
|
||||
mhd_assert (0 == tf->value_len);
|
||||
buf[i] = 0; /* Zero-terminate the value (or the name) */
|
||||
if (0 != tf->value_idx)
|
||||
tf->value_len = i - tf->value_idx;
|
||||
else
|
||||
tf->name_len = i - tf->name_idx;
|
||||
if (mhd_POST_TEXT_ST_AT_LF_BARE == tf->st)
|
||||
tf->st = mhd_POST_TEXT_ST_FULL_LINE_FOUND;
|
||||
else
|
||||
{
|
||||
tf->st = mhd_POST_TEXT_ST_CR_FOUND;
|
||||
++i; /* Process the next char */
|
||||
}
|
||||
continue;
|
||||
case mhd_POST_TEXT_ST_CR_FOUND:
|
||||
if ('\n' != buf[i])
|
||||
{
|
||||
enc_broken = true;
|
||||
break;
|
||||
}
|
||||
/* Intentional fall-through */
|
||||
case mhd_POST_TEXT_ST_FULL_LINE_FOUND:
|
||||
++i; /* Advance to the next char to be checked */
|
||||
if (process_complete_field (c,
|
||||
buf,
|
||||
&i,
|
||||
pdata_size,
|
||||
p_data->field_start,
|
||||
tf->name_idx,
|
||||
tf->name_len,
|
||||
tf->value_idx,
|
||||
tf->value_len))
|
||||
{
|
||||
if (c->suspended)
|
||||
--i; /* Go back to the same position */
|
||||
return true;
|
||||
}
|
||||
mhd_assert (*pdata_size >= i);
|
||||
reset_text_parse_field_data (&(c->rq.u_proc.post));
|
||||
continue; /* Process the next char */
|
||||
default:
|
||||
mhd_assert (0 && "Impossible value");
|
||||
MHD_UNREACHABLE_;
|
||||
enc_broken = true;
|
||||
break;
|
||||
}
|
||||
mhd_assert (enc_broken);
|
||||
break;
|
||||
}
|
||||
|
||||
mhd_assert ((*pdata_size == i) || enc_broken);
|
||||
|
||||
if (enc_broken)
|
||||
{
|
||||
if (p_data->some_data_provided)
|
||||
{
|
||||
mhd_LOG_MSG (c->daemon, \
|
||||
MHD_SC_REQ_POST_PARSE_PARTIAL_INVALID_POST_FORMAT, \
|
||||
"The request POST has broken encoding or format and " \
|
||||
"was parsed only partially.");
|
||||
c->rq.u_proc.post.parse_result =
|
||||
MHD_POST_PARSE_RES_PARTIAL_INVALID_POST_FORMAT;
|
||||
}
|
||||
else
|
||||
{
|
||||
mhd_LOG_MSG (c->daemon, \
|
||||
MHD_SC_REQ_POST_PARSE_FAILED_INVALID_POST_FORMAT, \
|
||||
"The request POST has broken encoding or format and " \
|
||||
"cannot be parsed.");
|
||||
c->rq.u_proc.post.parse_result =
|
||||
MHD_POST_PARSE_RES_FAILED_INVALID_POST_FORMAT;
|
||||
}
|
||||
c->discard_request = true;
|
||||
c->state = MHD_CONNECTION_FULL_REQ_RECEIVED;
|
||||
return true;
|
||||
}
|
||||
|
||||
mhd_assert (mhd_POST_TEXT_ST_AT_EQ != tf->st);
|
||||
mhd_assert (mhd_POST_TEXT_ST_AT_CR != tf->st);
|
||||
mhd_assert (mhd_POST_TEXT_ST_AT_LF_BARE != tf->st);
|
||||
mhd_assert (mhd_POST_TEXT_ST_FULL_LINE_FOUND != tf->st);
|
||||
|
||||
mhd_assert (*pdata_size == i);
|
||||
|
||||
if ((mhd_POST_TEXT_ST_VALUE == tf->st) &&
|
||||
(i != tf->value_idx))
|
||||
{
|
||||
if (process_partial_value(c,
|
||||
buf,
|
||||
&i,
|
||||
pdata_size,
|
||||
p_data->field_start,
|
||||
tf->name_idx,
|
||||
tf->name_len,
|
||||
tf->value_idx,
|
||||
i - tf->value_idx))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false; /* Continue parsing */
|
||||
}
|
||||
|
||||
MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
|
||||
MHD_FN_PAR_INOUT_(3) bool
|
||||
mhd_stream_post_parse (struct MHD_Connection *restrict c,
|
||||
size_t *restrict data_size,
|
||||
char *restrict buf)
|
||||
{
|
||||
struct mhd_PostParserData *const p_data = &(c->rq.u_proc.post);
|
||||
bool alloc_failed;
|
||||
|
||||
mhd_assert (MHD_HTTP_POST_ENCODING_OTHER != p_data->enc);
|
||||
mhd_assert (p_data->lbuf.size >= p_data->lbuf_used);
|
||||
|
||||
// TODO: support process in the connection buffer
|
||||
if (NULL == p_data->lbuf.data)
|
||||
{
|
||||
alloc_failed = ! get_lbuf_fixed_size (c,
|
||||
*data_size,
|
||||
&(p_data->lbuf));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (*data_size > (p_data->lbuf.size - p_data->lbuf_used))
|
||||
alloc_failed =
|
||||
! grow_lbuf_fixed_size (c,
|
||||
*data_size -
|
||||
(p_data->lbuf.size - p_data->lbuf_used),
|
||||
&(p_data->lbuf));
|
||||
else
|
||||
alloc_failed = false;
|
||||
|
||||
}
|
||||
if (alloc_failed)
|
||||
{
|
||||
mhd_LOG_MSG (c->daemon, \
|
||||
MHD_SC_REQ_POST_PARSE_FAILED_NO_LARGE_BUF_MEM, \
|
||||
"Not enough large shared buffer memory to " \
|
||||
"parse POST request.");
|
||||
c->rq.u_proc.post.parse_result =
|
||||
MHD_POST_PARSE_RES_FAILED_NO_LARGE_BUF_MEM;
|
||||
c->discard_request = true;
|
||||
c->state = MHD_CONNECTION_FULL_REQ_RECEIVED;
|
||||
return true;
|
||||
}
|
||||
memcpy (p_data->lbuf.data + p_data->lbuf_used,
|
||||
buf,
|
||||
*data_size);
|
||||
p_data->lbuf_used += *data_size;
|
||||
*data_size = 0; /* All data has been moved */
|
||||
|
||||
switch (p_data->enc)
|
||||
{
|
||||
case MHD_HTTP_POST_ENCODING_FORM_URLENCODED:
|
||||
// TODO: finish
|
||||
c->state = MHD_CONNECTION_FULL_REQ_RECEIVED;
|
||||
return true;
|
||||
case MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA:
|
||||
// TODO: finish
|
||||
c->state = MHD_CONNECTION_FULL_REQ_RECEIVED;
|
||||
return true;
|
||||
case MHD_HTTP_POST_ENCODING_TEXT_PLAIN:
|
||||
return parse_post_text (c,
|
||||
&(p_data->lbuf_used),
|
||||
p_data->lbuf.data);
|
||||
case MHD_HTTP_POST_ENCODING_OTHER:
|
||||
default:
|
||||
mhd_assert (0 && "Impossible value");
|
||||
MHD_UNREACHABLE_;
|
||||
c->rq.u_proc.post.parse_result =
|
||||
MHD_POST_PARSE_RES_PARTIAL_INVALID_POST_FORMAT;
|
||||
c->discard_request = true;
|
||||
c->state = MHD_CONNECTION_FULL_REQ_RECEIVED;
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
|
||||
MHD_FN_PAR_INOUT_(3) void
|
||||
mhd_stream_post_final_data (struct MHD_Connection *restrict c,
|
||||
size_t *restrict data_size,
|
||||
char *restrict buf)
|
||||
{
|
||||
// TODO: implement check for unprocessed broken partial data
|
||||
return;
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
This file is part of GNU libmicrohttpd
|
||||
Copyright (C) 2024 Evgeny Grin (Karlson2k)
|
||||
|
||||
GNU libmicrohttpd is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
GNU libmicrohttpd is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file src/mhd2/post_parser_funcs.h
|
||||
* @brief The declarations of internal POST parser functions
|
||||
* @author Karlson2k (Evgeny Grin)
|
||||
*/
|
||||
|
||||
#ifndef MHD_POST_PARSER_FUNCS_H
|
||||
#define MHD_POST_PARSER_FUNCS_H 1
|
||||
|
||||
#include "mhd_sys_options.h"
|
||||
|
||||
#include "sys_bool_type.h"
|
||||
|
||||
struct MHD_Connection; /* forward declaration */
|
||||
|
||||
/**
|
||||
* Make preparation necessary for parsing POST data.
|
||||
* @param c the stream to use
|
||||
* @return 'true' if succeed,
|
||||
* 'false' if failed and error result is set in the stream
|
||||
*/
|
||||
MHD_INTERNAL bool
|
||||
mhd_stream_prepare_for_post_parse (struct MHD_Connection *restrict c)
|
||||
MHD_FN_PAR_NONNULL_(1);
|
||||
|
||||
/**
|
||||
* Parse POST data.
|
||||
* @param c the stream to use
|
||||
* @return // FIXME
|
||||
*/
|
||||
MHD_INTERNAL bool
|
||||
mhd_stream_post_parse (struct MHD_Connection *restrict c,
|
||||
size_t *restrict data_size,
|
||||
char *restrict buf)
|
||||
MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_INOUT_SIZE_(3, 2);
|
||||
|
||||
// TODO: describe
|
||||
MHD_INTERNAL void
|
||||
mhd_stream_post_final_data (struct MHD_Connection *restrict c,
|
||||
size_t *restrict data_size,
|
||||
char *restrict buf)
|
||||
MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_INOUT_(3);
|
||||
|
||||
|
||||
#endif /* ! MHD_POST_PARSER_FUNCS_H */
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
This file is part of GNU libmicrohttpd
|
||||
Copyright (C) 2024 Christian Grothoff
|
||||
Copyright (C) 2024 Evgeny Grin (Karlson2k)
|
||||
|
||||
GNU libmicrohttpd is free software; you can redistribute it and/or
|
||||
@@ -48,18 +49,37 @@ mhd_request_get_value_n (struct MHD_Request *restrict request,
|
||||
size_t key_len,
|
||||
const char *restrict key)
|
||||
{
|
||||
struct mhd_RequestField *f;
|
||||
|
||||
mhd_assert (strlen (key) == key_len);
|
||||
|
||||
for (f = mhd_DLINKEDL_GET_FIRST (request, fields); NULL != f;
|
||||
f = mhd_DLINKEDL_GET_NEXT (f, fields))
|
||||
if (MHD_VK_POSTDATA != kind)
|
||||
{
|
||||
if ((key_len == f->field.nv.name.len) &&
|
||||
(kind == f->field.kind) &&
|
||||
(0 == memcmp (key, f->field.nv.name.cstr, key_len)))
|
||||
return &(f->field.nv.value);
|
||||
struct mhd_RequestField *f;
|
||||
|
||||
for (f = mhd_DLINKEDL_GET_FIRST (request, fields); NULL != f;
|
||||
f = mhd_DLINKEDL_GET_NEXT (f, fields))
|
||||
{
|
||||
if ((key_len == f->field.nv.name.len) &&
|
||||
(0 != (kind & f->field.kind)) &&
|
||||
(0 == memcmp (key, f->field.nv.name.cstr, key_len)))
|
||||
return &(f->field.nv.value);
|
||||
}
|
||||
}
|
||||
|
||||
#if HAVE_POST_PARSER
|
||||
if (0 != (MHD_VK_POSTDATA & kind))
|
||||
{
|
||||
struct mhd_RequestPostField *f;
|
||||
for (f = mhd_DLINKEDL_GET_FIRST (request, post_fields); NULL != f;
|
||||
f = mhd_DLINKEDL_GET_NEXT (f, post_fields))
|
||||
{
|
||||
if ((key_len == f->field.name.len) &&
|
||||
(0 == memcmp (key, f->field.name.cstr, key_len)))
|
||||
return &(f->field.value);
|
||||
}
|
||||
}
|
||||
#endif /* HAVE_POST_PARSER */
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
@@ -62,9 +62,9 @@ respond_with_error_len (struct MHD_Connection *c,
|
||||
|
||||
/* Discard most of the request data */
|
||||
|
||||
if (NULL != c->rq.cntn.lbuf.buf)
|
||||
if (NULL != c->rq.cntn.lbuf.data)
|
||||
mhd_daemon_free_lbuf (c->daemon, &(c->rq.cntn.lbuf));
|
||||
c->rq.cntn.lbuf.buf = NULL;
|
||||
c->rq.cntn.lbuf.data = NULL;
|
||||
|
||||
c->write_buffer = NULL;
|
||||
c->write_buffer_size = 0;
|
||||
|
||||
@@ -41,6 +41,16 @@ MHD_INTERNAL void
|
||||
mhd_response_deinit_content_data (struct MHD_Response *restrict r)
|
||||
MHD_FN_PAR_NONNULL_ (1);
|
||||
|
||||
/**
|
||||
* Create special internal-only response for sending automatic error messages
|
||||
* @param sc the HTTP status code (enum MHD_HTTP_StatusCode)
|
||||
* @param cntn_len the length of the @a cntn
|
||||
* @param cntn the response content
|
||||
* @param spec_hdr_len the length of the @a spec_hdr
|
||||
* @param spec_hdr the special string to be used as a header string
|
||||
* @return the response object if succeed,
|
||||
* NULL if failed (out of memory)
|
||||
*/
|
||||
MHD_INTERNAL struct MHD_Response *
|
||||
mhd_response_special_for_error (unsigned int sc,
|
||||
size_t cntn_len,
|
||||
|
||||
+17
-17
@@ -496,8 +496,10 @@ mhd_stream_finish_req_serving (struct MHD_Connection *restrict c,
|
||||
{
|
||||
mhd_assert (! c->stop_with_error || (NULL == c->rp.response) || \
|
||||
(c->rp.response->cfg.int_err_resp));
|
||||
/* Next function will destroy response, notify client,
|
||||
* destroy memory pool and set connection state to "CLOSED" */
|
||||
|
||||
/* Next function will notify client and set connection
|
||||
* state to "PRE-CLOSING" */
|
||||
/* Later response and memory pool will be destroyed */
|
||||
mhd_conn_pre_close (c,
|
||||
c->stop_with_error ?
|
||||
mhd_CONN_CLOSE_ERR_REPLY_SENT :
|
||||
@@ -652,7 +654,6 @@ mhd_conn_pre_close (struct MHD_Connection *restrict c,
|
||||
const char *log_msg)
|
||||
{
|
||||
bool close_hard;
|
||||
bool use_local_lingering;
|
||||
enum MHD_RequestEndedCode end_code;
|
||||
enum MHD_StatusCode sc;
|
||||
|
||||
@@ -774,7 +775,6 @@ mhd_conn_pre_close (struct MHD_Connection *restrict c,
|
||||
|
||||
mhd_assert ((NULL == log_msg) || (MHD_SC_INTERNAL_ERROR != sc));
|
||||
|
||||
use_local_lingering = false;
|
||||
/* Make changes on the socket early to let the kernel and the remote
|
||||
* to process the changes in parallel. */
|
||||
if (close_hard)
|
||||
@@ -789,13 +789,12 @@ mhd_conn_pre_close (struct MHD_Connection *restrict c,
|
||||
if (mhd_socket_shut_wr (c->socket_fd) && (! c->sk_rmt_shut_wr))
|
||||
{
|
||||
(void) 0; // TODO: start local lingering phase
|
||||
c->state = MHD_CONNECTION_CLOSED; // TODO: start local lingering phase
|
||||
c->state = MHD_CONNECTION_PRE_CLOSING; // TODO: start local lingering phase
|
||||
c->event_loop_info = MHD_EVENT_LOOP_INFO_CLEANUP; // TODO: start local lingering phase
|
||||
// use_local_lingering = true;
|
||||
}
|
||||
else
|
||||
{ /* No need / not possible to linger */
|
||||
c->state = MHD_CONNECTION_CLOSED;
|
||||
c->state = MHD_CONNECTION_PRE_CLOSING;
|
||||
c->event_loop_info = MHD_EVENT_LOOP_INFO_CLEANUP;
|
||||
}
|
||||
}
|
||||
@@ -809,13 +808,6 @@ mhd_conn_pre_close (struct MHD_Connection *restrict c,
|
||||
(void) log_msg;
|
||||
#endif /* ! HAVE_LOG_FUNCTIONALITY */
|
||||
|
||||
mhd_stream_call_dcc_cleanup_if_needed (c);
|
||||
if (NULL != c->rp.resp_iov.iov)
|
||||
{
|
||||
free (c->rp.resp_iov.iov);
|
||||
c->rp.resp_iov.iov = NULL;
|
||||
}
|
||||
|
||||
#if 0 // TODO: notification callback
|
||||
mhd_assert ((MHD_CONNECTION_INIT != c->state) || (! c->rq.app_aware));
|
||||
if ( (NULL != d->notify_completed) &&
|
||||
@@ -842,9 +834,6 @@ mhd_conn_pre_close (struct MHD_Connection *restrict c,
|
||||
#ifndef NDEBUG
|
||||
c->dbg.pre_closed = true;
|
||||
#endif
|
||||
|
||||
if (! use_local_lingering)
|
||||
mhd_conn_pre_clean (c);
|
||||
}
|
||||
|
||||
|
||||
@@ -854,8 +843,18 @@ mhd_conn_pre_clean (struct MHD_Connection *restrict c)
|
||||
{
|
||||
// TODO: support suspended connections
|
||||
|
||||
mhd_assert (c->dbg.pre_closed);
|
||||
mhd_assert (! c->dbg.pre_cleaned);
|
||||
|
||||
mhd_conn_mark_unready (c, c->daemon);
|
||||
|
||||
mhd_stream_call_dcc_cleanup_if_needed (c);
|
||||
if (NULL != c->rp.resp_iov.iov)
|
||||
{
|
||||
free (c->rp.resp_iov.iov);
|
||||
c->rp.resp_iov.iov = NULL;
|
||||
}
|
||||
|
||||
if (NULL != c->rq.cntn.lbuf.data)
|
||||
mhd_daemon_free_lbuf (c->daemon, &(c->rq.cntn.lbuf));
|
||||
c->rq.cntn.lbuf.data = NULL;
|
||||
@@ -893,6 +892,7 @@ mhd_conn_pre_clean (struct MHD_Connection *restrict c)
|
||||
}
|
||||
#endif /* MHD_USE_EPOLL */
|
||||
|
||||
c->state = MHD_CONNECTION_CLOSED;
|
||||
#ifndef NDEBUG
|
||||
c->dbg.pre_cleaned = true;
|
||||
#endif
|
||||
|
||||
@@ -1009,7 +1009,7 @@ mhd_stream_prep_unchunked_body (struct MHD_Connection *restrict c)
|
||||
size_to_fill);
|
||||
c->rp.app_act_ctx.connection = NULL; /* Block any attempt to create a new action */
|
||||
if (! preprocess_dcc_action (c, act))
|
||||
return false;
|
||||
return true;
|
||||
if (mhd_DCC_ACTION_FINISH == c->rp.app_act.act)
|
||||
{
|
||||
mhd_assert (MHD_SIZE_UNKNOWN == r->cntn_size);
|
||||
@@ -1029,7 +1029,7 @@ mhd_stream_prep_unchunked_body (struct MHD_Connection *restrict c)
|
||||
mhd_CONN_CLOSE_APP_ERROR,
|
||||
"Closing connection (application returned more data "
|
||||
"than requested).");
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
c->rp.rsp_cntn_read_pos += filled;
|
||||
c->write_buffer_append_offset += filled;
|
||||
@@ -1122,6 +1122,7 @@ mhd_stream_prep_chunked_body (struct MHD_Connection *restrict c)
|
||||
mhd_STREAM_ABORT (c,
|
||||
mhd_CONN_CLOSE_NO_POOL_MEM_FOR_REPLY,
|
||||
"No memory in the pool for the reply chunked content.");
|
||||
return true;
|
||||
}
|
||||
mhd_assert (max_chunk_overhead < \
|
||||
(c->write_buffer_size));
|
||||
@@ -1178,7 +1179,7 @@ mhd_stream_prep_chunked_body (struct MHD_Connection *restrict c)
|
||||
size_to_fill);
|
||||
c->rp.app_act_ctx.connection = NULL; /* Block any attempt to create a new action */
|
||||
if (! preprocess_dcc_action (c, act))
|
||||
return false;
|
||||
return true;
|
||||
if (mhd_DCC_ACTION_FINISH == c->rp.app_act.act)
|
||||
{
|
||||
mhd_assert (MHD_SIZE_UNKNOWN == r->cntn_size);
|
||||
@@ -1196,7 +1197,7 @@ mhd_stream_prep_chunked_body (struct MHD_Connection *restrict c)
|
||||
mhd_CONN_CLOSE_APP_ERROR,
|
||||
"Closing connection (application returned more data "
|
||||
"than requested).");
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
c->rp.rsp_cntn_read_pos += filled;
|
||||
c->write_buffer_append_offset += filled;
|
||||
@@ -1300,7 +1301,7 @@ prep_chunked_footer_inn (struct MHD_Connection *restrict c)
|
||||
}
|
||||
|
||||
|
||||
MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ void
|
||||
MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ bool
|
||||
mhd_stream_prep_chunked_footer (struct MHD_Connection *restrict c)
|
||||
{
|
||||
if (! prep_chunked_footer_inn (c))
|
||||
@@ -1308,7 +1309,8 @@ mhd_stream_prep_chunked_footer (struct MHD_Connection *restrict c)
|
||||
mhd_STREAM_ABORT (c,
|
||||
mhd_CONN_CLOSE_NO_POOL_MEM_FOR_REPLY,
|
||||
"No memory in the pool for the reply chunked footer.");
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
c->state = MHD_CONNECTION_FOOTERS_SENDING;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -75,6 +75,8 @@ MHD_FN_PAR_NONNULL_ALL_;
|
||||
/**
|
||||
* Prepare the chunked response content of this connection for sending.
|
||||
*
|
||||
* @param c the connection
|
||||
*
|
||||
* @return 'true' if connection new state could be processed now,
|
||||
* 'false' if no new state processing is needed.
|
||||
*/
|
||||
@@ -88,8 +90,11 @@ MHD_FN_PAR_NONNULL_ALL_;
|
||||
* with response footers.
|
||||
*
|
||||
* @param c the connection
|
||||
*
|
||||
* @return 'true' if connection new state could be processed now,
|
||||
* 'false' if no new state processing is needed.
|
||||
*/
|
||||
MHD_INTERNAL void
|
||||
MHD_INTERNAL bool
|
||||
mhd_stream_prep_chunked_footer (struct MHD_Connection *restrict c)
|
||||
MHD_FN_PAR_NONNULL_ALL_;
|
||||
|
||||
|
||||
+163
-123
@@ -422,14 +422,6 @@
|
||||
*/
|
||||
#define MHD_CHUNK_HEADER_REASONABLE_LEN 24
|
||||
|
||||
/**
|
||||
* Get whether bare LF in HTTP header and other protocol elements
|
||||
* should be treated as the line termination depending on the configured
|
||||
* strictness level.
|
||||
* RFC 9112, section 2.2
|
||||
*/
|
||||
#define MHD_ALLOW_BARE_LF_AS_CRLF_(discp_lvl) (0 >= discp_lvl)
|
||||
|
||||
/**
|
||||
* The valid length of any HTTP version string
|
||||
*/
|
||||
@@ -586,7 +578,7 @@ get_request_line_inner (struct MHD_Connection *restrict c)
|
||||
(skip_empty_lines && (-3 >= discp_lvl));
|
||||
/* Treat bare LF as the end of the line.
|
||||
RFC 9112, section 2.2 */
|
||||
const bool bare_lf_as_crlf = MHD_ALLOW_BARE_LF_AS_CRLF_ (discp_lvl);
|
||||
const bool bare_lf_as_crlf = mhd_ALLOW_BARE_LF_AS_CRLF (discp_lvl);
|
||||
/* Treat tab as whitespace delimiter.
|
||||
RFC 9112, section 3 */
|
||||
const bool tab_as_wsp = (0 >= discp_lvl);
|
||||
@@ -1561,7 +1553,7 @@ get_req_header (struct MHD_Connection *restrict c,
|
||||
RFC 9112, section 2.2-3
|
||||
Note: MHD never replaces bare LF with space (RFC 9110, section 5.5-5).
|
||||
Bare LF is processed as end of the line or rejected as broken request. */
|
||||
const bool bare_lf_as_crlf = MHD_ALLOW_BARE_LF_AS_CRLF_ (discp_lvl);
|
||||
const bool bare_lf_as_crlf = mhd_ALLOW_BARE_LF_AS_CRLF (discp_lvl);
|
||||
/* Keep bare CR character as is.
|
||||
Violates RFC 9112, section 2.2-4 */
|
||||
const bool bare_cr_keep = (-3 >= discp_lvl);
|
||||
@@ -2949,15 +2941,36 @@ mhd_stream_call_app_request_cb (struct MHD_Connection *restrict c)
|
||||
}
|
||||
c->state = MHD_CONNECTION_FULL_REQ_RECEIVED;
|
||||
return true;
|
||||
#ifdef HAVE_POST_PARSER
|
||||
case mhd_ACTION_POST_PARSE:
|
||||
mhd_assert (0 && "Not implemented yet");
|
||||
if (0 == c->rq.cntn.cntn_size)
|
||||
{
|
||||
c->rq.u_proc.post.parse_result = MHD_POST_PARSE_RES_REQUEST_EMPTY;
|
||||
c->state = MHD_CONNECTION_FULL_REQ_RECEIVED;
|
||||
return true;
|
||||
}
|
||||
if (! mhd_stream_prepare_for_post_parse (c))
|
||||
{
|
||||
mhd_assert (MHD_CONNECTION_FOOTERS_RECEIVED < c->state);
|
||||
return true;
|
||||
}
|
||||
if (need_100_continue (c))
|
||||
{
|
||||
c->state = MHD_CONNECTION_CONTINUE_SENDING;
|
||||
return true;
|
||||
}
|
||||
c->state = MHD_CONNECTION_BODY_RECEIVING;
|
||||
return true;
|
||||
#endif /* HAVE_POST_PARSER */
|
||||
case mhd_ACTION_SUSPEND:
|
||||
c->suspended = true;
|
||||
return false;
|
||||
case mhd_ACTION_ABORT:
|
||||
mhd_conn_pre_close_app_abort (c);
|
||||
return false;
|
||||
return true;
|
||||
#ifndef HAVE_POST_PARSER
|
||||
case mhd_ACTION_POST_PARSE:
|
||||
#endif /* ! HAVE_POST_PARSER */
|
||||
case mhd_ACTION_NO_ACTION:
|
||||
default:
|
||||
mhd_assert (0 && "Impossible value");
|
||||
@@ -2976,10 +2989,10 @@ mhd_stream_call_app_request_cb (struct MHD_Connection *restrict c)
|
||||
* @return true if connection state has been changed,
|
||||
* false otherwise
|
||||
*/
|
||||
static MHD_FN_PAR_NONNULL_ (1) bool
|
||||
process_upload_action (struct MHD_Connection *restrict c,
|
||||
const struct MHD_UploadAction *act,
|
||||
bool final)
|
||||
MHD_INTERNAL MHD_FN_PAR_NONNULL_ (1) bool
|
||||
mhd_stream_process_upload_action (struct MHD_Connection *restrict c,
|
||||
const struct MHD_UploadAction *act,
|
||||
bool final)
|
||||
{
|
||||
if (NULL != act)
|
||||
{
|
||||
@@ -3011,7 +3024,7 @@ process_upload_action (struct MHD_Connection *restrict c,
|
||||
return false;
|
||||
case mhd_UPLOAD_ACTION_ABORT:
|
||||
mhd_conn_pre_close_app_abort (c);
|
||||
return false;
|
||||
return true;
|
||||
case mhd_UPLOAD_ACTION_NO_ACTION:
|
||||
default:
|
||||
mhd_assert (0 && "Impossible value");
|
||||
@@ -3034,7 +3047,7 @@ process_request_chunked_body (struct MHD_Connection *restrict c)
|
||||
RFC 9112, section 2.2-3
|
||||
Note: MHD never replaces bare LF with space (RFC 9110, section 5.5-5).
|
||||
Bare LF is processed as end of the line or rejected as broken request. */
|
||||
const bool bare_lf_as_crlf = MHD_ALLOW_BARE_LF_AS_CRLF_ (discp_lvl);
|
||||
const bool bare_lf_as_crlf = mhd_ALLOW_BARE_LF_AS_CRLF (discp_lvl);
|
||||
/* Allow "Bad WhiteSpace" in chunk extension.
|
||||
RFC 9112, Section 7.1.1, Paragraph 2 */
|
||||
const bool allow_bws = (2 < discp_lvl);
|
||||
@@ -3229,79 +3242,94 @@ process_request_chunked_body (struct MHD_Connection *restrict c)
|
||||
}
|
||||
mhd_assert (c->rq.app_aware);
|
||||
|
||||
#ifdef HAVE_POST_PARSER
|
||||
if (mhd_ACTION_POST_PARSE == c->rq.app_act.head_act.act)
|
||||
{
|
||||
mhd_assert (0 && "Not implemented yet"); // TODO: implement POST
|
||||
return false;
|
||||
}
|
||||
|
||||
if (NULL != c->rq.app_act.head_act.data.upload.full.cb)
|
||||
{
|
||||
need_inc_proc = false;
|
||||
|
||||
mhd_assert (0 == c->rq.cntn.proc_size);
|
||||
if ((uint_fast64_t) c->rq.cntn.lbuf.size <
|
||||
c->rq.cntn.recv_size + cntn_data_ready)
|
||||
{
|
||||
size_t grow_size;
|
||||
|
||||
grow_size = (size_t) (c->rq.cntn.recv_size + cntn_data_ready
|
||||
- c->rq.cntn.lbuf.size);
|
||||
if (((size_t) (c->rq.cntn.recv_size + cntn_data_ready) <
|
||||
cntn_data_ready) || (! mhd_daemon_grow_lbuf (d,
|
||||
grow_size,
|
||||
&(c->rq.cntn.lbuf))))
|
||||
{
|
||||
/* Failed to grow the buffer, no space to put the new data */
|
||||
const struct MHD_UploadAction *act;
|
||||
if (NULL != c->rq.app_act.head_act.data.upload.inc.cb)
|
||||
{
|
||||
mhd_RESPOND_WITH_ERROR_STATIC (
|
||||
c,
|
||||
MHD_HTTP_STATUS_CONTENT_TOO_LARGE,
|
||||
ERR_RSP_MSG_REQUEST_TOO_BIG);
|
||||
return true;
|
||||
}
|
||||
c->rq.app_act.head_act.data.upload.full.cb = NULL; /* Cannot process "full" content */
|
||||
/* Process previously buffered data */
|
||||
mhd_assert (c->rq.cntn.recv_size <= c->rq.cntn.lbuf.size);
|
||||
act = c->rq.app_act.head_act.data.upload.inc.cb (
|
||||
c->rq.app_act.head_act.data.upload.inc.cls,
|
||||
&(c->rq),
|
||||
c->rq.cntn.recv_size,
|
||||
c->rq.cntn.lbuf.buf);
|
||||
c->rq.cntn.proc_size = c->rq.cntn.recv_size;
|
||||
mhd_daemon_free_lbuf (d, &(c->rq.cntn.lbuf));
|
||||
if (process_upload_action (c, act, false))
|
||||
return true;
|
||||
need_inc_proc = true;
|
||||
}
|
||||
}
|
||||
if (! need_inc_proc)
|
||||
{
|
||||
memcpy (c->rq.cntn.lbuf.buf + c->rq.cntn.recv_size,
|
||||
buffer_head, cntn_data_ready);
|
||||
c->rq.cntn.recv_size += cntn_data_ready;
|
||||
}
|
||||
}
|
||||
else
|
||||
need_inc_proc = true;
|
||||
|
||||
if (need_inc_proc)
|
||||
{
|
||||
const struct MHD_UploadAction *act;
|
||||
mhd_assert (NULL != c->rq.app_act.head_act.data.upload.inc.cb);
|
||||
size_t size_provided;
|
||||
|
||||
c->rq.cntn.recv_size += cntn_data_ready;
|
||||
act = c->rq.app_act.head_act.data.upload.inc.cb (
|
||||
c->rq.app_act.head_act.data.upload.inc.cls,
|
||||
&(c->rq),
|
||||
cntn_data_ready,
|
||||
buffer_head);
|
||||
c->rq.cntn.proc_size += cntn_data_ready;
|
||||
state_updated = process_upload_action (c, act, false);
|
||||
}
|
||||
size_provided = cntn_data_ready;
|
||||
|
||||
state_updated = mhd_stream_post_parse (c,
|
||||
&cntn_data_ready,
|
||||
buffer_head);
|
||||
mhd_assert (0 == cntn_data_ready); // TODO: support one chunk in-place processing?
|
||||
c->rq.cntn.recv_size += size_provided;
|
||||
|
||||
}
|
||||
else
|
||||
#endif /* HAVE_POST_PARSER */
|
||||
if (1)
|
||||
{
|
||||
mhd_assert (mhd_ACTION_UPLOAD == c->rq.app_act.head_act.act);
|
||||
if (NULL != c->rq.app_act.head_act.data.upload.full.cb)
|
||||
{
|
||||
need_inc_proc = false;
|
||||
|
||||
mhd_assert (0 == c->rq.cntn.proc_size);
|
||||
if ((uint_fast64_t) c->rq.cntn.lbuf.size <
|
||||
c->rq.cntn.recv_size + cntn_data_ready)
|
||||
{
|
||||
size_t grow_size;
|
||||
|
||||
grow_size = (size_t) (c->rq.cntn.recv_size + cntn_data_ready
|
||||
- c->rq.cntn.lbuf.size);
|
||||
if (((size_t) (c->rq.cntn.recv_size + cntn_data_ready) <
|
||||
cntn_data_ready) ||
|
||||
(! mhd_daemon_grow_lbuf (d,
|
||||
grow_size,
|
||||
&(c->rq.cntn.lbuf))))
|
||||
{
|
||||
/* Failed to grow the buffer, no space to put the new data */
|
||||
const struct MHD_UploadAction *act;
|
||||
if (NULL != c->rq.app_act.head_act.data.upload.inc.cb)
|
||||
{
|
||||
mhd_RESPOND_WITH_ERROR_STATIC (
|
||||
c,
|
||||
MHD_HTTP_STATUS_CONTENT_TOO_LARGE,
|
||||
ERR_RSP_MSG_REQUEST_TOO_BIG);
|
||||
return true;
|
||||
}
|
||||
c->rq.app_act.head_act.data.upload.full.cb = NULL; /* Cannot process "full" content */
|
||||
/* Process previously buffered data */
|
||||
mhd_assert (c->rq.cntn.recv_size <= c->rq.cntn.lbuf.size);
|
||||
act = c->rq.app_act.head_act.data.upload.inc.cb (
|
||||
c->rq.app_act.head_act.data.upload.inc.cls,
|
||||
&(c->rq),
|
||||
c->rq.cntn.recv_size,
|
||||
c->rq.cntn.lbuf.data);
|
||||
c->rq.cntn.proc_size = c->rq.cntn.recv_size;
|
||||
mhd_daemon_free_lbuf (d, &(c->rq.cntn.lbuf));
|
||||
if (process_upload_action (c, act, false))
|
||||
return true;
|
||||
need_inc_proc = true;
|
||||
}
|
||||
}
|
||||
if (! need_inc_proc)
|
||||
{
|
||||
memcpy (c->rq.cntn.lbuf.data + c->rq.cntn.recv_size,
|
||||
buffer_head, cntn_data_ready);
|
||||
c->rq.cntn.recv_size += cntn_data_ready;
|
||||
}
|
||||
}
|
||||
else
|
||||
need_inc_proc = true;
|
||||
|
||||
if (need_inc_proc)
|
||||
{
|
||||
const struct MHD_UploadAction *act;
|
||||
mhd_assert (NULL != c->rq.app_act.head_act.data.upload.inc.cb);
|
||||
|
||||
c->rq.cntn.recv_size += cntn_data_ready;
|
||||
act = c->rq.app_act.head_act.data.upload.inc.cb (
|
||||
c->rq.app_act.head_act.data.upload.inc.cls,
|
||||
&(c->rq),
|
||||
cntn_data_ready,
|
||||
buffer_head);
|
||||
c->rq.cntn.proc_size += cntn_data_ready;
|
||||
state_updated = process_upload_action (c, act, false);
|
||||
}
|
||||
}
|
||||
/* dh left "processed" bytes in buffer for next time... */
|
||||
buffer_head += cntn_data_ready;
|
||||
available -= cntn_data_ready;
|
||||
@@ -3341,54 +3369,66 @@ process_request_nonchunked_body (struct MHD_Connection *restrict c)
|
||||
else
|
||||
cntn_data_ready = c->read_buffer_offset;
|
||||
|
||||
if (mhd_ACTION_POST_PARSE == c->rq.app_act.head_act.act)
|
||||
{
|
||||
mhd_assert (0 && "Not implemented yet"); // TODO: implement POST
|
||||
return false;
|
||||
}
|
||||
|
||||
mhd_assert (mhd_ACTION_UPLOAD == c->rq.app_act.head_act.act);
|
||||
read_buf_reuse = false;
|
||||
state_updated = false;
|
||||
if (NULL != c->rq.app_act.head_act.data.upload.full.cb)
|
||||
|
||||
if (mhd_ACTION_POST_PARSE == c->rq.app_act.head_act.act)
|
||||
{
|
||||
// TODO: implement processing in pool memory if buffer is large enough
|
||||
mhd_assert ((c->rq.cntn.recv_size + cntn_data_ready) <=
|
||||
(uint_fast64_t) c->rq.cntn.lbuf.size);
|
||||
memcpy (c->rq.cntn.lbuf.buf + c->rq.cntn.recv_size,
|
||||
c->read_buffer, cntn_data_ready);
|
||||
size_t size_provided;
|
||||
|
||||
c->rq.cntn.recv_size += cntn_data_ready;
|
||||
size_provided = cntn_data_ready;
|
||||
|
||||
state_updated = mhd_stream_post_parse (c,
|
||||
&size_provided,
|
||||
c->read_buffer);
|
||||
mhd_assert (0 == size_provided); // TODO: support one chunk in-place processing?
|
||||
read_buf_reuse = true; // TODO: support one chunk in-place processing?
|
||||
c->rq.cntn.recv_size += cntn_data_ready;
|
||||
read_buf_reuse = true;
|
||||
if (c->rq.cntn.recv_size == c->rq.cntn.cntn_size)
|
||||
{
|
||||
c->state = MHD_CONNECTION_FULL_REQ_RECEIVED;
|
||||
state_updated = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const struct MHD_UploadAction *act;
|
||||
mhd_assert (NULL != c->rq.app_act.head_act.data.upload.inc.cb);
|
||||
mhd_assert (mhd_ACTION_UPLOAD == c->rq.app_act.head_act.act);
|
||||
if (NULL != c->rq.app_act.head_act.data.upload.full.cb)
|
||||
{
|
||||
// TODO: implement processing in pool memory if buffer is large enough
|
||||
mhd_assert ((c->rq.cntn.recv_size + cntn_data_ready) <=
|
||||
(uint_fast64_t) c->rq.cntn.lbuf.size);
|
||||
memcpy (c->rq.cntn.lbuf.data + c->rq.cntn.recv_size,
|
||||
c->read_buffer, cntn_data_ready);
|
||||
c->rq.cntn.recv_size += cntn_data_ready;
|
||||
read_buf_reuse = true;
|
||||
if (c->rq.cntn.recv_size == c->rq.cntn.cntn_size)
|
||||
{
|
||||
c->state = MHD_CONNECTION_FULL_REQ_RECEIVED;
|
||||
state_updated = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const struct MHD_UploadAction *act;
|
||||
mhd_assert (NULL != c->rq.app_act.head_act.data.upload.inc.cb);
|
||||
|
||||
c->rq.cntn.recv_size += cntn_data_ready;
|
||||
act = c->rq.app_act.head_act.data.upload.inc.cb (
|
||||
c->rq.app_act.head_act.data.upload.inc.cls,
|
||||
&(c->rq),
|
||||
cntn_data_ready,
|
||||
c->read_buffer);
|
||||
c->rq.cntn.proc_size += cntn_data_ready;
|
||||
read_buf_reuse = true;
|
||||
state_updated = process_upload_action (c, act, false);
|
||||
c->rq.cntn.recv_size += cntn_data_ready;
|
||||
act = c->rq.app_act.head_act.data.upload.inc.cb (
|
||||
c->rq.app_act.head_act.data.upload.inc.cls,
|
||||
&(c->rq),
|
||||
cntn_data_ready,
|
||||
c->read_buffer);
|
||||
c->rq.cntn.proc_size += cntn_data_ready;
|
||||
read_buf_reuse = true;
|
||||
state_updated = process_upload_action (c, act, false);
|
||||
}
|
||||
}
|
||||
|
||||
if (read_buf_reuse)
|
||||
{
|
||||
size_t data_left_size;
|
||||
mhd_assert (c->read_buffer_offset >= cntn_data_ready);
|
||||
data_left_size = c->read_buffer_offset - cntn_data_ready;
|
||||
if (0 != data_left_size)
|
||||
memmove (c->read_buffer, c->read_buffer + cntn_data_ready, data_left_size)
|
||||
;
|
||||
memmove (c->read_buffer,
|
||||
c->read_buffer + cntn_data_ready,
|
||||
data_left_size);
|
||||
c->read_buffer_offset = data_left_size;
|
||||
}
|
||||
|
||||
@@ -3423,14 +3463,14 @@ mhd_stream_call_app_final_upload_cb (struct MHD_Connection *restrict c)
|
||||
{
|
||||
mhd_assert (c->rq.cntn.recv_size == c->rq.cntn.cntn_size);
|
||||
mhd_assert (0 == c->rq.cntn.proc_size);
|
||||
mhd_assert (NULL != c->rq.cntn.lbuf.buf);
|
||||
mhd_assert (NULL != c->rq.cntn.lbuf.data);
|
||||
mhd_assert (c->rq.cntn.recv_size <= c->rq.cntn.lbuf.size);
|
||||
// TODO: implement processing in pool memory if it is large enough
|
||||
act = c->rq.app_act.head_act.data.upload.full.cb (
|
||||
c->rq.app_act.head_act.data.upload.full.cls,
|
||||
&(c->rq),
|
||||
c->rq.cntn.recv_size,
|
||||
c->rq.cntn.lbuf.buf);
|
||||
c->rq.cntn.lbuf.data);
|
||||
c->rq.cntn.proc_size = c->rq.cntn.recv_size;
|
||||
}
|
||||
else
|
||||
@@ -3450,9 +3490,9 @@ mhd_stream_call_app_final_upload_cb (struct MHD_Connection *restrict c)
|
||||
MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ bool
|
||||
mhd_stream_process_req_recv_finished (struct MHD_Connection *restrict c)
|
||||
{
|
||||
if (NULL != c->rq.cntn.lbuf.buf)
|
||||
if (NULL != c->rq.cntn.lbuf.data)
|
||||
mhd_daemon_free_lbuf (c->daemon, &(c->rq.cntn.lbuf));
|
||||
c->rq.cntn.lbuf.buf = NULL;
|
||||
c->rq.cntn.lbuf.data = NULL;
|
||||
if (c->rq.cntn.cntn_size != c->rq.cntn.proc_size)
|
||||
c->discard_request = true;
|
||||
mhd_assert (NULL != c->rp.response);
|
||||
|
||||
@@ -145,6 +145,22 @@ MHD_INTERNAL bool
|
||||
mhd_stream_call_app_request_cb (struct MHD_Connection *restrict c)
|
||||
MHD_FN_PAR_NONNULL_ALL_;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* React on provided action for upload
|
||||
* @param c the stream to use
|
||||
* @param act the action provided by application
|
||||
* @param final set to 'true' if this is final upload callback
|
||||
* @return true if connection state has been changed,
|
||||
* false otherwise
|
||||
*/
|
||||
MHD_INTERNAL bool
|
||||
mhd_stream_process_upload_action (struct MHD_Connection *restrict c,
|
||||
const struct MHD_UploadAction *act,
|
||||
bool final)
|
||||
MHD_FN_PAR_NONNULL_ (1);
|
||||
|
||||
/**
|
||||
* Process non-chunked request body or upload chunking encoding.
|
||||
* Call the upload handler of the application.
|
||||
|
||||
@@ -252,7 +252,7 @@ mhd_conn_process_data (struct MHD_Connection *restrict c)
|
||||
return false;
|
||||
}
|
||||
|
||||
while (true) // TODO: support suspend
|
||||
while (! c->suspended)
|
||||
{
|
||||
#ifdef HTTPS_SUPPORT
|
||||
// TODO: support TLS, handshake
|
||||
@@ -357,7 +357,7 @@ mhd_conn_process_data (struct MHD_Connection *restrict c)
|
||||
mhd_assert (NULL != c->rp.response);
|
||||
mhd_stream_switch_from_recv_to_send (c);
|
||||
if (! mhd_stream_build_header_response (c))
|
||||
break;
|
||||
continue;
|
||||
mhd_assert (MHD_CONNECTION_START_REPLY != c->state);
|
||||
break;
|
||||
case MHD_CONNECTION_HEADERS_SENDING:
|
||||
@@ -441,7 +441,8 @@ mhd_conn_process_data (struct MHD_Connection *restrict c)
|
||||
mhd_assert (c->write_buffer_send_offset <= \
|
||||
c->write_buffer_append_offset);
|
||||
mhd_stream_call_dcc_cleanup_if_needed (c);
|
||||
mhd_stream_prep_chunked_footer (c);
|
||||
if (mhd_stream_prep_chunked_footer (c))
|
||||
continue;
|
||||
break;
|
||||
case MHD_CONNECTION_FOOTERS_SENDING:
|
||||
mhd_assert (c->rp.props.send_reply_body);
|
||||
@@ -457,6 +458,9 @@ mhd_conn_process_data (struct MHD_Connection *restrict c)
|
||||
&& ! c->discard_request
|
||||
&& ! c->sk_rmt_shut_wr);
|
||||
continue;
|
||||
case MHD_CONNECTION_PRE_CLOSING:
|
||||
mhd_conn_pre_clean (c);
|
||||
break;
|
||||
case MHD_CONNECTION_CLOSED:
|
||||
break;
|
||||
#if 0 // def UPGRADE_SUPPORT
|
||||
@@ -471,6 +475,8 @@ mhd_conn_process_data (struct MHD_Connection *restrict c)
|
||||
break;
|
||||
}
|
||||
|
||||
mhd_assert (MHD_CONNECTION_PRE_CLOSING != c->state);
|
||||
|
||||
if (MHD_CONNECTION_CLOSED == c->state)
|
||||
return false;
|
||||
|
||||
@@ -488,15 +494,22 @@ mhd_conn_process_data (struct MHD_Connection *restrict c)
|
||||
mhd_CONN_CLOSE_HTTP_COMPLETED :
|
||||
mhd_CONN_CLOSE_CLIENT_SHUTDOWN_EARLY,
|
||||
NULL);
|
||||
mhd_conn_pre_clean (c);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mhd_stream_check_timedout (c)) // TODO: centralise timeout checks
|
||||
{
|
||||
mhd_conn_pre_close_timedout (c);
|
||||
mhd_conn_pre_clean (c);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (! update_active_state (c))
|
||||
{
|
||||
mhd_conn_pre_clean (c);
|
||||
return false;
|
||||
}
|
||||
update_active_state (c);
|
||||
/* MHD_connection_update_event_loop_info (c);*/
|
||||
|
||||
return true;
|
||||
|
||||
Reference in New Issue
Block a user