├── TODO ├── README.md ├── CMakeLists.txt ├── test └── main.c ├── include └── server_eh.h └── src ├── server_eh.c ├── http_parser.h └── http_parser.c /TODO: -------------------------------------------------------------------------------- 1 | project todos 2 | - support for connection keep-alive 3 | - write a file server example 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # webserver-libev-httpparser 2 | 3 | It's a http server library written in C using libev ( http://software.schmorp.de/pkg/libev.html ) and Ryan Dahl's http parser (see http://github.com/joyent/http-parser ) heavily based on lighttz ( https://arekzb.wordpress.com/2008/04/27/lighttz-a-simple-and-fast-web-server/ ) 4 | 5 | To compile: 6 | 7 | cmake CMakeLists.txt 8 | make 9 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8) 2 | project(webserver-libev-httpparser) 3 | 4 | set(CMAKE_C_FLAGS "-O0 -pedantic -Wall -std=gnu99") 5 | #set(CMAKE_C_FLAGS "-ggdb -O0 -Wall -std=c99") 6 | #set(CMAKE_VERBOSE_MAKEFILE on) 7 | set(EXECUTABLE_OUTPUT_PATH bin) 8 | set(LIBRARY_OUTPUT_PATH lib) 9 | 10 | include_directories(include src test) 11 | set(OBJS 12 | src/http_parser.c 13 | src/server_eh.c) 14 | 15 | add_library(server_eh SHARED ${OBJS}) 16 | add_executable(testsrv test/main.c) 17 | 18 | target_link_libraries(testsrv server_eh ev) 19 | 20 | -------------------------------------------------------------------------------- /test/main.c: -------------------------------------------------------------------------------- 1 | #include "server_eh.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | // see http_parser.h 13 | // char DELETE = 0; 14 | // char GET = 1; 15 | // char HEAD = 2; 16 | // char POST = 3; 17 | // char PUT = 4; 18 | 19 | void handle_request(struct http_request *request, int fd) { 20 | write(fd, "HTTP/1.1 200 OK\r\n\r\n", 19); 21 | struct http_header *header = request->headers; 22 | write(fd, "
Headers:\n", 14);
23 |     while (header != NULL) {
24 |         write(fd, header->name, strlen(header->name));
25 |         write(fd, ": ", 2);
26 |         write(fd, header->value, strlen(header->value));
27 |         write(fd, "\n", 1);
28 |         header = header->next;
29 |     }
30 |     if (request->flags & F_HREQ_KEEPALIVE) {
31 |          write(fd, "\nis keepalive.\n", 16);
32 |     }
33 |     char *my_data = (char*) request->data;
34 |     write(fd, "my string is ", 13);
35 |     write(fd, my_data, strlen(my_data));
36 |     write(fd, "\r\n\r\n", 4);
37 |     close(fd);
38 | }
39 | 
40 | static struct http_server server;
41 | 
42 | void sigint_handler(int s) {
43 |     struct ev_loop *loop = server.loop;
44 |     ev_io_stop(EV_A_ server.ev_accept);
45 |     exit(0);
46 | }
47 | 
48 | int main(int argc, char **argv) {
49 |     // configure server structures and desired listen address
50 |     struct sockaddr_in listen_addr;
51 |     memset(&listen_addr, 0, sizeof(listen_addr));
52 |     listen_addr.sin_family = AF_INET;
53 |     listen_addr.sin_addr.s_addr = INADDR_ANY;
54 |     listen_addr.sin_port = htons(9876);
55 |     server.listen_addr = &listen_addr;
56 |     server.handle_request = handle_request;
57 |     server.data = "this is my string";
58 | 
59 |     // ignore SIGPIPE
60 |     struct sigaction on_sigpipe;
61 |     memset(&on_sigpipe, 0, sizeof(struct sigaction));
62 |     on_sigpipe.sa_handler = SIG_IGN;
63 |     sigemptyset(&on_sigpipe.sa_mask);
64 |     sigaction(SIGPIPE, &on_sigpipe, NULL);
65 | 
66 |     // handle C-c
67 |     struct sigaction on_sigint;
68 |     memset(&on_sigint, 0, sizeof(struct sigaction));
69 |     on_sigint.sa_handler = sigint_handler;
70 |     sigemptyset(&on_sigint.sa_mask);
71 |     on_sigint.sa_flags = 0;
72 |     sigaction(SIGINT, &on_sigint, NULL);
73 | 
74 |     // start the server
75 |     return http_server_loop(&server);
76 | }
77 | 


