[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[libmicrohttpd] 03/03: Implemented correct processing of chunked request
From: |
gnunet |
Subject: |
[libmicrohttpd] 03/03: Implemented correct processing of chunked request encoding with BWS in chunk size line |
Date: |
Wed, 27 Sep 2023 18:45:11 +0200 |
This is an automated email from the git hooks/post-receive script.
karlson2k pushed a commit to branch master
in repository libmicrohttpd.
commit ed4c182944c33f0147b4eeed88362916995783b0
Author: Evgeny Grin (Karlson2k) <k2k@narod.ru>
AuthorDate: Wed Sep 27 08:32:07 2023 +0300
Implemented correct processing of chunked request encoding with BWS in
chunk size line
---
src/microhttpd/connection.c | 179 +++++++++++++++++++++++---------------------
1 file changed, 92 insertions(+), 87 deletions(-)
diff --git a/src/microhttpd/connection.c b/src/microhttpd/connection.c
index b15efb8a..b09dbd9a 100644
--- a/src/microhttpd/connection.c
+++ b/src/microhttpd/connection.c
@@ -4393,6 +4393,9 @@ process_request_body (struct MHD_Connection *connection)
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);
+ /* Allow "Bad WhiteSpace" in chunk extension.
+ RFC 9112, Section 7.1.1, Paragraph 2 */
+ const bool allow_bws = (2 < discp_lvl);
mhd_assert (NULL == connection->rp.response);
@@ -4460,86 +4463,102 @@ process_request_body (struct MHD_Connection
*connection)
}
}
else
- {
- size_t i;
- /** The length of the string with the number of the chunk size */
- size_t chunk_size_len;
- bool found_chunk_size_str;
- bool malformed;
+ { /* Need the parse the chunk size line */
+ /** The number of found digits in the chunk size number */
+ size_t num_dig;
+ uint64_t chunk_size;
+ bool broken;
+ bool overflow;
- /* we need to read chunk boundaries */
- i = 0;
- found_chunk_size_str = false;
- chunk_size_len = 0;
mhd_assert (0 != available);
- do
+
+ overflow = false;
+
+ num_dig = MHD_strx_to_uint64_n_ (buffer_head,
+ available,
+ &chunk_size);
+ mhd_assert (num_dig <= available);
+ if (num_dig == available)
+ continue; /* Need line delimiter */
+
+ broken = (0 == num_dig);
+ if (broken)
+ /* Check whether result is invalid due to uint64_t overflow */
+ overflow = ((('0' <= buffer_head[0]) && ('9' >= buffer_head[0])) ||
+ (('A' <= buffer_head[0]) && ('F' >= buffer_head[0])) ||
+ (('a' <= buffer_head[0]) && ('f' >= buffer_head[0])));
+ else
{
- if ('\n' == buffer_head[i])
- {
- if ((0 < i) && ('\r' == buffer_head[i - 1]))
- { /* CRLF */
- if (! found_chunk_size_str)
- chunk_size_len = i - 1;
+ /**
+ * The length of the string with the number of the chunk size,
+ * including chunk extension
+ */
+ size_t chunk_size_line_len;
+
+ chunk_size_line_len = 0;
+ if ((';' == buffer_head[num_dig]) ||
+ (allow_bws &&
+ ((' ' == buffer_head[num_dig]) ||
+ ('\t' == buffer_head[num_dig]))))
+ { /* Chunk extension */
+ size_t i;
+
+ /* Skip bad whitespaces (if any) */
+ for (i = num_dig; i < available; ++i)
+ {
+ if ((' ' != buffer_head[i]) && ('\t' != buffer_head[i]))
+ break;
}
- else
- { /* bare LF */
- if (bare_lf_as_crlf)
+ if (i == available)
+ break; /* need more data */
+ if (';' == buffer_head[i])
+ {
+ for (++i; i < available; ++i)
{
- if (! found_chunk_size_str)
- chunk_size_len = i;
+ if ('\n' == buffer_head[i])
+ break;
}
- else
- chunk_size_len = 0; /* Malformed */
+ if (i == available)
+ break; /* need more data */
+ mhd_assert (i > num_dig);
+ mhd_assert (1 <= i);
+ /* Found LF position */
+ if (bare_lf_as_crlf)
+ chunk_size_line_len = i; /* Don't care about CR before LF */
+ else if ('\r' == buffer_head[i - 1])
+ chunk_size_line_len = i;
}
- found_chunk_size_str = true;
- break; /* Found the end of the string */
- }
- else if (! found_chunk_size_str && (';' == buffer_head[i]))
- { /* Found chunk extension */
- chunk_size_len = i;
- found_chunk_size_str = true;
- }
- } while (available > ++i);
- mhd_assert ((i == available) || found_chunk_size_str);
- mhd_assert ((0 == chunk_size_len) || found_chunk_size_str);
- malformed = ((0 == chunk_size_len) && found_chunk_size_str);
- if (! malformed)
- {
- /* Check whether size is valid hexadecimal number
- * even if end of the string is not found yet. */
- size_t num_dig;
- uint64_t chunk_size;
- mhd_assert (0 < i);
- if (! found_chunk_size_str)
- {
- mhd_assert (i == available);
- /* Check already available part of the size string for valid
- * hexadecimal digits. */
- chunk_size_len = i;
- if ('\r' == buffer_head[i - 1])
- {
- chunk_size_len--;
- malformed = (0 == chunk_size_len);
+ else
+ { /* No ';' after "bad whitespace" */
+ mhd_assert (allow_bws);
+ mhd_assert (0 == chunk_size_line_len);
}
}
- num_dig = MHD_strx_to_uint64_n_ (buffer_head,
- chunk_size_len,
- &chunk_size);
- malformed = malformed || (chunk_size_len != num_dig);
-
- if ((available != i) && ! malformed)
+ else
{
- /* Found end of the string and the size of the chunk is valid */
+ mhd_assert (available >= num_dig);
+ if ((2 <= (available - num_dig)) &&
+ ('\r' == buffer_head[num_dig]) &&
+ ('\n' == buffer_head[num_dig + 1]))
+ chunk_size_line_len = num_dig + 2;
+ else if (bare_lf_as_crlf &&
+ ('\n' == buffer_head[num_dig]))
+ chunk_size_line_len = num_dig + 1;
+ else if (2 > (available - num_dig))
+ break; /* need more data */
+ }
- mhd_assert (found_chunk_size_str);
+ if (0 != chunk_size_line_len)
+ { /* Valid termination of the chunk size line */
+ mhd_assert (chunk_size_line_len <= available);
/* Start reading payload data of the chunk */
connection->rq.current_chunk_offset = 0;
connection->rq.current_chunk_size = chunk_size;
- i++; /* Consume the last checked char */
- available -= i;
- buffer_head += i;
- if (0 == connection->rq.current_chunk_size)
+ available -= chunk_size_line_len;
+ buffer_head += chunk_size_line_len;
+
+ if (0 == chunk_size)
{ /* The final (termination) chunk */
connection->rq.remaining_upload_size = 0;
break;
@@ -4548,32 +4567,18 @@ process_request_body (struct MHD_Connection *connection)
instant_retry = true;
continue;
}
-
- if ((0 == num_dig) && (0 != chunk_size_len))
- { /* Check whether result is invalid due to uint64_t overflow */
- /* At least one byte is always available
- * in the input buffer here. */
- const char d = buffer_head[0]; /**< first digit */
- if ((('0' <= d) && ('9' >= d)) ||
- (('A' <= d) && ('F' >= d)) ||
- (('a' <= d) && ('f' >= d)))
- { /* The first char is a valid hexadecimal digit */
- transmit_error_response_static (connection,
- MHD_HTTP_CONTENT_TOO_LARGE,
- REQUEST_CHUNK_TOO_LARGE);
- return;
- }
- }
+ /* Invalid chunk size line */
}
- if (malformed)
- {
+
+ if (! overflow)
transmit_error_response_static (connection,
MHD_HTTP_BAD_REQUEST,
REQUEST_CHUNKED_MALFORMED);
- return;
- }
- mhd_assert (available == i);
- break; /* The end of the string not found, need more upload data */
+ else
+ transmit_error_response_static (connection,
+ MHD_HTTP_CONTENT_TOO_LARGE,
+ REQUEST_CHUNK_TOO_LARGE);
+ return;
}
}
else
--
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.