diff options
Diffstat (limited to 'src/microhttpd/connection.c')
-rw-r--r-- | src/microhttpd/connection.c | 1027 |
1 files changed, 886 insertions, 141 deletions
diff --git a/src/microhttpd/connection.c b/src/microhttpd/connection.c index 756aba4f..2020b76b 100644 --- a/src/microhttpd/connection.c +++ b/src/microhttpd/connection.c | |||
@@ -64,13 +64,14 @@ | |||
64 | /** | 64 | /** |
65 | * Response text used when the request (http header) is too big to | 65 | * Response text used when the request (http header) is too big to |
66 | * be processed. | 66 | * be processed. |
67 | * | ||
68 | * Intentionally empty here to keep our memory footprint | ||
69 | * minimal. | ||
70 | */ | 67 | */ |
71 | #ifdef HAVE_MESSAGES | 68 | #ifdef HAVE_MESSAGES |
72 | #define REQUEST_TOO_BIG \ | 69 | #define REQUEST_TOO_BIG \ |
73 | "<html><head><title>Request too big</title></head><body>Your HTTP header was too big for the memory constraints of this webserver.</body></html>" | 70 | "<html>" \ |
71 | "<head><title>Request too big</title></head>" \ | ||
72 | "<body>Your HTTP header is too big for the memory constraints " \ | ||
73 | "of this webserver.</body>" \ | ||
74 | "</html>" | ||
74 | #else | 75 | #else |
75 | #define REQUEST_TOO_BIG "" | 76 | #define REQUEST_TOO_BIG "" |
76 | #endif | 77 | #endif |
@@ -104,6 +105,21 @@ | |||
104 | #endif | 105 | #endif |
105 | 106 | ||
106 | /** | 107 | /** |
108 | * Response text used when the request HTTP footer has bare CR character | ||
109 | * without LF character (and CR is not allowed to be treated as whitespace). | ||
110 | */ | ||
111 | #ifdef HAVE_MESSAGES | ||
112 | #define BARE_CR_IN_FOOTER \ | ||
113 | "<html>" \ | ||
114 | "<head><title>Request broken</title></head>" \ | ||
115 | "<body>Your HTTP footer has bare CR character without " \ | ||
116 | "following LF character.</body>" \ | ||
117 | "</html>" | ||
118 | #else | ||
119 | #define BARE_CR_IN_FOOTER "" | ||
120 | #endif | ||
121 | |||
122 | /** | ||
107 | * Response text used when the request HTTP header has bare LF character | 123 | * Response text used when the request HTTP header has bare LF character |
108 | * without CR character. | 124 | * without CR character. |
109 | */ | 125 | */ |
@@ -119,6 +135,21 @@ | |||
119 | #endif | 135 | #endif |
120 | 136 | ||
121 | /** | 137 | /** |
138 | * Response text used when the request HTTP footer has bare LF character | ||
139 | * without CR character. | ||
140 | */ | ||
141 | #ifdef HAVE_MESSAGES | ||
142 | #define BARE_LF_IN_FOOTER \ | ||
143 | "<html>" \ | ||
144 | "<head><title>Request broken</title></head>" \ | ||
145 | "<body>Your HTTP footer has bare LF character without " \ | ||
146 | "preceding CR character.</body>" \ | ||
147 | "</html>" | ||
148 | #else | ||
149 | #define BARE_LF_IN_FOOTER "" | ||
150 | #endif | ||
151 | |||
152 | /** | ||
122 | * Response text used when the request line has invalid characters in URI. | 153 | * Response text used when the request line has invalid characters in URI. |
123 | */ | 154 | */ |
124 | #ifdef HAVE_MESSAGES | 155 | #ifdef HAVE_MESSAGES |
@@ -133,6 +164,170 @@ | |||
133 | #endif | 164 | #endif |
134 | 165 | ||
135 | /** | 166 | /** |
167 | * Response text used when line folding is used in request headers. | ||
168 | */ | ||
169 | #ifdef HAVE_MESSAGES | ||
170 | #define ERR_RSP_OBS_FOLD \ | ||
171 | "<html>" \ | ||
172 | "<head><title>Request broken</title></head>" \ | ||
173 | "<body>Obsolete line folding is used in your HTTP request header.</body>" \ | ||
174 | "</html>" | ||
175 | #else | ||
176 | #define ERR_RSP_OBS_FOLD "" | ||
177 | #endif | ||
178 | |||
179 | /** | ||
180 | * Response text used when line folding is used in request footers. | ||
181 | */ | ||
182 | #ifdef HAVE_MESSAGES | ||
183 | #define ERR_RSP_OBS_FOLD_FOOTER \ | ||
184 | "<html>" \ | ||
185 | "<head><title>Request broken</title></head>" \ | ||
186 | "<body>Obsolete line folding is used in your HTTP request footer.</body>" \ | ||
187 | "</html>" | ||
188 | #else | ||
189 | #define ERR_RSP_OBS_FOLD_FOOTER "" | ||
190 | #endif | ||
191 | |||
192 | /** | ||
193 | * Response text used when the request has whitespace at the start | ||
194 | * of the first header line. | ||
195 | */ | ||
196 | #ifdef HAVE_MESSAGES | ||
197 | #define ERR_RSP_WSP_BEFORE_HEADER \ | ||
198 | "<html>" \ | ||
199 | "<head><title>Request broken</title></head>" \ | ||
200 | "<body>Your HTTP request has whitespace between the request line and " \ | ||
201 | "the first header.</body>" \ | ||
202 | "</html>" | ||
203 | #else | ||
204 | #define ERR_RSP_WSP_BEFORE_HEADER "" | ||
205 | #endif | ||
206 | |||
207 | /** | ||
208 | * Response text used when the request has whitespace at the start | ||
209 | * of the first footer line. | ||
210 | */ | ||
211 | #ifdef HAVE_MESSAGES | ||
212 | #define ERR_RSP_WSP_BEFORE_FOOTER \ | ||
213 | "<html>" \ | ||
214 | "<head><title>Request broken</title></head>" \ | ||
215 | "<body>Your first HTTP footer line has whitespace at the first " \ | ||
216 | "position.</body>" \ | ||
217 | "</html>" | ||
218 | #else | ||
219 | #define ERR_RSP_WSP_BEFORE_FOOTER "" | ||
220 | #endif | ||
221 | |||
222 | /** | ||
223 | * Response text used when the whitespace found before colon (inside header | ||
224 | * name or between header name and colon). | ||
225 | */ | ||
226 | #ifdef HAVE_MESSAGES | ||
227 | #define ERR_RSP_WSP_IN_HEADER_NAME \ | ||
228 | "<html>" \ | ||
229 | "<head><title>Request broken</title></head>" \ | ||
230 | "<body>Your HTTP request has whitespace before the first colon " \ | ||
231 | "in header line.</body>" \ | ||
232 | "</html>" | ||
233 | #else | ||
234 | #define ERR_RSP_WSP_IN_HEADER_NAME "" | ||
235 | #endif | ||
236 | |||
237 | /** | ||
238 | * Response text used when the whitespace found before colon (inside header | ||
239 | * name or between header name and colon). | ||
240 | */ | ||
241 | #ifdef HAVE_MESSAGES | ||
242 | #define ERR_RSP_WSP_IN_FOOTER_NAME \ | ||
243 | "<html>" \ | ||
244 | "<head><title>Request broken</title></head>" \ | ||
245 | "<body>Your HTTP request has whitespace before the first colon " \ | ||
246 | "in footer line.</body>" \ | ||
247 | "</html>" | ||
248 | #else | ||
249 | #define ERR_RSP_WSP_IN_FOOTER_NAME "" | ||
250 | #endif | ||
251 | |||
252 | /** | ||
253 | * Response text used when request header has invalid character. | ||
254 | */ | ||
255 | #ifdef HAVE_MESSAGES | ||
256 | #define ERR_RSP_INVALID_CHR_IN_HEADER \ | ||
257 | "<html>" \ | ||
258 | "<head><title>Request broken</title></head>" \ | ||
259 | "<body>Your HTTP request has invalid character in header.</body>" \ | ||
260 | "</html>" | ||
261 | #else | ||
262 | #define ERR_RSP_INVALID_CHR_IN_HEADER "" | ||
263 | #endif | ||
264 | |||
265 | /** | ||
266 | * Response text used when request header has invalid character. | ||
267 | */ | ||
268 | #ifdef HAVE_MESSAGES | ||
269 | #define ERR_RSP_INVALID_CHR_IN_FOOTER \ | ||
270 | "<html>" \ | ||
271 | "<head><title>Request broken</title></head>" \ | ||
272 | "<body>Your HTTP request has invalid character in footer.</body>" \ | ||
273 | "</html>" | ||
274 | #else | ||
275 | #define ERR_RSP_INVALID_CHR_IN_HEADER "" | ||
276 | #endif | ||
277 | |||
278 | /** | ||
279 | * Response text used when request header has no colon character. | ||
280 | */ | ||
281 | #ifdef HAVE_MESSAGES | ||
282 | #define ERR_RSP_HEADER_WITHOUT_COLON \ | ||
283 | "<html>" \ | ||
284 | "<head><title>Request broken</title></head>" \ | ||
285 | "<body>Your HTTP request header line has no colon character.</body>" \ | ||
286 | "</html>" | ||
287 | #else | ||
288 | #define ERR_RSP_INVALID_CHR_IN_HEADER "" | ||
289 | #endif | ||
290 | |||
291 | /** | ||
292 | * Response text used when request footer has no colon character. | ||
293 | */ | ||
294 | #ifdef HAVE_MESSAGES | ||
295 | #define ERR_RSP_FOOTER_WITHOUT_COLON \ | ||
296 | "<html>" \ | ||
297 | "<head><title>Request broken</title></head>" \ | ||
298 | "<body>Your HTTP request footer line has no colon character.</body>" \ | ||
299 | "</html>" | ||
300 | #else | ||
301 | #define ERR_RSP_FOOTER_WITHOUT_COLON "" | ||
302 | #endif | ||
303 | |||
304 | /** | ||
305 | * Response text used when request header has zero-length header (filed) name. | ||
306 | */ | ||
307 | #ifdef HAVE_MESSAGES | ||
308 | #define ERR_RSP_EMPTY_HEADER_NAME \ | ||
309 | "<html>" \ | ||
310 | "<head><title>Request broken</title></head>" \ | ||
311 | "<body>Your HTTP request header has empty header name.</body>" \ | ||
312 | "</html>" | ||
313 | #else | ||
314 | #define ERR_RSP_EMPTY_HEADER_NAME "" | ||
315 | #endif | ||
316 | |||
317 | /** | ||
318 | * Response text used when request header has zero-length header (filed) name. | ||
319 | */ | ||
320 | #ifdef HAVE_MESSAGES | ||
321 | #define ERR_RSP_EMPTY_FOOTER_NAME \ | ||
322 | "<html>" \ | ||
323 | "<head><title>Request broken</title></head>" \ | ||
324 | "<body>Your HTTP request footer has empty header name.</body>" \ | ||
325 | "</html>" | ||
326 | #else | ||
327 | #define ERR_RSP_EMPTY_FOOTER_NAME "" | ||
328 | #endif | ||
329 | |||
330 | /** | ||
136 | * Response text used when the request (http header) does not | 331 | * Response text used when the request (http header) does not |
137 | * contain a "Host:" header and still claims to be HTTP 1.1. | 332 | * contain a "Host:" header and still claims to be HTTP 1.1. |
138 | * | 333 | * |
@@ -2656,7 +2851,7 @@ MHD_connection_update_event_loop_info (struct MHD_Connection *connection) | |||
2656 | case MHD_CONNECTION_INIT: | 2851 | case MHD_CONNECTION_INIT: |
2657 | case MHD_CONNECTION_REQ_LINE_RECEIVING: | 2852 | case MHD_CONNECTION_REQ_LINE_RECEIVING: |
2658 | case MHD_CONNECTION_REQ_LINE_RECEIVED: | 2853 | case MHD_CONNECTION_REQ_LINE_RECEIVED: |
2659 | case MHD_CONNECTION_HEADER_PART_RECEIVED: | 2854 | case MHD_CONNECTION_REQ_HEADERS_RECEIVING: |
2660 | /* while reading headers, we always grow the | 2855 | /* while reading headers, we always grow the |
2661 | read buffer if needed, no size-check required */ | 2856 | read buffer if needed, no size-check required */ |
2662 | if ( (connection->read_buffer_offset == connection->read_buffer_size) && | 2857 | if ( (connection->read_buffer_offset == connection->read_buffer_size) && |
@@ -2723,7 +2918,7 @@ MHD_connection_update_event_loop_info (struct MHD_Connection *connection) | |||
2723 | connection->event_loop_info = MHD_EVENT_LOOP_INFO_READ; | 2918 | connection->event_loop_info = MHD_EVENT_LOOP_INFO_READ; |
2724 | break; | 2919 | break; |
2725 | case MHD_CONNECTION_BODY_RECEIVED: | 2920 | case MHD_CONNECTION_BODY_RECEIVED: |
2726 | case MHD_CONNECTION_FOOTER_PART_RECEIVED: | 2921 | case MHD_CONNECTION_FOOTERS_RECEIVING: |
2727 | /* while reading footers, we always grow the | 2922 | /* while reading footers, we always grow the |
2728 | read buffer if needed, no size-check required */ | 2923 | read buffer if needed, no size-check required */ |
2729 | if (connection->read_closed) | 2924 | if (connection->read_closed) |
@@ -3971,6 +4166,20 @@ parse_connection_headers (struct MHD_Connection *connection) | |||
3971 | } | 4166 | } |
3972 | 4167 | ||
3973 | 4168 | ||
4169 | /** | ||
4170 | * Reset request header processing state. | ||
4171 | * | ||
4172 | * This function resets the processing state before processing the next header | ||
4173 | * (or footer) line. | ||
4174 | * @param c the connection to process | ||
4175 | */ | ||
4176 | _MHD_static_inline void | ||
4177 | reset_rq_header_processing_state (struct MHD_Connection *c) | ||
4178 | { | ||
4179 | memset (&c->rq.hdrs.hdr, 0, sizeof(c->rq.hdrs.hdr)); | ||
4180 | } | ||
4181 | |||
4182 | |||
3974 | #ifndef MHD_MAX_EMPTY_LINES_SKIP | 4183 | #ifndef MHD_MAX_EMPTY_LINES_SKIP |
3975 | /** | 4184 | /** |
3976 | * The maximum number of ignored empty line before the request line | 4185 | * The maximum number of ignored empty line before the request line |
@@ -3982,7 +4191,8 @@ parse_connection_headers (struct MHD_Connection *connection) | |||
3982 | /** | 4191 | /** |
3983 | * Find and parse the request line. | 4192 | * Find and parse the request line. |
3984 | * @param c the connection to process | 4193 | * @param c the connection to process |
3985 | * @return true if request line completely processed and state is changed, | 4194 | * @return true if request line completely processed (or unrecoverable error |
4195 | * found) and state is changed, | ||
3986 | * false if not enough data yet in the receive buffer | 4196 | * false if not enough data yet in the receive buffer |
3987 | */ | 4197 | */ |
3988 | static bool | 4198 | static bool |
@@ -4733,26 +4943,641 @@ get_request_line (struct MHD_Connection *c) | |||
4733 | return true; /* Error in the request */ | 4943 | return true; /* Error in the request */ |
4734 | } | 4944 | } |
4735 | } | 4945 | } |
4946 | if (! process_request_target (c)) | ||
4947 | return true; /* Error in processing */ | ||
4948 | |||
4949 | c->state = MHD_CONNECTION_REQ_LINE_RECEIVED; | ||
4950 | return true; | ||
4951 | } | ||
4952 | |||
4953 | |||
4954 | /** | ||
4955 | * Results of header line reading | ||
4956 | */ | ||
4957 | enum MHD_HdrLineReadRes_ | ||
4958 | { | ||
4959 | /** | ||
4960 | * Not enough data yet | ||
4961 | */ | ||
4962 | MHD_HDR_LINE_READING_NEED_MORE_DATA = 0, | ||
4963 | /** | ||
4964 | * New header line has been read | ||
4965 | */ | ||
4966 | MHD_HDR_LINE_READING_GOT_HEADER, | ||
4967 | /** | ||
4968 | * Error in header data, error response has been queued | ||
4969 | */ | ||
4970 | MHD_HDR_LINE_READING_DATA_ERROR, | ||
4971 | /** | ||
4972 | * Found the end of the request header (end of field lines) | ||
4973 | */ | ||
4974 | MHD_HDR_LINE_READING_GOT_END_OF_HEADER | ||
4975 | } _MHD_FIXED_ENUM; | ||
4976 | |||
4977 | |||
4978 | /** | ||
4979 | * Find the end of the request header line and make basic header parsing. | ||
4980 | * Handle errors and header folding. | ||
4981 | * @param c the connection to process | ||
4982 | * @param process_footers if true then footers are processed, | ||
4983 | * if false then headers are processed | ||
4984 | * @param[out] hdr_name the name of the parsed header (field) | ||
4985 | * @param[out] hdr_name the value of the parsed header (field) | ||
4986 | * @return true if request header line completely processed, | ||
4987 | * false if not enough data yet in the receive buffer | ||
4988 | */ | ||
4989 | static enum MHD_HdrLineReadRes_ | ||
4990 | get_req_header (struct MHD_Connection *c, | ||
4991 | bool process_footers, | ||
4992 | struct _MHD_str_w_len *hdr_name, | ||
4993 | struct _MHD_str_w_len *hdr_value) | ||
4994 | { | ||
4995 | const int discp_lvl = c->daemon->client_discipline; | ||
4996 | /* Treat bare LF as the end of the line. | ||
4997 | RFC 9112, section 2.2-3 | ||
4998 | Note: MHD never replaces bare LF with space (RFC 9110, section 5.5-5). | ||
4999 | Bare LF is processed as end of the line or rejected as broken request. */ | ||
5000 | const bool bare_lf_as_crlf = (0 >= discp_lvl); | ||
5001 | /* Keep bare CR character as is. | ||
5002 | Violates RFC 9112, section 2.2-4 */ | ||
5003 | const bool bare_cr_keep = (-3 >= discp_lvl); | ||
5004 | /* Treat bare CR as space; replace it with space before processing. | ||
5005 | RFC 9112, section 2.2-4 */ | ||
5006 | const bool bare_cr_as_sp = ((! bare_cr_keep) && (-1 >= discp_lvl)); | ||
5007 | /* Treat NUL as space; replace it with space before processing. | ||
5008 | RFC 9110, section 5.5-5 */ | ||
5009 | const bool nul_as_sp = (-1 >= discp_lvl); | ||
5010 | /* Allow folded header lines. | ||
5011 | RFC 9112, section 5.2-4 */ | ||
5012 | const bool allow_folded = (0 >= discp_lvl); | ||
5013 | /* Do not reject headers with the whitespace at the start of the first line. | ||
5014 | When allowed, the first line with whitespace character at the first | ||
5015 | position is ignored (as well as all possible line foldings of the first | ||
5016 | line). | ||
5017 | RFC 9112, section 2.2-8 */ | ||
5018 | const bool allow_wsp_at_start = allow_folded && (-1 >= discp_lvl); | ||
5019 | /* Allow whitespace in header (field) name. | ||
5020 | Violates RFC 9110, section 5.1-2 */ | ||
5021 | const bool allow_wsp_in_name = (-2 >= discp_lvl); | ||
5022 | /* Allow zero-length header (field) name. | ||
5023 | Violates RFC 9110, section 5.1-2 */ | ||
5024 | const bool allow_empty_name = (-2 >= discp_lvl); | ||
5025 | /* Allow whitespace before colon. | ||
5026 | Violates RFC 9112, section 5.1-2 */ | ||
5027 | const bool allow_wsp_before_colon = (-3 >= discp_lvl); | ||
5028 | /* Do not abort the request when header line has no colon, just skip such | ||
5029 | bad lines. | ||
5030 | RFC 9112, section 5-1 */ | ||
5031 | const bool allow_line_without_colon = (-2 >= discp_lvl); | ||
5032 | |||
5033 | size_t p; /**< The position of the currently processed character */ | ||
5034 | |||
5035 | #if ! defined (HAVE_MESSAGES) && ! defined(_DEBUG) | ||
5036 | (void) process_footers; /* Unused parameter */ | ||
5037 | #endif /* !HAVE_MESSAGES && !_DEBUG */ | ||
5038 | |||
5039 | mhd_assert ((process_footers ? MHD_CONNECTION_FOOTERS_RECEIVING : \ | ||
5040 | MHD_CONNECTION_REQ_HEADERS_RECEIVING) == \ | ||
5041 | c->state); | ||
5042 | |||
5043 | p = c->rq.hdrs.hdr.proc_pos; | ||
5044 | |||
5045 | mhd_assert (p <= c->read_buffer_offset); | ||
5046 | while (p < c->read_buffer_offset) | ||
5047 | { | ||
5048 | const char chr = c->read_buffer[p]; | ||
5049 | bool end_of_line; | ||
5050 | |||
5051 | mhd_assert ((0 == c->rq.hdrs.hdr.name_len) || \ | ||
5052 | (c->rq.hdrs.hdr.name_len < p)); | ||
5053 | mhd_assert ((0 == c->rq.hdrs.hdr.name_len) || (0 != p)); | ||
5054 | mhd_assert ((0 == c->rq.hdrs.hdr.name_len) || \ | ||
5055 | (c->rq.hdrs.hdr.name_end_found)); | ||
5056 | mhd_assert ((0 == c->rq.hdrs.hdr.value_start) || \ | ||
5057 | (c->rq.hdrs.hdr.name_len < c->rq.hdrs.hdr.value_start)); | ||
5058 | mhd_assert ((0 == c->rq.hdrs.hdr.value_start) || \ | ||
5059 | (0 != c->rq.hdrs.hdr.name_len)); | ||
5060 | mhd_assert ((0 == c->rq.hdrs.hdr.ws_start) || \ | ||
5061 | (0 == c->rq.hdrs.hdr.name_len) || \ | ||
5062 | (c->rq.hdrs.hdr.ws_start > c->rq.hdrs.hdr.name_len)); | ||
5063 | mhd_assert ((0 == c->rq.hdrs.hdr.ws_start) || \ | ||
5064 | (0 == c->rq.hdrs.hdr.value_start) || \ | ||
5065 | (c->rq.hdrs.hdr.ws_start > c->rq.hdrs.hdr.value_start)); | ||
5066 | |||
5067 | /* Check for the end of the line */ | ||
5068 | if ('\r' == chr) | ||
5069 | { | ||
5070 | if (0 != p) | ||
5071 | { | ||
5072 | /* Line is not empty, need to check for possible line folding */ | ||
5073 | if (p + 2 >= c->read_buffer_offset) | ||
5074 | break; /* Not enough data yet to check for folded line */ | ||
5075 | } | ||
5076 | else | ||
5077 | { | ||
5078 | /* Line is empty, no need to check for possible line folding */ | ||
5079 | if (p + 2 > c->read_buffer_offset) | ||
5080 | break; /* Not enough data yet to check for the end of the line */ | ||
5081 | } | ||
5082 | if ('\n' == c->read_buffer[p + 1]) | ||
5083 | end_of_line = true; | ||
5084 | else | ||
5085 | { | ||
5086 | /* Bare CR alone */ | ||
5087 | /* Must be rejected or replaced with space char. | ||
5088 | See RFC 9112, section 2.2-4 */ | ||
5089 | if (bare_cr_as_sp) | ||
5090 | { | ||
5091 | c->read_buffer[p] = ' '; | ||
5092 | c->rq.num_cr_sp_replaced++; | ||
5093 | continue; /* Re-start processing of the current character */ | ||
5094 | } | ||
5095 | else if (! bare_cr_keep) | ||
5096 | { | ||
5097 | transmit_error_response_static (c, | ||
5098 | MHD_HTTP_BAD_REQUEST, | ||
5099 | (! process_footers) ? | ||
5100 | BARE_CR_IN_HEADER : | ||
5101 | BARE_CR_IN_FOOTER); | ||
5102 | return MHD_HDR_LINE_READING_DATA_ERROR; /* Error in the request */ | ||
5103 | } | ||
5104 | end_of_line = false; | ||
5105 | } | ||
5106 | } | ||
5107 | else if ('\n' == chr) | ||
5108 | { | ||
5109 | /* Bare LF may be recognised as a line delimiter. | ||
5110 | See RFC 9112, section 2.2-3 */ | ||
5111 | if (bare_lf_as_crlf) | ||
5112 | { | ||
5113 | if (0 != p) | ||
5114 | { | ||
5115 | /* Line is not empty, need to check for possible line folding */ | ||
5116 | if (p + 1 >= c->read_buffer_offset) | ||
5117 | break; /* Not enough data yet to check for folded line */ | ||
5118 | } | ||
5119 | end_of_line = true; | ||
5120 | } | ||
5121 | else | ||
5122 | { | ||
5123 | transmit_error_response_static (c, | ||
5124 | MHD_HTTP_BAD_REQUEST, | ||
5125 | (! process_footers) ? | ||
5126 | BARE_LF_IN_HEADER : BARE_LF_IN_FOOTER); | ||
5127 | return MHD_HDR_LINE_READING_DATA_ERROR; /* Error in the request */ | ||
5128 | } | ||
5129 | } | ||
5130 | else | ||
5131 | end_of_line = false; | ||
5132 | |||
5133 | if (end_of_line) | ||
5134 | { | ||
5135 | /* Handle the end of the line */ | ||
5136 | /** | ||
5137 | * The full length of the line, including CRLF (or bare LF). | ||
5138 | */ | ||
5139 | const size_t line_len = p + (('\r' == chr) ? 2 : 1); | ||
5140 | char next_line_char; | ||
5141 | mhd_assert (line_len <= c->read_buffer_offset); | ||
5142 | |||
5143 | if (0 == p) | ||
5144 | { | ||
5145 | /* Zero-length header line. This is the end of the request header | ||
5146 | section. | ||
5147 | RFC 9112, Section 2.1-1 */ | ||
5148 | mhd_assert (! c->rq.hdrs.hdr.starts_with_ws); | ||
5149 | mhd_assert (! c->rq.hdrs.hdr.name_end_found); | ||
5150 | mhd_assert (0 == c->rq.hdrs.hdr.name_len); | ||
5151 | mhd_assert (0 == c->rq.hdrs.hdr.ws_start); | ||
5152 | mhd_assert (0 == c->rq.hdrs.hdr.value_start); | ||
5153 | /* Consume the line with CRLF (or bare LF) */ | ||
5154 | c->read_buffer += line_len; | ||
5155 | c->read_buffer_offset -= line_len; | ||
5156 | c->read_buffer_size -= line_len; | ||
5157 | return MHD_HDR_LINE_READING_GOT_END_OF_HEADER; | ||
5158 | } | ||
5159 | |||
5160 | mhd_assert (line_len < c->read_buffer_offset); | ||
5161 | mhd_assert (0 != line_len); | ||
5162 | mhd_assert ('\n' == c->read_buffer[line_len - 1]); | ||
5163 | next_line_char = c->read_buffer[line_len]; | ||
5164 | if ((' ' == next_line_char) || | ||
5165 | ('\t' == next_line_char)) | ||
5166 | { | ||
5167 | /* Folded line */ | ||
5168 | if (! allow_folded) | ||
5169 | { | ||
5170 | transmit_error_response_static (c, | ||
5171 | MHD_HTTP_BAD_REQUEST, | ||
5172 | (! process_footers) ? | ||
5173 | ERR_RSP_OBS_FOLD : | ||
5174 | ERR_RSP_OBS_FOLD_FOOTER); | ||
5175 | return MHD_HDR_LINE_READING_DATA_ERROR; /* Error in the request */ | ||
5176 | } | ||
5177 | /* Replace CRLF (or bare LF) character(s) with space characters. | ||
5178 | See RFC 9112, Section 5.2-4 */ | ||
5179 | c->read_buffer[p] = ' '; | ||
5180 | if ('\r' == chr) | ||
5181 | c->read_buffer[p + 1] = ' '; | ||
5182 | continue; /* Re-start processing of the current character */ | ||
5183 | } | ||
5184 | else | ||
5185 | { | ||
5186 | /* It is not a folded line, it's the real end of the non-empty line */ | ||
5187 | bool skip_line = false; | ||
5188 | mhd_assert (0 != p); | ||
5189 | if (c->rq.hdrs.hdr.starts_with_ws) | ||
5190 | { | ||
5191 | /* This is the first line and it starts with whitespace. This line | ||
5192 | must be discarded completely. | ||
5193 | See RFC 9112, Section 2.2-8 */ | ||
5194 | mhd_assert (allow_wsp_at_start); | ||
5195 | #ifdef HAVE_MESSAGES | ||
5196 | MHD_DLOG (c->daemon, | ||
5197 | _ ("Whitespace-prefixed first header line " \ | ||
5198 | "has been skipped.\n")); | ||
5199 | #endif /* HAVE_MESSAGES */ | ||
5200 | skip_line = true; | ||
5201 | } | ||
5202 | else if (! c->rq.hdrs.hdr.name_end_found) | ||
5203 | { | ||
5204 | if (! allow_line_without_colon) | ||
5205 | { | ||
5206 | transmit_error_response_static (c, | ||
5207 | MHD_HTTP_BAD_REQUEST, | ||
5208 | (! process_footers) ? | ||
5209 | ERR_RSP_HEADER_WITHOUT_COLON : | ||
5210 | ERR_RSP_FOOTER_WITHOUT_COLON); | ||
5211 | return MHD_HDR_LINE_READING_DATA_ERROR; /* Error in the request */ | ||
5212 | } | ||
5213 | /* Skip broken line completely */ | ||
5214 | c->rq.skipped_broken_lines++; | ||
5215 | skip_line = true; | ||
5216 | } | ||
5217 | if (skip_line) | ||
5218 | { | ||
5219 | /* Skip the entire line */ | ||
5220 | c->read_buffer += line_len; | ||
5221 | c->read_buffer_offset -= line_len; | ||
5222 | c->read_buffer_size -= line_len; | ||
5223 | p = 0; | ||
5224 | /* Reset processing state */ | ||
5225 | memset (&c->rq.hdrs.hdr, 0, sizeof(c->rq.hdrs.hdr)); | ||
5226 | /* Start processing of the next line */ | ||
5227 | continue; | ||
5228 | } | ||
5229 | else | ||
5230 | { | ||
5231 | /* This line should be valid header line */ | ||
5232 | size_t value_len; | ||
5233 | mhd_assert ((0 != c->rq.hdrs.hdr.name_len) || allow_empty_name); | ||
5234 | |||
5235 | hdr_name->str = c->read_buffer + 0; /* The name always starts at the first character */ | ||
5236 | hdr_name->len = c->rq.hdrs.hdr.name_len; | ||
5237 | mhd_assert (0 == hdr_name->str[hdr_name->len]); | ||
5238 | |||
5239 | if (0 == c->rq.hdrs.hdr.value_start) | ||
5240 | { | ||
5241 | c->rq.hdrs.hdr.value_start = p; | ||
5242 | c->read_buffer[p] = 0; | ||
5243 | value_len = 0; | ||
5244 | } | ||
5245 | else if (0 != c->rq.hdrs.hdr.ws_start) | ||
5246 | { | ||
5247 | mhd_assert (p > c->rq.hdrs.hdr.ws_start); | ||
5248 | mhd_assert (c->rq.hdrs.hdr.ws_start > c->rq.hdrs.hdr.value_start); | ||
5249 | c->read_buffer[c->rq.hdrs.hdr.ws_start] = 0; | ||
5250 | value_len = c->rq.hdrs.hdr.ws_start - c->rq.hdrs.hdr.value_start; | ||
5251 | } | ||
5252 | else | ||
5253 | { | ||
5254 | mhd_assert (p > c->rq.hdrs.hdr.ws_start); | ||
5255 | c->read_buffer[p] = 0; | ||
5256 | value_len = p - c->rq.hdrs.hdr.value_start; | ||
5257 | } | ||
5258 | hdr_value->str = c->read_buffer + c->rq.hdrs.hdr.value_start; | ||
5259 | hdr_value->len = value_len; | ||
5260 | mhd_assert (0 == hdr_value->str[hdr_value->len]); | ||
5261 | /* Consume the entire line */ | ||
5262 | c->read_buffer += line_len; | ||
5263 | c->read_buffer_offset -= line_len; | ||
5264 | c->read_buffer_size -= line_len; | ||
5265 | return MHD_HDR_LINE_READING_GOT_HEADER; | ||
5266 | } | ||
5267 | } | ||
5268 | } | ||
5269 | else if ((' ' == chr) || ('\t' == chr)) | ||
5270 | { | ||
5271 | if (0 == p) | ||
5272 | { | ||
5273 | if (! allow_wsp_at_start) | ||
5274 | { | ||
5275 | transmit_error_response_static (c, | ||
5276 | MHD_HTTP_BAD_REQUEST, | ||
5277 | (! process_footers) ? | ||
5278 | ERR_RSP_WSP_BEFORE_HEADER : | ||
5279 | ERR_RSP_WSP_BEFORE_FOOTER); | ||
5280 | return MHD_HDR_LINE_READING_DATA_ERROR; /* Error in the request */ | ||
5281 | } | ||
5282 | c->rq.hdrs.hdr.starts_with_ws = true; | ||
5283 | } | ||
5284 | else if ((! c->rq.hdrs.hdr.name_end_found) && | ||
5285 | (! c->rq.hdrs.hdr.starts_with_ws)) | ||
5286 | { | ||
5287 | /* Whitespace in header name / between header name and colon */ | ||
5288 | if (allow_wsp_in_name || allow_wsp_before_colon) | ||
5289 | { | ||
5290 | if (0 == c->rq.hdrs.hdr.ws_start) | ||
5291 | c->rq.hdrs.hdr.ws_start = p; | ||
5292 | } | ||
5293 | else | ||
5294 | { | ||
5295 | transmit_error_response_static (c, | ||
5296 | MHD_HTTP_BAD_REQUEST, | ||
5297 | (! process_footers) ? | ||
5298 | ERR_RSP_WSP_IN_HEADER_NAME : | ||
5299 | ERR_RSP_WSP_IN_FOOTER_NAME); | ||
5300 | return MHD_HDR_LINE_READING_DATA_ERROR; /* Error in the request */ | ||
5301 | } | ||
5302 | } | ||
5303 | else | ||
5304 | { | ||
5305 | /* Whitespace before/inside/after header (field) value */ | ||
5306 | if (0 == c->rq.hdrs.hdr.ws_start) | ||
5307 | c->rq.hdrs.hdr.ws_start = p; | ||
5308 | } | ||
5309 | } | ||
5310 | else if (0 == chr) | ||
5311 | { | ||
5312 | if (! nul_as_sp) | ||
5313 | { | ||
5314 | transmit_error_response_static (c, | ||
5315 | MHD_HTTP_BAD_REQUEST, | ||
5316 | (! process_footers) ? | ||
5317 | ERR_RSP_INVALID_CHR_IN_HEADER : | ||
5318 | ERR_RSP_INVALID_CHR_IN_FOOTER); | ||
5319 | return MHD_HDR_LINE_READING_DATA_ERROR; /* Error in the request */ | ||
5320 | } | ||
5321 | c->read_buffer[p] = ' '; | ||
5322 | continue; /* Re-start processing of the current character */ | ||
5323 | } | ||
5324 | else | ||
5325 | { | ||
5326 | /* Not a whitespace, not the end of the header line */ | ||
5327 | mhd_assert ('\r' != chr); | ||
5328 | mhd_assert ('\n' != chr); | ||
5329 | mhd_assert ('\0' != chr); | ||
5330 | if ((! c->rq.hdrs.hdr.name_end_found) && | ||
5331 | (! c->rq.hdrs.hdr.starts_with_ws)) | ||
5332 | { | ||
5333 | /* Processing the header (field) name */ | ||
5334 | if (':' == chr) | ||
5335 | { | ||
5336 | if (0 == c->rq.hdrs.hdr.ws_start) | ||
5337 | c->rq.hdrs.hdr.name_len = p; | ||
5338 | else | ||
5339 | { | ||
5340 | mhd_assert (allow_wsp_in_name || allow_wsp_before_colon); | ||
5341 | if (! allow_wsp_before_colon) | ||
5342 | { | ||
5343 | transmit_error_response_static (c, | ||
5344 | MHD_HTTP_BAD_REQUEST, | ||
5345 | (! process_footers) ? | ||
5346 | ERR_RSP_WSP_IN_HEADER_NAME : | ||
5347 | ERR_RSP_WSP_IN_FOOTER_NAME); | ||
5348 | return MHD_HDR_LINE_READING_DATA_ERROR; /* Error in the request */ | ||
5349 | } | ||
5350 | c->rq.hdrs.hdr.name_len = c->rq.hdrs.hdr.ws_start; | ||
5351 | #ifndef MHD_FAVOR_SMALL_CODE | ||
5352 | c->rq.hdrs.hdr.ws_start = 0; /* Not on whitespace anymore */ | ||
5353 | #endif /* ! MHD_FAVOR_SMALL_CODE */ | ||
5354 | } | ||
5355 | if ((0 == c->rq.hdrs.hdr.name_len) && ! allow_empty_name) | ||
5356 | { | ||
5357 | transmit_error_response_static (c, | ||
5358 | MHD_HTTP_BAD_REQUEST, | ||
5359 | (! process_footers) ? | ||
5360 | ERR_RSP_EMPTY_HEADER_NAME : | ||
5361 | ERR_RSP_EMPTY_FOOTER_NAME); | ||
5362 | return MHD_HDR_LINE_READING_DATA_ERROR; /* Error in the request */ | ||
5363 | } | ||
5364 | c->rq.hdrs.hdr.name_end_found = true; | ||
5365 | c->read_buffer[c->rq.hdrs.hdr.name_len] = 0; /* Zero-terminate the name */ | ||
5366 | } | ||
5367 | else | ||
5368 | { | ||
5369 | if (0 != c->rq.hdrs.hdr.ws_start) | ||
5370 | { | ||
5371 | /* End of the whitespace in header (field) name */ | ||
5372 | mhd_assert (allow_wsp_in_name || allow_wsp_before_colon); | ||
5373 | if (! allow_wsp_in_name) | ||
5374 | { | ||
5375 | transmit_error_response_static (c, | ||
5376 | MHD_HTTP_BAD_REQUEST, | ||
5377 | (! process_footers) ? | ||
5378 | ERR_RSP_WSP_IN_HEADER_NAME : | ||
5379 | ERR_RSP_WSP_IN_FOOTER_NAME); | ||
5380 | return MHD_HDR_LINE_READING_DATA_ERROR; /* Error in the request */ | ||
5381 | } | ||
5382 | #ifndef MHD_FAVOR_SMALL_CODE | ||
5383 | c->rq.hdrs.hdr.ws_start = 0; /* Not on whitespace anymore */ | ||
5384 | #endif /* ! MHD_FAVOR_SMALL_CODE */ | ||
5385 | } | ||
5386 | } | ||
5387 | } | ||
5388 | else | ||
5389 | { | ||
5390 | /* Processing the header (field) value */ | ||
5391 | if (0 == c->rq.hdrs.hdr.value_start) | ||
5392 | c->rq.hdrs.hdr.value_start = p; | ||
5393 | #ifndef MHD_FAVOR_SMALL_CODE | ||
5394 | c->rq.hdrs.hdr.ws_start = 0; /* Not on whitespace anymore */ | ||
5395 | #endif /* ! MHD_FAVOR_SMALL_CODE */ | ||
5396 | } | ||
5397 | #ifdef MHD_FAVOR_SMALL_CODE | ||
5398 | c->rq.hdrs.hdr.ws_start = 0; /* Not on whitespace anymore */ | ||
5399 | #endif /* MHD_FAVOR_SMALL_CODE */ | ||
5400 | } | ||
5401 | p++; | ||
5402 | } | ||
5403 | c->rq.hdrs.hdr.proc_pos = p; | ||
5404 | return MHD_HDR_LINE_READING_NEED_MORE_DATA; /* Not enough data yet */ | ||
5405 | } | ||
5406 | |||
5407 | |||
5408 | /** | ||
5409 | * Find the end of the request headers and make basic header parsing. | ||
5410 | * Advance to the next state when done, handle errors. | ||
5411 | * @param c the connection to process | ||
5412 | * @param process_footers if true then footers are processed, | ||
5413 | * if false then headers are processed | ||
5414 | * @return true if request headers reading finished (either successfully | ||
5415 | * or with error), | ||
5416 | * false if not enough data yet in the receive buffer | ||
5417 | */ | ||
5418 | static bool | ||
5419 | get_req_headers (struct MHD_Connection *c, bool process_footers) | ||
5420 | { | ||
5421 | do | ||
5422 | { | ||
5423 | struct _MHD_str_w_len hdr_name; | ||
5424 | struct _MHD_str_w_len hdr_value; | ||
5425 | enum MHD_HdrLineReadRes_ res; | ||
5426 | |||
5427 | mhd_assert ((process_footers ? MHD_CONNECTION_FOOTERS_RECEIVING : \ | ||
5428 | MHD_CONNECTION_REQ_HEADERS_RECEIVING) == \ | ||
5429 | c->state); | ||
5430 | |||
5431 | #ifdef _DEBUG | ||
5432 | hdr_name.str = NULL; | ||
5433 | hdr_value.str = NULL; | ||
5434 | #endif /* _DEBUG */ | ||
5435 | res = get_req_header (c, process_footers, &hdr_name, &hdr_value); | ||
5436 | if (MHD_HDR_LINE_READING_GOT_HEADER == res) | ||
5437 | { | ||
5438 | mhd_assert ((process_footers ? MHD_CONNECTION_FOOTERS_RECEIVING : \ | ||
5439 | MHD_CONNECTION_REQ_HEADERS_RECEIVING) == \ | ||
5440 | c->state); | ||
5441 | mhd_assert (NULL != hdr_name.str); | ||
5442 | mhd_assert (NULL != hdr_value.str); | ||
5443 | /* Values must be zero-terminated and must not have binary zeros */ | ||
5444 | mhd_assert (strlen (hdr_name.str) == hdr_name.len); | ||
5445 | mhd_assert (strlen (hdr_value.str) == hdr_value.len); | ||
5446 | /* Values must not have whitespaces at the start or at the end */ | ||
5447 | mhd_assert ((hdr_name.len == 0) || (hdr_name.str[0] != ' ')); | ||
5448 | mhd_assert ((hdr_name.len == 0) || (hdr_name.str[0] != '\t')); | ||
5449 | mhd_assert ((hdr_name.len == 0) || \ | ||
5450 | (hdr_name.str[hdr_name.len - 1] != ' ')); | ||
5451 | mhd_assert ((hdr_name.len == 0) || \ | ||
5452 | (hdr_name.str[hdr_name.len - 1] != '\t')); | ||
5453 | mhd_assert ((hdr_value.len == 0) || (hdr_value.str[0] != ' ')); | ||
5454 | mhd_assert ((hdr_value.len == 0) || (hdr_value.str[0] != '\t')); | ||
5455 | mhd_assert ((hdr_value.len == 0) || \ | ||
5456 | (hdr_value.str[hdr_value.len - 1] != ' ')); | ||
5457 | mhd_assert ((hdr_value.len == 0) || \ | ||
5458 | (hdr_value.str[hdr_value.len - 1] != '\t')); | ||
5459 | |||
5460 | if (MHD_NO == | ||
5461 | MHD_set_connection_value_n_nocheck_ (c, | ||
5462 | (! process_footers) ? | ||
5463 | MHD_HEADER_KIND : | ||
5464 | MHD_FOOTER_KIND, | ||
5465 | hdr_name.str, hdr_name.len, | ||
5466 | hdr_value.str, hdr_value.len)) | ||
5467 | { | ||
5468 | /** | ||
5469 | * If 'true' then "headers too large" is used for the error response, | ||
5470 | * if 'false' then "URI too large is used for the error response. | ||
5471 | */ | ||
5472 | bool headers_large_err; | ||
5473 | #ifdef HAVE_MESSAGES | ||
5474 | MHD_DLOG (c->daemon, | ||
5475 | _ ("Failed to allocate memory in the connection memory " \ | ||
5476 | "pool to store %s.\n"), | ||
5477 | (! process_footers) ? _ ("header") : _ ("footer")); | ||
5478 | #endif /* HAVE_MESSAGES */ | ||
5479 | |||
5480 | if (! process_footers) | ||
5481 | { | ||
5482 | size_t http_headers_size; | ||
5483 | size_t url_size; | ||
5484 | const struct MHD_HTTP_Req_Header *hdr; | ||
5485 | |||
5486 | http_headers_size = hdr_name.len + hdr_value.len; | ||
5487 | url_size = c->rq.url_len; | ||
5488 | for (hdr = c->rq.headers_received; NULL != hdr; hdr = hdr->next) | ||
5489 | { | ||
5490 | if (MHD_HEADER_KIND == hdr->kind) | ||
5491 | http_headers_size += hdr->header_size + hdr->value_size + 2; | ||
5492 | else if (MHD_GET_ARGUMENT_KIND == hdr->kind) | ||
5493 | url_size += hdr->header_size + hdr->value_size + 2; | ||
5494 | } | ||
5495 | /* The comparison is not precise as linefeeds (for headers) and | ||
5496 | unescaping (for GET parameters) are not taken into account, | ||
5497 | but precision is not required here. */ | ||
5498 | headers_large_err = | ||
5499 | (http_headers_size >= url_size); | ||
5500 | } | ||
5501 | else | ||
5502 | headers_large_err = true; | ||
5503 | |||
5504 | transmit_error_response_static (c, | ||
5505 | headers_large_err ? | ||
5506 | MHD_HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE | ||
5507 | : MHD_HTTP_URI_TOO_LONG, | ||
5508 | REQUEST_TOO_BIG); | ||
5509 | mhd_assert (MHD_CONNECTION_FULL_REQ_RECEIVED < c->state); | ||
5510 | return true; | ||
5511 | } | ||
5512 | /* Reset processing state */ | ||
5513 | reset_rq_header_processing_state (c); | ||
5514 | mhd_assert ((process_footers ? MHD_CONNECTION_FOOTERS_RECEIVING : \ | ||
5515 | MHD_CONNECTION_REQ_HEADERS_RECEIVING) == \ | ||
5516 | c->state); | ||
5517 | /* Read the next header (field) line */ | ||
5518 | continue; | ||
5519 | } | ||
5520 | else if (MHD_HDR_LINE_READING_NEED_MORE_DATA == res) | ||
5521 | { | ||
5522 | mhd_assert ((process_footers ? MHD_CONNECTION_FOOTERS_RECEIVING : \ | ||
5523 | MHD_CONNECTION_REQ_HEADERS_RECEIVING) == \ | ||
5524 | c->state); | ||
5525 | return false; | ||
5526 | } | ||
5527 | else if (MHD_HDR_LINE_READING_DATA_ERROR == res) | ||
5528 | { | ||
5529 | mhd_assert ((process_footers ? \ | ||
5530 | MHD_CONNECTION_FOOTERS_RECEIVING : \ | ||
5531 | MHD_CONNECTION_REQ_HEADERS_RECEIVING) < c->state); | ||
5532 | mhd_assert (c->stop_with_error); | ||
5533 | mhd_assert (c->discard_request); | ||
5534 | return true; | ||
5535 | } | ||
5536 | mhd_assert (MHD_HDR_LINE_READING_GOT_END_OF_HEADER == res); | ||
5537 | break; | ||
5538 | } while (1); | ||
5539 | |||
4736 | #ifdef HAVE_MESSAGES | 5540 | #ifdef HAVE_MESSAGES |
4737 | if (1 == c->rq.num_cr_sp_replaced) | 5541 | if (1 == c->rq.num_cr_sp_replaced) |
4738 | { | 5542 | { |
4739 | MHD_DLOG (c->daemon, | 5543 | MHD_DLOG (c->daemon, |
4740 | _ ("One bare CR character has been replaced with space " \ | 5544 | _ ("One bare CR character has been replaced with space " \ |
4741 | "in the request line.\n")); | 5545 | "in %s.\n"), |
5546 | (! process_footers) ? | ||
5547 | _ ("the request line or in the request headers") : | ||
5548 | _ ("the request footers")); | ||
4742 | } | 5549 | } |
4743 | else if (0 != c->rq.num_cr_sp_replaced) | 5550 | else if (0 != c->rq.num_cr_sp_replaced) |
4744 | { | 5551 | { |
4745 | MHD_DLOG (c->daemon, | 5552 | MHD_DLOG (c->daemon, |
4746 | _ ("%" PRIu64 " bare CR characters have been replaced with " \ | 5553 | _ ("%" PRIu64 " bare CR characters have been replaced with " \ |
4747 | "spaces in the request line.\n"), | 5554 | "spaces in the request line and/or in the request %s.\n"), |
4748 | (uint64_t) c->rq.num_cr_sp_replaced); | 5555 | (uint64_t) c->rq.num_cr_sp_replaced, |
5556 | (! process_footers) ? _ ("headers") : _ ("footers")); | ||
5557 | } | ||
5558 | if (1 == c->rq.skipped_broken_lines) | ||
5559 | { | ||
5560 | MHD_DLOG (c->daemon, | ||
5561 | _ ("One %s line without colon has been skipped.\n"), | ||
5562 | (! process_footers) ? _ ("header") : _ ("footer")); | ||
5563 | } | ||
5564 | else if (0 != c->rq.skipped_broken_lines) | ||
5565 | { | ||
5566 | MHD_DLOG (c->daemon, | ||
5567 | _ ("%" PRIu64 " %s lines without colons has been skipped.\n"), | ||
5568 | (uint64_t) c->rq.skipped_broken_lines, | ||
5569 | (! process_footers) ? _ ("header") : _ ("footer")); | ||
4749 | } | 5570 | } |
4750 | #endif /* HAVE_MESSAGES */ | 5571 | #endif /* HAVE_MESSAGES */ |
4751 | if (! process_request_target (c)) | ||
4752 | return true; /* Error in processing */ | ||
4753 | 5572 | ||
4754 | memset (&c->rq.hdrs.hdr, 0, sizeof(c->rq.hdrs.hdr)); | 5573 | mhd_assert (c->rq.method < c->read_buffer); |
4755 | c->state = MHD_CONNECTION_REQ_LINE_RECEIVED; | 5574 | if (! process_footers) |
5575 | { | ||
5576 | c->rq.header_size = (size_t) (c->read_buffer - c->rq.method); | ||
5577 | c->state = MHD_CONNECTION_HEADERS_RECEIVED; | ||
5578 | } | ||
5579 | else | ||
5580 | c->state = MHD_CONNECTION_FOOTERS_RECEIVED; | ||
4756 | return true; | 5581 | return true; |
4757 | } | 5582 | } |
4758 | 5583 | ||
@@ -4920,15 +5745,9 @@ MHD_connection_handle_read (struct MHD_Connection *connection, | |||
4920 | { | 5745 | { |
4921 | case MHD_CONNECTION_INIT: | 5746 | case MHD_CONNECTION_INIT: |
4922 | case MHD_CONNECTION_REQ_LINE_RECEIVING: | 5747 | case MHD_CONNECTION_REQ_LINE_RECEIVING: |
4923 | case MHD_CONNECTION_REQ_LINE_RECEIVED: | 5748 | case MHD_CONNECTION_REQ_HEADERS_RECEIVING: |
4924 | case MHD_CONNECTION_HEADER_PART_RECEIVED: | ||
4925 | case MHD_CONNECTION_HEADERS_RECEIVED: | ||
4926 | case MHD_CONNECTION_HEADERS_PROCESSED: | ||
4927 | case MHD_CONNECTION_CONTINUE_SENDING: | ||
4928 | case MHD_CONNECTION_BODY_RECEIVING: | 5749 | case MHD_CONNECTION_BODY_RECEIVING: |
4929 | case MHD_CONNECTION_BODY_RECEIVED: | 5750 | case MHD_CONNECTION_FOOTERS_RECEIVING: |
4930 | case MHD_CONNECTION_FOOTER_PART_RECEIVED: | ||
4931 | case MHD_CONNECTION_FOOTERS_RECEIVED: | ||
4932 | case MHD_CONNECTION_FULL_REQ_RECEIVED: | 5751 | case MHD_CONNECTION_FULL_REQ_RECEIVED: |
4933 | /* nothing to do but default action */ | 5752 | /* nothing to do but default action */ |
4934 | if (connection->read_closed) | 5753 | if (connection->read_closed) |
@@ -4960,6 +5779,15 @@ MHD_connection_handle_read (struct MHD_Connection *connection, | |||
4960 | connection->read_buffer_size = connection->read_buffer_offset; | 5779 | connection->read_buffer_size = connection->read_buffer_offset; |
4961 | } | 5780 | } |
4962 | break; | 5781 | break; |
5782 | case MHD_CONNECTION_REQ_LINE_RECEIVED: | ||
5783 | case MHD_CONNECTION_HEADERS_RECEIVED: | ||
5784 | case MHD_CONNECTION_HEADERS_PROCESSED: | ||
5785 | case MHD_CONNECTION_BODY_RECEIVED: | ||
5786 | case MHD_CONNECTION_FOOTERS_RECEIVED: | ||
5787 | /* Milestone state, no data should be read */ | ||
5788 | mhd_assert (0); /* Should not be possible */ | ||
5789 | break; | ||
5790 | case MHD_CONNECTION_CONTINUE_SENDING: | ||
4963 | case MHD_CONNECTION_HEADERS_SENDING: | 5791 | case MHD_CONNECTION_HEADERS_SENDING: |
4964 | case MHD_CONNECTION_HEADERS_SENT: | 5792 | case MHD_CONNECTION_HEADERS_SENT: |
4965 | case MHD_CONNECTION_NORMAL_BODY_UNREADY: | 5793 | case MHD_CONNECTION_NORMAL_BODY_UNREADY: |
@@ -4971,6 +5799,7 @@ MHD_connection_handle_read (struct MHD_Connection *connection, | |||
4971 | case MHD_CONNECTION_FULL_REPLY_SENT: | 5799 | case MHD_CONNECTION_FULL_REPLY_SENT: |
4972 | default: | 5800 | default: |
4973 | mhd_assert (0); /* Should not be possible */ | 5801 | mhd_assert (0); /* Should not be possible */ |
5802 | break; | ||
4974 | } | 5803 | } |
4975 | return; | 5804 | return; |
4976 | } | 5805 | } |
@@ -5014,11 +5843,10 @@ MHD_connection_handle_write (struct MHD_Connection *connection) | |||
5014 | case MHD_CONNECTION_INIT: | 5843 | case MHD_CONNECTION_INIT: |
5015 | case MHD_CONNECTION_REQ_LINE_RECEIVING: | 5844 | case MHD_CONNECTION_REQ_LINE_RECEIVING: |
5016 | case MHD_CONNECTION_REQ_LINE_RECEIVED: | 5845 | case MHD_CONNECTION_REQ_LINE_RECEIVED: |
5017 | case MHD_CONNECTION_HEADER_PART_RECEIVED: | 5846 | case MHD_CONNECTION_REQ_HEADERS_RECEIVING: |
5018 | case MHD_CONNECTION_HEADERS_RECEIVED: | 5847 | case MHD_CONNECTION_HEADERS_RECEIVED: |
5019 | mhd_assert (0); | ||
5020 | return; | ||
5021 | case MHD_CONNECTION_HEADERS_PROCESSED: | 5848 | case MHD_CONNECTION_HEADERS_PROCESSED: |
5849 | mhd_assert (0); | ||
5022 | return; | 5850 | return; |
5023 | case MHD_CONNECTION_CONTINUE_SENDING: | 5851 | case MHD_CONNECTION_CONTINUE_SENDING: |
5024 | ret = MHD_send_data_ (connection, | 5852 | ret = MHD_send_data_ (connection, |
@@ -5051,9 +5879,11 @@ MHD_connection_handle_write (struct MHD_Connection *connection) | |||
5051 | return; | 5879 | return; |
5052 | case MHD_CONNECTION_BODY_RECEIVING: | 5880 | case MHD_CONNECTION_BODY_RECEIVING: |
5053 | case MHD_CONNECTION_BODY_RECEIVED: | 5881 | case MHD_CONNECTION_BODY_RECEIVED: |
5054 | case MHD_CONNECTION_FOOTER_PART_RECEIVED: | 5882 | case MHD_CONNECTION_FOOTERS_RECEIVING: |
5055 | case MHD_CONNECTION_FOOTERS_RECEIVED: | 5883 | case MHD_CONNECTION_FOOTERS_RECEIVED: |
5056 | case MHD_CONNECTION_FULL_REQ_RECEIVED: | 5884 | case MHD_CONNECTION_FULL_REQ_RECEIVED: |
5885 | mhd_assert (0); | ||
5886 | return; | ||
5057 | case MHD_CONNECTION_START_REPLY: | 5887 | case MHD_CONNECTION_START_REPLY: |
5058 | mhd_assert (0); | 5888 | mhd_assert (0); |
5059 | return; | 5889 | return; |
@@ -5579,67 +6409,19 @@ MHD_connection_handle_idle (struct MHD_Connection *connection) | |||
5579 | mhd_assert (MHD_CONNECTION_REQ_LINE_RECEIVING >= connection->state); | 6409 | mhd_assert (MHD_CONNECTION_REQ_LINE_RECEIVING >= connection->state); |
5580 | break; | 6410 | break; |
5581 | case MHD_CONNECTION_REQ_LINE_RECEIVED: | 6411 | case MHD_CONNECTION_REQ_LINE_RECEIVED: |
5582 | line = get_next_header_line (connection, | 6412 | reset_rq_header_processing_state (connection); |
5583 | NULL); | 6413 | connection->state = MHD_CONNECTION_REQ_HEADERS_RECEIVING; |
5584 | if (MHD_CONNECTION_REQ_LINE_RECEIVED != connection->state) | ||
5585 | continue; | ||
5586 | if (NULL == line) | ||
5587 | { | ||
5588 | if (connection->read_closed) | ||
5589 | { | ||
5590 | CONNECTION_CLOSE_ERROR (connection, | ||
5591 | NULL); | ||
5592 | continue; | ||
5593 | } | ||
5594 | break; | ||
5595 | } | ||
5596 | if (0 == line[0]) | ||
5597 | { | ||
5598 | connection->state = MHD_CONNECTION_HEADERS_RECEIVED; | ||
5599 | connection->rq.header_size = (size_t) (connection->read_buffer | ||
5600 | - connection->rq.method); | ||
5601 | continue; | ||
5602 | } | ||
5603 | if (MHD_NO == process_header_line (connection, | ||
5604 | line)) | ||
5605 | { | ||
5606 | transmit_error_response_static (connection, | ||
5607 | MHD_HTTP_BAD_REQUEST, | ||
5608 | REQUEST_MALFORMED); | ||
5609 | break; | ||
5610 | } | ||
5611 | connection->state = MHD_CONNECTION_HEADER_PART_RECEIVED; | ||
5612 | continue; | 6414 | continue; |
5613 | case MHD_CONNECTION_HEADER_PART_RECEIVED: | 6415 | case MHD_CONNECTION_REQ_HEADERS_RECEIVING: |
5614 | line = get_next_header_line (connection, | 6416 | if (get_req_headers (connection, false)) |
5615 | NULL); | ||
5616 | if (MHD_CONNECTION_HEADER_PART_RECEIVED != connection->state) | ||
5617 | continue; | ||
5618 | if (NULL == line) | ||
5619 | { | 6417 | { |
5620 | if (connection->state != MHD_CONNECTION_HEADER_PART_RECEIVED) | 6418 | mhd_assert (MHD_CONNECTION_REQ_HEADERS_RECEIVING < connection->state); |
5621 | continue; | 6419 | mhd_assert ((MHD_CONNECTION_HEADERS_RECEIVED == connection->state) || \ |
5622 | if (connection->read_closed) | 6420 | (connection->discard_request)); |
5623 | { | ||
5624 | CONNECTION_CLOSE_ERROR (connection, | ||
5625 | NULL); | ||
5626 | continue; | ||
5627 | } | ||
5628 | break; | ||
5629 | } | ||
5630 | if (MHD_NO == | ||
5631 | process_broken_line (connection, | ||
5632 | line, | ||
5633 | MHD_HEADER_KIND)) | ||
5634 | continue; | ||
5635 | if (0 == line[0]) | ||
5636 | { | ||
5637 | connection->state = MHD_CONNECTION_HEADERS_RECEIVED; | ||
5638 | connection->rq.header_size = (size_t) (connection->read_buffer | ||
5639 | - connection->rq.method); | ||
5640 | continue; | 6421 | continue; |
5641 | } | 6422 | } |
5642 | continue; | 6423 | mhd_assert (MHD_CONNECTION_REQ_HEADERS_RECEIVING == connection->state); |
6424 | break; | ||
5643 | case MHD_CONNECTION_HEADERS_RECEIVED: | 6425 | case MHD_CONNECTION_HEADERS_RECEIVED: |
5644 | parse_connection_headers (connection); | 6426 | parse_connection_headers (connection); |
5645 | if (MHD_CONNECTION_HEADERS_RECEIVED != connection->state) | 6427 | if (MHD_CONNECTION_HEADERS_RECEIVED != connection->state) |
@@ -5696,81 +6478,44 @@ MHD_connection_handle_idle (struct MHD_Connection *connection) | |||
5696 | if (MHD_CONNECTION_BODY_RECEIVING != connection->state) | 6478 | if (MHD_CONNECTION_BODY_RECEIVING != connection->state) |
5697 | continue; | 6479 | continue; |
5698 | } | 6480 | } |
5699 | /* Modify here when response queue during data processing | 6481 | /* Modify here when queueing of the response during data processing |
5700 | will be supported */ | 6482 | will be supported */ |
5701 | mhd_assert (! connection->discard_request); | 6483 | mhd_assert (! connection->discard_request); |
5702 | mhd_assert (NULL == connection->rp.response); | 6484 | mhd_assert (NULL == connection->rp.response); |
5703 | if (0 == connection->rq.remaining_upload_size) | 6485 | if (0 == connection->rq.remaining_upload_size) |
5704 | { | 6486 | { |
5705 | if (connection->rq.have_chunked_upload) | 6487 | connection->state = MHD_CONNECTION_BODY_RECEIVED; |
5706 | connection->state = MHD_CONNECTION_BODY_RECEIVED; | ||
5707 | else | ||
5708 | connection->state = MHD_CONNECTION_FULL_REQ_RECEIVED; | ||
5709 | continue; | 6488 | continue; |
5710 | } | 6489 | } |
5711 | break; | 6490 | break; |
5712 | case MHD_CONNECTION_BODY_RECEIVED: | 6491 | case MHD_CONNECTION_BODY_RECEIVED: |
5713 | line = get_next_header_line (connection, | 6492 | mhd_assert (! connection->discard_request); |
5714 | NULL); | 6493 | mhd_assert (NULL == connection->rp.response); |
5715 | if (connection->state != MHD_CONNECTION_BODY_RECEIVED) | 6494 | if (0 == connection->rq.remaining_upload_size) |
5716 | continue; | ||
5717 | if (NULL == line) | ||
5718 | { | 6495 | { |
5719 | if (connection->read_closed) | 6496 | if (connection->rq.have_chunked_upload) |
5720 | { | 6497 | { |
5721 | CONNECTION_CLOSE_ERROR (connection, | 6498 | /* Reset counter variables reused for footers */ |
5722 | NULL); | 6499 | connection->rq.num_cr_sp_replaced = 0; |
5723 | continue; | 6500 | connection->rq.skipped_broken_lines = 0; |
6501 | reset_rq_header_processing_state (connection); | ||
6502 | connection->state = MHD_CONNECTION_FOOTERS_RECEIVING; | ||
5724 | } | 6503 | } |
5725 | if (0 < connection->read_buffer_offset) | 6504 | else |
5726 | connection->state = MHD_CONNECTION_FOOTER_PART_RECEIVED; | 6505 | connection->state = MHD_CONNECTION_FULL_REQ_RECEIVED; |
5727 | break; | ||
5728 | } | ||
5729 | if (0 == line[0]) | ||
5730 | { | ||
5731 | connection->state = MHD_CONNECTION_FOOTERS_RECEIVED; | ||
5732 | if (connection->suspended) | ||
5733 | break; | ||
5734 | continue; | ||
5735 | } | ||
5736 | if (MHD_NO == process_header_line (connection, | ||
5737 | line)) | ||
5738 | { | ||
5739 | transmit_error_response_static (connection, | ||
5740 | MHD_HTTP_BAD_REQUEST, | ||
5741 | REQUEST_MALFORMED); | ||
5742 | break; | ||
5743 | } | ||
5744 | connection->state = MHD_CONNECTION_FOOTER_PART_RECEIVED; | ||
5745 | continue; | ||
5746 | case MHD_CONNECTION_FOOTER_PART_RECEIVED: | ||
5747 | line = get_next_header_line (connection, | ||
5748 | NULL); | ||
5749 | if (connection->state != MHD_CONNECTION_FOOTER_PART_RECEIVED) | ||
5750 | continue; | 6506 | continue; |
5751 | if (NULL == line) | ||
5752 | { | ||
5753 | if (connection->read_closed) | ||
5754 | { | ||
5755 | CONNECTION_CLOSE_ERROR (connection, | ||
5756 | NULL); | ||
5757 | continue; | ||
5758 | } | ||
5759 | break; | ||
5760 | } | 6507 | } |
5761 | if (MHD_NO == | 6508 | break; |
5762 | process_broken_line (connection, | 6509 | case MHD_CONNECTION_FOOTERS_RECEIVING: |
5763 | line, | 6510 | if (get_req_headers (connection, true)) |
5764 | MHD_FOOTER_KIND)) | ||
5765 | continue; | ||
5766 | if (0 == line[0]) | ||
5767 | { | 6511 | { |
5768 | connection->state = MHD_CONNECTION_FOOTERS_RECEIVED; | 6512 | mhd_assert (MHD_CONNECTION_FOOTERS_RECEIVING < connection->state); |
5769 | if (connection->suspended) | 6513 | mhd_assert ((MHD_CONNECTION_FOOTERS_RECEIVED == connection->state) || \ |
5770 | break; | 6514 | (connection->discard_request)); |
5771 | continue; | 6515 | continue; |
5772 | } | 6516 | } |
5773 | continue; | 6517 | mhd_assert (MHD_CONNECTION_FOOTERS_RECEIVING == connection->state); |
6518 | break; | ||
5774 | case MHD_CONNECTION_FOOTERS_RECEIVED: | 6519 | case MHD_CONNECTION_FOOTERS_RECEIVED: |
5775 | /* The header, the body, and the footers of the request has been received, | 6520 | /* The header, the body, and the footers of the request has been received, |
5776 | * switch to the final processing of the request. */ | 6521 | * switch to the final processing of the request. */ |