--------------------------------------------------------------------------------
/include/server_eh.h:
--------------------------------------------------------------------------------
 1 | #ifndef server_eh
 2 | #define server_eh 1
 3 | 
 4 | #include 
 5 | 
 6 | // http request components
 7 | 
 8 | struct http_header {
 9 |     char *name, *value;
10 |     struct http_header *next;
11 | };
12 | 
13 | static inline struct http_header *new_http_header() {
14 |     struct http_header *header = malloc(sizeof(struct http_header));
15 |     header->name = NULL;
16 |     header->value = NULL;
17 |     header->next = NULL;
18 |     return header;
19 | }
20 | 
21 | static inline void delete_http_header(struct http_header *header) {
22 |     if (header->name != NULL) free(header->name);
23 |     if (header->value != NULL) free(header->value);
24 |     free(header);
25 | }
26 | 
27 | struct http_request {
28 |     char method, *url, *body;
29 |     unsigned int flags;
30 |     unsigned short http_major, http_minor;
31 |     struct http_header *headers;
32 |     void *data;
33 | };
34 | 
35 | #define F_HREQ_KEEPALIVE 0x01
36 | 
37 | static inline struct http_request *new_http_request() {
38 |     struct http_request *request = malloc(sizeof(struct http_request));
39 |     request->headers = NULL;
40 |     request->url = NULL;
41 |     request->body = NULL;
42 |     request->flags = 0;
43 |     request->http_major = 0;
44 |     request->http_minor = 0;
45 |     request->data = NULL;
46 |     return request;
47 | }
48 | 
49 | static inline void delete_http_request(struct http_request *request) {
50 |     if (request->url != NULL) free(request->url);
51 |     if (request->body != NULL) free(request->body);
52 |     struct http_header *header = request->headers;
53 |     while (header != NULL) {
54 |         struct http_header *to_delete = header;
55 |         header = header->next;
56 |         delete_http_header(to_delete);
57 |     }
58 |     free(request);
59 | }
60 | 
61 | static inline struct http_header *add_http_header(struct http_request *request) {
62 |     struct http_header *header = request->headers;
63 |     while (header != NULL) {
64 |         if (header->next == NULL) {
65 |             header->next = new_http_header();
66 |             return header->next;
67 |         }
68 |         header = header->next;
69 |     }
70 |     request->headers = new_http_header();
71 |     return request->headers;
72 | }
73 | 
74 | // server library interface
75 | 
76 | #include 
77 | #include 
78 | 
79 | struct http_server {
80 |     struct ev_loop *loop;
81 |     struct sockaddr_in *listen_addr;
82 |     void (*handle_request)(struct http_request *request, int fd);
83 |     struct ev_io *ev_accept;
84 |     void *data;
85 | };
86 | 
87 | int http_server_loop(struct http_server *server);
88 | 
89 | #endif
90 | 


