mirror of
https://git.gnunet.org/libmicrohttpd.git
synced 2026-09-25 04:09:31 +03:00
Added MHD_OPTION_ALLOW_BIN_ZERO_IN_URI_PATH and MHD_get_connection_URI_path_n()
This commit is contained in:
@@ -1,3 +1,7 @@
|
||||
Sat Feb 28 23:38:39 CET 2026
|
||||
Added MHD_OPTION_ALLOW_BIN_ZERO_IN_URI_PATH daemon option.
|
||||
Added new function MHD_get_connection_URI_path_n(). -EG
|
||||
|
||||
Mon Jul 14 05:03:07 PM CEST 2025
|
||||
Fix double-close bugs on bind() errors reported by MC on the list.
|
||||
Removed MHD2 draft code, now in libmicrohttpd2.git.
|
||||
|
||||
@@ -101,7 +101,7 @@ MHD_C_DECLRATIONS_START_HERE_
|
||||
* they are parsed as decimal numbers.
|
||||
* Example: 0x01093001 = 1.9.30-1.
|
||||
*/
|
||||
#define MHD_VERSION 0x01000200
|
||||
#define MHD_VERSION 0x01000201
|
||||
|
||||
/* If generic headers don't work on your platform, include headers
|
||||
which define 'va_list', 'size_t', 'ssize_t', 'intptr_t', 'off_t',
|
||||
@@ -2198,6 +2198,26 @@ enum MHD_OPTION
|
||||
* @note Available since #MHD_VERSION 0x00097709
|
||||
*/
|
||||
MHD_OPTION_DIGEST_AUTH_DEFAULT_MAX_NC = 42
|
||||
,
|
||||
/**
|
||||
* Default maximum nc (nonce count) value used for Digest Auth.
|
||||
* This option must be followed by an 'int' argument.
|
||||
* If followed by '0' (default) then:
|
||||
* + requests are rejected if request URI has binary zero (the result
|
||||
* of %00 decoding) in the path part of the URI.
|
||||
* If followed by '1' then:
|
||||
* + binary zero is allowed in request URI path;
|
||||
* + #MHD_AccessHandlerCallback called with NULL in @a url parameter when
|
||||
* request URI path has binary zero, the full @a url is available only
|
||||
* via #MHD_get_connection_URI_path_n()
|
||||
* If followed by '2' (unsafe!) then:
|
||||
* + binary zero is allowed in request URI path;
|
||||
* + #MHD_AccessHandlerCallback called with truncated (unsafe!) @a url
|
||||
* parameter when request URI path has binary zero.
|
||||
* @see #MHD_get_connection_URI_path_n()
|
||||
* @note Available since #MHD_VERSION 0x01000201
|
||||
*/
|
||||
MHD_OPTION_ALLOW_BIN_ZERO_IN_URI_PATH = 43
|
||||
|
||||
} _MHD_FIXED_ENUM;
|
||||
|
||||
@@ -2689,7 +2709,9 @@ typedef enum MHD_Result
|
||||
* @param cls argument given together with the function
|
||||
* pointer when the handler was registered with MHD
|
||||
* @param connection the connection handle
|
||||
* @param url the requested url
|
||||
* @param url the requested url, can be truncated or can be NULL, depending
|
||||
* on #MHD_OPTION_ALLOW_BIN_ZERO_IN_URI_PATH option,
|
||||
* see #MHD_get_connection_URI_path_n()
|
||||
* @param method the HTTP method used (#MHD_HTTP_METHOD_GET,
|
||||
* #MHD_HTTP_METHOD_PUT, etc.)
|
||||
* @param version the HTTP version string (i.e.
|
||||
@@ -2718,7 +2740,7 @@ typedef enum MHD_Result
|
||||
* #MHD_NO if the socket must be closed due to a serious
|
||||
* error while handling the request
|
||||
*
|
||||
* @sa #MHD_queue_response()
|
||||
* @sa #MHD_queue_response(), #MHD_get_connection_URI_path_n()
|
||||
*/
|
||||
typedef enum MHD_Result
|
||||
(*MHD_AccessHandlerCallback)(void *cls,
|
||||
@@ -3518,6 +3540,39 @@ MHD_run_from_select2 (struct MHD_Daemon *daemon,
|
||||
|
||||
/* **************** Connection handling functions ***************** */
|
||||
|
||||
|
||||
/**
|
||||
* Get request URI path (the request target without query part).
|
||||
*
|
||||
* The value obtained by this function is the same value as @a url provided
|
||||
* for #MHD_AccessHandlerCallback callback, but this function also provides
|
||||
* the size of the string.
|
||||
*
|
||||
* This function is critically important when binary zero is allowed by daemon
|
||||
* option #MHD_OPTION_ALLOW_BIN_ZERO_IN_URI_PATH as this is the only way to
|
||||
* get the non-truncated request URI.
|
||||
*
|
||||
* Returned @a uri pointer is valid until response is started or connection
|
||||
* is terminated.
|
||||
*
|
||||
* @param connection the connection to URI from
|
||||
* @param[out] uri set to the request URI without query part, may contain
|
||||
* binary zeros (NUL) characters, never set to NULL on
|
||||
* success; can be NULL
|
||||
* @param[out] uri_size set to the size of the @a uri in bytes, not including
|
||||
* final zero-termination; can be NULL
|
||||
* @return #MHD_NO if failed (request is not yet processed or response has
|
||||
* been queued already);
|
||||
* #MHD_YES on success (*uri set to valid pointer)
|
||||
* @note Available since #MHD_VERSION 0x01000201
|
||||
* @sa #MHD_OPTION_ALLOW_BIN_ZERO_IN_URI_PATH, #MHD_AccessHandlerCallback
|
||||
* @ingroup request
|
||||
*/
|
||||
_MHD_EXTERN enum MHD_Result
|
||||
MHD_get_connection_URI_path_n (struct MHD_Connection *connection,
|
||||
const char **uri,
|
||||
size_t *uri_size);
|
||||
|
||||
/**
|
||||
* Get all of the headers from the request.
|
||||
*
|
||||
|
||||
+58
-10
@@ -512,6 +512,13 @@
|
||||
#define REQUEST_MALFORMED ""
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Response text used when the request target path has %00 sequence.
|
||||
*/
|
||||
#define REQUEST_HAS_NUL_CHAR_IN_PATH \
|
||||
"<html><head><title>Bad Request Path</title></head>" \
|
||||
"<body>The request path contains invalid characters.</body></html>"
|
||||
|
||||
/**
|
||||
* Response text used when the request HTTP chunked encoding is
|
||||
* malformed.
|
||||
@@ -792,6 +799,32 @@ recv_param_adapter (struct MHD_Connection *connection,
|
||||
}
|
||||
|
||||
|
||||
_MHD_EXTERN enum MHD_Result
|
||||
MHD_get_connection_URI_path_n (struct MHD_Connection *connection,
|
||||
const char **uri,
|
||||
size_t *uri_size)
|
||||
{
|
||||
if (NULL != uri)
|
||||
*uri = NULL;
|
||||
if (NULL != uri_size)
|
||||
*uri_size = 0u;
|
||||
|
||||
if (connection->state < MHD_CONNECTION_REQ_LINE_RECEIVED)
|
||||
return MHD_NO;
|
||||
if (connection->state >= MHD_CONNECTION_START_REPLY)
|
||||
return MHD_NO;
|
||||
if (NULL == connection->rq.url)
|
||||
return MHD_NO;
|
||||
|
||||
if (NULL != uri)
|
||||
*uri = connection->rq.url;
|
||||
if (NULL != uri_size)
|
||||
*uri_size = connection->rq.url_len;
|
||||
|
||||
return MHD_YES;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get all of the headers from the request.
|
||||
*
|
||||
@@ -2917,6 +2950,7 @@ transmit_error_response_len (struct MHD_Connection *connection,
|
||||
connection->rq.method = NULL;
|
||||
connection->rq.url = NULL;
|
||||
connection->rq.url_len = 0;
|
||||
connection->rq.url_for_callback = NULL;
|
||||
connection->rq.headers_received = NULL;
|
||||
connection->rq.headers_received_tail = NULL;
|
||||
connection->write_buffer = NULL;
|
||||
@@ -4402,7 +4436,7 @@ call_connection_handler (struct MHD_Connection *connection)
|
||||
if (MHD_NO ==
|
||||
daemon->default_handler (daemon->default_handler_cls,
|
||||
connection,
|
||||
connection->rq.url,
|
||||
connection->rq.url_for_callback,
|
||||
connection->rq.method,
|
||||
connection->rq.version,
|
||||
NULL,
|
||||
@@ -4435,11 +4469,9 @@ process_request_body (struct MHD_Connection *connection)
|
||||
bool instant_retry;
|
||||
char *buffer_head;
|
||||
const int discp_lvl = daemon->client_discipline;
|
||||
/* Treat bare LF as the end of the line.
|
||||
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);
|
||||
/* RFC does not allow LF as the line termination in chunk headers.
|
||||
See RFC 9112, section 7.1 and section 2.2-3 */
|
||||
const bool bare_lf_as_crlf = (-2 > discp_lvl);
|
||||
/* Allow "Bad WhiteSpace" in chunk extension.
|
||||
RFC 9112, Section 7.1.1, Paragraph 2 */
|
||||
const bool allow_bws = (2 > discp_lvl);
|
||||
@@ -4462,6 +4494,7 @@ process_request_body (struct MHD_Connection *connection)
|
||||
connection->rq.current_chunk_size) &&
|
||||
(0 != connection->rq.current_chunk_size) )
|
||||
{
|
||||
/* Skip CRLF chunk termination */
|
||||
size_t i;
|
||||
mhd_assert (0 != available);
|
||||
/* skip new line at the *end* of a chunk */
|
||||
@@ -4491,12 +4524,10 @@ process_request_body (struct MHD_Connection *connection)
|
||||
}
|
||||
if (0 != connection->rq.current_chunk_size)
|
||||
{
|
||||
/* Process chunk "content" */
|
||||
uint64_t cur_chunk_left;
|
||||
mhd_assert (connection->rq.current_chunk_offset < \
|
||||
connection->rq.current_chunk_size);
|
||||
/* we are in the middle of a chunk, give
|
||||
as much as possible to the client (without
|
||||
crossing chunk boundaries) */
|
||||
cur_chunk_left
|
||||
= connection->rq.current_chunk_size
|
||||
- connection->rq.current_chunk_offset;
|
||||
@@ -4532,10 +4563,12 @@ process_request_body (struct MHD_Connection *connection)
|
||||
|
||||
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
|
||||
{
|
||||
/**
|
||||
@@ -4646,7 +4679,7 @@ process_request_body (struct MHD_Connection *connection)
|
||||
if (MHD_NO ==
|
||||
daemon->default_handler (daemon->default_handler_cls,
|
||||
connection,
|
||||
connection->rq.url,
|
||||
connection->rq.url_for_callback,
|
||||
connection->rq.method,
|
||||
connection->rq.version,
|
||||
buffer_head,
|
||||
@@ -5589,6 +5622,7 @@ process_request_target (struct MHD_Connection *c)
|
||||
mhd_assert (MHD_CONNECTION_REQ_LINE_RECEIVING == c->state);
|
||||
mhd_assert (NULL == c->rq.url);
|
||||
mhd_assert (0 == c->rq.url_len);
|
||||
mhd_assert (NULL == c->rq.url_for_callback);
|
||||
mhd_assert (NULL != c->rq.hdrs.rq_line.rq_tgt);
|
||||
mhd_assert ((NULL == c->rq.hdrs.rq_line.rq_tgt_qmark) || \
|
||||
(c->rq.hdrs.rq_line.rq_tgt <= c->rq.hdrs.rq_line.rq_tgt_qmark));
|
||||
@@ -5630,6 +5664,7 @@ process_request_target (struct MHD_Connection *c)
|
||||
params_len = 0;
|
||||
#endif /* _DEBUG */
|
||||
|
||||
mhd_assert (NULL == c->rq.url_for_callback);
|
||||
mhd_assert (strlen (c->rq.hdrs.rq_line.rq_tgt) == \
|
||||
c->rq.req_target_len - params_len);
|
||||
|
||||
@@ -5640,6 +5675,18 @@ process_request_target (struct MHD_Connection *c)
|
||||
c->rq.hdrs.rq_line.rq_tgt);
|
||||
c->rq.url = c->rq.hdrs.rq_line.rq_tgt;
|
||||
|
||||
if (2 == c->daemon->allow_bzero_in_url)
|
||||
c->rq.url_for_callback = c->rq.url;
|
||||
else if (strlen (c->rq.url) == c->rq.url_len)
|
||||
c->rq.url_for_callback = c->rq.url;
|
||||
else if (0 == c->daemon->allow_bzero_in_url)
|
||||
{
|
||||
transmit_error_response_static (c,
|
||||
MHD_HTTP_BAD_REQUEST,
|
||||
REQUEST_HAS_NUL_CHAR_IN_PATH);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -5684,6 +5731,7 @@ get_request_line (struct MHD_Connection *c)
|
||||
mhd_assert (MHD_CONNECTION_REQ_LINE_RECEIVING == c->state);
|
||||
mhd_assert (NULL == c->rq.url);
|
||||
mhd_assert (0 == c->rq.url_len);
|
||||
mhd_assert (NULL == c->rq.url_for_callback);
|
||||
mhd_assert (NULL != c->rq.hdrs.rq_line.rq_tgt);
|
||||
if (0 != c->rq.hdrs.rq_line.num_ws_in_uri)
|
||||
{
|
||||
|
||||
@@ -7125,6 +7125,12 @@ parse_options_va (struct MHD_Daemon *daemon,
|
||||
}
|
||||
#endif /* HAVE_MESSAGES */
|
||||
break;
|
||||
case MHD_OPTION_ALLOW_BIN_ZERO_IN_URI_PATH:
|
||||
daemon->allow_bzero_in_url = va_arg (ap, int);
|
||||
if ((0 > daemon->allow_bzero_in_url) ||
|
||||
(2 < daemon->allow_bzero_in_url))
|
||||
daemon->allow_bzero_in_url = 1;
|
||||
break;
|
||||
case MHD_OPTION_ARRAY:
|
||||
params->num_opts--; /* Do not count MHD_OPTION_ARRAY */
|
||||
oa = va_arg (ap, struct MHD_OptionItem *);
|
||||
@@ -7189,6 +7195,7 @@ parse_options_va (struct MHD_Daemon *daemon,
|
||||
case MHD_OPTION_SIGPIPE_HANDLED_BY_APP:
|
||||
case MHD_OPTION_TLS_NO_ALPN:
|
||||
case MHD_OPTION_APP_FD_SETSIZE:
|
||||
case MHD_OPTION_ALLOW_BIN_ZERO_IN_URI_PATH:
|
||||
if (MHD_NO == parse_options (daemon,
|
||||
params,
|
||||
opt,
|
||||
|
||||
@@ -1105,6 +1105,12 @@ struct MHD_Request
|
||||
*/
|
||||
size_t req_target_len;
|
||||
|
||||
/**
|
||||
* Requested URL (everything after "GET" only).
|
||||
* Depending on daemon setting either the same as @a URL or NULL.
|
||||
*/
|
||||
const char *url_for_callback;
|
||||
|
||||
/**
|
||||
* Linked list of parsed headers.
|
||||
*/
|
||||
@@ -2264,6 +2270,13 @@ struct MHD_Daemon
|
||||
*/
|
||||
int client_discipline;
|
||||
|
||||
/**
|
||||
* Allow binary zero in the URI (excluding query part).
|
||||
* When set to '1' then @a url parameter must be NULL, when binary zero
|
||||
* is used in URI.
|
||||
*/
|
||||
int allow_bzero_in_url;
|
||||
|
||||
#ifdef HAS_FD_SETSIZE_OVERRIDABLE
|
||||
/**
|
||||
* The value of FD_SETSIZE used by the daemon.
|
||||
|
||||
Reference in New Issue
Block a user