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