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