aboutsummaryrefslogtreecommitdiff
path: root/src/microhttpd/connection.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/microhttpd/connection.c')
-rw-r--r--src/microhttpd/connection.c1027
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
4177reset_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 */
3988static bool 4198static 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 */
4957enum 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 */
4989static enum MHD_HdrLineReadRes_
4990get_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 */
5418static bool
5419get_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. */