aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEvgeny Grin (Karlson2k) <k2k@narod.ru>2022-12-22 16:30:12 +0300
committerEvgeny Grin (Karlson2k) <k2k@narod.ru>2022-12-22 18:25:49 +0300
commit5c3a61d68c04ebfd62695fa2a90e6212e42a1cae (patch)
tree6c1c02fde82d704d8233cca42d1719fe4c75eca9
parent42be9415cbcdb23463a86fbee612b3809bf7ed0c (diff)
downloadlibmicrohttpd-5c3a61d68c04ebfd62695fa2a90e6212e42a1cae.tar.gz
libmicrohttpd-5c3a61d68c04ebfd62695fa2a90e6212e42a1cae.zip
Added new daemon option MHD_OPTION_CLIENT_DISCIPLINE_LV
Reject URIs with spaces as per RFC. Fixed check for space before colon in headers (previously it was checked only when MHD was NOT strict). Reject HTTP/1.1 requests without host by default (as per RFC).
-rw-r--r--src/examples/connection_close.c2
-rw-r--r--src/examples/minimal_example.c1
-rw-r--r--src/examples/minimal_example_empty.c1
-rw-r--r--src/examples/minimal_example_empty_tls.c2
-rw-r--r--src/include/microhttpd.h74
-rw-r--r--src/microhttpd/connection.c18
-rw-r--r--src/microhttpd/daemon.c32
-rw-r--r--src/microhttpd/internal.h5
8 files changed, 103 insertions, 32 deletions
diff --git a/src/examples/connection_close.c b/src/examples/connection_close.c
index 8558eb46..de79d9f1 100644
--- a/src/examples/connection_close.c
+++ b/src/examples/connection_close.c
@@ -118,7 +118,7 @@ main (int argc, char *const *argv)
118 MHD_OPTION_NOTIFY_COMPLETED, &request_completed, NULL, 118 MHD_OPTION_NOTIFY_COMPLETED, &request_completed, NULL,
119 MHD_OPTION_NOTIFY_CONNECTION, &connection_completed, NULL, 119 MHD_OPTION_NOTIFY_CONNECTION, &connection_completed, NULL,
120 MHD_OPTION_CONNECTION_TIMEOUT, (unsigned int) 120, 120 MHD_OPTION_CONNECTION_TIMEOUT, (unsigned int) 120,
121 MHD_OPTION_STRICT_FOR_CLIENT, (int) 1, 121 MHD_OPTION_CLIENT_DISCIPLINE_LVL, (int) 1,
122 MHD_OPTION_END); 122 MHD_OPTION_END);
123 if (d == NULL) 123 if (d == NULL)
124 return 1; 124 return 1;
diff --git a/src/examples/minimal_example.c b/src/examples/minimal_example.c
index f7a0e64c..f3fb1c88 100644
--- a/src/examples/minimal_example.c
+++ b/src/examples/minimal_example.c
@@ -105,7 +105,6 @@ main (int argc,
105 (uint16_t) port, 105 (uint16_t) port,
106 NULL, NULL, &ahc_echo, &data_for_handler, 106 NULL, NULL, &ahc_echo, &data_for_handler,
107 MHD_OPTION_CONNECTION_TIMEOUT, (unsigned int) 120, 107 MHD_OPTION_CONNECTION_TIMEOUT, (unsigned int) 120,
108 MHD_OPTION_STRICT_FOR_CLIENT, (int) 1,
109 MHD_OPTION_END); 108 MHD_OPTION_END);
110 if (d == NULL) 109 if (d == NULL)
111 return 1; 110 return 1;
diff --git a/src/examples/minimal_example_empty.c b/src/examples/minimal_example_empty.c
index 3556d753..2c76654a 100644
--- a/src/examples/minimal_example_empty.c
+++ b/src/examples/minimal_example_empty.c
@@ -93,7 +93,6 @@ main (int argc,
93 (uint16_t) port, 93 (uint16_t) port,
94 NULL, NULL, &ahc_echo, NULL, 94 NULL, NULL, &ahc_echo, NULL,
95 MHD_OPTION_CONNECTION_TIMEOUT, (unsigned int) 120, 95 MHD_OPTION_CONNECTION_TIMEOUT, (unsigned int) 120,
96 MHD_OPTION_STRICT_FOR_CLIENT, (int) 1,
97 MHD_OPTION_END); 96 MHD_OPTION_END);
98 if (d == NULL) 97 if (d == NULL)
99 return 1; 98 return 1;
diff --git a/src/examples/minimal_example_empty_tls.c b/src/examples/minimal_example_empty_tls.c
index 465f7492..d0a4d6ff 100644
--- a/src/examples/minimal_example_empty_tls.c
+++ b/src/examples/minimal_example_empty_tls.c
@@ -160,7 +160,7 @@ main (int argc,
160 (uint16_t) port, 160 (uint16_t) port,
161 NULL, NULL, &ahc_echo, NULL, 161 NULL, NULL, &ahc_echo, NULL,
162 MHD_OPTION_CONNECTION_TIMEOUT, (unsigned int) 120, 162 MHD_OPTION_CONNECTION_TIMEOUT, (unsigned int) 120,
163 MHD_OPTION_STRICT_FOR_CLIENT, (int) 1, 163 MHD_OPTION_CLIENT_DISCIPLINE_LVL, (int) 1,
164 /* Optionally, the gnutls_load_file() can be used to 164 /* Optionally, the gnutls_load_file() can be used to
165 load the key and the certificate from file. */ 165 load the key and the certificate from file. */
166 MHD_OPTION_HTTPS_MEM_KEY, srv_signed_key_pem, 166 MHD_OPTION_HTTPS_MEM_KEY, srv_signed_key_pem,
diff --git a/src/include/microhttpd.h b/src/include/microhttpd.h
index b66f4b3d..93967c60 100644
--- a/src/include/microhttpd.h
+++ b/src/include/microhttpd.h
@@ -96,7 +96,7 @@ extern "C"
96 * they are parsed as decimal numbers. 96 * they are parsed as decimal numbers.
97 * Example: 0x01093001 = 1.9.30-1. 97 * Example: 0x01093001 = 1.9.30-1.
98 */ 98 */
99#define MHD_VERSION 0x00097544 99#define MHD_VERSION 0x00097545
100 100
101/* If generic headers don't work on your platform, include headers 101/* If generic headers don't work on your platform, include headers
102 which define 'va_list', 'size_t', 'ssize_t', 'intptr_t', 'off_t', 102 which define 'va_list', 'size_t', 'ssize_t', 'intptr_t', 'off_t',
@@ -1291,12 +1291,14 @@ enum MHD_FLAG
1291 * as liberal as possible in what you accept" norm. It is 1291 * as liberal as possible in what you accept" norm. It is
1292 * recommended to turn this ON if you are testing clients against 1292 * recommended to turn this ON if you are testing clients against
1293 * MHD, and OFF in production. 1293 * MHD, and OFF in production.
1294 * @sa #MHD_OPTION_CLIENT_DISCIPLINE_LVL
1294 */ 1295 */
1295 MHD_USE_PEDANTIC_CHECKS = 32, 1296 MHD_USE_PEDANTIC_CHECKS = 32,
1296#if 0 /* Will be marked for real deprecation later. */ 1297#if 0 /* Will be marked for real deprecation later. */
1297#define MHD_USE_PEDANTIC_CHECKS \ 1298#define MHD_USE_PEDANTIC_CHECKS \
1298 _MHD_DEPR_IN_MACRO ( \ 1299 _MHD_DEPR_IN_MACRO ( \
1299 "Flag MHD_USE_PEDANTIC_CHECKS is deprecated, use option MHD_OPTION_STRICT_FOR_CLIENT instead") \ 1300 "Flag MHD_USE_PEDANTIC_CHECKS is deprecated, " \
1301 "use option MHD_OPTION_CLIENT_DISCIPLINE_LVL instead") \
1300 32 1302 32
1301#endif /* 0 */ 1303#endif /* 0 */
1302 1304
@@ -1939,15 +1941,18 @@ enum MHD_OPTION
1939 * If set to 1 - be strict about the protocol. Use -1 to be 1941 * If set to 1 - be strict about the protocol. Use -1 to be
1940 * as tolerant as possible. 1942 * as tolerant as possible.
1941 * 1943 *
1942 * Specifically, at the moment, at 1 this flag 1944 * The more flexible option #MHD_OPTION_CLIENT_DISCIPLINE_LVL is recommended
1943 * causes MHD to reject HTTP 1.1 connections without a "Host" header, 1945 * instead of this option.
1944 * and to disallow spaces in the URL or (at -1) in HTTP header key strings.
1945 * 1946 *
1946 * These are required by some versions of the standard, but of 1947 * The values mapping table:
1947 * course in violation of the "be as liberal as possible in what you 1948 * #MHD_OPTION_STRICT_FOR_CLIENT | #MHD_OPTION_CLIENT_DISCIPLINE_LVL
1948 * accept" norm. It is recommended to set this to 1 if you are 1949 * -----------------------------:|:---------------------------------
1949 * testing clients against MHD, and 0 in production. This option 1950 * 1 | 1
1950 * should be followed by an `int` argument. 1951 * 0 | 0
1952 * -1 | -3
1953 *
1954 * This option should be followed by an `int` argument.
1955 * @sa #MHD_OPTION_CLIENT_DISCIPLINE_LVL
1951 */ 1956 */
1952 MHD_OPTION_STRICT_FOR_CLIENT = 29, 1957 MHD_OPTION_STRICT_FOR_CLIENT = 29,
1953 1958
@@ -2037,7 +2042,54 @@ enum MHD_OPTION
2037 * default priorities. 2042 * default priorities.
2038 * @note Available since #MHD_VERSION 0x00097542 2043 * @note Available since #MHD_VERSION 0x00097542
2039 */ 2044 */
2040 MHD_OPTION_HTTPS_PRIORITIES_APPEND = 37 2045 MHD_OPTION_HTTPS_PRIORITIES_APPEND = 37,
2046
2047 /**
2048 * Sets specified client discipline level (i.e. HTTP protocol parsing
2049 * strictness level).
2050 *
2051 * The following basic values are supported:
2052 * 0 - default MHD level, a balance between extra security and broader
2053 * compatibility, as allowed by RFCs for HTTP servers;
2054 * 1 - more strict protocol interpretation, within the limits set by
2055 * RFCs for HTTP servers;
2056 * -1 - more lenient protocol interpretation, within the limits set by
2057 * RFCs for HTTP servers.
2058 * The following extended values could be used as well:
2059 * 2 - stricter protocol interpretation, even stricter then allowed
2060 * by RFCs for HTTP servers, however it should be absolutely compatible
2061 * with clients following at least RFCs' "MUST" type of requirements
2062 * for HTTP clients;
2063 * 3 - strictest protocol interpretation, even stricter then allowed
2064 * by RFCs for HTTP servers, however it should be absolutely compatible
2065 * with clients following RFCs' "SHOULD" and "MUST" types of requirements
2066 * for HTTP clients;
2067 * -2 - more relaxed protocol interpretation, violating RFCs' "SHOULD" type
2068 * of requirements for HTTP servers;
2069 * -3 - the most flexible protocol interpretation, beyond RFCs' "MUST" type of
2070 * requirements for HTTP server.
2071 * Values higher than "3" or lower than "-3" are interpreted as "3" or "-3"
2072 * respectively.
2073 *
2074 * Higher values are more secure, lower values are more compatible with
2075 * various HTTP clients.
2076 *
2077 * The default value ("0") could be used in most cases.
2078 * Value "1" is suitable for highly loaded public servers.
2079 * Values "2" and "3" are generally recommended only for testing of HTTP
2080 * clients against MHD.
2081 * Value "2" may be used for security-centric application, however it is
2082 * slight violation of RFCs' requirements.
2083 * Negative values are not recommended for public servers.
2084 * Values "-1" and "-2" could be used for servers in isolated environment.
2085 * Value "-3" is not recommended unless it is absolutely necessary to
2086 * communicate with some client(s) with badly broken HTTP implementation.
2087 *
2088 * This option should be followed by an `int` argument.
2089 * @note Available since #MHD_VERSION 0x00097545
2090 */
2091 MHD_OPTION_CLIENT_DISCIPLINE_LVL = 38
2092
2041} _MHD_FIXED_ENUM; 2093} _MHD_FIXED_ENUM;
2042 2094
2043 2095
diff --git a/src/microhttpd/connection.c b/src/microhttpd/connection.c
index 5e5c2f13..1c6070e8 100644
--- a/src/microhttpd/connection.c
+++ b/src/microhttpd/connection.c
@@ -2846,15 +2846,15 @@ parse_cookies_string (char *str,
2846 size_t i; 2846 size_t i;
2847 bool non_strict; 2847 bool non_strict;
2848 /* Skip extra whitespaces and empty cookies */ 2848 /* Skip extra whitespaces and empty cookies */
2849 const bool allow_wsp_empty = (0 >= connection->daemon->strict_for_client); 2849 const bool allow_wsp_empty = (0 >= connection->daemon->client_discipline);
2850 /* Allow whitespaces around '=' character */ 2850 /* Allow whitespaces around '=' character */
2851 const bool wsp_around_eq = (0 > connection->daemon->strict_for_client); 2851 const bool wsp_around_eq = (-3 >= connection->daemon->client_discipline);
2852 /* Allow whitespaces in quoted cookie value */ 2852 /* Allow whitespaces in quoted cookie value */
2853 const bool wsp_in_quoted = (0 >= connection->daemon->strict_for_client); 2853 const bool wsp_in_quoted = (0 >= connection->daemon->client_discipline);
2854 /* Allow tab as space after semicolon between cookies */ 2854 /* Allow tab as space after semicolon between cookies */
2855 const bool tab_as_sp = (0 >= connection->daemon->strict_for_client); 2855 const bool tab_as_sp = (0 >= connection->daemon->client_discipline);
2856 /* Allow no space after semicolon between cookies */ 2856 /* Allow no space after semicolon between cookies */
2857 const bool allow_no_space = (0 >= connection->daemon->strict_for_client); 2857 const bool allow_no_space = (0 >= connection->daemon->client_discipline);
2858 2858
2859 non_strict = false; 2859 non_strict = false;
2860 i = 0; 2860 i = 0;
@@ -3327,7 +3327,7 @@ parse_initial_message_line (struct MHD_Connection *connection,
3327 uri_len = line_len - (size_t) (uri - line); 3327 uri_len = line_len - (size_t) (uri - line);
3328 } 3328 }
3329 /* check for spaces in URI if we are "strict" */ 3329 /* check for spaces in URI if we are "strict" */
3330 if ( (1 <= daemon->strict_for_client) && 3330 if ( (-2 < daemon->client_discipline) &&
3331 (NULL != memchr (uri, 3331 (NULL != memchr (uri,
3332 ' ', 3332 ' ',
3333 uri_len)) ) 3333 uri_len)) )
@@ -3752,7 +3752,7 @@ process_header_line (struct MHD_Connection *connection,
3752 /* error in header line, die hard */ 3752 /* error in header line, die hard */
3753 return MHD_NO; 3753 return MHD_NO;
3754 } 3754 }
3755 if (-1 >= connection->daemon->strict_for_client) 3755 if (-3 < connection->daemon->client_discipline)
3756 { 3756 {
3757 /* check for whitespace before colon, which is not allowed 3757 /* check for whitespace before colon, which is not allowed
3758 by RFC 7230 section 3.2.4; we count space ' ' and 3758 by RFC 7230 section 3.2.4; we count space ' ' and
@@ -3897,7 +3897,7 @@ parse_connection_headers (struct MHD_Connection *connection)
3897 return; 3897 return;
3898 } 3898 }
3899#endif /* COOKIE_SUPPORT */ 3899#endif /* COOKIE_SUPPORT */
3900 if ( (1 <= connection->daemon->strict_for_client) && 3900 if ( (-3 < connection->daemon->client_discipline) &&
3901 (MHD_IS_HTTP_VER_1_1_COMPAT (connection->rq.http_ver)) && 3901 (MHD_IS_HTTP_VER_1_1_COMPAT (connection->rq.http_ver)) &&
3902 (MHD_NO == 3902 (MHD_NO ==
3903 MHD_lookup_connection_value_n (connection, 3903 MHD_lookup_connection_value_n (connection,
@@ -3946,7 +3946,7 @@ parse_connection_headers (struct MHD_Connection *connection)
3946 NULL)) 3946 NULL))
3947 { 3947 {
3948 /* TODO: add individual settings */ 3948 /* TODO: add individual settings */
3949 if (1 <= connection->daemon->strict_for_client) 3949 if (1 <= connection->daemon->client_discipline)
3950 { 3950 {
3951 transmit_error_response_static (connection, 3951 transmit_error_response_static (connection,
3952 MHD_HTTP_BAD_REQUEST, 3952 MHD_HTTP_BAD_REQUEST,
diff --git a/src/microhttpd/daemon.c b/src/microhttpd/daemon.c
index d854de31..746d9493 100644
--- a/src/microhttpd/daemon.c
+++ b/src/microhttpd/daemon.c
@@ -5729,7 +5729,7 @@ unescape_wrapper (void *cls,
5729 (void) cls; /* Mute compiler warning. */ 5729 (void) cls; /* Mute compiler warning. */
5730 5730
5731 /* TODO: add individual parameter */ 5731 /* TODO: add individual parameter */
5732 if (1 <= connection->daemon->strict_for_client) 5732 if (0 <= connection->daemon->client_discipline)
5733 return MHD_str_pct_decode_in_place_strict_ (val); 5733 return MHD_str_pct_decode_in_place_strict_ (val);
5734 5734
5735 res = MHD_str_pct_decode_in_place_lenient_ (val, &broken); 5735 res = MHD_str_pct_decode_in_place_lenient_ (val, &broken);
@@ -6653,14 +6653,33 @@ parse_options_va (struct MHD_Daemon *daemon,
6653 unsigned int); 6653 unsigned int);
6654 break; 6654 break;
6655 case MHD_OPTION_STRICT_FOR_CLIENT: 6655 case MHD_OPTION_STRICT_FOR_CLIENT:
6656 daemon->strict_for_client = va_arg (ap, int); 6656 daemon->client_discipline = va_arg (ap, int); /* Temporal assignment */
6657 /* Map to correct value */
6658 if (-1 >= daemon->client_discipline)
6659 daemon->client_discipline = -3;
6660 else if (1 <= daemon->client_discipline)
6661 daemon->client_discipline = 1;
6657#ifdef HAVE_MESSAGES 6662#ifdef HAVE_MESSAGES
6658 if ( (0 != (daemon->options & MHD_USE_PEDANTIC_CHECKS)) && 6663 if ( (0 != (daemon->options & MHD_USE_PEDANTIC_CHECKS)) &&
6659 (1 != daemon->strict_for_client) ) 6664 (1 != daemon->client_discipline) )
6660 { 6665 {
6661 MHD_DLOG (daemon, 6666 MHD_DLOG (daemon,
6662 _ ("Flag MHD_USE_PEDANTIC_CHECKS is ignored because " 6667 _ ("Flag MHD_USE_PEDANTIC_CHECKS is ignored because "
6663 "another behavior is specified by MHD_OPTION_STRICT_CLIENT.\n")); 6668 "another behaviour is specified by "
6669 "MHD_OPTION_STRICT_CLIENT.\n"));
6670 }
6671#endif /* HAVE_MESSAGES */
6672 break;
6673 case MHD_OPTION_CLIENT_DISCIPLINE_LVL:
6674 daemon->client_discipline = va_arg (ap, int);
6675#ifdef HAVE_MESSAGES
6676 if ( (0 != (daemon->options & MHD_USE_PEDANTIC_CHECKS)) &&
6677 (1 != daemon->client_discipline) )
6678 {
6679 MHD_DLOG (daemon,
6680 _ ("Flag MHD_USE_PEDANTIC_CHECKS is ignored because "
6681 "another behaviour is specified by "
6682 "MHD_OPTION_CLIENT_DISCIPLINE_LVL.\n"));
6664 } 6683 }
6665#endif /* HAVE_MESSAGES */ 6684#endif /* HAVE_MESSAGES */
6666 break; 6685 break;
@@ -6723,6 +6742,7 @@ parse_options_va (struct MHD_Daemon *daemon,
6723 break; 6742 break;
6724 /* all options taking 'int' */ 6743 /* all options taking 'int' */
6725 case MHD_OPTION_STRICT_FOR_CLIENT: 6744 case MHD_OPTION_STRICT_FOR_CLIENT:
6745 case MHD_OPTION_CLIENT_DISCIPLINE_LVL:
6726 case MHD_OPTION_SIGPIPE_HANDLED_BY_APP: 6746 case MHD_OPTION_SIGPIPE_HANDLED_BY_APP:
6727 case MHD_OPTION_TLS_NO_ALPN: 6747 case MHD_OPTION_TLS_NO_ALPN:
6728 if (MHD_NO == parse_options (daemon, 6748 if (MHD_NO == parse_options (daemon,
@@ -7102,8 +7122,8 @@ MHD_start_daemon_va (unsigned int flags,
7102 daemon->listening_address_reuse = 0; 7122 daemon->listening_address_reuse = 0;
7103 daemon->options = *pflags; 7123 daemon->options = *pflags;
7104 pflags = &daemon->options; 7124 pflags = &daemon->options;
7105 daemon->strict_for_client = (0 != (*pflags & MHD_USE_PEDANTIC_CHECKS)) ? 1 : 7125 daemon->client_discipline = (0 != (*pflags & MHD_USE_PEDANTIC_CHECKS)) ?
7106 0; 7126 1 : 0;
7107 daemon->port = port; 7127 daemon->port = port;
7108 daemon->apc = apc; 7128 daemon->apc = apc;
7109 daemon->apc_cls = apc_cls; 7129 daemon->apc_cls = apc_cls;
diff --git a/src/microhttpd/internal.h b/src/microhttpd/internal.h
index 78481b21..9f5ed442 100644
--- a/src/microhttpd/internal.h
+++ b/src/microhttpd/internal.h
@@ -2104,9 +2104,10 @@ struct MHD_Daemon
2104 unsigned int per_ip_connection_limit; 2104 unsigned int per_ip_connection_limit;
2105 2105
2106 /** 2106 /**
2107 * Be neutral (zero), strict (1) or permissive (-1) to client. 2107 * The strictness level for parsing of incoming data.
2108 * @see #MHD_OPTION_CLIENT_DISCIPLINE_LVL
2108 */ 2109 */
2109 int strict_for_client; 2110 int client_discipline;
2110 2111
2111 /** 2112 /**
2112 * True if SIGPIPE is blocked 2113 * True if SIGPIPE is blocked