aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEvgeny Grin (Karlson2k) <k2k@narod.ru>2021-05-21 18:59:49 +0300
committerEvgeny Grin (Karlson2k) <k2k@narod.ru>2021-05-21 18:59:49 +0300
commitde6922ca8204fe08d8105591bf094c0a359da8c3 (patch)
treea6b86f967daf1b5f3b84221af284d0a73714c9a2
parent65413082c902934cacc32899fcda4ddae35e2f21 (diff)
downloadlibmicrohttpd-de6922ca8204fe08d8105591bf094c0a359da8c3.tar.gz
libmicrohttpd-de6922ca8204fe08d8105591bf094c0a359da8c3.zip
Added detection of HTTP version during early parsing
Requests with unsupported HTTP versions are rejected as specified by RFC 7230.
-rw-r--r--src/microhttpd/connection.c92
-rw-r--r--src/microhttpd/internal.h58
2 files changed, 150 insertions, 0 deletions
diff --git a/src/microhttpd/connection.c b/src/microhttpd/connection.c
index 08b76eb6..8876f692 100644
--- a/src/microhttpd/connection.c
+++ b/src/microhttpd/connection.c
@@ -114,6 +114,26 @@
114#define INTERNAL_ERROR "" 114#define INTERNAL_ERROR ""
115#endif 115#endif
116 116
117/**
118 * Response text used when the request HTTP version is too old.
119 */
120#ifdef HAVE_MESSAGES
121#define REQ_HTTP_VER_IS_TOO_OLD \
122 "<html><head><title>Requested HTTP version is not supported</title></head><body>Requested HTTP version is too old and not supported.</body></html>"
123#else
124#define REQ_HTTP_VER_IS_TOO_OLD ""
125#endif
126
127/**
128 * Response text used when the request HTTP version is too old.
129 */
130#ifdef HAVE_MESSAGES
131#define REQ_HTTP_VER_IS_NOT_SUPPORTED \
132 "<html><head><title>Requested HTTP version is not supported</title></head><body>Requested HTTP version is not supported.</body></html>"
133#else
134#define REQ_HTTP_VER_IS_NOT_SUPPORTED ""
135#endif
136
117 137
118/** 138/**
119 * sendfile() chuck size 139 * sendfile() chuck size
@@ -2088,6 +2108,69 @@ parse_cookie_header (struct MHD_Connection *connection)
2088 2108
2089 2109
2090/** 2110/**
2111 * Detect HTTP version
2112 *
2113 * @param connection the connection
2114 * @param http_string the pointer to HTTP version string
2115 * @param len the length of @a http_string in bytes
2116 * @return #MHD_YES if HTTP version is correct and supported,
2117 * #MHD_NO if HTTP version is not correct or unsupported.
2118 */
2119static enum MHD_Result
2120parse_http_version (struct MHD_Connection *connection,
2121 const char*http_string,
2122 size_t len)
2123{
2124 const char *const h = http_string; /**< short alias */
2125 mhd_assert (NULL != http_string);
2126
2127 /* String must starts with 'HTTP/d.d', case-sensetive match.
2128 * See https://datatracker.ietf.org/doc/html/rfc7230#section-2.6 */
2129 if ((len != 8) ||
2130 (h[0] != 'H') || (h[1] != 'T') || (h[2] != 'T') || (h[3] != 'P') ||
2131 (h[4] != '/')
2132 || (h[6] != '.') ||
2133 ((h[5] < '0') || (h[5] > '9')) ||
2134 ((h[7] < '0') || (h[7] > '9')))
2135 {
2136 connection->http_ver = MHD_HTTP_VER_INVALID;
2137 transmit_error_response (connection,
2138 MHD_HTTP_BAD_REQUEST,
2139 REQUEST_MALFORMED);
2140 return MHD_NO;
2141 }
2142 if (1 == h[5] - '0')
2143 {
2144 /* HTTP/1.x */
2145 if (1 == h[7] - '0')
2146 connection->http_ver = MHD_HTTP_VER_1_1;
2147 else if (0 == h[7] - '0')
2148 connection->http_ver = MHD_HTTP_VER_1_0;
2149 else
2150 connection->http_ver = MHD_HTTP_VER_1_2__1_9;
2151
2152 return MHD_YES;
2153 }
2154
2155 if (0 == h[5] - '0')
2156 {
2157 /* Too old major version */
2158 connection->http_ver = MHD_HTTP_VER_TOO_OLD;
2159 transmit_error_response (connection,
2160 MHD_HTTP_HTTP_VERSION_NOT_SUPPORTED,
2161 REQ_HTTP_VER_IS_TOO_OLD);
2162 return MHD_NO;
2163 }
2164
2165 connection->http_ver = MHD_HTTP_VER_FUTURE;
2166 transmit_error_response (connection,
2167 MHD_HTTP_HTTP_VERSION_NOT_SUPPORTED,
2168 REQ_HTTP_VER_IS_NOT_SUPPORTED);
2169 return MHD_NO;
2170}
2171
2172
2173/**
2091 * Parse the first line of the HTTP HEADER. 2174 * Parse the first line of the HTTP HEADER.
2092 * 2175 *
2093 * @param connection the connection (updated) 2176 * @param connection the connection (updated)
@@ -2126,6 +2209,8 @@ parse_initial_message_line (struct MHD_Connection *connection,
2126 uri = NULL; 2209 uri = NULL;
2127 connection->version = ""; 2210 connection->version = "";
2128 args = NULL; 2211 args = NULL;
2212 if (MHD_NO == parse_http_version (connection, connection->version, 0))
2213 return MHD_NO;
2129 } 2214 }
2130 else 2215 else
2131 { 2216 {
@@ -2146,11 +2231,17 @@ parse_initial_message_line (struct MHD_Connection *connection,
2146 /* http_version points to character before HTTP version string */ 2231 /* http_version points to character before HTTP version string */
2147 http_version[0] = '\0'; 2232 http_version[0] = '\0';
2148 connection->version = http_version + 1; 2233 connection->version = http_version + 1;
2234 if (MHD_NO == parse_http_version (connection, connection->version,
2235 line_len
2236 - (connection->version - line)))
2237 return MHD_NO;
2149 uri_len = http_version - uri; 2238 uri_len = http_version - uri;
2150 } 2239 }
2151 else 2240 else
2152 { 2241 {
2153 connection->version = ""; 2242 connection->version = "";
2243 if (MHD_NO == parse_http_version (connection, connection->version, 0))
2244 return MHD_NO;
2154 uri_len = line_len - (uri - line); 2245 uri_len = line_len - (uri - line);
2155 } 2246 }
2156 /* check for spaces in URI if we are "strict" */ 2247 /* check for spaces in URI if we are "strict" */
@@ -3756,6 +3847,7 @@ MHD_connection_handle_idle (struct MHD_Connection *connection)
3756 /* can try to keep-alive */ 3847 /* can try to keep-alive */
3757 3848
3758 connection->version = NULL; 3849 connection->version = NULL;
3850 connection->http_ver = MHD_HTTP_VER_UNKNOWN;
3759 connection->state = MHD_CONNECTION_INIT; 3851 connection->state = MHD_CONNECTION_INIT;
3760 connection->last = NULL; 3852 connection->last = NULL;
3761 connection->colon = NULL; 3853 connection->colon = NULL;
diff --git a/src/microhttpd/internal.h b/src/microhttpd/internal.h
index 346001c3..e684aa88 100644
--- a/src/microhttpd/internal.h
+++ b/src/microhttpd/internal.h
@@ -732,6 +732,59 @@ enum MHD_ConnKeepAlive
732 MHD_CONN_USE_KEEPALIVE = 1 732 MHD_CONN_USE_KEEPALIVE = 1
733}; 733};
734 734
735enum MHD_HTTP_version
736{
737 /**
738 * Not a HTTP protocol or HTTP version is invalid.
739 */
740 MHD_HTTP_VER_INVALID = -1,
741
742 /**
743 * HTTP version is not yet received from the client.
744 */
745 MHD_HTTP_VER_UNKNOWN = 0,
746
747 /**
748 * HTTP version before 1.0, unsupported.
749 */
750 MHD_HTTP_VER_TOO_OLD = 1,
751
752 /**
753 * HTTP version 1.0
754 */
755 MHD_HTTP_VER_1_0 = 2,
756
757 /**
758 * HTTP version 1.1
759 */
760 MHD_HTTP_VER_1_1 = 3,
761
762 /**
763 * HTTP version 1.2-1.9, must be used as 1.1
764 */
765 MHD_HTTP_VER_1_2__1_9 = 4,
766
767 /**
768 * HTTP future version. Unsupported.
769 * Reserved, not really detected.
770 */
771 MHD_HTTP_VER_FUTURE = 100
772};
773
774/**
775 * Returns boolean 'true' if HTTP version is supported by MHD
776 */
777#define MHD_IS_HTTP_VER_SUPPORTED(ver) (MHD_HTTP_VER_1_0 <= (ver) && \
778 MHD_HTTP_VER_1_2__1_9 >= (ver))
779
780/**
781 * Protocol should be used as HTTP/1.1 protocol.
782 *
783 * See the last paragraph of
784 * https://datatracker.ietf.org/doc/html/rfc7230#section-2.6
785 */
786#define MHD_IS_HTTP_VER_1_1_COMPAT(ver) (MHD_HTTP_VER_1_1 == (ver) || \
787 MHD_HTTP_VER_1_2__1_9 == (ver))
735 788
736/** 789/**
737 * State kept for each HTTP request. 790 * State kept for each HTTP request.
@@ -840,6 +893,11 @@ struct MHD_Connection
840 char *version; 893 char *version;
841 894
842 /** 895 /**
896 * HTTP protocol version as enum.
897 */
898 enum MHD_HTTP_version http_ver;
899
900 /**
843 * Close connection after sending response? 901 * Close connection after sending response?
844 * Functions may change value from "Unknown" or "KeepAlive" to "Must close", 902 * Functions may change value from "Unknown" or "KeepAlive" to "Must close",
845 * but no functions reset value "Must Close" to any other value. 903 * but no functions reset value "Must Close" to any other value.