mirror of
https://git.gnunet.org/libmicrohttpd.git
synced 2026-09-29 04:09:31 +03:00
post_parser: implemented URL-decoding, minor API update
This commit is contained in:
9 files changed
+814
-187
No files matched your search
@@ -6410,13 +6410,13 @@ 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 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 max_nonstream_size the size of the field (in encoded form) above which
|
||||
* values are not buffered and provided for
|
||||
* 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
|
||||
* @param stream_reader the function to call for "oversize" values in
|
||||
@@ -6438,7 +6438,7 @@ typedef const struct MHD_UploadAction *
|
||||
MHD_EXTERN_ const struct MHD_Action *
|
||||
MHD_action_parse_post (struct MHD_Request *request,
|
||||
size_t buffer_size,
|
||||
size_t auto_stream_size,
|
||||
size_t max_nonstream_size,
|
||||
enum MHD_HTTP_PostEncoding enc,
|
||||
MHD_PostDataReader stream_reader,
|
||||
void *reader_cls,
|
||||
|
||||
@@ -2046,13 +2046,13 @@ 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 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 max_nonstream_size the size of the field (in encoded form) above which
|
||||
* values are not buffered and provided for
|
||||
* 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
|
||||
* @param stream_reader the function to call for "oversize" values in
|
||||
@@ -2074,7 +2074,7 @@ typedef const struct MHD_UploadAction *
|
||||
MHD_EXTERN_ const struct MHD_Action *
|
||||
MHD_action_parse_post (struct MHD_Request *request,
|
||||
size_t buffer_size,
|
||||
size_t auto_stream_size,
|
||||
size_t max_nonstream_size,
|
||||
enum MHD_HTTP_PostEncoding enc,
|
||||
MHD_PostDataReader stream_reader,
|
||||
void *reader_cls,
|
||||
|
||||
+3
-3
@@ -109,7 +109,7 @@ MHD_EXTERN_
|
||||
MHD_FN_PAR_NONNULL_ (1) const struct MHD_Action *
|
||||
MHD_action_parse_post (struct MHD_Request *request,
|
||||
size_t buffer_size,
|
||||
size_t auto_stream_size,
|
||||
size_t max_nonstream_size,
|
||||
enum MHD_HTTP_PostEncoding enc,
|
||||
MHD_PostDataReader stream_reader,
|
||||
void *reader_cls,
|
||||
@@ -126,7 +126,7 @@ MHD_action_parse_post (struct MHD_Request *request,
|
||||
|
||||
head_act->act = mhd_ACTION_POST_PARSE;
|
||||
head_act->data.post_parse.buffer_size = buffer_size;
|
||||
head_act->data.post_parse.auto_stream_size = auto_stream_size;
|
||||
head_act->data.post_parse.max_nonstream_size = max_nonstream_size;
|
||||
head_act->data.post_parse.enc = enc;
|
||||
head_act->data.post_parse.stream_reader = stream_reader;
|
||||
head_act->data.post_parse.reader_cls = reader_cls;
|
||||
@@ -135,7 +135,7 @@ MHD_action_parse_post (struct MHD_Request *request,
|
||||
|
||||
return head_act;
|
||||
#else /* ! HAVE_POST_PARSER */
|
||||
(void) request; (void) buffer_size; (void) auto_stream_size;
|
||||
(void) request; (void) buffer_size; (void) max_nonstream_size;
|
||||
(void) enc; (void) stream_reader; (void) reader_cls;
|
||||
(void) done_cb; (void) done_cb_cls;
|
||||
return NULL;
|
||||
|
||||
@@ -166,7 +166,7 @@ typedef const struct MHD_UploadAction *
|
||||
struct mhd_PostParseActionData
|
||||
{
|
||||
size_t buffer_size;
|
||||
size_t auto_stream_size;
|
||||
size_t max_nonstream_size;
|
||||
enum MHD_HTTP_PostEncoding enc;
|
||||
MHD_PostDataReader stream_reader;
|
||||
void *reader_cls;
|
||||
|
||||
@@ -36,12 +36,112 @@
|
||||
#include "mhd_post_result.h"
|
||||
#include "mhd_buffer.h"
|
||||
|
||||
#ifdef SIZE_MAX
|
||||
# define mhd_POST_INVALID_POS SIZE_MAX
|
||||
#else
|
||||
# define mhd_POST_INVALID_POS ((size_t) (~((size_t) (0))))
|
||||
#endif
|
||||
|
||||
/**
|
||||
* The states of the "application/x-www-form-urlencoded" field parsing
|
||||
*/
|
||||
enum MHD_FIXED_ENUM_ mhd_PostUrlEncState
|
||||
{
|
||||
/**
|
||||
* The field processing has not been started
|
||||
*/
|
||||
mhd_POST_UENC_ST_NOT_STARTED = 0
|
||||
,
|
||||
/**
|
||||
* Processing name of the field
|
||||
*/
|
||||
mhd_POST_UENC_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_UENC_ST_AT_EQ
|
||||
,
|
||||
/**
|
||||
* The '=' character after the name has been found.
|
||||
* Looking for the first value character.
|
||||
*/
|
||||
mhd_POST_UENC_ST_EQ_FOUND
|
||||
,
|
||||
/**
|
||||
* Processing the value of the field.
|
||||
*/
|
||||
mhd_POST_UENC_ST_VALUE
|
||||
,
|
||||
/**
|
||||
* At the ampersand '&' character.
|
||||
* Means that full field is 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_UENC_ST_AT_AMPRSND
|
||||
,
|
||||
/**
|
||||
* Full field 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_UENC_ST_FULL_FIELD_FOUND
|
||||
};
|
||||
|
||||
/**
|
||||
* The "application/x-www-form-urlencoded" parsing data
|
||||
*/
|
||||
struct mhd_PostParserUrlEncData
|
||||
{
|
||||
/**
|
||||
* The parsing state
|
||||
*/
|
||||
enum mhd_PostUrlEncState 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.
|
||||
* If @a st is #mhd_POST_UENC_ST_VALUE and @a value_len is not zero,
|
||||
* then it is the length of the partial (decoded) value provided previously
|
||||
* to the "stream" processing callback (which responded with a "suspend"
|
||||
* action).
|
||||
*/
|
||||
size_t value_len;
|
||||
|
||||
/**
|
||||
* The index of the last percent ('%') character found.
|
||||
* Set to #mhd_POST_INVALID_POS when no '%' char found.
|
||||
* Used for two proposes:
|
||||
* + indicates that "name" or "value" needs persent-deconding
|
||||
* + helps to detect incomplete percent-encoded char for stream processing
|
||||
*/
|
||||
size_t last_pct_idx;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
+16
-14
@@ -1712,7 +1712,7 @@ mhd_str_pct_decode_lenient_n (const char *pct_encoded,
|
||||
size_t pct_encoded_len,
|
||||
char *decoded,
|
||||
size_t buf_size,
|
||||
bool *broken_encoding)
|
||||
bool *restrict broken_encoding)
|
||||
{
|
||||
size_t r;
|
||||
size_t w;
|
||||
@@ -1867,8 +1867,8 @@ mhd_str_pct_decode_in_place_strict (char *str)
|
||||
|
||||
|
||||
MHD_INTERNAL size_t
|
||||
mhd_str_pct_decode_in_place_lenient (char *str,
|
||||
bool *broken_encoding)
|
||||
mhd_str_pct_decode_in_place_lenient (char *restrict str,
|
||||
bool *restrict broken_encoding)
|
||||
{
|
||||
#ifdef MHD_FAVOR_SMALL_CODE
|
||||
size_t len;
|
||||
@@ -2031,6 +2031,7 @@ mhd_str_unquote (const char *quoted,
|
||||
return w;
|
||||
}
|
||||
|
||||
|
||||
#endif /* DAUTH_SUPPORT HAVE_POST_PARSER */
|
||||
|
||||
#if defined(DAUTH_SUPPORT) || defined(BAUTH_SUPPORT)
|
||||
@@ -2338,9 +2339,9 @@ mhd_str_starts_with_token_opt_param (const struct MHD_String *restrict str,
|
||||
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));
|
||||
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 */
|
||||
@@ -2364,8 +2365,9 @@ mhd_str_starts_with_token_opt_param (const struct MHD_String *restrict str,
|
||||
}
|
||||
|
||||
|
||||
MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_OUT_(4)
|
||||
MHD_FN_PAR_OUT_(5) enum mhd_StingStartsWithTokenResult
|
||||
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,
|
||||
@@ -2379,12 +2381,12 @@ mhd_str_starts_with_token_req_param (
|
||||
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));
|
||||
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;
|
||||
|
||||
+4
-4
@@ -556,7 +556,7 @@ mhd_str_pct_decode_lenient_n (const char *pct_encoded,
|
||||
size_t pct_encoded_len,
|
||||
char *decoded,
|
||||
size_t buf_size,
|
||||
bool *broken_encoding);
|
||||
bool *restrict broken_encoding);
|
||||
|
||||
|
||||
/**
|
||||
@@ -595,8 +595,8 @@ mhd_str_pct_decode_in_place_strict (char *str);
|
||||
* @return the number of character in decoded string
|
||||
*/
|
||||
MHD_INTERNAL size_t
|
||||
mhd_str_pct_decode_in_place_lenient (char *str,
|
||||
bool *broken_encoding);
|
||||
mhd_str_pct_decode_in_place_lenient (char *restrict str,
|
||||
bool *restrict broken_encoding);
|
||||
|
||||
#ifdef DAUTH_SUPPORT
|
||||
/**
|
||||
@@ -849,6 +849,6 @@ mhd_str_starts_with_token_req_param (
|
||||
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);
|
||||
MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_OUT_(4) MHD_FN_PAR_OUT_ (5);
|
||||
|
||||
#endif /* MHD_STR_H */
|
||||
+673
-149
@@ -302,14 +302,19 @@ detect_mpart_boundary_from_the_header (struct MHD_Connection *restrict c)
|
||||
|
||||
|
||||
static MHD_FN_PAR_NONNULL_ (1) void
|
||||
reset_text_parse_field_data (struct mhd_PostParserData *pdata)
|
||||
reset_parse_field_data_urlenc (struct mhd_PostParserData *pdata)
|
||||
{
|
||||
mhd_assert (MHD_HTTP_POST_ENCODING_FORM_URLENCODED == pdata->enc);
|
||||
memset (&(pdata->e_d.text), 0, sizeof(pdata->e_d.u_enc));
|
||||
pdata->field_start = 0;
|
||||
}
|
||||
|
||||
|
||||
static MHD_FN_PAR_NONNULL_ (1) void
|
||||
reset_parse_field_data_text (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;
|
||||
}
|
||||
|
||||
@@ -333,13 +338,14 @@ init_post_parse_data (struct MHD_Connection *restrict c)
|
||||
switch (pdata->enc)
|
||||
{
|
||||
case MHD_HTTP_POST_ENCODING_FORM_URLENCODED:
|
||||
// TODO:
|
||||
reset_parse_field_data_urlenc (pdata);
|
||||
break;
|
||||
case MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA:
|
||||
// TODO
|
||||
mhd_assert (0 && "Not yet finished");
|
||||
break;
|
||||
case MHD_HTTP_POST_ENCODING_TEXT_PLAIN:
|
||||
reset_text_parse_field_data (pdata);
|
||||
reset_parse_field_data_text (pdata);
|
||||
break;
|
||||
case MHD_HTTP_POST_ENCODING_OTHER:
|
||||
default:
|
||||
@@ -449,6 +455,37 @@ grow_lbuf_fixed_size (struct MHD_Connection *restrict c,
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test whether current incomplete value must be provided to the "stream"
|
||||
* reader.
|
||||
* @param c the connection to use
|
||||
* @param field_cur_size the current size of the current field
|
||||
* @return 'true' if the value must be provided via the "stream" reader,
|
||||
* 'false' otherwise.
|
||||
*/
|
||||
MHD_static_inline_ MHD_FN_PURE_ MHD_FN_PAR_NONNULL_ALL_ bool
|
||||
is_value_streaming_needed (struct MHD_Connection *restrict c,
|
||||
size_t field_cur_size)
|
||||
{
|
||||
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);
|
||||
|
||||
if (NULL == p_par->stream_reader)
|
||||
{
|
||||
mhd_assert (0 == p_data->value_off);
|
||||
return false; /* No value streaming possible */
|
||||
}
|
||||
|
||||
if (0 != p_data->value_off)
|
||||
return true; /* Part of the value has been already provided to "stream"
|
||||
reader, the rest of the value should be provided
|
||||
in the same way */
|
||||
|
||||
return (p_par->max_nonstream_size < field_cur_size);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add parsed POST field to the list of request's fields
|
||||
* @param c the stream to use
|
||||
@@ -606,7 +643,6 @@ process_complete_field_all (struct MHD_Connection *restrict c,
|
||||
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);
|
||||
|
||||
@@ -617,20 +653,25 @@ process_complete_field_all (struct MHD_Connection *restrict c,
|
||||
mhd_assert ((0 == enc_start) || \
|
||||
(MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA == p_data->enc));
|
||||
|
||||
mhd_assert (MHD_CONNECTION_REQ_RECV_FINISHED >= c->state);
|
||||
mhd_assert (value_start + value_len <= *pnext_pos);
|
||||
mhd_assert ((MHD_CONNECTION_FULL_REQ_RECEIVED <= c->state) || \
|
||||
(value_start + value_len < *pnext_pos));
|
||||
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 (value_start + value_len <= *pnext_pos);
|
||||
mhd_assert ((MHD_CONNECTION_FULL_REQ_RECEIVED <= c->state) || \
|
||||
(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 (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 (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 (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));
|
||||
@@ -657,66 +698,69 @@ process_complete_field_all (struct MHD_Connection *restrict c,
|
||||
&content_type,
|
||||
&encoding);
|
||||
|
||||
if (NULL != p_par->stream_reader)
|
||||
if (is_value_streaming_needed (c, (*pnext_pos - field_start)))
|
||||
{
|
||||
if ((p_par->auto_stream_size < (*pnext_pos - field_start))
|
||||
|| (0 != p_data->value_off))
|
||||
bool res;
|
||||
const struct MHD_UploadAction *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);
|
||||
p_data->some_data_provided = true;
|
||||
res = mhd_stream_process_upload_action (c, act, false);
|
||||
if (c->suspended)
|
||||
return true;
|
||||
p_data->value_off = 0;
|
||||
if (*pdata_size > *pnext_pos)
|
||||
{
|
||||
bool res;
|
||||
const struct MHD_UploadAction *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;
|
||||
memmove (buf + field_start,
|
||||
buf + *pnext_pos,
|
||||
*pdata_size - *pnext_pos);
|
||||
}
|
||||
}
|
||||
|
||||
if (0 != value_start)
|
||||
{
|
||||
value.len = value_len;
|
||||
value.cstr = buf + value_start;
|
||||
*pnext_pos -= field_size;
|
||||
*pdata_size -= field_size;
|
||||
return res;
|
||||
}
|
||||
else
|
||||
{
|
||||
value.len = 0;
|
||||
value.cstr = NULL;
|
||||
}
|
||||
struct MHD_StringNullable value;
|
||||
|
||||
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;
|
||||
if (0 != value_start)
|
||||
{
|
||||
value.len = value_len;
|
||||
value.cstr = buf + value_start;
|
||||
}
|
||||
else
|
||||
{
|
||||
value.len = 0;
|
||||
value.cstr = NULL;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
p_data->some_data_provided = true;
|
||||
}
|
||||
|
||||
return false; /* Continue parsing */
|
||||
@@ -752,10 +796,15 @@ process_complete_field (struct MHD_Connection *restrict c,
|
||||
size_t value_start,
|
||||
size_t value_len)
|
||||
{
|
||||
mhd_assert (value_start + value_len < *pnext_pos);
|
||||
mhd_assert (MHD_CONNECTION_REQ_RECV_FINISHED >= c->state);
|
||||
mhd_assert (value_start + value_len <= *pnext_pos);
|
||||
mhd_assert ((MHD_CONNECTION_FULL_REQ_RECEIVED <= c->state) || \
|
||||
(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 (name_start + name_len <= *pnext_pos);
|
||||
mhd_assert ((MHD_CONNECTION_FULL_REQ_RECEIVED <= c->state) || \
|
||||
(name_start + name_len < *pnext_pos));
|
||||
mhd_assert (field_start <= name_start);
|
||||
mhd_assert ((field_start <= value_start) || (0 == value_start));
|
||||
|
||||
@@ -775,12 +824,42 @@ process_complete_field (struct MHD_Connection *restrict c,
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Process the part of the POST value.
|
||||
*
|
||||
* The part of the value are be provided for "streaming" processing by
|
||||
* the application callback and removed from the buffer (the remaining of
|
||||
* the data in the buffer is shifted backward).
|
||||
* The function must be called only when streaming is the partial value is
|
||||
* needed.
|
||||
*
|
||||
* @param c the connection to use
|
||||
* @param buf the pointer to the buffer
|
||||
* @param pnext_pos the position of the next character to be processed
|
||||
* in the buffer
|
||||
* @param pdata_size the size of the data in the buffer
|
||||
* @param name_start the position of the "name", must be zero-terminated
|
||||
* @param name_len the length of the "name", not including zero-termination
|
||||
* @param filename_start the position of the filename, zero if not
|
||||
* provided / set
|
||||
* @param filename_len the length of the filename
|
||||
* @param cntn_type_start the position of field "Content-Type" value, zero
|
||||
* if not provided / set
|
||||
* @param cntn_type_len the length of the field "Content-Type" value
|
||||
* @param enc_start the position of the field "Content-Encoding" value, zero
|
||||
* if not provided / set
|
||||
* @param enc_len the length of the field "Content-Encoding" value
|
||||
* @param part_value_start the position of partial value data, does not
|
||||
* need to be zero-terminated
|
||||
* @param part_value_len the length of the partial value data
|
||||
* @return 'true' if connection/stream state has been changed,
|
||||
* 'false' indicates the need to continuation of POST data parsing
|
||||
*/
|
||||
static MHD_FN_PAR_NONNULL_ALL_ bool
|
||||
process_partial_value_all (struct MHD_Connection *restrict c,
|
||||
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,
|
||||
@@ -795,95 +874,120 @@ process_partial_value_all (struct MHD_Connection *restrict c,
|
||||
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;
|
||||
const struct MHD_UploadAction *act;
|
||||
bool res;
|
||||
|
||||
mhd_assert (*pnext_pos < *pdata_size);
|
||||
mhd_assert (MHD_CONNECTION_REQ_RECV_FINISHED >= c->state);
|
||||
mhd_assert (part_value_start + part_value_len <= *pnext_pos);
|
||||
mhd_assert ((MHD_CONNECTION_FULL_REQ_RECEIVED <= c->state) || \
|
||||
(part_value_start + part_value_len < *pnext_pos));
|
||||
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 (0 != part_value_len);
|
||||
mhd_assert (name_start + name_len <= *pnext_pos);
|
||||
mhd_assert ((MHD_CONNECTION_FULL_REQ_RECEIVED <= c->state) || \
|
||||
(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 (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 (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 (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));
|
||||
mhd_assert (NULL != p_par->stream_reader);
|
||||
|
||||
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);
|
||||
|
||||
p_data->some_data_provided = true;
|
||||
|
||||
if (NULL == p_par->stream_reader)
|
||||
return false; /* Continue parsing */
|
||||
res = mhd_stream_process_upload_action (c, act, false);
|
||||
if (c->suspended)
|
||||
return true;
|
||||
|
||||
if ((p_par->auto_stream_size < (*pnext_pos - field_start))
|
||||
|| (0 != p_data->value_off))
|
||||
p_data->value_off += part_value_len;
|
||||
if (*pdata_size > *pnext_pos)
|
||||
{
|
||||
struct MHD_String name;
|
||||
struct MHD_StringNullable filename;
|
||||
struct MHD_StringNullable content_type;
|
||||
struct MHD_StringNullable encoding;
|
||||
const struct MHD_UploadAction *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;
|
||||
memmove (buf + part_value_start,
|
||||
buf + part_value_start + part_value_len,
|
||||
part_value_len);
|
||||
}
|
||||
return false; /* Continue parsing */
|
||||
*pnext_pos -= part_value_len;
|
||||
*pdata_size -= part_value_len;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Process the part of the POST value.
|
||||
* The part of the value are be provided for "streaming" processing by
|
||||
* the application callback and removed from the buffer (the remaining of
|
||||
* the data in the buffer is shifted backward).
|
||||
* The function must be called only when streaming is the partial value is
|
||||
* needed.
|
||||
* @param c the connection to use
|
||||
* @param buf the pointer to the buffer
|
||||
* @param pnext_pos the position of the next character to be processed
|
||||
* in the buffer
|
||||
* @param pdata_size the size of the data in the buffer
|
||||
* @param name_start the position of the "name", must be zero-terminated
|
||||
* @param name_len the length of the "name", not including zero-termination
|
||||
* @param part_value_start the position of partial value data, does not
|
||||
* need to be zero-terminated
|
||||
* @param part_value_len the length of the partial value data
|
||||
* @return 'true' if connection/stream state has been changed,
|
||||
* 'false' indicates the need to continuation of POST data parsing
|
||||
*/
|
||||
static MHD_FN_PAR_NONNULL_ALL_ bool
|
||||
process_partial_value (struct MHD_Connection *restrict c,
|
||||
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 (MHD_CONNECTION_REQ_RECV_FINISHED >= c->state);
|
||||
mhd_assert (part_value_start + part_value_len <= *pnext_pos);
|
||||
mhd_assert ((MHD_CONNECTION_FULL_REQ_RECEIVED <= c->state) || \
|
||||
(part_value_start + part_value_len < *pnext_pos));
|
||||
mhd_assert (name_start + name_len <= part_value_start);
|
||||
mhd_assert ((MHD_CONNECTION_FULL_REQ_RECEIVED <= c->state) || \
|
||||
(name_start + name_len < part_value_start));
|
||||
mhd_assert (0 != part_value_start);
|
||||
mhd_assert (0 != part_value_len);
|
||||
mhd_assert (name_start + name_len < *pnext_pos);
|
||||
|
||||
|
||||
mhd_assert (MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA != \
|
||||
c->rq.u_proc.post.enc);
|
||||
|
||||
@@ -891,7 +995,6 @@ process_partial_value (struct MHD_Connection *restrict c,
|
||||
buf,
|
||||
pnext_pos,
|
||||
pdata_size,
|
||||
field_start,
|
||||
name_start,
|
||||
name_len,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
@@ -900,6 +1003,253 @@ process_partial_value (struct MHD_Connection *restrict c,
|
||||
}
|
||||
|
||||
|
||||
static MHD_FN_PAR_NONNULL_ALL_
|
||||
MHD_FN_PAR_INOUT_ (2) MHD_FN_PAR_INOUT_ (3) bool
|
||||
parse_post_urlenc (struct MHD_Connection *restrict c,
|
||||
size_t *restrict pdata_size,
|
||||
char *restrict buf)
|
||||
{
|
||||
struct mhd_PostParserData *const p_data = &(c->rq.u_proc.post);
|
||||
struct mhd_PostParserUrlEncData *const uf = &(p_data->e_d.u_enc); /**< the current "url-enc" field */
|
||||
size_t i;
|
||||
|
||||
mhd_assert (MHD_HTTP_POST_ENCODING_FORM_URLENCODED == c->rq.u_proc.post.enc);
|
||||
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);
|
||||
|
||||
if ((mhd_POST_UENC_ST_VALUE == uf->st) &&
|
||||
(0 != uf->value_len))
|
||||
{
|
||||
/* The 'value' was partially decoded, but not processed because application
|
||||
* asked for 'suspend' action */
|
||||
mhd_assert (NULL != c->rq.app_act.head_act.data.post_parse.stream_reader);
|
||||
if (process_partial_value (c,
|
||||
buf,
|
||||
&p_data->next_parse_pos,
|
||||
pdata_size,
|
||||
uf->name_idx,
|
||||
uf->name_len,
|
||||
uf->value_idx,
|
||||
uf->value_len))
|
||||
return true;
|
||||
uf->value_len = 0;
|
||||
}
|
||||
|
||||
i = p_data->next_parse_pos;
|
||||
while (*pdata_size > i)
|
||||
{
|
||||
switch (uf->st)
|
||||
{
|
||||
case mhd_POST_UENC_ST_NOT_STARTED:
|
||||
mhd_assert (0 == p_data->field_start);
|
||||
mhd_assert (0 == p_data->value_off);
|
||||
p_data->field_start = i;
|
||||
uf->name_idx = i;
|
||||
uf->last_pct_idx = mhd_POST_INVALID_POS;
|
||||
uf->st = mhd_POST_UENC_ST_NAME;
|
||||
/* Intentional fall-through */
|
||||
case mhd_POST_UENC_ST_NAME:
|
||||
do /* Fast local loop */
|
||||
{
|
||||
if ('+' == buf[i])
|
||||
buf[i] = ' ';
|
||||
else if ('%' == buf[i])
|
||||
uf->last_pct_idx = i;
|
||||
else if ('=' == buf[i])
|
||||
{
|
||||
uf->st = mhd_POST_UENC_ST_AT_EQ;
|
||||
break;
|
||||
}
|
||||
else if ('&' == buf[i])
|
||||
{
|
||||
uf->st = mhd_POST_UENC_ST_AT_AMPRSND;
|
||||
break;
|
||||
}
|
||||
} while (*pdata_size > ++i);
|
||||
mhd_assert ((*pdata_size == i) || \
|
||||
(mhd_POST_UENC_ST_AT_EQ == uf->st) || \
|
||||
(mhd_POST_UENC_ST_AT_AMPRSND == uf->st) );
|
||||
continue;
|
||||
case mhd_POST_UENC_ST_AT_EQ:
|
||||
mhd_assert (i > uf->name_idx);
|
||||
mhd_assert (0 == uf->name_len);
|
||||
mhd_assert (uf->last_pct_idx >= p_data->field_start);
|
||||
mhd_assert (uf->last_pct_idx >= uf->name_idx);
|
||||
mhd_assert ((uf->last_pct_idx == mhd_POST_INVALID_POS) || \
|
||||
(uf->last_pct_idx < i));
|
||||
mhd_assert (0 == uf->value_len);
|
||||
if (uf->last_pct_idx != mhd_POST_INVALID_POS)
|
||||
uf->name_len = mhd_str_pct_decode_lenient_n (buf + uf->name_idx,
|
||||
i - uf->name_idx,
|
||||
buf + uf->name_idx,
|
||||
i - uf->name_idx,
|
||||
NULL);
|
||||
else
|
||||
uf->name_len = i - uf->name_idx;
|
||||
buf[uf->name_idx + uf->name_len] = 0; /* Zero-terminate the name */
|
||||
|
||||
uf->st = mhd_POST_UENC_ST_EQ_FOUND;
|
||||
++i; /* Process the next char */
|
||||
continue; /* Check whether the next char is available */
|
||||
case mhd_POST_UENC_ST_EQ_FOUND:
|
||||
mhd_assert (0 == p_data->value_off);
|
||||
mhd_assert (0 == uf->value_idx);
|
||||
mhd_assert (0 == uf->value_len);
|
||||
mhd_assert (0 != i && "the 'value' should follow the 'name'");
|
||||
uf->last_pct_idx = mhd_POST_INVALID_POS;
|
||||
uf->value_idx = i;
|
||||
uf->st = mhd_POST_UENC_ST_VALUE;
|
||||
/* Intentional fall-through */
|
||||
case mhd_POST_UENC_ST_VALUE:
|
||||
do /* Fast local loop */
|
||||
{
|
||||
if ('+' == buf[i])
|
||||
buf[i] = ' ';
|
||||
else if ('%' == buf[i])
|
||||
uf->last_pct_idx = i;
|
||||
else if ('&' == buf[i])
|
||||
{
|
||||
uf->st = mhd_POST_UENC_ST_AT_AMPRSND;
|
||||
break;
|
||||
}
|
||||
} while (*pdata_size > ++i);
|
||||
mhd_assert ((*pdata_size == i) || \
|
||||
(mhd_POST_UENC_ST_AT_AMPRSND == uf->st));
|
||||
continue;
|
||||
case mhd_POST_UENC_ST_AT_AMPRSND:
|
||||
mhd_assert (0 == uf->value_len);
|
||||
mhd_assert ((uf->last_pct_idx == mhd_POST_INVALID_POS) || \
|
||||
(uf->last_pct_idx < i));
|
||||
mhd_assert ((uf->last_pct_idx == mhd_POST_INVALID_POS) || \
|
||||
((uf->name_idx + uf->name_len) < i));
|
||||
if (0 != uf->value_idx)
|
||||
{
|
||||
/* Have 'name' and 'value' */
|
||||
if (uf->last_pct_idx != mhd_POST_INVALID_POS)
|
||||
uf->value_len = mhd_str_pct_decode_lenient_n (buf + uf->value_idx,
|
||||
i - uf->value_idx,
|
||||
buf + uf->value_idx,
|
||||
i - uf->value_idx,
|
||||
NULL);
|
||||
else
|
||||
uf->value_len = i - uf->value_idx;
|
||||
buf[uf->value_idx + uf->value_len] = 0; /* Zero-terminate the value */
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Have 'name' only (without any 'value') */
|
||||
if (uf->last_pct_idx != mhd_POST_INVALID_POS)
|
||||
uf->name_len = mhd_str_pct_decode_lenient_n (buf + uf->name_idx,
|
||||
i - uf->name_idx,
|
||||
buf + uf->name_idx,
|
||||
i - uf->name_idx,
|
||||
NULL);
|
||||
else
|
||||
uf->name_len = i - uf->name_idx;
|
||||
buf[uf->name_idx + uf->name_len] = 0; /* Zero-terminate the name */
|
||||
}
|
||||
uf->st = mhd_POST_UENC_ST_FULL_FIELD_FOUND;
|
||||
/* Intentional fall-through */
|
||||
case mhd_POST_UENC_ST_FULL_FIELD_FOUND:
|
||||
++i; /* Consume current character,
|
||||
advance to the next char to be checked */
|
||||
if (process_complete_field (c,
|
||||
buf,
|
||||
&i,
|
||||
pdata_size,
|
||||
p_data->field_start,
|
||||
uf->name_idx,
|
||||
uf->name_len,
|
||||
uf->value_idx,
|
||||
uf->value_len))
|
||||
{
|
||||
if (c->suspended)
|
||||
--i; /* Go back to the same position */
|
||||
p_data->next_parse_pos = i;
|
||||
return true;
|
||||
}
|
||||
mhd_assert (*pdata_size >= i);
|
||||
reset_parse_field_data_urlenc (&(c->rq.u_proc.post));
|
||||
continue; /* Process the next char */
|
||||
default:
|
||||
mhd_assert (0 && "Impossible value");
|
||||
MHD_UNREACHABLE_;
|
||||
break;
|
||||
}
|
||||
mhd_assert (0 && "Should be unreachable");
|
||||
MHD_UNREACHABLE_;
|
||||
break;
|
||||
}
|
||||
|
||||
mhd_assert (*pdata_size == i);
|
||||
|
||||
mhd_assert (mhd_POST_UENC_ST_AT_EQ != uf->st);
|
||||
mhd_assert (mhd_POST_UENC_ST_AT_AMPRSND != uf->st);
|
||||
mhd_assert (mhd_POST_UENC_ST_FULL_FIELD_FOUND != uf->st);
|
||||
mhd_assert ((mhd_POST_UENC_ST_VALUE != uf->st) || \
|
||||
(0 == uf->value_len));
|
||||
|
||||
mhd_assert (*pdata_size == i);
|
||||
|
||||
if ((mhd_POST_UENC_ST_VALUE == uf->st) &&
|
||||
(i != uf->value_idx) && /* Encoded value must be larger then zero */
|
||||
is_value_streaming_needed (c, i - p_data->field_start))
|
||||
{
|
||||
size_t len_of_value_part;
|
||||
if (uf->last_pct_idx != mhd_POST_INVALID_POS)
|
||||
{
|
||||
mhd_assert (uf->last_pct_idx < i);
|
||||
mhd_assert (uf->last_pct_idx >= uf->value_idx);
|
||||
|
||||
if (2 >= (i - uf->last_pct_idx))
|
||||
i = uf->last_pct_idx; /* The last percent-encoded character is incomplete */
|
||||
|
||||
len_of_value_part =
|
||||
mhd_str_pct_decode_lenient_n (buf + uf->value_idx,
|
||||
i - uf->value_idx,
|
||||
buf + uf->value_idx,
|
||||
i - uf->value_idx,
|
||||
NULL);
|
||||
}
|
||||
else
|
||||
len_of_value_part = i - uf->value_idx;
|
||||
|
||||
if (0 != len_of_value_part)
|
||||
{
|
||||
bool proc_res;
|
||||
|
||||
proc_res =
|
||||
process_partial_value (c,
|
||||
buf,
|
||||
&i,
|
||||
pdata_size,
|
||||
uf->name_idx,
|
||||
uf->name_len,
|
||||
uf->value_idx,
|
||||
len_of_value_part);
|
||||
|
||||
/* Reset position of last '%' char: it was already decoded or
|
||||
* 'i' points to it and it will be processed again next time */
|
||||
uf->last_pct_idx = mhd_POST_INVALID_POS;
|
||||
|
||||
if (proc_res)
|
||||
{
|
||||
if (c->suspended)
|
||||
uf->value_len = len_of_value_part; /* Indicate that value has been
|
||||
partially decoded and needs
|
||||
to be "streamed" again */
|
||||
p_data->next_parse_pos = i;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
p_data->next_parse_pos = i;
|
||||
return false; /* Continue parsing */
|
||||
}
|
||||
|
||||
|
||||
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,
|
||||
@@ -917,6 +1267,7 @@ parse_post_text (struct MHD_Connection *restrict c,
|
||||
size_t i;
|
||||
bool enc_broken;
|
||||
|
||||
mhd_assert (MHD_HTTP_POST_ENCODING_TEXT_PLAIN == c->rq.u_proc.post.enc);
|
||||
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);
|
||||
@@ -969,6 +1320,7 @@ parse_post_text (struct MHD_Connection *restrict c,
|
||||
mhd_assert (0 == p_data->value_off);
|
||||
mhd_assert (0 == tf->value_idx);
|
||||
mhd_assert (0 == tf->value_len);
|
||||
mhd_assert (0 != i && "the 'value' should follow the 'name'");
|
||||
tf->value_idx = i;
|
||||
tf->st = mhd_POST_TEXT_ST_VALUE;
|
||||
/* Intentional fall-through */
|
||||
@@ -987,7 +1339,8 @@ parse_post_text (struct MHD_Connection *restrict c,
|
||||
}
|
||||
} while (*pdata_size > ++i);
|
||||
mhd_assert ((*pdata_size == i) || \
|
||||
(mhd_POST_TEXT_ST_VALUE != tf->st));
|
||||
(mhd_POST_TEXT_ST_AT_CR == tf->st) || \
|
||||
(mhd_POST_TEXT_ST_AT_LF_BARE == tf->st));
|
||||
continue;
|
||||
case mhd_POST_TEXT_ST_AT_LF_BARE:
|
||||
if (! bare_lf_as_crlf)
|
||||
@@ -1003,7 +1356,13 @@ parse_post_text (struct MHD_Connection *restrict c,
|
||||
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)
|
||||
if ((0 == tf->name_len) && (0 == tf->value_len))
|
||||
{ /* Empty line */
|
||||
++i; /* Advance to the next char to be checked */
|
||||
reset_parse_field_data_text (&(c->rq.u_proc.post));
|
||||
tf->st = mhd_POST_TEXT_ST_NOT_STARTED;
|
||||
}
|
||||
else if (mhd_POST_TEXT_ST_AT_LF_BARE == tf->st)
|
||||
tf->st = mhd_POST_TEXT_ST_FULL_LINE_FOUND;
|
||||
else
|
||||
{
|
||||
@@ -1017,6 +1376,7 @@ parse_post_text (struct MHD_Connection *restrict c,
|
||||
enc_broken = true;
|
||||
break;
|
||||
}
|
||||
tf->st = mhd_POST_TEXT_ST_FULL_LINE_FOUND;
|
||||
/* Intentional fall-through */
|
||||
case mhd_POST_TEXT_ST_FULL_LINE_FOUND:
|
||||
++i; /* Advance to the next char to be checked */
|
||||
@@ -1036,7 +1396,7 @@ parse_post_text (struct MHD_Connection *restrict c,
|
||||
return true;
|
||||
}
|
||||
mhd_assert (*pdata_size >= i);
|
||||
reset_text_parse_field_data (&(c->rq.u_proc.post));
|
||||
reset_parse_field_data_text (&(c->rq.u_proc.post));
|
||||
continue; /* Process the next char */
|
||||
default:
|
||||
mhd_assert (0 && "Impossible value");
|
||||
@@ -1083,13 +1443,13 @@ parse_post_text (struct MHD_Connection *restrict c,
|
||||
mhd_assert (*pdata_size == i);
|
||||
|
||||
if ((mhd_POST_TEXT_ST_VALUE == tf->st) &&
|
||||
(i != tf->value_idx))
|
||||
(i != tf->value_idx) &&
|
||||
is_value_streaming_needed (c, i - p_data->field_start))
|
||||
{
|
||||
if (process_partial_value (c,
|
||||
buf,
|
||||
&i,
|
||||
pdata_size,
|
||||
p_data->field_start,
|
||||
tf->name_idx,
|
||||
tf->name_len,
|
||||
tf->value_idx,
|
||||
@@ -1160,11 +1520,12 @@ mhd_stream_post_parse (struct MHD_Connection *restrict c,
|
||||
switch (p_data->enc)
|
||||
{
|
||||
case MHD_HTTP_POST_ENCODING_FORM_URLENCODED:
|
||||
// TODO: finish
|
||||
c->state = MHD_CONNECTION_FULL_REQ_RECEIVED;
|
||||
return true;
|
||||
return parse_post_urlenc (c,
|
||||
&(p_data->lbuf_used),
|
||||
p_data->lbuf.data);
|
||||
case MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA:
|
||||
// TODO: finish
|
||||
mhd_assert (0 && "Not yet finished");
|
||||
c->state = MHD_CONNECTION_FULL_REQ_RECEIVED;
|
||||
return true;
|
||||
case MHD_HTTP_POST_ENCODING_TEXT_PLAIN:
|
||||
@@ -1185,6 +1546,146 @@ mhd_stream_post_parse (struct MHD_Connection *restrict c,
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check whether some unprocessed or partially processed data left in buffers
|
||||
* for urlencoding POST encoding.
|
||||
* @param c the stream to use
|
||||
* @param pdata_size the pointer to the size of the data in the buffer
|
||||
* @param buf the buffer with the data
|
||||
* @return 'true' if stream state was changed,
|
||||
* 'false' to continue normal processing
|
||||
*/
|
||||
static MHD_FN_PAR_NONNULL_ALL_
|
||||
MHD_FN_PAR_INOUT_ (2) MHD_FN_PAR_INOUT_ (3) bool
|
||||
check_post_leftovers_urlenc (struct MHD_Connection *restrict c,
|
||||
size_t *restrict pdata_size,
|
||||
char *restrict buf)
|
||||
{
|
||||
struct mhd_PostParserData *const p_data = &(c->rq.u_proc.post);
|
||||
struct mhd_PostParserUrlEncData *const uf = &(p_data->e_d.u_enc); /**< the current "text" field */
|
||||
size_t pos;
|
||||
size_t name_start;
|
||||
size_t name_len;
|
||||
size_t value_start;
|
||||
size_t value_len;
|
||||
|
||||
pos = p_data->next_parse_pos; /* Points to the char AFTER the data, valid location as buffer is always at least one byte larger */
|
||||
mhd_assert (pos == p_data->next_parse_pos);
|
||||
mhd_assert (pos < p_data->lbuf.size); // TODO: support processing in connection buffer
|
||||
mhd_assert (*pdata_size >= pos);
|
||||
switch (uf->st)
|
||||
{
|
||||
case mhd_POST_UENC_ST_NOT_STARTED:
|
||||
mhd_assert (pos == *pdata_size);
|
||||
return false; /* Continue processing */
|
||||
case mhd_POST_UENC_ST_NAME:
|
||||
mhd_assert (pos == *pdata_size);
|
||||
/* Unfinished name */
|
||||
name_start = uf->name_idx;
|
||||
if (uf->last_pct_idx != mhd_POST_INVALID_POS)
|
||||
name_len = mhd_str_pct_decode_lenient_n (buf + uf->name_idx,
|
||||
pos - uf->name_idx,
|
||||
buf + uf->name_idx,
|
||||
pos - uf->name_idx,
|
||||
NULL);
|
||||
else
|
||||
name_len = pos - uf->name_idx;
|
||||
buf[name_start + name_len] = 0; /* Zero-terminate the result, an extra byte is always available in the buffer */
|
||||
value_start = 0;
|
||||
value_len = 0;
|
||||
break;
|
||||
case mhd_POST_UENC_ST_EQ_FOUND:
|
||||
mhd_assert (pos == *pdata_size);
|
||||
name_start = uf->name_idx;
|
||||
name_len = uf->name_len;
|
||||
value_start = pos;
|
||||
value_len = 0;
|
||||
buf[value_start] = 0; /* Zero-terminate the result, an extra byte is always available */
|
||||
break;
|
||||
case mhd_POST_UENC_ST_VALUE:
|
||||
mhd_assert (0 != uf->value_idx);
|
||||
name_start = uf->name_idx;
|
||||
name_len = uf->name_len;
|
||||
mhd_assert (0 == buf[name_start + name_len]);
|
||||
if (0 != uf->value_len)
|
||||
{
|
||||
/* The value was partially decoded and then application requested stream
|
||||
* suspending. */
|
||||
mhd_assert (pos < *pdata_size);
|
||||
mhd_assert (2 >= *pdata_size - pos);
|
||||
value_start = uf->value_idx;
|
||||
if (uf->value_idx + uf->value_len != pos)
|
||||
memmove (buf + uf->value_idx + uf->value_len,
|
||||
buf + pos,
|
||||
*pdata_size - pos);
|
||||
value_len = uf->value_len + *pdata_size - pos;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The value has not been decoded yet */
|
||||
mhd_assert (pos == *pdata_size);
|
||||
value_start = uf->value_idx;
|
||||
if (uf->last_pct_idx != mhd_POST_INVALID_POS)
|
||||
value_len = mhd_str_pct_decode_lenient_n (buf + uf->value_idx,
|
||||
pos - uf->value_idx,
|
||||
buf + uf->value_idx,
|
||||
pos - uf->value_idx,
|
||||
NULL);
|
||||
else
|
||||
value_len = pos - uf->value_idx;
|
||||
}
|
||||
buf[value_start + value_len] = 0; /* Zero-terminate the result, an extra byte is always available in the buffer */
|
||||
break;
|
||||
case mhd_POST_UENC_ST_FULL_FIELD_FOUND:
|
||||
/* Full value was found, but the stream has been suspended by
|
||||
* the application */
|
||||
mhd_assert (pos + 1 == *pdata_size);
|
||||
mhd_assert (0 != uf->value_idx);
|
||||
mhd_assert (pos != uf->value_idx);
|
||||
name_start = uf->name_idx;
|
||||
name_len = uf->name_len;
|
||||
value_start = uf->value_idx;
|
||||
value_len = uf->value_len;
|
||||
mhd_assert (0 == buf[name_start + name_len]);
|
||||
mhd_assert (0 == buf[value_start + value_len]);
|
||||
++pos;
|
||||
mhd_assert (pos == *pdata_size);
|
||||
break;
|
||||
case mhd_POST_UENC_ST_AT_EQ:
|
||||
case mhd_POST_UENC_ST_AT_AMPRSND:
|
||||
default:
|
||||
mhd_assert (0 && "Impossible value");
|
||||
MHD_UNREACHABLE_;
|
||||
p_data->parse_result = MHD_POST_PARSE_RES_FAILED_INVALID_POST_FORMAT;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (process_complete_field (c,
|
||||
buf,
|
||||
&pos,
|
||||
pdata_size,
|
||||
p_data->field_start,
|
||||
name_start,
|
||||
name_len,
|
||||
value_start,
|
||||
value_len))
|
||||
return true;
|
||||
|
||||
reset_parse_field_data_urlenc (&(c->rq.u_proc.post));
|
||||
|
||||
return false; /* Continue normal processing */
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check whether some unprocessed or partially processed data left in buffers
|
||||
* for "text" POST encoding.
|
||||
* @param c the stream to use
|
||||
* @param pdata_size the pointer to the size of the data in the buffer
|
||||
* @param buf the buffer with the data
|
||||
* @return 'true' if stream state was changed,
|
||||
* 'false' to continue normal processing
|
||||
*/
|
||||
static MHD_FN_PAR_NONNULL_ALL_
|
||||
MHD_FN_PAR_INOUT_ (2) MHD_FN_PAR_INOUT_ (3) bool
|
||||
check_post_leftovers_text (struct MHD_Connection *restrict c,
|
||||
@@ -1199,15 +1700,17 @@ check_post_leftovers_text (struct MHD_Connection *restrict c,
|
||||
size_t value_start;
|
||||
size_t value_len;
|
||||
|
||||
pos = *pdata_size; /* Points to the char AFTER the data, valid location as buffer is always at least one byte larger */
|
||||
pos = p_data->next_parse_pos; /* Points to the char AFTER the data, valid location as buffer is always at least one byte larger */
|
||||
mhd_assert (pos == p_data->next_parse_pos);
|
||||
mhd_assert (pos < p_data->lbuf.size); // TODO: support processing in connection buffer
|
||||
switch (tf->st)
|
||||
{
|
||||
case mhd_POST_TEXT_ST_NOT_STARTED:
|
||||
mhd_assert (pos == *pdata_size);
|
||||
return false; /* Continue processing */
|
||||
case mhd_POST_TEXT_ST_NAME:
|
||||
/* Unfinished name */
|
||||
mhd_assert (pos == *pdata_size);
|
||||
name_start = tf->name_idx;
|
||||
name_len = pos - name_start;
|
||||
buf[pos] = 0; /* Zero-terminate the result, an extra byte is always available */
|
||||
@@ -1215,6 +1718,7 @@ check_post_leftovers_text (struct MHD_Connection *restrict c,
|
||||
value_len = 0;
|
||||
break;
|
||||
case mhd_POST_TEXT_ST_EQ_FOUND:
|
||||
mhd_assert (pos == *pdata_size);
|
||||
name_start = tf->name_idx;
|
||||
name_len = tf->name_len;
|
||||
value_start = pos;
|
||||
@@ -1222,15 +1726,17 @@ check_post_leftovers_text (struct MHD_Connection *restrict c,
|
||||
buf[pos] = 0; /* Zero-terminate the result, an extra byte is always available */
|
||||
break;
|
||||
case mhd_POST_TEXT_ST_VALUE:
|
||||
mhd_assert (pos == *pdata_size);
|
||||
mhd_assert (0 != tf->value_idx);
|
||||
mhd_assert (pos != tf->value_idx);
|
||||
name_start = tf->name_idx;
|
||||
name_len = tf->name_len;
|
||||
value_start = tf->value_idx;
|
||||
value_len = pos - value_start;
|
||||
buf[pos] = 0; /* Zero-terminate the result, an extra byte is always available */
|
||||
buf[pos] = 0; /* Zero-terminate the result, an extra byte space is always available */
|
||||
break;
|
||||
case mhd_POST_TEXT_ST_CR_FOUND:
|
||||
mhd_assert (pos == *pdata_size);
|
||||
mhd_assert (0 != tf->value_idx);
|
||||
mhd_assert (pos != tf->value_idx);
|
||||
name_start = tf->name_idx;
|
||||
@@ -1240,10 +1746,24 @@ check_post_leftovers_text (struct MHD_Connection *restrict c,
|
||||
mhd_assert (value_start + value_len + 1 == pos);
|
||||
mhd_assert (0 == buf[value_start + value_len]);
|
||||
break;
|
||||
case mhd_POST_TEXT_ST_FULL_LINE_FOUND:
|
||||
/* Full value was found, but the stream has been suspended by
|
||||
* the application */
|
||||
mhd_assert (pos + 1 == *pdata_size);
|
||||
mhd_assert (0 != tf->value_idx);
|
||||
name_start = tf->name_idx;
|
||||
name_len = tf->name_len;
|
||||
value_start = tf->value_idx;
|
||||
value_len = tf->value_len;
|
||||
mhd_assert ((value_start + value_len + 1 == pos) || \
|
||||
(value_start + value_len + 2 == pos));
|
||||
mhd_assert (0 == buf[value_start + value_len]);
|
||||
++pos;
|
||||
mhd_assert (pos == *pdata_size);
|
||||
break;
|
||||
case mhd_POST_TEXT_ST_AT_EQ:
|
||||
case mhd_POST_TEXT_ST_AT_LF_BARE:
|
||||
case mhd_POST_TEXT_ST_AT_CR:
|
||||
case mhd_POST_TEXT_ST_FULL_LINE_FOUND:
|
||||
default:
|
||||
mhd_assert (0 && "Impossible value");
|
||||
MHD_UNREACHABLE_;
|
||||
@@ -1251,11 +1771,15 @@ check_post_leftovers_text (struct MHD_Connection *restrict c,
|
||||
return false;
|
||||
}
|
||||
|
||||
mhd_LOG_MSG (c->daemon, \
|
||||
MHD_SC_REQ_POST_PARSE_OK_BAD_TERMINATION, \
|
||||
"The request POST has invalid termination / ending. " \
|
||||
"The last parsed filed may be incorrect.");
|
||||
p_data->parse_result = MHD_POST_PARSE_RES_OK_BAD_TERMINATION;
|
||||
if (tf->st != mhd_POST_TEXT_ST_FULL_LINE_FOUND)
|
||||
{
|
||||
/* The line must be terminated by CRLF, but it is not */
|
||||
mhd_LOG_MSG (c->daemon, \
|
||||
MHD_SC_REQ_POST_PARSE_OK_BAD_TERMINATION, \
|
||||
"The request POST has invalid termination / ending. " \
|
||||
"The last parsed filed may be incorrect.");
|
||||
p_data->parse_result = MHD_POST_PARSE_RES_OK_BAD_TERMINATION;
|
||||
}
|
||||
|
||||
if (process_complete_field (c,
|
||||
buf,
|
||||
@@ -1268,7 +1792,7 @@ check_post_leftovers_text (struct MHD_Connection *restrict c,
|
||||
value_len))
|
||||
return true;
|
||||
|
||||
reset_text_parse_field_data (&(c->rq.u_proc.post));
|
||||
reset_parse_field_data_text (&(c->rq.u_proc.post));
|
||||
|
||||
return false; /* Continue normal processing */
|
||||
}
|
||||
@@ -1287,11 +1811,11 @@ check_post_leftovers (struct MHD_Connection *restrict c)
|
||||
switch (p_data->enc)
|
||||
{
|
||||
case MHD_HTTP_POST_ENCODING_FORM_URLENCODED:
|
||||
// TODO: finish
|
||||
c->state = MHD_CONNECTION_FULL_REQ_RECEIVED;
|
||||
return true;
|
||||
return check_post_leftovers_urlenc (c,
|
||||
&(p_data->lbuf_used),
|
||||
p_data->lbuf.data);
|
||||
case MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA:
|
||||
// TODO: finish
|
||||
mhd_assert (0 && "Not yet finished");
|
||||
c->state = MHD_CONNECTION_FULL_REQ_RECEIVED;
|
||||
return true;
|
||||
case MHD_HTTP_POST_ENCODING_TEXT_PLAIN:
|
||||
|
||||
@@ -3434,6 +3434,7 @@ process_request_nonchunked_body (struct MHD_Connection *restrict c)
|
||||
state_updated = mhd_stream_process_upload_action (c, act, false);
|
||||
}
|
||||
}
|
||||
|
||||
if (read_buf_reuse)
|
||||
{
|
||||
size_t data_left_size;
|
||||
|
||||
Reference in new issue
Block a user