1 /* SPDX-License-Identifier: MIT */
2
3 /* Based on src/http/ngx_http_parse.c from NGINX copyright Igor Sysoev
4 *
5 * Additional changes are licensed under the same terms as NGINX and
6 * copyright Joyent, Inc. and other Node contributors. All rights reserved.
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a copy
9 * of this software and associated documentation files (the "Software"), to
10 * deal in the Software without restriction, including without limitation the
11 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
12 * sell copies of the Software, and to permit persons to whom the Software is
13 * furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
24 * IN THE SOFTWARE.
25 */
26 #include <zephyr/net/http/parser.h>
27 #include <zephyr/sys/__assert.h>
28 #include <stddef.h>
29 #include <ctype.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <limits.h>
33 #include <zephyr/toolchain.h>
34
35 #ifndef ULLONG_MAX
36 # define ULLONG_MAX ((uint64_t) -1) /* 2^64-1 */
37 #endif
38
39 #ifndef MIN
40 # define MIN(a, b) ((a) < (b) ? (a) : (b))
41 #endif
42
43 #ifndef ARRAY_SIZE
44 # define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
45 #endif
46
47 #ifndef BIT_AT
48 # define BIT_AT(a, i) \
49 (!!((unsigned int) (a)[(unsigned int) (i) >> 3] & \
50 (1 << ((unsigned int) (i) & 7))))
51 #endif
52
53 #ifndef ELEM_AT
54 # define ELEM_AT(a, i, v) ((unsigned int) (i) < ARRAY_SIZE(a) ? (a)[(i)] : (v))
55 #endif
56
57 #define SET_ERRNO(e) (parser->http_errno = (e))
58 #define CURRENT_STATE() p_state
59 #define UPDATE_STATE(V) (p_state = (enum state)(V))
60
61 #ifdef __GNUC__
62 # define LIKELY(X) __builtin_expect(!!(X), 1)
63 # define UNLIKELY(X) __builtin_expect(!!(X), 0)
64 #else
65 # define LIKELY(X) (X)
66 # define UNLIKELY(X) (X)
67 #endif
68
69 /* Set the mark FOR; non-destructive if mark is already set */
70 #define MARK(FOR) \
71 do { \
72 if (!FOR##_mark) { \
73 FOR##_mark = p; \
74 } \
75 } while (false)
76
77 /* Don't allow the total size of the HTTP headers (including the status
78 * line) to exceed HTTP_MAX_HEADER_SIZE. This check is here to protect
79 * embedders against denial-of-service attacks where the attacker feeds
80 * us a never-ending header that the embedder keeps buffering.
81 *
82 * This check is arguably the responsibility of embedders but we're doing
83 * it on the embedder's behalf because most won't bother and this way we
84 * make the web a little safer. HTTP_MAX_HEADER_SIZE is still far bigger
85 * than any reasonable request or response so this should never affect
86 * day-to-day operation.
87 */
88 static inline
count_header_size(struct http_parser * parser,int bytes)89 int count_header_size(struct http_parser *parser, int bytes)
90 {
91 parser->nread += bytes;
92
93 if (UNLIKELY(parser->nread > (HTTP_MAX_HEADER_SIZE))) {
94 parser->http_errno = HPE_HEADER_OVERFLOW;
95 return -1;
96 }
97
98 return 0;
99 }
100
101 #define PROXY_CONNECTION "proxy-connection"
102 #define CONNECTION "connection"
103 #define CONTENT "content-"
104 #define CONTENT_LENGTH "content-length"
105 #define CONTENT_RANGE "content-range"
106 #define TRANSFER_ENCODING "transfer-encoding"
107 #define UPGRADE "upgrade"
108 #define CHUNKED "chunked"
109 #define KEEP_ALIVE "keep-alive"
110 #define CLOSE "close"
111
112
113 static const
114 char *method_strings[] = {"DELETE", "GET", "HEAD", "POST", "PUT", "CONNECT",
115 "OPTIONS", "TRACE", "COPY", "LOCK", "MKCOL", "MOVE",
116 "PROPFIND", "PROPPATCH", "SEARCH", "UNLOCK", "BIND",
117 "REBIND", "UNBIND", "ACL", "REPORT", "MKACTIVITY",
118 "CHECKOUT", "MERGE", "M-SEARCH", "NOTIFY",
119 "SUBSCRIBE", "UNSUBSCRIBE", "PATCH", "PURGE",
120 "MKCALENDAR", "LINK", "UNLINK"};
121
122
123 /* Tokens as defined by rfc 2616. Also lowercases them.
124 * token = 1*<any CHAR except CTLs or separators>
125 * separators = "(" | ")" | "<" | ">" | "@"
126 * | "," | ";" | ":" | "\" | <">
127 * | "/" | "[" | "]" | "?" | "="
128 * | "{" | "}" | SP | HT
129 */
130 static const char tokens[256] = {
131 /* 0 nul 1 soh 2 stx 3 etx 4 eot 5 enq 6 ack 7 bel */
132 0, 0, 0, 0, 0, 0, 0, 0,
133 /* 8 bs 9 ht 10 nl 11 vt 12 np 13 cr 14 so 15 si */
134 0, 0, 0, 0, 0, 0, 0, 0,
135 /* 16 dle 17 dc1 18 dc2 19 dc3 20 dc4 21 nak 22 syn 23 etb */
136 0, 0, 0, 0, 0, 0, 0, 0,
137 /* 24 can 25 em 26 sub 27 esc 28 fs 29 gs 30 rs 31 us */
138 0, 0, 0, 0, 0, 0, 0, 0,
139 /* 32 sp 33 ! 34 " 35 # 36 $ 37 % 38 & 39 ' */
140 0, '!', 0, '#', '$', '%', '&', '\'',
141 /* 40 ( 41 ) 42 * 43 + 44 , 45 - 46 . 47 / */
142 0, 0, '*', '+', 0, '-', '.', 0,
143 /* 48 0 49 1 50 2 51 3 52 4 53 5 54 6 55 7 */
144 '0', '1', '2', '3', '4', '5', '6', '7',
145 /* 56 8 57 9 58 : 59 ; 60 < 61 = 62 > 63 ? */
146 '8', '9', 0, 0, 0, 0, 0, 0,
147 /* 64 @ 65 A 66 B 67 C 68 D 69 E 70 F 71 G */
148 0, 'a', 'b', 'c', 'd', 'e', 'f', 'g',
149 /* 72 H 73 I 74 J 75 K 76 L 77 M 78 N 79 O */
150 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
151 /* 80 P 81 Q 82 R 83 S 84 T 85 U 86 V 87 W */
152 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
153 /* 88 X 89 Y 90 Z 91 [ 92 \ 93 ] 94 ^ 95 _ */
154 'x', 'y', 'z', 0, 0, 0, '^', '_',
155 /* 96 ` 97 a 98 b 99 c 100 d 101 e 102 f 103 g */
156 '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
157 /* 104 h 105 i 106 j 107 k 108 l 109 m 110 n 111 o */
158 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
159 /* 112 p 113 q 114 r 115 s 116 t 117 u 118 v 119 w */
160 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
161 /* 120 x 121 y 122 z 123 { 124 | 125 } 126 ~ 127 del */
162 'x', 'y', 'z', 0, '|', 0, '~', 0
163 };
164
165
166 static const
167 int8_t unhex[256] = {
168 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
169 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
170 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
171 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
172 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
173 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
174 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
175 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
176 };
177
178
179 #define PARSING_HEADER(state) (state <= s_headers_done)
180
181 enum header_states {
182 h_general = 0,
183 h_C,
184 h_CO,
185 h_CON,
186 h_matching_connection,
187 h_matching_proxy_connection,
188 h_matching_content,
189 h_CONTENT_,
190 h_matching_content_length,
191 h_matching_content_range,
192 h_matching_transfer_encoding,
193 h_matching_upgrade,
194 h_connection,
195 h_content_length,
196 h_content_range_start,
197 h_content_range_end,
198 h_content_range_total,
199 h_transfer_encoding,
200 h_upgrade,
201 h_matching_transfer_encoding_chunked,
202 h_matching_connection_token_start,
203 h_matching_connection_keep_alive,
204 h_matching_connection_close,
205 h_matching_connection_upgrade,
206 h_matching_connection_token,
207 h_transfer_encoding_chunked,
208 h_connection_keep_alive,
209 h_connection_close,
210 h_connection_upgrade
211 };
212
213 static inline
cb_notify(struct http_parser * parser,enum state * current_state,http_cb cb,int cb_error,size_t * parsed,size_t already_parsed)214 int cb_notify(struct http_parser *parser, enum state *current_state, http_cb cb,
215 int cb_error, size_t *parsed, size_t already_parsed)
216 {
217 __ASSERT_NO_MSG(HTTP_PARSER_ERRNO(parser) == HPE_OK);
218
219 if (cb == NULL) {
220 return 0;
221 }
222
223 parser->state = *current_state;
224 if (UNLIKELY(cb(parser) != 0)) {
225 SET_ERRNO(cb_error);
226 }
227 *current_state = parser->state;
228 /* We either errored above or got paused; get out */
229 if (UNLIKELY(HTTP_PARSER_ERRNO(parser) != HPE_OK)) {
230 *parsed = already_parsed;
231 return -HTTP_PARSER_ERRNO(parser);
232 }
233
234 return 0;
235 }
236
237 static inline
cb_data(struct http_parser * parser,http_data_cb cb,int cb_error,enum state * current_state,size_t * parsed,size_t already_parsed,const char ** mark,size_t len)238 int cb_data(struct http_parser *parser, http_data_cb cb, int cb_error,
239 enum state *current_state, size_t *parsed, size_t already_parsed,
240 const char **mark, size_t len)
241 {
242 int rc;
243
244 __ASSERT_NO_MSG(HTTP_PARSER_ERRNO(parser) == HPE_OK);
245 if (*mark == NULL) {
246 return 0;
247 }
248 if (cb == NULL) {
249 goto lb_end;
250 }
251
252 parser->state = *current_state;
253 rc = cb(parser, *mark, len);
254 if (UNLIKELY(rc != 0)) {
255 SET_ERRNO(cb_error);
256 }
257 *current_state = parser->state;
258 /* We either errored above or got paused; get out */
259 if (UNLIKELY(HTTP_PARSER_ERRNO(parser) != HPE_OK)) {
260 *parsed = already_parsed;
261 return -HTTP_PARSER_ERRNO(parser);
262 }
263 lb_end:
264 *mark = NULL;
265
266 return 0;
267 }
268
269
270 /* Macros for character classes; depends on strict-mode */
271 #define CR '\r'
272 #define LF '\n'
273 #define LOWER(c) (unsigned char)(c | 0x20)
274 #define IS_ALPHA(c) (LOWER(c) >= 'a' && LOWER(c) <= 'z')
275 #define IS_NUM(c) ((c) >= '0' && (c) <= '9')
276 #define IS_ALPHANUM(c) (IS_ALPHA(c) || IS_NUM(c))
277 #define IS_HEX(c) (IS_NUM(c) || (LOWER(c) >= 'a' && LOWER(c) <= 'f'))
278
279 #define IS_MARK(c) ((c) == '-' || (c) == '_' || (c) == '.' || \
280 (c) == '!' || (c) == '~' || (c) == '*' || \
281 (c) == '\'' || (c) == '(' || (c) == ')')
282
283 #define IS_USERINFO_CHAR(c) (IS_ALPHANUM(c) || IS_MARK(c) || (c) == '%' || \
284 (c) == ';' || (c) == ':' || (c) == '&' || \
285 (c) == '=' || (c) == '+' || (c) == '$' || \
286 (c) == ',')
287
288 #define STRICT_TOKEN(c) (tokens[(unsigned char)c])
289
290 #ifdef HTTP_PARSER_STRICT
291 #define TOKEN(c) (tokens[(unsigned char)c])
292 #define IS_HOST_CHAR(c) (IS_ALPHANUM(c) || (c) == '.' || (c) == '-')
293 #else
294 #define TOKEN(c) ((c == ' ') ? ' ' : tokens[(unsigned char)c])
295 #define IS_HOST_CHAR(c) \
296 (IS_ALPHANUM(c) || (c) == '.' || (c) == '-' || (c) == '_')
297 #endif
298
299 /**
300 * Verify that a char is a valid visible (printable) US-ASCII
301 * character or %x80-FF
302 **/
303 #define IS_HEADER_CHAR(ch) \
304 (ch == CR || ch == LF || ch == 9 || \
305 ((unsigned char)ch > 31 && ch != 127))
306
307 #define start_state (parser->type == HTTP_REQUEST ? s_start_req : s_start_res)
308
309
310 #ifdef HTTP_PARSER_STRICT
311 static inline
strict_check(struct http_parser * parser,int c)312 int strict_check(struct http_parser *parser, int c)
313 {
314 if (c) {
315 parser->http_errno = HPE_STRICT;
316 return -1;
317 }
318 return 0;
319 }
320
321 # define NEW_MESSAGE() (http_should_keep_alive(parser) ? start_state : s_dead)
322 #else
323 static inline
strict_check(struct http_parser * parser,int c)324 int strict_check(struct http_parser *parser, int c)
325 {
326 (void)parser;
327 (void)c;
328 return 0;
329 }
330 # define NEW_MESSAGE() start_state
331 #endif
332
333 static struct {
334 const char *name;
335 const char *description;
336 } http_strerror_tab[] = {
337 {"HPE_OK", "success"},
338 {"HPE_CB_message_begin", "the on_message_begin callback failed"},
339 {"HPE_CB_url", "the on_url callback failed"},
340 {"HPE_CB_header_field", "the on_header_field callback failed"},
341 {"HPE_CB_header_value", "the on_header_value callback failed"},
342 {"HPE_CB_headers_complete", "the on_headers_complete callback failed"},
343 {"HPE_CB_body", "the on_body callback failed"},
344 {"HPE_CB_message_complete", "the on_message_complete callback failed"},
345 {"HPE_CB_status", "the on_status callback failed"},
346 {"HPE_CB_chunk_header", "the on_chunk_header callback failed"},
347 {"HPE_CB_chunk_complete", "the on_chunk_complete callback failed"},
348 {"HPE_INVALID_EOF_STATE", "stream ended at an unexpected time"},
349 {"HPE_HEADER_OVERFLOW", "too many header bytes seen; "
350 "overflow detected"},
351 {"HPE_CLOSED_CONNECTION", "data received after completed connection: "
352 "close message"},
353 {"HPE_INVALID_VERSION", "invalid HTTP version"},
354 {"HPE_INVALID_STATUS", "invalid HTTP status code"},
355 {"HPE_INVALID_METHOD", "invalid HTTP method"},
356 {"HPE_INVALID_URL", "invalid URL"},
357 {"HPE_INVALID_HOST", "invalid host"},
358 {"HPE_INVALID_PORT", "invalid port"},
359 {"HPE_INVALID_PATH", "invalid path"},
360 {"HPE_INVALID_QUERY_STRING", "invalid query string"},
361 {"HPE_INVALID_FRAGMENT", "invalid fragment"},
362 {"HPE_LF_EXPECTED", "LF character expected"},
363 {"HPE_INVALID_HEADER_TOKEN", "invalid character in header"},
364 {"HPE_INVALID_CONTENT_LENGTH", "invalid character in content-length "
365 "header"},
366 {"HPE_UNEXPECTED_CONTENT_LENGTH", "unexpected content-length header"},
367 {"HPE_INVALID_CONTENT_RANGE", "invalid character in content-range header"},
368 {"HPE_UNEXPECTED_CONTENT_RANGE", "unexpected content-range header"},
369 {"HPE_INVALID_CHUNK_SIZE", "invalid character in chunk size header"},
370 {"HPE_INVALID_CONSTANT", "invalid constant string"},
371 {"HPE_INVALID_INTERNAL_STATE", "encountered unexpected internal state"},
372 {"HPE_STRICT", "strict mode assertion failed"},
373 {"HPE_PAUSED", "parser is paused"},
374 {"HPE_UNKNOWN", "an unknown error occurred"}
375 };
376
377 int http_message_needs_eof(const struct http_parser *parser);
378
379 static
parser_header_state(struct http_parser * parser,char ch,char c)380 int parser_header_state(struct http_parser *parser, char ch, char c)
381 {
382 int cond1;
383
384 switch (parser->header_state) {
385 case h_general:
386 break;
387
388 case h_C:
389 parser->index++;
390 parser->header_state = (c == 'o' ? h_CO : h_general);
391 break;
392
393 case h_CO:
394 parser->index++;
395 parser->header_state = (c == 'n' ? h_CON : h_general);
396 break;
397
398 case h_CON:
399 parser->index++;
400 switch (c) {
401 case 'n':
402 parser->header_state = h_matching_connection;
403 break;
404 case 't':
405 parser->header_state = h_matching_content;
406 break;
407 default:
408 parser->header_state = h_general;
409 break;
410 }
411 break;
412
413 /* connection */
414
415 case h_matching_connection:
416 parser->index++;
417 cond1 = parser->index > sizeof(CONNECTION) - 1;
418 if (cond1 || c != CONNECTION[parser->index]) {
419 parser->header_state = h_general;
420 } else if (parser->index == sizeof(CONNECTION) - 2) {
421 parser->header_state = h_connection;
422 }
423 break;
424
425 /* proxy-connection */
426
427 case h_matching_proxy_connection:
428 parser->index++;
429 cond1 = parser->index > sizeof(PROXY_CONNECTION) - 1;
430 if (cond1 || c != PROXY_CONNECTION[parser->index]) {
431 parser->header_state = h_general;
432 } else if (parser->index == sizeof(PROXY_CONNECTION) - 2) {
433 parser->header_state = h_connection;
434 }
435 break;
436
437 /*content-length or content-range*/
438
439 case h_matching_content:
440 parser->index++;
441 cond1 = parser->index > sizeof(CONTENT) - 1;
442 if (cond1 || c != CONTENT[parser->index]) {
443 parser->header_state = h_general;
444 } else if (parser->index == sizeof(CONTENT) - 2) {
445 parser->header_state = h_CONTENT_;
446 }
447 break;
448
449 case h_CONTENT_:
450 parser->index++;
451 if (c == 'l') {
452 parser->header_state = h_matching_content_length;
453 } else if (c == 'r') {
454 parser->header_state = h_matching_content_range;
455 } else {
456 parser->header_state = h_general;
457 }
458 break;
459
460
461 case h_matching_content_length:
462 parser->index++;
463 cond1 = parser->index > sizeof(CONTENT_LENGTH) - 1;
464 if (cond1 || c != CONTENT_LENGTH[parser->index]) {
465 parser->header_state = h_general;
466 } else if (parser->index == sizeof(CONTENT_LENGTH) - 2) {
467 parser->header_state = h_content_length;
468 }
469 break;
470
471 case h_matching_content_range:
472 parser->index++;
473 cond1 = parser->index > sizeof(CONTENT_RANGE) - 1;
474 if (cond1 || c != CONTENT_RANGE[parser->index]) {
475 parser->header_state = h_general;
476 } else if (parser->index == sizeof(CONTENT_RANGE) - 2) {
477 parser->header_state = h_content_range_start;
478 }
479 break;
480
481 /* transfer-encoding */
482
483 case h_matching_transfer_encoding:
484 parser->index++;
485 cond1 = parser->index > sizeof(TRANSFER_ENCODING) - 1;
486 if (cond1 || c != TRANSFER_ENCODING[parser->index]) {
487 parser->header_state = h_general;
488 } else if (parser->index == sizeof(TRANSFER_ENCODING) - 2) {
489 parser->header_state = h_transfer_encoding;
490 }
491 break;
492
493 /* upgrade */
494
495 case h_matching_upgrade:
496 parser->index++;
497 cond1 = parser->index > sizeof(UPGRADE) - 1;
498 if (cond1 || c != UPGRADE[parser->index]) {
499 parser->header_state = h_general;
500 } else if (parser->index == sizeof(UPGRADE) - 2) {
501 parser->header_state = h_upgrade;
502 }
503 break;
504
505 case h_connection:
506 case h_content_length:
507 case h_content_range_start:
508 case h_content_range_end:
509 case h_content_range_total:
510 case h_transfer_encoding:
511 case h_upgrade:
512 if (ch != ' ') {
513 parser->header_state = h_general;
514 }
515 break;
516
517 default:
518 __ASSERT_NO_MSG(0 && "Unknown header_state");
519 break;
520 }
521 return 0;
522 }
523
524 static
header_states(struct http_parser * parser,const char * data,size_t len,const char ** ptr,enum state * p_state,enum header_states * header_state,char ch,char c)525 int header_states(struct http_parser *parser, const char *data, size_t len,
526 const char **ptr, enum state *p_state,
527 enum header_states *header_state, char ch, char c)
528 {
529 enum header_states h_state = *header_state;
530 const char *p = *ptr;
531 int cond1;
532
533 switch (h_state) {
534 case h_general: {
535 size_t limit = data + len - p;
536 const char *p_cr;
537 const char *p_lf;
538
539 limit = MIN(limit, HTTP_MAX_HEADER_SIZE);
540 p_cr = (const char *)memchr(p, CR, limit);
541 p_lf = (const char *)memchr(p, LF, limit);
542 if (p_cr != NULL) {
543 if (p_lf != NULL && p_cr >= p_lf) {
544 p = p_lf;
545 } else {
546 p = p_cr;
547 }
548 } else if (UNLIKELY(p_lf != NULL)) {
549 p = p_lf;
550 } else {
551 p = data + len;
552 }
553 --p;
554
555 break;
556 }
557
558 case h_connection:
559 case h_transfer_encoding:
560 __ASSERT_NO_MSG(0 && "Shouldn't get here.");
561 break;
562
563 case h_content_length: {
564 uint64_t t;
565 uint64_t value;
566
567 if (ch == ' ') {
568 break;
569 }
570
571 if (UNLIKELY(!IS_NUM(ch))) {
572 SET_ERRNO(HPE_INVALID_CONTENT_LENGTH);
573 parser->header_state = h_state;
574 return -1;
575 }
576
577 t = parser->content_length;
578 t *= 10U;
579 t += ch - '0';
580
581 /* Overflow? Test against a conservative limit for simplicity */
582 value = (ULLONG_MAX - 10) / 10;
583
584 if (UNLIKELY(value < parser->content_length)) {
585 SET_ERRNO(HPE_INVALID_CONTENT_LENGTH);
586 parser->header_state = h_state;
587 return -1;
588 }
589
590 parser->content_length = t;
591 break;
592 }
593
594 case h_content_range_start: {
595 uint64_t t;
596 uint64_t value;
597
598 if (IS_ALPHA(ch)) {
599 break;
600 }
601
602 if (ch == ' ') {
603 break;
604 }
605
606 if (ch == '-' || ch == '*') {
607 h_state = h_content_range_end;
608 break;
609 }
610
611 if (UNLIKELY(!IS_NUM(ch))) {
612 SET_ERRNO(HPE_INVALID_CONTENT_RANGE);
613 parser->header_state = h_state;
614 return -1;
615 }
616
617 t = parser->content_range.start;
618 t *= 10U;
619 t += ch - '0';
620
621 /* Overflow? Test against a conservative limit for simplicity */
622 value = (ULLONG_MAX - 10) / 10;
623
624 if (UNLIKELY(value < parser->content_range.start)) {
625 SET_ERRNO(HPE_INVALID_CONTENT_RANGE);
626 parser->header_state = h_state;
627 return -1;
628 }
629
630 parser->content_range.start = t;
631 break;
632 }
633
634 case h_content_range_end: {
635 uint64_t t;
636 uint64_t value;
637
638 if (ch == ' ') {
639 break;
640 }
641
642 if (ch == '/') {
643 h_state = h_content_range_total;
644 break;
645 }
646
647 if (UNLIKELY(!IS_NUM(ch))) {
648 SET_ERRNO(HPE_INVALID_CONTENT_RANGE);
649 parser->header_state = h_state;
650 return -1;
651 }
652
653 t = parser->content_range.end;
654 t *= 10U;
655 t += ch - '0';
656
657 /* Overflow? Test against a conservative limit for simplicity */
658 value = (ULLONG_MAX - 10) / 10;
659
660 if (UNLIKELY(value < parser->content_range.end)) {
661 SET_ERRNO(HPE_INVALID_CONTENT_RANGE);
662 parser->header_state = h_state;
663 return -1;
664 }
665
666 parser->content_range.end = t;
667 break;
668 }
669
670 case h_content_range_total: {
671 uint64_t t;
672 uint64_t value;
673
674 if (ch == ' ') {
675 break;
676 }
677
678 if (ch == '*') {
679 break;
680 }
681
682 if (UNLIKELY(!IS_NUM(ch))) {
683 SET_ERRNO(HPE_INVALID_CONTENT_RANGE);
684 parser->header_state = h_state;
685 return -1;
686 }
687
688 t = parser->content_range.total;
689 t *= 10U;
690 t += ch - '0';
691
692 /* Overflow? Test against a conservative limit for simplicity */
693 value = (ULLONG_MAX - 10) / 10;
694
695 if (UNLIKELY(value < parser->content_range.total)) {
696 SET_ERRNO(HPE_INVALID_CONTENT_RANGE);
697 parser->header_state = h_state;
698 return -1;
699 }
700
701 parser->content_range.total = t;
702 break;
703 }
704
705 /* Transfer-Encoding: chunked */
706 case h_matching_transfer_encoding_chunked:
707 parser->index++;
708 cond1 = parser->index > sizeof(CHUNKED) - 1;
709 if (cond1 || c != CHUNKED[parser->index]) {
710 h_state = h_general;
711 } else if (parser->index == sizeof(CHUNKED) - 2) {
712 h_state = h_transfer_encoding_chunked;
713 }
714 break;
715
716 case h_matching_connection_token_start:
717 /* looking for 'Connection: keep-alive' */
718 if (c == 'k') {
719 h_state = h_matching_connection_keep_alive;
720 /* looking for 'Connection: close' */
721 } else if (c == 'c') {
722 h_state = h_matching_connection_close;
723 } else if (c == 'u') {
724 h_state = h_matching_connection_upgrade;
725 } else if (STRICT_TOKEN(c)) {
726 h_state = h_matching_connection_token;
727 } else if (c == ' ' || c == '\t') {
728 /* Skip lws */
729 } else {
730 h_state = h_general;
731 }
732 break;
733
734 /* looking for 'Connection: keep-alive' */
735 case h_matching_connection_keep_alive:
736 parser->index++;
737 cond1 = parser->index > sizeof(KEEP_ALIVE) - 1;
738 if (cond1 || c != KEEP_ALIVE[parser->index]) {
739 h_state = h_matching_connection_token;
740 } else if (parser->index == sizeof(KEEP_ALIVE) - 2) {
741 h_state = h_connection_keep_alive;
742 }
743 break;
744
745 /* looking for 'Connection: close' */
746 case h_matching_connection_close:
747 parser->index++;
748 cond1 = parser->index > sizeof(CLOSE) - 1;
749 if (cond1 || c != CLOSE[parser->index]) {
750 h_state = h_matching_connection_token;
751 } else if (parser->index == sizeof(CLOSE) - 2) {
752 h_state = h_connection_close;
753 }
754 break;
755
756 /* looking for 'Connection: upgrade' */
757 case h_matching_connection_upgrade:
758 parser->index++;
759 cond1 = parser->index > sizeof(UPGRADE) - 1;
760 if (cond1 || c != UPGRADE[parser->index]) {
761 h_state = h_matching_connection_token;
762 } else if (parser->index == sizeof(UPGRADE) - 2) {
763 h_state = h_connection_upgrade;
764 }
765 break;
766
767 case h_matching_connection_token:
768 if (ch == ',') {
769 h_state = h_matching_connection_token_start;
770 parser->index = 0U;
771 }
772 break;
773
774 case h_transfer_encoding_chunked:
775 if (ch != ' ') {
776 h_state = h_general;
777 }
778 break;
779
780 case h_connection_keep_alive:
781 case h_connection_close:
782 case h_connection_upgrade:
783 if (ch == ',') {
784 if (h_state == h_connection_keep_alive) {
785 parser->flags |= F_CONNECTION_KEEP_ALIVE;
786 } else if (h_state == h_connection_close) {
787 parser->flags |= F_CONNECTION_CLOSE;
788 } else if (h_state == h_connection_upgrade) {
789 parser->flags |= F_CONNECTION_UPGRADE;
790 }
791 h_state = h_matching_connection_token_start;
792 parser->index = 0U;
793 } else if (ch != ' ') {
794 h_state = h_matching_connection_token;
795 }
796 break;
797
798 default:
799 *p_state = s_header_value;
800 h_state = h_general;
801 break;
802 }
803
804 *header_state = h_state;
805 *ptr = p;
806
807 return 0;
808 }
809
810 static
zero_content_length(struct http_parser * parser,const struct http_parser_settings * settings,enum state * current_state,size_t * parsed,const char * p,const char * data)811 int zero_content_length(struct http_parser *parser,
812 const struct http_parser_settings *settings,
813 enum state *current_state, size_t *parsed,
814 const char *p, const char *data)
815 {
816 enum state p_state = *current_state;
817 int rc;
818
819 if (parser->content_length == 0U) {
820 /* Content-Length header given but zero:
821 * Content-Length: 0\r\n
822 */
823 UPDATE_STATE(NEW_MESSAGE());
824
825 rc = cb_notify(parser, &p_state, settings->on_message_complete,
826 HPE_CB_message_complete, parsed, p - data + 1);
827 if (rc != 0) {
828 return rc;
829 }
830
831 } else if (parser->content_length != ULLONG_MAX) {
832 /* Content-Length header given and
833 * non-zero
834 */
835 UPDATE_STATE(s_body_identity);
836 } else {
837 if (!http_message_needs_eof(parser)) {
838 /* Assume content-length 0 -
839 * read the next
840 */
841 UPDATE_STATE(NEW_MESSAGE());
842
843 rc = cb_notify(parser, &p_state,
844 settings->on_message_complete,
845 HPE_CB_message_complete, parsed,
846 p - data + 1);
847 if (rc != 0) {
848 return rc;
849 }
850
851 } else {
852 /* Read body until EOF */
853 UPDATE_STATE(s_body_identity_eof);
854 }
855 }
856
857 *current_state = p_state;
858
859 return 0;
860 }
861
862 static
parser_execute(struct http_parser * parser,const struct http_parser_settings * settings,const char * data,size_t len,size_t * parsed)863 int parser_execute(struct http_parser *parser,
864 const struct http_parser_settings *settings,
865 const char *data, size_t len, size_t *parsed)
866 {
867 const unsigned int lenient = parser->lenient_http_headers;
868 enum state p_state = (enum state) parser->state;
869 const char *p = data;
870 const char *header_field_mark = 0;
871 const char *header_value_mark = 0;
872 const char *url_mark = 0;
873 const char *body_mark = 0;
874 const char *status_mark = 0;
875 int8_t unhex_val;
876 int rc;
877 char ch;
878 char c;
879
880 *parsed = 0;
881
882 /* We're in an error state. Don't bother doing anything. */
883 if (HTTP_PARSER_ERRNO(parser) != HPE_OK) {
884 return 0;
885 }
886
887 if (len == 0) {
888 switch (CURRENT_STATE()) {
889 case s_body_identity_eof:
890 /* Use of CALLBACK_NOTIFY() here would erroneously
891 * return 1 byte read if
892 * we got paused.
893 */
894 cb_notify(parser, &p_state,
895 settings->on_message_complete,
896 HPE_CB_message_complete, parsed, p - data);
897 return 0;
898
899 case s_dead:
900 case s_start_req_or_res:
901 case s_start_res:
902 case s_start_req:
903 return 0;
904
905 default:
906 SET_ERRNO(HPE_INVALID_EOF_STATE);
907 return 1;
908 }
909 }
910
911
912 if (CURRENT_STATE() == s_header_field) {
913 header_field_mark = data;
914 }
915 if (CURRENT_STATE() == s_header_value) {
916 header_value_mark = data;
917 }
918 switch (CURRENT_STATE()) {
919 case s_req_path:
920 case s_req_schema:
921 case s_req_schema_slash:
922 case s_req_schema_slash_slash:
923 case s_req_server_start:
924 case s_req_server:
925 case s_req_server_with_at:
926 case s_req_query_string_start:
927 case s_req_query_string:
928 case s_req_fragment_start:
929 case s_req_fragment:
930 url_mark = data;
931 break;
932 case s_res_status:
933 status_mark = data;
934 break;
935 default:
936 break;
937 }
938
939 for (p = data; p != data + len; p++) {
940 ch = *p;
941
942 if (PARSING_HEADER(CURRENT_STATE())) {
943 rc = count_header_size(parser, 1);
944 if (rc != 0) {
945 goto error;
946 }
947 }
948
949 reexecute:
950 switch (CURRENT_STATE()) {
951
952 case s_dead:
953 /* this state is used after a 'Connection: close'
954 * message
955 * the parser will error out if it reads another message
956 */
957 if (LIKELY(ch == CR || ch == LF)) {
958 break;
959 }
960
961 SET_ERRNO(HPE_CLOSED_CONNECTION);
962 goto error;
963
964 case s_start_req_or_res: {
965 if (ch == CR || ch == LF) {
966 break;
967 }
968 parser->flags = 0U;
969 parser->content_length = ULLONG_MAX;
970 parser->content_range.start = 0U;
971 parser->content_range.end = 0U;
972 parser->content_range.total = 0U;
973 parser->content_range_present = false;
974
975 if (ch == 'H') {
976 UPDATE_STATE(s_res_or_resp_H);
977
978 rc = cb_notify(parser, &p_state,
979 settings->on_message_begin,
980 HPE_CB_message_begin,
981 parsed, p - data + 1);
982 if (rc != 0) {
983 return rc;
984 }
985 } else {
986 parser->type = HTTP_REQUEST;
987 UPDATE_STATE(s_start_req);
988 goto reexecute;
989 }
990
991 break;
992 }
993
994 case s_res_or_resp_H:
995 if (ch == 'T') {
996 parser->type = HTTP_RESPONSE;
997 UPDATE_STATE(s_res_HT);
998 } else {
999 if (UNLIKELY(ch != 'E')) {
1000 SET_ERRNO(HPE_INVALID_CONSTANT);
1001 goto error;
1002 }
1003
1004 parser->type = HTTP_REQUEST;
1005 parser->method = HTTP_HEAD;
1006 parser->index = 2U;
1007 UPDATE_STATE(s_req_method);
1008 }
1009 break;
1010
1011 case s_start_res: {
1012 parser->flags = 0U;
1013 parser->content_length = ULLONG_MAX;
1014
1015 switch (ch) {
1016 case 'H':
1017 UPDATE_STATE(s_res_H);
1018 break;
1019
1020 case CR:
1021 case LF:
1022 break;
1023
1024 default:
1025 SET_ERRNO(HPE_INVALID_CONSTANT);
1026 goto error;
1027 }
1028
1029
1030 rc = cb_notify(parser, &p_state,
1031 settings->on_message_begin,
1032 HPE_CB_message_begin, parsed,
1033 p - data + 1);
1034 if (rc != 0) {
1035 return rc;
1036 }
1037 break;
1038 }
1039
1040 case s_res_H:
1041 rc = strict_check(parser, ch != 'T');
1042 if (rc != 0) {
1043 goto error;
1044 }
1045 UPDATE_STATE(s_res_HT);
1046 break;
1047
1048 case s_res_HT:
1049 rc = strict_check(parser, ch != 'T');
1050 if (rc != 0) {
1051 goto error;
1052 }
1053 UPDATE_STATE(s_res_HTT);
1054 break;
1055
1056 case s_res_HTT:
1057 rc = strict_check(parser, ch != 'P');
1058 if (rc != 0) {
1059 goto error;
1060 }
1061 UPDATE_STATE(s_res_HTTP);
1062 break;
1063
1064 case s_res_HTTP:
1065 rc = strict_check(parser, ch != '/');
1066 if (rc != 0) {
1067 goto error;
1068 }
1069 UPDATE_STATE(s_res_first_http_major);
1070 break;
1071
1072 case s_res_first_http_major:
1073 if (UNLIKELY(ch < '0' || ch > '9')) {
1074 SET_ERRNO(HPE_INVALID_VERSION);
1075 goto error;
1076 }
1077
1078 parser->http_major = ch - '0';
1079 UPDATE_STATE(s_res_http_major);
1080 break;
1081
1082 /* major HTTP version or dot */
1083 case s_res_http_major: {
1084 if (ch == '.') {
1085 UPDATE_STATE(s_res_first_http_minor);
1086 break;
1087 }
1088
1089 if (!IS_NUM(ch)) {
1090 SET_ERRNO(HPE_INVALID_VERSION);
1091 goto error;
1092 }
1093
1094 parser->http_major *= 10U;
1095 parser->http_major += ch - '0';
1096
1097 if (UNLIKELY(parser->http_major > 999)) {
1098 SET_ERRNO(HPE_INVALID_VERSION);
1099 goto error;
1100 }
1101
1102 break;
1103 }
1104
1105 /* first digit of minor HTTP version */
1106 case s_res_first_http_minor:
1107 if (UNLIKELY(!IS_NUM(ch))) {
1108 SET_ERRNO(HPE_INVALID_VERSION);
1109 goto error;
1110 }
1111
1112 parser->http_minor = ch - '0';
1113 UPDATE_STATE(s_res_http_minor);
1114 break;
1115
1116 /* minor HTTP version or end of request line */
1117 case s_res_http_minor: {
1118 if (ch == ' ') {
1119 UPDATE_STATE(s_res_first_status_code);
1120 break;
1121 }
1122
1123 if (UNLIKELY(!IS_NUM(ch))) {
1124 SET_ERRNO(HPE_INVALID_VERSION);
1125 goto error;
1126 }
1127
1128 parser->http_minor *= 10U;
1129 parser->http_minor += ch - '0';
1130
1131 if (UNLIKELY(parser->http_minor > 999)) {
1132 SET_ERRNO(HPE_INVALID_VERSION);
1133 goto error;
1134 }
1135
1136 break;
1137 }
1138
1139 case s_res_first_status_code: {
1140 if (!IS_NUM(ch)) {
1141 if (ch == ' ') {
1142 break;
1143 }
1144
1145 SET_ERRNO(HPE_INVALID_STATUS);
1146 goto error;
1147 }
1148 parser->status_code = ch - '0';
1149 UPDATE_STATE(s_res_status_code);
1150 break;
1151 }
1152
1153 case s_res_status_code: {
1154 if (!IS_NUM(ch)) {
1155 /* Numeric status only */
1156 if ((ch == CR) || (ch == LF)) {
1157 const char *no_status_txt = "";
1158
1159 rc = cb_data(parser,
1160 settings->on_status,
1161 HPE_CB_status, &p_state, parsed,
1162 p - data + 1, &no_status_txt, 0);
1163 if (rc != 0) {
1164 return rc;
1165 }
1166 }
1167
1168 switch (ch) {
1169 case ' ':
1170 UPDATE_STATE(s_res_status_start);
1171 break;
1172 case CR:
1173 UPDATE_STATE(s_res_line_almost_done);
1174 break;
1175 case LF:
1176 UPDATE_STATE(s_header_field_start);
1177 break;
1178 default:
1179 SET_ERRNO(HPE_INVALID_STATUS);
1180 goto error;
1181 }
1182 break;
1183 }
1184
1185 parser->status_code *= 10U;
1186 parser->status_code += ch - '0';
1187
1188 if (UNLIKELY(parser->status_code > 999)) {
1189 SET_ERRNO(HPE_INVALID_STATUS);
1190 goto error;
1191 }
1192
1193 break;
1194 }
1195
1196 case s_res_status_start: {
1197 if (!status_mark && ((ch == CR) || (ch == LF))) {
1198 /* Numeric status only */
1199 const char *no_status_txt = "";
1200
1201 rc = cb_data(parser,
1202 settings->on_status,
1203 HPE_CB_status, &p_state, parsed,
1204 p - data + 1, &no_status_txt, 0);
1205 if (rc != 0) {
1206 return rc;
1207 }
1208 }
1209 if (ch == CR) {
1210 UPDATE_STATE(s_res_line_almost_done);
1211 break;
1212 }
1213
1214 if (ch == LF) {
1215 UPDATE_STATE(s_header_field_start);
1216 break;
1217 }
1218
1219 MARK(status);
1220 UPDATE_STATE(s_res_status);
1221 parser->index = 0U;
1222 break;
1223 }
1224
1225 case s_res_status:
1226 if (ch == CR) {
1227 UPDATE_STATE(s_res_line_almost_done);
1228 rc = cb_data(parser, settings->on_status,
1229 HPE_CB_status, &p_state, parsed,
1230 p - data + 1, &status_mark,
1231 p - status_mark);
1232 if (rc != 0) {
1233 return rc;
1234 }
1235 break;
1236 }
1237
1238 if (ch == LF) {
1239 UPDATE_STATE(s_header_field_start);
1240 rc = cb_data(parser, settings->on_status,
1241 HPE_CB_status, &p_state, parsed,
1242 p - data + 1, &status_mark,
1243 p - status_mark);
1244 if (rc != 0) {
1245 return rc;
1246 }
1247
1248 break;
1249 }
1250
1251 break;
1252
1253 case s_res_line_almost_done:
1254 rc = strict_check(parser, ch != LF);
1255 if (rc != 0) {
1256 goto error;
1257 }
1258 UPDATE_STATE(s_header_field_start);
1259 break;
1260
1261 case s_start_req: {
1262 if (ch == CR || ch == LF) {
1263 break;
1264 }
1265 parser->flags = 0U;
1266 parser->content_length = ULLONG_MAX;
1267 parser->content_range.start = 0U;
1268 parser->content_range.end = 0U;
1269 parser->content_range.total = 0U;
1270 parser->content_range_present = false;
1271
1272 if (UNLIKELY(!IS_ALPHA(ch))) {
1273 SET_ERRNO(HPE_INVALID_METHOD);
1274 goto error;
1275 }
1276
1277 parser->method = (enum http_method) 0;
1278 parser->index = 1U;
1279 switch (ch) {
1280 case 'A':
1281 parser->method = HTTP_ACL;
1282 break;
1283 case 'B':
1284 parser->method = HTTP_BIND;
1285 break;
1286 case 'C':
1287 parser->method = HTTP_CONNECT;
1288 /* or COPY, CHECKOUT */
1289 break;
1290 case 'D':
1291 parser->method = HTTP_DELETE;
1292 break;
1293 case 'G':
1294 parser->method = HTTP_GET;
1295 break;
1296 case 'H':
1297 parser->method = HTTP_HEAD;
1298 break;
1299 case 'L':
1300 parser->method = HTTP_LOCK; /* or LINK */
1301 break;
1302 case 'M':
1303 parser->method =
1304 HTTP_MKCOL;
1305 /* or MOVE, MKACTIVITY, MERGE, M-SEARCH,
1306 * MKCALENDAR
1307 */
1308 break;
1309 case 'N':
1310 parser->method = HTTP_NOTIFY;
1311 break;
1312 case 'O':
1313 parser->method = HTTP_OPTIONS;
1314 break;
1315 case 'P':
1316 parser->method = HTTP_POST;
1317 /* or PROPFIND|PROPPATCH|PUT|PATCH|PURGE */
1318 break;
1319 case 'R':
1320 parser->method = HTTP_REPORT; /* or REBIND */
1321 break;
1322 case 'S':
1323 parser->method = HTTP_SUBSCRIBE; /* or SEARCH */
1324 break;
1325 case 'T':
1326 parser->method = HTTP_TRACE;
1327 break;
1328 case 'U':
1329 parser->method = HTTP_UNLOCK;
1330 /* or UNSUBSCRIBE, UNBIND, UNLINK */
1331 break;
1332 default:
1333 SET_ERRNO(HPE_INVALID_METHOD);
1334 goto error;
1335 }
1336 UPDATE_STATE(s_req_method);
1337
1338
1339 rc = cb_notify(parser, &p_state,
1340 settings->on_message_begin,
1341 HPE_CB_message_begin, parsed,
1342 p - data + 1);
1343 if (rc != 0) {
1344 return rc;
1345 }
1346 break;
1347 }
1348
1349 case s_req_method: {
1350 const char *matcher;
1351
1352 if (UNLIKELY(ch == '\0')) {
1353 SET_ERRNO(HPE_INVALID_METHOD);
1354 goto error;
1355 }
1356
1357 matcher = method_strings[parser->method];
1358 if (ch == ' ' && matcher[parser->index] == '\0') {
1359 UPDATE_STATE(s_req_spaces_before_url);
1360 } else if (ch == matcher[parser->index]) {
1361 ; /* nada */
1362 } else if (IS_ALPHA(ch)) {
1363
1364 uint64_t sw_option = parser->method << 16 |
1365 parser->index << 8 | ch;
1366 switch (sw_option) {
1367 case (HTTP_POST << 16 | 1 << 8 | 'U'):
1368 parser->method = HTTP_PUT;
1369 break;
1370 case (HTTP_POST << 16 | 1 << 8 | 'A'):
1371 parser->method = HTTP_PATCH;
1372 break;
1373 case (HTTP_CONNECT << 16 | 1 << 8 | 'H'):
1374 parser->method = HTTP_CHECKOUT;
1375 break;
1376 case (HTTP_CONNECT << 16 | 2 << 8 | 'P'):
1377 parser->method = HTTP_COPY;
1378 break;
1379 case (HTTP_MKCOL << 16 | 1 << 8 | 'O'):
1380 parser->method = HTTP_MOVE;
1381 break;
1382 case (HTTP_MKCOL << 16 | 1 << 8 | 'E'):
1383 parser->method = HTTP_MERGE;
1384 break;
1385 case (HTTP_MKCOL << 16 | 2 << 8 | 'A'):
1386 parser->method = HTTP_MKACTIVITY;
1387 break;
1388 case (HTTP_MKCOL << 16 | 3 << 8 | 'A'):
1389 parser->method = HTTP_MKCALENDAR;
1390 break;
1391 case (HTTP_SUBSCRIBE << 16 | 1 << 8 | 'E'):
1392 parser->method = HTTP_SEARCH;
1393 break;
1394 case (HTTP_REPORT << 16 | 2 << 8 | 'B'):
1395 parser->method = HTTP_REBIND;
1396 break;
1397 case (HTTP_POST << 16 | 1 << 8 | 'R'):
1398 parser->method = HTTP_PROPFIND;
1399 break;
1400 case (HTTP_PROPFIND << 16 | 4 << 8 | 'P'):
1401 parser->method = HTTP_PROPPATCH;
1402 break;
1403 case (HTTP_PUT << 16 | 2 << 8 | 'R'):
1404 parser->method = HTTP_PURGE;
1405 break;
1406 case (HTTP_LOCK << 16 | 1 << 8 | 'I'):
1407 parser->method = HTTP_LINK;
1408 break;
1409 case (HTTP_UNLOCK << 16 | 2 << 8 | 'S'):
1410 parser->method = HTTP_UNSUBSCRIBE;
1411 break;
1412 case (HTTP_UNLOCK << 16 | 2 << 8 | 'B'):
1413 parser->method = HTTP_UNBIND;
1414 break;
1415 case (HTTP_UNLOCK << 16 | 3 << 8 | 'I'):
1416 parser->method = HTTP_UNLINK;
1417 break;
1418 default:
1419 parser->http_errno = HPE_INVALID_METHOD;
1420 goto error;
1421 }
1422 } else if (ch == '-' &&
1423 parser->index == 1U &&
1424 parser->method == HTTP_MKCOL) {
1425 parser->method = HTTP_MSEARCH;
1426 } else {
1427 SET_ERRNO(HPE_INVALID_METHOD);
1428 goto error;
1429 }
1430
1431 ++parser->index;
1432 break;
1433 }
1434
1435 case s_req_spaces_before_url: {
1436 if (ch == ' ') {
1437 break;
1438 }
1439
1440 MARK(url);
1441 if (parser->method == HTTP_CONNECT) {
1442 UPDATE_STATE(s_req_server_start);
1443 }
1444
1445 UPDATE_STATE(parse_url_char(CURRENT_STATE(), ch));
1446 if (UNLIKELY(CURRENT_STATE() == s_dead)) {
1447 SET_ERRNO(HPE_INVALID_URL);
1448 goto error;
1449 }
1450
1451 break;
1452 }
1453
1454 case s_req_schema:
1455 case s_req_schema_slash:
1456 case s_req_schema_slash_slash:
1457 case s_req_server_start: {
1458 switch (ch) {
1459 /* No whitespace allowed here */
1460 case ' ':
1461 case CR:
1462 case LF:
1463 SET_ERRNO(HPE_INVALID_URL);
1464 goto error;
1465 default:
1466 UPDATE_STATE
1467 (parse_url_char(CURRENT_STATE(), ch));
1468 if (UNLIKELY(CURRENT_STATE() == s_dead)) {
1469 SET_ERRNO(HPE_INVALID_URL);
1470 goto error;
1471 }
1472 }
1473
1474 break;
1475 }
1476
1477 case s_req_server:
1478 case s_req_server_with_at:
1479 case s_req_path:
1480 case s_req_query_string_start:
1481 case s_req_query_string:
1482 case s_req_fragment_start:
1483 case s_req_fragment: {
1484 switch (ch) {
1485 case ' ':
1486 UPDATE_STATE(s_req_http_start);
1487 rc = cb_data(parser, settings->on_url,
1488 HPE_CB_url, &p_state, parsed,
1489 p - data + 1, &url_mark,
1490 p - url_mark);
1491 if (rc != 0) {
1492 return rc;
1493 }
1494
1495 break;
1496 case CR:
1497 case LF:
1498 parser->http_major = 0U;
1499 parser->http_minor = 9U;
1500 UPDATE_STATE((ch == CR) ?
1501 s_req_line_almost_done :
1502 s_header_field_start);
1503 rc = cb_data(parser, settings->on_url,
1504 HPE_CB_url, &p_state, parsed,
1505 p - data + 1, &url_mark,
1506 p - url_mark);
1507 if (rc != 0) {
1508 return rc;
1509 }
1510
1511 break;
1512 default:
1513 UPDATE_STATE
1514 (parse_url_char(CURRENT_STATE(), ch));
1515 if (UNLIKELY(CURRENT_STATE() == s_dead)) {
1516 SET_ERRNO(HPE_INVALID_URL);
1517 goto error;
1518 }
1519 }
1520 break;
1521 }
1522
1523 case s_req_http_start:
1524 switch (ch) {
1525 case 'H':
1526 UPDATE_STATE(s_req_http_H);
1527 break;
1528 case ' ':
1529 break;
1530 default:
1531 SET_ERRNO(HPE_INVALID_CONSTANT);
1532 goto error;
1533 }
1534 break;
1535
1536 case s_req_http_H:
1537 rc = strict_check(parser, ch != 'T');
1538 if (rc != 0) {
1539 goto error;
1540 }
1541 UPDATE_STATE(s_req_http_HT);
1542 break;
1543
1544 case s_req_http_HT:
1545 rc = strict_check(parser, ch != 'T');
1546 if (rc != 0) {
1547 goto error;
1548 }
1549 UPDATE_STATE(s_req_http_HTT);
1550 break;
1551
1552 case s_req_http_HTT:
1553 rc = strict_check(parser, ch != 'P');
1554 if (rc != 0) {
1555 goto error;
1556 }
1557 UPDATE_STATE(s_req_http_HTTP);
1558 break;
1559
1560 case s_req_http_HTTP:
1561 rc = strict_check(parser, ch != '/');
1562 if (rc != 0) {
1563 goto error;
1564 }
1565 UPDATE_STATE(s_req_first_http_major);
1566 break;
1567
1568 /* first digit of major HTTP version */
1569 case s_req_first_http_major:
1570 if (UNLIKELY(ch < '1' || ch > '9')) {
1571 SET_ERRNO(HPE_INVALID_VERSION);
1572 goto error;
1573 }
1574
1575 parser->http_major = ch - '0';
1576 UPDATE_STATE(s_req_http_major);
1577 break;
1578
1579 /* major HTTP version or dot */
1580 case s_req_http_major: {
1581 if (ch == '.') {
1582 UPDATE_STATE(s_req_first_http_minor);
1583 break;
1584 }
1585
1586 if (UNLIKELY(!IS_NUM(ch))) {
1587 SET_ERRNO(HPE_INVALID_VERSION);
1588 goto error;
1589 }
1590
1591 parser->http_major *= 10U;
1592 parser->http_major += ch - '0';
1593
1594 if (UNLIKELY(parser->http_major > 999)) {
1595 SET_ERRNO(HPE_INVALID_VERSION);
1596 goto error;
1597 }
1598
1599 break;
1600 }
1601
1602 /* first digit of minor HTTP version */
1603 case s_req_first_http_minor:
1604 if (UNLIKELY(!IS_NUM(ch))) {
1605 SET_ERRNO(HPE_INVALID_VERSION);
1606 goto error;
1607 }
1608
1609 parser->http_minor = ch - '0';
1610 UPDATE_STATE(s_req_http_minor);
1611 break;
1612
1613 /* minor HTTP version or end of request line */
1614 case s_req_http_minor: {
1615 if (ch == CR) {
1616 UPDATE_STATE(s_req_line_almost_done);
1617 break;
1618 }
1619
1620 if (ch == LF) {
1621 UPDATE_STATE(s_header_field_start);
1622 break;
1623 }
1624
1625 /* XXX allow spaces after digit? */
1626
1627 if (UNLIKELY(!IS_NUM(ch))) {
1628 SET_ERRNO(HPE_INVALID_VERSION);
1629 goto error;
1630 }
1631
1632 parser->http_minor *= 10U;
1633 parser->http_minor += ch - '0';
1634
1635 if (UNLIKELY(parser->http_minor > 999)) {
1636 SET_ERRNO(HPE_INVALID_VERSION);
1637 goto error;
1638 }
1639
1640 break;
1641 }
1642
1643 /* end of request line */
1644 case s_req_line_almost_done: {
1645 if (UNLIKELY(ch != LF)) {
1646 SET_ERRNO(HPE_LF_EXPECTED);
1647 goto error;
1648 }
1649
1650 UPDATE_STATE(s_header_field_start);
1651 break;
1652 }
1653
1654 case s_header_field_start: {
1655 if (ch == CR) {
1656 UPDATE_STATE(s_headers_almost_done);
1657 break;
1658 }
1659
1660 if (ch == LF) {
1661 /* they might be just sending \n instead of \r\n
1662 * so this would be
1663 * the second \n to denote the end of headers
1664 */
1665 UPDATE_STATE(s_headers_almost_done);
1666 goto reexecute;
1667 }
1668
1669 c = TOKEN(ch);
1670
1671 if (UNLIKELY(!c)) {
1672 SET_ERRNO(HPE_INVALID_HEADER_TOKEN);
1673 goto error;
1674 }
1675
1676 MARK(header_field);
1677
1678 parser->index = 0U;
1679 UPDATE_STATE(s_header_field);
1680
1681 switch (c) {
1682 case 'c':
1683 parser->header_state = h_C;
1684 break;
1685
1686 case 'p':
1687 parser->header_state =
1688 h_matching_proxy_connection;
1689 break;
1690
1691 case 't':
1692 parser->header_state =
1693 h_matching_transfer_encoding;
1694 break;
1695
1696 case 'u':
1697 parser->header_state = h_matching_upgrade;
1698 break;
1699
1700 default:
1701 parser->header_state = h_general;
1702 break;
1703 }
1704 break;
1705 }
1706
1707 case s_header_field: {
1708 const char *start = p;
1709
1710 for (; p != data + len; p++) {
1711 ch = *p;
1712 c = TOKEN(ch);
1713
1714 if (!c) {
1715 break;
1716 }
1717 parser_header_state(parser, ch, c);
1718 }
1719
1720 rc = count_header_size(parser, p - start);
1721 if (rc != 0) {
1722 goto error;
1723 }
1724
1725 if (p == data + len) {
1726 --p;
1727 break;
1728 }
1729
1730 if (ch == ':') {
1731 UPDATE_STATE(s_header_value_discard_ws);
1732 rc = cb_data(parser, settings->on_header_field,
1733 HPE_CB_header_field, &p_state,
1734 parsed, p - data + 1,
1735 &header_field_mark,
1736 p - header_field_mark);
1737 if (rc != 0) {
1738 return rc;
1739 }
1740
1741 break;
1742 }
1743
1744 SET_ERRNO(HPE_INVALID_HEADER_TOKEN);
1745 goto error;
1746 }
1747
1748 case s_header_value_discard_ws:
1749 if (ch == ' ' || ch == '\t') {
1750 break;
1751 }
1752
1753 if (ch == CR) {
1754 UPDATE_STATE
1755 (s_header_value_discard_ws_almost_done);
1756 break;
1757 }
1758
1759 if (ch == LF) {
1760 UPDATE_STATE(s_header_value_discard_lws);
1761 break;
1762 }
1763
1764 __fallthrough;
1765
1766 case s_header_value_start: {
1767 MARK(header_value);
1768
1769 UPDATE_STATE(s_header_value);
1770 parser->index = 0U;
1771
1772 c = LOWER(ch);
1773
1774 switch (parser->header_state) {
1775 case h_upgrade:
1776 parser->flags |= F_UPGRADE;
1777 parser->header_state = h_general;
1778 break;
1779
1780 case h_transfer_encoding:
1781 /* looking for 'Transfer-Encoding: chunked' */
1782 if ('c' == c) {
1783 parser->header_state =
1784 h_matching_transfer_encoding_chunked;
1785 } else {
1786 parser->header_state = h_general;
1787 }
1788 break;
1789
1790 case h_content_length:
1791 if (UNLIKELY(!IS_NUM(ch))) {
1792 SET_ERRNO(HPE_INVALID_CONTENT_LENGTH);
1793 goto error;
1794 }
1795
1796 if (parser->flags & F_CONTENTLENGTH) {
1797 SET_ERRNO
1798 (HPE_UNEXPECTED_CONTENT_LENGTH);
1799 goto error;
1800 }
1801
1802 parser->flags |= F_CONTENTLENGTH;
1803 parser->content_length = ch - '0';
1804 break;
1805
1806 case h_content_range_start:
1807 if (parser->content_range_present) {
1808 SET_ERRNO(HPE_UNEXPECTED_CONTENT_RANGE);
1809 goto error;
1810 }
1811
1812 parser->content_range_present = true;
1813 parser->content_range.start = 0;
1814 break;
1815
1816 case h_connection:
1817 /* looking for 'Connection: keep-alive' */
1818 if (c == 'k') {
1819 parser->header_state =
1820 h_matching_connection_keep_alive;
1821 /* looking for 'Connection: close' */
1822 } else if (c == 'c') {
1823 parser->header_state =
1824 h_matching_connection_close;
1825 } else if (c == 'u') {
1826 parser->header_state =
1827 h_matching_connection_upgrade;
1828 } else {
1829 parser->header_state =
1830 h_matching_connection_token;
1831 }
1832 break;
1833
1834 /* Multi-value `Connection` header */
1835 case h_matching_connection_token_start:
1836 break;
1837
1838 default:
1839 parser->header_state = h_general;
1840 break;
1841 }
1842 break;
1843 }
1844
1845 case s_header_value: {
1846 const char *start = p;
1847 enum header_states h_state =
1848 (enum header_states)parser->header_state;
1849
1850 for (; p != data + len; p++) {
1851 ch = *p;
1852 if (ch == CR) {
1853 UPDATE_STATE(s_header_almost_done);
1854 parser->header_state = h_state;
1855 rc = cb_data(parser,
1856 settings->on_header_value,
1857 HPE_CB_header_value,
1858 &p_state, parsed,
1859 p - data + 1,
1860 &header_value_mark,
1861 p - header_value_mark);
1862 if (rc != 0) {
1863 return rc;
1864 }
1865
1866 break;
1867 }
1868
1869 if (ch == LF) {
1870 UPDATE_STATE(s_header_almost_done);
1871 rc = count_header_size(parser,
1872 p - start);
1873 if (rc != 0) {
1874 goto error;
1875 }
1876 parser->header_state = h_state;
1877 rc = cb_data(parser,
1878 settings->on_header_value,
1879 HPE_CB_header_value,
1880 &p_state, parsed, p - data,
1881 &header_value_mark,
1882 p - header_value_mark);
1883 if (rc != 0) {
1884 return rc;
1885 }
1886
1887 goto reexecute;
1888 }
1889
1890 if (!lenient && !IS_HEADER_CHAR(ch)) {
1891 SET_ERRNO(HPE_INVALID_HEADER_TOKEN);
1892 goto error;
1893 }
1894
1895 c = LOWER(ch);
1896
1897 rc = header_states(parser, data, len, &p,
1898 &p_state, &h_state, ch, c);
1899 if (rc != 0) {
1900 goto error;
1901 }
1902
1903 }
1904 parser->header_state = h_state;
1905
1906 rc = count_header_size(parser, p - start);
1907 if (rc != 0) {
1908 goto error;
1909 }
1910
1911 if (p == data + len) {
1912 --p;
1913 }
1914 break;
1915 }
1916
1917 case s_header_almost_done: {
1918 if (UNLIKELY(ch != LF)) {
1919 SET_ERRNO(HPE_LF_EXPECTED);
1920 goto error;
1921 }
1922
1923 UPDATE_STATE(s_header_value_lws);
1924 break;
1925 }
1926
1927 case s_header_value_lws: {
1928 if (ch == ' ' || ch == '\t') {
1929 UPDATE_STATE(s_header_value_start);
1930 goto reexecute;
1931 }
1932
1933 /* finished the header */
1934 switch (parser->header_state) {
1935 case h_connection_keep_alive:
1936 parser->flags |= F_CONNECTION_KEEP_ALIVE;
1937 break;
1938 case h_connection_close:
1939 parser->flags |= F_CONNECTION_CLOSE;
1940 break;
1941 case h_transfer_encoding_chunked:
1942 parser->flags |= F_CHUNKED;
1943 break;
1944 case h_connection_upgrade:
1945 parser->flags |= F_CONNECTION_UPGRADE;
1946 break;
1947 default:
1948 break;
1949 }
1950
1951 UPDATE_STATE(s_header_field_start);
1952 goto reexecute;
1953 }
1954
1955 case s_header_value_discard_ws_almost_done: {
1956 rc = strict_check(parser, ch != LF);
1957 if (rc != 0) {
1958 goto error;
1959 }
1960 UPDATE_STATE(s_header_value_discard_lws);
1961 break;
1962 }
1963
1964 case s_header_value_discard_lws: {
1965 if (ch == ' ' || ch == '\t') {
1966 UPDATE_STATE(s_header_value_discard_ws);
1967 break;
1968 }
1969 switch (parser->header_state) {
1970 case h_connection_keep_alive:
1971 parser->flags |=
1972 F_CONNECTION_KEEP_ALIVE;
1973 break;
1974 case h_connection_close:
1975 parser->flags |= F_CONNECTION_CLOSE;
1976 break;
1977 case h_connection_upgrade:
1978 parser->flags |= F_CONNECTION_UPGRADE;
1979 break;
1980 case h_transfer_encoding_chunked:
1981 parser->flags |= F_CHUNKED;
1982 break;
1983 default:
1984 break;
1985 }
1986
1987 /* header value was empty */
1988 MARK(header_value);
1989 UPDATE_STATE(s_header_field_start);
1990 rc = cb_data(parser, settings->on_header_value,
1991 HPE_CB_header_value, &p_state, parsed,
1992 p - data, &header_value_mark,
1993 p - header_value_mark);
1994 if (rc != 0) {
1995 return rc;
1996 }
1997
1998 goto reexecute;
1999 }
2000
2001 case s_headers_almost_done: {
2002 rc = strict_check(parser, ch != LF);
2003 if (rc != 0) {
2004 goto error;
2005 }
2006
2007 if (parser->flags & F_TRAILING) {
2008 /* End of a chunked request */
2009 UPDATE_STATE(s_message_done);
2010
2011 rc = cb_notify(parser, &p_state,
2012 settings->on_chunk_complete,
2013 HPE_CB_chunk_complete, parsed,
2014 p - data);
2015 if (rc != 0) {
2016 return rc;
2017 }
2018 goto reexecute;
2019 }
2020
2021 /* Cannot use chunked encoding and a content-length
2022 * header together per the HTTP specification.
2023 */
2024 if ((parser->flags & F_CHUNKED) &&
2025 (parser->flags & F_CONTENTLENGTH)) {
2026 SET_ERRNO(HPE_UNEXPECTED_CONTENT_LENGTH);
2027 goto error;
2028 }
2029
2030 UPDATE_STATE(s_headers_done);
2031
2032 /* Set this here so that on_headers_complete() callbacks
2033 * can see it
2034 */
2035 int flags = (F_UPGRADE | F_CONNECTION_UPGRADE);
2036
2037 parser->upgrade =
2038 ((parser->flags & flags) == flags ||
2039 parser->method == HTTP_CONNECT);
2040
2041 /* Here we call the headers_complete callback. This is
2042 * somewhat
2043 * different than other callbacks because if the user
2044 * returns 1, we
2045 * will interpret that as saying that this message has
2046 * no body. This
2047 * is needed for the annoying case of receiving a
2048 * response to a HEAD
2049 * request.
2050 *
2051 * We'd like to use CALLBACK_NOTIFY_NOADVANCE() here but
2052 * we cannot, so
2053 * we have to simulate it by handling a change in errno
2054 * below.
2055 */
2056 if (settings->on_headers_complete) {
2057 switch (settings->on_headers_complete(parser)) {
2058 case 0:
2059 break;
2060
2061 case 2:
2062 parser->upgrade = 1U;
2063 __fallthrough;
2064
2065 case 1:
2066 parser->flags |= F_SKIPBODY;
2067 break;
2068
2069 default:
2070 SET_ERRNO(HPE_CB_headers_complete);
2071
2072 parser->state = CURRENT_STATE();
2073 *parsed = p - data;
2074 return -HTTP_PARSER_ERRNO(parser);
2075 }
2076 }
2077
2078 if (HTTP_PARSER_ERRNO(parser) != HPE_OK) {
2079 parser->state = CURRENT_STATE();
2080 *parsed = p - data;
2081 return -HTTP_PARSER_ERRNO(parser);
2082 }
2083
2084 goto reexecute;
2085 }
2086
2087 case s_headers_done: {
2088 int hasBody;
2089
2090 rc = strict_check(parser, ch != LF);
2091 if (rc != 0) {
2092 goto error;
2093 }
2094
2095 parser->nread = 0U;
2096
2097 hasBody = parser->flags & F_CHUNKED ||
2098 (parser->content_length > 0 &&
2099 parser->content_length != ULLONG_MAX);
2100 if (parser->upgrade &&
2101 (parser->method == HTTP_CONNECT ||
2102 (parser->flags & F_SKIPBODY) || !hasBody)) {
2103 /* Exit, the rest of the message is in a
2104 * different protocol.
2105 */
2106 UPDATE_STATE(NEW_MESSAGE());
2107
2108 rc = cb_notify(parser, &p_state,
2109 settings->on_message_complete,
2110 HPE_CB_message_complete, parsed,
2111 p - data + 1);
2112 if (rc != 0) {
2113 return rc;
2114 }
2115 parser->state = CURRENT_STATE();
2116 *parsed = p - data + 1;
2117 return 0;
2118 }
2119
2120 if (parser->flags & F_SKIPBODY) {
2121 UPDATE_STATE(NEW_MESSAGE());
2122
2123 rc = cb_notify(parser, &p_state,
2124 settings->on_message_complete,
2125 HPE_CB_message_complete, parsed,
2126 p - data + 1);
2127 if (rc != 0) {
2128 return rc;
2129 }
2130
2131 } else if (parser->flags & F_CHUNKED) {
2132 /* chunked encoding - ignore Content-Length
2133 * header
2134 */
2135 UPDATE_STATE(s_chunk_size_start);
2136 } else {
2137 rc = zero_content_length(parser, settings,
2138 &p_state, parsed, p,
2139 data);
2140 if (rc != 0) {
2141 return rc;
2142 }
2143 }
2144
2145 break;
2146 }
2147
2148 case s_body_identity: {
2149 uint64_t to_read = MIN(parser->content_length,
2150 (uint64_t) ((data + len) - p));
2151
2152 __ASSERT_NO_MSG(parser->content_length != 0U
2153 && parser->content_length != ULLONG_MAX);
2154
2155 /* The difference between advancing content_length and
2156 * p is because
2157 * the latter will automatically advance on the next
2158 * loop
2159 * iteration.
2160 * Further, if content_length ends up at 0, we want to
2161 * see the last
2162 * byte again for our message complete callback.
2163 */
2164 MARK(body);
2165 parser->content_length -= to_read;
2166 p += to_read - 1;
2167
2168 if (parser->content_length == 0U) {
2169 UPDATE_STATE(s_message_done);
2170
2171 /* Mimic CALLBACK_DATA_NOADVANCE() but with one
2172 * extra byte.
2173 *
2174 * The alternative to doing this is to wait for
2175 * the next byte to
2176 * trigger the data callback, just as in every
2177 * other case. The
2178 * problem with this is that this makes it
2179 * difficult for the test
2180 * harness to distinguish between
2181 * complete-on-EOF and
2182 * complete-on-length. It's not clear that this
2183 * distinction is
2184 * important for applications, but let's keep it
2185 * for now.
2186 */
2187
2188 rc = cb_data(parser, settings->on_body,
2189 HPE_CB_body, &p_state, parsed,
2190 p - data, &body_mark,
2191 p - body_mark + 1);
2192 if (rc != 0) {
2193 return rc;
2194 }
2195
2196 goto reexecute;
2197 }
2198
2199 break;
2200 }
2201
2202 /* read until EOF */
2203 case s_body_identity_eof:
2204 MARK(body);
2205 p = data + len - 1;
2206
2207 break;
2208
2209 case s_message_done:
2210 UPDATE_STATE(NEW_MESSAGE());
2211
2212 rc = cb_notify(parser, &p_state,
2213 settings->on_message_complete,
2214 HPE_CB_message_complete, parsed,
2215 p - data + 1);
2216 if (rc != 0) {
2217 return rc;
2218 }
2219 if (parser->upgrade) {
2220 /* Exit, the rest of the message is in a
2221 * different protocol.
2222 */
2223 parser->state = CURRENT_STATE();
2224 *parsed = p - data + 1;
2225 return 0;
2226 }
2227 break;
2228
2229 case s_chunk_size_start: {
2230 __ASSERT_NO_MSG(parser->nread == 1U);
2231 __ASSERT_NO_MSG(parser->flags & F_CHUNKED);
2232
2233 unhex_val = unhex[(unsigned char)ch];
2234 if (UNLIKELY(unhex_val == -1)) {
2235 SET_ERRNO(HPE_INVALID_CHUNK_SIZE);
2236 goto error;
2237 }
2238
2239 parser->content_length = unhex_val;
2240 UPDATE_STATE(s_chunk_size);
2241 break;
2242 }
2243
2244 case s_chunk_size: {
2245 uint64_t t;
2246
2247 __ASSERT_NO_MSG(parser->flags & F_CHUNKED);
2248
2249 if (ch == CR) {
2250 UPDATE_STATE(s_chunk_size_almost_done);
2251 break;
2252 }
2253
2254 unhex_val = unhex[(unsigned char)ch];
2255
2256 if (unhex_val == -1) {
2257 if (ch == ';' || ch == ' ') {
2258 UPDATE_STATE(s_chunk_parameters);
2259 break;
2260 }
2261
2262 SET_ERRNO(HPE_INVALID_CHUNK_SIZE);
2263 goto error;
2264 }
2265
2266 t = parser->content_length;
2267 t *= 16U;
2268 t += unhex_val;
2269
2270 /* Overflow? Test against a conservative limit for
2271 * simplicity.
2272 */
2273 uint64_t ulong_value = (ULLONG_MAX - 16) / 16;
2274
2275 if (UNLIKELY(ulong_value < parser->content_length)) {
2276 SET_ERRNO(HPE_INVALID_CONTENT_LENGTH);
2277 goto error;
2278 }
2279
2280 parser->content_length = t;
2281 break;
2282 }
2283
2284 case s_chunk_parameters: {
2285 __ASSERT_NO_MSG(parser->flags & F_CHUNKED);
2286 /* just ignore this shit. TODO check for overflow */
2287 if (ch == CR) {
2288 UPDATE_STATE(s_chunk_size_almost_done);
2289 break;
2290 }
2291 break;
2292 }
2293
2294 case s_chunk_size_almost_done: {
2295 __ASSERT_NO_MSG(parser->flags & F_CHUNKED);
2296
2297 rc = strict_check(parser, ch != LF);
2298 if (rc != 0) {
2299 goto error;
2300 }
2301
2302 parser->nread = 0U;
2303
2304 if (parser->content_length == 0U) {
2305 parser->flags |= F_TRAILING;
2306 UPDATE_STATE(s_header_field_start);
2307 } else {
2308 UPDATE_STATE(s_chunk_data);
2309 }
2310
2311 rc = cb_notify(parser, &p_state,
2312 settings->on_chunk_header,
2313 HPE_CB_chunk_header, parsed,
2314 p - data + 1);
2315 if (rc != 0) {
2316 return rc;
2317 }
2318 break;
2319 }
2320
2321 case s_chunk_data: {
2322 uint64_t to_read = MIN(parser->content_length,
2323 (uint64_t) ((data + len) - p));
2324
2325 __ASSERT_NO_MSG(parser->flags & F_CHUNKED);
2326 __ASSERT_NO_MSG(parser->content_length != 0U
2327 && parser->content_length != ULLONG_MAX);
2328
2329 /* See the explanation in s_body_identity for why the
2330 * content
2331 * length and data pointers are managed this way.
2332 */
2333 MARK(body);
2334 parser->content_length -= to_read;
2335 p += to_read - 1;
2336
2337 if (parser->content_length == 0U) {
2338 UPDATE_STATE(s_chunk_data_almost_done);
2339 }
2340
2341 break;
2342 }
2343
2344 case s_chunk_data_almost_done:
2345 __ASSERT_NO_MSG(parser->flags & F_CHUNKED);
2346 __ASSERT_NO_MSG(parser->content_length == 0U);
2347 rc = strict_check(parser, ch != CR);
2348 if (rc != 0) {
2349 goto error;
2350 }
2351 UPDATE_STATE(s_chunk_data_done);
2352 rc = cb_data(parser, settings->on_body, HPE_CB_body,
2353 &p_state, parsed, p - data + 1, &body_mark,
2354 p - body_mark);
2355 if (rc != 0) {
2356 return rc;
2357 }
2358
2359 break;
2360
2361 case s_chunk_data_done:
2362 __ASSERT_NO_MSG(parser->flags & F_CHUNKED);
2363 rc = strict_check(parser, ch != LF);
2364 if (rc != 0) {
2365 goto error;
2366 }
2367 parser->nread = 0U;
2368 UPDATE_STATE(s_chunk_size_start);
2369
2370 rc = cb_notify(parser, &p_state,
2371 settings->on_chunk_complete,
2372 HPE_CB_chunk_complete, parsed,
2373 p - data + 1);
2374 if (rc != 0) {
2375 return rc;
2376 }
2377 break;
2378
2379 default:
2380 __ASSERT_NO_MSG(0 && "unhandled state");
2381 SET_ERRNO(HPE_INVALID_INTERNAL_STATE);
2382 goto error;
2383 }
2384 }
2385
2386 /* Run callbacks for any marks that we have leftover after we ran our of
2387 * bytes. There should be at most one of these set, so it's OK to invoke
2388 * them in series (unset marks will not result in callbacks).
2389 *
2390 * We use the NOADVANCE() variety of callbacks here because 'p' has
2391 * already
2392 * overflowed 'data' and this allows us to correct for the off-by-one
2393 * that
2394 * we'd otherwise have (since CALLBACK_DATA() is meant to be run with a
2395 * 'p'
2396 * value that's in-bounds).
2397 */
2398
2399 __ASSERT_NO_MSG(((header_field_mark ? 1 : 0) +
2400 (header_value_mark ? 1 : 0) +
2401 (url_mark ? 1 : 0) +
2402 (body_mark ? 1 : 0) +
2403 (status_mark ? 1 : 0)) <= 1);
2404
2405 rc = cb_data(parser, settings->on_header_field, HPE_CB_header_field,
2406 &p_state, parsed, p - data, &header_field_mark,
2407 p - header_field_mark);
2408 if (rc != 0) {
2409 return rc;
2410 }
2411 rc = cb_data(parser, settings->on_header_value, HPE_CB_header_value,
2412 &p_state, parsed, p - data, &header_value_mark,
2413 p - header_value_mark);
2414 if (rc != 0) {
2415 return rc;
2416 }
2417 rc = cb_data(parser, settings->on_url, HPE_CB_url, &p_state, parsed,
2418 p - data, &url_mark, p - url_mark);
2419 if (rc != 0) {
2420 return rc;
2421 }
2422 rc = cb_data(parser, settings->on_body, HPE_CB_body, &p_state, parsed,
2423 p - data, &body_mark, p - body_mark);
2424 if (rc != 0) {
2425 return rc;
2426 }
2427 rc = cb_data(parser, settings->on_status, HPE_CB_status, &p_state,
2428 parsed, p - data, &status_mark, p - status_mark);
2429 if (rc != 0) {
2430 return rc;
2431 }
2432
2433 parser->state = CURRENT_STATE();
2434 *parsed = len;
2435 return 0;
2436
2437 error:
2438 if (HTTP_PARSER_ERRNO(parser) == HPE_OK) {
2439 SET_ERRNO(HPE_UNKNOWN);
2440 }
2441
2442 parser->state = CURRENT_STATE();
2443 *parsed = p - data; /* Error */
2444 return -HTTP_PARSER_ERRNO(parser);
2445 }
2446
http_parser_execute(struct http_parser * parser,const struct http_parser_settings * settings,const char * data,size_t len)2447 size_t http_parser_execute(struct http_parser *parser,
2448 const struct http_parser_settings *settings,
2449 const char *data, size_t len)
2450 {
2451 size_t parsed;
2452
2453 parser_execute(parser, settings, data, len, &parsed);
2454 return parsed;
2455 }
2456
2457 /* Does the parser need to see an EOF to find the end of the message? */
http_message_needs_eof(const struct http_parser * parser)2458 int http_message_needs_eof(const struct http_parser *parser)
2459 {
2460 if (parser->type == HTTP_REQUEST) {
2461 return 0;
2462 }
2463
2464 /* See RFC 2616 section 4.4 */
2465 if (parser->status_code / 100 == 1U || /* 1xx e.g. Continue */
2466 parser->status_code == 204U || /* No Content */
2467 parser->status_code == 304U || /* Not Modified */
2468 parser->flags & F_SKIPBODY) { /* response to a HEAD
2469 * request
2470 */
2471 return 0;
2472 }
2473
2474 if ((parser->flags & F_CHUNKED) ||
2475 parser->content_length != ULLONG_MAX) {
2476 return 0;
2477 }
2478
2479 return 1;
2480 }
2481
2482
http_should_keep_alive(const struct http_parser * parser)2483 int http_should_keep_alive(const struct http_parser *parser)
2484 {
2485 if (parser->http_major > 0 && parser->http_minor > 0) {
2486 /* HTTP/1.1 */
2487 if (parser->flags & F_CONNECTION_CLOSE) {
2488 return 0;
2489 }
2490 } else {
2491 /* HTTP/1.0 or earlier */
2492 if (!(parser->flags & F_CONNECTION_KEEP_ALIVE)) {
2493 return 0;
2494 }
2495 }
2496
2497 return !http_message_needs_eof(parser);
2498 }
2499
2500
http_method_str(enum http_method m)2501 const char *http_method_str(enum http_method m)
2502 {
2503 return ELEM_AT(method_strings, m, "<unknown>");
2504 }
2505
2506
http_parser_init(struct http_parser * parser,enum http_parser_type t)2507 void http_parser_init(struct http_parser *parser, enum http_parser_type t)
2508 {
2509 void *data = parser->data; /* preserve application data */
2510
2511 (void)memset(parser, 0, sizeof(*parser));
2512 parser->data = data;
2513 parser->type = t;
2514 parser->state =
2515 (t == HTTP_REQUEST ? s_start_req :
2516 (t == HTTP_RESPONSE ? s_start_res : s_start_req_or_res));
2517 parser->http_errno = HPE_OK;
2518 }
2519
http_parser_settings_init(struct http_parser_settings * settings)2520 void http_parser_settings_init(struct http_parser_settings *settings)
2521 {
2522 (void)memset(settings, 0, sizeof(*settings));
2523 }
2524
http_errno_name(enum http_errno err)2525 const char *http_errno_name(enum http_errno err)
2526 {
2527 __ASSERT_NO_MSG(((size_t) err) < ARRAY_SIZE(http_strerror_tab));
2528
2529 return http_strerror_tab[err].name;
2530 }
2531
http_errno_description(enum http_errno err)2532 const char *http_errno_description(enum http_errno err)
2533 {
2534 __ASSERT_NO_MSG(((size_t) err) < ARRAY_SIZE(http_strerror_tab));
2535
2536 return http_strerror_tab[err].description;
2537 }
2538
http_parser_pause(struct http_parser * parser,int paused)2539 void http_parser_pause(struct http_parser *parser, int paused)
2540 {
2541 /* Users should only be pausing/unpausing a parser that is not in an
2542 * error
2543 * state. In non-debug builds, there's not much that we can do about
2544 * this
2545 * other than ignore it.
2546 */
2547 if (HTTP_PARSER_ERRNO(parser) == HPE_OK ||
2548 HTTP_PARSER_ERRNO(parser) == HPE_PAUSED) {
2549 SET_ERRNO((paused) ? HPE_PAUSED : HPE_OK);
2550 } else {
2551 __ASSERT_NO_MSG(0 && "Attempting to pause parser in error state");
2552 }
2553 }
2554
http_body_is_final(const struct http_parser * parser)2555 int http_body_is_final(const struct http_parser *parser)
2556 {
2557 return parser->state == s_message_done;
2558 }
2559
http_parser_version(void)2560 unsigned long http_parser_version(void)
2561 {
2562 return HTTP_PARSER_VERSION_MAJOR * 0x10000 |
2563 HTTP_PARSER_VERSION_MINOR * 0x00100 |
2564 HTTP_PARSER_VERSION_PATCH * 0x00001;
2565 }
2566