--------------------------------------------------------------------------------
/src/server_eh.c:
--------------------------------------------------------------------------------
  1 | #include "server_eh.h"
  2 | #include "http_parser.h"
  3 | 
  4 | #include 
  5 | #include 
  6 | #include 
  7 | #include 
  8 | #include 
  9 | #include 
 10 | #include 
 11 | 
 12 | // utils
 13 | 
 14 | static inline int setnonblock(int fd) {
 15 |     int flags = fcntl(fd, F_GETFL);
 16 |     if (flags < 0) return flags;
 17 |     flags |= O_NONBLOCK;
 18 |     if (fcntl(fd, F_SETFL, flags) < 0) return -1;
 19 |     return 0;
 20 | }
 21 | 
 22 | #define REQUEST_BUFFER_SIZE 2048
 23 | 
 24 | #define alloc_cpy(dest, src, len) \
 25 |     dest = malloc(len + 1);\
 26 |     memcpy(dest, src, len);\
 27 |     dest[len] = '\0';
 28 | 
 29 | // http_parser callback and settings
 30 | 
 31 | int null_cb(http_parser *parser) { return 0; }
 32 | 
 33 | int url_cb(http_parser *parser, const char *buf, size_t len) {
 34 |     struct http_request *request = (struct http_request *) parser->data;
 35 |     request->method = parser->method;
 36 |     request->http_major = parser->http_major;
 37 |     request->http_minor = parser->http_minor;
 38 |     alloc_cpy(request->url, buf, len)
 39 |     return 0;
 40 | }
 41 | 
 42 | int header_field_cb(http_parser *parser, const char *buf, size_t len) {
 43 |     struct http_request *request = (struct http_request *) parser->data;
 44 |     struct http_header *header = add_http_header(request);
 45 |     alloc_cpy(header->name, buf, len)
 46 |     return 0;
 47 | }
 48 | 
 49 | int header_value_cb(http_parser *parser, const char *buf, size_t len) {
 50 |     struct http_request *request = (struct http_request *) parser->data;
 51 |     struct http_header *header = request->headers;
 52 |     while (header->next != NULL) {
 53 |         header = header->next;
 54 |     }
 55 |     alloc_cpy(header->value, buf, len)
 56 |     return 0;
 57 | }
 58 | 
 59 | int body_cb(http_parser *parser, const char *buf, size_t len) {
 60 |     struct http_request *request = (struct http_request *) parser->data;
 61 |     alloc_cpy(request->body, buf, len)
 62 |     return 0;
 63 | }
 64 | 
 65 | static http_parser_settings parser_settings =
 66 | {
 67 |      .on_message_begin    = null_cb
 68 |     ,.on_message_complete = null_cb
 69 |     ,.on_headers_complete = null_cb
 70 |     ,.on_header_field     = header_field_cb
 71 |     ,.on_header_value     = header_value_cb
 72 |     ,.on_url              = url_cb
 73 |     ,.on_body             = body_cb
 74 | };
 75 | 
 76 | struct http_request *parse_request(char *request_data, int len) {
 77 |     http_parser *parser = malloc(sizeof(http_parser));
 78 |     http_parser_init(parser, HTTP_REQUEST);
 79 |     struct http_request *request = new_http_request();
 80 |     parser->data = request;
 81 |     int res = http_parser_execute(parser, &parser_settings, request_data, len);
 82 |     if (res == len) {
 83 |         if (http_should_keep_alive(parser)) {
 84 |             request->flags |= F_HREQ_KEEPALIVE;
 85 |         }
 86 |         free(parser);
 87 |         return request;
 88 |     }
 89 |     delete_http_request(request);
 90 |     free(parser);
 91 |     return NULL;
 92 | }
 93 | 
 94 | // libev callbacks and client structures
 95 | 
 96 | struct client {
 97 |     int fd;
 98 |     ev_io ev_accept;
 99 |     ev_io ev_read;
100 |     ev_io ev_write;
101 |     char *request_data;
102 |     struct http_request *request;
103 |     void (*handle_request)(struct http_request *request, int fd);
104 |     void *data;
105 | };
106 | 
107 | static void write_cb(struct ev_loop *loop, struct ev_io *w, int revents) {
108 |     if (!(revents & EV_WRITE)) {
109 |         ev_io_stop(EV_A_ w);
110 |         return;
111 |     }
112 |     struct client *client =
113 |         (struct client *)
114 |         (((char *) w) - offsetof(struct client, ev_write));
115 |     struct http_request *request = client->request;
116 |     if (request == NULL) {
117 |         write(client->fd, "HTTP/1.1 400 Bad Request\r\n\r\n", 24);
118 |         close(client->fd);
119 |         free(client->request_data);
120 |         free(client);
121 |         ev_io_stop(EV_A_ w);
122 |         return;
123 |     }
124 |     client->handle_request(request, client->fd);
125 |     delete_http_request(request);
126 |     free(client->request_data);
127 |     free(client);
128 |     ev_io_stop(EV_A_ w);
129 | }
130 | 
131 | static void read_cb(struct ev_loop *loop, struct ev_io *w, int revents) {
132 |     if (!(revents & EV_READ)) {
133 |         ev_io_stop(EV_A_ w);
134 |         return;
135 |     }
136 |     struct client *client =
137 |         (struct client *)
138 |         (((char *) w) - offsetof(struct client, ev_read));
139 |     char *rbuff[REQUEST_BUFFER_SIZE + 1];
140 |     int sum = 0, len = 0;
141 |     client->request_data = NULL;
142 |     do {
143 |         len = read(client->fd, &rbuff, REQUEST_BUFFER_SIZE);
144 |         sum += len;
145 |         if (len < REQUEST_BUFFER_SIZE)
146 |             rbuff[len] = '\0';
147 |         if (client->request_data == NULL) {
148 |             client->request_data = malloc(len+1);
149 |             memcpy(client->request_data, rbuff, len);
150 |         } else {
151 |             client->request_data = realloc(client->request_data, sum + 1);
152 |             memcpy(client->request_data + sum - len, rbuff, len);
153 |         }
154 |     } while (len == REQUEST_BUFFER_SIZE);
155 |     client->request = NULL;
156 |     client->request = parse_request(client->request_data, sum);
157 |     client->request->data = client->data;
158 |     ev_io_stop(EV_A_ w);
159 |     ev_io_init(&client->ev_write, write_cb, client->fd, EV_WRITE);
160 |     ev_io_start(loop, &client->ev_write);
161 | }
162 | 
163 | static void accept_cb(struct ev_loop *loop, struct ev_io *w, int revents) {
164 |     struct client *main_client =
165 |         (struct client *)
166 |         (((char *) w) - offsetof(struct client, ev_accept));
167 |     struct sockaddr_in client_addr;
168 |     socklen_t client_len = sizeof(struct sockaddr_in);
169 |     int client_fd = accept(w->fd, (struct sockaddr *) &client_addr, &client_len);
170 |     if (client_fd == -1) {
171 |         return;
172 |     }
173 |     if (setnonblock(client_fd) < 0) {
174 |         perror("failed to set client socket to nonblock");
175 |         return;
176 |     }
177 |     struct client *client = malloc(sizeof(struct client));
178 |     client->handle_request = main_client->handle_request;
179 |     client->data = main_client->data;
180 |     client->fd = client_fd;
181 |     ev_io_init(&client->ev_read, read_cb, client->fd, EV_READ);
182 |     ev_io_start(loop, &client->ev_read);
183 | }
184 | 
185 | int http_server_loop(struct http_server *server) {
186 |     server->loop = ev_default_loop(0);
187 |     int listen_fd = socket(AF_INET, SOCK_STREAM, 0);
188 |     if (listen_fd < 0) {
189 |         perror("listen failed(socket)");
190 |         return -1;
191 |     }
192 |     int reuseaddr_on = 1;
193 |     if (setsockopt(
194 |             listen_fd,
195 |             SOL_SOCKET,
196 |             SO_REUSEADDR,
197 |             &reuseaddr_on,
198 |             sizeof(server->listen_addr)) == -1) {
199 |         perror("setsockopt failed");
200 |         return -1;
201 |     }
202 |     struct sockaddr *listen_addr = (struct sockaddr *) server->listen_addr;
203 |     if (bind(listen_fd, listen_addr, sizeof(*listen_addr)) < 0) {
204 |         perror("bind failed");
205 |         return -1;
206 |     }
207 |     if (listen(listen_fd, 5) < 0) {
208 |         perror("listen failed(listen)");
209 |         return -1;
210 |     }
211 |     if (setnonblock(listen_fd) < 0) {
212 |         perror("failed to set server socket to nonblock");
213 |         return -1;
214 |     }
215 |     struct client *main_client = malloc(sizeof(struct client));
216 |     main_client->handle_request = server->handle_request;
217 |     main_client->data = server->data;
218 |     ev_io_init(&main_client->ev_accept, accept_cb, listen_fd, EV_READ);
219 |     ev_io_start(server->loop, &main_client->ev_accept);
220 |     server->ev_accept = &main_client->ev_accept;
221 |     ev_loop(server->loop, 0);
222 |     return 0;
223 | }
224 | 


