/src/dovecot/src/lib-http/http-request-parser.c
Line | Count | Source |
1 | | /* Copyright (c) Dovecot authors, see top-level COPYING file */ |
2 | | |
3 | | #include "lib.h" |
4 | | #include "istream.h" |
5 | | #include "http-url.h" |
6 | | #include "http-parser.h" |
7 | | #include "http-message-parser.h" |
8 | | #include "http-request-parser.h" |
9 | | |
10 | 82.9k | #define HTTP_REQUEST_PARSER_MAX_METHOD_LENGTH 32 |
11 | | |
12 | | enum http_request_parser_state { |
13 | | HTTP_REQUEST_PARSE_STATE_INIT = 0, |
14 | | HTTP_REQUEST_PARSE_STATE_SKIP_LINE, |
15 | | HTTP_REQUEST_PARSE_STATE_METHOD, |
16 | | HTTP_REQUEST_PARSE_STATE_SP1, |
17 | | HTTP_REQUEST_PARSE_STATE_TARGET, |
18 | | HTTP_REQUEST_PARSE_STATE_SP2, |
19 | | HTTP_REQUEST_PARSE_STATE_VERSION, |
20 | | HTTP_REQUEST_PARSE_STATE_CR, |
21 | | HTTP_REQUEST_PARSE_STATE_LF, |
22 | | HTTP_REQUEST_PARSE_STATE_HEADER |
23 | | }; |
24 | | |
25 | | struct http_request_parser { |
26 | | struct http_message_parser parser; |
27 | | pool_t pool; |
28 | | |
29 | | enum http_request_parser_state state; |
30 | | |
31 | | struct http_url *default_base_url; |
32 | | |
33 | | uoff_t max_target_length; |
34 | | |
35 | | enum http_request_parse_error error_code; |
36 | | |
37 | | const char *request_method; |
38 | | const char *request_target; |
39 | | |
40 | | bool skipping_line:1; |
41 | | }; |
42 | | |
43 | | struct http_request_parser * |
44 | | http_request_parser_init(struct istream *input, |
45 | | const struct http_url *default_base_url, |
46 | | const struct http_request_limits *limits, |
47 | | enum http_request_parse_flags flags) |
48 | 7.00k | { |
49 | 7.00k | struct http_request_parser *parser; |
50 | 7.00k | pool_t pool; |
51 | 7.00k | struct http_header_limits hdr_limits; |
52 | 7.00k | uoff_t max_payload_size; |
53 | 7.00k | enum http_message_parse_flags msg_flags = 0; |
54 | | |
55 | 7.00k | pool = pool_alloconly_create("http request parser", 1024); |
56 | 7.00k | parser = p_new(pool, struct http_request_parser, 1); |
57 | 7.00k | parser->pool = pool; |
58 | | |
59 | 7.00k | if (default_base_url != NULL) { |
60 | 0 | parser->default_base_url = |
61 | 0 | http_url_clone_authority(pool, default_base_url); |
62 | 0 | } |
63 | | |
64 | 7.00k | if (limits != NULL) { |
65 | 0 | hdr_limits = limits->header; |
66 | 0 | max_payload_size = limits->max_payload_size; |
67 | 0 | parser->max_target_length = limits->max_target_length; |
68 | 7.00k | } else { |
69 | 7.00k | i_zero(&hdr_limits); |
70 | 7.00k | max_payload_size = 0; |
71 | 7.00k | parser->max_target_length = 0; |
72 | 7.00k | } |
73 | | |
74 | | /* substitute default limits */ |
75 | 7.00k | if (parser->max_target_length == 0) |
76 | 7.00k | parser->max_target_length = HTTP_REQUEST_DEFAULT_MAX_TARGET_LENGTH; |
77 | 7.00k | if (hdr_limits.max_size == 0) |
78 | 7.00k | hdr_limits.max_size = HTTP_REQUEST_DEFAULT_MAX_HEADER_SIZE; |
79 | 7.00k | if (hdr_limits.max_field_size == 0) |
80 | 7.00k | hdr_limits.max_field_size = HTTP_REQUEST_DEFAULT_MAX_HEADER_FIELD_SIZE; |
81 | 7.00k | if (hdr_limits.max_fields == 0) |
82 | 7.00k | hdr_limits.max_fields = HTTP_REQUEST_DEFAULT_MAX_HEADER_FIELDS; |
83 | 7.00k | if (max_payload_size == 0) |
84 | 7.00k | max_payload_size = HTTP_REQUEST_DEFAULT_MAX_PAYLOAD_SIZE; |
85 | | |
86 | 7.00k | if ((flags & HTTP_REQUEST_PARSE_FLAG_STRICT) != 0) |
87 | 0 | msg_flags |= HTTP_MESSAGE_PARSE_FLAG_STRICT; |
88 | 7.00k | http_message_parser_init(&parser->parser, input, |
89 | 7.00k | &hdr_limits, max_payload_size, msg_flags); |
90 | 7.00k | return parser; |
91 | 7.00k | } |
92 | | |
93 | | void http_request_parser_deinit(struct http_request_parser **_parser) |
94 | 7.00k | { |
95 | 7.00k | struct http_request_parser *parser = *_parser; |
96 | | |
97 | 7.00k | *_parser = NULL; |
98 | | |
99 | 7.00k | http_message_parser_deinit(&parser->parser); |
100 | 7.00k | pool_unref(&parser->pool); |
101 | 7.00k | } |
102 | | |
103 | | static void |
104 | | http_request_parser_restart(struct http_request_parser *parser, |
105 | | pool_t pool) |
106 | 86.9k | { |
107 | 86.9k | http_message_parser_restart(&parser->parser, pool); |
108 | 86.9k | parser->request_method = NULL; |
109 | 86.9k | parser->request_target = NULL; |
110 | 86.9k | } |
111 | | |
112 | | static int http_request_parse_method(struct http_request_parser *parser) |
113 | 82.9k | { |
114 | 82.9k | const unsigned char *p = parser->parser.cur; |
115 | 82.9k | pool_t pool; |
116 | | |
117 | | /* method = token |
118 | | */ |
119 | 142k | while (p < parser->parser.end && http_char_is_token(*p)) |
120 | 59.4k | p++; |
121 | | |
122 | 82.9k | if ((p - parser->parser.cur) > HTTP_REQUEST_PARSER_MAX_METHOD_LENGTH) { |
123 | 4 | parser->error_code = HTTP_REQUEST_PARSE_ERROR_METHOD_TOO_LONG; |
124 | 4 | parser->parser.error = "HTTP request method is too long"; |
125 | 4 | return -1; |
126 | 4 | } |
127 | 82.9k | if (p == parser->parser.end) |
128 | 135 | return 0; |
129 | 82.8k | pool = http_message_parser_get_pool(&parser->parser); |
130 | 82.8k | parser->request_method = |
131 | 82.8k | p_strdup_until(pool, parser->parser.cur, p); |
132 | 82.8k | parser->parser.cur = p; |
133 | 82.8k | return 1; |
134 | 82.9k | } |
135 | | |
136 | | static int http_request_parse_target(struct http_request_parser *parser) |
137 | 82.5k | { |
138 | 82.5k | struct http_message_parser *_parser = &parser->parser; |
139 | 82.5k | const unsigned char *p = parser->parser.cur; |
140 | 82.5k | pool_t pool; |
141 | | |
142 | | /* We'll just parse anything up to the first SP or a control char. |
143 | | We could also implement workarounds for buggy HTTP clients and |
144 | | parse anything up to the HTTP-version and return 301 with the |
145 | | target properly encoded (FIXME). */ |
146 | 20.0M | while (p < _parser->end && *p > ' ') |
147 | 19.9M | p++; |
148 | | |
149 | | /* target is too long when explicit limit is exceeded or when input buffer |
150 | | runs out of space */ |
151 | | /* FIXME: put limit on full request line rather than target and method |
152 | | separately */ |
153 | | /* FIXME: is it wise to keep target in stream buffer? It can become very |
154 | | large for some applications, increasing the stream buffer size */ |
155 | 82.5k | if ((uoff_t)(p - _parser->cur) > parser->max_target_length || |
156 | 82.5k | (p == _parser->end && ((uoff_t)(p - _parser->cur) >= |
157 | 131 | i_stream_get_max_buffer_size(_parser->input)))) { |
158 | 27 | parser->error_code = HTTP_REQUEST_PARSE_ERROR_TARGET_TOO_LONG; |
159 | 27 | parser->parser.error = "HTTP request target is too long"; |
160 | 27 | return -1; |
161 | 27 | } |
162 | 82.5k | if (p == _parser->end) |
163 | 131 | return 0; |
164 | 82.4k | pool = http_message_parser_get_pool(_parser); |
165 | 82.4k | parser->request_target = p_strdup_until(pool, _parser->cur, p); |
166 | 82.4k | parser->parser.cur = p; |
167 | 82.4k | return 1; |
168 | 82.5k | } |
169 | | |
170 | | static inline const char *_chr_sanitize(unsigned char c) |
171 | 433 | { |
172 | 433 | if (c >= 0x20 && c < 0x7F) |
173 | 99 | return t_strdup_printf("`%c'", c); |
174 | 334 | if (c == 0x0a) |
175 | 108 | return "<LF>"; |
176 | 226 | if (c == 0x0d) |
177 | 3 | return "<CR>"; |
178 | 223 | return t_strdup_printf("<0x%02x>", c); |
179 | 226 | } |
180 | | |
181 | | static int http_request_parse(struct http_request_parser *parser, |
182 | | pool_t pool) |
183 | 83.0k | { |
184 | 83.0k | struct http_message_parser *_parser = &parser->parser; |
185 | 83.0k | int ret; |
186 | | |
187 | | /* RFC 7230, Section 3.1.1: Request Line |
188 | | |
189 | | request-line = method SP request-target SP HTTP-version CRLF |
190 | | method = token |
191 | | */ |
192 | 90.9k | for (;;) { |
193 | 90.9k | switch (parser->state) { |
194 | 86.9k | case HTTP_REQUEST_PARSE_STATE_INIT: |
195 | 86.9k | http_request_parser_restart(parser, pool); |
196 | 86.9k | parser->state = HTTP_REQUEST_PARSE_STATE_SKIP_LINE; |
197 | 86.9k | if (_parser->cur == _parser->end) |
198 | 9 | return 0; |
199 | | /* fall through */ |
200 | 86.9k | case HTTP_REQUEST_PARSE_STATE_SKIP_LINE: |
201 | 86.9k | if (*_parser->cur == '\r' || *_parser->cur == '\n') { |
202 | 3.98k | if (parser->skipping_line) { |
203 | | /* second extra CRLF; not allowed */ |
204 | 10 | parser->error_code = HTTP_REQUEST_PARSE_ERROR_BROKEN_REQUEST; |
205 | 10 | _parser->error = "Empty request line"; |
206 | 10 | return -1; |
207 | 10 | } |
208 | | /* HTTP/1.0 client sent one extra CRLF after body. |
209 | | ignore it. */ |
210 | 3.97k | parser->skipping_line = TRUE; |
211 | 3.97k | parser->state = HTTP_REQUEST_PARSE_STATE_CR; |
212 | 3.97k | break; |
213 | 3.98k | } |
214 | 82.9k | parser->state = HTTP_REQUEST_PARSE_STATE_METHOD; |
215 | 82.9k | parser->skipping_line = FALSE; |
216 | | /* fall through */ |
217 | 82.9k | case HTTP_REQUEST_PARSE_STATE_METHOD: |
218 | 82.9k | if ((ret=http_request_parse_method(parser)) <= 0) |
219 | 139 | return ret; |
220 | 82.8k | parser->state = HTTP_REQUEST_PARSE_STATE_SP1; |
221 | 82.8k | if (_parser->cur == _parser->end) |
222 | 0 | return 0; |
223 | | /* fall through */ |
224 | 82.8k | case HTTP_REQUEST_PARSE_STATE_SP1: |
225 | 82.8k | if (*_parser->cur != ' ') { |
226 | 226 | parser->error_code = HTTP_REQUEST_PARSE_ERROR_BROKEN_REQUEST; |
227 | 226 | _parser->error = t_strdup_printf |
228 | 226 | ("Unexpected character %s in request method", |
229 | 226 | _chr_sanitize(*_parser->cur)); |
230 | 226 | return -1; |
231 | 226 | } |
232 | 82.6k | _parser->cur++; |
233 | 82.6k | parser->state = HTTP_REQUEST_PARSE_STATE_TARGET; |
234 | 82.6k | if (_parser->cur >= _parser->end) |
235 | 32 | return 0; |
236 | | /* fall through */ |
237 | 82.5k | case HTTP_REQUEST_PARSE_STATE_TARGET: |
238 | 82.5k | if ((ret=http_request_parse_target(parser)) <= 0) |
239 | 158 | return ret; |
240 | 82.4k | parser->state = HTTP_REQUEST_PARSE_STATE_SP2; |
241 | 82.4k | if (_parser->cur == _parser->end) |
242 | 0 | return 0; |
243 | | /* fall through */ |
244 | 82.4k | case HTTP_REQUEST_PARSE_STATE_SP2: |
245 | 82.4k | if (*_parser->cur != ' ') { |
246 | 163 | parser->error_code = HTTP_REQUEST_PARSE_ERROR_BROKEN_REQUEST; |
247 | 163 | _parser->error = t_strdup_printf |
248 | 163 | ("Unexpected character %s in request target", |
249 | 163 | _chr_sanitize(*_parser->cur)); |
250 | 163 | return -1; |
251 | 163 | } |
252 | 82.2k | _parser->cur++; |
253 | 82.2k | parser->state = HTTP_REQUEST_PARSE_STATE_VERSION; |
254 | 82.2k | if (_parser->cur >= _parser->end) |
255 | 19 | return 0; |
256 | | /* fall through */ |
257 | 82.2k | case HTTP_REQUEST_PARSE_STATE_VERSION: |
258 | 82.2k | if ((ret=http_message_parse_version(&parser->parser)) <= 0) { |
259 | 158 | if (ret < 0) { |
260 | 107 | parser->error_code = HTTP_REQUEST_PARSE_ERROR_BROKEN_REQUEST; |
261 | 107 | _parser->error = "Invalid HTTP version in request"; |
262 | 107 | } |
263 | 158 | return ret; |
264 | 158 | } |
265 | 82.0k | parser->state = HTTP_REQUEST_PARSE_STATE_CR; |
266 | 82.0k | if (_parser->cur == _parser->end) |
267 | 2 | return 0; |
268 | | /* fall through */ |
269 | 86.0k | case HTTP_REQUEST_PARSE_STATE_CR: |
270 | 86.0k | if (*_parser->cur == '\r') |
271 | 3.59k | _parser->cur++; |
272 | 86.0k | parser->state = HTTP_REQUEST_PARSE_STATE_LF; |
273 | 86.0k | if (_parser->cur == _parser->end) |
274 | 5 | return 0; |
275 | | /* fall through */ |
276 | 86.0k | case HTTP_REQUEST_PARSE_STATE_LF: |
277 | 86.0k | if (*_parser->cur != '\n') { |
278 | 44 | parser->error_code = HTTP_REQUEST_PARSE_ERROR_BROKEN_REQUEST; |
279 | 44 | _parser->error = t_strdup_printf |
280 | 44 | ("Unexpected character %s at end of request line", |
281 | 44 | _chr_sanitize(*_parser->cur)); |
282 | 44 | return -1; |
283 | 44 | } |
284 | 86.0k | _parser->cur++; |
285 | 86.0k | if (!parser->skipping_line) { |
286 | 82.0k | parser->state = HTTP_REQUEST_PARSE_STATE_HEADER; |
287 | 82.0k | return 1; |
288 | 82.0k | } |
289 | 3.94k | parser->state = HTTP_REQUEST_PARSE_STATE_INIT; |
290 | 3.94k | break; |
291 | 0 | case HTTP_REQUEST_PARSE_STATE_HEADER: |
292 | 0 | default: |
293 | 0 | i_unreached(); |
294 | 90.9k | } |
295 | 90.9k | } |
296 | | |
297 | 83.0k | i_unreached(); |
298 | 83.0k | } |
299 | | |
300 | | static int http_request_parse_request_line(struct http_request_parser *parser, |
301 | | pool_t pool) |
302 | 83.7k | { |
303 | 83.7k | struct http_message_parser *_parser = &parser->parser; |
304 | 83.7k | const unsigned char *begin; |
305 | 83.7k | size_t size, old_bytes = 0; |
306 | 83.7k | int ret; |
307 | | |
308 | 84.1k | while ((ret = i_stream_read_bytes(_parser->input, &begin, &size, |
309 | 84.1k | old_bytes + 1)) > 0) { |
310 | 83.0k | _parser->begin = _parser->cur = begin; |
311 | 83.0k | _parser->end = _parser->begin + size; |
312 | | |
313 | 83.0k | if ((ret = http_request_parse(parser, pool)) < 0) |
314 | 581 | return -1; |
315 | | |
316 | 82.4k | i_stream_skip(_parser->input, _parser->cur - begin); |
317 | 82.4k | if (ret > 0) |
318 | 82.0k | return 1; |
319 | 384 | old_bytes = i_stream_get_data_size(_parser->input); |
320 | 384 | } |
321 | | |
322 | 1.12k | if (ret == -2) { |
323 | 0 | parser->error_code = HTTP_REQUEST_PARSE_ERROR_BROKEN_REQUEST; |
324 | 0 | _parser->error = "HTTP request line is too long"; |
325 | 0 | return -1; |
326 | 0 | } |
327 | 1.12k | if (ret < 0) { |
328 | 1.12k | if (_parser->input->eof && |
329 | 1.12k | parser->state == HTTP_REQUEST_PARSE_STATE_INIT) |
330 | 738 | return 0; |
331 | 384 | parser->error_code = HTTP_REQUEST_PARSE_ERROR_BROKEN_STREAM; |
332 | 384 | _parser->error = "Broken stream"; |
333 | 384 | return -1; |
334 | 1.12k | } |
335 | 0 | return 0; |
336 | 1.12k | } |
337 | | |
338 | | static inline enum http_request_parse_error |
339 | | http_request_parser_message_error(struct http_request_parser *parser) |
340 | 3.43k | { |
341 | 3.43k | switch (parser->parser.error_code) { |
342 | 1.33k | case HTTP_MESSAGE_PARSE_ERROR_BROKEN_STREAM: |
343 | 1.33k | return HTTP_REQUEST_PARSE_ERROR_BROKEN_STREAM; |
344 | 6 | case HTTP_MESSAGE_PARSE_ERROR_BAD_MESSAGE: |
345 | 6 | return HTTP_REQUEST_PARSE_ERROR_BAD_REQUEST; |
346 | 7 | case HTTP_MESSAGE_PARSE_ERROR_NOT_IMPLEMENTED: |
347 | 7 | return HTTP_REQUEST_PARSE_ERROR_NOT_IMPLEMENTED; |
348 | 335 | case HTTP_MESSAGE_PARSE_ERROR_PAYLOAD_TOO_LARGE: |
349 | 335 | return HTTP_REQUEST_PARSE_ERROR_PAYLOAD_TOO_LARGE; |
350 | 1.74k | case HTTP_MESSAGE_PARSE_ERROR_BROKEN_MESSAGE: |
351 | 1.74k | return HTTP_REQUEST_PARSE_ERROR_BROKEN_REQUEST; |
352 | 0 | default: |
353 | 0 | break; |
354 | 3.43k | } |
355 | 3.43k | i_unreached(); |
356 | 3.43k | } |
357 | | |
358 | | bool http_request_parser_pending_payload( |
359 | | struct http_request_parser *parser) |
360 | 0 | { |
361 | 0 | if (parser->parser.payload == NULL) |
362 | 0 | return FALSE; |
363 | 0 | return i_stream_have_bytes_left(parser->parser.payload); |
364 | 0 | } |
365 | | |
366 | | static int |
367 | | http_request_parse_expect_header(struct http_request_parser *parser, |
368 | | struct http_request *request, const struct http_header_field *hdr) |
369 | 630 | { |
370 | 630 | struct http_message_parser *_parser = &parser->parser; |
371 | 630 | struct http_parser hparser; |
372 | 630 | bool parse_error = FALSE; |
373 | 630 | unsigned int num_expectations = 0; |
374 | | |
375 | | /* RFC 7231, Section 5.1.1: |
376 | | |
377 | | Expect = "100-continue" |
378 | | */ |
379 | | // FIXME: simplify; RFC 7231 discarded Expect extension mechanism |
380 | 630 | http_parser_init(&hparser, (const unsigned char *)hdr->value, hdr->size); |
381 | 4.28k | while (!parse_error) { |
382 | 4.28k | const char *expect_name, *expect_value; |
383 | | |
384 | | /* expect-name */ |
385 | 4.28k | if (http_parse_token(&hparser, &expect_name) > 0) { |
386 | 2.54k | num_expectations++; |
387 | 2.54k | if (strcasecmp(expect_name, "100-continue") == 0) { |
388 | 1.53k | request->expect_100_continue = TRUE; |
389 | 1.53k | } else { |
390 | 1.01k | if (parser->error_code == HTTP_REQUEST_PARSE_ERROR_NONE) { |
391 | 198 | parser->error_code = HTTP_REQUEST_PARSE_ERROR_EXPECTATION_FAILED; |
392 | 198 | _parser->error = t_strdup_printf |
393 | 198 | ("Unknown Expectation `%s'", expect_name); |
394 | 198 | } |
395 | 1.01k | } |
396 | | |
397 | | /* BWS "=" BWS */ |
398 | 2.54k | http_parse_ows(&hparser); |
399 | 2.54k | if (hparser.cur >= hparser.end) |
400 | 180 | break; |
401 | | |
402 | 2.36k | if (*hparser.cur == '=') { |
403 | 433 | hparser.cur++; |
404 | 433 | http_parse_ows(&hparser); |
405 | | |
406 | | /* value */ |
407 | 433 | if (http_parse_token_or_qstring(&hparser, &expect_value) <= 0) { |
408 | 21 | parse_error = TRUE; |
409 | 21 | break; |
410 | 21 | } |
411 | | |
412 | 412 | if (parser->error_code == HTTP_REQUEST_PARSE_ERROR_NONE) { |
413 | 1 | parser->error_code = HTTP_REQUEST_PARSE_ERROR_EXPECTATION_FAILED; |
414 | 1 | _parser->error = t_strdup_printf |
415 | 1 | ("Expectation `%s' has unexpected value", expect_name); |
416 | 1 | } |
417 | 412 | } |
418 | | |
419 | | /* *( OWS ";" [ OWS expect-param ] ) */ |
420 | 2.67k | while (!parse_error) { |
421 | 2.67k | const char *attribute, *value; |
422 | | |
423 | | /* OWS ";" */ |
424 | 2.67k | http_parse_ows(&hparser); |
425 | 2.67k | if (hparser.cur >= hparser.end || *hparser.cur != ';') |
426 | 2.33k | break; |
427 | 340 | hparser.cur++; |
428 | 340 | http_parse_ows(&hparser); |
429 | | |
430 | | /* expect-param */ |
431 | 340 | if (http_parse_token(&hparser, &attribute) <= 0) { |
432 | 3 | parse_error = TRUE; |
433 | 3 | break; |
434 | 3 | } |
435 | | |
436 | | /* BWS "=" BWS */ |
437 | 337 | http_parse_ows(&hparser); |
438 | 337 | if (hparser.cur >= hparser.end || *hparser.cur != '=') { |
439 | 7 | parse_error = TRUE; |
440 | 7 | break; |
441 | 7 | } |
442 | 330 | hparser.cur++; |
443 | 330 | http_parse_ows(&hparser); |
444 | | |
445 | | /* value */ |
446 | 330 | if (http_parse_token_or_qstring(&hparser, &value) <= 0) { |
447 | 4 | parse_error = TRUE; |
448 | 4 | break; |
449 | 4 | } |
450 | | |
451 | 326 | if (parser->error_code == HTTP_REQUEST_PARSE_ERROR_NONE) { |
452 | 1 | parser->error_code = HTTP_REQUEST_PARSE_ERROR_EXPECTATION_FAILED; |
453 | 1 | _parser->error = t_strdup_printf |
454 | 1 | ("Expectation `%s' has unknown parameter `'%s'", |
455 | 1 | expect_name, attribute); |
456 | 1 | } |
457 | 326 | } |
458 | 2.34k | if (parse_error) |
459 | 14 | break; |
460 | 2.34k | } |
461 | 4.06k | http_parse_ows(&hparser); |
462 | 4.06k | if (hparser.cur >= hparser.end || *hparser.cur != ',') |
463 | 415 | break; |
464 | 3.65k | hparser.cur++; |
465 | 3.65k | http_parse_ows(&hparser); |
466 | 3.65k | } |
467 | | |
468 | 630 | if (parse_error || hparser.cur < hparser.end) { |
469 | 83 | parser->error_code = HTTP_REQUEST_PARSE_ERROR_BAD_REQUEST; |
470 | 83 | _parser->error = "Invalid Expect header"; |
471 | 83 | return -1; |
472 | 83 | } |
473 | | |
474 | 547 | if (parser->error_code != HTTP_REQUEST_PARSE_ERROR_NONE) |
475 | 132 | return -1; |
476 | | |
477 | 415 | if (num_expectations == 0) { |
478 | 14 | parser->error_code = HTTP_REQUEST_PARSE_ERROR_BAD_REQUEST; |
479 | 14 | _parser->error = "Empty Expect header"; |
480 | 14 | return -1; |
481 | 14 | } |
482 | 401 | return 0; |
483 | 415 | } |
484 | | |
485 | | static int |
486 | | http_request_parse_headers(struct http_request_parser *parser, |
487 | | struct http_request *request) |
488 | 77.7k | { |
489 | 77.7k | const ARRAY_TYPE(http_header_field) *hdrs; |
490 | 77.7k | const struct http_header_field *hdr; |
491 | | |
492 | 77.7k | hdrs = http_header_get_fields(parser->parser.msg.header); |
493 | 232k | array_foreach(hdrs, hdr) { |
494 | 232k | int ret = 0; |
495 | | |
496 | | /* Expect: */ |
497 | 232k | if (http_header_field_is(hdr, "Expect")) |
498 | 630 | ret = http_request_parse_expect_header(parser, request, hdr); |
499 | | |
500 | 232k | if (ret < 0) |
501 | 229 | return -1; |
502 | 232k | } |
503 | 77.5k | return 0; |
504 | 77.7k | } |
505 | | |
506 | | int http_request_parse_finish_payload( |
507 | | struct http_request_parser *parser, |
508 | | enum http_request_parse_error *error_code_r, |
509 | | const char **error_r) |
510 | 84.5k | { |
511 | 84.5k | int ret; |
512 | | |
513 | 84.5k | *error_code_r = parser->error_code = HTTP_REQUEST_PARSE_ERROR_NONE; |
514 | 84.5k | *error_r = parser->parser.error = NULL; |
515 | | |
516 | | /* make sure we finished streaming payload from previous request |
517 | | before we continue. */ |
518 | 84.5k | if ((ret = http_message_parse_finish_payload(&parser->parser)) <= 0) { |
519 | 797 | if (ret < 0) { |
520 | 797 | *error_code_r = http_request_parser_message_error(parser); |
521 | 797 | *error_r = parser->parser.error; |
522 | 797 | } |
523 | 797 | } |
524 | 84.5k | return ret; |
525 | 84.5k | } |
526 | | |
527 | | int http_request_parse_next(struct http_request_parser *parser, |
528 | | pool_t pool, struct http_request *request, |
529 | | enum http_request_parse_error *error_code_r, const char **error_r) |
530 | 84.5k | { |
531 | 84.5k | const struct http_header_field *hdr; |
532 | 84.5k | const char *host_hdr, *error; |
533 | 84.5k | int ret; |
534 | | |
535 | | /* initialize and get rid of any payload of previous request */ |
536 | 84.5k | if ((ret=http_request_parse_finish_payload |
537 | 84.5k | (parser, error_code_r, error_r)) <= 0) |
538 | 797 | return ret; |
539 | | |
540 | | /* RFC 7230, Section 3: |
541 | | |
542 | | HTTP-message = start-line |
543 | | *( header-field CRLF ) |
544 | | CRLF |
545 | | [ message-body ] |
546 | | */ |
547 | 83.7k | if (parser->state != HTTP_REQUEST_PARSE_STATE_HEADER) { |
548 | 83.7k | ret = http_request_parse_request_line(parser, pool); |
549 | | |
550 | | /* assign early for error reporting */ |
551 | 83.7k | request->method = parser->request_method; |
552 | 83.7k | request->target_raw = parser->request_target; |
553 | 83.7k | request->version_major = parser->parser.msg.version_major; |
554 | 83.7k | request->version_minor = parser->parser.msg.version_minor; |
555 | | |
556 | 83.7k | if (ret <= 0) { |
557 | 1.70k | if (ret < 0) { |
558 | 965 | *error_code_r = parser->error_code; |
559 | 965 | *error_r = parser->parser.error; |
560 | 965 | } |
561 | 1.70k | return ret; |
562 | 1.70k | } |
563 | 83.7k | } |
564 | | |
565 | 82.0k | if ((ret = http_message_parse_headers(&parser->parser)) <= 0) { |
566 | 2.34k | if (ret < 0) { |
567 | 2.34k | *error_code_r = http_request_parser_message_error(parser); |
568 | 2.34k | *error_r = parser->parser.error; |
569 | 2.34k | } |
570 | 2.34k | return ret; |
571 | 2.34k | } |
572 | | |
573 | 79.7k | if (http_message_parse_body(&parser->parser, TRUE) < 0) { |
574 | 292 | *error_code_r = http_request_parser_message_error(parser); |
575 | 292 | *error_r = parser->parser.error; |
576 | 292 | return -1; |
577 | 292 | } |
578 | 79.4k | parser->state = HTTP_REQUEST_PARSE_STATE_INIT; |
579 | | |
580 | | /* RFC 7230, Section 5.4: Host |
581 | | |
582 | | A server MUST respond with a 400 (Bad Request) status code to any |
583 | | HTTP/1.1 request message that lacks a Host header field and to any |
584 | | request message that contains more than one Host header field or a |
585 | | Host header field with an invalid field-value. |
586 | | */ |
587 | 79.4k | host_hdr = NULL; |
588 | 79.4k | if (parser->parser.msg.version_major == 1 && |
589 | 79.3k | parser->parser.msg.version_minor > 0) { |
590 | 79.2k | if ((ret=http_header_field_find_unique( |
591 | 79.2k | parser->parser.msg.header, "Host", &hdr)) <= 0) { |
592 | 139 | *error_code_r = HTTP_REQUEST_PARSE_ERROR_BAD_REQUEST; |
593 | 139 | if (ret == 0) |
594 | 128 | *error_r = "Missing Host header"; |
595 | 11 | else |
596 | 11 | *error_r = "Duplicate Host header"; |
597 | 139 | return -1; |
598 | 139 | } |
599 | | |
600 | 79.0k | host_hdr = hdr->value; |
601 | 79.0k | } |
602 | | |
603 | 79.2k | i_zero(request); |
604 | | |
605 | 79.2k | pool = http_message_parser_get_pool(&parser->parser); |
606 | 79.2k | if (http_url_request_target_parse(parser->request_target, host_hdr, |
607 | 79.2k | parser->default_base_url, pool, &request->target, &error) < 0) { |
608 | 1.50k | *error_code_r = HTTP_REQUEST_PARSE_ERROR_BAD_REQUEST; |
609 | 1.50k | *error_r = t_strdup_printf("Bad request target `%s': %s", |
610 | 1.50k | parser->request_target, error); |
611 | 1.50k | return -1; |
612 | 1.50k | } |
613 | | |
614 | | /* parse request-specific headers */ |
615 | 77.7k | if (http_request_parse_headers(parser, request) < 0) { |
616 | 229 | *error_code_r = parser->error_code; |
617 | 229 | *error_r = parser->parser.error; |
618 | 229 | return -1; |
619 | 229 | } |
620 | | |
621 | 77.5k | request->method = parser->request_method; |
622 | 77.5k | request->target_raw = parser->request_target; |
623 | 77.5k | request->version_major = parser->parser.msg.version_major; |
624 | 77.5k | request->version_minor = parser->parser.msg.version_minor; |
625 | 77.5k | request->date = parser->parser.msg.date; |
626 | 77.5k | request->payload = parser->parser.payload; |
627 | 77.5k | request->header = parser->parser.msg.header; |
628 | 77.5k | request->connection_options = parser->parser.msg.connection_options; |
629 | 77.5k | request->connection_close = parser->parser.msg.connection_close; |
630 | | |
631 | | /* reset this state early */ |
632 | 77.5k | parser->request_method = NULL; |
633 | 77.5k | parser->request_target = NULL; |
634 | 77.5k | return 1; |
635 | 77.7k | } |