1 /* Based on src/http/ngx_http_parse.c from NGINX copyright Igor Sysoev
3 * Additional changes are licensed under the same terms as NGINX and
4 * copyright Joyent, Inc. and other Node contributors. All rights reserved.
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to
8 * deal in the Software without restriction, including without limitation the
9 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 * sell copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
24 #include "http_parser.h"
30 # define MIN(a,b) ((a) < (b) ? (a) : (b))
35 #define SET_ERRNO(e) \
37 parser->http_errno = (e); \
38 parser->error_lineno = __LINE__; \
41 #define SET_ERRNO(e) \
43 parser->http_errno = (e); \
48 #define CALLBACK2(FOR) \
50 if (settings->on_##FOR) { \
51 if (0 != settings->on_##FOR(parser)) { \
52 SET_ERRNO(HPE_CB_##FOR); \
64 #define CALLBACK(FOR) \
67 if (settings->on_##FOR) { \
68 if (0 != settings->on_##FOR(parser, \
72 SET_ERRNO(HPE_CB_##FOR); \
81 #define PROXY_CONNECTION "proxy-connection"
82 #define CONNECTION "connection"
83 #define CONTENT_LENGTH "content-length"
84 #define TRANSFER_ENCODING "transfer-encoding"
85 #define UPGRADE "upgrade"
86 #define CHUNKED "chunked"
87 #define KEEP_ALIVE "keep-alive"
91 static const char *method_strings
[] =
130 /* Tokens as defined by rfc 2616. Also lowercases them.
131 * token = 1*<any CHAR except CTLs or separators>
132 * separators = "(" | ")" | "<" | ">" | "@"
133 * | "," | ";" | ":" | "\" | <">
134 * | "/" | "[" | "]" | "?" | "="
135 * | "{" | "}" | SP | HT
137 static const char tokens
[256] = {
138 /* 0 nul 1 soh 2 stx 3 etx 4 eot 5 enq 6 ack 7 bel */
139 0, 0, 0, 0, 0, 0, 0, 0,
140 /* 8 bs 9 ht 10 nl 11 vt 12 np 13 cr 14 so 15 si */
141 0, 0, 0, 0, 0, 0, 0, 0,
142 /* 16 dle 17 dc1 18 dc2 19 dc3 20 dc4 21 nak 22 syn 23 etb */
143 0, 0, 0, 0, 0, 0, 0, 0,
144 /* 24 can 25 em 26 sub 27 esc 28 fs 29 gs 30 rs 31 us */
145 0, 0, 0, 0, 0, 0, 0, 0,
146 /* 32 sp 33 ! 34 " 35 # 36 $ 37 % 38 & 39 ' */
147 ' ', '!', '"', '#', '$', '%', '&', '\'',
148 /* 40 ( 41 ) 42 * 43 + 44 , 45 - 46 . 47 / */
149 0, 0, '*', '+', 0, '-', '.', '/',
150 /* 48 0 49 1 50 2 51 3 52 4 53 5 54 6 55 7 */
151 '0', '1', '2', '3', '4', '5', '6', '7',
152 /* 56 8 57 9 58 : 59 ; 60 < 61 = 62 > 63 ? */
153 '8', '9', 0, 0, 0, 0, 0, 0,
154 /* 64 @ 65 A 66 B 67 C 68 D 69 E 70 F 71 G */
155 0, 'a', 'b', 'c', 'd', 'e', 'f', 'g',
156 /* 72 H 73 I 74 J 75 K 76 L 77 M 78 N 79 O */
157 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
158 /* 80 P 81 Q 82 R 83 S 84 T 85 U 86 V 87 W */
159 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
160 /* 88 X 89 Y 90 Z 91 [ 92 \ 93 ] 94 ^ 95 _ */
161 'x', 'y', 'z', 0, 0, 0, '^', '_',
162 /* 96 ` 97 a 98 b 99 c 100 d 101 e 102 f 103 g */
163 '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
164 /* 104 h 105 i 106 j 107 k 108 l 109 m 110 n 111 o */
165 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
166 /* 112 p 113 q 114 r 115 s 116 t 117 u 118 v 119 w */
167 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
168 /* 120 x 121 y 122 z 123 { 124 | 125 } 126 ~ 127 del */
169 'x', 'y', 'z', 0, '|', '}', '~', 0 };
172 static const int8_t unhex
[256] =
173 {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
174 ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
175 ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
176 , 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1
177 ,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1
178 ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
179 ,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1
180 ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
184 static const uint8_t normal_url_char
[256] = {
185 /* 0 nul 1 soh 2 stx 3 etx 4 eot 5 enq 6 ack 7 bel */
186 0, 0, 0, 0, 0, 0, 0, 0,
187 /* 8 bs 9 ht 10 nl 11 vt 12 np 13 cr 14 so 15 si */
188 0, 0, 0, 0, 0, 0, 0, 0,
189 /* 16 dle 17 dc1 18 dc2 19 dc3 20 dc4 21 nak 22 syn 23 etb */
190 0, 0, 0, 0, 0, 0, 0, 0,
191 /* 24 can 25 em 26 sub 27 esc 28 fs 29 gs 30 rs 31 us */
192 0, 0, 0, 0, 0, 0, 0, 0,
193 /* 32 sp 33 ! 34 " 35 # 36 $ 37 % 38 & 39 ' */
194 0, 1, 1, 0, 1, 1, 1, 1,
195 /* 40 ( 41 ) 42 * 43 + 44 , 45 - 46 . 47 / */
196 1, 1, 1, 1, 1, 1, 1, 1,
197 /* 48 0 49 1 50 2 51 3 52 4 53 5 54 6 55 7 */
198 1, 1, 1, 1, 1, 1, 1, 1,
199 /* 56 8 57 9 58 : 59 ; 60 < 61 = 62 > 63 ? */
200 1, 1, 1, 1, 1, 1, 1, 0,
201 /* 64 @ 65 A 66 B 67 C 68 D 69 E 70 F 71 G */
202 1, 1, 1, 1, 1, 1, 1, 1,
203 /* 72 H 73 I 74 J 75 K 76 L 77 M 78 N 79 O */
204 1, 1, 1, 1, 1, 1, 1, 1,
205 /* 80 P 81 Q 82 R 83 S 84 T 85 U 86 V 87 W */
206 1, 1, 1, 1, 1, 1, 1, 1,
207 /* 88 X 89 Y 90 Z 91 [ 92 \ 93 ] 94 ^ 95 _ */
208 1, 1, 1, 1, 1, 1, 1, 1,
209 /* 96 ` 97 a 98 b 99 c 100 d 101 e 102 f 103 g */
210 1, 1, 1, 1, 1, 1, 1, 1,
211 /* 104 h 105 i 106 j 107 k 108 l 109 m 110 n 111 o */
212 1, 1, 1, 1, 1, 1, 1, 1,
213 /* 112 p 113 q 114 r 115 s 116 t 117 u 118 v 119 w */
214 1, 1, 1, 1, 1, 1, 1, 1,
215 /* 120 x 121 y 122 z 123 { 124 | 125 } 126 ~ 127 del */
216 1, 1, 1, 1, 1, 1, 1, 0, };
220 { s_dead
= 1 /* important that this is > 0 */
229 , s_res_first_http_major
231 , s_res_first_http_minor
233 , s_res_first_status_code
236 , s_res_line_almost_done
241 , s_req_spaces_before_url
244 , s_req_schema_slash_slash
248 , s_req_query_string_start
250 , s_req_fragment_start
257 , s_req_first_http_major
259 , s_req_first_http_minor
261 , s_req_line_almost_done
263 , s_header_field_start
265 , s_header_value_start
269 , s_header_almost_done
274 , s_chunk_size_almost_done
276 , s_headers_almost_done
277 /* Important: 's_headers_almost_done' must be the last 'header' state. All
278 * states beyond this must be 'body' states. It is used for overflow
279 * checking. See the PARSING_HEADER() macro.
283 , s_chunk_data_almost_done
287 , s_body_identity_eof
291 #define PARSING_HEADER(state) (state <= s_headers_almost_done)
300 , h_matching_connection
301 , h_matching_proxy_connection
302 , h_matching_content_length
303 , h_matching_transfer_encoding
308 , h_transfer_encoding
311 , h_matching_transfer_encoding_chunked
312 , h_matching_connection_keep_alive
313 , h_matching_connection_close
315 , h_transfer_encoding_chunked
316 , h_connection_keep_alive
321 /* Macros for character classes; depends on strict-mode */
324 #define LOWER(c) (unsigned char)(c | 0x20)
325 #define TOKEN(c) (tokens[(unsigned char)c])
326 #define IS_ALPHA(c) (LOWER(c) >= 'a' && LOWER(c) <= 'z')
327 #define IS_NUM(c) ((c) >= '0' && (c) <= '9')
328 #define IS_ALPHANUM(c) (IS_ALPHA(c) || IS_NUM(c))
329 #define IS_NUMERIC_CHAR(c) (IS_NUM(c) || (LOWER(c) >= 'a' && LOWER(c) <= 'f') || (c) == '.' || (c) == ':')
331 #if HTTP_PARSER_STRICT
332 #define IS_URL_CHAR(c) (normal_url_char[(unsigned char) (c)])
333 #define IS_HOST_CHAR(c) (IS_ALPHANUM(c) || (c) == '.' || (c) == '-')
335 #define IS_URL_CHAR(c) \
336 (normal_url_char[(unsigned char) (c)] || ((c) & 0x80))
337 #define IS_HOST_CHAR(c) \
338 (IS_ALPHANUM(c) || (c) == '.' || (c) == '-' || (c) == '_')
342 #define start_state (parser->type == HTTP_REQUEST ? s_start_req : s_start_res)
345 #if HTTP_PARSER_STRICT
346 # define STRICT_CHECK(cond) \
349 SET_ERRNO(HPE_STRICT); \
353 # define NEW_MESSAGE() (http_should_keep_alive(parser) ? start_state : s_dead)
355 # define STRICT_CHECK(cond)
356 # define NEW_MESSAGE() start_state
360 /* Map errno values to strings for human-readable output */
361 #define HTTP_STRERROR_GEN(n, s) { "HPE_" #n, s },
364 const char *description
;
365 } http_strerror_tab
[] = {
366 HTTP_ERRNO_MAP(HTTP_STRERROR_GEN
)
368 #undef HTTP_STRERROR_GEN
371 size_t http_parser_execute (http_parser
*parser
,
372 const http_parser_settings
*settings
,
378 const char *p
= data
, *pe
;
381 enum header_states header_state
;
382 uint64_t index
= parser
->index
;
383 uint64_t nread
= parser
->nread
;
385 /* technically we could combine all of these (except for url_mark) into one
386 variable, saving stack space, but it seems more clear to have them
388 const char *header_field_mark
= 0;
389 const char *header_value_mark
= 0;
390 const char *url_mark
= 0;
392 /* We're in an error state. Don't bother doing anything. */
393 if (HTTP_PARSER_ERRNO(parser
) != HPE_OK
) {
397 state
= (enum state
) parser
->state
;
398 header_state
= (enum header_states
) parser
->header_state
;
402 case s_body_identity_eof
:
403 CALLBACK2(message_complete
);
407 case s_start_req_or_res
:
413 SET_ERRNO(HPE_INVALID_EOF_STATE
);
419 if (state
== s_header_field
)
420 header_field_mark
= data
;
421 if (state
== s_header_value
)
422 header_value_mark
= data
;
423 if (state
== s_req_path
|| state
== s_req_schema
|| state
== s_req_schema_slash
424 || state
== s_req_schema_slash_slash
|| state
== s_req_port
425 || state
== s_req_query_string_start
|| state
== s_req_query_string
426 || state
== s_req_host
427 || state
== s_req_fragment_start
|| state
== s_req_fragment
)
430 for (p
=data
, pe
=data
+len
; p
!= pe
; p
++) {
433 if (PARSING_HEADER(state
)) {
435 /* Buffer overflow attack */
436 if (nread
> HTTP_MAX_HEADER_SIZE
) {
437 SET_ERRNO(HPE_HEADER_OVERFLOW
);
445 /* this state is used after a 'Connection: close' message
446 * the parser will error out if it reads another message
448 SET_ERRNO(HPE_CLOSED_CONNECTION
);
451 case s_start_req_or_res
:
453 if (ch
== CR
|| ch
== LF
)
456 parser
->content_length
= -1;
458 CALLBACK2(message_begin
);
461 state
= s_res_or_resp_H
;
463 parser
->type
= HTTP_REQUEST
;
464 goto start_req_method_assign
;
469 case s_res_or_resp_H
:
471 parser
->type
= HTTP_RESPONSE
;
475 SET_ERRNO(HPE_INVALID_CONSTANT
);
479 parser
->type
= HTTP_REQUEST
;
480 parser
->method
= HTTP_HEAD
;
482 state
= s_req_method
;
489 parser
->content_length
= -1;
491 CALLBACK2(message_begin
);
503 SET_ERRNO(HPE_INVALID_CONSTANT
);
510 STRICT_CHECK(ch
!= 'T');
515 STRICT_CHECK(ch
!= 'T');
520 STRICT_CHECK(ch
!= 'P');
525 STRICT_CHECK(ch
!= '/');
526 state
= s_res_first_http_major
;
529 case s_res_first_http_major
:
530 if (ch
< '0' || ch
> '9') {
531 SET_ERRNO(HPE_INVALID_VERSION
);
535 parser
->http_major
= ch
- '0';
536 state
= s_res_http_major
;
539 /* major HTTP version or dot */
540 case s_res_http_major
:
543 state
= s_res_first_http_minor
;
548 SET_ERRNO(HPE_INVALID_VERSION
);
552 parser
->http_major
*= 10;
553 parser
->http_major
+= ch
- '0';
555 if (parser
->http_major
> 999) {
556 SET_ERRNO(HPE_INVALID_VERSION
);
563 /* first digit of minor HTTP version */
564 case s_res_first_http_minor
:
566 SET_ERRNO(HPE_INVALID_VERSION
);
570 parser
->http_minor
= ch
- '0';
571 state
= s_res_http_minor
;
574 /* minor HTTP version or end of request line */
575 case s_res_http_minor
:
578 state
= s_res_first_status_code
;
583 SET_ERRNO(HPE_INVALID_VERSION
);
587 parser
->http_minor
*= 10;
588 parser
->http_minor
+= ch
- '0';
590 if (parser
->http_minor
> 999) {
591 SET_ERRNO(HPE_INVALID_VERSION
);
598 case s_res_first_status_code
:
605 SET_ERRNO(HPE_INVALID_STATUS
);
608 parser
->status_code
= ch
- '0';
609 state
= s_res_status_code
;
613 case s_res_status_code
:
618 state
= s_res_status
;
621 state
= s_res_line_almost_done
;
624 state
= s_header_field_start
;
627 SET_ERRNO(HPE_INVALID_STATUS
);
633 parser
->status_code
*= 10;
634 parser
->status_code
+= ch
- '0';
636 if (parser
->status_code
> 999) {
637 SET_ERRNO(HPE_INVALID_STATUS
);
645 /* the human readable status. e.g. "NOT FOUND"
646 * we are not humans so just ignore this */
648 state
= s_res_line_almost_done
;
653 state
= s_header_field_start
;
658 case s_res_line_almost_done
:
659 STRICT_CHECK(ch
!= LF
);
660 state
= s_header_field_start
;
665 if (ch
== CR
|| ch
== LF
)
668 parser
->content_length
= -1;
670 CALLBACK2(message_begin
);
673 SET_ERRNO(HPE_INVALID_METHOD
);
677 start_req_method_assign
:
678 parser
->method
= (enum http_method
) 0;
681 case 'A': parser
->method
= HTTP_ANNOUNCE
; break;
682 case 'C': parser
->method
= HTTP_CONNECT
; /* or COPY, CHECKOUT */ break;
683 case 'D': parser
->method
= HTTP_DELETE
; /* or DESCRIBE */ break;
684 case 'F': parser
->method
= HTTP_FLUSH
; break;
685 case 'G': parser
->method
= HTTP_GET
; /* or GET_PARAMETER */ break;
686 case 'H': parser
->method
= HTTP_HEAD
; break;
687 case 'L': parser
->method
= HTTP_LOCK
; break;
688 case 'M': parser
->method
= HTTP_MKCOL
; /* or MOVE, MKACTIVITY, MERGE, M-SEARCH */ break;
689 case 'N': parser
->method
= HTTP_NOTIFY
; break;
690 case 'O': parser
->method
= HTTP_OPTIONS
; break;
691 case 'P': parser
->method
= HTTP_POST
;
692 /* or PROPFIND or PROPPATCH or PUT or PATCH or PLAY or PAUSE */
694 case 'R': parser
->method
= HTTP_REPORT
; /* or REDIRECT, RECORD */ break;
695 case 'S': parser
->method
= HTTP_SUBSCRIBE
; /* or SETUP, SET_PARAMETER */ break;
696 case 'T': parser
->method
= HTTP_TRACE
; /* or TEARDOWN */ break;
697 case 'U': parser
->method
= HTTP_UNLOCK
; /* or UNSUBSCRIBE */ break;
699 SET_ERRNO(HPE_INVALID_METHOD
);
702 state
= s_req_method
;
710 SET_ERRNO(HPE_INVALID_METHOD
);
714 matcher
= method_strings
[parser
->method
];
715 if (ch
== ' ' && matcher
[index
] == '\0') {
716 state
= s_req_spaces_before_url
;
717 } else if (ch
== matcher
[index
]) {
719 } else if (parser
->method
== HTTP_CONNECT
) {
720 if (index
== 1 && ch
== 'H') {
721 parser
->method
= HTTP_CHECKOUT
;
722 } else if (index
== 2 && ch
== 'P') {
723 parser
->method
= HTTP_COPY
;
727 } else if (index
== 2 && parser
->method
== HTTP_DELETE
&& ch
== 'S') {
728 parser
->method
= HTTP_DESCRIBE
;
729 } else if (index
== 3 && parser
->method
== HTTP_GET
&& ch
== '_') {
730 parser
->method
= HTTP_GET_PARAMETER
;
731 } else if (parser
->method
== HTTP_MKCOL
) {
732 if (index
== 1 && ch
== 'O') {
733 parser
->method
= HTTP_MOVE
;
734 } else if (index
== 1 && ch
== 'E') {
735 parser
->method
= HTTP_MERGE
;
736 } else if (index
== 1 && ch
== '-') {
737 parser
->method
= HTTP_MSEARCH
;
738 } else if (index
== 2 && ch
== 'A') {
739 parser
->method
= HTTP_MKACTIVITY
;
743 } else if (index
== 1 && parser
->method
== HTTP_POST
) {
745 parser
->method
= HTTP_PROPFIND
; /* or HTTP_PROPPATCH */
746 } else if (ch
== 'U') {
747 parser
->method
= HTTP_PUT
;
748 } else if (ch
== 'A') {
749 parser
->method
= HTTP_PATCH
; /* or HTTP_PAUSE */
750 } else if (ch
== 'L') {
751 parser
->method
= HTTP_PLAY
;
755 } else if (index
== 2 && parser
->method
== HTTP_REPORT
) {
757 parser
->method
= HTTP_REDIRECT
;
758 } else if (ch
== 'C') {
759 parser
->method
= HTTP_RECORD
;
763 } else if (index
== 1 && parser
->method
== HTTP_SUBSCRIBE
&& ch
== 'E') {
764 parser
->method
= HTTP_SETUP
; /* or HTTP_SET_PARAMETER */
765 } else if (index
== 3 && parser
->method
== HTTP_SETUP
&& ch
== '_') {
766 parser
->method
= HTTP_SET_PARAMETER
;
767 } else if (index
== 1 && parser
->method
== HTTP_TRACE
&& ch
== 'E') {
768 parser
->method
= HTTP_TEARDOWN
;
769 } else if (index
== 2 && parser
->method
== HTTP_UNLOCK
&& ch
== 'S') {
770 parser
->method
= HTTP_UNSUBSCRIBE
;
771 } else if (index
== 4 && parser
->method
== HTTP_PROPFIND
&& ch
== 'P') {
772 parser
->method
= HTTP_PROPPATCH
;
773 } else if (index
== 2 && parser
->method
== HTTP_PATCH
&& ch
== 'U') {
774 parser
->method
= HTTP_PAUSE
;
776 SET_ERRNO(HPE_INVALID_METHOD
);
783 case s_req_spaces_before_url
:
785 if (ch
== ' ') break;
787 if (ch
== '/' || ch
== '*') {
793 /* Proxied requests are followed by scheme of an absolute URI (alpha).
794 * CONNECT is followed by a hostname, which begins with alphanum.
795 * All other methods are followed by '/' or '*' (handled above).
797 if (IS_ALPHA(ch
) || (parser
->method
== HTTP_CONNECT
&& IS_NUM(ch
))) {
799 state
= (parser
->method
== HTTP_CONNECT
) ? s_req_host
: s_req_schema
;
803 SET_ERRNO(HPE_INVALID_URL
);
809 if (IS_ALPHA(ch
)) break;
812 state
= s_req_schema_slash
;
816 SET_ERRNO(HPE_INVALID_URL
);
820 case s_req_schema_slash
:
821 STRICT_CHECK(ch
!= '/');
822 state
= s_req_schema_slash_slash
;
825 case s_req_schema_slash_slash
:
826 STRICT_CHECK(ch
!= '/');
832 if (parser
->numerichost
) {
833 if (IS_NUMERIC_CHAR(ch
)) break;
835 if (IS_HOST_CHAR(ch
)) break;
845 /* The request line looks like:
846 * "GET http://foo.bar.com HTTP/1.1"
847 * That is, there is no path.
850 state
= s_req_http_start
;
853 state
= s_req_query_string_start
;
856 SET_ERRNO(HPE_INVALID_HOST
);
864 if (IS_NUM(ch
)) break;
870 /* The request line looks like:
871 * "GET http://foo.bar.com:1234 HTTP/1.1"
872 * That is, there is no path.
875 state
= s_req_http_start
;
878 state
= s_req_query_string_start
;
881 SET_ERRNO(HPE_INVALID_PORT
);
889 if (IS_URL_CHAR(ch
)) break;
894 state
= s_req_http_start
;
898 parser
->http_major
= 0;
899 parser
->http_minor
= 9;
900 state
= s_req_line_almost_done
;
904 parser
->http_major
= 0;
905 parser
->http_minor
= 9;
906 state
= s_header_field_start
;
909 state
= s_req_query_string_start
;
912 state
= s_req_fragment_start
;
915 SET_ERRNO(HPE_INVALID_PATH
);
921 case s_req_query_string_start
:
923 if (IS_URL_CHAR(ch
)) {
924 state
= s_req_query_string
;
930 break; /* XXX ignore extra '?' ... is this right? */
933 state
= s_req_http_start
;
937 parser
->http_major
= 0;
938 parser
->http_minor
= 9;
939 state
= s_req_line_almost_done
;
943 parser
->http_major
= 0;
944 parser
->http_minor
= 9;
945 state
= s_header_field_start
;
948 state
= s_req_fragment_start
;
951 SET_ERRNO(HPE_INVALID_QUERY_STRING
);
957 case s_req_query_string
:
959 if (IS_URL_CHAR(ch
)) break;
963 /* allow extra '?' in query string */
967 state
= s_req_http_start
;
971 parser
->http_major
= 0;
972 parser
->http_minor
= 9;
973 state
= s_req_line_almost_done
;
977 parser
->http_major
= 0;
978 parser
->http_minor
= 9;
979 state
= s_header_field_start
;
982 state
= s_req_fragment_start
;
985 SET_ERRNO(HPE_INVALID_QUERY_STRING
);
991 case s_req_fragment_start
:
993 if (IS_URL_CHAR(ch
)) {
994 state
= s_req_fragment
;
1001 state
= s_req_http_start
;
1005 parser
->http_major
= 0;
1006 parser
->http_minor
= 9;
1007 state
= s_req_line_almost_done
;
1011 parser
->http_major
= 0;
1012 parser
->http_minor
= 9;
1013 state
= s_header_field_start
;
1016 state
= s_req_fragment
;
1021 SET_ERRNO(HPE_INVALID_FRAGMENT
);
1027 case s_req_fragment
:
1029 if (IS_URL_CHAR(ch
)) break;
1034 state
= s_req_http_start
;
1038 parser
->http_major
= 0;
1039 parser
->http_minor
= 9;
1040 state
= s_req_line_almost_done
;
1044 parser
->http_major
= 0;
1045 parser
->http_minor
= 9;
1046 state
= s_header_field_start
;
1052 SET_ERRNO(HPE_INVALID_FRAGMENT
);
1058 case s_req_http_start
:
1062 state
= s_req_http_H
;
1067 SET_ERRNO(HPE_INVALID_CONSTANT
);
1073 STRICT_CHECK(ch
!= 'T');
1074 state
= s_req_http_HT
;
1078 STRICT_CHECK(ch
!= 'T');
1079 state
= s_req_http_HTT
;
1082 case s_req_http_HTT
:
1083 STRICT_CHECK(ch
!= 'P');
1084 state
= s_req_http_HTTP
;
1087 case s_req_http_HTTP
:
1088 STRICT_CHECK(ch
!= '/');
1089 state
= s_req_first_http_major
;
1092 /* first digit of major HTTP version */
1093 case s_req_first_http_major
:
1094 if (ch
< '1' || ch
> '9') {
1095 SET_ERRNO(HPE_INVALID_VERSION
);
1099 parser
->http_major
= ch
- '0';
1100 state
= s_req_http_major
;
1103 /* major HTTP version or dot */
1104 case s_req_http_major
:
1107 state
= s_req_first_http_minor
;
1112 SET_ERRNO(HPE_INVALID_VERSION
);
1116 parser
->http_major
*= 10;
1117 parser
->http_major
+= ch
- '0';
1119 if (parser
->http_major
> 999) {
1120 SET_ERRNO(HPE_INVALID_VERSION
);
1127 /* first digit of minor HTTP version */
1128 case s_req_first_http_minor
:
1130 SET_ERRNO(HPE_INVALID_VERSION
);
1134 parser
->http_minor
= ch
- '0';
1135 state
= s_req_http_minor
;
1138 /* minor HTTP version or end of request line */
1139 case s_req_http_minor
:
1142 state
= s_req_line_almost_done
;
1147 state
= s_header_field_start
;
1151 /* XXX allow spaces after digit? */
1154 SET_ERRNO(HPE_INVALID_VERSION
);
1158 parser
->http_minor
*= 10;
1159 parser
->http_minor
+= ch
- '0';
1161 if (parser
->http_minor
> 999) {
1162 SET_ERRNO(HPE_INVALID_VERSION
);
1169 /* end of request line */
1170 case s_req_line_almost_done
:
1173 SET_ERRNO(HPE_LF_EXPECTED
);
1177 state
= s_header_field_start
;
1181 case s_header_field_start
:
1185 state
= s_headers_almost_done
;
1190 /* they might be just sending \n instead of \r\n so this would be
1191 * the second \n to denote the end of headers*/
1192 state
= s_headers_almost_done
;
1193 goto headers_almost_done
;
1199 SET_ERRNO(HPE_INVALID_HEADER_TOKEN
);
1206 state
= s_header_field
;
1214 header_state
= h_matching_proxy_connection
;
1218 header_state
= h_matching_transfer_encoding
;
1222 header_state
= h_matching_upgrade
;
1226 header_state
= h_general
;
1232 case s_header_field
:
1237 switch (header_state
) {
1243 header_state
= (c
== 'o' ? h_CO
: h_general
);
1248 header_state
= (c
== 'n' ? h_CON
: h_general
);
1255 header_state
= h_matching_connection
;
1258 header_state
= h_matching_content_length
;
1261 header_state
= h_general
;
1268 case h_matching_connection
:
1270 if (index
> sizeof(CONNECTION
)-1
1271 || c
!= CONNECTION
[index
]) {
1272 header_state
= h_general
;
1273 } else if (index
== sizeof(CONNECTION
)-2) {
1274 header_state
= h_connection
;
1278 /* proxy-connection */
1280 case h_matching_proxy_connection
:
1282 if (index
> sizeof(PROXY_CONNECTION
)-1
1283 || c
!= PROXY_CONNECTION
[index
]) {
1284 header_state
= h_general
;
1285 } else if (index
== sizeof(PROXY_CONNECTION
)-2) {
1286 header_state
= h_connection
;
1290 /* content-length */
1292 case h_matching_content_length
:
1294 if (index
> sizeof(CONTENT_LENGTH
)-1
1295 || c
!= CONTENT_LENGTH
[index
]) {
1296 header_state
= h_general
;
1297 } else if (index
== sizeof(CONTENT_LENGTH
)-2) {
1298 header_state
= h_content_length
;
1302 /* transfer-encoding */
1304 case h_matching_transfer_encoding
:
1306 if (index
> sizeof(TRANSFER_ENCODING
)-1
1307 || c
!= TRANSFER_ENCODING
[index
]) {
1308 header_state
= h_general
;
1309 } else if (index
== sizeof(TRANSFER_ENCODING
)-2) {
1310 header_state
= h_transfer_encoding
;
1316 case h_matching_upgrade
:
1318 if (index
> sizeof(UPGRADE
)-1
1319 || c
!= UPGRADE
[index
]) {
1320 header_state
= h_general
;
1321 } else if (index
== sizeof(UPGRADE
)-2) {
1322 header_state
= h_upgrade
;
1327 case h_content_length
:
1328 case h_transfer_encoding
:
1330 if (ch
!= ' ') header_state
= h_general
;
1334 assert(0 && "Unknown header_state");
1341 CALLBACK(header_field
);
1342 state
= s_header_value_start
;
1347 state
= s_header_almost_done
;
1348 CALLBACK(header_field
);
1353 CALLBACK(header_field
);
1354 state
= s_header_field_start
;
1358 SET_ERRNO(HPE_INVALID_HEADER_TOKEN
);
1362 case s_header_value_start
:
1364 if (ch
== ' ' || ch
== '\t') break;
1368 state
= s_header_value
;
1372 CALLBACK(header_value
);
1373 header_state
= h_general
;
1374 state
= s_header_almost_done
;
1379 CALLBACK(header_value
);
1380 state
= s_header_field_start
;
1386 switch (header_state
) {
1388 parser
->flags
|= F_UPGRADE
;
1389 header_state
= h_general
;
1392 case h_transfer_encoding
:
1393 /* looking for 'Transfer-Encoding: chunked' */
1395 header_state
= h_matching_transfer_encoding_chunked
;
1397 header_state
= h_general
;
1401 case h_content_length
:
1403 SET_ERRNO(HPE_INVALID_CONTENT_LENGTH
);
1407 parser
->content_length
= ch
- '0';
1411 /* looking for 'Connection: keep-alive' */
1413 header_state
= h_matching_connection_keep_alive
;
1414 /* looking for 'Connection: close' */
1415 } else if (c
== 'c') {
1416 header_state
= h_matching_connection_close
;
1418 header_state
= h_general
;
1423 header_state
= h_general
;
1429 case s_header_value
:
1433 CALLBACK(header_value
);
1434 state
= s_header_almost_done
;
1439 CALLBACK(header_value
);
1440 goto header_almost_done
;
1445 switch (header_state
) {
1450 case h_transfer_encoding
:
1451 assert(0 && "Shouldn't get here.");
1454 case h_content_length
:
1455 if (ch
== ' ') break;
1457 SET_ERRNO(HPE_INVALID_CONTENT_LENGTH
);
1461 parser
->content_length
*= 10;
1462 parser
->content_length
+= ch
- '0';
1465 /* Transfer-Encoding: chunked */
1466 case h_matching_transfer_encoding_chunked
:
1468 if (index
> sizeof(CHUNKED
)-1
1469 || c
!= CHUNKED
[index
]) {
1470 header_state
= h_general
;
1471 } else if (index
== sizeof(CHUNKED
)-2) {
1472 header_state
= h_transfer_encoding_chunked
;
1476 /* looking for 'Connection: keep-alive' */
1477 case h_matching_connection_keep_alive
:
1479 if (index
> sizeof(KEEP_ALIVE
)-1
1480 || c
!= KEEP_ALIVE
[index
]) {
1481 header_state
= h_general
;
1482 } else if (index
== sizeof(KEEP_ALIVE
)-2) {
1483 header_state
= h_connection_keep_alive
;
1487 /* looking for 'Connection: close' */
1488 case h_matching_connection_close
:
1490 if (index
> sizeof(CLOSE
)-1 || c
!= CLOSE
[index
]) {
1491 header_state
= h_general
;
1492 } else if (index
== sizeof(CLOSE
)-2) {
1493 header_state
= h_connection_close
;
1497 case h_transfer_encoding_chunked
:
1498 case h_connection_keep_alive
:
1499 case h_connection_close
:
1500 if (ch
!= ' ') header_state
= h_general
;
1504 state
= s_header_value
;
1505 header_state
= h_general
;
1511 case s_header_almost_done
:
1514 STRICT_CHECK(ch
!= LF
);
1516 state
= s_header_value_lws
;
1518 switch (header_state
) {
1519 case h_connection_keep_alive
:
1520 parser
->flags
|= F_CONNECTION_KEEP_ALIVE
;
1522 case h_connection_close
:
1523 parser
->flags
|= F_CONNECTION_CLOSE
;
1525 case h_transfer_encoding_chunked
:
1526 parser
->flags
|= F_CHUNKED
;
1534 case s_header_value_lws
:
1536 if (ch
== ' ' || ch
== '\t')
1537 state
= s_header_value_start
;
1540 state
= s_header_field_start
;
1541 goto header_field_start
;
1546 case s_headers_almost_done
:
1547 headers_almost_done
:
1549 STRICT_CHECK(ch
!= LF
);
1551 if (parser
->flags
& F_TRAILING
) {
1552 /* End of a chunked request */
1553 CALLBACK2(message_complete
);
1554 state
= NEW_MESSAGE();
1560 if (parser
->flags
& F_UPGRADE
|| parser
->method
== HTTP_CONNECT
) {
1561 parser
->upgrade
= 1;
1564 /* Here we call the headers_complete callback. This is somewhat
1565 * different than other callbacks because if the user returns 1, we
1566 * will interpret that as saying that this message has no body. This
1567 * is needed for the annoying case of recieving a response to a HEAD
1570 if (settings
->on_headers_complete
) {
1571 switch (settings
->on_headers_complete(parser
)) {
1576 parser
->flags
|= F_SKIPBODY
;
1580 parser
->state
= state
;
1581 SET_ERRNO(HPE_CB_headers_complete
);
1582 return p
- data
; /* Error */
1586 /* Exit, the rest of the connect is in a different protocol. */
1587 if (parser
->upgrade
) {
1588 CALLBACK2(message_complete
);
1589 return (p
- data
) + 1;
1592 if (parser
->flags
& F_SKIPBODY
) {
1593 CALLBACK2(message_complete
);
1594 state
= NEW_MESSAGE();
1595 } else if (parser
->flags
& F_CHUNKED
) {
1596 /* chunked encoding - ignore Content-Length header */
1597 state
= s_chunk_size_start
;
1599 if (parser
->content_length
== 0) {
1600 /* Content-Length header given but zero: Content-Length: 0\r\n */
1601 CALLBACK2(message_complete
);
1602 state
= NEW_MESSAGE();
1603 } else if (parser
->content_length
> 0) {
1604 /* Content-Length header given and non-zero */
1605 state
= s_body_identity
;
1607 if (parser
->type
== HTTP_REQUEST
|| http_should_keep_alive(parser
)) {
1608 /* Assume content-length 0 - read the next */
1609 CALLBACK2(message_complete
);
1610 state
= NEW_MESSAGE();
1612 /* Read body until EOF */
1613 state
= s_body_identity_eof
;
1621 case s_body_identity
:
1622 to_read
= MIN(pe
- p
, (int64_t)parser
->content_length
);
1624 if (settings
->on_body
) settings
->on_body(parser
, p
, to_read
);
1626 parser
->content_length
-= to_read
;
1627 if (parser
->content_length
== 0) {
1628 CALLBACK2(message_complete
);
1629 state
= NEW_MESSAGE();
1634 /* read until EOF */
1635 case s_body_identity_eof
:
1638 if (settings
->on_body
) settings
->on_body(parser
, p
, to_read
);
1643 case s_chunk_size_start
:
1646 assert(parser
->flags
& F_CHUNKED
);
1648 unhex_val
= unhex
[(unsigned char)ch
];
1649 if (unhex_val
== -1) {
1650 SET_ERRNO(HPE_INVALID_CHUNK_SIZE
);
1654 parser
->content_length
= unhex_val
;
1655 state
= s_chunk_size
;
1661 assert(parser
->flags
& F_CHUNKED
);
1664 state
= s_chunk_size_almost_done
;
1668 unhex_val
= unhex
[(unsigned char)ch
];
1670 if (unhex_val
== -1) {
1671 if (ch
== ';' || ch
== ' ') {
1672 state
= s_chunk_parameters
;
1676 SET_ERRNO(HPE_INVALID_CHUNK_SIZE
);
1680 parser
->content_length
*= 16;
1681 parser
->content_length
+= unhex_val
;
1685 case s_chunk_parameters
:
1687 assert(parser
->flags
& F_CHUNKED
);
1688 /* just ignore this shit. TODO check for overflow */
1690 state
= s_chunk_size_almost_done
;
1696 case s_chunk_size_almost_done
:
1698 assert(parser
->flags
& F_CHUNKED
);
1699 STRICT_CHECK(ch
!= LF
);
1703 if (parser
->content_length
== 0) {
1704 parser
->flags
|= F_TRAILING
;
1705 state
= s_header_field_start
;
1707 state
= s_chunk_data
;
1714 assert(parser
->flags
& F_CHUNKED
);
1716 to_read
= MIN(pe
- p
, (int64_t)(parser
->content_length
));
1719 if (settings
->on_body
) settings
->on_body(parser
, p
, to_read
);
1723 if (to_read
== parser
->content_length
) {
1724 state
= s_chunk_data_almost_done
;
1727 parser
->content_length
-= to_read
;
1731 case s_chunk_data_almost_done
:
1732 assert(parser
->flags
& F_CHUNKED
);
1733 STRICT_CHECK(ch
!= CR
);
1734 state
= s_chunk_data_done
;
1737 case s_chunk_data_done
:
1738 assert(parser
->flags
& F_CHUNKED
);
1739 STRICT_CHECK(ch
!= LF
);
1740 state
= s_chunk_size_start
;
1744 assert(0 && "unhandled state");
1745 SET_ERRNO(HPE_INVALID_INTERNAL_STATE
);
1750 CALLBACK(header_field
);
1751 CALLBACK(header_value
);
1754 parser
->state
= state
;
1755 parser
->header_state
= header_state
;
1756 parser
->index
= index
;
1757 parser
->nread
= nread
;
1762 if (HTTP_PARSER_ERRNO(parser
) == HPE_OK
) {
1763 SET_ERRNO(HPE_UNKNOWN
);
1771 http_should_keep_alive (http_parser
*parser
)
1773 if (parser
->http_major
> 0 && parser
->http_minor
> 0) {
1775 if (parser
->flags
& F_CONNECTION_CLOSE
) {
1781 /* HTTP/1.0 or earlier */
1782 if (parser
->flags
& F_CONNECTION_KEEP_ALIVE
) {
1791 const char * http_method_str (enum http_method m
)
1793 return method_strings
[m
];
1798 http_parser_init (http_parser
*parser
, enum http_parser_type t
, char numerichost
)
1800 parser
->numerichost
= numerichost
;
1802 parser
->state
= (t
== HTTP_REQUEST
? s_start_req
: (t
== HTTP_RESPONSE
? s_start_res
: s_start_req_or_res
));
1804 parser
->upgrade
= 0;
1807 parser
->http_errno
= 0;
1811 http_errno_name(enum http_errno err
) {
1812 assert(err
< (sizeof(http_strerror_tab
)/sizeof(http_strerror_tab
[0])));
1813 return http_strerror_tab
[err
].name
;
1817 http_errno_description(enum http_errno err
) {
1818 assert(err
< (sizeof(http_strerror_tab
)/sizeof(http_strerror_tab
[0])));
1819 return http_strerror_tab
[err
].description
;