18 #if defined(_WIN32) && !defined(__MINGW32__) && \
19 (!defined(_MSC_VER) || _MSC_VER<1600) && !defined(__WINE__)
21 typedef __int8 int8_t;
22 typedef unsigned __int8 uint8_t;
23 typedef __int16 int16_t;
24 typedef unsigned __int16 uint16_t;
25 typedef __int32 int32_t;
26 typedef unsigned __int32 uint32_t;
27 typedef __int64 int64_t;
28 typedef unsigned __int64 uint64_t;
29 #elif (defined(__sun) || defined(__sun__)) && defined(__SunOS_5_9)
30 #include <sys/inttypes.h>
40 #include "crow/common.h"
50 #ifndef CROW_HTTP_MAX_HEADER_SIZE
51 # define CROW_HTTP_MAX_HEADER_SIZE (80*1024)
54 typedef struct http_parser http_parser;
55 typedef struct http_parser_settings http_parser_settings;
75 typedef int (*http_data_cb) (http_parser*,
const char *at,
size_t length);
76 typedef int (*http_cb) (http_parser*);
80 enum http_connection_flags
82 , F_CONNECTION_KEEP_ALIVE = 1 << 1
83 , F_CONNECTION_CLOSE = 1 << 2
87 , F_CONTENTLENGTH = 1 << 6
95 #define CROW_HTTP_ERRNO_MAP(CROW_XX) \
97 CROW_XX(OK, "success") \
100 CROW_XX(CB_message_begin, "the on_message_begin callback failed") \
101 CROW_XX(CB_method, "the on_method callback failed") \
102 CROW_XX(CB_url, "the \"on_url\" callback failed") \
103 CROW_XX(CB_header_field, "the \"on_header_field\" callback failed") \
104 CROW_XX(CB_header_value, "the \"on_header_value\" callback failed") \
105 CROW_XX(CB_headers_complete, "the \"on_headers_complete\" callback failed") \
106 CROW_XX(CB_body, "the \"on_body\" callback failed") \
107 CROW_XX(CB_message_complete, "the \"on_message_complete\" callback failed") \
108 CROW_XX(CB_status, "the \"on_status\" callback failed") \
111 CROW_XX(INVALID_EOF_STATE, "stream ended at an unexpected time") \
112 CROW_XX(HEADER_OVERFLOW, "too many header bytes seen; overflow detected") \
113 CROW_XX(CLOSED_CONNECTION, "data received after completed connection: close message") \
114 CROW_XX(INVALID_VERSION, "invalid HTTP version") \
115 CROW_XX(INVALID_STATUS, "invalid HTTP status code") \
116 CROW_XX(INVALID_METHOD, "invalid HTTP method") \
117 CROW_XX(INVALID_URL, "invalid URL") \
118 CROW_XX(INVALID_HOST, "invalid host") \
119 CROW_XX(INVALID_PORT, "invalid port") \
120 CROW_XX(INVALID_PATH, "invalid path") \
121 CROW_XX(INVALID_QUERY_STRING, "invalid query string") \
122 CROW_XX(INVALID_FRAGMENT, "invalid fragment") \
123 CROW_XX(LF_EXPECTED, "LF character expected") \
124 CROW_XX(INVALID_HEADER_TOKEN, "invalid character in header") \
125 CROW_XX(INVALID_CONTENT_LENGTH, "invalid character in content-length header") \
126 CROW_XX(UNEXPECTED_CONTENT_LENGTH, "unexpected content-length header") \
127 CROW_XX(INVALID_CHUNK_SIZE, "invalid character in chunk size header") \
128 CROW_XX(INVALID_CONSTANT, "invalid constant string") \
129 CROW_XX(INVALID_INTERNAL_STATE, "encountered unexpected internal state") \
130 CROW_XX(STRICT, "strict mode assertion failed") \
131 CROW_XX(UNKNOWN, "an unknown error occurred") \
132 CROW_XX(INVALID_TRANSFER_ENCODING, "request has invalid transfer-encoding") \
136 #define CROW_HTTP_ERRNO_GEN(n, s) CHPE_##n,
138 CROW_HTTP_ERRNO_MAP(CROW_HTTP_ERRNO_GEN)
140 #undef CROW_HTTP_ERRNO_GEN
144 #define CROW_HTTP_PARSER_ERRNO(p) ((enum http_errno)(p)->http_errno)
151 unsigned int state : 8;
152 unsigned int header_state : 7;
153 unsigned int index : 5;
154 unsigned int uses_transfer_encoding : 1;
155 unsigned int allow_chunked_length : 1;
156 unsigned int lenient_http_headers : 1;
159 uint64_t content_length;
160 unsigned long qs_point;
164 unsigned char http_minor;
165 unsigned int method : 8;
166 unsigned int http_errno : 7;
173 unsigned int upgrade : 1;
182 http_cb on_message_begin;
185 http_data_cb on_header_field;
186 http_data_cb on_header_value;
187 http_cb on_headers_complete;
188 http_data_cb on_body;
189 http_cb on_message_complete;
195 static uint32_t max_header_size = CROW_HTTP_MAX_HEADER_SIZE;
197 #ifndef CROW_ULLONG_MAX
198 # define CROW_ULLONG_MAX ((uint64_t) -1)
202 # define CROW_MIN(a,b) ((a) < (b) ? (a) : (b))
205 #ifndef CROW_ARRAY_SIZE
206 # define CROW_ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
210 # define CROW_BIT_AT(a, i) \
211 (!!((unsigned int) (a)[(unsigned int) (i) >> 3] & \
212 (1 << ((unsigned int) (i) & 7))))
215 #define CROW_SET_ERRNO(e) \
217 parser->nread = nread; \
218 parser->http_errno = (e); \
222 #define CROW_CALLBACK_NOTIFY_(FOR, ER) \
224 assert(CROW_HTTP_PARSER_ERRNO(parser) == CHPE_OK); \
226 if (CROW_LIKELY(settings->on_##FOR)) { \
227 if (CROW_UNLIKELY(0 != settings->on_##FOR(parser))) { \
228 CROW_SET_ERRNO(CHPE_CB_##FOR); \
232 if (CROW_UNLIKELY(CROW_HTTP_PARSER_ERRNO(parser) != CHPE_OK)) { \
239 #define CROW_CALLBACK_NOTIFY(FOR) CROW_CALLBACK_NOTIFY_(FOR, p - data + 1)
242 #define CROW_CALLBACK_NOTIFY_NOADVANCE(FOR) CROW_CALLBACK_NOTIFY_(FOR, p - data)
245 #define CROW_CALLBACK_DATA_(FOR, LEN, ER) \
247 assert(CROW_HTTP_PARSER_ERRNO(parser) == CHPE_OK); \
250 if (CROW_LIKELY(settings->on_##FOR)) { \
251 if (CROW_UNLIKELY(0 != \
252 settings->on_##FOR(parser, FOR##_mark, (LEN)))) { \
253 CROW_SET_ERRNO(CHPE_CB_##FOR); \
257 if (CROW_UNLIKELY(CROW_HTTP_PARSER_ERRNO(parser) != CHPE_OK)) {\
266 #define CROW_CALLBACK_DATA(FOR) \
267 CROW_CALLBACK_DATA_(FOR, p - FOR##_mark, p - data + 1)
270 #define CROW_CALLBACK_DATA_NOADVANCE(FOR) \
271 CROW_CALLBACK_DATA_(FOR, p - FOR##_mark, p - data)
274 #define CROW_MARK(FOR) \
292 #define CROW_COUNT_HEADER_SIZE(V) \
294 nread += (uint32_t)(V); \
295 if (CROW_UNLIKELY(nread > max_header_size)) { \
296 CROW_SET_ERRNO(CHPE_HEADER_OVERFLOW); \
300 #define CROW_REEXECUTE() \
303 #define CROW_PROXY_CONNECTION "proxy-connection"
304 #define CROW_CONNECTION "connection"
305 #define CROW_CONTENT_LENGTH "content-length"
306 #define CROW_TRANSFER_ENCODING "transfer-encoding"
307 #define CROW_UPGRADE "upgrade"
308 #define CROW_CHUNKED "chunked"
309 #define CROW_KEEP_ALIVE "keep-alive"
310 #define CROW_CLOSE "close"
323 s_req_spaces_before_url,
326 s_req_schema_slash_slash,
329 s_req_server_with_at,
331 s_req_query_string_start,
344 s_req_line_almost_done
347 s_header_field_start,
349 s_header_value_discard_ws,
350 s_header_value_discard_ws_almost_done,
351 s_header_value_discard_lws,
352 s_header_value_start,
363 s_chunk_size_almost_done
366 s_headers_almost_done,
376 s_chunk_data_almost_done,
388 #define CROW_PARSING_HEADER(state) (state <= s_headers_done)
397 , h_matching_connection
398 , h_matching_proxy_connection
399 , h_matching_content_length
400 , h_matching_transfer_encoding
405 , h_content_length_num
406 , h_content_length_ws
407 , h_transfer_encoding
410 , h_matching_transfer_encoding_token_start
411 , h_matching_transfer_encoding_chunked
412 , h_matching_transfer_encoding_token
414 , h_matching_connection_keep_alive
415 , h_matching_connection_close
417 , h_transfer_encoding_chunked
418 , h_connection_keep_alive
425 , s_http_userinfo_start
428 , s_http_host_v6_start
432 , s_http_host_v6_zone_start
433 , s_http_host_v6_zone
434 , s_http_host_port_start
439 #define CROW_LOWER(c) (unsigned char)(c | 0x20)
440 #define CROW_IS_ALPHA(c) (CROW_LOWER(c) >= 'a' && CROW_LOWER(c) <= 'z')
441 #define CROW_IS_NUM(c) ((c) >= '0' && (c) <= '9')
442 #define CROW_IS_ALPHANUM(c) (CROW_IS_ALPHA(c) || CROW_IS_NUM(c))
444 #define CROW_IS_MARK(c) ((c) == '-' || (c) == '_' || (c) == '.' || \
445 (c) == '!' || (c) == '~' || (c) == '*' || (c) == '\'' || (c) == '(' || \
447 #define CROW_IS_USERINFO_CHAR(c) (CROW_IS_ALPHANUM(c) || CROW_IS_MARK(c) || (c) == '%' || \
448 (c) == ';' || (c) == ':' || (c) == '&' || (c) == '=' || (c) == '+' || \
449 (c) == '$' || (c) == ',')
451 #define CROW_TOKEN(c) (tokens[(unsigned char)c])
452 #define CROW_IS_URL_CHAR(c) (CROW_BIT_AT(normal_url_char, (unsigned char)c))
459 #define CROW_IS_HEADER_CHAR(ch) \
460 (ch == cr || ch == lf || ch == 9 || ((unsigned char)ch > 31 && ch != 127))
462 #define CROW_start_state s_start_req
464 # define CROW_STRICT_CHECK(cond) \
467 CROW_SET_ERRNO(CHPE_STRICT); \
471 #define CROW_NEW_MESSAGE() (CROW_start_state)
485 parse_url_char(
enum state s,
const char ch, http_parser *parser,
const char* url_mark,
const char* p)
490 static const uint8_t normal_url_char[32] = {
492 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0,
494 0 |CROW_T(2)| 0 | 0 |CROW_T(16)| 0 | 0 | 0,
496 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0,
498 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0,
500 0 | 2 | 4 | 0 | 16 | 32 | 64 | 128,
502 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
504 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
506 1 | 2 | 4 | 8 | 16 | 32 | 64 | 0,
508 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
510 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
512 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
514 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
516 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
518 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
520 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
522 1 | 2 | 4 | 8 | 16 | 32 | 64 | 0, };
526 if (ch ==
' ' || ch ==
'\r' || ch ==
'\n') {
529 if (ch ==
'\t' || ch ==
'\f') {
534 case s_req_spaces_before_url:
539 if (ch ==
'/' || ch ==
'*') {
543 if (CROW_IS_ALPHA(ch)) {
550 if (CROW_IS_ALPHA(ch)) {
555 return s_req_schema_slash;
560 case s_req_schema_slash:
562 return s_req_schema_slash_slash;
567 case s_req_schema_slash_slash:
569 return s_req_server_start;
574 case s_req_server_with_at:
580 case s_req_server_start:
587 parser->qs_point = p - url_mark;
588 return s_req_query_string_start;
592 return s_req_server_with_at;
595 if (CROW_IS_USERINFO_CHAR(ch) || ch ==
'[' || ch ==
']') {
602 if (CROW_IS_URL_CHAR(ch)) {
607 parser->qs_point = p - url_mark;
608 return s_req_query_string_start;
613 case s_req_query_string_start:
614 case s_req_query_string:
615 if (CROW_IS_URL_CHAR(ch)) {
616 return s_req_query_string;
620 return s_req_query_string;
633 inline size_t http_parser_execute (http_parser *parser,
634 const http_parser_settings *settings,
646 static const char tokens[256] = {
648 0, 0, 0, 0, 0, 0, 0, 0,
650 0, 0, 0, 0, 0, 0, 0, 0,
652 0, 0, 0, 0, 0, 0, 0, 0,
654 0, 0, 0, 0, 0, 0, 0, 0,
656 0,
'!', 0,
'#',
'$',
'%',
'&',
'\'',
658 0, 0,
'*',
'+', 0,
'-',
'.', 0,
660 '0',
'1',
'2',
'3',
'4',
'5',
'6',
'7',
662 '8',
'9', 0, 0, 0, 0, 0, 0,
664 0,
'a',
'b',
'c',
'd',
'e',
'f',
'g',
666 'h',
'i',
'j',
'k',
'l',
'm',
'n',
'o',
668 'p',
'q',
'r',
's',
't',
'u',
'v',
'w',
670 'x',
'y',
'z', 0, 0, 0,
'^',
'_',
672 '`',
'a',
'b',
'c',
'd',
'e',
'f',
'g',
674 'h',
'i',
'j',
'k',
'l',
'm',
'n',
'o',
676 'p',
'q',
'r',
's',
't',
'u',
'v',
'w',
678 'x',
'y',
'z', 0,
'|', 0,
'~', 0 };
681 static const int8_t unhex[256] =
682 {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
683 ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
684 ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
685 , 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1
686 ,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1
687 ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
688 ,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1
689 ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
696 const char *p = data;
697 const char *header_field_mark = 0;
698 const char *header_value_mark = 0;
699 const char *url_mark = 0;
700 const char *url_start_mark = 0;
701 const char *body_mark = 0;
702 const unsigned int lenient = parser->lenient_http_headers;
703 const unsigned int allow_chunked_length = parser->allow_chunked_length;
705 uint32_t nread = parser->nread;
708 if (CROW_HTTP_PARSER_ERRNO(parser) != CHPE_OK) {
713 switch (parser->state) {
714 case s_body_identity_eof:
716 CROW_CALLBACK_NOTIFY_NOADVANCE(message_complete);
724 CROW_SET_ERRNO(CHPE_INVALID_EOF_STATE);
730 if (parser->state == s_header_field)
731 header_field_mark = data;
732 if (parser->state == s_header_value)
733 header_value_mark = data;
734 switch (parser->state) {
737 case s_req_schema_slash:
738 case s_req_schema_slash_slash:
739 case s_req_server_start:
741 case s_req_server_with_at:
742 case s_req_query_string_start:
743 case s_req_query_string:
750 for (p=data; p != data + len; p++) {
753 if (CROW_PARSING_HEADER(parser->state))
754 CROW_COUNT_HEADER_SIZE(1);
757 switch (parser->state) {
763 if (CROW_LIKELY(ch == cr || ch == lf))
766 CROW_SET_ERRNO(CHPE_CLOSED_CONNECTION);
771 if (ch == cr || ch == lf)
774 parser->uses_transfer_encoding = 0;
775 parser->content_length = CROW_ULLONG_MAX;
777 if (CROW_UNLIKELY(!CROW_IS_ALPHA(ch))) {
778 CROW_SET_ERRNO(CHPE_INVALID_METHOD);
785 case 'A': parser->method = (unsigned)HTTPMethod::Acl;
break;
786 case 'B': parser->method = (unsigned)HTTPMethod::Bind;
break;
787 case 'C': parser->method = (unsigned)HTTPMethod::Connect;
break;
788 case 'D': parser->method = (unsigned)HTTPMethod::Delete;
break;
789 case 'G': parser->method = (unsigned)HTTPMethod::Get;
break;
790 case 'H': parser->method = (unsigned)HTTPMethod::Head;
break;
791 case 'L': parser->method = (unsigned)HTTPMethod::Lock;
break;
792 case 'M': parser->method = (unsigned)HTTPMethod::MkCol;
break;
793 case 'N': parser->method = (unsigned)HTTPMethod::Notify;
break;
794 case 'O': parser->method = (unsigned)HTTPMethod::Options;
break;
795 case 'P': parser->method = (unsigned)HTTPMethod::Post;
break;
796 case 'R': parser->method = (unsigned)HTTPMethod::Report;
break;
797 case 'S': parser->method = (unsigned)HTTPMethod::Subscribe;
break;
798 case 'T': parser->method = (unsigned)HTTPMethod::Trace;
break;
799 case 'U': parser->method = (unsigned)HTTPMethod::Unlock;
break;
801 CROW_SET_ERRNO(CHPE_INVALID_METHOD);
804 parser->state = s_req_method;
806 CROW_CALLBACK_NOTIFY(message_begin);
814 if (CROW_UNLIKELY(ch ==
'\0')) {
815 CROW_SET_ERRNO(CHPE_INVALID_METHOD);
819 matcher = method_strings[parser->method];
820 if (ch ==
' ' && matcher[parser->index] ==
'\0') {
821 parser->state = s_req_spaces_before_url;
822 }
else if (ch == matcher[parser->index]) {
824 }
else if ((ch >=
'A' && ch <=
'Z') || ch ==
'-') {
826 switch (parser->method << 16 | parser->index << 8 | ch) {
827 #define CROW_XX(meth, pos, ch, new_meth) \
828 case ((unsigned)HTTPMethod::meth << 16 | pos << 8 | ch): \
829 parser->method = (unsigned)HTTPMethod::new_meth; break;
831 CROW_XX(Post, 1,
'U', Put)
832 CROW_XX(Post, 1,
'A', Patch)
833 CROW_XX(Post, 1,
'R', Propfind)
834 CROW_XX(Put, 2,
'R', Purge)
835 CROW_XX(Connect, 1,
'H', Checkout)
836 CROW_XX(Connect, 2,
'P', Copy)
837 CROW_XX(MkCol, 1,
'O', Move)
838 CROW_XX(MkCol, 1,
'E', Merge)
839 CROW_XX(MkCol, 1,
'-', MSearch)
840 CROW_XX(MkCol, 2,
'A', MkActivity)
841 CROW_XX(MkCol, 3,
'A', MkCalendar)
842 CROW_XX(Subscribe, 1,
'E', Search)
843 CROW_XX(Subscribe, 1,
'O', Source)
844 CROW_XX(Report, 2,
'B', Rebind)
845 CROW_XX(Propfind, 4,
'P', Proppatch)
846 CROW_XX(Lock, 1,
'I', Link)
847 CROW_XX(Unlock, 2,
'S', Unsubscribe)
848 CROW_XX(Unlock, 2,
'B', Unbind)
849 CROW_XX(Unlock, 3,
'I', Unlink)
852 CROW_SET_ERRNO(CHPE_INVALID_METHOD);
856 CROW_SET_ERRNO(CHPE_INVALID_METHOD);
860 CROW_CALLBACK_NOTIFY_NOADVANCE(method);
866 case s_req_spaces_before_url:
868 if (ch ==
' ')
break;
871 CROW_MARK(url_start);
872 if (parser->method == (
unsigned)HTTPMethod::Connect) {
873 parser->state = s_req_server_start;
876 parser->state = parse_url_char(
static_cast<state
>(parser->state), ch, parser, url_start_mark, p);
877 if (CROW_UNLIKELY(parser->state == s_dead)) {
878 CROW_SET_ERRNO(CHPE_INVALID_URL);
886 case s_req_schema_slash:
887 case s_req_schema_slash_slash:
888 case s_req_server_start:
895 CROW_SET_ERRNO(CHPE_INVALID_URL);
898 parser->state = parse_url_char(
static_cast<state
>(parser->state), ch, parser, url_start_mark, p);
899 if (CROW_UNLIKELY(parser->state == s_dead)) {
900 CROW_SET_ERRNO(CHPE_INVALID_URL);
909 case s_req_server_with_at:
911 case s_req_query_string_start:
912 case s_req_query_string:
916 parser->state = s_req_http_start;
917 CROW_CALLBACK_DATA(url);
921 if (CROW_UNLIKELY(parser->method != (
unsigned)HTTPMethod::Get))
923 parser->state = s_dead;
924 CROW_SET_ERRNO(CHPE_INVALID_VERSION);
927 parser->http_major = 0;
928 parser->http_minor = 9;
929 parser->state = (ch == cr) ?
930 s_req_line_almost_done :
931 s_header_field_start;
932 CROW_CALLBACK_DATA(url);
935 parser->state = parse_url_char(
static_cast<state
>(parser->state), ch, parser, url_start_mark, p);
936 if (CROW_UNLIKELY(parser->state == s_dead)) {
937 CROW_SET_ERRNO(CHPE_INVALID_URL);
944 case s_req_http_start:
949 parser->state = s_req_http_H;
952 if (parser->method == (
unsigned)HTTPMethod::Source) {
953 parser->state = s_req_http_I;
958 CROW_SET_ERRNO(CHPE_INVALID_CONSTANT);
964 CROW_STRICT_CHECK(ch !=
'T');
965 parser->state = s_req_http_HT;
969 CROW_STRICT_CHECK(ch !=
'T');
970 parser->state = s_req_http_HTT;
974 CROW_STRICT_CHECK(ch !=
'P');
975 parser->state = s_req_http_HTTP;
979 CROW_STRICT_CHECK(ch !=
'C');
980 parser->state = s_req_http_IC;
984 CROW_STRICT_CHECK(ch !=
'E');
985 parser->state = s_req_http_HTTP;
988 case s_req_http_HTTP:
989 CROW_STRICT_CHECK(ch !=
'/');
990 parser->state = s_req_http_major;
994 case s_req_http_major:
995 if (CROW_UNLIKELY(!CROW_IS_NUM(ch))) {
996 CROW_SET_ERRNO(CHPE_INVALID_VERSION);
1000 parser->http_major = ch -
'0';
1001 parser->state = s_req_http_dot;
1004 case s_req_http_dot:
1006 if (CROW_UNLIKELY(ch !=
'.')) {
1007 CROW_SET_ERRNO(CHPE_INVALID_VERSION);
1011 parser->state = s_req_http_minor;
1016 case s_req_http_minor:
1017 if (CROW_UNLIKELY(!CROW_IS_NUM(ch))) {
1018 CROW_SET_ERRNO(CHPE_INVALID_VERSION);
1022 parser->http_minor = ch -
'0';
1023 parser->state = s_req_http_end;
1027 case s_req_http_end:
1030 parser->state = s_req_line_almost_done;
1035 parser->state = s_header_field_start;
1039 CROW_SET_ERRNO(CHPE_INVALID_VERSION);
1045 case s_req_line_almost_done:
1047 if (CROW_UNLIKELY(ch != lf)) {
1048 CROW_SET_ERRNO(CHPE_LF_EXPECTED);
1052 parser->state = s_header_field_start;
1056 case s_header_field_start:
1059 parser->state = s_headers_almost_done;
1066 parser->state = s_headers_almost_done;
1072 if (CROW_UNLIKELY(!c)) {
1073 CROW_SET_ERRNO(CHPE_INVALID_HEADER_TOKEN);
1077 CROW_MARK(header_field);
1080 parser->state = s_header_field;
1084 parser->header_state = h_C;
1088 parser->header_state = h_matching_proxy_connection;
1092 parser->header_state = h_matching_transfer_encoding;
1096 parser->header_state = h_matching_upgrade;
1100 parser->header_state = h_general;
1106 case s_header_field:
1108 const char* start = p;
1109 for (; p != data + len; p++) {
1116 switch (parser->header_state) {
1118 size_t left = data + len - p;
1119 const char* pe = p + CROW_MIN(left, max_header_size);
1120 while (p+1 < pe && CROW_TOKEN(p[1])) {
1128 parser->header_state = (c ==
'o' ? h_CO : h_general);
1133 parser->header_state = (c ==
'n' ? h_CON : h_general);
1140 parser->header_state = h_matching_connection;
1143 parser->header_state = h_matching_content_length;
1146 parser->header_state = h_general;
1153 case h_matching_connection:
1155 if (parser->index >
sizeof(CROW_CONNECTION)-1 || c != CROW_CONNECTION[parser->index]) {
1156 parser->header_state = h_general;
1157 }
else if (parser->index ==
sizeof(CROW_CONNECTION)-2) {
1158 parser->header_state = h_connection;
1164 case h_matching_proxy_connection:
1166 if (parser->index >
sizeof(CROW_PROXY_CONNECTION)-1 || c != CROW_PROXY_CONNECTION[parser->index]) {
1167 parser->header_state = h_general;
1168 }
else if (parser->index ==
sizeof(CROW_PROXY_CONNECTION)-2) {
1169 parser->header_state = h_connection;
1175 case h_matching_content_length:
1177 if (parser->index >
sizeof(CROW_CONTENT_LENGTH)-1 || c != CROW_CONTENT_LENGTH[parser->index]) {
1178 parser->header_state = h_general;
1179 }
else if (parser->index ==
sizeof(CROW_CONTENT_LENGTH)-2) {
1180 parser->header_state = h_content_length;
1186 case h_matching_transfer_encoding:
1188 if (parser->index >
sizeof(CROW_TRANSFER_ENCODING)-1 || c != CROW_TRANSFER_ENCODING[parser->index]) {
1189 parser->header_state = h_general;
1190 }
else if (parser->index ==
sizeof(CROW_TRANSFER_ENCODING)-2) {
1191 parser->header_state = h_transfer_encoding;
1192 parser->uses_transfer_encoding = 1;
1198 case h_matching_upgrade:
1200 if (parser->index >
sizeof(CROW_UPGRADE)-1 || c != CROW_UPGRADE[parser->index]) {
1201 parser->header_state = h_general;
1202 }
else if (parser->index ==
sizeof(CROW_UPGRADE)-2) {
1203 parser->header_state = h_upgrade;
1208 case h_content_length:
1209 case h_transfer_encoding:
1211 if (ch !=
' ') parser->header_state = h_general;
1215 assert(0 &&
"Unknown header_state");
1220 if (p == data + len) {
1222 CROW_COUNT_HEADER_SIZE(p - start);
1226 CROW_COUNT_HEADER_SIZE(p - start);
1229 parser->state = s_header_value_discard_ws;
1230 CROW_CALLBACK_DATA(header_field);
1246 CROW_SET_ERRNO(CHPE_INVALID_HEADER_TOKEN);
1250 case s_header_value_discard_ws:
1251 if (ch ==
' ' || ch ==
'\t')
break;
1254 parser->state = s_header_value_discard_ws_almost_done;
1259 parser->state = s_header_value_discard_lws;
1265 case s_header_value_start:
1267 CROW_MARK(header_value);
1269 parser->state = s_header_value;
1274 switch (parser->header_state) {
1281 if (ch !=
'h' || p+1 == (data + len) || *(p+1) !=
'2') {
1282 parser->flags |= F_UPGRADE;
1284 parser->header_state = h_general;
1287 case h_transfer_encoding:
1290 parser->header_state = h_matching_transfer_encoding_chunked;
1292 parser->header_state = h_matching_transfer_encoding_token;
1297 case h_matching_transfer_encoding_token_start:
1300 case h_content_length:
1301 if (CROW_UNLIKELY(!CROW_IS_NUM(ch))) {
1302 CROW_SET_ERRNO(CHPE_INVALID_CONTENT_LENGTH);
1306 if (parser->flags & F_CONTENTLENGTH) {
1307 CROW_SET_ERRNO(CHPE_UNEXPECTED_CONTENT_LENGTH);
1310 parser->flags |= F_CONTENTLENGTH;
1311 parser->content_length = ch -
'0';
1312 parser->header_state = h_content_length_num;
1317 case h_content_length_ws:
1323 parser->header_state = h_matching_connection_keep_alive;
1325 }
else if (c ==
'c') {
1326 parser->header_state = h_matching_connection_close;
1327 }
else if (c ==
' ' || c ==
'\t') {
1330 parser->header_state = h_general;
1335 parser->header_state = h_general;
1341 case s_header_value:
1343 const char* start = p;
1344 enum header_states h_state =
static_cast<header_states
>(parser->header_state);
1345 for (; p != data + len; p++) {
1349 parser->state = s_header_almost_done;
1350 parser->header_state = h_state;
1351 CROW_CALLBACK_DATA(header_value);
1356 parser->state = s_header_almost_done;
1357 CROW_COUNT_HEADER_SIZE(p - start);
1358 parser->header_state = h_state;
1359 CROW_CALLBACK_DATA_NOADVANCE(header_value);
1363 if (!lenient && !CROW_IS_HEADER_CHAR(ch)) {
1364 CROW_SET_ERRNO(CHPE_INVALID_HEADER_TOKEN);
1373 size_t left = data + len - p;
1374 const char* pe = p + CROW_MIN(left, max_header_size);
1376 for (; p != pe; p++) {
1378 if (ch == cr || ch == lf) {
1382 if (!lenient && !CROW_IS_HEADER_CHAR(ch)) {
1383 CROW_SET_ERRNO(CHPE_INVALID_HEADER_TOKEN);
1387 if (p == data + len)
1393 case h_transfer_encoding:
1394 assert(0 &&
"Shouldn't get here.");
1397 case h_content_length:
1398 if (ch ==
' ')
break;
1399 h_state = h_content_length_num;
1402 case h_content_length_num:
1407 h_state = h_content_length_ws;
1411 if (CROW_UNLIKELY(!CROW_IS_NUM(ch))) {
1412 CROW_SET_ERRNO(CHPE_INVALID_CONTENT_LENGTH);
1413 parser->header_state = h_state;
1417 t = parser->content_length;
1422 if (CROW_UNLIKELY((CROW_ULLONG_MAX - 10) / 10 < parser->content_length)) {
1423 CROW_SET_ERRNO(CHPE_INVALID_CONTENT_LENGTH);
1424 parser->header_state = h_state;
1428 parser->content_length = t;
1432 case h_content_length_ws:
1433 if (ch ==
' ')
break;
1434 CROW_SET_ERRNO(CHPE_INVALID_CONTENT_LENGTH);
1435 parser->header_state = h_state;
1439 case h_matching_transfer_encoding_token_start:
1442 h_state = h_matching_transfer_encoding_chunked;
1443 }
else if (CROW_TOKEN(c)) {
1449 h_state = h_matching_transfer_encoding_token;
1450 }
else if (c ==
' ' || c ==
'\t') {
1453 h_state = h_general;
1457 case h_matching_transfer_encoding_chunked:
1459 if (parser->index >
sizeof(CROW_CHUNKED)-1 || c != CROW_CHUNKED[parser->index]) {
1460 h_state = h_matching_transfer_encoding_token;
1461 }
else if (parser->index ==
sizeof(CROW_CHUNKED)-2) {
1462 h_state = h_transfer_encoding_chunked;
1466 case h_matching_transfer_encoding_token:
1468 h_state = h_matching_transfer_encoding_token_start;
1474 case h_matching_connection_keep_alive:
1476 if (parser->index >
sizeof(CROW_KEEP_ALIVE)-1 || c != CROW_KEEP_ALIVE[parser->index]) {
1477 h_state = h_general;
1478 }
else if (parser->index ==
sizeof(CROW_KEEP_ALIVE)-2) {
1479 h_state = h_connection_keep_alive;
1484 case h_matching_connection_close:
1486 if (parser->index >
sizeof(CROW_CLOSE)-1 || c != CROW_CLOSE[parser->index]) {
1487 h_state = h_general;
1488 }
else if (parser->index ==
sizeof(CROW_CLOSE)-2) {
1489 h_state = h_connection_close;
1494 case h_transfer_encoding_chunked:
1495 if (ch !=
' ') h_state = h_matching_transfer_encoding_token;
1497 case h_connection_keep_alive:
1498 case h_connection_close:
1499 if (ch !=
' ') h_state = h_general;
1503 parser->state = s_header_value;
1504 h_state = h_general;
1508 parser->header_state = h_state;
1511 if (p == data + len)
1514 CROW_COUNT_HEADER_SIZE(p - start);
1518 case s_header_almost_done:
1520 if (CROW_UNLIKELY(ch != lf)) {
1521 CROW_SET_ERRNO(CHPE_LF_EXPECTED);
1525 parser->state = s_header_value_lws;
1529 case s_header_value_lws:
1531 if (ch ==
' ' || ch ==
'\t') {
1532 if (parser->header_state == h_content_length_num) {
1534 parser->header_state = h_content_length_ws;
1536 parser->state = s_header_value_start;
1541 switch (parser->header_state) {
1542 case h_connection_keep_alive:
1543 parser->flags |= F_CONNECTION_KEEP_ALIVE;
1545 case h_connection_close:
1546 parser->flags |= F_CONNECTION_CLOSE;
1548 case h_transfer_encoding_chunked:
1549 parser->flags |= F_CHUNKED;
1555 parser->state = s_header_field_start;
1559 case s_header_value_discard_ws_almost_done:
1561 CROW_STRICT_CHECK(ch != lf);
1562 parser->state = s_header_value_discard_lws;
1566 case s_header_value_discard_lws:
1568 if (ch ==
' ' || ch ==
'\t') {
1569 parser->state = s_header_value_discard_ws;
1573 CROW_MARK(header_value);
1574 parser->state = s_header_field_start;
1575 CROW_CALLBACK_DATA_NOADVANCE(header_value);
1580 case s_headers_almost_done:
1582 CROW_STRICT_CHECK(ch != lf);
1584 if (parser->flags & F_TRAILING) {
1586 CROW_CALLBACK_NOTIFY(message_complete);
1592 if ((parser->uses_transfer_encoding == 1) &&
1593 (parser->flags & F_CONTENTLENGTH)) {
1597 if (parser->flags & F_CHUNKED) {
1598 if (!allow_chunked_length) {
1599 CROW_SET_ERRNO(CHPE_UNEXPECTED_CONTENT_LENGTH);
1602 }
else if (!lenient) {
1603 CROW_SET_ERRNO(CHPE_UNEXPECTED_CONTENT_LENGTH);
1608 parser->state = s_headers_done;
1612 (parser->flags & F_UPGRADE || parser->method == (unsigned)HTTPMethod::Connect);
1623 if (settings->on_headers_complete) {
1624 switch (settings->on_headers_complete(parser)) {
1629 parser->upgrade = 1;
1634 parser->flags |= F_SKIPBODY;
1638 CROW_SET_ERRNO(CHPE_CB_headers_complete);
1639 parser->nread = nread;
1644 if (CROW_HTTP_PARSER_ERRNO(parser) != CHPE_OK) {
1645 parser->nread = nread;
1652 case s_headers_done:
1654 CROW_STRICT_CHECK(ch != lf);
1660 if (parser->upgrade) {
1661 CROW_CALLBACK_NOTIFY(message_complete);
1662 parser->nread = nread;
1663 return (p - data) + 1;
1666 if (parser->flags & F_SKIPBODY) {
1667 CROW_CALLBACK_NOTIFY(message_complete);
1668 }
else if (parser->flags & F_CHUNKED) {
1671 parser->state = s_chunk_size_start;
1673 else if (parser->uses_transfer_encoding == 1)
1685 CROW_SET_ERRNO(CHPE_INVALID_TRANSFER_ENCODING);
1686 parser->nread = nread;
1698 parser->state = s_body_identity_eof;
1703 if (parser->content_length == 0)
1706 CROW_CALLBACK_NOTIFY(message_complete);
1708 else if (parser->content_length != CROW_ULLONG_MAX)
1711 parser->state = s_body_identity;
1716 CROW_CALLBACK_NOTIFY(message_complete);
1723 case s_body_identity:
1725 uint64_t to_read = CROW_MIN(parser->content_length,
1726 (uint64_t) ((data + len) - p));
1728 assert(parser->content_length != 0
1729 && parser->content_length != CROW_ULLONG_MAX);
1737 parser->content_length -= to_read;
1740 if (parser->content_length == 0) {
1741 parser->state = s_message_done;
1752 CROW_CALLBACK_DATA_(body, p - body_mark + 1, p - data);
1760 case s_body_identity_eof:
1766 case s_message_done:
1767 CROW_CALLBACK_NOTIFY(message_complete);
1770 case s_chunk_size_start:
1773 assert(parser->flags & F_CHUNKED);
1775 unhex_val = unhex[
static_cast<unsigned char>(ch)];
1776 if (CROW_UNLIKELY(unhex_val == -1)) {
1777 CROW_SET_ERRNO(CHPE_INVALID_CHUNK_SIZE);
1781 parser->content_length = unhex_val;
1782 parser->state = s_chunk_size;
1790 assert(parser->flags & F_CHUNKED);
1793 parser->state = s_chunk_size_almost_done;
1797 unhex_val = unhex[
static_cast<unsigned char>(ch)];
1799 if (unhex_val == -1) {
1800 if (ch ==
';' || ch ==
' ') {
1801 parser->state = s_chunk_parameters;
1805 CROW_SET_ERRNO(CHPE_INVALID_CHUNK_SIZE);
1809 t = parser->content_length;
1814 if (CROW_UNLIKELY((CROW_ULLONG_MAX - 16) / 16 < parser->content_length)) {
1815 CROW_SET_ERRNO(CHPE_INVALID_CONTENT_LENGTH);
1819 parser->content_length = t;
1823 case s_chunk_parameters:
1825 assert(parser->flags & F_CHUNKED);
1828 parser->state = s_chunk_size_almost_done;
1834 case s_chunk_size_almost_done:
1836 assert(parser->flags & F_CHUNKED);
1837 CROW_STRICT_CHECK(ch != lf);
1842 if (parser->content_length == 0) {
1843 parser->flags |= F_TRAILING;
1844 parser->state = s_header_field_start;
1846 parser->state = s_chunk_data;
1853 uint64_t to_read = CROW_MIN(parser->content_length,
1854 (uint64_t) ((data + len) - p));
1856 assert(parser->flags & F_CHUNKED);
1857 assert(parser->content_length != 0
1858 && parser->content_length != CROW_ULLONG_MAX);
1864 parser->content_length -= to_read;
1867 if (parser->content_length == 0) {
1868 parser->state = s_chunk_data_almost_done;
1874 case s_chunk_data_almost_done:
1875 assert(parser->flags & F_CHUNKED);
1876 assert(parser->content_length == 0);
1877 CROW_STRICT_CHECK(ch != cr);
1878 parser->state = s_chunk_data_done;
1879 CROW_CALLBACK_DATA(body);
1882 case s_chunk_data_done:
1883 assert(parser->flags & F_CHUNKED);
1884 CROW_STRICT_CHECK(ch != lf);
1887 parser->state = s_chunk_size_start;
1891 assert(0 &&
"unhandled state");
1892 CROW_SET_ERRNO(CHPE_INVALID_INTERNAL_STATE);
1907 assert(((header_field_mark ? 1 : 0) +
1908 (header_value_mark ? 1 : 0) +
1909 (url_mark ? 1 : 0) +
1910 (body_mark ? 1 : 0)) <= 1);
1912 CROW_CALLBACK_DATA_NOADVANCE(header_field);
1913 CROW_CALLBACK_DATA_NOADVANCE(header_value);
1914 CROW_CALLBACK_DATA_NOADVANCE(url);
1915 CROW_CALLBACK_DATA_NOADVANCE(body);
1917 parser->nread = nread;
1921 if (CROW_HTTP_PARSER_ERRNO(parser) == CHPE_OK) {
1922 CROW_SET_ERRNO(CHPE_UNKNOWN);
1925 parser->nread = nread;
1930 http_parser_init(http_parser* parser)
1932 void *data = parser->data;
1933 memset(parser, 0,
sizeof(*parser));
1934 parser->data = data;
1935 parser->state = s_start_req;
1936 parser->http_errno = CHPE_OK;
1941 http_errno_name(
enum http_errno err) {
1943 #define CROW_HTTP_STRERROR_GEN(n, s) { "CHPE_" #n, s },
1946 const char *description;
1947 } http_strerror_tab[] = {
1948 CROW_HTTP_ERRNO_MAP(CROW_HTTP_STRERROR_GEN)
1950 #undef CROW_HTTP_STRERROR_GEN
1951 assert(((
size_t) err) < CROW_ARRAY_SIZE(http_strerror_tab));
1952 return http_strerror_tab[err].name;
1957 http_errno_description(
enum http_errno err) {
1959 #define CROW_HTTP_STRERROR_GEN(n, s) { "CHPE_" #n, s },
1962 const char *description;
1963 } http_strerror_tab[] = {
1964 CROW_HTTP_ERRNO_MAP(CROW_HTTP_STRERROR_GEN)
1966 #undef CROW_HTTP_STRERROR_GEN
1967 assert(((
size_t) err) < CROW_ARRAY_SIZE(http_strerror_tab));
1968 return http_strerror_tab[err].description;
1973 http_body_is_final(
const struct http_parser *parser) {
1974 return parser->state == s_message_done;
1979 http_parser_set_max_header_size(uint32_t size) {
1980 max_header_size = size;
1983 #undef CROW_HTTP_ERRNO_MAP
1984 #undef CROW_SET_ERRNO
1985 #undef CROW_CALLBACK_NOTIFY_
1986 #undef CROW_CALLBACK_NOTIFY
1987 #undef CROW_CALLBACK_NOTIFY_NOADVANCE
1988 #undef CROW_CALLBACK_DATA_
1989 #undef CROW_CALLBACK_DATA
1990 #undef CROW_CALLBACK_DATA_NOADVANCE
1992 #undef CROW_PROXY_CONNECTION
1993 #undef CROW_CONNECTION
1994 #undef CROW_CONTENT_LENGTH
1995 #undef CROW_TRANSFER_ENCODING
1998 #undef CROW_KEEP_ALIVE
2000 #undef CROW_PARSING_HEADER
2002 #undef CROW_IS_ALPHA
2004 #undef CROW_IS_ALPHANUM
2007 #undef CROW_IS_USERINFO_CHAR
2009 #undef CROW_IS_URL_CHAR
2011 #undef CROW_STRICT_CHECK
The main namespace of the library. In this namespace is defined the most important classes and functi...
Definition: http_parser_merged.h:181
Definition: http_parser_merged.h:148
unsigned char http_major
Definition: http_parser_merged.h:163
unsigned int flags
Definition: http_parser_merged.h:150
void * data
Definition: http_parser_merged.h:176