--------------------------------------------------------------------------------
/src/http_parser.h:
--------------------------------------------------------------------------------
  1 | /* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
  2 |  *
  3 |  * Permission is hereby granted, free of charge, to any person obtaining a copy
  4 |  * of this software and associated documentation files (the "Software"), to
  5 |  * deal in the Software without restriction, including without limitation the
  6 |  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  7 |  * sell copies of the Software, and to permit persons to whom the Software is
  8 |  * furnished to do so, subject to the following conditions:
  9 |  *
 10 |  * The above copyright notice and this permission notice shall be included in
 11 |  * all copies or substantial portions of the Software.
 12 |  *
 13 |  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 14 |  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 15 |  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 16 |  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 17 |  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 18 |  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 19 |  * IN THE SOFTWARE.
 20 |  */
 21 | #ifndef http_parser_h
 22 | #define http_parser_h
 23 | #ifdef __cplusplus
 24 | extern "C" {
 25 | #endif
 26 | 
 27 | /* Also update SONAME in the Makefile whenever you change these. */
 28 | #define HTTP_PARSER_VERSION_MAJOR 2
 29 | #define HTTP_PARSER_VERSION_MINOR 4
 30 | #define HTTP_PARSER_VERSION_PATCH 2
 31 | 
 32 | #include 
 33 | #if defined(_WIN32) && !defined(__MINGW32__) && (!defined(_MSC_VER) || _MSC_VER<1600)
 34 | #include 
 35 | #include 
 36 | typedef __int8 int8_t;
 37 | typedef unsigned __int8 uint8_t;
 38 | typedef __int16 int16_t;
 39 | typedef unsigned __int16 uint16_t;
 40 | typedef __int32 int32_t;
 41 | typedef unsigned __int32 uint32_t;
 42 | typedef __int64 int64_t;
 43 | typedef unsigned __int64 uint64_t;
 44 | #else
 45 | #include 
 46 | #endif
 47 | 
 48 | /* Compile with -DHTTP_PARSER_STRICT=0 to make less checks, but run
 49 |  * faster
 50 |  */
 51 | #ifndef HTTP_PARSER_STRICT
 52 | # define HTTP_PARSER_STRICT 1
 53 | #endif
 54 | 
 55 | /* Maximium header size allowed. If the macro is not defined
 56 |  * before including this header then the default is used. To
 57 |  * change the maximum header size, define the macro in the build
 58 |  * environment (e.g. -DHTTP_MAX_HEADER_SIZE=). To remove
 59 |  * the effective limit on the size of the header, define the macro
 60 |  * to a very large number (e.g. -DHTTP_MAX_HEADER_SIZE=0x7fffffff)
 61 |  */
 62 | #ifndef HTTP_MAX_HEADER_SIZE
 63 | # define HTTP_MAX_HEADER_SIZE (80*1024)
 64 | #endif
 65 | 
 66 | typedef struct http_parser http_parser;
 67 | typedef struct http_parser_settings http_parser_settings;
 68 | 
 69 | 
 70 | /* Callbacks should return non-zero to indicate an error. The parser will
 71 |  * then halt execution.
 72 |  *
 73 |  * The one exception is on_headers_complete. In a HTTP_RESPONSE parser
 74 |  * returning '1' from on_headers_complete will tell the parser that it
 75 |  * should not expect a body. This is used when receiving a response to a
 76 |  * HEAD request which may contain 'Content-Length' or 'Transfer-Encoding:
 77 |  * chunked' headers that indicate the presence of a body.
 78 |  *
 79 |  * http_data_cb does not return data chunks. It will be called arbitrarily
 80 |  * many times for each string. E.G. you might get 10 callbacks for "on_url"
 81 |  * each providing just a few characters more data.
 82 |  */
 83 | typedef int (*http_data_cb) (http_parser*, const char *at, size_t length);
 84 | typedef int (*http_cb) (http_parser*);
 85 | 
 86 | 
 87 | /* Request Methods */
 88 | #define HTTP_METHOD_MAP(XX)         \
 89 |   XX(0,  DELETE,      DELETE)       \
 90 |   XX(1,  GET,         GET)          \
 91 |   XX(2,  HEAD,        HEAD)         \
 92 |   XX(3,  POST,        POST)         \
 93 |   XX(4,  PUT,         PUT)          \
 94 |   /* pathological */                \
 95 |   XX(5,  CONNECT,     CONNECT)      \
 96 |   XX(6,  OPTIONS,     OPTIONS)      \
 97 |   XX(7,  TRACE,       TRACE)        \
 98 |   /* webdav */                      \
 99 |   XX(8,  COPY,        COPY)         \
100 |   XX(9,  LOCK,        LOCK)         \
101 |   XX(10, MKCOL,       MKCOL)        \
102 |   XX(11, MOVE,        MOVE)         \
103 |   XX(12, PROPFIND,    PROPFIND)     \
104 |   XX(13, PROPPATCH,   PROPPATCH)    \
105 |   XX(14, SEARCH,      SEARCH)       \
106 |   XX(15, UNLOCK,      UNLOCK)       \
107 |   /* subversion */                  \
108 |   XX(16, REPORT,      REPORT)       \
109 |   XX(17, MKACTIVITY,  MKACTIVITY)   \
110 |   XX(18, CHECKOUT,    CHECKOUT)     \
111 |   XX(19, MERGE,       MERGE)        \
112 |   /* upnp */                        \
113 |   XX(20, MSEARCH,     M-SEARCH)     \
114 |   XX(21, NOTIFY,      NOTIFY)       \
115 |   XX(22, SUBSCRIBE,   SUBSCRIBE)    \
116 |   XX(23, UNSUBSCRIBE, UNSUBSCRIBE)  \
117 |   /* RFC-5789 */                    \
118 |   XX(24, PATCH,       PATCH)        \
119 |   XX(25, PURGE,       PURGE)        \
120 |   /* CalDAV */                      \
121 |   XX(26, MKCALENDAR,  MKCALENDAR)   \
122 | 
123 | enum http_method
124 |   {
125 | #define XX(num, name, string) HTTP_##name = num,
126 |   HTTP_METHOD_MAP(XX)
127 | #undef XX
128 |   };
129 | 
130 | 
131 | enum http_parser_type { HTTP_REQUEST, HTTP_RESPONSE, HTTP_BOTH };
132 | 
133 | 
134 | /* Flag values for http_parser.flags field */
135 | enum flags
136 |   { F_CHUNKED               = 1 << 0
137 |   , F_CONNECTION_KEEP_ALIVE = 1 << 1
138 |   , F_CONNECTION_CLOSE      = 1 << 2
139 |   , F_CONNECTION_UPGRADE    = 1 << 3
140 |   , F_TRAILING              = 1 << 4
141 |   , F_UPGRADE               = 1 << 5
142 |   , F_SKIPBODY              = 1 << 6
143 |   };
144 | 
145 | 
146 | /* Map for errno-related constants
147 |  * 
148 |  * The provided argument should be a macro that takes 2 arguments.
149 |  */
150 | #define HTTP_ERRNO_MAP(XX)                                           \
151 |   /* No error */                                                     \
152 |   XX(OK, "success")                                                  \
153 |                                                                      \
154 |   /* Callback-related errors */                                      \
155 |   XX(CB_message_begin, "the on_message_begin callback failed")       \
156 |   XX(CB_url, "the on_url callback failed")                           \
157 |   XX(CB_header_field, "the on_header_field callback failed")         \
158 |   XX(CB_header_value, "the on_header_value callback failed")         \
159 |   XX(CB_headers_complete, "the on_headers_complete callback failed") \
160 |   XX(CB_body, "the on_body callback failed")                         \
161 |   XX(CB_message_complete, "the on_message_complete callback failed") \
162 |   XX(CB_status, "the on_status callback failed")                     \
163 |                                                                      \
164 |   /* Parsing-related errors */                                       \
165 |   XX(INVALID_EOF_STATE, "stream ended at an unexpected time")        \
166 |   XX(HEADER_OVERFLOW,                                                \
167 |      "too many header bytes seen; overflow detected")                \
168 |   XX(CLOSED_CONNECTION,                                              \
169 |      "data received after completed connection: close message")      \
170 |   XX(INVALID_VERSION, "invalid HTTP version")                        \
171 |   XX(INVALID_STATUS, "invalid HTTP status code")                     \
172 |   XX(INVALID_METHOD, "invalid HTTP method")                          \
173 |   XX(INVALID_URL, "invalid URL")                                     \
174 |   XX(INVALID_HOST, "invalid host")                                   \
175 |   XX(INVALID_PORT, "invalid port")                                   \
176 |   XX(INVALID_PATH, "invalid path")                                   \
177 |   XX(INVALID_QUERY_STRING, "invalid query string")                   \
178 |   XX(INVALID_FRAGMENT, "invalid fragment")                           \
179 |   XX(LF_EXPECTED, "LF character expected")                           \
180 |   XX(INVALID_HEADER_TOKEN, "invalid character in header")            \
181 |   XX(INVALID_CONTENT_LENGTH,                                         \
182 |      "invalid character in content-length header")                   \
183 |   XX(INVALID_CHUNK_SIZE,                                             \
184 |      "invalid character in chunk size header")                       \
185 |   XX(INVALID_CONSTANT, "invalid constant string")                    \
186 |   XX(INVALID_INTERNAL_STATE, "encountered unexpected internal state")\
187 |   XX(STRICT, "strict mode assertion failed")                         \
188 |   XX(PAUSED, "parser is paused")                                     \
189 |   XX(UNKNOWN, "an unknown error occurred")
190 | 
191 | 
192 | /* Define HPE_* values for each errno value above */
193 | #define HTTP_ERRNO_GEN(n, s) HPE_##n,
194 | enum http_errno {
195 |   HTTP_ERRNO_MAP(HTTP_ERRNO_GEN)
196 | };
197 | #undef HTTP_ERRNO_GEN
198 | 
199 | 
200 | /* Get an http_errno value from an http_parser */
201 | #define HTTP_PARSER_ERRNO(p)            ((enum http_errno) (p)->http_errno)
202 | 
203 | 
204 | struct http_parser {
205 |   /** PRIVATE **/
206 |   unsigned int type : 2;         /* enum http_parser_type */
207 |   unsigned int flags : 7;        /* F_* values from 'flags' enum; semi-public */
208 |   unsigned int state : 7;        /* enum state from http_parser.c */
209 |   unsigned int header_state : 8; /* enum header_state from http_parser.c */
210 |   unsigned int index : 8;        /* index into current matcher */
211 | 
212 |   uint32_t nread;          /* # bytes read in various scenarios */
213 |   uint64_t content_length; /* # bytes in body (0 if no Content-Length header) */
214 | 
215 |   /** READ-ONLY **/
216 |   unsigned short http_major;
217 |   unsigned short http_minor;
218 |   unsigned int status_code : 16; /* responses only */
219 |   unsigned int method : 8;       /* requests only */
220 |   unsigned int http_errno : 7;
221 | 
222 |   /* 1 = Upgrade header was present and the parser has exited because of that.
223 |    * 0 = No upgrade header present.
224 |    * Should be checked when http_parser_execute() returns in addition to
225 |    * error checking.
226 |    */
227 |   unsigned int upgrade : 1;
228 | 
229 |   /** PUBLIC **/
230 |   void *data; /* A pointer to get hook to the "connection" or "socket" object */
231 | };
232 | 
233 | 
234 | struct http_parser_settings {
235 |   http_cb      on_message_begin;
236 |   http_data_cb on_url;
237 |   http_data_cb on_status;
238 |   http_data_cb on_header_field;
239 |   http_data_cb on_header_value;
240 |   http_cb      on_headers_complete;
241 |   http_data_cb on_body;
242 |   http_cb      on_message_complete;
243 | };
244 | 
245 | 
246 | enum http_parser_url_fields
247 |   { UF_SCHEMA           = 0
248 |   , UF_HOST             = 1
249 |   , UF_PORT             = 2
250 |   , UF_PATH             = 3
251 |   , UF_QUERY            = 4
252 |   , UF_FRAGMENT         = 5
253 |   , UF_USERINFO         = 6
254 |   , UF_MAX              = 7
255 |   };
256 | 
257 | 
258 | /* Result structure for http_parser_parse_url().
259 |  *
260 |  * Callers should index into field_data[] with UF_* values iff field_set
261 |  * has the relevant (1 << UF_*) bit set. As a courtesy to clients (and
262 |  * because we probably have padding left over), we convert any port to
263 |  * a uint16_t.
264 |  */
265 | struct http_parser_url {
266 |   uint16_t field_set;           /* Bitmask of (1 << UF_*) values */
267 |   uint16_t port;                /* Converted UF_PORT string */
268 | 
269 |   struct {
270 |     uint16_t off;               /* Offset into buffer in which field starts */
271 |     uint16_t len;               /* Length of run in buffer */
272 |   } field_data[UF_MAX];
273 | };
274 | 
275 | 
276 | /* Returns the library version. Bits 16-23 contain the major version number,
277 |  * bits 8-15 the minor version number and bits 0-7 the patch level.
278 |  * Usage example:
279 |  *
280 |  *   unsigned long version = http_parser_version();
281 |  *   unsigned major = (version >> 16) & 255;
282 |  *   unsigned minor = (version >> 8) & 255;
283 |  *   unsigned patch = version & 255;
284 |  *   printf("http_parser v%u.%u.%u\n", major, minor, patch);
285 |  */
286 | unsigned long http_parser_version(void);
287 | 
288 | void http_parser_init(http_parser *parser, enum http_parser_type type);
289 | 
290 | 
291 | /* Initialize http_parser_settings members to 0
292 |  */
293 | void http_parser_settings_init(http_parser_settings *settings);
294 | 
295 | 
296 | /* Executes the parser. Returns number of parsed bytes. Sets
297 |  * `parser->http_errno` on error. */
298 | size_t http_parser_execute(http_parser *parser,
299 |                            const http_parser_settings *settings,
300 |                            const char *data,
301 |                            size_t len);
302 | 
303 | 
304 | /* If http_should_keep_alive() in the on_headers_complete or
305 |  * on_message_complete callback returns 0, then this should be
306 |  * the last message on the connection.
307 |  * If you are the server, respond with the "Connection: close" header.
308 |  * If you are the client, close the connection.
309 |  */
310 | int http_should_keep_alive(const http_parser *parser);
311 | 
312 | /* Returns a string version of the HTTP method. */
313 | const char *http_method_str(enum http_method m);
314 | 
315 | /* Return a string name of the given error */
316 | const char *http_errno_name(enum http_errno err);
317 | 
318 | /* Return a string description of the given error */
319 | const char *http_errno_description(enum http_errno err);
320 | 
321 | /* Parse a URL; return nonzero on failure */
322 | int http_parser_parse_url(const char *buf, size_t buflen,
323 |                           int is_connect,
324 |                           struct http_parser_url *u);
325 | 
326 | /* Pause or un-pause the parser; a nonzero value pauses */
327 | void http_parser_pause(http_parser *parser, int paused);
328 | 
329 | /* Checks if this is the final chunk of the body. */
330 | int http_body_is_final(const http_parser *parser);
331 | 
332 | #ifdef __cplusplus
333 | }
334 | #endif
335 | #endif
336 | 


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


--------------------------------------------------------------------------------