diff --git a/srcs/httpserver/CMakeLists.txt b/srcs/httpserver/CMakeLists.txt index bad1824..d20a7c4 100644 --- a/srcs/httpserver/CMakeLists.txt +++ b/srcs/httpserver/CMakeLists.txt @@ -20,7 +20,7 @@ if (UNIX) add_definitions(-DUNIX) endif (UNIX) -INCLUDE_DIRECTORIES(./include ./src) +INCLUDE_DIRECTORIES(./include ./src ../libs/include) file(GLOB_RECURSE HW_HEADS ./src/haywire/*.h diff --git a/srcs/httpserver/include/haywire.h b/srcs/httpserver/include/haywire.h index 371f782..5c8f42a 100644 --- a/srcs/httpserver/include/haywire.h +++ b/srcs/httpserver/include/haywire.h @@ -185,7 +185,7 @@ HAYWIRE_EXTERN void hw_set_response_status_code(hw_http_response* response, hw_s HAYWIRE_EXTERN void hw_set_response_header(hw_http_response* response, hw_string* name, hw_string* value); HAYWIRE_EXTERN void hw_set_body(hw_http_response* response, hw_string* body); HAYWIRE_EXTERN void hw_http_response_send(hw_http_response* response, void* user_data, http_response_complete_callback callback); - +HAYWIRE_EXTERN void hw_http_response_send_error(hw_http_response *response, const char *error, const char *err_msg); HAYWIRE_EXTERN void hw_print_request_headers(http_request* request); #ifdef __cplusplus diff --git a/srcs/httpserver/src/haywire/configuration/configuration.c b/srcs/httpserver/src/haywire/configuration/configuration.c index 49bed76..dcbf472 100644 --- a/srcs/httpserver/src/haywire/configuration/configuration.c +++ b/srcs/httpserver/src/haywire/configuration/configuration.c @@ -4,33 +4,25 @@ #include "../khash.h" #include "ini.h" -KHASH_MAP_INIT_STR(route_hashes, char*) +KHASH_MAP_INIT_STR(route_hashes, char *) + +int configuration_handler(void *user, const char *section, const char *name, const char *value) { + configuration *config = (configuration *)user; -int configuration_handler(void* user, const char* section, const char* name, const char* value) -{ - configuration* config = (configuration*)user; - #define MATCH(s, n) strcmp(section, s) == 0 && strcmp(name, n) == 0 - if (MATCH("http", "listen_address")) - { + if (MATCH("http", "listen_address")) { config->http_listen_address = dupstr(value); - } - else if (MATCH("http", "listen_port")) - { + } else if (MATCH("http", "listen_port")) { config->http_listen_port = atoi(value); - } - else - { - return 0; /* unknown section/name, error */ + } else { + return 0; /* unknown section/name, error */ } return 1; } -configuration* load_configuration(const char* filename) -{ - configuration* config = malloc(sizeof(configuration)); - if (ini_parse(filename, configuration_handler, config) < 0) - { +configuration *load_configuration(const char *filename) { + configuration *config = malloc(sizeof(configuration)); + if (ini_parse(filename, configuration_handler, config) < 0) { dzlog_error("Can't load configuration\n"); return NULL; } diff --git a/srcs/httpserver/src/haywire/configuration/configuration.h b/srcs/httpserver/src/haywire/configuration/configuration.h index 8726f25..75711bf 100644 --- a/srcs/httpserver/src/haywire/configuration/configuration.h +++ b/srcs/httpserver/src/haywire/configuration/configuration.h @@ -1,4 +1,4 @@ #pragma once #include "haywire.h" -configuration* load_configuration(const char* filename); +configuration *load_configuration(const char *filename); diff --git a/srcs/httpserver/src/haywire/configuration/ini.c b/srcs/httpserver/src/haywire/configuration/ini.c index ee061fb..46bf276 100644 --- a/srcs/httpserver/src/haywire/configuration/ini.c +++ b/srcs/httpserver/src/haywire/configuration/ini.c @@ -14,71 +14,63 @@ #include "ini.h" -#define MAX_LINE 200 +#define MAX_LINE 200 #define MAX_SECTION 50 -#define MAX_NAME 50 +#define MAX_NAME 50 /* Strip whitespace chars off end of given string, in place. Return s. */ -static char* rstrip(char* s) -{ - char* p = s + strlen(s); +static char *rstrip(char *s) { + char *p = s + strlen(s); while (p > s && isspace(*--p)) *p = '\0'; return s; } /* Return pointer to first non-whitespace char in given string. */ -static char* lskip(const char* s) -{ +static char *lskip(const char *s) { while (*s && isspace(*s)) s++; - return (char*)s; + return (char *)s; } /* Return pointer to first char c or ';' comment in given string, or pointer to null at end of string if neither found. ';' must be prefixed by a whitespace character to register as a comment. */ -static char* find_char_or_comment(const char* s, char c) -{ +static char *find_char_or_comment(const char *s, char c) { int was_whitespace = 0; while (*s && *s != c && !(was_whitespace && *s == ';')) { was_whitespace = isspace(*s); s++; } - return (char*)s; + return (char *)s; } /* Version of strncpy that ensures dest (size bytes) is null-terminated. */ -static char* strncpy0(char* dest, const char* src, size_t size) -{ +static char *strncpy0(char *dest, const char *src, size_t size) { strncpy(dest, src, size); dest[size - 1] = '\0'; return dest; } /* See documentation in header file. */ -int ini_parse_file(FILE* file, - int (*handler)(void*, const char*, const char*, - const char*), - void* user) -{ +int ini_parse_file(FILE *file, int (*handler)(void *, const char *, const char *, const char *), void *user) { /* Uses a fair bit of stack (use heap instead if you need to) */ char line[MAX_LINE]; char section[MAX_SECTION] = ""; - char prev_name[MAX_NAME] = ""; - - char* start; - char* end; - char* name; - char* value; - int lineno = 0; - int error = 0; - + char prev_name[MAX_NAME] = ""; + + char *start; + char *end; + char *name; + char *value; + int lineno = 0; + int error = 0; + /* Scan through file line by line */ while (fgets(line, sizeof(line), file) != NULL) { lineno++; start = lskip(rstrip(line)); - + if (*start == ';' || *start == '#') { /* Per Python ConfigParser, allow '#' comments at start of line */ } @@ -97,50 +89,44 @@ int ini_parse_file(FILE* file, *end = '\0'; strncpy0(section, start + 1, sizeof(section)); *prev_name = '\0'; - } - else if (!error) { + } else if (!error) { /* No ']' found on section line */ error = lineno; } - } - else if (*start && *start != ';') { + } else if (*start && *start != ';') { /* Not a comment, must be a name[=:]value pair */ end = find_char_or_comment(start, '='); if (*end != '=') { end = find_char_or_comment(start, ':'); } if (*end == '=' || *end == ':') { - *end = '\0'; - name = rstrip(start); + *end = '\0'; + name = rstrip(start); value = lskip(end + 1); - end = find_char_or_comment(value, '\0'); + end = find_char_or_comment(value, '\0'); if (*end == ';') *end = '\0'; rstrip(value); - + /* Valid name[=:]value pair found, call handler */ strncpy0(prev_name, name, sizeof(prev_name)); if (!handler(user, section, name, value) && !error) error = lineno; - } - else if (!error) { + } else if (!error) { /* No '=' or ':' found on name[=:]value line */ error = lineno; } } } - + return error; } /* See documentation in header file. */ -int ini_parse(const char* filename, - int (*handler)(void*, const char*, const char*, const char*), - void* user) -{ - FILE* file; - int error; - +int ini_parse(const char *filename, int (*handler)(void *, const char *, const char *, const char *), void *user) { + FILE *file; + int error; + file = fopen(filename, "r"); if (!file) return -1; diff --git a/srcs/httpserver/src/haywire/configuration/ini.h b/srcs/httpserver/src/haywire/configuration/ini.h index 9b20211..991b383 100644 --- a/srcs/httpserver/src/haywire/configuration/ini.h +++ b/srcs/httpserver/src/haywire/configuration/ini.h @@ -15,10 +15,10 @@ #ifdef __cplusplus extern "C" { #endif - + #include - - /* Parse given INI-style file. May have [section]s, name=value pairs + +/* Parse given INI-style file. May have [section]s, name=value pairs (whitespace stripped), and comments starting with ';' (semicolon). Section is "" if name=value pair parsed before any section heading. name:value pairs are also supported as a concession to Python's ConfigParser. @@ -30,25 +30,21 @@ extern "C" { Returns 0 on success, line number of first error on parse error (doesn't stop on first error), or -1 on file open error. */ - int ini_parse(const char* filename, - int (*handler)(void* user, const char* section, - const char* name, const char* value), - void* user); - - /* Same as ini_parse(), but takes a FILE* instead of filename. This doesn't +int ini_parse(const char *filename, + int (*handler)(void *user, const char *section, const char *name, const char *value), void *user); + +/* Same as ini_parse(), but takes a FILE* instead of filename. This doesn't close the file when it's finished -- the caller must do that. */ - int ini_parse_file(FILE* file, - int (*handler)(void* user, const char* section, - const char* name, const char* value), - void* user); - - /* Nonzero to allow multi-line value parsing, in the style of Python's +int ini_parse_file(FILE *file, int (*handler)(void *user, const char *section, const char *name, const char *value), + void *user); + +/* Nonzero to allow multi-line value parsing, in the style of Python's ConfigParser. If allowed, ini_parse() will call the handler with the same name for each subsequent line parsed. */ #ifndef INI_ALLOW_MULTILINE #define INI_ALLOW_MULTILINE 1 #endif - + #ifdef __cplusplus } #endif diff --git a/srcs/httpserver/src/haywire/connection_consumer.c b/srcs/httpserver/src/haywire/connection_consumer.c index 40f64c1..fc2dbe3 100644 --- a/srcs/httpserver/src/haywire/connection_consumer.c +++ b/srcs/httpserver/src/haywire/connection_consumer.c @@ -8,121 +8,111 @@ static bool tcp_nodelay; -void ipc_read_cb(uv_stream_t* handle, ssize_t nread, const uv_buf_t* buf) -{ - int rc; - struct ipc_client_ctx* ctx; - uv_loop_t* loop; - uv_handle_type type; - uv_pipe_t* ipc_pipe; - - ipc_pipe = (uv_pipe_t*)handle; - ctx = container_of(ipc_pipe, struct ipc_client_ctx, ipc_pipe); - loop = ipc_pipe->loop; - +void ipc_read_cb(uv_stream_t *handle, ssize_t nread, const uv_buf_t *buf) { + int rc; + struct ipc_client_ctx *ctx; + uv_loop_t *loop; + uv_handle_type type; + uv_pipe_t *ipc_pipe; + + ipc_pipe = (uv_pipe_t *)handle; + ctx = container_of(ipc_pipe, struct ipc_client_ctx, ipc_pipe); + loop = ipc_pipe->loop; + uv_pipe_pending_count(ipc_pipe); type = uv_pipe_pending_type(ipc_pipe); - + if (type == UV_TCP) { - rc = uv_tcp_init(loop, (uv_tcp_t*) ctx->server_handle); + rc = uv_tcp_init(loop, (uv_tcp_t *)ctx->server_handle); if (tcp_nodelay) { - rc = uv_tcp_nodelay((uv_tcp_t*) ctx->server_handle, 1); + rc = uv_tcp_nodelay((uv_tcp_t *)ctx->server_handle, 1); } - } - else if (type == UV_NAMED_PIPE) - rc = uv_pipe_init(loop, (uv_pipe_t*) ctx->server_handle, 0); - + } else if (type == UV_NAMED_PIPE) + rc = uv_pipe_init(loop, (uv_pipe_t *)ctx->server_handle, 0); + rc = uv_accept(handle, ctx->server_handle); - uv_close((uv_handle_t*) &ctx->ipc_pipe, NULL); + uv_close((uv_handle_t *)&ctx->ipc_pipe, NULL); } -void ipc_alloc_cb(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf) -{ - struct ipc_client_ctx* ctx; - ctx = container_of(handle, struct ipc_client_ctx, ipc_pipe); +void ipc_alloc_cb(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) { + struct ipc_client_ctx *ctx; + ctx = container_of(handle, struct ipc_client_ctx, ipc_pipe); buf->base = ctx->scratch; - buf->len = sizeof(ctx->scratch); + buf->len = sizeof(ctx->scratch); } -void ipc_connect_cb(uv_connect_t* req, int status) -{ - int rc; - struct ipc_client_ctx* ctx; +void ipc_connect_cb(uv_connect_t *req, int status) { + int rc; + struct ipc_client_ctx *ctx; ctx = container_of(req, struct ipc_client_ctx, connect_req); - rc = uv_read_start((uv_stream_t*)&ctx->ipc_pipe, ipc_alloc_cb, ipc_read_cb); + rc = uv_read_start((uv_stream_t *)&ctx->ipc_pipe, ipc_alloc_cb, ipc_read_cb); } -void connection_consumer_alloc(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf) -{ +void connection_consumer_alloc(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) { static char slab[32]; buf->base = slab; - buf->len = sizeof(slab); + buf->len = sizeof(slab); } -void connection_consumer_new_connection(uv_stream_t* server_handle, int status) -{ - int rc = 0; - http_connection* connection = create_http_connection(); +void connection_consumer_new_connection(uv_stream_t *server_handle, int status) { + int rc = 0; + http_connection *connection = create_http_connection(); http_parser_init(&connection->parser, HTTP_REQUEST); - + connection->parser.data = connection; connection->stream.data = connection; - + rc = uv_tcp_init(server_handle->loop, &connection->stream); - + if (tcp_nodelay) { - rc = uv_tcp_nodelay((uv_tcp_t*)&connection->stream, 1); + rc = uv_tcp_nodelay((uv_tcp_t *)&connection->stream, 1); } - rc = uv_accept(server_handle, (uv_stream_t*)&connection->stream); - rc = uv_read_start((uv_stream_t*)&connection->stream, http_stream_on_alloc, http_stream_on_read); + rc = uv_accept(server_handle, (uv_stream_t *)&connection->stream); + rc = uv_read_start((uv_stream_t *)&connection->stream, http_stream_on_alloc, http_stream_on_read); } -void connection_consumer_close(uv_async_t* handle, int status) -{ - struct server_ctx* ctx; +void connection_consumer_close(uv_async_t *handle, int status) { + struct server_ctx *ctx; ctx = container_of(handle, struct server_ctx, async_handle); - uv_close((uv_handle_t*) &ctx->server_handle, NULL); - uv_close((uv_handle_t*) &ctx->async_handle, NULL); + uv_close((uv_handle_t *)&ctx->server_handle, NULL); + uv_close((uv_handle_t *)&ctx->async_handle, NULL); } -void get_listen_handle(uv_loop_t* loop, uv_stream_t* server_handle) -{ - int rc; +void get_listen_handle(uv_loop_t *loop, uv_stream_t *server_handle) { + int rc; struct ipc_client_ctx ctx; - - ctx.server_handle = server_handle; + + ctx.server_handle = server_handle; ctx.server_handle->data = "server handle"; - + rc = uv_pipe_init(loop, &ctx.ipc_pipe, 1); uv_pipe_connect(&ctx.connect_req, &ctx.ipc_pipe, "HAYWIRE_CONNECTION_DISPATCH_PIPE_NAME", ipc_connect_cb); rc = uv_run(loop, UV_RUN_DEFAULT); } -void connection_consumer_start(void *arg) -{ - int rc; +void connection_consumer_start(void *arg) { struct server_ctx *ctx; - uv_loop_t* loop; - - ctx = arg; - tcp_nodelay = ctx->tcp_nodelay; - loop = uv_loop_new(); + uv_loop_t *loop; + + ctx = arg; + tcp_nodelay = ctx->tcp_nodelay; + loop = uv_loop_new(); listener_event_loops[ctx->index] = *loop; - + http_request_cache_configure_listener(loop, &listener_async_handles[ctx->index]); uv_barrier_wait(listeners_created_barrier); - - rc = uv_async_init(loop, &ctx->async_handle, connection_consumer_close); - uv_unref((uv_handle_t*) &ctx->async_handle); - + + uv_async_init(loop, &ctx->async_handle, connection_consumer_close); + uv_unref((uv_handle_t *)&ctx->async_handle); + /* Wait until the main thread is ready. */ uv_sem_wait(&ctx->semaphore); - get_listen_handle(loop, (uv_stream_t*) &ctx->server_handle); + get_listen_handle(loop, (uv_stream_t *)&ctx->server_handle); uv_sem_post(&ctx->semaphore); - - rc = uv_listen((uv_stream_t*)&ctx->server_handle, ctx->listen_backlog, connection_consumer_new_connection); - rc = uv_run(loop, UV_RUN_DEFAULT); - + + uv_listen((uv_stream_t *)&ctx->server_handle, ctx->listen_backlog, connection_consumer_new_connection); + uv_run(loop, UV_RUN_DEFAULT); + uv_loop_delete(loop); } diff --git a/srcs/httpserver/src/haywire/connection_consumer.h b/srcs/httpserver/src/haywire/connection_consumer.h index 12a7507..9dfab53 100644 --- a/srcs/httpserver/src/haywire/connection_consumer.h +++ b/srcs/httpserver/src/haywire/connection_consumer.h @@ -4,47 +4,42 @@ #include "uv.h" #ifndef offsetof -#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) +#define offsetof(TYPE, MEMBER) ((size_t) & ((TYPE *)0)->MEMBER) #endif -#define container_of(ptr, type, member) ((type*)(((char*)(ptr)) - offsetof(type, member))) +#define container_of(ptr, type, member) ((type *)(((char *)(ptr)) - offsetof(type, member))) - -union stream_handle2 -{ +union stream_handle2 { uv_pipe_t pipe; - uv_tcp_t tcp; + uv_tcp_t tcp; }; typedef unsigned char handle_storage_t[sizeof(union stream_handle2)]; -struct server_ctx -{ - int index; +struct server_ctx { + int index; handle_storage_t server_handle; - unsigned int num_connects; - uv_async_t async_handle; - uv_thread_t thread_id; - uv_sem_t semaphore; - bool tcp_nodelay; - unsigned int listen_backlog; + unsigned int num_connects; + uv_async_t async_handle; + uv_thread_t thread_id; + uv_sem_t semaphore; + bool tcp_nodelay; + unsigned int listen_backlog; }; -struct ipc_client_ctx -{ +struct ipc_client_ctx { uv_connect_t connect_req; - uv_stream_t* server_handle; - uv_pipe_t ipc_pipe; - char scratch[16]; + uv_stream_t *server_handle; + uv_pipe_t ipc_pipe; + char scratch[16]; }; -struct ipc_server_ctx -{ +struct ipc_server_ctx { handle_storage_t server_handle; - unsigned int num_connects; - uv_pipe_t ipc_pipe; - bool tcp_nodelay; + unsigned int num_connects; + uv_pipe_t ipc_pipe; + bool tcp_nodelay; }; void connection_consumer_start(void *arg); -void connection_consumer_close(uv_async_t* handle, int status); +void connection_consumer_close(uv_async_t *handle, int status); diff --git a/srcs/httpserver/src/haywire/connection_dispatcher.c b/srcs/httpserver/src/haywire/connection_dispatcher.c index 79174c8..9d4365c 100644 --- a/srcs/httpserver/src/haywire/connection_dispatcher.c +++ b/srcs/httpserver/src/haywire/connection_dispatcher.c @@ -6,53 +6,45 @@ static struct sockaddr_in listen_addr; -void ipc_close_cb(uv_handle_t* handle) -{ - struct ipc_peer_ctx* ctx; +void ipc_close_cb(uv_handle_t *handle) { + struct ipc_peer_ctx *ctx; ctx = container_of(handle, struct ipc_peer_ctx, peer_handle); free(ctx); } -void ipc_write_cb(uv_write_t* req, int status) -{ - struct ipc_peer_ctx* ctx; +void ipc_write_cb(uv_write_t *req, int status) { + struct ipc_peer_ctx *ctx; ctx = container_of(req, struct ipc_peer_ctx, write_req); - uv_close((uv_handle_t*) &ctx->peer_handle, ipc_close_cb); + uv_close((uv_handle_t *)&ctx->peer_handle, ipc_close_cb); } -void ipc_connection_cb(uv_stream_t* ipc_pipe, int status) -{ - int rc; - struct ipc_server_ctx* sc; - struct ipc_peer_ctx* pc; - uv_loop_t* loop; - uv_buf_t buf; - +void ipc_connection_cb(uv_stream_t *ipc_pipe, int status) { + int rc; + struct ipc_server_ctx *sc; + struct ipc_peer_ctx *pc; + uv_loop_t *loop; + uv_buf_t buf; + loop = ipc_pipe->loop; - buf = uv_buf_init("PING", 4); - sc = container_of(ipc_pipe, struct ipc_server_ctx, ipc_pipe); - pc = calloc(1, sizeof(*pc)); + buf = uv_buf_init("PING", 4); + sc = container_of(ipc_pipe, struct ipc_server_ctx, ipc_pipe); + pc = calloc(1, sizeof(*pc)); //ASSERT(pc != NULL); - + if (ipc_pipe->type == UV_TCP) { - rc = uv_tcp_init(loop, (uv_tcp_t*) &pc->peer_handle); + rc = uv_tcp_init(loop, (uv_tcp_t *)&pc->peer_handle); if (sc->tcp_nodelay) { - rc = uv_tcp_nodelay((uv_tcp_t*) &pc->peer_handle, 1); + rc = uv_tcp_nodelay((uv_tcp_t *)&pc->peer_handle, 1); } - } - else if (ipc_pipe->type == UV_NAMED_PIPE) - rc = uv_pipe_init(loop, (uv_pipe_t*) &pc->peer_handle, 1); - - rc = uv_accept(ipc_pipe, (uv_stream_t*) &pc->peer_handle); - rc = uv_write2(&pc->write_req, - (uv_stream_t*) &pc->peer_handle, - &buf, - 1, - (uv_stream_t*) &sc->server_handle, - ipc_write_cb); - + } else if (ipc_pipe->type == UV_NAMED_PIPE) + rc = uv_pipe_init(loop, (uv_pipe_t *)&pc->peer_handle, 1); + + rc = uv_accept(ipc_pipe, (uv_stream_t *)&pc->peer_handle); + rc = uv_write2( + &pc->write_req, (uv_stream_t *)&pc->peer_handle, &buf, 1, (uv_stream_t *)&sc->server_handle, ipc_write_cb); + if (--sc->num_connects == 0) - uv_close((uv_handle_t*) ipc_pipe, NULL); + uv_close((uv_handle_t *)ipc_pipe, NULL); } extern void print_configuration(); @@ -60,43 +52,42 @@ extern void print_configuration(); * threads. It's kind of cumbersome for such a simple operation, maybe we * should revive uv_import() and uv_export(). */ -void start_connection_dispatching(uv_handle_type type, unsigned int num_servers, struct server_ctx* servers, char* listen_address, int listen_port, bool tcp_nodelay, int listen_backlog) -{ - int rc; +void start_connection_dispatching(uv_handle_type type, unsigned int num_servers, struct server_ctx *servers, + char *listen_address, int listen_port, bool tcp_nodelay, int listen_backlog) { + int rc; struct ipc_server_ctx ctx; - uv_loop_t* loop; - unsigned int i; - - loop = uv_default_loop(); + uv_loop_t *loop; + unsigned int i; + + loop = uv_default_loop(); ctx.num_connects = num_servers; - ctx.tcp_nodelay = tcp_nodelay; - - if (type == UV_TCP) - { + ctx.tcp_nodelay = tcp_nodelay; + + if (type == UV_TCP) { uv_ip4_addr(listen_address, listen_port, &listen_addr); - - rc = uv_tcp_init(loop, (uv_tcp_t*) &ctx.server_handle); - + + rc = uv_tcp_init(loop, (uv_tcp_t *)&ctx.server_handle); + if (ctx.tcp_nodelay) { - rc = uv_tcp_nodelay((uv_tcp_t*) &ctx.server_handle, 1); + rc = uv_tcp_nodelay((uv_tcp_t *)&ctx.server_handle, 1); } - rc = uv_tcp_bind((uv_tcp_t*) &ctx.server_handle, (const struct sockaddr*)&listen_addr, 0); + rc = uv_tcp_bind((uv_tcp_t *)&ctx.server_handle, (const struct sockaddr *)&listen_addr, 0); print_configuration(); printf("Listening...\n"); } - + rc = uv_pipe_init(loop, &ctx.ipc_pipe, 1); rc = uv_pipe_bind(&ctx.ipc_pipe, "HAYWIRE_CONNECTION_DISPATCH_PIPE_NAME"); - rc = uv_listen((uv_stream_t*) &ctx.ipc_pipe, listen_backlog, ipc_connection_cb); - + rc = uv_listen((uv_stream_t *)&ctx.ipc_pipe, listen_backlog, ipc_connection_cb); + for (i = 0; i < num_servers; i++) uv_sem_post(&servers[i].semaphore); - + rc = uv_run(loop, UV_RUN_DEFAULT); - uv_close((uv_handle_t*) &ctx.server_handle, NULL); + uv_close((uv_handle_t *)&ctx.server_handle, NULL); rc = uv_run(loop, UV_RUN_DEFAULT); - + for (i = 0; i < num_servers; i++) uv_sem_wait(&servers[i].semaphore); } diff --git a/srcs/httpserver/src/haywire/connection_dispatcher.h b/srcs/httpserver/src/haywire/connection_dispatcher.h index a2b7f74..d8c0462 100644 --- a/srcs/httpserver/src/haywire/connection_dispatcher.h +++ b/srcs/httpserver/src/haywire/connection_dispatcher.h @@ -3,10 +3,10 @@ #include "uv.h" #include "connection_consumer.h" -struct ipc_peer_ctx -{ +struct ipc_peer_ctx { handle_storage_t peer_handle; - uv_write_t write_req; + uv_write_t write_req; }; -void start_connection_dispatching(uv_handle_type type, unsigned int num_servers, struct server_ctx* servers, char* listen_address, int listen_port, bool tcp_nodelay, int listen_backlog); +void start_connection_dispatching(uv_handle_type type, unsigned int num_servers, struct server_ctx *servers, + char *listen_address, int listen_port, bool tcp_nodelay, int listen_backlog); diff --git a/srcs/httpserver/src/haywire/http_connection.h b/srcs/httpserver/src/haywire/http_connection.h index c8e2cb5..7ac4984 100644 --- a/srcs/httpserver/src/haywire/http_connection.h +++ b/srcs/httpserver/src/haywire/http_connection.h @@ -6,16 +6,19 @@ #include "http_request.h" #include "http_request_buffers.h" -typedef struct -{ - uv_tcp_t stream; - http_parser parser; - uv_write_t write_req; - http_request* request; - hw_string current_header_key; - hw_string current_header_value; - int keep_alive; - int last_was_value; - enum {OPEN, CLOSING, CLOSED} state; - hw_request_buffer* buffer; +typedef struct { + uv_tcp_t stream; + http_parser parser; + uv_write_t write_req; + http_request *request; + hw_string current_header_key; + hw_string current_header_value; + int keep_alive; + int last_was_value; + enum { + OPEN, + CLOSING, + CLOSED + } state; + hw_request_buffer *buffer; } http_connection; diff --git a/srcs/httpserver/src/haywire/http_parser.c b/srcs/httpserver/src/haywire/http_parser.c index c24a901..9a5a150 100644 --- a/srcs/httpserver/src/haywire/http_parser.c +++ b/srcs/httpserver/src/haywire/http_parser.c @@ -30,116 +30,109 @@ #include #ifndef ULLONG_MAX -# define ULLONG_MAX ((uint64_t) -1) /* 2^64-1 */ +#define ULLONG_MAX ((uint64_t)-1) /* 2^64-1 */ #endif #ifndef MIN -# define MIN(a,b) ((a) < (b) ? (a) : (b)) +#define MIN(a, b) ((a) < (b) ? (a) : (b)) #endif #ifndef ARRAY_SIZE -# define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) +#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) #endif #ifndef BIT_AT -# define BIT_AT(a, i) \ -(!!((unsigned int) (a)[(unsigned int) (i) >> 3] & \ -(1 << ((unsigned int) (i) & 7)))) +#define BIT_AT(a, i) (!!((unsigned int)(a)[(unsigned int)(i) >> 3] & (1 << ((unsigned int)(i)&7)))) #endif #ifndef ELEM_AT -# define ELEM_AT(a, i, v) ((unsigned int) (i) < ARRAY_SIZE(a) ? (a)[(i)] : (v)) +#define ELEM_AT(a, i, v) ((unsigned int)(i) < ARRAY_SIZE(a) ? (a)[(i)] : (v)) #endif -#define SET_ERRNO(e) \ -do { \ -parser->http_errno = (e); \ -} while(0) +#define SET_ERRNO(e) \ + do { \ + parser->http_errno = (e); \ + } while (0) #define CURRENT_STATE() p_state #define UPDATE_STATE(V) p_state = (V); -#define RETURN(V) \ -do { \ -parser->state = CURRENT_STATE(); \ -return (V); \ -} while (0); -#define REEXECUTE() \ ---p; \ -break; - +#define RETURN(V) \ + do { \ + parser->state = CURRENT_STATE(); \ + return (V); \ + } while (0); +#define REEXECUTE() \ + --p; \ + break; #ifdef __GNUC__ -# define LIKELY(X) __builtin_expect(!!(X), 1) -# define UNLIKELY(X) __builtin_expect(!!(X), 0) +#define LIKELY(X) __builtin_expect(!!(X), 1) +#define UNLIKELY(X) __builtin_expect(!!(X), 0) #else -# define LIKELY(X) (X) -# define UNLIKELY(X) (X) +#define LIKELY(X) (X) +#define UNLIKELY(X) (X) #endif - /* Run the notify callback FOR, returning ER if it fails */ -#define CALLBACK_NOTIFY_(FOR, ER) \ -do { \ -assert(HTTP_PARSER_ERRNO(parser) == HPE_OK); \ -\ -if (LIKELY(settings->on_##FOR)) { \ -parser->state = CURRENT_STATE(); \ -if (UNLIKELY(0 != settings->on_##FOR(parser))) { \ -SET_ERRNO(HPE_CB_##FOR); \ -} \ -UPDATE_STATE(parser->state); \ -\ -/* We either errored above or got paused; get out */ \ -if (UNLIKELY(HTTP_PARSER_ERRNO(parser) != HPE_OK)) { \ -return (ER); \ -} \ -} \ -} while (0) +#define CALLBACK_NOTIFY_(FOR, ER) \ + do { \ + assert(HTTP_PARSER_ERRNO(parser) == HPE_OK); \ + \ + if (LIKELY(settings->on_##FOR)) { \ + parser->state = CURRENT_STATE(); \ + if (UNLIKELY(0 != settings->on_##FOR(parser))) { \ + SET_ERRNO(HPE_CB_##FOR); \ + } \ + UPDATE_STATE(parser->state); \ + \ + /* We either errored above or got paused; get out */ \ + if (UNLIKELY(HTTP_PARSER_ERRNO(parser) != HPE_OK)) { \ + return (ER); \ + } \ + } \ + } while (0) /* Run the notify callback FOR and consume the current byte */ -#define CALLBACK_NOTIFY(FOR) CALLBACK_NOTIFY_(FOR, p - data + 1) +#define CALLBACK_NOTIFY(FOR) CALLBACK_NOTIFY_(FOR, p - data + 1) /* Run the notify callback FOR and don't consume the current byte */ -#define CALLBACK_NOTIFY_NOADVANCE(FOR) CALLBACK_NOTIFY_(FOR, p - data) +#define CALLBACK_NOTIFY_NOADVANCE(FOR) CALLBACK_NOTIFY_(FOR, p - data) /* Run data callback FOR with LEN bytes, returning ER if it fails */ -#define CALLBACK_DATA_(FOR, LEN, ER) \ -do { \ -assert(HTTP_PARSER_ERRNO(parser) == HPE_OK); \ -\ -if (FOR##_mark) { \ -if (LIKELY(settings->on_##FOR)) { \ -parser->state = CURRENT_STATE(); \ -if (UNLIKELY(0 != \ -settings->on_##FOR(parser, FOR##_mark, (LEN)))) { \ -SET_ERRNO(HPE_CB_##FOR); \ -} \ -UPDATE_STATE(parser->state); \ -\ -/* We either errored above or got paused; get out */ \ -if (UNLIKELY(HTTP_PARSER_ERRNO(parser) != HPE_OK)) { \ -return (ER); \ -} \ -} \ -FOR##_mark = NULL; \ -} \ -} while (0) +#define CALLBACK_DATA_(FOR, LEN, ER) \ + do { \ + assert(HTTP_PARSER_ERRNO(parser) == HPE_OK); \ + \ + if (FOR##_mark) { \ + if (LIKELY(settings->on_##FOR)) { \ + parser->state = CURRENT_STATE(); \ + if (UNLIKELY(0 != settings->on_##FOR(parser, FOR##_mark, (LEN)))) { \ + SET_ERRNO(HPE_CB_##FOR); \ + } \ + UPDATE_STATE(parser->state); \ + \ + /* We either errored above or got paused; get out */ \ + if (UNLIKELY(HTTP_PARSER_ERRNO(parser) != HPE_OK)) { \ + return (ER); \ + } \ + } \ + FOR##_mark = NULL; \ + } \ + } while (0) /* Run the data callback FOR and consume the current byte */ -#define CALLBACK_DATA(FOR) \ -CALLBACK_DATA_(FOR, p - FOR##_mark, p - data + 1) +#define CALLBACK_DATA(FOR) CALLBACK_DATA_(FOR, p - FOR##_mark, p - data + 1) /* Run the data callback FOR and don't consume the current byte */ -#define CALLBACK_DATA_NOADVANCE(FOR) \ -CALLBACK_DATA_(FOR, p - FOR##_mark, p - data) +#define CALLBACK_DATA_NOADVANCE(FOR) CALLBACK_DATA_(FOR, p - FOR##_mark, p - data) /* Set the mark FOR; non-destructive if mark is already set */ -#define MARK(FOR) \ -do { \ -if (!FOR##_mark) { \ -FOR##_mark = p; \ -} \ -} while (0) +#define MARK(FOR) \ + do { \ + if (!FOR##_mark) { \ + FOR##_mark = p; \ + } \ + } while (0) /* Don't allow the total size of the HTTP headers (including the status * line) to exceed HTTP_MAX_HEADER_SIZE. This check is here to protect @@ -152,34 +145,30 @@ FOR##_mark = p; \ * than any reasonable request or response so this should never affect * day-to-day operation. */ -#define COUNT_HEADER_SIZE(V) \ -do { \ -parser->nread += (V); \ -if (UNLIKELY(parser->nread > (HTTP_MAX_HEADER_SIZE))) { \ -SET_ERRNO(HPE_HEADER_OVERFLOW); \ -goto error; \ -} \ -} while (0) +#define COUNT_HEADER_SIZE(V) \ + do { \ + parser->nread += (V); \ + if (UNLIKELY(parser->nread > (HTTP_MAX_HEADER_SIZE))) { \ + SET_ERRNO(HPE_HEADER_OVERFLOW); \ + goto error; \ + } \ + } while (0) - -#define PROXY_CONNECTION "proxy-connection" -#define CONNECTION "connection" -#define CONTENT_LENGTH "content-length" +#define PROXY_CONNECTION "proxy-connection" +#define CONNECTION "connection" +#define CONTENT_LENGTH "content-length" #define TRANSFER_ENCODING "transfer-encoding" -#define UPGRADE "upgrade" -#define CHUNKED "chunked" -#define KEEP_ALIVE "keep-alive" -#define CLOSE "close" +#define UPGRADE "upgrade" +#define CHUNKED "chunked" +#define KEEP_ALIVE "keep-alive" +#define CLOSE "close" - -static const char *method_strings[] = -{ +static const char *method_strings[] = { #define XX(num, name, string) #string, HTTP_METHOD_MAP(XX) #undef XX }; - /* Tokens as defined by rfc 2616. Also lowercases them. * token = 1* * separators = "(" | ")" | "<" | ">" | "@" @@ -189,278 +178,388 @@ static const char *method_strings[] = */ static const char tokens[256] = { /* 0 nul 1 soh 2 stx 3 etx 4 eot 5 enq 6 ack 7 bel */ - 0, 0, 0, 0, 0, 0, 0, 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, /* 8 bs 9 ht 10 nl 11 vt 12 np 13 cr 14 so 15 si */ - 0, 0, 0, 0, 0, 0, 0, 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, /* 16 dle 17 dc1 18 dc2 19 dc3 20 dc4 21 nak 22 syn 23 etb */ - 0, 0, 0, 0, 0, 0, 0, 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, /* 24 can 25 em 26 sub 27 esc 28 fs 29 gs 30 rs 31 us */ - 0, 0, 0, 0, 0, 0, 0, 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, /* 32 sp 33 ! 34 " 35 # 36 $ 37 % 38 & 39 ' */ - 0, '!', 0, '#', '$', '%', '&', '\'', + 0, + '!', + 0, + '#', + '$', + '%', + '&', + '\'', /* 40 ( 41 ) 42 * 43 + 44 , 45 - 46 . 47 / */ - 0, 0, '*', '+', 0, '-', '.', 0, + 0, + 0, + '*', + '+', + 0, + '-', + '.', + 0, /* 48 0 49 1 50 2 51 3 52 4 53 5 54 6 55 7 */ - '0', '1', '2', '3', '4', '5', '6', '7', + '0', + '1', + '2', + '3', + '4', + '5', + '6', + '7', /* 56 8 57 9 58 : 59 ; 60 < 61 = 62 > 63 ? */ - '8', '9', 0, 0, 0, 0, 0, 0, + '8', + '9', + 0, + 0, + 0, + 0, + 0, + 0, /* 64 @ 65 A 66 B 67 C 68 D 69 E 70 F 71 G */ - 0, 'a', 'b', 'c', 'd', 'e', 'f', 'g', + 0, + 'a', + 'b', + 'c', + 'd', + 'e', + 'f', + 'g', /* 72 H 73 I 74 J 75 K 76 L 77 M 78 N 79 O */ - 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', + 'h', + 'i', + 'j', + 'k', + 'l', + 'm', + 'n', + 'o', /* 80 P 81 Q 82 R 83 S 84 T 85 U 86 V 87 W */ - 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', + 'p', + 'q', + 'r', + 's', + 't', + 'u', + 'v', + 'w', /* 88 X 89 Y 90 Z 91 [ 92 \ 93 ] 94 ^ 95 _ */ - 'x', 'y', 'z', 0, 0, 0, '^', '_', + 'x', + 'y', + 'z', + 0, + 0, + 0, + '^', + '_', /* 96 ` 97 a 98 b 99 c 100 d 101 e 102 f 103 g */ - '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', + '`', + 'a', + 'b', + 'c', + 'd', + 'e', + 'f', + 'g', /* 104 h 105 i 106 j 107 k 108 l 109 m 110 n 111 o */ - 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', + 'h', + 'i', + 'j', + 'k', + 'l', + 'm', + 'n', + 'o', /* 112 p 113 q 114 r 115 s 116 t 117 u 118 v 119 w */ - 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', + 'p', + 'q', + 'r', + 's', + 't', + 'u', + 'v', + 'w', /* 120 x 121 y 122 z 123 { 124 | 125 } 126 ~ 127 del */ - 'x', 'y', 'z', 0, '|', 0, '~', 0 }; - - -static const int8_t unhex[256] = -{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 - ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 - ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 - , 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1 - ,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1 - ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 - ,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1 - ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 -}; + 'x', + 'y', + 'z', + 0, + '|', + 0, + '~', + 0}; +static const int8_t unhex[256] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, + 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; #if HTTP_PARSER_STRICT -# define T(v) 0 +#define T(v) 0 #else -# define T(v) v +#define T(v) v #endif - static const uint8_t normal_url_char[32] = { /* 0 nul 1 soh 2 stx 3 etx 4 eot 5 enq 6 ack 7 bel */ - 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0, + 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0, /* 8 bs 9 ht 10 nl 11 vt 12 np 13 cr 14 so 15 si */ - 0 | T(2) | 0 | 0 | T(16) | 0 | 0 | 0, + 0 | T(2) | 0 | 0 | T(16) | 0 | 0 | 0, /* 16 dle 17 dc1 18 dc2 19 dc3 20 dc4 21 nak 22 syn 23 etb */ - 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0, + 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0, /* 24 can 25 em 26 sub 27 esc 28 fs 29 gs 30 rs 31 us */ - 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0, + 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0, /* 32 sp 33 ! 34 " 35 # 36 $ 37 % 38 & 39 ' */ - 0 | 2 | 4 | 0 | 16 | 32 | 64 | 128, + 0 | 2 | 4 | 0 | 16 | 32 | 64 | 128, /* 40 ( 41 ) 42 * 43 + 44 , 45 - 46 . 47 / */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, + 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, /* 48 0 49 1 50 2 51 3 52 4 53 5 54 6 55 7 */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, + 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, /* 56 8 57 9 58 : 59 ; 60 < 61 = 62 > 63 ? */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 0, + 1 | 2 | 4 | 8 | 16 | 32 | 64 | 0, /* 64 @ 65 A 66 B 67 C 68 D 69 E 70 F 71 G */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, + 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, /* 72 H 73 I 74 J 75 K 76 L 77 M 78 N 79 O */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, + 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, /* 80 P 81 Q 82 R 83 S 84 T 85 U 86 V 87 W */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, + 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, /* 88 X 89 Y 90 Z 91 [ 92 \ 93 ] 94 ^ 95 _ */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, + 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, /* 96 ` 97 a 98 b 99 c 100 d 101 e 102 f 103 g */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, + 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, /* 104 h 105 i 106 j 107 k 108 l 109 m 110 n 111 o */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, + 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, /* 112 p 113 q 114 r 115 s 116 t 117 u 118 v 119 w */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, + 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, /* 120 x 121 y 122 z 123 { 124 | 125 } 126 ~ 127 del */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 0, }; + 1 | 2 | 4 | 8 | 16 | 32 | 64 | 0, +}; #undef T -enum state -{ s_dead = 1 /* important that this is > 0 */ - - , s_start_req_or_res - , s_res_or_resp_H - , s_start_res - , s_res_H - , s_res_HT - , s_res_HTT - , s_res_HTTP - , s_res_first_http_major - , s_res_http_major - , s_res_first_http_minor - , s_res_http_minor - , s_res_first_status_code - , s_res_status_code - , s_res_status_start - , s_res_status - , s_res_line_almost_done - - , s_start_req - - , s_req_method - , s_req_spaces_before_url - , s_req_schema - , s_req_schema_slash - , s_req_schema_slash_slash - , s_req_server_start - , s_req_server - , s_req_server_with_at - , s_req_path - , s_req_query_string_start - , s_req_query_string - , s_req_fragment_start - , s_req_fragment - , s_req_http_start - , s_req_http_H - , s_req_http_HT - , s_req_http_HTT - , s_req_http_HTTP - , s_req_first_http_major - , s_req_http_major - , s_req_first_http_minor - , s_req_http_minor - , s_req_line_almost_done - - , s_header_field_start - , s_header_field - , s_header_value_discard_ws - , s_header_value_discard_ws_almost_done - , s_header_value_discard_lws - , s_header_value_start - , s_header_value - , s_header_value_lws - - , s_header_almost_done - - , s_chunk_size_start - , s_chunk_size - , s_chunk_parameters - , s_chunk_size_almost_done - - , s_headers_almost_done - , s_headers_done - - /* Important: 's_headers_done' must be the last 'header' state. All +enum state { + s_dead = 1 /* important that this is > 0 */ + + , + s_start_req_or_res, + s_res_or_resp_H, + s_start_res, + s_res_H, + s_res_HT, + s_res_HTT, + s_res_HTTP, + s_res_first_http_major, + s_res_http_major, + s_res_first_http_minor, + s_res_http_minor, + s_res_first_status_code, + s_res_status_code, + s_res_status_start, + s_res_status, + s_res_line_almost_done + + , + s_start_req + + , + s_req_method, + s_req_spaces_before_url, + s_req_schema, + s_req_schema_slash, + s_req_schema_slash_slash, + s_req_server_start, + s_req_server, + s_req_server_with_at, + s_req_path, + s_req_query_string_start, + s_req_query_string, + s_req_fragment_start, + s_req_fragment, + s_req_http_start, + s_req_http_H, + s_req_http_HT, + s_req_http_HTT, + s_req_http_HTTP, + s_req_first_http_major, + s_req_http_major, + s_req_first_http_minor, + s_req_http_minor, + s_req_line_almost_done + + , + s_header_field_start, + s_header_field, + s_header_value_discard_ws, + s_header_value_discard_ws_almost_done, + s_header_value_discard_lws, + s_header_value_start, + s_header_value, + s_header_value_lws + + , + s_header_almost_done + + , + s_chunk_size_start, + s_chunk_size, + s_chunk_parameters, + s_chunk_size_almost_done + + , + s_headers_almost_done, + s_headers_done + + /* Important: 's_headers_done' must be the last 'header' state. All * states beyond this must be 'body' states. It is used for overflow * checking. See the PARSING_HEADER() macro. */ - - , s_chunk_data - , s_chunk_data_almost_done - , s_chunk_data_done - - , s_body_identity - , s_body_identity_eof - - , s_message_done -}; + , + s_chunk_data, + s_chunk_data_almost_done, + s_chunk_data_done + + , + s_body_identity, + s_body_identity_eof + + , + s_message_done +}; #define PARSING_HEADER(state) (state <= s_headers_done) +enum header_states { + h_general = 0, + h_C, + h_CO, + h_CON -enum header_states -{ h_general = 0 - , h_C - , h_CO - , h_CON - - , h_matching_connection - , h_matching_proxy_connection - , h_matching_content_length - , h_matching_transfer_encoding - , h_matching_upgrade - - , h_connection - , h_content_length - , h_transfer_encoding - , h_upgrade - - , h_matching_transfer_encoding_chunked - , h_matching_connection_token_start - , h_matching_connection_keep_alive - , h_matching_connection_close - , h_matching_connection_upgrade - , h_matching_connection_token - - , h_transfer_encoding_chunked - , h_connection_keep_alive - , h_connection_close - , h_connection_upgrade + , + h_matching_connection, + h_matching_proxy_connection, + h_matching_content_length, + h_matching_transfer_encoding, + h_matching_upgrade + + , + h_connection, + h_content_length, + h_transfer_encoding, + h_upgrade + + , + h_matching_transfer_encoding_chunked, + h_matching_connection_token_start, + h_matching_connection_keep_alive, + h_matching_connection_close, + h_matching_connection_upgrade, + h_matching_connection_token + + , + h_transfer_encoding_chunked, + h_connection_keep_alive, + h_connection_close, + h_connection_upgrade }; -enum http_host_state -{ - s_http_host_dead = 1 - , s_http_userinfo_start - , s_http_userinfo - , s_http_host_start - , s_http_host_v6_start - , s_http_host - , s_http_host_v6 - , s_http_host_v6_end - , s_http_host_port_start - , s_http_host_port +enum http_host_state { + s_http_host_dead = 1, + s_http_userinfo_start, + s_http_userinfo, + s_http_host_start, + s_http_host_v6_start, + s_http_host, + s_http_host_v6, + s_http_host_v6_end, + s_http_host_port_start, + s_http_host_port }; /* Macros for character classes; depends on strict-mode */ -#define CR '\r' -#define LF '\n' -#define LOWER(c) (unsigned char)(c | 0x20) -#define IS_ALPHA(c) (LOWER(c) >= 'a' && LOWER(c) <= 'z') -#define IS_NUM(c) ((c) >= '0' && (c) <= '9') -#define IS_ALPHANUM(c) (IS_ALPHA(c) || IS_NUM(c)) -#define IS_HEX(c) (IS_NUM(c) || (LOWER(c) >= 'a' && LOWER(c) <= 'f')) -#define IS_MARK(c) ((c) == '-' || (c) == '_' || (c) == '.' || \ -(c) == '!' || (c) == '~' || (c) == '*' || (c) == '\'' || (c) == '(' || \ -(c) == ')') -#define IS_USERINFO_CHAR(c) (IS_ALPHANUM(c) || IS_MARK(c) || (c) == '%' || \ -(c) == ';' || (c) == ':' || (c) == '&' || (c) == '=' || (c) == '+' || \ -(c) == '$' || (c) == ',') +#define CR '\r' +#define LF '\n' +#define LOWER(c) (unsigned char)(c | 0x20) +#define IS_ALPHA(c) (LOWER(c) >= 'a' && LOWER(c) <= 'z') +#define IS_NUM(c) ((c) >= '0' && (c) <= '9') +#define IS_ALPHANUM(c) (IS_ALPHA(c) || IS_NUM(c)) +#define IS_HEX(c) (IS_NUM(c) || (LOWER(c) >= 'a' && LOWER(c) <= 'f')) +#define IS_MARK(c) \ + ((c) == '-' || (c) == '_' || (c) == '.' || (c) == '!' || (c) == '~' || (c) == '*' || (c) == '\'' || (c) == '(' \ + || (c) == ')') +#define IS_USERINFO_CHAR(c) \ + (IS_ALPHANUM(c) || IS_MARK(c) || (c) == '%' || (c) == ';' || (c) == ':' || (c) == '&' || (c) == '=' || (c) == '+' \ + || (c) == '$' || (c) == ',') -#define STRICT_TOKEN(c) (tokens[(unsigned char)c]) +#define STRICT_TOKEN(c) (tokens[(unsigned char)c]) #if HTTP_PARSER_STRICT -#define TOKEN(c) (tokens[(unsigned char)c]) -#define IS_URL_CHAR(c) (BIT_AT(normal_url_char, (unsigned char)c)) -#define IS_HOST_CHAR(c) (IS_ALPHANUM(c) || (c) == '.' || (c) == '-') +#define TOKEN(c) (tokens[(unsigned char)c]) +#define IS_URL_CHAR(c) (BIT_AT(normal_url_char, (unsigned char)c)) +#define IS_HOST_CHAR(c) (IS_ALPHANUM(c) || (c) == '.' || (c) == '-') #else -#define TOKEN(c) ((c == ' ') ? ' ' : tokens[(unsigned char)c]) -#define IS_URL_CHAR(c) \ -(BIT_AT(normal_url_char, (unsigned char)c) || ((c) & 0x80)) -#define IS_HOST_CHAR(c) \ -(IS_ALPHANUM(c) || (c) == '.' || (c) == '-' || (c) == '_') +#define TOKEN(c) ((c == ' ') ? ' ' : tokens[(unsigned char)c]) +#define IS_URL_CHAR(c) (BIT_AT(normal_url_char, (unsigned char)c) || ((c)&0x80)) +#define IS_HOST_CHAR(c) (IS_ALPHANUM(c) || (c) == '.' || (c) == '-' || (c) == '_') #endif - #define start_state (parser->type == HTTP_REQUEST ? s_start_req : s_start_res) - #if HTTP_PARSER_STRICT -# define STRICT_CHECK(cond) \ -do { \ -if (cond) { \ -SET_ERRNO(HPE_STRICT); \ -goto error; \ -} \ -} while (0) -# define NEW_MESSAGE() (http_should_keep_alive(parser) ? start_state : s_dead) +#define STRICT_CHECK(cond) \ + do { \ + if (cond) { \ + SET_ERRNO(HPE_STRICT); \ + goto error; \ + } \ + } while (0) +#define NEW_MESSAGE() (http_should_keep_alive(parser) ? start_state : s_dead) #else -# define STRICT_CHECK(cond) -# define NEW_MESSAGE() start_state +#define STRICT_CHECK(cond) +#define NEW_MESSAGE() start_state #endif - /* Map errno values to strings for human-readable output */ -#define HTTP_STRERROR_GEN(n, s) { "HPE_" #n, s }, +#define HTTP_STRERROR_GEN(n, s) {"HPE_" #n, s}, static struct { const char *name; const char *description; -} http_strerror_tab[] = { - HTTP_ERRNO_MAP(HTTP_STRERROR_GEN) -}; +} http_strerror_tab[] = {HTTP_ERRNO_MAP(HTTP_STRERROR_GEN)}; #undef HTTP_STRERROR_GEN int http_message_needs_eof(const http_parser *parser); @@ -476,174 +575,168 @@ int http_message_needs_eof(const http_parser *parser); * assumed that the caller cares about (and can detect) the transition between * URL and non-URL states by looking for these. */ -static enum state -parse_url_char(enum state s, const char ch) -{ +static enum state parse_url_char(enum state s, const char ch) { if (ch == ' ' || ch == '\r' || ch == '\n') { return s_dead; } - + #if HTTP_PARSER_STRICT if (ch == '\t' || ch == '\f') { return s_dead; } #endif - + switch (s) { case s_req_spaces_before_url: /* Proxied requests are followed by scheme of an absolute URI (alpha). * All methods except CONNECT are followed by '/' or '*'. */ - + if (ch == '/' || ch == '*') { return s_req_path; } - + if (IS_ALPHA(ch)) { return s_req_schema; } - + break; - + case s_req_schema: if (IS_ALPHA(ch)) { return s; } - + if (ch == ':') { return s_req_schema_slash; } - + break; - + case s_req_schema_slash: if (ch == '/') { return s_req_schema_slash_slash; } - + break; - + case s_req_schema_slash_slash: if (ch == '/') { return s_req_server_start; } - + break; - + case s_req_server_with_at: if (ch == '@') { return s_dead; } - + /* FALLTHROUGH */ case s_req_server_start: case s_req_server: if (ch == '/') { return s_req_path; } - + if (ch == '?') { return s_req_query_string_start; } - + if (ch == '@') { return s_req_server_with_at; } - + if (IS_USERINFO_CHAR(ch) || ch == '[' || ch == ']') { return s_req_server; } - + break; - + case s_req_path: if (IS_URL_CHAR(ch)) { return s; } - + switch (ch) { case '?': return s_req_query_string_start; - + case '#': return s_req_fragment_start; } - + break; - + case s_req_query_string_start: case s_req_query_string: if (IS_URL_CHAR(ch)) { return s_req_query_string; } - + switch (ch) { case '?': /* allow extra '?' in query string */ return s_req_query_string; - + case '#': return s_req_fragment_start; } - + break; - + case s_req_fragment_start: if (IS_URL_CHAR(ch)) { return s_req_fragment; } - + switch (ch) { case '?': return s_req_fragment; - + case '#': return s; } - + break; - + case s_req_fragment: if (IS_URL_CHAR(ch)) { return s; } - + switch (ch) { case '?': case '#': return s; } - + break; - + default: break; } - + /* We should never fall out of the switch above unless there's an error */ return s_dead; } -size_t http_parser_execute (http_parser *parser, - const http_parser_settings *settings, - const char *data, - size_t len) -{ - char c, ch; - int8_t unhex_val; - const char *p = data; +size_t http_parser_execute(http_parser *parser, const http_parser_settings *settings, const char *data, size_t len) { + char c, ch; + int8_t unhex_val; + const char *p = data; const char *header_field_mark = 0; const char *header_value_mark = 0; - const char *url_mark = 0; - const char *body_mark = 0; - const char *status_mark = 0; - enum state p_state = parser->state; - + const char *url_mark = 0; + const char *body_mark = 0; + const char *status_mark = 0; + enum state p_state = parser->state; + /* We're in an error state. Don't bother doing anything. */ if (HTTP_PARSER_ERRNO(parser) != HPE_OK) { return 0; } - + if (len == 0) { switch (CURRENT_STATE()) { case s_body_identity_eof: @@ -652,20 +745,19 @@ size_t http_parser_execute (http_parser *parser, */ CALLBACK_NOTIFY_NOADVANCE(message_complete); return 0; - + case s_dead: case s_start_req_or_res: case s_start_res: case s_start_req: return 0; - + default: SET_ERRNO(HPE_INVALID_EOF_STATE); return 1; } } - - + if (CURRENT_STATE() == s_header_field) header_field_mark = data; if (CURRENT_STATE() == s_header_value) @@ -690,45 +782,44 @@ size_t http_parser_execute (http_parser *parser, default: break; } - - for (p=data; p != data + len; p++) { + + for (p = data; p != data + len; p++) { ch = *p; - + if (PARSING_HEADER(CURRENT_STATE())) COUNT_HEADER_SIZE(1); - + switch (CURRENT_STATE()) { - + case s_dead: /* this state is used after a 'Connection: close' message * the parser will error out if it reads another message */ if (LIKELY(ch == CR || ch == LF)) break; - + SET_ERRNO(HPE_CLOSED_CONNECTION); goto error; - - case s_start_req_or_res: - { + + case s_start_req_or_res: { if (ch == CR || ch == LF) break; - parser->flags = 0; + parser->flags = 0; parser->content_length = ULLONG_MAX; - + if (ch == 'H') { UPDATE_STATE(s_res_or_resp_H); - + CALLBACK_NOTIFY(message_begin); } else { parser->type = HTTP_REQUEST; UPDATE_STATE(s_start_req); REEXECUTE(); } - + break; } - + case s_res_or_resp_H: if (ch == 'T') { parser->type = HTTP_RESPONSE; @@ -738,133 +829,129 @@ size_t http_parser_execute (http_parser *parser, SET_ERRNO(HPE_INVALID_CONSTANT); goto error; } - - parser->type = HTTP_REQUEST; + + parser->type = HTTP_REQUEST; parser->method = HTTP_HEAD; - parser->index = 2; + parser->index = 2; UPDATE_STATE(s_req_method); } break; - - case s_start_res: - { - parser->flags = 0; + + case s_start_res: { + parser->flags = 0; parser->content_length = ULLONG_MAX; - + switch (ch) { case 'H': UPDATE_STATE(s_res_H); break; - + case CR: case LF: break; - + default: SET_ERRNO(HPE_INVALID_CONSTANT); goto error; } - + CALLBACK_NOTIFY(message_begin); break; } - + case s_res_H: STRICT_CHECK(ch != 'T'); UPDATE_STATE(s_res_HT); break; - + case s_res_HT: STRICT_CHECK(ch != 'T'); UPDATE_STATE(s_res_HTT); break; - + case s_res_HTT: STRICT_CHECK(ch != 'P'); UPDATE_STATE(s_res_HTTP); break; - + case s_res_HTTP: STRICT_CHECK(ch != '/'); UPDATE_STATE(s_res_first_http_major); break; - + case s_res_first_http_major: if (UNLIKELY(ch < '0' || ch > '9')) { SET_ERRNO(HPE_INVALID_VERSION); goto error; } - + parser->http_major = ch - '0'; UPDATE_STATE(s_res_http_major); break; - + /* major HTTP version or dot */ - case s_res_http_major: - { + case s_res_http_major: { if (ch == '.') { UPDATE_STATE(s_res_first_http_minor); break; } - + if (!IS_NUM(ch)) { SET_ERRNO(HPE_INVALID_VERSION); goto error; } - + parser->http_major *= 10; parser->http_major += ch - '0'; - + if (UNLIKELY(parser->http_major > 999)) { SET_ERRNO(HPE_INVALID_VERSION); goto error; } - + break; } - + /* first digit of minor HTTP version */ case s_res_first_http_minor: if (UNLIKELY(!IS_NUM(ch))) { SET_ERRNO(HPE_INVALID_VERSION); goto error; } - + parser->http_minor = ch - '0'; UPDATE_STATE(s_res_http_minor); break; - + /* minor HTTP version or end of request line */ - case s_res_http_minor: - { + case s_res_http_minor: { if (ch == ' ') { UPDATE_STATE(s_res_first_status_code); break; } - + if (UNLIKELY(!IS_NUM(ch))) { SET_ERRNO(HPE_INVALID_VERSION); goto error; } - + parser->http_minor *= 10; parser->http_minor += ch - '0'; - + if (UNLIKELY(parser->http_minor > 999)) { SET_ERRNO(HPE_INVALID_VERSION); goto error; } - + break; } - - case s_res_first_status_code: - { + + case s_res_first_status_code: { if (!IS_NUM(ch)) { if (ch == ' ') { break; } - + SET_ERRNO(HPE_INVALID_STATUS); goto error; } @@ -872,9 +959,8 @@ size_t http_parser_execute (http_parser *parser, UPDATE_STATE(s_res_status_code); break; } - - case s_res_status_code: - { + + case s_res_status_code: { if (!IS_NUM(ch)) { switch (ch) { case ' ': @@ -892,105 +978,127 @@ size_t http_parser_execute (http_parser *parser, } break; } - + parser->status_code *= 10; parser->status_code += ch - '0'; - + if (UNLIKELY(parser->status_code > 999)) { SET_ERRNO(HPE_INVALID_STATUS); goto error; } - + break; } - - case s_res_status_start: - { + + case s_res_status_start: { if (ch == CR) { UPDATE_STATE(s_res_line_almost_done); break; } - + if (ch == LF) { UPDATE_STATE(s_header_field_start); break; } - + MARK(status); UPDATE_STATE(s_res_status); parser->index = 0; break; } - + case s_res_status: if (ch == CR) { UPDATE_STATE(s_res_line_almost_done); CALLBACK_DATA(status); break; } - + if (ch == LF) { UPDATE_STATE(s_header_field_start); CALLBACK_DATA(status); break; } - + break; - + case s_res_line_almost_done: STRICT_CHECK(ch != LF); UPDATE_STATE(s_header_field_start); break; - - case s_start_req: - { + + case s_start_req: { if (ch == CR || ch == LF) break; - parser->flags = 0; + parser->flags = 0; parser->content_length = ULLONG_MAX; - + if (UNLIKELY(!IS_ALPHA(ch))) { SET_ERRNO(HPE_INVALID_METHOD); goto error; } - - parser->method = (enum http_method) 0; - parser->index = 1; + + parser->method = (enum http_method)0; + parser->index = 1; switch (ch) { - case 'C': parser->method = HTTP_CONNECT; /* or COPY, CHECKOUT */ break; - case 'D': parser->method = HTTP_DELETE; break; - case 'G': parser->method = HTTP_GET; break; - case 'H': parser->method = HTTP_HEAD; break; - case 'L': parser->method = HTTP_LOCK; break; - case 'M': parser->method = HTTP_MKCOL; /* or MOVE, MKACTIVITY, MERGE, M-SEARCH, MKCALENDAR */ break; - case 'N': parser->method = HTTP_NOTIFY; break; - case 'O': parser->method = HTTP_OPTIONS; break; - case 'P': parser->method = HTTP_POST; + case 'C': + parser->method = HTTP_CONNECT; /* or COPY, CHECKOUT */ + break; + case 'D': + parser->method = HTTP_DELETE; + break; + case 'G': + parser->method = HTTP_GET; + break; + case 'H': + parser->method = HTTP_HEAD; + break; + case 'L': + parser->method = HTTP_LOCK; + break; + case 'M': + parser->method = HTTP_MKCOL; /* or MOVE, MKACTIVITY, MERGE, M-SEARCH, MKCALENDAR */ + break; + case 'N': + parser->method = HTTP_NOTIFY; + break; + case 'O': + parser->method = HTTP_OPTIONS; + break; + case 'P': + parser->method = HTTP_POST; /* or PROPFIND|PROPPATCH|PUT|PATCH|PURGE */ break; - case 'R': parser->method = HTTP_REPORT; break; - case 'S': parser->method = HTTP_SUBSCRIBE; /* or SEARCH */ break; - case 'T': parser->method = HTTP_TRACE; break; - case 'U': parser->method = HTTP_UNLOCK; /* or UNSUBSCRIBE */ break; + case 'R': + parser->method = HTTP_REPORT; + break; + case 'S': + parser->method = HTTP_SUBSCRIBE; /* or SEARCH */ + break; + case 'T': + parser->method = HTTP_TRACE; + break; + case 'U': + parser->method = HTTP_UNLOCK; /* or UNSUBSCRIBE */ + break; default: SET_ERRNO(HPE_INVALID_METHOD); goto error; } UPDATE_STATE(s_req_method); - + CALLBACK_NOTIFY(message_begin); - + break; } - - case s_req_method: - { + + case s_req_method: { const char *matcher; if (UNLIKELY(ch == '\0')) { SET_ERRNO(HPE_INVALID_METHOD); goto error; } - + matcher = method_strings[parser->method]; if (ch == ' ' && matcher[parser->index] == '\0') { UPDATE_STATE(s_req_spaces_before_url); @@ -999,7 +1107,7 @@ size_t http_parser_execute (http_parser *parser, } else if (parser->method == HTTP_CONNECT) { if (parser->index == 1 && ch == 'H') { parser->method = HTTP_CHECKOUT; - } else if (parser->index == 2 && ch == 'P') { + } else if (parser->index == 2 && ch == 'P') { parser->method = HTTP_COPY; } else { SET_ERRNO(HPE_INVALID_METHOD); @@ -1063,34 +1171,33 @@ size_t http_parser_execute (http_parser *parser, SET_ERRNO(HPE_INVALID_METHOD); goto error; } - + ++parser->index; break; } - - case s_req_spaces_before_url: - { - if (ch == ' ') break; - + + case s_req_spaces_before_url: { + if (ch == ' ') + break; + MARK(url); if (parser->method == HTTP_CONNECT) { UPDATE_STATE(s_req_server_start); } - + UPDATE_STATE(parse_url_char(CURRENT_STATE(), ch)); if (UNLIKELY(CURRENT_STATE() == s_dead)) { SET_ERRNO(HPE_INVALID_URL); goto error; } - + break; } - + case s_req_schema: case s_req_schema_slash: case s_req_schema_slash_slash: - case s_req_server_start: - { + case s_req_server_start: { switch (ch) { /* No whitespace allowed here */ case ' ': @@ -1105,18 +1212,17 @@ size_t http_parser_execute (http_parser *parser, goto error; } } - + break; } - + case s_req_server: case s_req_server_with_at: case s_req_path: case s_req_query_string_start: case s_req_query_string: case s_req_fragment_start: - case s_req_fragment: - { + case s_req_fragment: { switch (ch) { case ' ': UPDATE_STATE(s_req_http_start); @@ -1126,9 +1232,7 @@ size_t http_parser_execute (http_parser *parser, case LF: parser->http_major = 0; parser->http_minor = 9; - UPDATE_STATE((ch == CR) ? - s_req_line_almost_done : - s_header_field_start); + UPDATE_STATE((ch == CR) ? s_req_line_almost_done : s_header_field_start); CALLBACK_DATA(url); break; default: @@ -1140,7 +1244,7 @@ size_t http_parser_execute (http_parser *parser, } break; } - + case s_req_http_start: switch (ch) { case 'H': @@ -1153,190 +1257,185 @@ size_t http_parser_execute (http_parser *parser, goto error; } break; - + case s_req_http_H: STRICT_CHECK(ch != 'T'); UPDATE_STATE(s_req_http_HT); break; - + case s_req_http_HT: STRICT_CHECK(ch != 'T'); UPDATE_STATE(s_req_http_HTT); break; - + case s_req_http_HTT: STRICT_CHECK(ch != 'P'); UPDATE_STATE(s_req_http_HTTP); break; - + case s_req_http_HTTP: STRICT_CHECK(ch != '/'); UPDATE_STATE(s_req_first_http_major); break; - + /* first digit of major HTTP version */ case s_req_first_http_major: if (UNLIKELY(ch < '1' || ch > '9')) { SET_ERRNO(HPE_INVALID_VERSION); goto error; } - + parser->http_major = ch - '0'; UPDATE_STATE(s_req_http_major); break; - + /* major HTTP version or dot */ - case s_req_http_major: - { + case s_req_http_major: { if (ch == '.') { UPDATE_STATE(s_req_first_http_minor); break; } - + if (UNLIKELY(!IS_NUM(ch))) { SET_ERRNO(HPE_INVALID_VERSION); goto error; } - + parser->http_major *= 10; parser->http_major += ch - '0'; - + if (UNLIKELY(parser->http_major > 999)) { SET_ERRNO(HPE_INVALID_VERSION); goto error; } - + break; } - + /* first digit of minor HTTP version */ case s_req_first_http_minor: if (UNLIKELY(!IS_NUM(ch))) { SET_ERRNO(HPE_INVALID_VERSION); goto error; } - + parser->http_minor = ch - '0'; UPDATE_STATE(s_req_http_minor); break; - + /* minor HTTP version or end of request line */ - case s_req_http_minor: - { + case s_req_http_minor: { if (ch == CR) { UPDATE_STATE(s_req_line_almost_done); break; } - + if (ch == LF) { UPDATE_STATE(s_header_field_start); break; } - + /* XXX allow spaces after digit? */ - + if (UNLIKELY(!IS_NUM(ch))) { SET_ERRNO(HPE_INVALID_VERSION); goto error; } - + parser->http_minor *= 10; parser->http_minor += ch - '0'; - + if (UNLIKELY(parser->http_minor > 999)) { SET_ERRNO(HPE_INVALID_VERSION); goto error; } - + break; } - + /* end of request line */ - case s_req_line_almost_done: - { + case s_req_line_almost_done: { if (UNLIKELY(ch != LF)) { SET_ERRNO(HPE_LF_EXPECTED); goto error; } - + UPDATE_STATE(s_header_field_start); break; } - - case s_header_field_start: - { + + case s_header_field_start: { if (ch == CR) { UPDATE_STATE(s_headers_almost_done); break; } - + if (ch == LF) { /* they might be just sending \n instead of \r\n so this would be * the second \n to denote the end of headers*/ UPDATE_STATE(s_headers_almost_done); REEXECUTE(); } - + c = TOKEN(ch); - + if (UNLIKELY(!c)) { SET_ERRNO(HPE_INVALID_HEADER_TOKEN); goto error; } - + MARK(header_field); - + parser->index = 0; UPDATE_STATE(s_header_field); - + switch (c) { case 'c': parser->header_state = h_C; break; - + case 'p': parser->header_state = h_matching_proxy_connection; break; - + case 't': parser->header_state = h_matching_transfer_encoding; break; - + case 'u': parser->header_state = h_matching_upgrade; break; - + default: parser->header_state = h_general; break; } break; } - - case s_header_field: - { - const char* start = p; + + case s_header_field: { + const char *start = p; for (; p != data + len; p++) { ch = *p; - c = TOKEN(ch); - + c = TOKEN(ch); + if (!c) break; - + switch (parser->header_state) { case h_general: break; - + case h_C: parser->index++; parser->header_state = (c == 'o' ? h_CO : h_general); break; - + case h_CO: parser->index++; parser->header_state = (c == 'n' ? h_CON : h_general); break; - + case h_CON: parser->index++; switch (c) { @@ -1351,127 +1450,124 @@ size_t http_parser_execute (http_parser *parser, break; } break; - + /* connection */ - + case h_matching_connection: parser->index++; - if (parser->index > sizeof(CONNECTION)-1 - || c != CONNECTION[parser->index]) { + if (parser->index > sizeof(CONNECTION) - 1 || c != CONNECTION[parser->index]) { parser->header_state = h_general; - } else if (parser->index == sizeof(CONNECTION)-2) { + } else if (parser->index == sizeof(CONNECTION) - 2) { parser->header_state = h_connection; } break; - + /* proxy-connection */ - + case h_matching_proxy_connection: parser->index++; - if (parser->index > sizeof(PROXY_CONNECTION)-1 - || c != PROXY_CONNECTION[parser->index]) { + if (parser->index > sizeof(PROXY_CONNECTION) - 1 || c != PROXY_CONNECTION[parser->index]) { parser->header_state = h_general; - } else if (parser->index == sizeof(PROXY_CONNECTION)-2) { + } else if (parser->index == sizeof(PROXY_CONNECTION) - 2) { parser->header_state = h_connection; } break; - + /* content-length */ - + case h_matching_content_length: parser->index++; - if (parser->index > sizeof(CONTENT_LENGTH)-1 - || c != CONTENT_LENGTH[parser->index]) { + if (parser->index > sizeof(CONTENT_LENGTH) - 1 || c != CONTENT_LENGTH[parser->index]) { parser->header_state = h_general; - } else if (parser->index == sizeof(CONTENT_LENGTH)-2) { + } else if (parser->index == sizeof(CONTENT_LENGTH) - 2) { parser->header_state = h_content_length; } break; - + /* transfer-encoding */ - + case h_matching_transfer_encoding: parser->index++; - if (parser->index > sizeof(TRANSFER_ENCODING)-1 + if (parser->index > sizeof(TRANSFER_ENCODING) - 1 || c != TRANSFER_ENCODING[parser->index]) { parser->header_state = h_general; - } else if (parser->index == sizeof(TRANSFER_ENCODING)-2) { + } else if (parser->index == sizeof(TRANSFER_ENCODING) - 2) { parser->header_state = h_transfer_encoding; } break; - + /* upgrade */ - + case h_matching_upgrade: parser->index++; - if (parser->index > sizeof(UPGRADE)-1 - || c != UPGRADE[parser->index]) { + if (parser->index > sizeof(UPGRADE) - 1 || c != UPGRADE[parser->index]) { parser->header_state = h_general; - } else if (parser->index == sizeof(UPGRADE)-2) { + } else if (parser->index == sizeof(UPGRADE) - 2) { parser->header_state = h_upgrade; } break; - + case h_connection: case h_content_length: case h_transfer_encoding: case h_upgrade: - if (ch != ' ') parser->header_state = h_general; + if (ch != ' ') + parser->header_state = h_general; break; - + default: assert(0 && "Unknown header_state"); break; } } - + COUNT_HEADER_SIZE(p - start); - + if (p == data + len) { --p; break; } - + if (ch == ':') { UPDATE_STATE(s_header_value_discard_ws); CALLBACK_DATA(header_field); break; } - + SET_ERRNO(HPE_INVALID_HEADER_TOKEN); goto error; } - + case s_header_value_discard_ws: - if (ch == ' ' || ch == '\t') break; - + if (ch == ' ' || ch == '\t') + break; + if (ch == CR) { UPDATE_STATE(s_header_value_discard_ws_almost_done); break; } - + if (ch == LF) { UPDATE_STATE(s_header_value_discard_lws); break; } - + /* FALLTHROUGH */ - - case s_header_value_start: - { + + case s_header_value_start: { MARK(header_value); - + UPDATE_STATE(s_header_value); parser->index = 0; - + c = LOWER(ch); - + switch (parser->header_state) { case h_upgrade: parser->flags |= F_UPGRADE; parser->header_state = h_general; break; - + case h_transfer_encoding: /* looking for 'Transfer-Encoding: chunked' */ if ('c' == c) { @@ -1480,16 +1576,16 @@ size_t http_parser_execute (http_parser *parser, parser->header_state = h_general; } break; - + case h_content_length: if (UNLIKELY(!IS_NUM(ch))) { SET_ERRNO(HPE_INVALID_CONTENT_LENGTH); goto error; } - + parser->content_length = ch - '0'; break; - + case h_connection: /* looking for 'Connection: keep-alive' */ if (c == 'k') { @@ -1503,21 +1599,20 @@ size_t http_parser_execute (http_parser *parser, parser->header_state = h_matching_connection_token; } break; - + /* Multi-value `Connection` header */ case h_matching_connection_token_start: break; - + default: parser->header_state = h_general; break; } break; } - - case s_header_value: - { - const char* start = p; + + case s_header_value: { + const char *start = p; enum header_states h_state = parser->header_state; for (; p != data + len; p++) { ch = *p; @@ -1527,7 +1622,7 @@ size_t http_parser_execute (http_parser *parser, CALLBACK_DATA(header_value); break; } - + if (ch == LF) { UPDATE_STATE(s_header_almost_done); COUNT_HEADER_SIZE(p - start); @@ -1535,18 +1630,17 @@ size_t http_parser_execute (http_parser *parser, CALLBACK_DATA_NOADVANCE(header_value); REEXECUTE(); } - + c = LOWER(ch); - + switch (h_state) { - case h_general: - { - const char* p_cr; - const char* p_lf; - size_t limit = data + len - p; - + case h_general: { + const char *p_cr; + const char *p_lf; + size_t limit = data + len - p; + limit = MIN(limit, HTTP_MAX_HEADER_SIZE); - + p_cr = memchr(p, CR, limit); p_lf = memchr(p, LF, limit); if (p_cr != NULL) { @@ -1560,53 +1654,52 @@ size_t http_parser_execute (http_parser *parser, p = data + len; } --p; - + break; } - + case h_connection: case h_transfer_encoding: assert(0 && "Shouldn't get here."); break; - - case h_content_length: - { + + case h_content_length: { uint64_t t; - - if (ch == ' ') break; - + + if (ch == ' ') + break; + if (UNLIKELY(!IS_NUM(ch))) { SET_ERRNO(HPE_INVALID_CONTENT_LENGTH); parser->header_state = h_state; goto error; } - + t = parser->content_length; t *= 10; t += ch - '0'; - + /* Overflow? Test against a conservative limit for simplicity. */ if (UNLIKELY((ULLONG_MAX - 10) / 10 < parser->content_length)) { SET_ERRNO(HPE_INVALID_CONTENT_LENGTH); parser->header_state = h_state; goto error; } - + parser->content_length = t; break; } - + /* Transfer-Encoding: chunked */ case h_matching_transfer_encoding_chunked: parser->index++; - if (parser->index > sizeof(CHUNKED)-1 - || c != CHUNKED[parser->index]) { + if (parser->index > sizeof(CHUNKED) - 1 || c != CHUNKED[parser->index]) { h_state = h_general; - } else if (parser->index == sizeof(CHUNKED)-2) { + } else if (parser->index == sizeof(CHUNKED) - 2) { h_state = h_transfer_encoding_chunked; } break; - + case h_matching_connection_token_start: /* looking for 'Connection: keep-alive' */ if (c == 'k') { @@ -1622,50 +1715,49 @@ size_t http_parser_execute (http_parser *parser, h_state = h_general; } break; - + /* looking for 'Connection: keep-alive' */ case h_matching_connection_keep_alive: parser->index++; - if (parser->index > sizeof(KEEP_ALIVE)-1 - || c != KEEP_ALIVE[parser->index]) { + if (parser->index > sizeof(KEEP_ALIVE) - 1 || c != KEEP_ALIVE[parser->index]) { h_state = h_matching_connection_token; - } else if (parser->index == sizeof(KEEP_ALIVE)-2) { + } else if (parser->index == sizeof(KEEP_ALIVE) - 2) { h_state = h_connection_keep_alive; } break; - + /* looking for 'Connection: close' */ case h_matching_connection_close: parser->index++; - if (parser->index > sizeof(CLOSE)-1 || c != CLOSE[parser->index]) { + if (parser->index > sizeof(CLOSE) - 1 || c != CLOSE[parser->index]) { h_state = h_matching_connection_token; - } else if (parser->index == sizeof(CLOSE)-2) { + } else if (parser->index == sizeof(CLOSE) - 2) { h_state = h_connection_close; } break; - + /* looking for 'Connection: upgrade' */ case h_matching_connection_upgrade: parser->index++; - if (parser->index > sizeof(UPGRADE) - 1 || - c != UPGRADE[parser->index]) { + if (parser->index > sizeof(UPGRADE) - 1 || c != UPGRADE[parser->index]) { h_state = h_matching_connection_token; - } else if (parser->index == sizeof(UPGRADE)-2) { + } else if (parser->index == sizeof(UPGRADE) - 2) { h_state = h_connection_upgrade; } break; - + case h_matching_connection_token: if (ch == ',') { - h_state = h_matching_connection_token_start; + h_state = h_matching_connection_token_start; parser->index = 0; } break; - + case h_transfer_encoding_chunked: - if (ch != ' ') h_state = h_general; + if (ch != ' ') + h_state = h_general; break; - + case h_connection_keep_alive: case h_connection_close: case h_connection_upgrade: @@ -1677,13 +1769,13 @@ size_t http_parser_execute (http_parser *parser, } else if (h_state == h_connection_upgrade) { parser->flags |= F_CONNECTION_UPGRADE; } - h_state = h_matching_connection_token_start; + h_state = h_matching_connection_token_start; parser->index = 0; } else if (ch != ' ') { h_state = h_matching_connection_token; } break; - + default: UPDATE_STATE(s_header_value); h_state = h_general; @@ -1691,29 +1783,27 @@ size_t http_parser_execute (http_parser *parser, } } parser->header_state = h_state; - + COUNT_HEADER_SIZE(p - start); - + if (p == data + len) --p; break; } - - case s_header_almost_done: - { + + case s_header_almost_done: { STRICT_CHECK(ch != LF); - + UPDATE_STATE(s_header_value_lws); break; } - - case s_header_value_lws: - { + + case s_header_value_lws: { if (ch == ' ' || ch == '\t') { UPDATE_STATE(s_header_value_start); REEXECUTE(); } - + /* finished the header */ switch (parser->header_state) { case h_connection_keep_alive: @@ -1731,20 +1821,18 @@ size_t http_parser_execute (http_parser *parser, default: break; } - + UPDATE_STATE(s_header_field_start); REEXECUTE(); } - - case s_header_value_discard_ws_almost_done: - { + + case s_header_value_discard_ws_almost_done: { STRICT_CHECK(ch != LF); UPDATE_STATE(s_header_value_discard_lws); break; } - - case s_header_value_discard_lws: - { + + case s_header_value_discard_lws: { if (ch == ' ' || ch == '\t') { UPDATE_STATE(s_header_value_discard_ws); break; @@ -1765,7 +1853,7 @@ size_t http_parser_execute (http_parser *parser, default: break; } - + /* header value was empty */ MARK(header_value); UPDATE_STATE(s_header_field_start); @@ -1773,26 +1861,24 @@ size_t http_parser_execute (http_parser *parser, REEXECUTE(); } } - - case s_headers_almost_done: - { + + case s_headers_almost_done: { STRICT_CHECK(ch != LF); - + if (parser->flags & F_TRAILING) { /* End of a chunked request */ UPDATE_STATE(NEW_MESSAGE()); CALLBACK_NOTIFY(message_complete); break; } - + UPDATE_STATE(s_headers_done); - + /* Set this here so that on_headers_complete() callbacks can see it */ - parser->upgrade = - ((parser->flags & (F_UPGRADE | F_CONNECTION_UPGRADE)) == - (F_UPGRADE | F_CONNECTION_UPGRADE) || - parser->method == HTTP_CONNECT); - + parser->upgrade = ((parser->flags & (F_UPGRADE | F_CONNECTION_UPGRADE)) + == (F_UPGRADE | F_CONNECTION_UPGRADE) + || parser->method == HTTP_CONNECT); + /* Here we call the headers_complete callback. This is somewhat * different than other callbacks because if the user returns 1, we * will interpret that as saying that this message has no body. This @@ -1806,37 +1892,36 @@ size_t http_parser_execute (http_parser *parser, switch (settings->on_headers_complete(parser)) { case 0: break; - + case 1: parser->flags |= F_SKIPBODY; break; - + default: SET_ERRNO(HPE_CB_headers_complete); RETURN(p - data); /* Error */ } } - + if (HTTP_PARSER_ERRNO(parser) != HPE_OK) { RETURN(p - data); } - + REEXECUTE(); } - - case s_headers_done: - { + + case s_headers_done: { STRICT_CHECK(ch != LF); - + parser->nread = 0; - + /* Exit, the rest of the connect is in a different protocol. */ if (parser->upgrade) { UPDATE_STATE(NEW_MESSAGE()); CALLBACK_NOTIFY(message_complete); RETURN((p - data) + 1); } - + if (parser->flags & F_SKIPBODY) { UPDATE_STATE(NEW_MESSAGE()); CALLBACK_NOTIFY(message_complete); @@ -1852,8 +1937,7 @@ size_t http_parser_execute (http_parser *parser, /* Content-Length header given and non-zero */ UPDATE_STATE(s_body_identity); } else { - if (parser->type == HTTP_REQUEST || - !http_message_needs_eof(parser)) { + if (parser->type == HTTP_REQUEST || !http_message_needs_eof(parser)) { /* Assume content-length 0 - read the next */ UPDATE_STATE(NEW_MESSAGE()); CALLBACK_NOTIFY(message_complete); @@ -1863,18 +1947,15 @@ size_t http_parser_execute (http_parser *parser, } } } - + break; } - - case s_body_identity: - { - uint64_t to_read = MIN(parser->content_length, - (uint64_t) ((data + len) - p)); - - assert(parser->content_length != 0 - && parser->content_length != ULLONG_MAX); - + + case s_body_identity: { + uint64_t to_read = MIN(parser->content_length, (uint64_t)((data + len) - p)); + + assert(parser->content_length != 0 && parser->content_length != ULLONG_MAX); + /* The difference between advancing content_length and p is because * the latter will automaticaly advance on the next loop iteration. * Further, if content_length ends up at 0, we want to see the last @@ -1883,10 +1964,10 @@ size_t http_parser_execute (http_parser *parser, MARK(body); parser->content_length -= to_read; p += to_read - 1; - + if (parser->content_length == 0) { UPDATE_STATE(s_message_done); - + /* Mimic CALLBACK_DATA_NOADVANCE() but with one extra byte. * * The alternative to doing this is to wait for the next byte to @@ -1899,77 +1980,74 @@ size_t http_parser_execute (http_parser *parser, CALLBACK_DATA_(body, p - body_mark + 1, p - data); REEXECUTE(); } - + break; } - + /* read until EOF */ case s_body_identity_eof: MARK(body); p = data + len - 1; - + break; - + case s_message_done: UPDATE_STATE(NEW_MESSAGE()); CALLBACK_NOTIFY(message_complete); break; - - case s_chunk_size_start: - { + + case s_chunk_size_start: { assert(parser->nread == 1); assert(parser->flags & F_CHUNKED); - + unhex_val = unhex[(unsigned char)ch]; if (UNLIKELY(unhex_val == -1)) { SET_ERRNO(HPE_INVALID_CHUNK_SIZE); goto error; } - + parser->content_length = unhex_val; UPDATE_STATE(s_chunk_size); break; } - - case s_chunk_size: - { + + case s_chunk_size: { uint64_t t; - + assert(parser->flags & F_CHUNKED); - + if (ch == CR) { UPDATE_STATE(s_chunk_size_almost_done); break; } - + unhex_val = unhex[(unsigned char)ch]; - + if (unhex_val == -1) { if (ch == ';' || ch == ' ') { UPDATE_STATE(s_chunk_parameters); break; } - + SET_ERRNO(HPE_INVALID_CHUNK_SIZE); goto error; } - + t = parser->content_length; t *= 16; t += unhex_val; - + /* Overflow? Test against a conservative limit for simplicity. */ if (UNLIKELY((ULLONG_MAX - 16) / 16 < parser->content_length)) { SET_ERRNO(HPE_INVALID_CONTENT_LENGTH); goto error; } - + parser->content_length = t; break; } - - case s_chunk_parameters: - { + + case s_chunk_parameters: { assert(parser->flags & F_CHUNKED); /* just ignore this shit. TODO check for overflow */ if (ch == CR) { @@ -1978,14 +2056,13 @@ size_t http_parser_execute (http_parser *parser, } break; } - - case s_chunk_size_almost_done: - { + + case s_chunk_size_almost_done: { assert(parser->flags & F_CHUNKED); STRICT_CHECK(ch != LF); - + parser->nread = 0; - + if (parser->content_length == 0) { parser->flags |= F_TRAILING; UPDATE_STATE(s_header_field_start); @@ -1994,30 +2071,27 @@ size_t http_parser_execute (http_parser *parser, } break; } - - case s_chunk_data: - { - uint64_t to_read = MIN(parser->content_length, - (uint64_t) ((data + len) - p)); - + + case s_chunk_data: { + uint64_t to_read = MIN(parser->content_length, (uint64_t)((data + len) - p)); + assert(parser->flags & F_CHUNKED); - assert(parser->content_length != 0 - && parser->content_length != ULLONG_MAX); - + assert(parser->content_length != 0 && parser->content_length != ULLONG_MAX); + /* See the explanation in s_body_identity for why the content * length and data pointers are managed this way. */ MARK(body); parser->content_length -= to_read; p += to_read - 1; - + if (parser->content_length == 0) { UPDATE_STATE(s_chunk_data_almost_done); } - + break; } - + case s_chunk_data_almost_done: assert(parser->flags & F_CHUNKED); assert(parser->content_length == 0); @@ -2025,21 +2099,21 @@ size_t http_parser_execute (http_parser *parser, UPDATE_STATE(s_chunk_data_done); CALLBACK_DATA(body); break; - + case s_chunk_data_done: assert(parser->flags & F_CHUNKED); STRICT_CHECK(ch != LF); parser->nread = 0; UPDATE_STATE(s_chunk_size_start); break; - + default: assert(0 && "unhandled state"); SET_ERRNO(HPE_INVALID_INTERNAL_STATE); goto error; } } - + /* Run callbacks for any marks that we have leftover after we ran our of * bytes. There should be at most one of these set, so it's OK to invoke * them in series (unset marks will not result in callbacks). @@ -2049,38 +2123,33 @@ size_t http_parser_execute (http_parser *parser, * we'd otherwise have (since CALLBACK_DATA() is meant to be run with a 'p' * value that's in-bounds). */ - - assert(((header_field_mark ? 1 : 0) + - (header_value_mark ? 1 : 0) + - (url_mark ? 1 : 0) + - (body_mark ? 1 : 0) + - (status_mark ? 1 : 0)) <= 1); - + + assert(((header_field_mark ? 1 : 0) + (header_value_mark ? 1 : 0) + (url_mark ? 1 : 0) + (body_mark ? 1 : 0) + + (status_mark ? 1 : 0)) + <= 1); + CALLBACK_DATA_NOADVANCE(header_field); CALLBACK_DATA_NOADVANCE(header_value); CALLBACK_DATA_NOADVANCE(url); CALLBACK_DATA_NOADVANCE(body); CALLBACK_DATA_NOADVANCE(status); - + RETURN(len); - + error: if (HTTP_PARSER_ERRNO(parser) == HPE_OK) { SET_ERRNO(HPE_UNKNOWN); } - + RETURN(p - data); } - /* Does the parser need to see an EOF to find the end of the message? */ -int -http_message_needs_eof (const http_parser *parser) -{ +int http_message_needs_eof(const http_parser *parser) { if (parser->type == HTTP_REQUEST) { return 0; } - + /* See RFC 2616 section 4.4 */ if (parser->status_code / 100 == 1 || /* 1xx e.g. Continue */ parser->status_code == 204 || /* No Content */ @@ -2088,18 +2157,15 @@ http_message_needs_eof (const http_parser *parser) parser->flags & F_SKIPBODY) { /* response to a HEAD request */ return 0; } - + if ((parser->flags & F_CHUNKED) || parser->content_length != ULLONG_MAX) { return 0; } - + return 1; } - -int -http_should_keep_alive (const http_parser *parser) -{ +int http_should_keep_alive(const http_parser *parser) { if (parser->http_major > 0 && parser->http_minor > 0) { /* HTTP/1.1 */ if (parser->flags & F_CONNECTION_CLOSE) { @@ -2111,139 +2177,129 @@ http_should_keep_alive (const http_parser *parser) return 0; } } - + return !http_message_needs_eof(parser); } - -const char * -http_method_str (enum http_method m) -{ +const char *http_method_str(enum http_method m) { return ELEM_AT(method_strings, m, ""); } - -void -http_parser_init (http_parser *parser, enum http_parser_type t) -{ +void http_parser_init(http_parser *parser, enum http_parser_type t) { void *data = parser->data; /* preserve application data */ memset(parser, 0, sizeof(*parser)); - parser->data = data; - parser->type = t; - parser->state = (t == HTTP_REQUEST ? s_start_req : (t == HTTP_RESPONSE ? s_start_res : s_start_req_or_res)); + parser->data = data; + parser->type = t; + parser->state = (t == HTTP_REQUEST ? s_start_req : (t == HTTP_RESPONSE ? s_start_res : s_start_req_or_res)); parser->http_errno = HPE_OK; } -const char * -http_errno_name(enum http_errno err) { - assert(err < (sizeof(http_strerror_tab)/sizeof(http_strerror_tab[0]))); +const char *http_errno_name(enum http_errno err) { + assert(err < (sizeof(http_strerror_tab) / sizeof(http_strerror_tab[0]))); return http_strerror_tab[err].name; } -const char * -http_errno_description(enum http_errno err) { - assert(err < (sizeof(http_strerror_tab)/sizeof(http_strerror_tab[0]))); +const char *http_errno_description(enum http_errno err) { + assert(err < (sizeof(http_strerror_tab) / sizeof(http_strerror_tab[0]))); return http_strerror_tab[err].description; } -static enum http_host_state -http_parse_host_char(enum http_host_state s, const char ch) { - switch(s) { +static enum http_host_state http_parse_host_char(enum http_host_state s, const char ch) { + switch (s) { case s_http_userinfo: case s_http_userinfo_start: if (ch == '@') { return s_http_host_start; } - + if (IS_USERINFO_CHAR(ch)) { return s_http_userinfo; } break; - + case s_http_host_start: if (ch == '[') { return s_http_host_v6_start; } - + if (IS_HOST_CHAR(ch)) { return s_http_host; } - + break; - + case s_http_host: if (IS_HOST_CHAR(ch)) { return s_http_host; } - + /* FALLTHROUGH */ case s_http_host_v6_end: if (ch == ':') { return s_http_host_port_start; } - + break; - + case s_http_host_v6: if (ch == ']') { return s_http_host_v6_end; } - + /* FALLTHROUGH */ case s_http_host_v6_start: if (IS_HEX(ch) || ch == ':' || ch == '.') { return s_http_host_v6; } - + break; - + case s_http_host_port: case s_http_host_port_start: if (IS_NUM(ch)) { return s_http_host_port; } - + break; - + default: break; } return s_http_host_dead; } -static int -http_parse_host(const char * buf, struct http_parser_url *u, int found_at) { +static int http_parse_host(const char *buf, struct http_parser_url *u, int found_at) { enum http_host_state s; - + const char *p; - size_t buflen = u->field_data[UF_HOST].off + u->field_data[UF_HOST].len; - + size_t buflen = u->field_data[UF_HOST].off + u->field_data[UF_HOST].len; + u->field_data[UF_HOST].len = 0; - + s = found_at ? s_http_userinfo_start : s_http_host_start; - + for (p = buf + u->field_data[UF_HOST].off; p < buf + buflen; p++) { enum http_host_state new_s = http_parse_host_char(s, *p); - + if (new_s == s_http_host_dead) { return 1; } - - switch(new_s) { + + switch (new_s) { case s_http_host: if (s != s_http_host) { u->field_data[UF_HOST].off = p - buf; } u->field_data[UF_HOST].len++; break; - + case s_http_host_v6: if (s != s_http_host_v6) { u->field_data[UF_HOST].off = p - buf; } u->field_data[UF_HOST].len++; break; - + case s_http_host_port: if (s != s_http_host_port) { u->field_data[UF_PORT].off = p - buf; @@ -2252,22 +2308,22 @@ http_parse_host(const char * buf, struct http_parser_url *u, int found_at) { } u->field_data[UF_PORT].len++; break; - + case s_http_userinfo: if (s != s_http_userinfo) { - u->field_data[UF_USERINFO].off = p - buf ; + u->field_data[UF_USERINFO].off = p - buf; u->field_data[UF_USERINFO].len = 0; u->field_set |= (1 << UF_USERINFO); } u->field_data[UF_USERINFO].len++; break; - + default: break; } s = new_s; } - + /* Make sure we don't end somewhere unexpected */ switch (s) { case s_http_host_start: @@ -2280,31 +2336,28 @@ http_parse_host(const char * buf, struct http_parser_url *u, int found_at) { default: break; } - + return 0; } -int -http_parser_parse_url(const char *buf, size_t buflen, int is_connect, - struct http_parser_url *u) -{ - enum state s; - const char *p; +int http_parser_parse_url(const char *buf, size_t buflen, int is_connect, struct http_parser_url *u) { + enum state s; + const char *p; enum http_parser_url_fields uf, old_uf; - int found_at = 0; - + int found_at = 0; + u->port = u->field_set = 0; - s = is_connect ? s_req_server_start : s_req_spaces_before_url; - old_uf = UF_MAX; - + s = is_connect ? s_req_server_start : s_req_spaces_before_url; + old_uf = UF_MAX; + for (p = buf; p < buf + buflen; p++) { s = parse_url_char(s, *p); - + /* Figure out the next field that we're operating on */ switch (s) { case s_dead: return 1; - + /* Skip delimeters */ case s_req_schema_slash: case s_req_schema_slash_slash: @@ -2312,49 +2365,49 @@ http_parser_parse_url(const char *buf, size_t buflen, int is_connect, case s_req_query_string_start: case s_req_fragment_start: continue; - + case s_req_schema: uf = UF_SCHEMA; break; - + case s_req_server_with_at: found_at = 1; - + /* FALLTROUGH */ case s_req_server: uf = UF_HOST; break; - + case s_req_path: uf = UF_PATH; break; - + case s_req_query_string: uf = UF_QUERY; break; - + case s_req_fragment: uf = UF_FRAGMENT; break; - + default: assert(!"Unexpected state"); return 1; } - + /* Nothing's changed; soldier on */ if (uf == old_uf) { u->field_data[uf].len++; continue; } - + u->field_data[uf].off = p - buf; u->field_data[uf].len = 1; - + u->field_set |= (1 << uf); old_uf = uf; } - + /* host must be present if there is a schema */ /* parsing http:///toto will fail */ if ((u->field_set & ((1 << UF_SCHEMA) | (1 << UF_HOST))) != 0) { @@ -2362,49 +2415,44 @@ http_parser_parse_url(const char *buf, size_t buflen, int is_connect, return 1; } } - + /* CONNECT requests can only contain "hostname:port" */ - if (is_connect && u->field_set != ((1 << UF_HOST)|(1 << UF_PORT))) { + if (is_connect && u->field_set != ((1 << UF_HOST) | (1 << UF_PORT))) { return 1; } - + if (u->field_set & (1 << UF_PORT)) { /* Don't bother with endp; we've already validated the string */ unsigned long v = strtoul(buf + u->field_data[UF_PORT].off, NULL, 10); - + /* Ports have a max value of 2^16 */ if (v > 0xffff) { return 1; } - - u->port = (uint16_t) v; + + u->port = (uint16_t)v; } - + return 0; } -void -http_parser_pause(http_parser *parser, int paused) { +void http_parser_pause(http_parser *parser, int paused) { /* Users should only be pausing/unpausing a parser that is not in an error * state. In non-debug builds, there's not much that we can do about this * other than ignore it. */ - if (HTTP_PARSER_ERRNO(parser) == HPE_OK || - HTTP_PARSER_ERRNO(parser) == HPE_PAUSED) { + if (HTTP_PARSER_ERRNO(parser) == HPE_OK || HTTP_PARSER_ERRNO(parser) == HPE_PAUSED) { SET_ERRNO((paused) ? HPE_PAUSED : HPE_OK); } else { assert(0 && "Attempting to pause parser in error state"); } } -int -http_body_is_final(const struct http_parser *parser) { +int http_body_is_final(const struct http_parser *parser) { return parser->state == s_message_done; } -unsigned long -http_parser_version(void) { - return HTTP_PARSER_VERSION_MAJOR * 0x10000 | - HTTP_PARSER_VERSION_MINOR * 0x00100 | - HTTP_PARSER_VERSION_PATCH * 0x00001; +unsigned long http_parser_version(void) { + return HTTP_PARSER_VERSION_MAJOR * 0x10000 | HTTP_PARSER_VERSION_MINOR * 0x00100 + | HTTP_PARSER_VERSION_PATCH * 0x00001; } \ No newline at end of file diff --git a/srcs/httpserver/src/haywire/http_parser.h b/srcs/httpserver/src/haywire/http_parser.h index d8289ff..346d2f4 100644 --- a/srcs/httpserver/src/haywire/http_parser.h +++ b/srcs/httpserver/src/haywire/http_parser.h @@ -23,36 +23,36 @@ #ifdef __cplusplus extern "C" { #endif - - /* Also update SONAME in the Makefile whenever you change these. */ + +/* Also update SONAME in the Makefile whenever you change these. */ #define HTTP_PARSER_VERSION_MAJOR 2 #define HTTP_PARSER_VERSION_MINOR 3 #define HTTP_PARSER_VERSION_PATCH 0 - + #include -#if defined(_WIN32) && !defined(__MINGW32__) && (!defined(_MSC_VER) || _MSC_VER<1600) +#if defined(_WIN32) && !defined(__MINGW32__) && (!defined(_MSC_VER) || _MSC_VER < 1600) #include #include - typedef __int8 int8_t; - typedef unsigned __int8 uint8_t; - typedef __int16 int16_t; - typedef unsigned __int16 uint16_t; - typedef __int32 int32_t; - typedef unsigned __int32 uint32_t; - typedef __int64 int64_t; - typedef unsigned __int64 uint64_t; +typedef __int8 int8_t; +typedef unsigned __int8 uint8_t; +typedef __int16 int16_t; +typedef unsigned __int16 uint16_t; +typedef __int32 int32_t; +typedef unsigned __int32 uint32_t; +typedef __int64 int64_t; +typedef unsigned __int64 uint64_t; #else #include #endif - - /* Compile with -DHTTP_PARSER_STRICT=0 to make less checks, but run + +/* Compile with -DHTTP_PARSER_STRICT=0 to make less checks, but run * faster */ #ifndef HTTP_PARSER_STRICT -# define HTTP_PARSER_STRICT 1 +#define HTTP_PARSER_STRICT 1 #endif - - /* Maximium header size allowed. If the macro is not defined + +/* Maximium header size allowed. If the macro is not defined * before including this header then the default is used. To * change the maximum header size, define the macro in the build * environment (e.g. -DHTTP_MAX_HEADER_SIZE=). To remove @@ -60,14 +60,13 @@ extern "C" { * to a very large number (e.g. -DHTTP_MAX_HEADER_SIZE=0x7fffffff) */ #ifndef HTTP_MAX_HEADER_SIZE -# define HTTP_MAX_HEADER_SIZE (80*1024) +#define HTTP_MAX_HEADER_SIZE (80 * 1024) #endif - - typedef struct http_parser http_parser; - typedef struct http_parser_settings http_parser_settings; - - - /* Callbacks should return non-zero to indicate an error. The parser will + +typedef struct http_parser http_parser; +typedef struct http_parser_settings http_parser_settings; + +/* Callbacks should return non-zero to indicate an error. The parser will * then halt execution. * * The one exception is on_headers_complete. In a HTTP_RESPONSE parser @@ -80,199 +79,188 @@ extern "C" { * many times for each string. E.G. you might get 10 callbacks for "on_url" * each providing just a few characters more data. */ - typedef int (*http_data_cb) (http_parser*, const char *at, size_t length); - typedef int (*http_cb) (http_parser*); +typedef int (*http_data_cb)(http_parser *, const char *at, size_t length); +typedef int (*http_cb)(http_parser *); - /* Request Methods */ -#define HTTP_METHOD_MAP(XX) \ -XX(0, DELETE, DELETE) \ -XX(1, GET, GET) \ -XX(2, HEAD, HEAD) \ -XX(3, POST, POST) \ -XX(4, PUT, PUT) \ -/* pathological */ \ -XX(5, CONNECT, CONNECT) \ -XX(6, OPTIONS, OPTIONS) \ -XX(7, TRACE, TRACE) \ -/* webdav */ \ -XX(8, COPY, COPY) \ -XX(9, LOCK, LOCK) \ -XX(10, MKCOL, MKCOL) \ -XX(11, MOVE, MOVE) \ -XX(12, PROPFIND, PROPFIND) \ -XX(13, PROPPATCH, PROPPATCH) \ -XX(14, SEARCH, SEARCH) \ -XX(15, UNLOCK, UNLOCK) \ -/* subversion */ \ -XX(16, REPORT, REPORT) \ -XX(17, MKACTIVITY, MKACTIVITY) \ -XX(18, CHECKOUT, CHECKOUT) \ -XX(19, MERGE, MERGE) \ -/* upnp */ \ -XX(20, MSEARCH, M-SEARCH) \ -XX(21, NOTIFY, NOTIFY) \ -XX(22, SUBSCRIBE, SUBSCRIBE) \ -XX(23, UNSUBSCRIBE, UNSUBSCRIBE) \ -/* RFC-5789 */ \ -XX(24, PATCH, PATCH) \ -XX(25, PURGE, PURGE) \ -/* CalDAV */ \ -XX(26, MKCALENDAR, MKCALENDAR) \ +/* Request Methods */ +#define HTTP_METHOD_MAP(XX) \ + XX(0, DELETE, DELETE) \ + XX(1, GET, GET) \ + XX(2, HEAD, HEAD) \ + XX(3, POST, POST) \ + XX(4, PUT, PUT) \ + /* pathological */ \ + XX(5, CONNECT, CONNECT) \ + XX(6, OPTIONS, OPTIONS) \ + XX(7, TRACE, TRACE) \ + /* webdav */ \ + XX(8, COPY, COPY) \ + XX(9, LOCK, LOCK) \ + XX(10, MKCOL, MKCOL) \ + XX(11, MOVE, MOVE) \ + XX(12, PROPFIND, PROPFIND) \ + XX(13, PROPPATCH, PROPPATCH) \ + XX(14, SEARCH, SEARCH) \ + XX(15, UNLOCK, UNLOCK) \ + /* subversion */ \ + XX(16, REPORT, REPORT) \ + XX(17, MKACTIVITY, MKACTIVITY) \ + XX(18, CHECKOUT, CHECKOUT) \ + XX(19, MERGE, MERGE) \ + /* upnp */ \ + XX(20, MSEARCH, M - SEARCH) \ + XX(21, NOTIFY, NOTIFY) \ + XX(22, SUBSCRIBE, SUBSCRIBE) \ + XX(23, UNSUBSCRIBE, UNSUBSCRIBE) \ + /* RFC-5789 */ \ + XX(24, PATCH, PATCH) \ + XX(25, PURGE, PURGE) \ + /* CalDAV */ \ + XX(26, MKCALENDAR, MKCALENDAR) - enum http_method - { +enum http_method { #define XX(num, name, string) HTTP_##name = num, - HTTP_METHOD_MAP(XX) + HTTP_METHOD_MAP(XX) #undef XX - }; - - - enum http_parser_type { HTTP_REQUEST, HTTP_RESPONSE, HTTP_BOTH }; - - - /* Flag values for http_parser.flags field */ - enum flags - { F_CHUNKED = 1 << 0 - , F_CONNECTION_KEEP_ALIVE = 1 << 1 - , F_CONNECTION_CLOSE = 1 << 2 - , F_CONNECTION_UPGRADE = 1 << 3 - , F_TRAILING = 1 << 4 - , F_UPGRADE = 1 << 5 - , F_SKIPBODY = 1 << 6 - }; - - - /* Map for errno-related constants +}; + +enum http_parser_type { + HTTP_REQUEST, + HTTP_RESPONSE, + HTTP_BOTH +}; + +/* Flag values for http_parser.flags field */ +enum flags { + F_CHUNKED = 1 << 0, + F_CONNECTION_KEEP_ALIVE = 1 << 1, + F_CONNECTION_CLOSE = 1 << 2, + F_CONNECTION_UPGRADE = 1 << 3, + F_TRAILING = 1 << 4, + F_UPGRADE = 1 << 5, + F_SKIPBODY = 1 << 6 +}; + +/* Map for errno-related constants * * The provided argument should be a macro that takes 2 arguments. */ -#define HTTP_ERRNO_MAP(XX) \ -/* No error */ \ -XX(OK, "success") \ -\ -/* Callback-related errors */ \ -XX(CB_message_begin, "the on_message_begin callback failed") \ -XX(CB_url, "the on_url callback failed") \ -XX(CB_header_field, "the on_header_field callback failed") \ -XX(CB_header_value, "the on_header_value callback failed") \ -XX(CB_headers_complete, "the on_headers_complete callback failed") \ -XX(CB_body, "the on_body callback failed") \ -XX(CB_message_complete, "the on_message_complete callback failed") \ -XX(CB_status, "the on_status callback failed") \ -\ -/* Parsing-related errors */ \ -XX(INVALID_EOF_STATE, "stream ended at an unexpected time") \ -XX(HEADER_OVERFLOW, \ -"too many header bytes seen; overflow detected") \ -XX(CLOSED_CONNECTION, \ -"data received after completed connection: close message") \ -XX(INVALID_VERSION, "invalid HTTP version") \ -XX(INVALID_STATUS, "invalid HTTP status code") \ -XX(INVALID_METHOD, "invalid HTTP method") \ -XX(INVALID_URL, "invalid URL") \ -XX(INVALID_HOST, "invalid host") \ -XX(INVALID_PORT, "invalid port") \ -XX(INVALID_PATH, "invalid path") \ -XX(INVALID_QUERY_STRING, "invalid query string") \ -XX(INVALID_FRAGMENT, "invalid fragment") \ -XX(LF_EXPECTED, "LF character expected") \ -XX(INVALID_HEADER_TOKEN, "invalid character in header") \ -XX(INVALID_CONTENT_LENGTH, \ -"invalid character in content-length header") \ -XX(INVALID_CHUNK_SIZE, \ -"invalid character in chunk size header") \ -XX(INVALID_CONSTANT, "invalid constant string") \ -XX(INVALID_INTERNAL_STATE, "encountered unexpected internal state")\ -XX(STRICT, "strict mode assertion failed") \ -XX(PAUSED, "parser is paused") \ -XX(UNKNOWN, "an unknown error occurred") - - - /* Define HPE_* values for each errno value above */ +#define HTTP_ERRNO_MAP(XX) \ + /* No error */ \ + XX(OK, "success") \ + \ + /* Callback-related errors */ \ + XX(CB_message_begin, "the on_message_begin callback failed") \ + XX(CB_url, "the on_url callback failed") \ + XX(CB_header_field, "the on_header_field callback failed") \ + XX(CB_header_value, "the on_header_value callback failed") \ + XX(CB_headers_complete, "the on_headers_complete callback failed") \ + XX(CB_body, "the on_body callback failed") \ + XX(CB_message_complete, "the on_message_complete callback failed") \ + XX(CB_status, "the on_status callback failed") \ + \ + /* Parsing-related errors */ \ + XX(INVALID_EOF_STATE, "stream ended at an unexpected time") \ + XX(HEADER_OVERFLOW, "too many header bytes seen; overflow detected") \ + XX(CLOSED_CONNECTION, "data received after completed connection: close message") \ + XX(INVALID_VERSION, "invalid HTTP version") \ + XX(INVALID_STATUS, "invalid HTTP status code") \ + XX(INVALID_METHOD, "invalid HTTP method") \ + XX(INVALID_URL, "invalid URL") \ + XX(INVALID_HOST, "invalid host") \ + XX(INVALID_PORT, "invalid port") \ + XX(INVALID_PATH, "invalid path") \ + XX(INVALID_QUERY_STRING, "invalid query string") \ + XX(INVALID_FRAGMENT, "invalid fragment") \ + XX(LF_EXPECTED, "LF character expected") \ + XX(INVALID_HEADER_TOKEN, "invalid character in header") \ + XX(INVALID_CONTENT_LENGTH, "invalid character in content-length header") \ + XX(INVALID_CHUNK_SIZE, "invalid character in chunk size header") \ + XX(INVALID_CONSTANT, "invalid constant string") \ + XX(INVALID_INTERNAL_STATE, "encountered unexpected internal state") \ + XX(STRICT, "strict mode assertion failed") \ + XX(PAUSED, "parser is paused") \ + XX(UNKNOWN, "an unknown error occurred") + +/* Define HPE_* values for each errno value above */ #define HTTP_ERRNO_GEN(n, s) HPE_##n, - enum http_errno { - HTTP_ERRNO_MAP(HTTP_ERRNO_GEN) - }; +enum http_errno { + HTTP_ERRNO_MAP(HTTP_ERRNO_GEN) +}; #undef HTTP_ERRNO_GEN - - - /* Get an http_errno value from an http_parser */ -#define HTTP_PARSER_ERRNO(p) ((enum http_errno) (p)->http_errno) - - - struct http_parser { - /** PRIVATE **/ - unsigned int type : 2; /* enum http_parser_type */ - unsigned int flags : 6; /* F_* values from 'flags' enum; semi-public */ - unsigned int state : 8; /* enum state from http_parser.c */ - unsigned int header_state : 8; /* enum header_state from http_parser.c */ - unsigned int index : 8; /* index into current matcher */ - - uint32_t nread; /* # bytes read in various scenarios */ - uint64_t content_length; /* # bytes in body (0 if no Content-Length header) */ - - /** READ-ONLY **/ - unsigned short http_major; - unsigned short http_minor; - unsigned int status_code : 16; /* responses only */ - unsigned int method : 8; /* requests only */ - unsigned int http_errno : 7; - - /* 1 = Upgrade header was present and the parser has exited because of that. + +/* Get an http_errno value from an http_parser */ +#define HTTP_PARSER_ERRNO(p) ((enum http_errno)(p)->http_errno) + +struct http_parser { + /** PRIVATE **/ + unsigned int type : 2; /* enum http_parser_type */ + unsigned int flags : 6; /* F_* values from 'flags' enum; semi-public */ + unsigned int state : 8; /* enum state from http_parser.c */ + unsigned int header_state : 8; /* enum header_state from http_parser.c */ + unsigned int index : 8; /* index into current matcher */ + + uint32_t nread; /* # bytes read in various scenarios */ + uint64_t content_length; /* # bytes in body (0 if no Content-Length header) */ + + /** READ-ONLY **/ + unsigned short http_major; + unsigned short http_minor; + unsigned int status_code : 16; /* responses only */ + unsigned int method : 8; /* requests only */ + unsigned int http_errno : 7; + + /* 1 = Upgrade header was present and the parser has exited because of that. * 0 = No upgrade header present. * Should be checked when http_parser_execute() returns in addition to * error checking. */ - unsigned int upgrade : 1; - - /** PUBLIC **/ - void *data; /* A pointer to get hook to the "connection" or "socket" object */ - }; - - - struct http_parser_settings { - http_cb on_message_begin; - http_data_cb on_url; - http_data_cb on_status; - http_data_cb on_header_field; - http_data_cb on_header_value; - http_cb on_headers_complete; - http_data_cb on_body; - http_cb on_message_complete; - }; - - - enum http_parser_url_fields - { UF_SCHEMA = 0 - , UF_HOST = 1 - , UF_PORT = 2 - , UF_PATH = 3 - , UF_QUERY = 4 - , UF_FRAGMENT = 5 - , UF_USERINFO = 6 - , UF_MAX = 7 - }; - - - /* Result structure for http_parser_parse_url(). + unsigned int upgrade : 1; + + /** PUBLIC **/ + void *data; /* A pointer to get hook to the "connection" or "socket" object */ +}; + +struct http_parser_settings { + http_cb on_message_begin; + http_data_cb on_url; + http_data_cb on_status; + http_data_cb on_header_field; + http_data_cb on_header_value; + http_cb on_headers_complete; + http_data_cb on_body; + http_cb on_message_complete; +}; + +enum http_parser_url_fields { + UF_SCHEMA = 0, + UF_HOST = 1, + UF_PORT = 2, + UF_PATH = 3, + UF_QUERY = 4, + UF_FRAGMENT = 5, + UF_USERINFO = 6, + UF_MAX = 7 +}; + +/* Result structure for http_parser_parse_url(). * * Callers should index into field_data[] with UF_* values iff field_set * has the relevant (1 << UF_*) bit set. As a courtesy to clients (and * because we probably have padding left over), we convert any port to * a uint16_t. */ - struct http_parser_url { - uint16_t field_set; /* Bitmask of (1 << UF_*) values */ - uint16_t port; /* Converted UF_PORT string */ - - struct { - uint16_t off; /* Offset into buffer in which field starts */ - uint16_t len; /* Length of run in buffer */ - } field_data[UF_MAX]; - }; - - - /* Returns the library version. Bits 16-23 contain the major version number, +struct http_parser_url { + uint16_t field_set; /* Bitmask of (1 << UF_*) values */ + uint16_t port; /* Converted UF_PORT string */ + + struct { + uint16_t off; /* Offset into buffer in which field starts */ + uint16_t len; /* Length of run in buffer */ + } field_data[UF_MAX]; +}; + +/* Returns the library version. Bits 16-23 contain the major version number, * bits 8-15 the minor version number and bits 0-7 the patch level. * Usage example: * @@ -282,47 +270,40 @@ XX(UNKNOWN, "an unknown error occurred") * unsigned patch = version & 255; * printf("http_parser v%u.%u.%u\n", major, minor, patch); */ - unsigned long http_parser_version(void); - - void http_parser_init(http_parser *parser, enum http_parser_type type); - - - /* Executes the parser. Returns number of parsed bytes. Sets +unsigned long http_parser_version(void); + +void http_parser_init(http_parser *parser, enum http_parser_type type); + +/* Executes the parser. Returns number of parsed bytes. Sets * `parser->http_errno` on error. */ - size_t http_parser_execute(http_parser *parser, - const http_parser_settings *settings, - const char *data, - size_t len); - - - /* If http_should_keep_alive() in the on_headers_complete or +size_t http_parser_execute(http_parser *parser, const http_parser_settings *settings, const char *data, size_t len); + +/* If http_should_keep_alive() in the on_headers_complete or * on_message_complete callback returns 0, then this should be * the last message on the connection. * If you are the server, respond with the "Connection: close" header. * If you are the client, close the connection. */ - int http_should_keep_alive(const http_parser *parser); - - /* Returns a string version of the HTTP method. */ - const char *http_method_str(enum http_method m); - - /* Return a string name of the given error */ - const char *http_errno_name(enum http_errno err); - - /* Return a string description of the given error */ - const char *http_errno_description(enum http_errno err); - - /* Parse a URL; return nonzero on failure */ - int http_parser_parse_url(const char *buf, size_t buflen, - int is_connect, - struct http_parser_url *u); - - /* Pause or un-pause the parser; a nonzero value pauses */ - void http_parser_pause(http_parser *parser, int paused); - - /* Checks if this is the final chunk of the body. */ - int http_body_is_final(const http_parser *parser); - +int http_should_keep_alive(const http_parser *parser); + +/* Returns a string version of the HTTP method. */ +const char *http_method_str(enum http_method m); + +/* Return a string name of the given error */ +const char *http_errno_name(enum http_errno err); + +/* Return a string description of the given error */ +const char *http_errno_description(enum http_errno err); + +/* Parse a URL; return nonzero on failure */ +int http_parser_parse_url(const char *buf, size_t buflen, int is_connect, struct http_parser_url *u); + +/* Pause or un-pause the parser; a nonzero value pauses */ +void http_parser_pause(http_parser *parser, int paused); + +/* Checks if this is the final chunk of the body. */ +int http_body_is_final(const http_parser *parser); + #ifdef __cplusplus } #endif diff --git a/srcs/httpserver/src/haywire/http_request.c b/srcs/httpserver/src/haywire/http_request.c index 11986f6..971db00 100644 --- a/srcs/httpserver/src/haywire/http_request.c +++ b/srcs/httpserver/src/haywire/http_request.c @@ -10,68 +10,59 @@ #include "http_server.h" #include "server_stats.h" #include "route_compare_method.h" +#include "misc.h" -extern char* uv__strndup(const char* s, size_t n); +extern char *uv__strndup(const char *s, size_t n); #define CRLF "\r\n" -static const char response_404[] = - "HTTP/1.1 404 Not Found" CRLF - "Server: Haywire/master" CRLF - "Date: Fri, 26 Aug 2011 00:31:53 GMT" CRLF - "Connection: Keep-Alive" CRLF - "Content-Type: text/html" CRLF - "Content-Length: 16" CRLF - CRLF - "404 Not Found" CRLF - ; +static const char response_404[] = "HTTP/1.1 404 Not Found" CRLF "Server: Haywire/master" CRLF + "Date: Fri, 26 Aug 2011 00:31:53 GMT" CRLF "Connection: Keep-Alive" CRLF + "Content-Type: text/html" CRLF "Content-Length: 16" CRLF CRLF "404 Not Found" CRLF; -static kh_inline khint_t hw_string_hash_func(hw_string* s) -{ +static kh_inline khint_t hw_string_hash_func(hw_string *s) { khint_t h = s->length > 0 ? (khint_t)*s->value : 0; - if (h) for (int i = 0; i < s->length; i++) h = (h << 5) - h + (khint_t)*(s->value + i); + if (h) + for (int i = 0; i < s->length; i++) + h = (h << 5) - h + (khint_t) * (s->value + i); return h; } #define hw_string_hash_equal(a, b) (hw_strcmp(a, b) == 0) -KHASH_INIT(hw_string_hashmap, hw_string*, hw_string*, 1, hw_string_hash_func, hw_string_hash_equal) -KHASH_MAP_INIT_STR(string_hashmap, char*) +KHASH_INIT(hw_string_hashmap, hw_string *, hw_string *, 1, hw_string_hash_func, hw_string_hash_equal) +KHASH_MAP_INIT_STR(string_hashmap, char *) KHASH_MAP_INIT_INT64(offset_hashmap, int) -void hw_print_request_headers(http_request* request) -{ - hw_string* k; - hw_string* v; +void hw_print_request_headers(http_request *request) { + hw_string *k; + hw_string *v; khash_t(hw_string_hashmap) *h = request->headers; kh_foreach(h, k, v, { - char* key = uv__strndup(k->value, k->length + 1); - char* value = uv__strndup(v->value, v->length + 1); + char *key = uv__strndup(k->value, k->length + 1); + char *value = uv__strndup(v->value, v->length + 1); printf("KEY: %s VALUE: %s\n", key, value); free(key); free(value); }); } -void hw_print_body(http_request* request) -{ +void hw_print_body(http_request *request) { if (request->body->length > 0) { - char* body = uv__strndup(request->body->value, request->body->length); + char *body = uv__strndup(request->body->value, request->body->length); printf("BODY: %s\n", body); free(body); - } - else { + } else { printf("BODY is empty!\n"); } } -void* get_header(http_request* request, hw_string* name) -{ +void *get_header(http_request *request, hw_string *name) { khash_t(hw_string_hashmap) *h = request->headers; - khiter_t k = kh_get(hw_string_hashmap, h, name); + khiter_t k = kh_get(hw_string_hashmap, h, name); + + void *val; - void* val; - int is_missing = (k == kh_end(h)); if (is_missing) { val = NULL; @@ -81,48 +72,43 @@ void* get_header(http_request* request, hw_string* name) return val; } -void set_header(http_request* request, hw_string* name, hw_string* value) -{ - int ret, i; +void set_header(http_request *request, hw_string *name, hw_string *value) { + int ret, i; khiter_t k; khash_t(hw_string_hashmap) *h = request->headers; - for (i = 0; i < name->length; i++) - { + for (i = 0; i < name->length; i++) { name->value[i] = tolower(name->value[i]); } - void* prev = get_header(request, name); + void *prev = get_header(request, name); if (prev) { free(prev); } - k = kh_put(hw_string_hashmap, h, name, &ret); + k = kh_put(hw_string_hashmap, h, name, &ret); kh_value(h, k) = value; } -http_request* create_http_request(http_connection* connection) -{ - http_request* request = calloc(1, sizeof(http_request)); - request->headers = kh_init(hw_string_hashmap); - request->url = calloc(1, sizeof(hw_string)); - request->body = calloc(1, sizeof(hw_string)); - request->state = OK; +http_request *create_http_request(http_connection *UNUSED(connection)) { + http_request *request = calloc(1, sizeof(http_request)); + request->headers = kh_init(hw_string_hashmap); + request->url = calloc(1, sizeof(hw_string)); + request->body = calloc(1, sizeof(hw_string)); + request->state = OK; INCREMENT_STAT(stat_requests_created_total); return request; } -void free_http_request(http_request* request) -{ +void free_http_request(http_request *request) { khash_t(hw_string_hashmap) *h = request->headers; - hw_string* k; - hw_string* v; + hw_string *k; + hw_string *v; - kh_foreach(h, k, v, - { - free((hw_string*)k); - free((hw_string*)v); + kh_foreach(h, k, v, { + free((hw_string *)k); + free((hw_string *)v); }); kh_destroy(hw_string_hashmap, h); @@ -135,15 +121,13 @@ void free_http_request(http_request* request) INCREMENT_STAT(stat_requests_destroyed_total); } -hw_string* hw_get_header(http_request* request, hw_string* key) -{ - void* value = get_header(request, key); +hw_string *hw_get_header(http_request *request, hw_string *key) { + void *value = get_header(request, key); return value; } -int http_request_on_message_begin(http_parser* parser) -{ - http_connection* connection = (http_connection*)parser->data; +int http_request_on_message_begin(http_parser *parser) { + http_connection *connection = (http_connection *)parser->data; if (connection->request) { /* We're seeing a new request on the same connection, so it's time to free up the old one * and create a new one. @@ -156,18 +140,17 @@ int http_request_on_message_begin(http_parser* parser) return 0; } -int http_request_on_url(http_parser *parser, const char *at, size_t length) -{ - http_connection* connection = (http_connection*)parser->data; - http_request* request = connection->request; - hw_string* url = request->url; +int http_request_on_url(http_parser *parser, const char *at, size_t length) { + http_connection *connection = (http_connection *)parser->data; + http_request *request = connection->request; + hw_string *url = request->url; if (url->length) { /* This is not the first URL chunk that has been seen in the buffer. Since we've already captured the initial pointer in the branch below, so we can recover the URL later on, we only increment the URL length and ignore the pointer passed in as a parameter. */ url->length += length; } else { - url->value = at; + url->value = at; url->length = length; /* We've seen the URL start, so we need to pin it to recover it later */ http_request_buffer_pin(connection->buffer, url, url->value); @@ -176,9 +159,9 @@ int http_request_on_url(http_parser *parser, const char *at, size_t length) return 0; } -void http_request_save_current_header(http_connection* connection) { - hw_string* header_key_copy = hw_strdup(&connection->current_header_key); - hw_string* header_value_copy = hw_strdup(&connection->current_header_value); +void http_request_save_current_header(http_connection *connection) { + hw_string *header_key_copy = hw_strdup(&connection->current_header_key); + hw_string *header_value_copy = hw_strdup(&connection->current_header_value); /* We duplicate the current header key/value, so we actually need to use the new pointers as pin ids, as * those will be the IDs we'll use later on to locate the headers */ @@ -187,25 +170,23 @@ void http_request_save_current_header(http_connection* connection) { /* Set headers is going to need to have the values of header key/value, so we need to make sure we get * the pointers pointing at the right place in the buffer */ - header_key_copy->value = http_request_buffer_locate(connection->buffer, header_key_copy, - connection->current_header_key.value); + header_key_copy->value = http_request_buffer_locate( + connection->buffer, header_key_copy, connection->current_header_key.value); - header_value_copy->value = http_request_buffer_locate(connection->buffer, header_value_copy, - connection->current_header_value.value); + header_value_copy->value = http_request_buffer_locate( + connection->buffer, header_value_copy, connection->current_header_value.value); /* Save last header key/value pair that was read */ set_header(connection->request, header_key_copy, header_value_copy); } - -int http_request_on_header_field(http_parser *parser, const char *at, size_t length) -{ - http_connection* connection = (http_connection*)parser->data; +int http_request_on_header_field(http_parser *parser, const char *at, size_t length) { + http_connection *connection = (http_connection *)parser->data; if (connection->last_was_value && connection->current_header_key.length > 0) { http_request_save_current_header(connection); - connection->current_header_key.length = 0; + connection->current_header_key.length = 0; connection->current_header_value.length = 0; } @@ -215,7 +196,7 @@ int http_request_on_header_field(http_parser *parser, const char *at, size_t len connection->current_header_key.length += length; } else { /* Start of a new header key */ - connection->current_header_key.value = at; + connection->current_header_key.value = at; connection->current_header_key.length = length; /* Pin the header key */ http_request_buffer_pin(connection->buffer, &connection->current_header_key, at); @@ -225,14 +206,13 @@ int http_request_on_header_field(http_parser *parser, const char *at, size_t len return 0; } -int http_request_on_header_value(http_parser *parser, const char *at, size_t length) -{ - http_connection* connection = (http_connection*)parser->data; +int http_request_on_header_value(http_parser *parser, const char *at, size_t length) { + http_connection *connection = (http_connection *)parser->data; if (!connection->last_was_value) { - connection->current_header_value.value = at; + connection->current_header_value.value = at; connection->current_header_value.length = length; - connection->last_was_value = 1; + connection->last_was_value = 1; /* Pin the header value */ http_request_buffer_pin(connection->buffer, &connection->current_header_value, at); } else { @@ -244,70 +224,63 @@ int http_request_on_header_value(http_parser *parser, const char *at, size_t len return 0; } -int http_request_on_headers_complete(http_parser* parser) -{ - http_connection* connection = (http_connection*)parser->data; +int http_request_on_headers_complete(http_parser *parser) { + http_connection *connection = (http_connection *)parser->data; if (connection->current_header_key.length > 0 && connection->current_header_value.length > 0) { http_request_save_current_header(connection); } - connection->current_header_key.length = 0; + connection->current_header_key.length = 0; connection->current_header_value.length = 0; - + connection->request->http_major = parser->http_major; connection->request->http_minor = parser->http_minor; - connection->request->method = parser->method; - connection->keep_alive = http_should_keep_alive(parser); + connection->request->method = parser->method; + connection->keep_alive = http_should_keep_alive(parser); connection->request->keep_alive = connection->keep_alive; return 0; } -int http_request_on_body(http_parser *parser, const char *at, size_t length) -{ - http_connection* connection = (http_connection*)parser->data; - http_request* request = connection->request; - hw_string* body = request->body; - if (length != 0) - { +int http_request_on_body(http_parser *parser, const char *at, size_t length) { + http_connection *connection = (http_connection *)parser->data; + http_request *request = connection->request; + hw_string *body = request->body; + if (length != 0) { if (body->length == 0) { - body->value = at; + body->value = at; body->length = length; /* Let's pin the body so we can recover it later, even if the underlying buffers change */ http_request_buffer_pin(connection->buffer, body, body->value); } else { body->length += length; } - + request->body_length = body->length; } return 0; } -hw_route_entry* get_route_callback(hw_string* url) -{ - hw_route_entry* route_entry = NULL; - - const char* k; - const char* v; - +hw_route_entry *get_route_callback(hw_string *url) { + hw_route_entry *route_entry = NULL; + + const char *k; + const char *v; + khash_t(string_hashmap) *h = routes; - kh_foreach(h, k, v, - { + kh_foreach(h, k, v, { int found = hw_route_compare_method(url, k); - if (found) - { - route_entry = (hw_route_entry*)v; + if (found) { + route_entry = (hw_route_entry *)v; } }); - + return route_entry; } -void send_error_response(http_request* request, http_response* response, const char* error_code, - const char* error_message) -{ +void send_error_response(http_request *request, http_response *response, const char *error_code, + const char *error_message) { hw_string status_code; hw_string content_type_name; hw_string content_type_value; @@ -315,28 +288,25 @@ void send_error_response(http_request* request, http_response* response, const c hw_string keep_alive_name; hw_string keep_alive_value; - status_code.value = error_code; + status_code.value = error_code; status_code.length = strlen(error_code); hw_set_response_status_code(response, &status_code); - + SETSTRING(content_type_name, "Content-Type"); - + SETSTRING(content_type_value, "text/html"); hw_set_response_header(response, &content_type_name, &content_type_value); - body.value = error_message; + body.value = error_message; body.length = strlen(error_message); hw_set_body(response, &body); - - if (request->keep_alive) - { + + if (request->keep_alive) { SETSTRING(keep_alive_name, "Connection"); - + SETSTRING(keep_alive_value, "Keep-Alive"); hw_set_response_header(response, &keep_alive_name, &keep_alive_value); - } - else - { + } else { hw_set_http_version(response, 1, 0); } @@ -348,30 +318,28 @@ void send_error_response(http_request* request, http_response* response, const c * This is because the underlying buffers might have been reallocated/resized, * so we can't use the pointers of where data chunks (e.g. URL start) were originally seen. */ -void http_request_locate_members(http_connection* connection) -{ - hw_request_buffer* buffer = connection->buffer; - http_request* request = connection->request; - request->url->value = http_request_buffer_locate(buffer, request->url, request->url->value); - request->body->value = http_request_buffer_locate(buffer, request->body, request->body->value); +void http_request_locate_members(http_connection *connection) { + hw_request_buffer *buffer = connection->buffer; + http_request *request = connection->request; + request->url->value = http_request_buffer_locate(buffer, request->url, request->url->value); + request->body->value = http_request_buffer_locate(buffer, request->body, request->body->value); - hw_string* header_name; - hw_string* header_value; + hw_string *header_name; + hw_string *header_value; khash_t(hw_string_hashmap) *h = request->headers; kh_foreach(h, header_name, header_value, { - header_name->value = http_request_buffer_locate(buffer, header_name, header_name->value); + header_name->value = http_request_buffer_locate(buffer, header_name, header_name->value); header_value->value = http_request_buffer_locate(buffer, header_value, header_value->value); }); } -int http_request_on_message_complete(http_parser* parser) -{ - http_connection* connection = (http_connection*)parser->data; - http_request* request = connection->request; - hw_http_response* response = hw_create_http_response(connection); +int http_request_on_message_complete(http_parser *parser) { + http_connection *connection = (http_connection *)parser->data; + http_request *request = connection->request; + hw_http_response *response = hw_create_http_response(connection); - char* error = NULL; + char *error = NULL; if (connection->request->state == SIZE_EXCEEDED) { // 413 Request entity too large @@ -384,14 +352,11 @@ int http_request_on_message_complete(http_parser* parser) } else { http_request_locate_members(connection); - hw_route_entry* route_entry = request != NULL ? get_route_callback(request->url) : NULL; + hw_route_entry *route_entry = request != NULL ? get_route_callback(request->url) : NULL; - if (route_entry != NULL) - { + if (route_entry != NULL) { route_entry->callback(request, response, route_entry->user_data); - } - else - { + } else { // 404 Not Found. error = HTTP_STATUS_404; } @@ -406,9 +371,9 @@ int http_request_on_message_complete(http_parser* parser) * currently being processed and on which callback fired. */ http_request_buffer_mark(connection->buffer); } - + if (error) { - send_error_response(request, (http_response*)response, error, error); + send_error_response(request, (http_response *)response, error, error); } return 0; diff --git a/srcs/httpserver/src/haywire/http_request.h b/srcs/httpserver/src/haywire/http_request.h index 97acd6a..4208539 100644 --- a/srcs/httpserver/src/haywire/http_request.h +++ b/srcs/httpserver/src/haywire/http_request.h @@ -6,11 +6,11 @@ extern int last_was_value; -void free_http_request(http_request* request); -int http_request_on_message_begin(http_parser *parser); -int http_request_on_url(http_parser *parser, const char *at, size_t length); -int http_request_on_header_field(http_parser *parser, const char *at, size_t length); -int http_request_on_header_value(http_parser *parser, const char *at, size_t length); -int http_request_on_body(http_parser *parser, const char *at, size_t length); -int http_request_on_headers_complete(http_parser *parser); -int http_request_on_message_complete(http_parser *parser); \ No newline at end of file +void free_http_request(http_request *request); +int http_request_on_message_begin(http_parser *parser); +int http_request_on_url(http_parser *parser, const char *at, size_t length); +int http_request_on_header_field(http_parser *parser, const char *at, size_t length); +int http_request_on_header_value(http_parser *parser, const char *at, size_t length); +int http_request_on_body(http_parser *parser, const char *at, size_t length); +int http_request_on_headers_complete(http_parser *parser); +int http_request_on_message_complete(http_parser *parser); \ No newline at end of file diff --git a/srcs/httpserver/src/haywire/http_request_buffers.c b/srcs/httpserver/src/haywire/http_request_buffers.c index e89c846..407b81b 100644 --- a/srcs/httpserver/src/haywire/http_request_buffers.c +++ b/srcs/httpserver/src/haywire/http_request_buffers.c @@ -7,7 +7,7 @@ #define MIN(x, y) (((x) < (y)) ? (x) : (y)) -KHASH_MAP_INIT_INT64(pointer_hashmap, void*) +KHASH_MAP_INIT_INT64(pointer_hashmap, void *) typedef struct { size_t max_size; @@ -15,30 +15,30 @@ typedef struct { size_t mark; size_t used; size_t used_before; - void* current; - khash_t(pointer_hashmap)* offsets; + void *current; + khash_t(pointer_hashmap) * offsets; bool offsets_active; } http_request_buffer; -void http_request_buffer_consume(hw_request_buffer* buf, size_t consumed) { - http_request_buffer* buffer = (http_request_buffer*) buf; - buffer->used_before = buffer->used; +void http_request_buffer_consume(hw_request_buffer *buf, size_t consumed) { + http_request_buffer *buffer = (http_request_buffer *)buf; + buffer->used_before = buffer->used; buffer->used += consumed; } -void http_request_buffer_mark(hw_request_buffer* buf) { - http_request_buffer* buffer = (http_request_buffer*) buf; +void http_request_buffer_mark(hw_request_buffer *buf) { + http_request_buffer *buffer = (http_request_buffer *)buf; /* unfortunately, the parser doesn't tell us where the request ends exactly, * so the only thing we can be sure is that it ends in the current buffer chunk, so anything before it can * effectively be swept, so we're placing the mark at that point now. */ buffer->mark = buffer->used_before; } -void http_request_buffer_sweep(hw_request_buffer* buf) { - http_request_buffer* buffer = (http_request_buffer*) buf; - void* pointer; - int offset; - int used = buffer->used - buffer->mark; +void http_request_buffer_sweep(hw_request_buffer *buf) { + http_request_buffer *buffer = (http_request_buffer *)buf; + void *pointer; + int offset; + int used = buffer->used - buffer->mark; if (buffer->mark > 0) { bool offsets_active = false; @@ -53,10 +53,10 @@ void http_request_buffer_sweep(hw_request_buffer* buf) { if (buffer->size > DEFAULT_BUFFER_SHRINKSIZE && buffer->used < DEFAULT_BUFFER_SHRINKSIZE) { /* Shrink buffer */ - buffer->size = DEFAULT_BUFFER_SHRINKSIZE; + buffer->size = DEFAULT_BUFFER_SHRINKSIZE; buffer->current = realloc(buffer->current, buffer->size); if (!buffer->current) { - errno = ENOMEM; + errno = ENOMEM; buffer->size = 0; } } @@ -72,7 +72,7 @@ void http_request_buffer_sweep(hw_request_buffer* buf) { } else { /* There's at least one offset beyond the mark, so the offsets are active and should be considered * when locating pointers. We need to shift the offset back by the width of the mark */ - offsets_active = true; + offsets_active = true; kh_value(buffer->offsets, offset_key) = offset - buffer->mark; } }); @@ -81,35 +81,35 @@ void http_request_buffer_sweep(hw_request_buffer* buf) { kh_clear(pointer_hashmap, buffer->offsets); } - buffer->mark = 0; - buffer->used = used; + buffer->mark = 0; + buffer->used = used; buffer->offsets_active = offsets_active; } } -hw_request_buffer* http_request_buffer_init(size_t max_size) { - http_request_buffer* buffer = malloc(sizeof(http_request_buffer)); - buffer->max_size = max_size; - buffer->size = 0; - buffer->used = 0; - buffer->mark = 0; - buffer->used_before = 0; - buffer->current = NULL; - buffer->offsets = kh_init(pointer_hashmap); - buffer->offsets_active = false; +hw_request_buffer *http_request_buffer_init(size_t max_size) { + http_request_buffer *buffer = malloc(sizeof(http_request_buffer)); + buffer->max_size = max_size; + buffer->size = 0; + buffer->used = 0; + buffer->mark = 0; + buffer->used_before = 0; + buffer->current = NULL; + buffer->offsets = kh_init(pointer_hashmap); + buffer->offsets_active = false; return buffer; } -void http_request_buffer_chunk(hw_request_buffer* buf, hw_request_buffer_chunk* chunk) { - http_request_buffer *buffer = (http_request_buffer *) buf; - chunk->size = buffer->size ? buffer->size - buffer->used : 0; - chunk->buffer = buffer->current + buffer->used; +void http_request_buffer_chunk(hw_request_buffer *buf, hw_request_buffer_chunk *chunk) { + http_request_buffer *buffer = (http_request_buffer *)buf; + chunk->size = buffer->size ? buffer->size - buffer->used : 0; + chunk->buffer = buffer->current + buffer->used; } -bool http_request_buffer_alloc(hw_request_buffer* buf, size_t requested_size) { - http_request_buffer* buffer = (http_request_buffer*) buf; - bool ret = true; - void* previous = NULL; +bool http_request_buffer_alloc(hw_request_buffer *buf, size_t requested_size) { + http_request_buffer *buffer = (http_request_buffer *)buf; + bool ret = true; + void *previous = NULL; size_t requested_size_capped = MIN(buffer->max_size, requested_size); @@ -117,8 +117,8 @@ bool http_request_buffer_alloc(hw_request_buffer* buf, size_t requested_size) { buffer->current = malloc(requested_size_capped); if (!buffer->current) { buffer->size = 0; - errno = ENOMEM; - ret = false; + errno = ENOMEM; + ret = false; } else { buffer->size = requested_size_capped; } @@ -133,33 +133,33 @@ bool http_request_buffer_alloc(hw_request_buffer* buf, size_t requested_size) { if (!buffer->current) { buffer->size = 0; - errno = ENOMEM; - ret = false; + errno = ENOMEM; + ret = false; } else if (buffer->current != previous) { buffer->offsets_active = true; } } else { /* maximum request size exceeded */ - errno = ERANGE; + errno = ERANGE; buffer->size = 0; - ret = false; + ret = false; } return ret; } -void http_request_buffer_print(hw_request_buffer* buf) { - http_request_buffer* buffer = (http_request_buffer*) buf; +void http_request_buffer_print(hw_request_buffer *buf) { + http_request_buffer *buffer = (http_request_buffer *)buf; printf("Buffer: current=%u; size=%u; used=%u\n", buffer->current, buffer->size, buffer->used); printf(" 0\t"); for (int i = 0; i < buffer->used; i++) { - if (((char*) buffer->current)[i] == '\n') { + if (((char *)buffer->current)[i] == '\n') { printf("\\n"); - } else if (((char*) buffer->current)[i] == '\r') { + } else if (((char *)buffer->current)[i] == '\r') { printf("\\r"); } else { - printf("%c", ((char*) buffer->current)[i]); + printf("%c", ((char *)buffer->current)[i]); } if ((i + 1) % 10 == 0) { @@ -170,16 +170,14 @@ void http_request_buffer_print(hw_request_buffer* buf) { } printf("\n"); - void* pointer; - int offset; - kh_foreach(buffer->offsets, pointer, offset, { - printf("\tPointer %u -> offset=%u\n", pointer, offset); - }); + void *pointer; + int offset; + kh_foreach(buffer->offsets, pointer, offset, { printf("\tPointer %u -> offset=%u\n", pointer, offset); }); printf("----\n"); } -void http_request_buffer_pin(hw_request_buffer* buf, void* key, void* pointer) { - http_request_buffer* buffer = (http_request_buffer*) buf; +void http_request_buffer_pin(hw_request_buffer *buf, void *key, void *pointer) { + http_request_buffer *buffer = (http_request_buffer *)buf; khiter_t offset_key = kh_get(pointer_hashmap, buffer->offsets, key); @@ -189,13 +187,13 @@ void http_request_buffer_pin(hw_request_buffer* buf, void* key, void* pointer) { int is_missing = (offset_key == kh_end(buffer->offsets)); if (is_missing) { offset_key = kh_put(pointer_hashmap, buffer->offsets, key, &ret); - } + } kh_value(buffer->offsets, offset_key) = offset; } -void http_request_buffer_reassign_pin(hw_request_buffer* buf, void* old_key, void* new_key) { - http_request_buffer* buffer = (http_request_buffer*) buf; +void http_request_buffer_reassign_pin(hw_request_buffer *buf, void *old_key, void *new_key) { + http_request_buffer *buffer = (http_request_buffer *)buf; khiter_t old_offset_key = kh_get(pointer_hashmap, buffer->offsets, old_key); @@ -206,24 +204,24 @@ void http_request_buffer_reassign_pin(hw_request_buffer* buf, void* old_key, voi if (!is_missing) { offset = kh_val(buffer->offsets, old_offset_key); - khiter_t new_offset_key = kh_put(pointer_hashmap, buffer->offsets, new_key, &ret); + khiter_t new_offset_key = kh_put(pointer_hashmap, buffer->offsets, new_key, &ret); kh_value(buffer->offsets, new_offset_key) = offset; - old_offset_key = kh_get(pointer_hashmap, buffer->offsets, old_key); + old_offset_key = kh_get(pointer_hashmap, buffer->offsets, old_key); kh_del(pointer_hashmap, buffer->offsets, old_offset_key); } } -void* http_request_buffer_locate(hw_request_buffer* buf, void* key, void* default_pointer) { - http_request_buffer* buffer = (http_request_buffer*) buf; - void* location = default_pointer; - khiter_t offset_key = kh_get(pointer_hashmap, buffer->offsets, key); +void *http_request_buffer_locate(hw_request_buffer *buf, void *key, void *default_pointer) { + http_request_buffer *buffer = (http_request_buffer *)buf; + void *location = default_pointer; + khiter_t offset_key = kh_get(pointer_hashmap, buffer->offsets, key); int offset, is_missing; if (buffer->offsets_active) { is_missing = (offset_key == kh_end(buffer->offsets)); if (!is_missing) { - offset = kh_value(buffer->offsets, offset_key); + offset = kh_value(buffer->offsets, offset_key); location = buffer->current + offset; } } @@ -231,8 +229,8 @@ void* http_request_buffer_locate(hw_request_buffer* buf, void* key, void* defaul return location; } -void http_request_buffer_destroy(hw_request_buffer* buf) { - http_request_buffer* buffer = (http_request_buffer*) buf; +void http_request_buffer_destroy(hw_request_buffer *buf) { + http_request_buffer *buffer = (http_request_buffer *)buf; kh_destroy(pointer_hashmap, buffer->offsets); free(buffer->current); free(buffer); diff --git a/srcs/httpserver/src/haywire/http_request_buffers.h b/srcs/httpserver/src/haywire/http_request_buffers.h index c906c43..05df178 100644 --- a/srcs/httpserver/src/haywire/http_request_buffers.h +++ b/srcs/httpserver/src/haywire/http_request_buffers.h @@ -4,38 +4,38 @@ #include "haywire.h" typedef struct { - void* buffer; + void *buffer; size_t size; } hw_request_buffer_chunk; -typedef void* hw_request_buffer; +typedef void *hw_request_buffer; /** * Initializes a new buffer. The caller is responsible for calling http_request_buffer_destroy to free up memory. */ -hw_request_buffer* http_request_buffer_init(size_t max_size); +hw_request_buffer *http_request_buffer_init(size_t max_size); /** * Signals that "size" bytes from the buffer are now in use. */ -void http_request_buffer_consume(hw_request_buffer* buffer, size_t size); +void http_request_buffer_consume(hw_request_buffer *buffer, size_t size); /** * Marks all buffer chunks up to the last one allocated (exclusive) for removal when * http_request_buffer_sweep gets called. */ -void http_request_buffer_mark(hw_request_buffer* buffer); +void http_request_buffer_mark(hw_request_buffer *buffer); /** * Sweeps all buffer chunks up to the mark. Data for the last chunk is copied to the beginning of the buffer * and the offsets are updates accordingly. */ -void http_request_buffer_sweep(hw_request_buffer* buffer); +void http_request_buffer_sweep(hw_request_buffer *buffer); /** * Prints the buffer. */ -void http_request_buffer_print(hw_request_buffer* buffer); +void http_request_buffer_print(hw_request_buffer *buffer); /** * Ensures that there's will be a sizable chunk available when the it's requested via http_request_buffer_chunk. @@ -45,24 +45,24 @@ void http_request_buffer_print(hw_request_buffer* buffer); * * Returns true if the allocation succeeds, false otherwise (errno is set accordingly). */ -bool http_request_buffer_alloc(hw_request_buffer* buf, size_t requested_size); +bool http_request_buffer_alloc(hw_request_buffer *buf, size_t requested_size); /** * Returns a new buffer chunk to be used by request reader. */ -void http_request_buffer_chunk(hw_request_buffer* buffer, hw_request_buffer_chunk* chunk); +void http_request_buffer_chunk(hw_request_buffer *buffer, hw_request_buffer_chunk *chunk); /** * Informs the buffer manager that *pointer is a memory region of interest and that will have to be made available to * the caller eventually, when http_request_buffer_locate is called. The pin is given a key by the caller so it can be * retrieved later. Pins will be overwritten if the same key is used multiple times. */ -void http_request_buffer_pin(hw_request_buffer* buffer, void* key, void* pointer); +void http_request_buffer_pin(hw_request_buffer *buffer, void *key, void *pointer); /** * Allows the caller to assign a new key to a pin. */ -void http_request_buffer_reassign_pin(hw_request_buffer* buffer, void* old_key, void* new_key); +void http_request_buffer_reassign_pin(hw_request_buffer *buffer, void *old_key, void *new_key); /** * Returns the pointer to the memory region associated with a pin. If there isn't a pin with that key, then @@ -73,9 +73,9 @@ void http_request_buffer_reassign_pin(hw_request_buffer* buffer, void* old_key, * sequentially. It's the responsibility of the caller to know how long that region is, by keeping track of its * length as it's being read in. */ -void* http_request_buffer_locate(hw_request_buffer* buffer, void* key, void* default_pointer); +void *http_request_buffer_locate(hw_request_buffer *buffer, void *key, void *default_pointer); /** * Destroys the buffer and any underlying buffer chunks. */ -void http_request_buffer_destroy(hw_request_buffer* buffer); +void http_request_buffer_destroy(hw_request_buffer *buffer); diff --git a/srcs/httpserver/src/haywire/http_response.c b/srcs/httpserver/src/haywire/http_response.c index 58b4987..d7d4c1b 100644 --- a/srcs/httpserver/src/haywire/http_response.c +++ b/srcs/httpserver/src/haywire/http_response.c @@ -8,59 +8,54 @@ #include "hw_string.h" #define CRLF "\r\n" -KHASH_MAP_INIT_STR(string_hashmap, char*) +KHASH_MAP_INIT_STR(string_hashmap, char *) -hw_http_response hw_create_http_response(http_connection* connection) -{ - http_response* response = malloc(sizeof(http_response)); - response->connection = connection; - response->request = connection->request; - response->http_major = 1; - response->http_minor = 1; - response->body.value = NULL; - response->body.length = 0; +hw_http_response hw_create_http_response(http_connection *connection) { + http_response *response = malloc(sizeof(http_response)); + response->connection = connection; + response->request = connection->request; + response->http_major = 1; + response->http_minor = 1; + response->body.value = NULL; + response->body.length = 0; response->number_of_headers = 0; return response; } -void hw_free_http_response(hw_http_response* response) -{ - http_response* resp = (http_response*)response; +void hw_free_http_response(hw_http_response *response) { + http_response *resp = (http_response *)response; free(resp); } -void hw_set_http_version(hw_http_response* response, unsigned short major, unsigned short minor) -{ - http_response* resp = (http_response*)response; - resp->http_major = major; - resp->http_minor = minor; +void hw_set_http_version(hw_http_response *response, unsigned short major, unsigned short minor) { + http_response *resp = (http_response *)response; + resp->http_major = major; + resp->http_minor = minor; } -void hw_set_response_status_code(hw_http_response* response, hw_string* status_code) -{ - http_response* resp = (http_response*)response; - resp->status_code = *status_code; +void hw_set_response_status_code(hw_http_response *response, hw_string *status_code) { + http_response *resp = (http_response *)response; + resp->status_code = *status_code; } -void hw_set_response_header(hw_http_response* response, hw_string* name, hw_string* value) -{ - http_response* resp = (http_response*)response; - http_header* header = &resp->headers[resp->number_of_headers]; - header->name = *name; - header->value = *value; +void hw_set_response_header(hw_http_response *response, hw_string *name, hw_string *value) { + http_response *resp = (http_response *)response; + http_header *header = &resp->headers[resp->number_of_headers]; + header->name = *name; + header->value = *value; resp->headers[resp->number_of_headers] = *header; resp->number_of_headers++; } -void hw_set_body(hw_http_response* response, hw_string* body) -{ - http_response* resp = (http_response*)response; - resp->body = *body; +void hw_set_body(hw_http_response *response, hw_string *body) { + http_response *resp = (http_response *)response; + resp->body = *body; } int num_chars(int n) { int r = 1; - if (n < 0) n = (n == INT_MIN) ? INT_MAX : -n; + if (n < 0) + n = (n == INT_MIN) ? INT_MAX : -n; while (n > 9) { n /= 10; r++; @@ -68,35 +63,34 @@ int num_chars(int n) { return r; } -hw_string* create_response_buffer(hw_http_response* response) -{ - http_response* resp = (http_response*)response; - hw_string* response_string = malloc(sizeof(hw_string)); - hw_string* cached_entry = get_cached_request(resp->status_code.value); - hw_string content_length; +hw_string *create_response_buffer(hw_http_response *response) { + http_response *resp = (http_response *)response; + hw_string *response_string = malloc(sizeof(hw_string)); + hw_string *cached_entry = get_cached_request(resp->status_code.value); + hw_string content_length; int i = 0; char length_header[] = "Content-Length: "; - int line_sep_size = sizeof(CRLF); + int line_sep_size = sizeof(CRLF); - int header_buffer_incr = 512; - int body_size = resp->body.length; + int header_buffer_incr = 512; + int body_size = resp->body.length; int header_size_remaining = header_buffer_incr; - int response_size = header_size_remaining + sizeof(length_header) + num_chars(resp->body.length) + 2 * line_sep_size + body_size + line_sep_size; + int response_size = header_size_remaining + sizeof(length_header) + num_chars(resp->body.length) + 2 * line_sep_size + + body_size + line_sep_size; response_string->value = malloc(response_size); response_string->length = 0; append_string(response_string, cached_entry); - - for (i=0; i< resp->number_of_headers; i++) - { + + for (i = 0; i < resp->number_of_headers; i++) { http_header header = resp->headers[i]; header_size_remaining -= header.name.length + 2 + header.value.length + line_sep_size; if (header_size_remaining < 0) { - header_size_remaining += header_buffer_incr * ((-header_size_remaining/header_buffer_incr) + 1); + header_size_remaining += header_buffer_incr * ((-header_size_remaining / header_buffer_incr) + 1); response_size += header_size_remaining; response_string->value = realloc(response_string->value, response_size); } @@ -106,43 +100,39 @@ hw_string* create_response_buffer(hw_http_response* response) append_string(response_string, &header.value); APPENDSTRING(response_string, CRLF); } - + /* Add the body */ APPENDSTRING(response_string, length_header); string_from_int(&content_length, body_size, 10); - + if (body_size > 0) { append_string(response_string, &content_length); - } - else { + } else { hw_string zero_content; - zero_content.value = "0"; + zero_content.value = "0"; zero_content.length = 1; append_string(response_string, &zero_content); } - + APPENDSTRING(response_string, CRLF CRLF); - - if (body_size > 0) - { + + if (body_size > 0) { append_string(response_string, &resp->body); } return response_string; } - -void hw_http_response_send(hw_http_response* response, void* user_data, http_response_complete_callback callback) -{ - hw_write_context* write_context = malloc(sizeof(hw_write_context)); - http_response* resp = (http_response*)response; - hw_string* response_buffer = create_response_buffer(response); +void hw_http_response_send(hw_http_response *response, void *user_data, http_response_complete_callback callback) { + hw_write_context *write_context = malloc(sizeof(hw_write_context)); + http_response *resp = (http_response *)response; + hw_string *response_buffer = create_response_buffer(response); write_context->connection = resp->connection; - write_context->user_data = user_data; - write_context->callback = callback; - write_context->request = resp->request; + write_context->user_data = user_data; + write_context->callback = callback; + write_context->request = resp->request; http_server_write_response(write_context, response_buffer); resp->sent = 1; @@ -150,3 +140,28 @@ void hw_http_response_send(hw_http_response* response, void* user_data, http_res free(response_buffer); hw_free_http_response(response); } + +void hw_http_response_send_error(hw_http_response *response, const char *error, const char *err_msg) { + hw_string status_code; + hw_string content_type_name; + hw_string content_type_value; + hw_string body; + hw_string keep_alive_name; + hw_string keep_alive_value; + + SETSTRING(content_type_name, "Content-Type"); + SETSTRING(content_type_value, "text/html"); + hw_set_response_header(response, &content_type_name, &content_type_value); + + SETSTRING(status_code, error); + SETSTRING(body, err_msg); + + hw_set_body(response, &body); + hw_set_response_status_code(response, &status_code); + + SETSTRING(keep_alive_name, "Connection"); + SETSTRING(keep_alive_value, "close"); + hw_set_response_header(response, &keep_alive_name, &keep_alive_value); + + hw_http_response_send(response, NULL, NULL); +} diff --git a/srcs/httpserver/src/haywire/http_response.h b/srcs/httpserver/src/haywire/http_response.h index 0d8725e..04da4dc 100644 --- a/srcs/httpserver/src/haywire/http_response.h +++ b/srcs/httpserver/src/haywire/http_response.h @@ -2,33 +2,30 @@ #include "haywire.h" #include "http_connection.h" -typedef struct -{ +typedef struct { hw_string name; hw_string value; } http_header; #define MAX_HEADERS 64 -typedef struct -{ - http_connection* connection; - http_request* request; - unsigned short http_major; - unsigned short http_minor; - hw_string status_code; - http_header headers[MAX_HEADERS]; - int number_of_headers; - hw_string body; - int sent; +typedef struct { + http_connection *connection; + http_request *request; + unsigned short http_major; + unsigned short http_minor; + hw_string status_code; + http_header headers[MAX_HEADERS]; + int number_of_headers; + hw_string body; + int sent; } http_response; -typedef struct -{ - http_connection* connection; - http_request* request; - void* user_data; +typedef struct { + http_connection *connection; + http_request *request; + void *user_data; http_response_complete_callback callback; } hw_write_context; -hw_http_response hw_create_http_response(http_connection* connection); -hw_string* create_response_buffer(hw_http_response* response); +hw_http_response hw_create_http_response(http_connection *connection); +hw_string *create_response_buffer(hw_http_response *response); diff --git a/srcs/httpserver/src/haywire/http_response_cache.c b/srcs/httpserver/src/haywire/http_response_cache.c index 80ba854..1802ebf 100644 --- a/srcs/httpserver/src/haywire/http_response_cache.c +++ b/srcs/httpserver/src/haywire/http_response_cache.c @@ -11,69 +11,61 @@ #include "http_server.h" #define CRLF "\r\n" -KHASH_MAP_INIT_STR(string_hashmap, hw_string*) +KHASH_MAP_INIT_STR(string_hashmap, hw_string *) static uv_timer_t cache_invalidation_timer; -static uv_key_t thread_cache_key; +static uv_key_t thread_cache_key; -void initialize_http_request_cache(); -void free_http_request_cache(); -void http_request_cache_timer(uv_timer_t* handle); -void create_cached_http_request(khash_t(string_hashmap)* http_request_cache, const char* http_status); -void set_cached_request(khash_t(string_hashmap)* http_request_cache, char* http_status, hw_string* cache_entry); -hw_string* get_cached_request(const char* http_status); +void initialize_http_request_cache(); +void free_http_request_cache(); +void http_request_cache_timer(uv_timer_t *handle); +void create_cached_http_request(khash_t(string_hashmap) * http_request_cache, const char *http_status); +void set_cached_request(khash_t(string_hashmap) * http_request_cache, char *http_status, hw_string *cache_entry); +hw_string *get_cached_request(const char *http_status); -void initialize_http_request_cache() -{ +void initialize_http_request_cache() { uv_key_create(&thread_cache_key); } -void http_request_cache_configure_listener(uv_loop_t* loop, uv_async_t* handle) -{ - uv_timer_t* cache_invalidation_timer = malloc(sizeof(uv_timer_t)); +void http_request_cache_configure_listener(uv_loop_t *loop, uv_async_t *handle) { + uv_timer_t *cache_invalidation_timer = malloc(sizeof(uv_timer_t)); uv_timer_init(loop, cache_invalidation_timer); uv_timer_start(cache_invalidation_timer, http_request_cache_timer, 500, 500); - - if (handle != NULL) - { - uv_unref((uv_handle_t*) cache_invalidation_timer); + + if (handle != NULL) { + uv_unref((uv_handle_t *)cache_invalidation_timer); } } -void http_request_cache_timer(uv_timer_t* timer) -{ - khash_t(string_hashmap)* http_request_cache = uv_key_get(&thread_cache_key); - if (http_request_cache != NULL) - { +void http_request_cache_timer(uv_timer_t *timer) { + khash_t(string_hashmap) *http_request_cache = uv_key_get(&thread_cache_key); + if (http_request_cache != NULL) { free_http_request_cache(http_request_cache); } } -void free_http_request_cache(khash_t(string_hashmap)* http_request_cache) -{ - const char* k; - hw_string* v; - - kh_foreach(http_request_cache, k, v, - { - free((char*)k); - free(v->value); - free(v); - }); - +void free_http_request_cache(khash_t(string_hashmap) * http_request_cache) { + const char *k; + hw_string *v; + + kh_foreach(http_request_cache, k, v, { + free((char *)k); + free(v->value); + free(v); + }); + kh_destroy_string_hashmap(http_request_cache); uv_key_set(&thread_cache_key, NULL); } -void create_cached_http_request(khash_t(string_hashmap)* http_request_cache, const char* http_status) -{ - hw_string* cache_entry = malloc(sizeof(hw_string)); - cache_entry->value = calloc(1024, 1); - cache_entry->length = 0; +void create_cached_http_request(khash_t(string_hashmap) * http_request_cache, const char *http_status) { + hw_string *cache_entry = malloc(sizeof(hw_string)); + cache_entry->value = calloc(1024, 1); + cache_entry->length = 0; hw_string status; status.length = strlen(http_status); - status.value = http_status; - + status.value = http_status; + append_string(cache_entry, http_v1_1); append_string(cache_entry, &status); APPENDSTRING(cache_entry, CRLF); @@ -83,9 +75,9 @@ void create_cached_http_request(khash_t(string_hashmap)* http_request_cache, con // Add the current time. time_t curtime; time(&curtime); - char* current_time = ctime(&curtime); + char *current_time = ctime(&curtime); hw_string current_datetime; - current_datetime.value = current_time; + current_datetime.value = current_time; current_datetime.length = strlen(current_time); APPENDSTRING(cache_entry, "Date: "); append_string(cache_entry, ¤t_datetime); @@ -93,60 +85,48 @@ void create_cached_http_request(khash_t(string_hashmap)* http_request_cache, con set_cached_request(http_request_cache, http_status, cache_entry); } -void set_cached_request(khash_t(string_hashmap)* http_request_cache, char* http_status, hw_string* cache_entry) -{ - int ret; +void set_cached_request(khash_t(string_hashmap) * http_request_cache, char *http_status, hw_string *cache_entry) { + int ret; khiter_t key; key = kh_get(string_hashmap, http_request_cache, http_status); - if (key == kh_end(http_request_cache)) - { - key = kh_put(string_hashmap, http_request_cache, dupstr(http_status), &ret); + if (key == kh_end(http_request_cache)) { + key = kh_put(string_hashmap, http_request_cache, dupstr(http_status), &ret); kh_value(http_request_cache, key) = cache_entry; } } -hw_string* get_cached_request(const char* http_status) -{ - int is_missing = 0; - void* val; - khash_t(string_hashmap)* http_request_cache; +hw_string *get_cached_request(const char *http_status) { + int is_missing = 0; + void *val; + khash_t(string_hashmap) * http_request_cache; khiter_t key = 0; /* This thread hasn't created a response cache so create one */ http_request_cache = uv_key_get(&thread_cache_key); - if (http_request_cache == NULL) - { + if (http_request_cache == NULL) { http_request_cache = kh_init(string_hashmap); uv_key_set(&thread_cache_key, http_request_cache); } - + key = kh_get(string_hashmap, http_request_cache, http_status); - if (key == kh_end(http_request_cache)) - { + if (key == kh_end(http_request_cache)) { create_cached_http_request(http_request_cache, http_status); - } - else - { + } else { val = kh_value(http_request_cache, key); } - + key = kh_get(string_hashmap, http_request_cache, http_status); - if (key == kh_end(http_request_cache)) - { + if (key == kh_end(http_request_cache)) { is_missing = 1; - } - else - { - val = kh_value(http_request_cache, key); + } else { + val = kh_value(http_request_cache, key); is_missing = 0; } - if (is_missing) - { + if (is_missing) { return NULL; } return val; } - diff --git a/srcs/httpserver/src/haywire/http_response_cache.h b/srcs/httpserver/src/haywire/http_response_cache.h index fb04b4e..b48df67 100644 --- a/srcs/httpserver/src/haywire/http_response_cache.h +++ b/srcs/httpserver/src/haywire/http_response_cache.h @@ -2,6 +2,6 @@ #include "uv.h" #include "haywire.h" -void initialize_http_request_cache(); -hw_string* get_cached_request(const char* http_status); -void http_request_cache_configure_listener(uv_loop_t* loop, uv_async_t* handle); +void initialize_http_request_cache(); +hw_string *get_cached_request(const char *http_status); +void http_request_cache_configure_listener(uv_loop_t *loop, uv_async_t *handle); diff --git a/srcs/httpserver/src/haywire/http_server.c b/srcs/httpserver/src/haywire/http_server.c index 89d7b97..448538b 100644 --- a/srcs/httpserver/src/haywire/http_server.c +++ b/srcs/httpserver/src/haywire/http_server.c @@ -1,6 +1,6 @@ #ifdef PLATFORM_POSIX #include -#endif // PLATFORM_POSIX +#endif// PLATFORM_POSIX #include #include @@ -19,74 +19,72 @@ #include "configuration/configuration.h" #include "http_connection.h" #include "http_request.h" +#include "misc.h" #define UVERR(err, msg) dzlog_error("%s: %s\n", msg, uv_strerror(err)) - //fprintf(stderr, "%s: %s\n", msg, uv_strerror(err)) -#define CHECK(r, msg) \ -if (r) { \ -uv_err_t err = uv_last_error(uv_loop); \ -UVERR(err, msg); \ -exit(1); \ -} +//fprintf(stderr, "%s: %s\n", msg, uv_strerror(err)) +#if 0 +#define CHECK(r, msg) \ + if (r) { \ + uv_err_t err = uv_last_error(uv_loop); \ + UVERR(err, msg); \ + exit(1); \ + } +#endif -KHASH_MAP_INIT_STR(string_hashmap, hw_route_entry*) +KHASH_MAP_INIT_STR(string_hashmap, hw_route_entry *) -configuration* config; -static uv_tcp_t server; +configuration *config; +static uv_tcp_t server; static http_parser_settings parser_settings; -static struct sockaddr_in listen_address; +static struct sockaddr_in listen_address; -uv_loop_t* uv_loop; -void* routes; -hw_string* http_v1_0; -hw_string* http_v1_1; -hw_string* server_name; -int listener_count; -uv_async_t* listener_async_handles; -uv_loop_t* listener_event_loops; -uv_barrier_t* listeners_created_barrier; +uv_loop_t *uv_loop; +void *routes; +//hw_string* http_v1_0; +hw_string *http_v1_1; +hw_string *server_name; +int listener_count; +uv_async_t *listener_async_handles; +//uv_loop_t* listener_event_loops; +uv_barrier_t *listeners_created_barrier; -int hw_init_with_config(configuration* c) -{ +int hw_init_with_config(configuration *c) { #ifdef DEBUG char route[] = "/stats"; hw_http_add_route(route, get_server_stats, NULL); #endif /* DEBUG */ /* Copy the configuration */ - config = malloc(sizeof(configuration)); + config = malloc(sizeof(configuration)); config->http_listen_address = dupstr(c->http_listen_address); - config->http_listen_port = c->http_listen_port; - config->thread_count = c->thread_count; - config->tcp_nodelay = c->tcp_nodelay; - config->listen_backlog = c->listen_backlog? c->listen_backlog : SOMAXCONN; - config->parser = dupstr(c->parser); - config->balancer = dupstr(c->balancer); - config->max_request_size = c->max_request_size; + config->http_listen_port = c->http_listen_port; + config->thread_count = c->thread_count; + config->tcp_nodelay = c->tcp_nodelay; + config->listen_backlog = c->listen_backlog ? c->listen_backlog : SOMAXCONN; + config->parser = dupstr(c->parser); + config->balancer = dupstr(c->balancer); + config->max_request_size = c->max_request_size; - http_v1_0 = create_string("HTTP/1.0 "); - http_v1_1 = create_string("HTTP/1.1 "); + http_v1_0 = create_string("HTTP/1.0 "); + http_v1_1 = create_string("HTTP/1.1 "); server_name = create_string("Server: Haywire/master"); - if (strcmp(config->parser, "http_parser") == 0) - { + if (strcmp(config->parser, "http_parser") == 0) { http_stream_on_read = &http_stream_on_read_http_parser; } http_server_write_response = &http_server_write_response_single; return 0; } -int hw_init_from_config(char* configuration_filename) -{ - configuration* config = load_configuration(configuration_filename); - if (config == NULL) - { +int hw_init_from_config(char *configuration_filename) { + configuration *config = load_configuration(configuration_filename); + if (config == NULL) { return 1; } return hw_init_with_config(config); } -void print_configuration() -{ +void print_configuration() { #if 0 dzlog_debug("Address: %s\n\tPort: %d\n\tThreads: %d\n\tBalancer: %s\n\t" "Parser: %s\n\tTCP No Delay: %s\n\tListen backlog: %d\n\tMaximum request size: %d\n", @@ -101,18 +99,15 @@ void print_configuration() #endif } -http_connection* create_http_connection() -{ - http_connection* connection = calloc(1, sizeof(http_connection)); - connection->buffer = http_request_buffer_init(config->max_request_size); +http_connection *create_http_connection() { + http_connection *connection = calloc(1, sizeof(http_connection)); + connection->buffer = http_request_buffer_init(config->max_request_size); INCREMENT_STAT(stat_connections_created_total); return connection; } -void free_http_connection(http_connection* connection) -{ - if (connection->request) - { +void free_http_connection(http_connection *connection) { + if (connection->request) { free_http_request(connection->request); } http_request_buffer_destroy(connection->buffer); @@ -120,220 +115,207 @@ void free_http_connection(http_connection* connection) INCREMENT_STAT(stat_connections_destroyed_total); } -void set_route(void* hashmap, char* name, hw_route_entry* route_entry) -{ - int ret; +void set_route(void *hashmap, char *name, hw_route_entry *route_entry) { + int ret; khiter_t k; khash_t(string_hashmap) *h = hashmap; - k = kh_put(string_hashmap, h, dupstr(name), &ret); - kh_value(h, k) = route_entry; + k = kh_put(string_hashmap, h, dupstr(name), &ret); + kh_value(h, k) = route_entry; } -void hw_http_add_route(char *route, http_request_callback callback, void* user_data) -{ - hw_route_entry* route_entry = malloc(sizeof(hw_route_entry)); - route_entry->callback = callback; - route_entry->user_data = user_data; - - if (routes == NULL) - { +void hw_http_add_route(char *route, http_request_callback callback, void *user_data) { + hw_route_entry *route_entry = malloc(sizeof(hw_route_entry)); + route_entry->callback = callback; + route_entry->user_data = user_data; + + if (routes == NULL) { routes = kh_init(string_hashmap); } set_route(routes, route, route_entry); - dzlog_debug("Added route %s\n", route); // TODO: Replace with logging instead. + dzlog_debug("Added route %s\n", route);// TODO: Replace with logging instead. } -void free_http_server() -{ +void free_http_server() { /* TODO: Shut down accepting incoming requests */ khash_t(string_hashmap) *h = routes; - const char* k; - const char* v; - kh_foreach(h, k, v, { free((char*)k); free((char*)v); }); + const char *k; + const char *v; + kh_foreach(h, k, v, { + free((char *)k); + free((char *)v); + }); kh_destroy(string_hashmap, routes); } -int hw_http_open() -{ - int threads = config->thread_count; - uv_async_t* service_handle = 0; +int hw_http_open() { + int threads = (int)config->thread_count; + uv_async_t *service_handle; - if (routes == NULL) - { + if (routes == NULL) { routes = kh_init(string_hashmap); } - parser_settings.on_header_field = http_request_on_header_field; - parser_settings.on_header_value = http_request_on_header_value; + parser_settings.on_header_field = http_request_on_header_field; + parser_settings.on_header_value = http_request_on_header_value; parser_settings.on_headers_complete = http_request_on_headers_complete; - parser_settings.on_body = http_request_on_body; - parser_settings.on_message_begin = http_request_on_message_begin; + parser_settings.on_body = http_request_on_body; + parser_settings.on_message_begin = http_request_on_message_begin; parser_settings.on_message_complete = http_request_on_message_complete; - parser_settings.on_url = http_request_on_url; - + parser_settings.on_url = http_request_on_url; + #ifdef UNIX signal(SIGPIPE, SIG_IGN); -#endif // UNIX - +#endif// UNIX + listener_count = threads; - + /* TODO: Use the return values from uv_tcp_init() and uv_tcp_bind() */ uv_loop = uv_default_loop(); - + listener_async_handles = calloc(listener_count, sizeof(uv_async_t)); - listener_event_loops = calloc(listener_count, sizeof(uv_loop_t)); - + listener_event_loops = calloc(listener_count, sizeof(uv_loop_t)); + listeners_created_barrier = malloc(sizeof(uv_barrier_t)); uv_barrier_init(listeners_created_barrier, listener_count + 1); - + service_handle = malloc(sizeof(uv_async_t)); uv_async_init(uv_loop, service_handle, NULL); - - if (listener_count == 0) - { + + if (listener_count == 0) { /* If running single threaded there is no need to use the IPC pipe - to distribute requests between threads so lets avoid the IPC overhead */ + to distribute requests between threads so let's avoid the IPC overhead */ int rc; rc = uv_tcp_init_ex(uv_loop, &server, AF_INET); - if (rc != 0) - { + if (rc != 0) { dzlog_warn("TWO %d\n", rc); } - - if (strcmp(config->balancer, "reuseport") == 0) - { + + if (strcmp(config->balancer, "reuseport") == 0) { uv_os_fd_t fd; - int on = 1; - rc = uv_fileno(&server, &fd); - if (rc != 0) - { + int on = 1; + rc = uv_fileno(&server, &fd); + if (rc != 0) { dzlog_warn("ONE %d\n", rc); } - rc = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, (char*)&on, sizeof(on)); - if (rc != 0) - { + rc = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, (char *)&on, sizeof(on)); + if (rc != 0) { dzlog_warn("THREE %d\n", errno); } } - + initialize_http_request_cache(); http_request_cache_configure_listener(uv_loop, NULL); - - uv_ip4_addr(config->http_listen_address, config->http_listen_port, &listen_address); - uv_tcp_bind(&server, (const struct sockaddr*)&listen_address, 0); - + + uv_ip4_addr(config->http_listen_address, (int)config->http_listen_port, &listen_address); + uv_tcp_bind(&server, (const struct sockaddr *)&listen_address, 0); + if (config->tcp_nodelay) { uv_tcp_nodelay(&server, 1); } - - uv_listen((uv_stream_t*)&server, config->listen_backlog, http_stream_on_connect); + + uv_listen((uv_stream_t *)&server, (int)config->listen_backlog, http_stream_on_connect); print_configuration(); dzlog_debug("Listening...\n"); //uv_run(uv_loop, UV_RUN_DEFAULT); - } - else if (listener_count > 0 && strcmp(config->balancer, "ipc") == 0) - { - int i = 0; + } else if (listener_count > 0 && strcmp(config->balancer, "ipc") == 0) { + int i; - /* If we are running multi-threaded spin up the dispatcher that uses + /* If we are running multithreaded spin up the dispatcher that uses an IPC pipe to send socket connection requests to listening threads */ - struct server_ctx* servers; + struct server_ctx *servers; servers = calloc(threads, sizeof(servers[0])); - for (i = 0; i < threads; i++) - { - int rc = 0; - struct server_ctx* ctx = servers + i; - ctx->index = i; - ctx->listen_backlog = config->listen_backlog; - - rc = uv_sem_init(&ctx->semaphore, 0); - rc = uv_thread_create(&ctx->thread_id, connection_consumer_start, ctx); + for (i = 0; i < threads; i++) { + //int rc; + struct server_ctx *ctx = servers + i; + ctx->index = i; + ctx->listen_backlog = config->listen_backlog; + + uv_sem_init(&ctx->semaphore, 0); + uv_thread_create(&ctx->thread_id, connection_consumer_start, ctx); } - + uv_barrier_wait(listeners_created_barrier); initialize_http_request_cache(); - - start_connection_dispatching(UV_TCP, threads, servers, config->http_listen_address, config->http_listen_port, config->tcp_nodelay, config->listen_backlog); - } - else if (listener_count > 0 && strcmp(config->balancer, "reuseport") == 0) - { - struct server_ctx* servers; + + start_connection_dispatching(UV_TCP, + threads, + servers, + config->http_listen_address, + (int)config->http_listen_port, + config->tcp_nodelay, + (int)config->listen_backlog); + } else if (listener_count > 0 && strcmp(config->balancer, "reuseport") == 0) { + struct server_ctx *servers; servers = calloc(threads, sizeof(servers[0])); - - for (int i = 0; i < threads; i++) - { - struct server_ctx* ctx = servers + i; - ctx->index = i; - int rc = uv_thread_create(&ctx->thread_id, reuseport_thread_start, ctx); + + for (int i = 0; i < threads; i++) { + struct server_ctx *ctx = servers + i; + ctx->index = i; + uv_thread_create(&ctx->thread_id, reuseport_thread_start, ctx); } - + print_configuration(); dzlog_debug("Listening...\n"); //uv_run(uv_loop, UV_RUN_DEFAULT); } - + return 0; } -void reuseport_thread_start(void *arg) -{ - int rc; - struct server_ctx* ctx; - uv_loop_t* loop; - uv_tcp_t svr; - - ctx = arg; - loop = uv_loop_new(); +void reuseport_thread_start(void *arg) { + int rc; + struct server_ctx *ctx; + uv_loop_t *loop; + + ctx = arg; + loop = uv_loop_new(); listener_event_loops[ctx->index] = *loop; - + initialize_http_request_cache(); http_request_cache_configure_listener(loop, &listener_async_handles[ctx->index]); - + struct sockaddr_in addr; - uv_tcp_t server; - - rc = uv_tcp_init_ex(loop, &server, AF_INET); - uv_ip4_addr(config->http_listen_address, config->http_listen_port, &addr); - + uv_tcp_t server; + + uv_tcp_init_ex(loop, &server, AF_INET); + uv_ip4_addr(config->http_listen_address, (int)config->http_listen_port, &addr); + uv_os_fd_t fd; - int on = 1; + int on = 1; uv_fileno(&server, &fd); - rc = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, (char*)&on, sizeof(on)); - if (rc != 0) - { + rc = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, (char *)&on, sizeof(on)); + if (rc != 0) { dzlog_warn("%d\n", errno); } - - uv_tcp_bind(&server, (const struct sockaddr*)&addr, 0); - int r = uv_listen((uv_stream_t*) &server, 128, http_stream_on_connect); - rc = uv_run(loop, UV_RUN_DEFAULT); + uv_tcp_bind(&server, (const struct sockaddr *)&addr, 0); + uv_listen((uv_stream_t *)&server, 128, http_stream_on_connect); + + uv_run(loop, UV_RUN_DEFAULT); uv_loop_delete(loop); } -void http_stream_on_connect(uv_stream_t* stream, int status) -{ - http_connection* connection = create_http_connection(); +void http_stream_on_connect(uv_stream_t *stream, int UNUSED(status)) { + http_connection *connection = create_http_connection(); uv_tcp_init(stream->loop, &connection->stream); http_parser_init(&connection->parser, HTTP_REQUEST); - + connection->parser.data = connection; connection->stream.data = connection; /* TODO: Use the return values from uv_accept() and uv_read_start() */ - uv_accept(stream, (uv_stream_t*)&connection->stream); + uv_accept(stream, (uv_stream_t *)&connection->stream); connection->state = OPEN; - uv_read_start((uv_stream_t*)&connection->stream, http_stream_on_alloc, http_stream_on_read); + uv_read_start((uv_stream_t *)&connection->stream, http_stream_on_alloc, http_stream_on_read); } -void http_stream_on_alloc(uv_handle_t* client, size_t suggested_size, uv_buf_t* buf) -{ - http_connection* connection = (http_connection*)client->data; +void http_stream_on_alloc(uv_handle_t *client, size_t suggested_size, uv_buf_t *buf) { + http_connection *connection = (http_connection *)client->data; - bool success = http_request_buffer_alloc(connection->buffer, suggested_size); + bool success = http_request_buffer_alloc(connection->buffer, suggested_size); hw_request_buffer_chunk chunk; - chunk.size = 0; + chunk.size = 0; chunk.buffer = NULL; if (success) { @@ -345,28 +327,26 @@ void http_stream_on_alloc(uv_handle_t* client, size_t suggested_size, uv_buf_t* *buf = uv_buf_init(chunk.buffer, chunk.size); } -void http_stream_on_close(uv_handle_t* handle) -{ - uv_handle_t* stream = handle; - http_connection* connection = stream->data; +void http_stream_on_close(uv_handle_t *handle) { + uv_handle_t *stream = handle; + http_connection *connection = stream->data; if (connection->state != CLOSED) { - connection->state = CLOSED; - http_connection* connection = (http_connection*)handle->data; + connection->state = CLOSED; + http_connection *connection = (http_connection *)handle->data; free_http_connection(connection); } } -void http_stream_close_connection(http_connection* connection) { +void http_stream_close_connection(http_connection *connection) { if (connection->state == OPEN) { connection->state = CLOSING; uv_close(&connection->stream, http_stream_on_close); } } -void handle_request_error(http_connection* connection) -{ - uv_handle_t* stream = &connection->stream; +void handle_request_error(http_connection *connection) { + uv_handle_t *stream = &connection->stream; if (connection->state == OPEN) { uv_read_stop(stream); @@ -384,8 +364,7 @@ void handle_request_error(http_connection* connection) } } -void handle_bad_request(http_connection* connection) -{ +void handle_bad_request(http_connection *connection) { if (connection->request) { connection->request->state = BAD_REQUEST; } @@ -393,8 +372,7 @@ void handle_bad_request(http_connection* connection) handle_request_error(connection); } -void handle_buffer_exceeded_error(http_connection* connection) -{ +void handle_buffer_exceeded_error(http_connection *connection) { if (connection->request) { connection->request->state = SIZE_EXCEEDED; } @@ -402,8 +380,7 @@ void handle_buffer_exceeded_error(http_connection* connection) handle_request_error(connection); } -void handle_internal_error(http_connection* connection) -{ +void handle_internal_error(http_connection *connection) { if (connection->request) { connection->request->state = INTERNAL_ERROR; } @@ -411,25 +388,23 @@ void handle_internal_error(http_connection* connection) handle_request_error(connection); } -void http_stream_on_shutdown(uv_shutdown_t* req, int status) -{ - http_connection* connection = req->data; - uv_handle_t* stream = &connection->stream; +void http_stream_on_shutdown(uv_shutdown_t *req, int UNUSED(status)) { + http_connection *connection = req->data; + // uv_handle_t *stream = &connection->stream; if (connection->state == OPEN) { http_stream_close_connection(connection); } free(req); } -void http_stream_on_read_http_parser(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf) -{ - http_connection* connection = (http_connection*)tcp->data; +void http_stream_on_read_http_parser(uv_stream_t *tcp, ssize_t nread, const uv_buf_t *buf) { + http_connection *connection = (http_connection *)tcp->data; if (nread > 0) { /* Need to tell the buffer that we care about the next nread bytes */ http_request_buffer_consume(connection->buffer, nread); - http_parser_execute(&connection->parser, &parser_settings, (const char*) buf->base, nread); + http_parser_execute(&connection->parser, &parser_settings, (const char *)buf->base, nread); if (connection->parser.http_errno) { handle_bad_request(connection); @@ -443,16 +418,13 @@ void http_stream_on_read_http_parser(uv_stream_t* tcp, ssize_t nread, const uv_b } } else if (nread == 0) { /* no-op - there's no data to be read, but there might be later */ - } - else if (nread == UV_ENOBUFS) { + } else if (nread == UV_ENOBUFS) { handle_buffer_exceeded_error(connection); - } - else if (nread == UV_EOF){ - uv_shutdown_t* req = malloc(sizeof(uv_shutdown_t)); - req->data = connection; + } else if (nread == UV_EOF) { + uv_shutdown_t *req = malloc(sizeof(uv_shutdown_t)); + req->data = connection; uv_shutdown(req, &connection->stream, http_stream_on_shutdown); - } - else if (nread == UV_ECONNRESET || nread == UV_ECONNABORTED) { + } else if (nread == UV_ECONNRESET || nread == UV_ECONNABORTED) { /* Let's close the connection as the other peer just disappeared */ http_stream_close_connection(connection); } else { @@ -462,30 +434,28 @@ void http_stream_on_read_http_parser(uv_stream_t* tcp, ssize_t nread, const uv_b } } -void http_server_cleanup_write(char* response_string, hw_write_context* write_context, uv_write_t* write_req) -{ +void http_server_cleanup_write(char *response_string, hw_write_context *write_context, uv_write_t *write_req) { free(response_string); free(write_context); free(write_req); } -int http_server_write_response_single(hw_write_context* write_context, hw_string* response) -{ - http_connection* connection = write_context->connection; +int http_server_write_response_single(hw_write_context *write_context, hw_string *response) { + http_connection *connection = write_context->connection; if (connection->state == OPEN) { - uv_write_t *write_req = (uv_write_t *) malloc(sizeof(*write_req) + sizeof(uv_buf_t)); - uv_buf_t *resbuf = (uv_buf_t *) (write_req + 1); + uv_write_t *write_req = (uv_write_t *)malloc(sizeof(*write_req) + sizeof(uv_buf_t)); + uv_buf_t *resbuf = (uv_buf_t *)(write_req + 1); resbuf->base = response->value; - resbuf->len = response->length; + resbuf->len = response->length; write_req->data = write_context; - uv_stream_t *stream = (uv_stream_t *) &write_context->connection->stream; + uv_stream_t *stream = (uv_stream_t *)&write_context->connection->stream; if (uv_is_writable(stream)) { - /* Ensuring that the the response can still be written. */ + /* Ensuring that the response can still be written. */ uv_write(write_req, stream, resbuf, 1, http_server_after_write); /* TODO: Use the return values from uv_write() */ } else { @@ -497,23 +467,20 @@ int http_server_write_response_single(hw_write_context* write_context, hw_string return 0; } -void http_server_after_write(uv_write_t* req, int status) -{ - hw_write_context* write_context = (hw_write_context*)req->data; - uv_buf_t *resbuf = (uv_buf_t *)(req+1); - uv_handle_t* stream = (uv_handle_t*) req->handle; +void http_server_after_write(uv_write_t *req, int UNUSED(status)) { + hw_write_context *write_context = (hw_write_context *)req->data; + uv_buf_t *resbuf = (uv_buf_t *)(req + 1); + //uv_handle_t *stream = (uv_handle_t *)req->handle; - http_connection* connection = write_context->connection; + http_connection *connection = write_context->connection; if (!connection->keep_alive && connection->state == OPEN) { http_stream_close_connection(connection); } - - if (write_context->callback) - { + + if (write_context->callback) { write_context->callback(write_context->user_data); } http_server_cleanup_write(resbuf->base, write_context, req); } - diff --git a/srcs/httpserver/src/haywire/http_server.h b/srcs/httpserver/src/haywire/http_server.h index 7861cf4..ae41451 100644 --- a/srcs/httpserver/src/haywire/http_server.h +++ b/srcs/httpserver/src/haywire/http_server.h @@ -5,36 +5,34 @@ #include "http_parser.h" #include "http_response.h" -typedef struct -{ +typedef struct { http_request_callback callback; - void* user_data; + void *user_data; } hw_route_entry; -union stream_handle -{ +union stream_handle { uv_pipe_t pipe; - uv_tcp_t tcp; + uv_tcp_t tcp; }; -extern void* routes; -extern uv_loop_t* uv_loop; -extern hw_string* http_v1_0; -extern hw_string* http_v1_1; -extern hw_string* server_name; -extern int listener_count; -extern uv_async_t* listener_async_handles; -extern uv_loop_t* listener_event_loops; -extern uv_barrier_t* listeners_created_barrier; +extern void *routes; +extern uv_loop_t *uv_loop; +extern hw_string *http_v1_0; +extern hw_string *http_v1_1; +extern hw_string *server_name; +extern int listener_count; +extern uv_async_t *listener_async_handles; +extern uv_loop_t *listener_event_loops; +extern uv_barrier_t *listeners_created_barrier; -void (*http_stream_on_read)(uv_stream_t*, ssize_t, const uv_buf_t*); -int (*http_server_write_response)(hw_write_context*, hw_string*); +void (*http_stream_on_read)(uv_stream_t *, ssize_t, const uv_buf_t *); +int (*http_server_write_response)(hw_write_context *, hw_string *); -http_connection* create_http_connection(); -void http_stream_on_connect(uv_stream_t* stream, int status); -void http_stream_on_alloc(uv_handle_t* client, size_t suggested_size, uv_buf_t* buf); -void http_stream_on_close(uv_handle_t* handle); -int http_server_write_response_single(hw_write_context* write_context, hw_string* response); -void http_server_after_write(uv_write_t* req, int status); -void http_stream_on_read_http_parser(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf); -void reuseport_thread_start(void *arg); +http_connection *create_http_connection(); +void http_stream_on_connect(uv_stream_t *stream, int status); +void http_stream_on_alloc(uv_handle_t *client, size_t suggested_size, uv_buf_t *buf); +void http_stream_on_close(uv_handle_t *handle); +int http_server_write_response_single(hw_write_context *write_context, hw_string *response); +void http_server_after_write(uv_write_t *req, int status); +void http_stream_on_read_http_parser(uv_stream_t *tcp, ssize_t nread, const uv_buf_t *buf); +void reuseport_thread_start(void *arg); diff --git a/srcs/httpserver/src/haywire/hw_string.c b/srcs/httpserver/src/haywire/hw_string.c index d28e8b5..def9ba4 100644 --- a/srcs/httpserver/src/haywire/hw_string.c +++ b/srcs/httpserver/src/haywire/hw_string.c @@ -3,27 +3,25 @@ #include #include "haywire.h" -hw_string* create_string(const char* value) -{ - int length = (int)strlen(value); - hw_string* str = malloc(sizeof(hw_string)); - str->value = malloc(length); +hw_string *create_string(const char *value) { + int length = (int)strlen(value); + hw_string *str = malloc(sizeof(hw_string)); + str->value = malloc(length); memcpy(str->value, value, length); str->length = length; return str; } -hw_string* hw_strdup(hw_string* tocopy) -{ - hw_string* str = malloc(sizeof(hw_string)); - str->value = tocopy->value; - str->length = tocopy->length; +hw_string *hw_strdup(hw_string *tocopy) { + hw_string *str = malloc(sizeof(hw_string)); + str->value = tocopy->value; + str->length = tocopy->length; return str; } -int hw_strcmp(hw_string* a, hw_string* b) { +int hw_strcmp(hw_string *a, hw_string *b) { int ret; - + if (a->length > b->length) { ret = strncmp(a->value, b->value, b->length); if (!ret) { @@ -37,40 +35,35 @@ int hw_strcmp(hw_string* a, hw_string* b) { ret = -1; } } - + return ret; } -void append_string(hw_string* destination, hw_string* source) -{ - void* location = (void*) (destination->value + destination->length); +void append_string(hw_string *destination, hw_string *source) { + void *location = (void *)(destination->value + destination->length); memcpy(location, source->value, source->length); destination->length += source->length; } /* Added because of http://stackoverflow.com/questions/8359966/strdup-returning-address-out-of-bounds */ -char* dupstr(const char *s) -{ - char* result = malloc(strlen(s) + 1); - if (result != NULL) - { +char *dupstr(const char *s) { + char *result = malloc(strlen(s) + 1); + if (result != NULL) { strcpy(result, s); } return result; } -void string_from_int(hw_string* str, int val, int base) -{ - static char buf[32] = {0}; - int i = 30; - int length = 0; - - for(; val && i ; --i, val /= base) - { - buf[i] = "0123456789abcdef"[val % base]; +void string_from_int(hw_string *str, int val, int base) { + static char buf[32] = {0}; + int i = 30; + int length = 0; + + for (; val && i; --i, val /= base) { + buf[i] = "0123456789abcdef"[val % base]; length++; } - - str->value = &buf[i+1]; + + str->value = &buf[i + 1]; str->length = length; } \ No newline at end of file diff --git a/srcs/httpserver/src/haywire/hw_string.h b/srcs/httpserver/src/haywire/hw_string.h index 0af8d4f..cf27bc3 100644 --- a/srcs/httpserver/src/haywire/hw_string.h +++ b/srcs/httpserver/src/haywire/hw_string.h @@ -1,9 +1,9 @@ #pragma once -hw_string* create_string(const char* value); -int hw_strcmp(hw_string* a, hw_string* b); -hw_string* hw_strdup(hw_string* tocopy); -void append_string(hw_string* destination, hw_string* source); -char* dupstr(const char *s); -void string_from_int(hw_string* str, int val, int base); -int hw_strcmp(hw_string* a, hw_string* b); +hw_string *create_string(const char *value); +int hw_strcmp(hw_string *a, hw_string *b); +hw_string *hw_strdup(hw_string *tocopy); +void append_string(hw_string *destination, hw_string *source); +char *dupstr(const char *s); +void string_from_int(hw_string *str, int val, int base); +int hw_strcmp(hw_string *a, hw_string *b); diff --git a/srcs/httpserver/src/haywire/khash.h b/srcs/httpserver/src/haywire/khash.h index 3aede7e..43f898c 100644 --- a/srcs/httpserver/src/haywire/khash.h +++ b/srcs/httpserver/src/haywire/khash.h @@ -113,7 +113,6 @@ * Added destructor */ - #ifndef __AC_KHASH_H #define __AC_KHASH_H @@ -134,7 +133,7 @@ #if UINT_MAX == 0xffffffffu typedef unsigned int khint32_t; #elif ULONG_MAX == 0xffffffffu -typedef unsigned long khint32_t; +typedef unsigned long khint32_t; #endif #if ULONG_MAX == ULLONG_MAX @@ -150,30 +149,31 @@ typedef unsigned long long khint64_t; #endif typedef khint32_t khint_t; -typedef khint_t khiter_t; +typedef khint_t khiter_t; -#define __ac_isempty(flag, i) ((flag[i>>4]>>((i&0xfU)<<1))&2) -#define __ac_isdel(flag, i) ((flag[i>>4]>>((i&0xfU)<<1))&1) -#define __ac_iseither(flag, i) ((flag[i>>4]>>((i&0xfU)<<1))&3) -#define __ac_set_isdel_false(flag, i) (flag[i>>4]&=~(1ul<<((i&0xfU)<<1))) -#define __ac_set_isempty_false(flag, i) (flag[i>>4]&=~(2ul<<((i&0xfU)<<1))) -#define __ac_set_isboth_false(flag, i) (flag[i>>4]&=~(3ul<<((i&0xfU)<<1))) -#define __ac_set_isdel_true(flag, i) (flag[i>>4]|=1ul<<((i&0xfU)<<1)) +#define __ac_isempty(flag, i) ((flag[i >> 4] >> ((i & 0xfU) << 1)) & 2) +#define __ac_isdel(flag, i) ((flag[i >> 4] >> ((i & 0xfU) << 1)) & 1) +#define __ac_iseither(flag, i) ((flag[i >> 4] >> ((i & 0xfU) << 1)) & 3) +#define __ac_set_isdel_false(flag, i) (flag[i >> 4] &= ~(1ul << ((i & 0xfU) << 1))) +#define __ac_set_isempty_false(flag, i) (flag[i >> 4] &= ~(2ul << ((i & 0xfU) << 1))) +#define __ac_set_isboth_false(flag, i) (flag[i >> 4] &= ~(3ul << ((i & 0xfU) << 1))) +#define __ac_set_isdel_true(flag, i) (flag[i >> 4] |= 1ul << ((i & 0xfU) << 1)) -#define __ac_fsize(m) ((m) < 16? 1 : (m)>>4) +#define __ac_fsize(m) ((m) < 16 ? 1 : (m) >> 4) #ifndef kroundup32 -#define kroundup32(x) (--(x), (x)|=(x)>>1, (x)|=(x)>>2, (x)|=(x)>>4, (x)|=(x)>>8, (x)|=(x)>>16, ++(x)) +#define kroundup32(x) \ + (--(x), (x) |= (x) >> 1, (x) |= (x) >> 2, (x) |= (x) >> 4, (x) |= (x) >> 8, (x) |= (x) >> 16, ++(x)) #endif #ifndef kcalloc -#define kcalloc(N,Z) calloc(N,Z) +#define kcalloc(N, Z) calloc(N, Z) #endif #ifndef kmalloc #define kmalloc(Z) malloc(Z) #endif #ifndef krealloc -#define krealloc(P,Z) realloc(P,Z) +#define krealloc(P, Z) realloc(P, Z) #endif #ifndef kfree #define kfree(P) free(P) @@ -181,179 +181,208 @@ typedef khint_t khiter_t; static const double __ac_HASH_UPPER = 0.77; -#define __KHASH_TYPE(name, khkey_t, khval_t) \ -typedef struct { \ -khint_t n_buckets, size, n_occupied, upper_bound; \ -khint32_t *flags; \ -khkey_t *keys; \ -khval_t *vals; \ -} kh_##name##_t; +#define __KHASH_TYPE(name, khkey_t, khval_t) \ + typedef struct { \ + khint_t n_buckets, size, n_occupied, upper_bound; \ + khint32_t *flags; \ + khkey_t *keys; \ + khval_t *vals; \ + } kh_##name##_t; -#define __KHASH_PROTOTYPES(name, khkey_t, khval_t) \ -extern kh_##name##_t *kh_init_##name(void); \ -extern void kh_destroy_##name(kh_##name##_t *h); \ -extern void kh_clear_##name(kh_##name##_t *h); \ -extern khint_t kh_get_##name(const kh_##name##_t *h, khkey_t key); \ -extern int kh_resize_##name(kh_##name##_t *h, khint_t new_n_buckets); \ -extern khint_t kh_put_##name(kh_##name##_t *h, khkey_t key, int *ret); \ -extern void kh_del_##name(kh_##name##_t *h, khint_t x); +#define __KHASH_PROTOTYPES(name, khkey_t, khval_t) \ + extern kh_##name##_t *kh_init_##name(void); \ + extern void kh_destroy_##name(kh_##name##_t *h); \ + extern void kh_clear_##name(kh_##name##_t *h); \ + extern khint_t kh_get_##name(const kh_##name##_t *h, khkey_t key); \ + extern int kh_resize_##name(kh_##name##_t *h, khint_t new_n_buckets); \ + extern khint_t kh_put_##name(kh_##name##_t *h, khkey_t key, int *ret); \ + extern void kh_del_##name(kh_##name##_t *h, khint_t x); -#define __KHASH_IMPL(name, SCOPE, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal) \ -SCOPE kh_##name##_t *kh_init_##name(void) { \ -return (kh_##name##_t*)kcalloc(1, sizeof(kh_##name##_t)); \ -} \ -SCOPE void kh_destroy_##name(kh_##name##_t *h) \ -{ \ -if (h) { \ -kfree((void *)h->keys); kfree(h->flags); \ -kfree((void *)h->vals); \ -kfree(h); \ -} \ -} \ -SCOPE void kh_clear_##name(kh_##name##_t *h) \ -{ \ -if (h && h->flags) { \ -memset(h->flags, 0xaa, __ac_fsize(h->n_buckets) * sizeof(khint32_t)); \ -h->size = h->n_occupied = 0; \ -} \ -} \ -SCOPE khint_t kh_get_##name(const kh_##name##_t *h, khkey_t key) \ -{ \ -if (h->n_buckets) { \ -khint_t k, i, last, mask, step = 0; \ -mask = h->n_buckets - 1; \ -k = __hash_func(key); i = k & mask; \ -last = i; \ -while (!__ac_isempty(h->flags, i) && (__ac_isdel(h->flags, i) || !__hash_equal(h->keys[i], key))) { \ -i = (i + (++step)) & mask; \ -if (i == last) return h->n_buckets; \ -} \ -return __ac_iseither(h->flags, i)? h->n_buckets : i; \ -} else return 0; \ -} \ -SCOPE int kh_resize_##name(kh_##name##_t *h, khint_t new_n_buckets) \ -{ /* This function uses 0.25*n_buckets bytes of working space instead of [sizeof(key_t+val_t)+.25]*n_buckets. */ \ -khint32_t *new_flags = 0; \ -khint_t j = 1; \ -{ \ -kroundup32(new_n_buckets); \ -if (new_n_buckets < 4) new_n_buckets = 4; \ -if (h->size >= (khint_t)(new_n_buckets * __ac_HASH_UPPER + 0.5)) j = 0; /* requested size is too small */ \ -else { /* hash table size to be changed (shrink or expand); rehash */ \ -new_flags = (khint32_t*)kmalloc(__ac_fsize(new_n_buckets) * sizeof(khint32_t)); \ -if (!new_flags) return -1; \ -memset(new_flags, 0xaa, __ac_fsize(new_n_buckets) * sizeof(khint32_t)); \ -if (h->n_buckets < new_n_buckets) { /* expand */ \ -khkey_t *new_keys = (khkey_t*)krealloc((void *)h->keys, new_n_buckets * sizeof(khkey_t)); \ -if (!new_keys) return -1; \ -h->keys = new_keys; \ -if (kh_is_map) { \ -khval_t *new_vals = (khval_t*)krealloc((void *)h->vals, new_n_buckets * sizeof(khval_t)); \ -if (!new_vals) return -1; \ -h->vals = new_vals; \ -} \ -} /* otherwise shrink */ \ -} \ -} \ -if (j) { /* rehashing is needed */ \ -for (j = 0; j != h->n_buckets; ++j) { \ -if (__ac_iseither(h->flags, j) == 0) { \ -khkey_t key = h->keys[j]; \ -khval_t val; \ -khint_t new_mask; \ -new_mask = new_n_buckets - 1; \ -if (kh_is_map) val = h->vals[j]; \ -__ac_set_isdel_true(h->flags, j); \ -while (1) { /* kick-out process; sort of like in Cuckoo hashing */ \ -khint_t k, i, step = 0; \ -k = __hash_func(key); \ -i = k & new_mask; \ -while (!__ac_isempty(new_flags, i)) i = (i + (++step)) & new_mask; \ -__ac_set_isempty_false(new_flags, i); \ -if (i < h->n_buckets && __ac_iseither(h->flags, i) == 0) { /* kick out the existing element */ \ -{ khkey_t tmp = h->keys[i]; h->keys[i] = key; key = tmp; } \ -if (kh_is_map) { khval_t tmp = h->vals[i]; h->vals[i] = val; val = tmp; } \ -__ac_set_isdel_true(h->flags, i); /* mark it as deleted in the old hash table */ \ -} else { /* write the element and jump out of the loop */ \ -h->keys[i] = key; \ -if (kh_is_map) h->vals[i] = val; \ -break; \ -} \ -} \ -} \ -} \ -if (h->n_buckets > new_n_buckets) { /* shrink the hash table */ \ -h->keys = (khkey_t*)krealloc((void *)h->keys, new_n_buckets * sizeof(khkey_t)); \ -if (kh_is_map) h->vals = (khval_t*)krealloc((void *)h->vals, new_n_buckets * sizeof(khval_t)); \ -} \ -kfree(h->flags); /* free the working space */ \ -h->flags = new_flags; \ -h->n_buckets = new_n_buckets; \ -h->n_occupied = h->size; \ -h->upper_bound = (khint_t)(h->n_buckets * __ac_HASH_UPPER + 0.5); \ -} \ -return 0; \ -} \ -SCOPE khint_t kh_put_##name(kh_##name##_t *h, khkey_t key, int *ret) \ -{ \ -khint_t x; \ -if (h->n_occupied >= h->upper_bound) { /* update the hash table */ \ -if (h->n_buckets > (h->size<<1)) { \ -if (kh_resize_##name(h, h->n_buckets - 1) < 0) { /* clear "deleted" elements */ \ -*ret = -1; return h->n_buckets; \ -} \ -} else if (kh_resize_##name(h, h->n_buckets + 1) < 0) { /* expand the hash table */ \ -*ret = -1; return h->n_buckets; \ -} \ -} /* TODO: to implement automatically shrinking; resize() already support shrinking */ \ -{ \ -khint_t k, i, site, last, mask = h->n_buckets - 1, step = 0; \ -x = site = h->n_buckets; k = __hash_func(key); i = k & mask; \ -if (__ac_isempty(h->flags, i)) x = i; /* for speed up */ \ -else { \ -last = i; \ -while (!__ac_isempty(h->flags, i) && (__ac_isdel(h->flags, i) || !__hash_equal(h->keys[i], key))) { \ -if (__ac_isdel(h->flags, i)) site = i; \ -i = (i + (++step)) & mask; \ -if (i == last) { x = site; break; } \ -} \ -if (x == h->n_buckets) { \ -if (__ac_isempty(h->flags, i) && site != h->n_buckets) x = site; \ -else x = i; \ -} \ -} \ -} \ -if (__ac_isempty(h->flags, x)) { /* not present at all */ \ -h->keys[x] = key; \ -__ac_set_isboth_false(h->flags, x); \ -++h->size; ++h->n_occupied; \ -*ret = 1; \ -} else if (__ac_isdel(h->flags, x)) { /* deleted */ \ -h->keys[x] = key; \ -__ac_set_isboth_false(h->flags, x); \ -++h->size; \ -*ret = 2; \ -} else *ret = 0; /* Don't touch h->keys[x] if present and not deleted */ \ -return x; \ -} \ -SCOPE void kh_del_##name(kh_##name##_t *h, khint_t x) \ -{ \ -if (x != h->n_buckets && !__ac_iseither(h->flags, x)) { \ -__ac_set_isdel_true(h->flags, x); \ ---h->size; \ -} \ -} +#define __KHASH_IMPL(name, SCOPE, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal) \ + SCOPE kh_##name##_t *kh_init_##name(void) { return (kh_##name##_t *)kcalloc(1, sizeof(kh_##name##_t)); } \ + SCOPE void kh_destroy_##name(kh_##name##_t *h) { \ + if (h) { \ + kfree((void *)h->keys); \ + kfree(h->flags); \ + kfree((void *)h->vals); \ + kfree(h); \ + } \ + } \ + SCOPE void kh_clear_##name(kh_##name##_t *h) { \ + if (h && h->flags) { \ + memset(h->flags, 0xaa, __ac_fsize(h->n_buckets) * sizeof(khint32_t)); \ + h->size = h->n_occupied = 0; \ + } \ + } \ + SCOPE khint_t kh_get_##name(const kh_##name##_t *h, khkey_t key) { \ + if (h->n_buckets) { \ + khint_t k, i, last, mask, step = 0; \ + mask = h->n_buckets - 1; \ + k = __hash_func(key); \ + i = k & mask; \ + last = i; \ + while (!__ac_isempty(h->flags, i) && (__ac_isdel(h->flags, i) || !__hash_equal(h->keys[i], key))) { \ + i = (i + (++step)) & mask; \ + if (i == last) \ + return h->n_buckets; \ + } \ + return __ac_iseither(h->flags, i) ? h->n_buckets : i; \ + } else \ + return 0; \ + } \ + SCOPE int kh_resize_##name( \ + kh_##name##_t *h, \ + khint_t \ + new_n_buckets) { /* This function uses 0.25*n_buckets bytes of working space instead of [sizeof(key_t+val_t)+.25]*n_buckets. */ \ + khint32_t *new_flags = 0; \ + khint_t j = 1; \ + { \ + kroundup32(new_n_buckets); \ + if (new_n_buckets < 4) \ + new_n_buckets = 4; \ + if (h->size >= (khint_t)(new_n_buckets * __ac_HASH_UPPER + 0.5)) \ + j = 0; /* requested size is too small */ \ + else { /* hash table size to be changed (shrink or expand); rehash */ \ + new_flags = (khint32_t *)kmalloc(__ac_fsize(new_n_buckets) * sizeof(khint32_t)); \ + if (!new_flags) \ + return -1; \ + memset(new_flags, 0xaa, __ac_fsize(new_n_buckets) * sizeof(khint32_t)); \ + if (h->n_buckets < new_n_buckets) { /* expand */ \ + khkey_t *new_keys = (khkey_t *)krealloc((void *)h->keys, new_n_buckets * sizeof(khkey_t)); \ + if (!new_keys) \ + return -1; \ + h->keys = new_keys; \ + if (kh_is_map) { \ + khval_t *new_vals = (khval_t *)krealloc((void *)h->vals, new_n_buckets * sizeof(khval_t)); \ + if (!new_vals) \ + return -1; \ + h->vals = new_vals; \ + } \ + } /* otherwise shrink */ \ + } \ + } \ + if (j) { /* rehashing is needed */ \ + for (j = 0; j != h->n_buckets; ++j) { \ + if (__ac_iseither(h->flags, j) == 0) { \ + khkey_t key = h->keys[j]; \ + khval_t val; \ + khint_t new_mask; \ + new_mask = new_n_buckets - 1; \ + if (kh_is_map) \ + val = h->vals[j]; \ + __ac_set_isdel_true(h->flags, j); \ + while (1) { /* kick-out process; sort of like in Cuckoo hashing */ \ + khint_t k, i, step = 0; \ + k = __hash_func(key); \ + i = k & new_mask; \ + while (!__ac_isempty(new_flags, i)) \ + i = (i + (++step)) & new_mask; \ + __ac_set_isempty_false(new_flags, i); \ + if (i < h->n_buckets && __ac_iseither(h->flags, i) == 0) { /* kick out the existing element */ \ + { \ + khkey_t tmp = h->keys[i]; \ + h->keys[i] = key; \ + key = tmp; \ + } \ + if (kh_is_map) { \ + khval_t tmp = h->vals[i]; \ + h->vals[i] = val; \ + val = tmp; \ + } \ + __ac_set_isdel_true(h->flags, i); /* mark it as deleted in the old hash table */ \ + } else { /* write the element and jump out of the loop */ \ + h->keys[i] = key; \ + if (kh_is_map) \ + h->vals[i] = val; \ + break; \ + } \ + } \ + } \ + } \ + if (h->n_buckets > new_n_buckets) { /* shrink the hash table */ \ + h->keys = (khkey_t *)krealloc((void *)h->keys, new_n_buckets * sizeof(khkey_t)); \ + if (kh_is_map) \ + h->vals = (khval_t *)krealloc((void *)h->vals, new_n_buckets * sizeof(khval_t)); \ + } \ + kfree(h->flags); /* free the working space */ \ + h->flags = new_flags; \ + h->n_buckets = new_n_buckets; \ + h->n_occupied = h->size; \ + h->upper_bound = (khint_t)(h->n_buckets * __ac_HASH_UPPER + 0.5); \ + } \ + return 0; \ + } \ + SCOPE khint_t kh_put_##name(kh_##name##_t *h, khkey_t key, int *ret) { \ + khint_t x; \ + if (h->n_occupied >= h->upper_bound) { /* update the hash table */ \ + if (h->n_buckets > (h->size << 1)) { \ + if (kh_resize_##name(h, h->n_buckets - 1) < 0) { /* clear "deleted" elements */ \ + *ret = -1; \ + return h->n_buckets; \ + } \ + } else if (kh_resize_##name(h, h->n_buckets + 1) < 0) { /* expand the hash table */ \ + *ret = -1; \ + return h->n_buckets; \ + } \ + } /* TODO: to implement automatically shrinking; resize() already support shrinking */ \ + { \ + khint_t k, i, site, last, mask = h->n_buckets - 1, step = 0; \ + x = site = h->n_buckets; \ + k = __hash_func(key); \ + i = k & mask; \ + if (__ac_isempty(h->flags, i)) \ + x = i; /* for speed up */ \ + else { \ + last = i; \ + while (!__ac_isempty(h->flags, i) && (__ac_isdel(h->flags, i) || !__hash_equal(h->keys[i], key))) { \ + if (__ac_isdel(h->flags, i)) \ + site = i; \ + i = (i + (++step)) & mask; \ + if (i == last) { \ + x = site; \ + break; \ + } \ + } \ + if (x == h->n_buckets) { \ + if (__ac_isempty(h->flags, i) && site != h->n_buckets) \ + x = site; \ + else \ + x = i; \ + } \ + } \ + } \ + if (__ac_isempty(h->flags, x)) { /* not present at all */ \ + h->keys[x] = key; \ + __ac_set_isboth_false(h->flags, x); \ + ++h->size; \ + ++h->n_occupied; \ + *ret = 1; \ + } else if (__ac_isdel(h->flags, x)) { /* deleted */ \ + h->keys[x] = key; \ + __ac_set_isboth_false(h->flags, x); \ + ++h->size; \ + *ret = 2; \ + } else \ + *ret = 0; /* Don't touch h->keys[x] if present and not deleted */ \ + return x; \ + } \ + SCOPE void kh_del_##name(kh_##name##_t *h, khint_t x) { \ + if (x != h->n_buckets && !__ac_iseither(h->flags, x)) { \ + __ac_set_isdel_true(h->flags, x); \ + --h->size; \ + } \ + } -#define KHASH_DECLARE(name, khkey_t, khval_t) \ -__KHASH_TYPE(name, khkey_t, khval_t) \ -__KHASH_PROTOTYPES(name, khkey_t, khval_t) +#define KHASH_DECLARE(name, khkey_t, khval_t) \ + __KHASH_TYPE(name, khkey_t, khval_t) \ + __KHASH_PROTOTYPES(name, khkey_t, khval_t) #define KHASH_INIT2(name, SCOPE, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal) \ -__KHASH_TYPE(name, khkey_t, khval_t) \ -__KHASH_IMPL(name, SCOPE, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal) + __KHASH_TYPE(name, khkey_t, khval_t) \ + __KHASH_IMPL(name, SCOPE, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal) #define KHASH_INIT(name, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal) \ -KHASH_INIT2(name, static kh_inline, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal) + KHASH_INIT2(name, static kh_inline, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal) /* --- BEGIN OF HASH FUNCTIONS --- */ @@ -372,7 +401,7 @@ KHASH_INIT2(name, static kh_inline, khkey_t, khval_t, kh_is_map, __hash_func, __ @param key The integer [khint64_t] @return The hash value [khint_t] */ -#define kh_int64_hash_func(key) (khint32_t)((key)>>33^(key)^(key)<<11) +#define kh_int64_hash_func(key) (khint32_t)((key) >> 33 ^ (key) ^ (key) << 11) /*! @function @abstract 64-bit integer comparison function */ @@ -382,11 +411,12 @@ KHASH_INIT2(name, static kh_inline, khkey_t, khval_t, kh_is_map, __hash_func, __ @param s Pointer to a null terminated string @return The hash value */ -static kh_inline khint_t __ac_X31_hash_string(const char *s) -{ - khint_t h = (khint_t)*s; - if (h) for (++s ; *s; ++s) h = (h << 5) - h + (khint_t)*s; - return h; +static kh_inline khint_t __ac_X31_hash_string(const char *s) { + khint_t h = (khint_t)*s; + if (h) + for (++s; *s; ++s) + h = (h << 5) - h + (khint_t)*s; + return h; } /*! @function @abstract Another interface to const char* hash function @@ -399,14 +429,13 @@ static kh_inline khint_t __ac_X31_hash_string(const char *s) */ #define kh_str_hash_equal(a, b) (strcmp(a, b) == 0) -static kh_inline khint_t __ac_Wang_hash(khint_t key) -{ +static kh_inline khint_t __ac_Wang_hash(khint_t key) { key += ~(key << 15); - key ^= (key >> 10); - key += (key << 3); - key ^= (key >> 6); + key ^= (key >> 10); + key += (key << 3); + key ^= (key >> 6); key += ~(key << 11); - key ^= (key >> 16); + key ^= (key >> 16); return key; } #define kh_int_hash_func2(k) __ac_Wang_hash((khint_t)key) @@ -544,13 +573,17 @@ static kh_inline khint_t __ac_Wang_hash(khint_t key) @param vvar Variable to which value will be assigned @param code Block of code to execute */ -#define kh_foreach(h, kvar, vvar, code) { khint_t __i; \ -for (__i = kh_begin(h); __i != kh_end(h); ++__i) { \ -if (!kh_exist(h,__i)) continue; \ -(kvar) = kh_key(h,__i); \ -(vvar) = kh_val(h,__i); \ -code; \ -} } +#define kh_foreach(h, kvar, vvar, code) \ + { \ + khint_t __i; \ + for (__i = kh_begin(h); __i != kh_end(h); ++__i) { \ + if (!kh_exist(h, __i)) \ + continue; \ + (kvar) = kh_key(h, __i); \ + (vvar) = kh_val(h, __i); \ + code; \ + } \ + } /*! @function @abstract Iterate over the values in the hash table @@ -558,12 +591,16 @@ code; \ @param vvar Variable to which value will be assigned @param code Block of code to execute */ -#define kh_foreach_value(h, vvar, code) { khint_t __i; \ -for (__i = kh_begin(h); __i != kh_end(h); ++__i) { \ -if (!kh_exist(h,__i)) continue; \ -(vvar) = kh_val(h,__i); \ -code; \ -} } +#define kh_foreach_value(h, vvar, code) \ + { \ + khint_t __i; \ + for (__i = kh_begin(h); __i != kh_end(h); ++__i) { \ + if (!kh_exist(h, __i)) \ + continue; \ + (vvar) = kh_val(h, __i); \ + code; \ + } \ + } /* More conenient interfaces */ @@ -571,47 +608,41 @@ code; \ @abstract Instantiate a hash set containing integer keys @param name Name of the hash table [symbol] */ -#define KHASH_SET_INIT_INT(name) \ -KHASH_INIT(name, khint32_t, char, 0, kh_int_hash_func, kh_int_hash_equal) +#define KHASH_SET_INIT_INT(name) KHASH_INIT(name, khint32_t, char, 0, kh_int_hash_func, kh_int_hash_equal) /*! @function @abstract Instantiate a hash map containing integer keys @param name Name of the hash table [symbol] @param khval_t Type of values [type] */ -#define KHASH_MAP_INIT_INT(name, khval_t) \ -KHASH_INIT(name, khint32_t, khval_t, 1, kh_int_hash_func, kh_int_hash_equal) +#define KHASH_MAP_INIT_INT(name, khval_t) KHASH_INIT(name, khint32_t, khval_t, 1, kh_int_hash_func, kh_int_hash_equal) /*! @function @abstract Instantiate a hash map containing 64-bit integer keys @param name Name of the hash table [symbol] */ -#define KHASH_SET_INIT_INT64(name) \ -KHASH_INIT(name, khint64_t, char, 0, kh_int64_hash_func, kh_int64_hash_equal) +#define KHASH_SET_INIT_INT64(name) KHASH_INIT(name, khint64_t, char, 0, kh_int64_hash_func, kh_int64_hash_equal) /*! @function @abstract Instantiate a hash map containing 64-bit integer keys @param name Name of the hash table [symbol] @param khval_t Type of values [type] */ -#define KHASH_MAP_INIT_INT64(name, khval_t) \ -KHASH_INIT(name, khint64_t, khval_t, 1, kh_int64_hash_func, kh_int64_hash_equal) +#define KHASH_MAP_INIT_INT64(name, khval_t) \ + KHASH_INIT(name, khint64_t, khval_t, 1, kh_int64_hash_func, kh_int64_hash_equal) typedef const char *kh_cstr_t; /*! @function @abstract Instantiate a hash map containing const char* keys @param name Name of the hash table [symbol] */ -#define KHASH_SET_INIT_STR(name) \ -KHASH_INIT(name, kh_cstr_t, char, 0, kh_str_hash_func, kh_str_hash_equal) +#define KHASH_SET_INIT_STR(name) KHASH_INIT(name, kh_cstr_t, char, 0, kh_str_hash_func, kh_str_hash_equal) /*! @function @abstract Instantiate a hash map containing const char* keys @param name Name of the hash table [symbol] @param khval_t Type of values [type] */ -#define KHASH_MAP_INIT_STR(name, khval_t) \ -KHASH_INIT(name, kh_cstr_t, khval_t, 1, kh_str_hash_func, kh_str_hash_equal) +#define KHASH_MAP_INIT_STR(name, khval_t) KHASH_INIT(name, kh_cstr_t, khval_t, 1, kh_str_hash_func, kh_str_hash_equal) #endif /* __AC_KHASH_H */ - diff --git a/srcs/httpserver/src/haywire/picohttpparser.c b/srcs/httpserver/src/haywire/picohttpparser.c index 5d47311..5dd378f 100644 --- a/srcs/httpserver/src/haywire/picohttpparser.c +++ b/srcs/httpserver/src/haywire/picohttpparser.c @@ -38,10 +38,10 @@ /* $Id$ */ #if __GNUC__ >= 3 -#define likely(x) __builtin_expect(!!(x), 1) +#define likely(x) __builtin_expect(!!(x), 1) #define unlikely(x) __builtin_expect(!!(x), 0) #else -#define likely(x) (x) +#define likely(x) (x) #define unlikely(x) (x) #endif @@ -53,55 +53,56 @@ #define IS_PRINTABLE_ASCII(c) ((unsigned char)(c)-040u < 0137u) -#define CHECK_EOF() \ - if (buf == buf_end) { \ - *ret = -2; \ - return NULL; \ +#define CHECK_EOF() \ + if (buf == buf_end) { \ + *ret = -2; \ + return NULL; \ } -#define EXPECT_CHAR(ch) \ - CHECK_EOF(); \ - if (*buf++ != ch) { \ - *ret = -1; \ - return NULL; \ +#define EXPECT_CHAR(ch) \ + CHECK_EOF(); \ + if (*buf++ != ch) { \ + *ret = -1; \ + return NULL; \ } -#define ADVANCE_TOKEN(tok, toklen) \ - do { \ - const char *tok_start = buf; \ - static const char ALIGNED(16) ranges2[] = "\000\040\177\177"; \ - int found2; \ - buf = findchar_fast(buf, buf_end, ranges2, sizeof(ranges2) - 1, &found2); \ - if (!found2) { \ - CHECK_EOF(); \ - } \ - while (1) { \ - if (*buf == ' ') { \ - break; \ - } else if (unlikely(!IS_PRINTABLE_ASCII(*buf))) { \ - if ((unsigned char)*buf < '\040' || *buf == '\177') { \ - *ret = -1; \ - return NULL; \ - } \ - } \ - ++buf; \ - CHECK_EOF(); \ - } \ - tok = tok_start; \ - toklen = buf - tok_start; \ +#define ADVANCE_TOKEN(tok, toklen) \ + do { \ + const char *tok_start = buf; \ + static const char ALIGNED(16) ranges2[] = "\000\040\177\177"; \ + int found2; \ + buf = findchar_fast(buf, buf_end, ranges2, sizeof(ranges2) - 1, &found2); \ + if (!found2) { \ + CHECK_EOF(); \ + } \ + while (1) { \ + if (*buf == ' ') { \ + break; \ + } else if (unlikely(!IS_PRINTABLE_ASCII(*buf))) { \ + if ((unsigned char)*buf < '\040' || *buf == '\177') { \ + *ret = -1; \ + return NULL; \ + } \ + } \ + ++buf; \ + CHECK_EOF(); \ + } \ + tok = tok_start; \ + toklen = buf - tok_start; \ } while (0) -static const char *token_char_map = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\1\1\1\1\1\1\1\0\0\1\1\0\1\1\0\1\1\1\1\1\1\1\1\1\1\0\0\0\0\0\0" - "\0\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\0\0\0\1\1" - "\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\0\1\0\1\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; +static const char *token_char_map = + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\1\1\1\1\1\1\1\0\0\1\1\0\1\1\0\1\1\1\1\1\1\1\1\1\1\0\0\0\0\0\0" + "\0\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\0\0\0\1\1" + "\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\0\1\0\1\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; -static const char *findchar_fast(const char *buf, const char *buf_end, const char *ranges, size_t ranges_size, int *found) -{ +static const char *findchar_fast(const char *buf, const char *buf_end, const char *ranges, size_t ranges_size, + int *found) { *found = 0; #if __SSE4_2__ if (likely(buf_end - buf >= 16)) { @@ -110,7 +111,8 @@ static const char *findchar_fast(const char *buf, const char *buf_end, const cha size_t left = (buf_end - buf) & ~15; do { __m128i b16 = _mm_loadu_si128((void *)buf); - int r = _mm_cmpestri(ranges16, ranges_size, b16, 16, _SIDD_LEAST_SIGNIFICANT | _SIDD_CMP_RANGES | _SIDD_UBYTE_OPS); + int r = _mm_cmpestri( + ranges16, ranges_size, b16, 16, _SIDD_LEAST_SIGNIFICANT | _SIDD_CMP_RANGES | _SIDD_UBYTE_OPS); if (unlikely(r != 16)) { buf += r; *found = 1; @@ -124,16 +126,17 @@ static const char *findchar_fast(const char *buf, const char *buf_end, const cha return buf; } -static const char *get_token_to_eol(const char *buf, const char *buf_end, const char **token, size_t *token_len, int *ret) -{ +static const char *get_token_to_eol(const char *buf, const char *buf_end, const char **token, size_t *token_len, + int *ret) { const char *token_start = buf; #ifdef __SSE4_2__ - static const char ranges1[] = "\0\010" - /* allow HT */ - "\012\037" - /* allow SP and up to but not including DEL */ - "\177\177" + static const char ranges1 + [] = "\0\010" + /* allow HT */ + "\012\037" + /* allow SP and up to but not including DEL */ + "\177\177" /* allow chars w. MSB set */ ; int found; @@ -143,11 +146,11 @@ static const char *get_token_to_eol(const char *buf, const char *buf_end, const #else /* find non-printable char within the next 8 bytes, this is the hottest code; manually inlined */ while (likely(buf_end - buf >= 8)) { -#define DOIT() \ - do { \ - if (unlikely(!IS_PRINTABLE_ASCII(*buf))) \ - goto NonPrintable; \ - ++buf; \ +#define DOIT() \ + do { \ + if (unlikely(!IS_PRINTABLE_ASCII(*buf))) \ + goto NonPrintable; \ + ++buf; \ } while (0) DOIT(); DOIT(); @@ -191,10 +194,9 @@ FOUND_CTL: return buf; } -static const char *is_complete(const char *buf, const char *buf_end, size_t last_len, int *ret) -{ +static const char *is_complete(const char *buf, const char *buf_end, size_t last_len, int *ret) { int ret_cnt = 0; - buf = last_len < 3 ? buf : buf + last_len - 3; + buf = last_len < 3 ? buf : buf + last_len - 3; while (1) { CHECK_EOF(); @@ -220,8 +222,7 @@ static const char *is_complete(const char *buf, const char *buf_end, size_t last } /* *_buf is always within [buf, buf_end) upon success */ -static const char *parse_int(const char *buf, const char *buf_end, int *value, int *ret) -{ +static const char *parse_int(const char *buf, const char *buf_end, int *value, int *ret) { int v; CHECK_EOF(); if (!('0' <= *buf && *buf <= '9')) { @@ -243,8 +244,7 @@ static const char *parse_int(const char *buf, const char *buf_end, int *value, i } /* returned pointer is always within [buf, buf_end), or null */ -static const char *parse_http_version(const char *buf, const char *buf_end, int *minor_version, int *ret) -{ +static const char *parse_http_version(const char *buf, const char *buf_end, int *minor_version, int *ret) { EXPECT_CHAR('H'); EXPECT_CHAR('T'); EXPECT_CHAR('T'); @@ -256,8 +256,7 @@ static const char *parse_http_version(const char *buf, const char *buf_end, int } static const char *parse_headers(const char *buf, const char *buf_end, struct phr_header *headers, size_t *num_headers, - size_t max_headers, int *ret) -{ + size_t max_headers, int *ret) { for (;; ++*num_headers) { CHECK_EOF(); if (*buf == '\015') { @@ -279,9 +278,9 @@ static const char *parse_headers(const char *buf, const char *buf_end, struct ph } /* parsing name, but do not discard SP before colon, see * http://www.mozilla.org/security/announce/2006/mfsa2006-33.html */ - headers[*num_headers].name = buf; + headers[*num_headers].name = buf; static const char ALIGNED(16) ranges1[] = "::\x00\037"; - int found; + int found; buf = findchar_fast(buf, buf_end, ranges1, sizeof(ranges1) - 1, &found); if (!found) { CHECK_EOF(); @@ -305,20 +304,20 @@ static const char *parse_headers(const char *buf, const char *buf_end, struct ph } } } else { - headers[*num_headers].name = NULL; + headers[*num_headers].name = NULL; headers[*num_headers].name_len = 0; } - if ((buf = get_token_to_eol(buf, buf_end, &headers[*num_headers].value, &headers[*num_headers].value_len, ret)) == NULL) { + if ((buf = get_token_to_eol(buf, buf_end, &headers[*num_headers].value, &headers[*num_headers].value_len, ret)) + == NULL) { return NULL; } } return buf; } -static const char *parse_request(const char *buf, const char *buf_end, const char **method, size_t *method_len, const char **path, - size_t *path_len, int *minor_version, struct phr_header *headers, size_t *num_headers, - size_t max_headers, int *ret) -{ +static const char *parse_request(const char *buf, const char *buf_end, const char **method, size_t *method_len, + const char **path, size_t *path_len, int *minor_version, struct phr_header *headers, + size_t *num_headers, size_t max_headers, int *ret) { /* skip first empty line (some clients add CRLF after POST content) */ CHECK_EOF(); if (*buf == '\015') { @@ -350,18 +349,18 @@ static const char *parse_request(const char *buf, const char *buf_end, const cha } int phr_parse_request(const char *buf_start, size_t len, const char **method, size_t *method_len, const char **path, - size_t *path_len, int *minor_version, struct phr_header *headers, size_t *num_headers, size_t last_len) -{ + size_t *path_len, int *minor_version, struct phr_header *headers, size_t *num_headers, + size_t last_len) { const char *buf = buf_start, *buf_end = buf_start + len; - size_t max_headers = *num_headers; - int r; + size_t max_headers = *num_headers; + int r; - *method = NULL; - *method_len = 0; - *path = NULL; - *path_len = 0; + *method = NULL; + *method_len = 0; + *path = NULL; + *path_len = 0; *minor_version = -1; - *num_headers = 0; + *num_headers = 0; /* if last_len != 0, check if the request is complete (a fast countermeasure againt slowloris */ @@ -369,17 +368,18 @@ int phr_parse_request(const char *buf_start, size_t len, const char **method, si return r; } - if ((buf = parse_request(buf, buf_end, method, method_len, path, path_len, minor_version, headers, num_headers, max_headers, - &r)) == NULL) { + if ((buf = parse_request( + buf, buf_end, method, method_len, path, path_len, minor_version, headers, num_headers, max_headers, &r)) + == NULL) { return r; } return (int)(buf - buf_start); } -static const char *parse_response(const char *buf, const char *buf_end, int *minor_version, int *status, const char **msg, - size_t *msg_len, struct phr_header *headers, size_t *num_headers, size_t max_headers, int *ret) -{ +static const char *parse_response(const char *buf, const char *buf_end, int *minor_version, int *status, + const char **msg, size_t *msg_len, struct phr_header *headers, size_t *num_headers, + size_t max_headers, int *ret) { /* parse "HTTP/1.x" */ if ((buf = parse_http_version(buf, buf_end, minor_version, ret)) == NULL) { return NULL; @@ -406,18 +406,17 @@ static const char *parse_response(const char *buf, const char *buf_end, int *min return parse_headers(buf, buf_end, headers, num_headers, max_headers, ret); } -int phr_parse_response(const char *buf_start, size_t len, int *minor_version, int *status, const char **msg, size_t *msg_len, - struct phr_header *headers, size_t *num_headers, size_t last_len) -{ +int phr_parse_response(const char *buf_start, size_t len, int *minor_version, int *status, const char **msg, + size_t *msg_len, struct phr_header *headers, size_t *num_headers, size_t last_len) { const char *buf = buf_start, *buf_end = buf + len; - size_t max_headers = *num_headers; - int r; + size_t max_headers = *num_headers; + int r; *minor_version = -1; - *status = 0; - *msg = NULL; - *msg_len = 0; - *num_headers = 0; + *status = 0; + *msg = NULL; + *msg_len = 0; + *num_headers = 0; /* if last_len != 0, check if the response is complete (a fast countermeasure against slowloris */ @@ -425,18 +424,19 @@ int phr_parse_response(const char *buf_start, size_t len, int *minor_version, in return r; } - if ((buf = parse_response(buf, buf_end, minor_version, status, msg, msg_len, headers, num_headers, max_headers, &r)) == NULL) { + if ((buf = parse_response(buf, buf_end, minor_version, status, msg, msg_len, headers, num_headers, max_headers, &r)) + == NULL) { return r; } return (int)(buf - buf_start); } -int phr_parse_headers(const char *buf_start, size_t len, struct phr_header *headers, size_t *num_headers, size_t last_len) -{ +int phr_parse_headers(const char *buf_start, size_t len, struct phr_header *headers, size_t *num_headers, + size_t last_len) { const char *buf = buf_start, *buf_end = buf + len; - size_t max_headers = *num_headers; - int r; + size_t max_headers = *num_headers; + int r; *num_headers = 0; @@ -462,8 +462,7 @@ enum { CHUNKED_IN_TRAILERS_LINE_MIDDLE }; -static int decode_hex(int ch) -{ +static int decode_hex(int ch) { if ('0' <= ch && ch <= '9') { return ch - '0'; } else if ('A' <= ch && ch <= 'F') { @@ -475,109 +474,108 @@ static int decode_hex(int ch) } } -ssize_t phr_decode_chunked(struct phr_chunked_decoder *decoder, char *buf, size_t *_bufsz) -{ - size_t dst = 0, src = 0, bufsz = *_bufsz; +ssize_t phr_decode_chunked(struct phr_chunked_decoder *decoder, char *buf, size_t *_bufsz) { + size_t dst = 0, src = 0, bufsz = *_bufsz; ssize_t ret = -2; /* incomplete */ while (1) { switch (decoder->_state) { - case CHUNKED_IN_CHUNK_SIZE: - for (;; ++src) { - int v; - if (src == bufsz) - goto Exit; - if ((v = decode_hex(buf[src])) == -1) { - if (decoder->_hex_count == 0) { + case CHUNKED_IN_CHUNK_SIZE: + for (;; ++src) { + int v; + if (src == bufsz) + goto Exit; + if ((v = decode_hex(buf[src])) == -1) { + if (decoder->_hex_count == 0) { + ret = -1; + goto Exit; + } + break; + } + if (decoder->_hex_count == sizeof(size_t) * 2) { ret = -1; goto Exit; } - break; + decoder->bytes_left_in_chunk = decoder->bytes_left_in_chunk * 16 + v; + ++decoder->_hex_count; } - if (decoder->_hex_count == sizeof(size_t) * 2) { + decoder->_hex_count = 0; + decoder->_state = CHUNKED_IN_CHUNK_EXT; + /* fallthru */ + case CHUNKED_IN_CHUNK_EXT: + /* RFC 7230 A.2 "Line folding in chunk extensions is disallowed" */ + for (;; ++src) { + if (src == bufsz) + goto Exit; + if (buf[src] == '\012') + break; + } + ++src; + if (decoder->bytes_left_in_chunk == 0) { + if (decoder->consume_trailer) { + decoder->_state = CHUNKED_IN_TRAILERS_LINE_HEAD; + break; + } else { + goto Complete; + } + } + decoder->_state = CHUNKED_IN_CHUNK_DATA; + /* fallthru */ + case CHUNKED_IN_CHUNK_DATA: { + size_t avail = bufsz - src; + if (avail < decoder->bytes_left_in_chunk) { + if (dst != src) + memmove(buf + dst, buf + src, avail); + src += avail; + dst += avail; + decoder->bytes_left_in_chunk -= avail; + goto Exit; + } + if (dst != src) + memmove(buf + dst, buf + src, decoder->bytes_left_in_chunk); + src += decoder->bytes_left_in_chunk; + dst += decoder->bytes_left_in_chunk; + decoder->bytes_left_in_chunk = 0; + decoder->_state = CHUNKED_IN_CHUNK_CRLF; + } + /* fallthru */ + case CHUNKED_IN_CHUNK_CRLF: + for (;; ++src) { + if (src == bufsz) + goto Exit; + if (buf[src] != '\015') + break; + } + if (buf[src] != '\012') { ret = -1; goto Exit; } - decoder->bytes_left_in_chunk = decoder->bytes_left_in_chunk * 16 + v; - ++decoder->_hex_count; - } - decoder->_hex_count = 0; - decoder->_state = CHUNKED_IN_CHUNK_EXT; - /* fallthru */ - case CHUNKED_IN_CHUNK_EXT: - /* RFC 7230 A.2 "Line folding in chunk extensions is disallowed" */ - for (;; ++src) { - if (src == bufsz) - goto Exit; - if (buf[src] == '\012') - break; - } - ++src; - if (decoder->bytes_left_in_chunk == 0) { - if (decoder->consume_trailer) { - decoder->_state = CHUNKED_IN_TRAILERS_LINE_HEAD; - break; - } else { - goto Complete; + ++src; + decoder->_state = CHUNKED_IN_CHUNK_SIZE; + break; + case CHUNKED_IN_TRAILERS_LINE_HEAD: + for (;; ++src) { + if (src == bufsz) + goto Exit; + if (buf[src] != '\015') + break; } - } - decoder->_state = CHUNKED_IN_CHUNK_DATA; - /* fallthru */ - case CHUNKED_IN_CHUNK_DATA: { - size_t avail = bufsz - src; - if (avail < decoder->bytes_left_in_chunk) { - if (dst != src) - memmove(buf + dst, buf + src, avail); - src += avail; - dst += avail; - decoder->bytes_left_in_chunk -= avail; - goto Exit; - } - if (dst != src) - memmove(buf + dst, buf + src, decoder->bytes_left_in_chunk); - src += decoder->bytes_left_in_chunk; - dst += decoder->bytes_left_in_chunk; - decoder->bytes_left_in_chunk = 0; - decoder->_state = CHUNKED_IN_CHUNK_CRLF; - } - /* fallthru */ - case CHUNKED_IN_CHUNK_CRLF: - for (;; ++src) { - if (src == bufsz) - goto Exit; - if (buf[src] != '\015') - break; - } - if (buf[src] != '\012') { - ret = -1; - goto Exit; - } - ++src; - decoder->_state = CHUNKED_IN_CHUNK_SIZE; - break; - case CHUNKED_IN_TRAILERS_LINE_HEAD: - for (;; ++src) { - if (src == bufsz) - goto Exit; - if (buf[src] != '\015') - break; - } - if (buf[src++] == '\012') - goto Complete; - decoder->_state = CHUNKED_IN_TRAILERS_LINE_MIDDLE; - /* fallthru */ - case CHUNKED_IN_TRAILERS_LINE_MIDDLE: - for (;; ++src) { - if (src == bufsz) - goto Exit; - if (buf[src] == '\012') - break; - } - ++src; - decoder->_state = CHUNKED_IN_TRAILERS_LINE_HEAD; - break; - default: - assert(!"decoder is corrupt"); + if (buf[src++] == '\012') + goto Complete; + decoder->_state = CHUNKED_IN_TRAILERS_LINE_MIDDLE; + /* fallthru */ + case CHUNKED_IN_TRAILERS_LINE_MIDDLE: + for (;; ++src) { + if (src == bufsz) + goto Exit; + if (buf[src] == '\012') + break; + } + ++src; + decoder->_state = CHUNKED_IN_TRAILERS_LINE_HEAD; + break; + default: + assert(!"decoder is corrupt"); } } diff --git a/srcs/httpserver/src/haywire/picohttpparser.h b/srcs/httpserver/src/haywire/picohttpparser.h index ded2259..2ca55b2 100644 --- a/srcs/httpserver/src/haywire/picohttpparser.h +++ b/srcs/httpserver/src/haywire/picohttpparser.h @@ -43,15 +43,16 @@ extern "C" { * of a multiline header */ struct phr_header { const char *name; - size_t name_len; + size_t name_len; const char *value; - size_t value_len; + size_t value_len; }; /* returns number of bytes consumed if successful, -2 if request is partial, * -1 if failed */ -int phr_parse_request(const char *buf, size_t len, const char **method, size_t *method_len, const char **path, size_t *path_len, - int *minor_version, struct phr_header *headers, size_t *num_headers, size_t last_len); +int phr_parse_request(const char *buf, size_t len, const char **method, size_t *method_len, const char **path, + size_t *path_len, int *minor_version, struct phr_header *headers, size_t *num_headers, + size_t last_len); /* ditto */ int phr_parse_response(const char *_buf, size_t len, int *minor_version, int *status, const char **msg, size_t *msg_len, @@ -63,9 +64,9 @@ int phr_parse_headers(const char *buf, size_t len, struct phr_header *headers, s /* should be zero-filled before start */ struct phr_chunked_decoder { size_t bytes_left_in_chunk; /* number of bytes left in current chunk */ - char consume_trailer; /* if trailing headers should be consumed */ - char _hex_count; - char _state; + char consume_trailer; /* if trailing headers should be consumed */ + char _hex_count; + char _state; }; /* the function rewrites the buffer given as (buf, bufsz) removing the chunked- diff --git a/srcs/httpserver/src/haywire/route_compare_method.c b/srcs/httpserver/src/haywire/route_compare_method.c index 3690d05..ff89fe5 100644 --- a/srcs/httpserver/src/haywire/route_compare_method.c +++ b/srcs/httpserver/src/haywire/route_compare_method.c @@ -7,85 +7,75 @@ typedef struct hw_route_token_st { hw_string string; - int start; + int start; } hw_route_token; -void hw_route_next_token(hw_string* url, int start, hw_route_token* result) { +void hw_route_next_token(hw_string *url, int start, hw_route_token *result) { while (start < url->length && (url->value[start] == '/')) { start++; } - + int end = start; - + while (end < url->length && url->value[end] != '/') { end++; } - + if (end != start) { - result->string.value = url->value + start; + result->string.value = url->value + start; result->string.length = end - start; - result->start = start; - } - else { - result->string.value = NULL; + result->start = start; + } else { + result->string.value = NULL; result->string.length = 0; - result->start = -1; + result->start = -1; } } -int hw_route_compare_method(hw_string* url, char* route) -{ +int hw_route_compare_method(hw_string *url, char *route) { int equal = 0; int match = 0; - + // TODO route should probably be a hw_string* too hw_string hw_route; - hw_route.value = route; + hw_route.value = route; hw_route.length = strlen(route); - + hw_route_token route_token; hw_route_token request_token; hw_route_next_token(url, 0, &request_token); hw_route_next_token(&hw_route, 0, &route_token); - - while (route_token.string.value != NULL && request_token.string.value != NULL) - { + + while (route_token.string.value != NULL && request_token.string.value != NULL) { if (route_token.string.value[0] == '*') { // wildcard support: any route fragment marked with '*' matches the corresponding url fragment equal = 1; - } - else - { + } else { match = hw_strcmp(&route_token.string, &request_token.string); - if (!match) - { + if (!match) { equal = 1; - } - else - { + } else { equal = 0; break; } } - + hw_route_next_token(url, request_token.start + request_token.string.length + 1, &request_token); hw_route_next_token(&hw_route, route_token.start + route_token.string.length + 1, &route_token); } - - if (!equal) - { + + if (!equal) { match = hw_strcmp(url, &hw_route); - if (!match) - { + if (!match) { equal = 1; } } - if ((route_token.string.value == NULL && request_token.string.value != NULL) || (route_token.string.value != NULL && request_token.string.value == NULL)) - { + if ((route_token.string.value == NULL && request_token.string.value != NULL) + || (route_token.string.value != NULL && request_token.string.value == NULL)) { equal = 0; } - + return equal; } \ No newline at end of file diff --git a/srcs/httpserver/src/haywire/route_compare_method.h b/srcs/httpserver/src/haywire/route_compare_method.h index cc35aa4..1eec549 100644 --- a/srcs/httpserver/src/haywire/route_compare_method.h +++ b/srcs/httpserver/src/haywire/route_compare_method.h @@ -1,3 +1,3 @@ #include "haywire.h" -int hw_route_compare_method(hw_string* url, char* route); +int hw_route_compare_method(hw_string *url, char *route); diff --git a/srcs/httpserver/src/haywire/server_stats.c b/srcs/httpserver/src/haywire/server_stats.c index 3b00746..0bcad49 100644 --- a/srcs/httpserver/src/haywire/server_stats.c +++ b/srcs/httpserver/src/haywire/server_stats.c @@ -9,51 +9,43 @@ int stat_requests_destroyed_total; #define CRLF "\r\n" -static const char stats_response[] = - "HTTP/1.1 200 OK" CRLF - "Server: Haywire/master" CRLF - "Date: Fri, 26 Aug 2011 00:31:53 GMT" CRLF - "Connection: Keep-Alive" CRLF - "Content-Type: text/html" CRLF - "Content-Length: 16" CRLF - CRLF - "stats printed" CRLF; +static const char stats_response[] = "HTTP/1.1 200 OK" CRLF "Server: Haywire/master" CRLF + "Date: Fri, 26 Aug 2011 00:31:53 GMT" CRLF "Connection: Keep-Alive" CRLF + "Content-Type: text/html" CRLF "Content-Length: 16" CRLF CRLF "stats printed" CRLF; -void get_server_stats(http_request* request, hw_http_response* response, void* user_data) -{ +void get_server_stats(http_request *request, hw_http_response *response, void *user_data) { hw_string status_code; hw_string content_type_name; hw_string content_type_value; hw_string body; hw_string keep_alive_name; hw_string keep_alive_value; - + SETSTRING(status_code, HTTP_STATUS_200); hw_set_response_status_code(response, &status_code); - + SETSTRING(content_type_name, "Content-Type"); - + SETSTRING(content_type_value, "text/html"); hw_set_response_header(response, &content_type_name, &content_type_value); - + SETSTRING(body, "stats printed"); hw_set_body(response, &body); - - if (request->keep_alive) - { + + if (request->keep_alive) { SETSTRING(keep_alive_name, "Connection"); - + SETSTRING(keep_alive_value, "Keep-Alive"); hw_set_response_header(response, &keep_alive_name, &keep_alive_value); - } - else - { + } else { hw_set_http_version(response, 1, 0); } - + hw_http_response_send(response, NULL, NULL); - - printf("connections_created_total: %d\nconnections_destroyed_total: %d\nrequests_created_total: %d\nrequests_destroyed_total: %d\n\n", + + printf( + "connections_created_total: %d\nconnections_destroyed_total: %d\nrequests_created_total: " + "%d\nrequests_destroyed_total: %d\n\n", stat_connections_created_total, stat_connections_destroyed_total, stat_requests_created_total, diff --git a/srcs/httpserver/src/haywire/server_stats.h b/srcs/httpserver/src/haywire/server_stats.h index 1743fd8..3a7172c 100644 --- a/srcs/httpserver/src/haywire/server_stats.h +++ b/srcs/httpserver/src/haywire/server_stats.h @@ -7,10 +7,9 @@ #define INCREMENT_STAT(stat) #endif /* DEBUG */ - extern int stat_connections_created_total; extern int stat_connections_destroyed_total; extern int stat_requests_created_total; extern int stat_requests_destroyed_total; -void get_server_stats(http_request* request, hw_http_response* response, void* user_data); +void get_server_stats(http_request *request, hw_http_response *response, void *user_data); diff --git a/srcs/libs/network/http_svr.c b/srcs/libs/network/http_svr.c index 5a34465..b90419e 100644 --- a/srcs/libs/network/http_svr.c +++ b/srcs/libs/network/http_svr.c @@ -4,7 +4,6 @@ #include "http_svr.h" #include "user_errno.h" #include "haywire.h" -#include "misc.h" #include "config.h" int http_svr_init() {