OCT 重新格式化代码
This commit is contained in:
parent
1aaad54c7e
commit
b8ece8e445
|
@ -20,7 +20,7 @@ if (UNIX)
|
||||||
add_definitions(-DUNIX)
|
add_definitions(-DUNIX)
|
||||||
endif (UNIX)
|
endif (UNIX)
|
||||||
|
|
||||||
INCLUDE_DIRECTORIES(./include ./src)
|
INCLUDE_DIRECTORIES(./include ./src ../libs/include)
|
||||||
|
|
||||||
file(GLOB_RECURSE HW_HEADS
|
file(GLOB_RECURSE HW_HEADS
|
||||||
./src/haywire/*.h
|
./src/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_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_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(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);
|
HAYWIRE_EXTERN void hw_print_request_headers(http_request* request);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
|
@ -6,31 +6,23 @@
|
||||||
|
|
||||||
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)
|
int configuration_handler(void *user, const char *section, const char *name, const char *value) {
|
||||||
{
|
|
||||||
configuration *config = (configuration *)user;
|
configuration *config = (configuration *)user;
|
||||||
|
|
||||||
#define MATCH(s, n) strcmp(section, s) == 0 && strcmp(name, n) == 0
|
#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);
|
config->http_listen_address = dupstr(value);
|
||||||
}
|
} else if (MATCH("http", "listen_port")) {
|
||||||
else if (MATCH("http", "listen_port"))
|
|
||||||
{
|
|
||||||
config->http_listen_port = atoi(value);
|
config->http_listen_port = atoi(value);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
return 0; /* unknown section/name, error */
|
return 0; /* unknown section/name, error */
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
configuration* load_configuration(const char* filename)
|
configuration *load_configuration(const char *filename) {
|
||||||
{
|
|
||||||
configuration *config = malloc(sizeof(configuration));
|
configuration *config = malloc(sizeof(configuration));
|
||||||
if (ini_parse(filename, configuration_handler, config) < 0)
|
if (ini_parse(filename, configuration_handler, config) < 0) {
|
||||||
{
|
|
||||||
dzlog_error("Can't load configuration\n");
|
dzlog_error("Can't load configuration\n");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,8 +19,7 @@
|
||||||
#define MAX_NAME 50
|
#define MAX_NAME 50
|
||||||
|
|
||||||
/* Strip whitespace chars off end of given string, in place. Return s. */
|
/* Strip whitespace chars off end of given string, in place. Return s. */
|
||||||
static char* rstrip(char* s)
|
static char *rstrip(char *s) {
|
||||||
{
|
|
||||||
char *p = s + strlen(s);
|
char *p = s + strlen(s);
|
||||||
while (p > s && isspace(*--p))
|
while (p > s && isspace(*--p))
|
||||||
*p = '\0';
|
*p = '\0';
|
||||||
|
@ -28,8 +27,7 @@ static char* rstrip(char* s)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return pointer to first non-whitespace char in given string. */
|
/* 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))
|
while (*s && isspace(*s))
|
||||||
s++;
|
s++;
|
||||||
return (char *)s;
|
return (char *)s;
|
||||||
|
@ -38,8 +36,7 @@ static char* lskip(const char* s)
|
||||||
/* Return pointer to first char c or ';' comment in given string, or pointer to
|
/* 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
|
null at end of string if neither found. ';' must be prefixed by a whitespace
|
||||||
character to register as a comment. */
|
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;
|
int was_whitespace = 0;
|
||||||
while (*s && *s != c && !(was_whitespace && *s == ';')) {
|
while (*s && *s != c && !(was_whitespace && *s == ';')) {
|
||||||
was_whitespace = isspace(*s);
|
was_whitespace = isspace(*s);
|
||||||
|
@ -49,19 +46,14 @@ static char* find_char_or_comment(const char* s, char c)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Version of strncpy that ensures dest (size bytes) is null-terminated. */
|
/* 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);
|
strncpy(dest, src, size);
|
||||||
dest[size - 1] = '\0';
|
dest[size - 1] = '\0';
|
||||||
return dest;
|
return dest;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* See documentation in header file. */
|
/* See documentation in header file. */
|
||||||
int ini_parse_file(FILE* file,
|
int ini_parse_file(FILE *file, int (*handler)(void *, const char *, const char *, const char *), void *user) {
|
||||||
int (*handler)(void*, const char*, const char*,
|
|
||||||
const char*),
|
|
||||||
void* user)
|
|
||||||
{
|
|
||||||
/* Uses a fair bit of stack (use heap instead if you need to) */
|
/* Uses a fair bit of stack (use heap instead if you need to) */
|
||||||
char line[MAX_LINE];
|
char line[MAX_LINE];
|
||||||
char section[MAX_SECTION] = "";
|
char section[MAX_SECTION] = "";
|
||||||
|
@ -97,13 +89,11 @@ int ini_parse_file(FILE* file,
|
||||||
*end = '\0';
|
*end = '\0';
|
||||||
strncpy0(section, start + 1, sizeof(section));
|
strncpy0(section, start + 1, sizeof(section));
|
||||||
*prev_name = '\0';
|
*prev_name = '\0';
|
||||||
}
|
} else if (!error) {
|
||||||
else if (!error) {
|
|
||||||
/* No ']' found on section line */
|
/* No ']' found on section line */
|
||||||
error = lineno;
|
error = lineno;
|
||||||
}
|
}
|
||||||
}
|
} else if (*start && *start != ';') {
|
||||||
else if (*start && *start != ';') {
|
|
||||||
/* Not a comment, must be a name[=:]value pair */
|
/* Not a comment, must be a name[=:]value pair */
|
||||||
end = find_char_or_comment(start, '=');
|
end = find_char_or_comment(start, '=');
|
||||||
if (*end != '=') {
|
if (*end != '=') {
|
||||||
|
@ -122,8 +112,7 @@ int ini_parse_file(FILE* file,
|
||||||
strncpy0(prev_name, name, sizeof(prev_name));
|
strncpy0(prev_name, name, sizeof(prev_name));
|
||||||
if (!handler(user, section, name, value) && !error)
|
if (!handler(user, section, name, value) && !error)
|
||||||
error = lineno;
|
error = lineno;
|
||||||
}
|
} else if (!error) {
|
||||||
else if (!error) {
|
|
||||||
/* No '=' or ':' found on name[=:]value line */
|
/* No '=' or ':' found on name[=:]value line */
|
||||||
error = lineno;
|
error = lineno;
|
||||||
}
|
}
|
||||||
|
@ -134,10 +123,7 @@ int ini_parse_file(FILE* file,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* See documentation in header file. */
|
/* See documentation in header file. */
|
||||||
int ini_parse(const char* filename,
|
int ini_parse(const char *filename, int (*handler)(void *, const char *, const char *, const char *), void *user) {
|
||||||
int (*handler)(void*, const char*, const char*, const char*),
|
|
||||||
void* user)
|
|
||||||
{
|
|
||||||
FILE *file;
|
FILE *file;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
|
|
|
@ -31,15 +31,11 @@ extern "C" {
|
||||||
stop on first error), or -1 on file open error.
|
stop on first error), or -1 on file open error.
|
||||||
*/
|
*/
|
||||||
int ini_parse(const char *filename,
|
int ini_parse(const char *filename,
|
||||||
int (*handler)(void* user, const char* section,
|
int (*handler)(void *user, const char *section, const char *name, const char *value), void *user);
|
||||||
const char* name, const char* value),
|
|
||||||
void* user);
|
|
||||||
|
|
||||||
/* Same as ini_parse(), but takes a FILE* instead of filename. This doesn't
|
/* 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. */
|
close the file when it's finished -- the caller must do that. */
|
||||||
int ini_parse_file(FILE* file,
|
int ini_parse_file(FILE *file, int (*handler)(void *user, const char *section, const char *name, const char *value),
|
||||||
int (*handler)(void* user, const char* section,
|
|
||||||
const char* name, const char* value),
|
|
||||||
void *user);
|
void *user);
|
||||||
|
|
||||||
/* Nonzero to allow multi-line value parsing, in the style of Python's
|
/* Nonzero to allow multi-line value parsing, in the style of Python's
|
||||||
|
|
|
@ -8,8 +8,7 @@
|
||||||
|
|
||||||
static bool tcp_nodelay;
|
static bool tcp_nodelay;
|
||||||
|
|
||||||
void ipc_read_cb(uv_stream_t* handle, ssize_t nread, const uv_buf_t* buf)
|
void ipc_read_cb(uv_stream_t *handle, ssize_t nread, const uv_buf_t *buf) {
|
||||||
{
|
|
||||||
int rc;
|
int rc;
|
||||||
struct ipc_client_ctx *ctx;
|
struct ipc_client_ctx *ctx;
|
||||||
uv_loop_t *loop;
|
uv_loop_t *loop;
|
||||||
|
@ -28,39 +27,34 @@ void ipc_read_cb(uv_stream_t* handle, ssize_t nread, const uv_buf_t* buf)
|
||||||
if (tcp_nodelay) {
|
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)
|
||||||
else if (type == UV_NAMED_PIPE)
|
|
||||||
rc = uv_pipe_init(loop, (uv_pipe_t *)ctx->server_handle, 0);
|
rc = uv_pipe_init(loop, (uv_pipe_t *)ctx->server_handle, 0);
|
||||||
|
|
||||||
rc = uv_accept(handle, ctx->server_handle);
|
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)
|
void ipc_alloc_cb(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) {
|
||||||
{
|
|
||||||
struct ipc_client_ctx *ctx;
|
struct ipc_client_ctx *ctx;
|
||||||
ctx = container_of(handle, struct ipc_client_ctx, ipc_pipe);
|
ctx = container_of(handle, struct ipc_client_ctx, ipc_pipe);
|
||||||
buf->base = ctx->scratch;
|
buf->base = ctx->scratch;
|
||||||
buf->len = sizeof(ctx->scratch);
|
buf->len = sizeof(ctx->scratch);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ipc_connect_cb(uv_connect_t* req, int status)
|
void ipc_connect_cb(uv_connect_t *req, int status) {
|
||||||
{
|
|
||||||
int rc;
|
int rc;
|
||||||
struct ipc_client_ctx *ctx;
|
struct ipc_client_ctx *ctx;
|
||||||
ctx = container_of(req, struct ipc_client_ctx, connect_req);
|
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];
|
static char slab[32];
|
||||||
buf->base = slab;
|
buf->base = slab;
|
||||||
buf->len = sizeof(slab);
|
buf->len = sizeof(slab);
|
||||||
}
|
}
|
||||||
|
|
||||||
void connection_consumer_new_connection(uv_stream_t* server_handle, int status)
|
void connection_consumer_new_connection(uv_stream_t *server_handle, int status) {
|
||||||
{
|
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
http_connection *connection = create_http_connection();
|
http_connection *connection = create_http_connection();
|
||||||
http_parser_init(&connection->parser, HTTP_REQUEST);
|
http_parser_init(&connection->parser, HTTP_REQUEST);
|
||||||
|
@ -78,16 +72,14 @@ void connection_consumer_new_connection(uv_stream_t* server_handle, int status)
|
||||||
rc = uv_read_start((uv_stream_t *)&connection->stream, http_stream_on_alloc, http_stream_on_read);
|
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)
|
void connection_consumer_close(uv_async_t *handle, int status) {
|
||||||
{
|
|
||||||
struct server_ctx *ctx;
|
struct server_ctx *ctx;
|
||||||
ctx = container_of(handle, struct server_ctx, async_handle);
|
ctx = container_of(handle, struct server_ctx, async_handle);
|
||||||
uv_close((uv_handle_t *)&ctx->server_handle, NULL);
|
uv_close((uv_handle_t *)&ctx->server_handle, NULL);
|
||||||
uv_close((uv_handle_t *)&ctx->async_handle, NULL);
|
uv_close((uv_handle_t *)&ctx->async_handle, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void get_listen_handle(uv_loop_t* loop, uv_stream_t* server_handle)
|
void get_listen_handle(uv_loop_t *loop, uv_stream_t *server_handle) {
|
||||||
{
|
|
||||||
int rc;
|
int rc;
|
||||||
struct ipc_client_ctx ctx;
|
struct ipc_client_ctx ctx;
|
||||||
|
|
||||||
|
@ -99,9 +91,7 @@ void get_listen_handle(uv_loop_t* loop, uv_stream_t* server_handle)
|
||||||
rc = uv_run(loop, UV_RUN_DEFAULT);
|
rc = uv_run(loop, UV_RUN_DEFAULT);
|
||||||
}
|
}
|
||||||
|
|
||||||
void connection_consumer_start(void *arg)
|
void connection_consumer_start(void *arg) {
|
||||||
{
|
|
||||||
int rc;
|
|
||||||
struct server_ctx *ctx;
|
struct server_ctx *ctx;
|
||||||
uv_loop_t *loop;
|
uv_loop_t *loop;
|
||||||
|
|
||||||
|
@ -113,7 +103,7 @@ void connection_consumer_start(void *arg)
|
||||||
http_request_cache_configure_listener(loop, &listener_async_handles[ctx->index]);
|
http_request_cache_configure_listener(loop, &listener_async_handles[ctx->index]);
|
||||||
uv_barrier_wait(listeners_created_barrier);
|
uv_barrier_wait(listeners_created_barrier);
|
||||||
|
|
||||||
rc = uv_async_init(loop, &ctx->async_handle, connection_consumer_close);
|
uv_async_init(loop, &ctx->async_handle, connection_consumer_close);
|
||||||
uv_unref((uv_handle_t *)&ctx->async_handle);
|
uv_unref((uv_handle_t *)&ctx->async_handle);
|
||||||
|
|
||||||
/* Wait until the main thread is ready. */
|
/* Wait until the main thread is ready. */
|
||||||
|
@ -121,8 +111,8 @@ void connection_consumer_start(void *arg)
|
||||||
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);
|
uv_sem_post(&ctx->semaphore);
|
||||||
|
|
||||||
rc = uv_listen((uv_stream_t*)&ctx->server_handle, ctx->listen_backlog, connection_consumer_new_connection);
|
uv_listen((uv_stream_t *)&ctx->server_handle, ctx->listen_backlog, connection_consumer_new_connection);
|
||||||
rc = uv_run(loop, UV_RUN_DEFAULT);
|
uv_run(loop, UV_RUN_DEFAULT);
|
||||||
|
|
||||||
uv_loop_delete(loop);
|
uv_loop_delete(loop);
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,17 +9,14 @@
|
||||||
|
|
||||||
#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_pipe_t pipe;
|
||||||
uv_tcp_t tcp;
|
uv_tcp_t tcp;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef unsigned char handle_storage_t[sizeof(union stream_handle2)];
|
typedef unsigned char handle_storage_t[sizeof(union stream_handle2)];
|
||||||
|
|
||||||
struct server_ctx
|
struct server_ctx {
|
||||||
{
|
|
||||||
int index;
|
int index;
|
||||||
handle_storage_t server_handle;
|
handle_storage_t server_handle;
|
||||||
unsigned int num_connects;
|
unsigned int num_connects;
|
||||||
|
@ -30,16 +27,14 @@ struct server_ctx
|
||||||
unsigned int listen_backlog;
|
unsigned int listen_backlog;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ipc_client_ctx
|
struct ipc_client_ctx {
|
||||||
{
|
|
||||||
uv_connect_t connect_req;
|
uv_connect_t connect_req;
|
||||||
uv_stream_t *server_handle;
|
uv_stream_t *server_handle;
|
||||||
uv_pipe_t ipc_pipe;
|
uv_pipe_t ipc_pipe;
|
||||||
char scratch[16];
|
char scratch[16];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ipc_server_ctx
|
struct ipc_server_ctx {
|
||||||
{
|
|
||||||
handle_storage_t server_handle;
|
handle_storage_t server_handle;
|
||||||
unsigned int num_connects;
|
unsigned int num_connects;
|
||||||
uv_pipe_t ipc_pipe;
|
uv_pipe_t ipc_pipe;
|
||||||
|
|
|
@ -6,22 +6,19 @@
|
||||||
|
|
||||||
static struct sockaddr_in listen_addr;
|
static struct sockaddr_in listen_addr;
|
||||||
|
|
||||||
void ipc_close_cb(uv_handle_t* handle)
|
void ipc_close_cb(uv_handle_t *handle) {
|
||||||
{
|
|
||||||
struct ipc_peer_ctx *ctx;
|
struct ipc_peer_ctx *ctx;
|
||||||
ctx = container_of(handle, struct ipc_peer_ctx, peer_handle);
|
ctx = container_of(handle, struct ipc_peer_ctx, peer_handle);
|
||||||
free(ctx);
|
free(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ipc_write_cb(uv_write_t* req, int status)
|
void ipc_write_cb(uv_write_t *req, int status) {
|
||||||
{
|
|
||||||
struct ipc_peer_ctx *ctx;
|
struct ipc_peer_ctx *ctx;
|
||||||
ctx = container_of(req, struct ipc_peer_ctx, write_req);
|
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)
|
void ipc_connection_cb(uv_stream_t *ipc_pipe, int status) {
|
||||||
{
|
|
||||||
int rc;
|
int rc;
|
||||||
struct ipc_server_ctx *sc;
|
struct ipc_server_ctx *sc;
|
||||||
struct ipc_peer_ctx *pc;
|
struct ipc_peer_ctx *pc;
|
||||||
|
@ -39,17 +36,12 @@ void ipc_connection_cb(uv_stream_t* ipc_pipe, int status)
|
||||||
if (sc->tcp_nodelay) {
|
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)
|
||||||
else if (ipc_pipe->type == UV_NAMED_PIPE)
|
|
||||||
rc = uv_pipe_init(loop, (uv_pipe_t *)&pc->peer_handle, 1);
|
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_accept(ipc_pipe, (uv_stream_t *)&pc->peer_handle);
|
||||||
rc = uv_write2(&pc->write_req,
|
rc = uv_write2(
|
||||||
(uv_stream_t*) &pc->peer_handle,
|
&pc->write_req, (uv_stream_t *)&pc->peer_handle, &buf, 1, (uv_stream_t *)&sc->server_handle, ipc_write_cb);
|
||||||
&buf,
|
|
||||||
1,
|
|
||||||
(uv_stream_t*) &sc->server_handle,
|
|
||||||
ipc_write_cb);
|
|
||||||
|
|
||||||
if (--sc->num_connects == 0)
|
if (--sc->num_connects == 0)
|
||||||
uv_close((uv_handle_t *)ipc_pipe, NULL);
|
uv_close((uv_handle_t *)ipc_pipe, NULL);
|
||||||
|
@ -60,8 +52,8 @@ extern void print_configuration();
|
||||||
* threads. It's kind of cumbersome for such a simple operation, maybe we
|
* threads. It's kind of cumbersome for such a simple operation, maybe we
|
||||||
* should revive uv_import() and uv_export().
|
* 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)
|
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;
|
int rc;
|
||||||
struct ipc_server_ctx ctx;
|
struct ipc_server_ctx ctx;
|
||||||
uv_loop_t *loop;
|
uv_loop_t *loop;
|
||||||
|
@ -71,8 +63,7 @@ void start_connection_dispatching(uv_handle_type type, unsigned int num_servers,
|
||||||
ctx.num_connects = num_servers;
|
ctx.num_connects = num_servers;
|
||||||
ctx.tcp_nodelay = tcp_nodelay;
|
ctx.tcp_nodelay = tcp_nodelay;
|
||||||
|
|
||||||
if (type == UV_TCP)
|
if (type == UV_TCP) {
|
||||||
{
|
|
||||||
uv_ip4_addr(listen_address, listen_port, &listen_addr);
|
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);
|
||||||
|
|
|
@ -3,10 +3,10 @@
|
||||||
#include "uv.h"
|
#include "uv.h"
|
||||||
#include "connection_consumer.h"
|
#include "connection_consumer.h"
|
||||||
|
|
||||||
struct ipc_peer_ctx
|
struct ipc_peer_ctx {
|
||||||
{
|
|
||||||
handle_storage_t peer_handle;
|
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);
|
||||||
|
|
|
@ -6,8 +6,7 @@
|
||||||
#include "http_request.h"
|
#include "http_request.h"
|
||||||
#include "http_request_buffers.h"
|
#include "http_request_buffers.h"
|
||||||
|
|
||||||
typedef struct
|
typedef struct {
|
||||||
{
|
|
||||||
uv_tcp_t stream;
|
uv_tcp_t stream;
|
||||||
http_parser parser;
|
http_parser parser;
|
||||||
uv_write_t write_req;
|
uv_write_t write_req;
|
||||||
|
@ -16,6 +15,10 @@ typedef struct
|
||||||
hw_string current_header_value;
|
hw_string current_header_value;
|
||||||
int keep_alive;
|
int keep_alive;
|
||||||
int last_was_value;
|
int last_was_value;
|
||||||
enum {OPEN, CLOSING, CLOSED} state;
|
enum {
|
||||||
|
OPEN,
|
||||||
|
CLOSING,
|
||||||
|
CLOSED
|
||||||
|
} state;
|
||||||
hw_request_buffer *buffer;
|
hw_request_buffer *buffer;
|
||||||
} http_connection;
|
} http_connection;
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -66,7 +66,6 @@ extern "C" {
|
||||||
typedef struct http_parser http_parser;
|
typedef struct http_parser http_parser;
|
||||||
typedef struct http_parser_settings http_parser_settings;
|
typedef struct http_parser_settings http_parser_settings;
|
||||||
|
|
||||||
|
|
||||||
/* Callbacks should return non-zero to indicate an error. The parser will
|
/* Callbacks should return non-zero to indicate an error. The parser will
|
||||||
* then halt execution.
|
* then halt execution.
|
||||||
*
|
*
|
||||||
|
@ -117,30 +116,30 @@ XX(23, UNSUBSCRIBE, UNSUBSCRIBE) \
|
||||||
XX(24, PATCH, PATCH) \
|
XX(24, PATCH, PATCH) \
|
||||||
XX(25, PURGE, PURGE) \
|
XX(25, PURGE, PURGE) \
|
||||||
/* CalDAV */ \
|
/* CalDAV */ \
|
||||||
XX(26, MKCALENDAR, MKCALENDAR) \
|
XX(26, MKCALENDAR, MKCALENDAR)
|
||||||
|
|
||||||
enum http_method
|
enum http_method {
|
||||||
{
|
|
||||||
#define XX(num, name, string) HTTP_##name = num,
|
#define XX(num, name, string) HTTP_##name = num,
|
||||||
HTTP_METHOD_MAP(XX)
|
HTTP_METHOD_MAP(XX)
|
||||||
#undef XX
|
#undef XX
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum http_parser_type {
|
||||||
enum http_parser_type { HTTP_REQUEST, HTTP_RESPONSE, HTTP_BOTH };
|
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
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* 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
|
/* Map for errno-related constants
|
||||||
*
|
*
|
||||||
|
@ -162,10 +161,8 @@ XX(CB_status, "the on_status callback failed") \
|
||||||
\
|
\
|
||||||
/* Parsing-related errors */ \
|
/* Parsing-related errors */ \
|
||||||
XX(INVALID_EOF_STATE, "stream ended at an unexpected time") \
|
XX(INVALID_EOF_STATE, "stream ended at an unexpected time") \
|
||||||
XX(HEADER_OVERFLOW, \
|
XX(HEADER_OVERFLOW, "too many header bytes seen; overflow detected") \
|
||||||
"too many header bytes seen; overflow detected") \
|
XX(CLOSED_CONNECTION, "data received after completed connection: close message") \
|
||||||
XX(CLOSED_CONNECTION, \
|
|
||||||
"data received after completed connection: close message") \
|
|
||||||
XX(INVALID_VERSION, "invalid HTTP version") \
|
XX(INVALID_VERSION, "invalid HTTP version") \
|
||||||
XX(INVALID_STATUS, "invalid HTTP status code") \
|
XX(INVALID_STATUS, "invalid HTTP status code") \
|
||||||
XX(INVALID_METHOD, "invalid HTTP method") \
|
XX(INVALID_METHOD, "invalid HTTP method") \
|
||||||
|
@ -177,17 +174,14 @@ XX(INVALID_QUERY_STRING, "invalid query string") \
|
||||||
XX(INVALID_FRAGMENT, "invalid fragment") \
|
XX(INVALID_FRAGMENT, "invalid fragment") \
|
||||||
XX(LF_EXPECTED, "LF character expected") \
|
XX(LF_EXPECTED, "LF character expected") \
|
||||||
XX(INVALID_HEADER_TOKEN, "invalid character in header") \
|
XX(INVALID_HEADER_TOKEN, "invalid character in header") \
|
||||||
XX(INVALID_CONTENT_LENGTH, \
|
XX(INVALID_CONTENT_LENGTH, "invalid character in content-length header") \
|
||||||
"invalid character in content-length header") \
|
XX(INVALID_CHUNK_SIZE, "invalid character in chunk size header") \
|
||||||
XX(INVALID_CHUNK_SIZE, \
|
|
||||||
"invalid character in chunk size header") \
|
|
||||||
XX(INVALID_CONSTANT, "invalid constant string") \
|
XX(INVALID_CONSTANT, "invalid constant string") \
|
||||||
XX(INVALID_INTERNAL_STATE, "encountered unexpected internal state") \
|
XX(INVALID_INTERNAL_STATE, "encountered unexpected internal state") \
|
||||||
XX(STRICT, "strict mode assertion failed") \
|
XX(STRICT, "strict mode assertion failed") \
|
||||||
XX(PAUSED, "parser is paused") \
|
XX(PAUSED, "parser is paused") \
|
||||||
XX(UNKNOWN, "an unknown error occurred")
|
XX(UNKNOWN, "an unknown error occurred")
|
||||||
|
|
||||||
|
|
||||||
/* Define HPE_* values for each errno value above */
|
/* Define HPE_* values for each errno value above */
|
||||||
#define HTTP_ERRNO_GEN(n, s) HPE_##n,
|
#define HTTP_ERRNO_GEN(n, s) HPE_##n,
|
||||||
enum http_errno {
|
enum http_errno {
|
||||||
|
@ -195,11 +189,9 @@ XX(UNKNOWN, "an unknown error occurred")
|
||||||
};
|
};
|
||||||
#undef HTTP_ERRNO_GEN
|
#undef HTTP_ERRNO_GEN
|
||||||
|
|
||||||
|
|
||||||
/* Get an http_errno value from an http_parser */
|
/* Get an http_errno value from an http_parser */
|
||||||
#define HTTP_PARSER_ERRNO(p) ((enum http_errno)(p)->http_errno)
|
#define HTTP_PARSER_ERRNO(p) ((enum http_errno)(p)->http_errno)
|
||||||
|
|
||||||
|
|
||||||
struct http_parser {
|
struct http_parser {
|
||||||
/** PRIVATE **/
|
/** PRIVATE **/
|
||||||
unsigned int type : 2; /* enum http_parser_type */
|
unsigned int type : 2; /* enum http_parser_type */
|
||||||
|
@ -229,7 +221,6 @@ XX(UNKNOWN, "an unknown error occurred")
|
||||||
void *data; /* A pointer to get hook to the "connection" or "socket" object */
|
void *data; /* A pointer to get hook to the "connection" or "socket" object */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
struct http_parser_settings {
|
struct http_parser_settings {
|
||||||
http_cb on_message_begin;
|
http_cb on_message_begin;
|
||||||
http_data_cb on_url;
|
http_data_cb on_url;
|
||||||
|
@ -241,19 +232,17 @@ XX(UNKNOWN, "an unknown error occurred")
|
||||||
http_cb on_message_complete;
|
http_cb on_message_complete;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum http_parser_url_fields {
|
||||||
enum http_parser_url_fields
|
UF_SCHEMA = 0,
|
||||||
{ UF_SCHEMA = 0
|
UF_HOST = 1,
|
||||||
, UF_HOST = 1
|
UF_PORT = 2,
|
||||||
, UF_PORT = 2
|
UF_PATH = 3,
|
||||||
, UF_PATH = 3
|
UF_QUERY = 4,
|
||||||
, UF_QUERY = 4
|
UF_FRAGMENT = 5,
|
||||||
, UF_FRAGMENT = 5
|
UF_USERINFO = 6,
|
||||||
, UF_USERINFO = 6
|
UF_MAX = 7
|
||||||
, UF_MAX = 7
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/* Result structure for http_parser_parse_url().
|
/* Result structure for http_parser_parse_url().
|
||||||
*
|
*
|
||||||
* Callers should index into field_data[] with UF_* values iff field_set
|
* Callers should index into field_data[] with UF_* values iff field_set
|
||||||
|
@ -271,7 +260,6 @@ XX(UNKNOWN, "an unknown error occurred")
|
||||||
} field_data[UF_MAX];
|
} field_data[UF_MAX];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/* Returns the library version. Bits 16-23 contain the major version number,
|
/* 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.
|
* bits 8-15 the minor version number and bits 0-7 the patch level.
|
||||||
* Usage example:
|
* Usage example:
|
||||||
|
@ -286,14 +274,9 @@ XX(UNKNOWN, "an unknown error occurred")
|
||||||
|
|
||||||
void http_parser_init(http_parser *parser, enum http_parser_type type);
|
void http_parser_init(http_parser *parser, enum http_parser_type type);
|
||||||
|
|
||||||
|
|
||||||
/* Executes the parser. Returns number of parsed bytes. Sets
|
/* Executes the parser. Returns number of parsed bytes. Sets
|
||||||
* `parser->http_errno` on error. */
|
* `parser->http_errno` on error. */
|
||||||
size_t http_parser_execute(http_parser *parser,
|
size_t http_parser_execute(http_parser *parser, const http_parser_settings *settings, const char *data, size_t len);
|
||||||
const http_parser_settings *settings,
|
|
||||||
const char *data,
|
|
||||||
size_t len);
|
|
||||||
|
|
||||||
|
|
||||||
/* If http_should_keep_alive() in the on_headers_complete or
|
/* If http_should_keep_alive() in the on_headers_complete or
|
||||||
* on_message_complete callback returns 0, then this should be
|
* on_message_complete callback returns 0, then this should be
|
||||||
|
@ -313,9 +296,7 @@ XX(UNKNOWN, "an unknown error occurred")
|
||||||
const char *http_errno_description(enum http_errno err);
|
const char *http_errno_description(enum http_errno err);
|
||||||
|
|
||||||
/* Parse a URL; return nonzero on failure */
|
/* Parse a URL; return nonzero on failure */
|
||||||
int http_parser_parse_url(const char *buf, size_t buflen,
|
int http_parser_parse_url(const char *buf, size_t buflen, int is_connect, struct http_parser_url *u);
|
||||||
int is_connect,
|
|
||||||
struct http_parser_url *u);
|
|
||||||
|
|
||||||
/* Pause or un-pause the parser; a nonzero value pauses */
|
/* Pause or un-pause the parser; a nonzero value pauses */
|
||||||
void http_parser_pause(http_parser *parser, int paused);
|
void http_parser_pause(http_parser *parser, int paused);
|
||||||
|
|
|
@ -10,25 +10,20 @@
|
||||||
#include "http_server.h"
|
#include "http_server.h"
|
||||||
#include "server_stats.h"
|
#include "server_stats.h"
|
||||||
#include "route_compare_method.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"
|
#define CRLF "\r\n"
|
||||||
static const char response_404[] =
|
static const char response_404[] = "HTTP/1.1 404 Not Found" CRLF "Server: Haywire/master" CRLF
|
||||||
"HTTP/1.1 404 Not Found" CRLF
|
"Date: Fri, 26 Aug 2011 00:31:53 GMT" CRLF "Connection: Keep-Alive" CRLF
|
||||||
"Server: Haywire/master" CRLF
|
"Content-Type: text/html" CRLF "Content-Length: 16" CRLF CRLF "404 Not Found" 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;
|
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;
|
return h;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,8 +33,7 @@ KHASH_INIT(hw_string_hashmap, hw_string*, hw_string*, 1, hw_string_hash_func, h
|
||||||
KHASH_MAP_INIT_STR(string_hashmap, char *)
|
KHASH_MAP_INIT_STR(string_hashmap, char *)
|
||||||
KHASH_MAP_INIT_INT64(offset_hashmap, int)
|
KHASH_MAP_INIT_INT64(offset_hashmap, int)
|
||||||
|
|
||||||
void hw_print_request_headers(http_request* request)
|
void hw_print_request_headers(http_request *request) {
|
||||||
{
|
|
||||||
hw_string *k;
|
hw_string *k;
|
||||||
hw_string *v;
|
hw_string *v;
|
||||||
|
|
||||||
|
@ -53,20 +47,17 @@ void hw_print_request_headers(http_request* request)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void hw_print_body(http_request* request)
|
void hw_print_body(http_request *request) {
|
||||||
{
|
|
||||||
if (request->body->length > 0) {
|
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);
|
printf("BODY: %s\n", body);
|
||||||
free(body);
|
free(body);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
printf("BODY is empty!\n");
|
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;
|
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);
|
||||||
|
|
||||||
|
@ -81,14 +72,12 @@ void* get_header(http_request* request, hw_string* name)
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_header(http_request* request, hw_string* name, hw_string* value)
|
void set_header(http_request *request, hw_string *name, hw_string *value) {
|
||||||
{
|
|
||||||
int ret, i;
|
int ret, i;
|
||||||
khiter_t k;
|
khiter_t k;
|
||||||
khash_t(hw_string_hashmap) *h = request->headers;
|
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]);
|
name->value[i] = tolower(name->value[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,8 +90,7 @@ void set_header(http_request* request, hw_string* name, hw_string* value)
|
||||||
kh_value(h, k) = value;
|
kh_value(h, k) = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
http_request* create_http_request(http_connection* connection)
|
http_request *create_http_request(http_connection *UNUSED(connection)) {
|
||||||
{
|
|
||||||
http_request *request = calloc(1, sizeof(http_request));
|
http_request *request = calloc(1, sizeof(http_request));
|
||||||
request->headers = kh_init(hw_string_hashmap);
|
request->headers = kh_init(hw_string_hashmap);
|
||||||
request->url = calloc(1, sizeof(hw_string));
|
request->url = calloc(1, sizeof(hw_string));
|
||||||
|
@ -112,15 +100,13 @@ http_request* create_http_request(http_connection* connection)
|
||||||
return request;
|
return request;
|
||||||
}
|
}
|
||||||
|
|
||||||
void free_http_request(http_request* request)
|
void free_http_request(http_request *request) {
|
||||||
{
|
|
||||||
khash_t(hw_string_hashmap) *h = request->headers;
|
khash_t(hw_string_hashmap) *h = request->headers;
|
||||||
|
|
||||||
hw_string *k;
|
hw_string *k;
|
||||||
hw_string *v;
|
hw_string *v;
|
||||||
|
|
||||||
kh_foreach(h, k, v,
|
kh_foreach(h, k, v, {
|
||||||
{
|
|
||||||
free((hw_string *)k);
|
free((hw_string *)k);
|
||||||
free((hw_string *)v);
|
free((hw_string *)v);
|
||||||
});
|
});
|
||||||
|
@ -135,14 +121,12 @@ void free_http_request(http_request* request)
|
||||||
INCREMENT_STAT(stat_requests_destroyed_total);
|
INCREMENT_STAT(stat_requests_destroyed_total);
|
||||||
}
|
}
|
||||||
|
|
||||||
hw_string* hw_get_header(http_request* request, hw_string* key)
|
hw_string *hw_get_header(http_request *request, hw_string *key) {
|
||||||
{
|
|
||||||
void *value = get_header(request, key);
|
void *value = get_header(request, key);
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
int http_request_on_message_begin(http_parser* parser)
|
int http_request_on_message_begin(http_parser *parser) {
|
||||||
{
|
|
||||||
http_connection *connection = (http_connection *)parser->data;
|
http_connection *connection = (http_connection *)parser->data;
|
||||||
if (connection->request) {
|
if (connection->request) {
|
||||||
/* We're seeing a new request on the same connection, so it's time to free up the old one
|
/* We're seeing a new request on the same connection, so it's time to free up the old one
|
||||||
|
@ -156,8 +140,7 @@ int http_request_on_message_begin(http_parser* parser)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int http_request_on_url(http_parser *parser, const char *at, size_t length)
|
int http_request_on_url(http_parser *parser, const char *at, size_t length) {
|
||||||
{
|
|
||||||
http_connection *connection = (http_connection *)parser->data;
|
http_connection *connection = (http_connection *)parser->data;
|
||||||
http_request *request = connection->request;
|
http_request *request = connection->request;
|
||||||
hw_string *url = request->url;
|
hw_string *url = request->url;
|
||||||
|
@ -187,19 +170,17 @@ 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
|
/* 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 */
|
* the pointers pointing at the right place in the buffer */
|
||||||
header_key_copy->value = http_request_buffer_locate(connection->buffer, header_key_copy,
|
header_key_copy->value = http_request_buffer_locate(
|
||||||
connection->current_header_key.value);
|
connection->buffer, header_key_copy, connection->current_header_key.value);
|
||||||
|
|
||||||
header_value_copy->value = http_request_buffer_locate(connection->buffer, header_value_copy,
|
header_value_copy->value = http_request_buffer_locate(
|
||||||
connection->current_header_value.value);
|
connection->buffer, header_value_copy, connection->current_header_value.value);
|
||||||
|
|
||||||
/* Save last header key/value pair that was read */
|
/* Save last header key/value pair that was read */
|
||||||
set_header(connection->request, header_key_copy, header_value_copy);
|
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) {
|
||||||
int http_request_on_header_field(http_parser *parser, const char *at, size_t length)
|
|
||||||
{
|
|
||||||
http_connection *connection = (http_connection *)parser->data;
|
http_connection *connection = (http_connection *)parser->data;
|
||||||
|
|
||||||
if (connection->last_was_value && connection->current_header_key.length > 0) {
|
if (connection->last_was_value && connection->current_header_key.length > 0) {
|
||||||
|
@ -225,8 +206,7 @@ int http_request_on_header_field(http_parser *parser, const char *at, size_t len
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int http_request_on_header_value(http_parser *parser, const char *at, size_t length)
|
int http_request_on_header_value(http_parser *parser, const char *at, size_t length) {
|
||||||
{
|
|
||||||
http_connection *connection = (http_connection *)parser->data;
|
http_connection *connection = (http_connection *)parser->data;
|
||||||
|
|
||||||
if (!connection->last_was_value) {
|
if (!connection->last_was_value) {
|
||||||
|
@ -244,8 +224,7 @@ int http_request_on_header_value(http_parser *parser, const char *at, size_t len
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int http_request_on_headers_complete(http_parser* parser)
|
int http_request_on_headers_complete(http_parser *parser) {
|
||||||
{
|
|
||||||
http_connection *connection = (http_connection *)parser->data;
|
http_connection *connection = (http_connection *)parser->data;
|
||||||
|
|
||||||
if (connection->current_header_key.length > 0 && connection->current_header_value.length > 0) {
|
if (connection->current_header_key.length > 0 && connection->current_header_value.length > 0) {
|
||||||
|
@ -262,13 +241,11 @@ int http_request_on_headers_complete(http_parser* parser)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int http_request_on_body(http_parser *parser, const char *at, size_t length)
|
int http_request_on_body(http_parser *parser, const char *at, size_t length) {
|
||||||
{
|
|
||||||
http_connection *connection = (http_connection *)parser->data;
|
http_connection *connection = (http_connection *)parser->data;
|
||||||
http_request *request = connection->request;
|
http_request *request = connection->request;
|
||||||
hw_string *body = request->body;
|
hw_string *body = request->body;
|
||||||
if (length != 0)
|
if (length != 0) {
|
||||||
{
|
|
||||||
if (body->length == 0) {
|
if (body->length == 0) {
|
||||||
body->value = at;
|
body->value = at;
|
||||||
body->length = length;
|
body->length = length;
|
||||||
|
@ -284,8 +261,7 @@ int http_request_on_body(http_parser *parser, const char *at, size_t length)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
hw_route_entry* get_route_callback(hw_string* url)
|
hw_route_entry *get_route_callback(hw_string *url) {
|
||||||
{
|
|
||||||
hw_route_entry *route_entry = NULL;
|
hw_route_entry *route_entry = NULL;
|
||||||
|
|
||||||
const char *k;
|
const char *k;
|
||||||
|
@ -293,11 +269,9 @@ hw_route_entry* get_route_callback(hw_string* url)
|
||||||
|
|
||||||
khash_t(string_hashmap) *h = routes;
|
khash_t(string_hashmap) *h = routes;
|
||||||
|
|
||||||
kh_foreach(h, k, v,
|
kh_foreach(h, k, v, {
|
||||||
{
|
|
||||||
int found = hw_route_compare_method(url, k);
|
int found = hw_route_compare_method(url, k);
|
||||||
if (found)
|
if (found) {
|
||||||
{
|
|
||||||
route_entry = (hw_route_entry *)v;
|
route_entry = (hw_route_entry *)v;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -306,8 +280,7 @@ hw_route_entry* get_route_callback(hw_string* url)
|
||||||
}
|
}
|
||||||
|
|
||||||
void send_error_response(http_request *request, http_response *response, const char *error_code,
|
void send_error_response(http_request *request, http_response *response, const char *error_code,
|
||||||
const char* error_message)
|
const char *error_message) {
|
||||||
{
|
|
||||||
hw_string status_code;
|
hw_string status_code;
|
||||||
hw_string content_type_name;
|
hw_string content_type_name;
|
||||||
hw_string content_type_value;
|
hw_string content_type_value;
|
||||||
|
@ -328,15 +301,12 @@ void send_error_response(http_request* request, http_response* response, const c
|
||||||
body.length = strlen(error_message);
|
body.length = strlen(error_message);
|
||||||
hw_set_body(response, &body);
|
hw_set_body(response, &body);
|
||||||
|
|
||||||
if (request->keep_alive)
|
if (request->keep_alive) {
|
||||||
{
|
|
||||||
SETSTRING(keep_alive_name, "Connection");
|
SETSTRING(keep_alive_name, "Connection");
|
||||||
|
|
||||||
SETSTRING(keep_alive_value, "Keep-Alive");
|
SETSTRING(keep_alive_value, "Keep-Alive");
|
||||||
hw_set_response_header(response, &keep_alive_name, &keep_alive_value);
|
hw_set_response_header(response, &keep_alive_name, &keep_alive_value);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
hw_set_http_version(response, 1, 0);
|
hw_set_http_version(response, 1, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -348,8 +318,7 @@ void send_error_response(http_request* request, http_response* response, const c
|
||||||
* This is because the underlying buffers might have been reallocated/resized,
|
* 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.
|
* 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)
|
void http_request_locate_members(http_connection *connection) {
|
||||||
{
|
|
||||||
hw_request_buffer *buffer = connection->buffer;
|
hw_request_buffer *buffer = connection->buffer;
|
||||||
http_request *request = connection->request;
|
http_request *request = connection->request;
|
||||||
request->url->value = http_request_buffer_locate(buffer, request->url, request->url->value);
|
request->url->value = http_request_buffer_locate(buffer, request->url, request->url->value);
|
||||||
|
@ -365,8 +334,7 @@ void http_request_locate_members(http_connection* connection)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
int http_request_on_message_complete(http_parser* parser)
|
int http_request_on_message_complete(http_parser *parser) {
|
||||||
{
|
|
||||||
http_connection *connection = (http_connection *)parser->data;
|
http_connection *connection = (http_connection *)parser->data;
|
||||||
http_request *request = connection->request;
|
http_request *request = connection->request;
|
||||||
hw_http_response *response = hw_create_http_response(connection);
|
hw_http_response *response = hw_create_http_response(connection);
|
||||||
|
@ -386,12 +354,9 @@ int http_request_on_message_complete(http_parser* parser)
|
||||||
|
|
||||||
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);
|
route_entry->callback(request, response, route_entry->user_data);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
// 404 Not Found.
|
// 404 Not Found.
|
||||||
error = HTTP_STATUS_404;
|
error = HTTP_STATUS_404;
|
||||||
}
|
}
|
||||||
|
|
|
@ -172,9 +172,7 @@ void http_request_buffer_print(hw_request_buffer* buf) {
|
||||||
|
|
||||||
void *pointer;
|
void *pointer;
|
||||||
int offset;
|
int offset;
|
||||||
kh_foreach(buffer->offsets, pointer, offset, {
|
kh_foreach(buffer->offsets, pointer, offset, { printf("\tPointer %u -> offset=%u\n", pointer, offset); });
|
||||||
printf("\tPointer %u -> offset=%u\n", pointer, offset);
|
|
||||||
});
|
|
||||||
printf("----\n");
|
printf("----\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,8 +10,7 @@
|
||||||
#define CRLF "\r\n"
|
#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)
|
hw_http_response hw_create_http_response(http_connection *connection) {
|
||||||
{
|
|
||||||
http_response *response = malloc(sizeof(http_response));
|
http_response *response = malloc(sizeof(http_response));
|
||||||
response->connection = connection;
|
response->connection = connection;
|
||||||
response->request = connection->request;
|
response->request = connection->request;
|
||||||
|
@ -23,27 +22,23 @@ hw_http_response hw_create_http_response(http_connection* connection)
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
void hw_free_http_response(hw_http_response* response)
|
void hw_free_http_response(hw_http_response *response) {
|
||||||
{
|
|
||||||
http_response *resp = (http_response *)response;
|
http_response *resp = (http_response *)response;
|
||||||
free(resp);
|
free(resp);
|
||||||
}
|
}
|
||||||
|
|
||||||
void hw_set_http_version(hw_http_response* response, unsigned short major, unsigned short minor)
|
void hw_set_http_version(hw_http_response *response, unsigned short major, unsigned short minor) {
|
||||||
{
|
|
||||||
http_response *resp = (http_response *)response;
|
http_response *resp = (http_response *)response;
|
||||||
resp->http_major = major;
|
resp->http_major = major;
|
||||||
resp->http_minor = minor;
|
resp->http_minor = minor;
|
||||||
}
|
}
|
||||||
|
|
||||||
void hw_set_response_status_code(hw_http_response* response, hw_string* status_code)
|
void hw_set_response_status_code(hw_http_response *response, hw_string *status_code) {
|
||||||
{
|
|
||||||
http_response *resp = (http_response *)response;
|
http_response *resp = (http_response *)response;
|
||||||
resp->status_code = *status_code;
|
resp->status_code = *status_code;
|
||||||
}
|
}
|
||||||
|
|
||||||
void hw_set_response_header(hw_http_response* response, hw_string* name, hw_string* value)
|
void hw_set_response_header(hw_http_response *response, hw_string *name, hw_string *value) {
|
||||||
{
|
|
||||||
http_response *resp = (http_response *)response;
|
http_response *resp = (http_response *)response;
|
||||||
http_header *header = &resp->headers[resp->number_of_headers];
|
http_header *header = &resp->headers[resp->number_of_headers];
|
||||||
header->name = *name;
|
header->name = *name;
|
||||||
|
@ -52,15 +47,15 @@ void hw_set_response_header(hw_http_response* response, hw_string* name, hw_stri
|
||||||
resp->number_of_headers++;
|
resp->number_of_headers++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void hw_set_body(hw_http_response* response, hw_string* body)
|
void hw_set_body(hw_http_response *response, hw_string *body) {
|
||||||
{
|
|
||||||
http_response *resp = (http_response *)response;
|
http_response *resp = (http_response *)response;
|
||||||
resp->body = *body;
|
resp->body = *body;
|
||||||
}
|
}
|
||||||
|
|
||||||
int num_chars(int n) {
|
int num_chars(int n) {
|
||||||
int r = 1;
|
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) {
|
while (n > 9) {
|
||||||
n /= 10;
|
n /= 10;
|
||||||
r++;
|
r++;
|
||||||
|
@ -68,8 +63,7 @@ int num_chars(int n) {
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
hw_string* create_response_buffer(hw_http_response* response)
|
hw_string *create_response_buffer(hw_http_response *response) {
|
||||||
{
|
|
||||||
http_response *resp = (http_response *)response;
|
http_response *resp = (http_response *)response;
|
||||||
hw_string *response_string = malloc(sizeof(hw_string));
|
hw_string *response_string = malloc(sizeof(hw_string));
|
||||||
hw_string *cached_entry = get_cached_request(resp->status_code.value);
|
hw_string *cached_entry = get_cached_request(resp->status_code.value);
|
||||||
|
@ -83,15 +77,15 @@ hw_string* create_response_buffer(hw_http_response* response)
|
||||||
int header_buffer_incr = 512;
|
int header_buffer_incr = 512;
|
||||||
int body_size = resp->body.length;
|
int body_size = resp->body.length;
|
||||||
int header_size_remaining = header_buffer_incr;
|
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->value = malloc(response_size);
|
||||||
|
|
||||||
response_string->length = 0;
|
response_string->length = 0;
|
||||||
append_string(response_string, cached_entry);
|
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];
|
http_header header = resp->headers[i];
|
||||||
|
|
||||||
header_size_remaining -= header.name.length + 2 + header.value.length + line_sep_size;
|
header_size_remaining -= header.name.length + 2 + header.value.length + line_sep_size;
|
||||||
|
@ -114,8 +108,7 @@ hw_string* create_response_buffer(hw_http_response* response)
|
||||||
|
|
||||||
if (body_size > 0) {
|
if (body_size > 0) {
|
||||||
append_string(response_string, &content_length);
|
append_string(response_string, &content_length);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
hw_string zero_content;
|
hw_string zero_content;
|
||||||
zero_content.value = "0";
|
zero_content.value = "0";
|
||||||
zero_content.length = 1;
|
zero_content.length = 1;
|
||||||
|
@ -124,17 +117,14 @@ hw_string* create_response_buffer(hw_http_response* response)
|
||||||
|
|
||||||
APPENDSTRING(response_string, CRLF CRLF);
|
APPENDSTRING(response_string, CRLF CRLF);
|
||||||
|
|
||||||
if (body_size > 0)
|
if (body_size > 0) {
|
||||||
{
|
|
||||||
append_string(response_string, &resp->body);
|
append_string(response_string, &resp->body);
|
||||||
}
|
}
|
||||||
|
|
||||||
return response_string;
|
return response_string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void hw_http_response_send(hw_http_response *response, void *user_data, http_response_complete_callback callback) {
|
||||||
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));
|
hw_write_context *write_context = malloc(sizeof(hw_write_context));
|
||||||
http_response *resp = (http_response *)response;
|
http_response *resp = (http_response *)response;
|
||||||
hw_string *response_buffer = create_response_buffer(response);
|
hw_string *response_buffer = create_response_buffer(response);
|
||||||
|
@ -150,3 +140,28 @@ void hw_http_response_send(hw_http_response* response, void* user_data, http_res
|
||||||
free(response_buffer);
|
free(response_buffer);
|
||||||
hw_free_http_response(response);
|
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);
|
||||||
|
}
|
||||||
|
|
|
@ -2,15 +2,13 @@
|
||||||
#include "haywire.h"
|
#include "haywire.h"
|
||||||
#include "http_connection.h"
|
#include "http_connection.h"
|
||||||
|
|
||||||
typedef struct
|
typedef struct {
|
||||||
{
|
|
||||||
hw_string name;
|
hw_string name;
|
||||||
hw_string value;
|
hw_string value;
|
||||||
} http_header;
|
} http_header;
|
||||||
|
|
||||||
#define MAX_HEADERS 64
|
#define MAX_HEADERS 64
|
||||||
typedef struct
|
typedef struct {
|
||||||
{
|
|
||||||
http_connection *connection;
|
http_connection *connection;
|
||||||
http_request *request;
|
http_request *request;
|
||||||
unsigned short http_major;
|
unsigned short http_major;
|
||||||
|
@ -22,8 +20,7 @@ typedef struct
|
||||||
int sent;
|
int sent;
|
||||||
} http_response;
|
} http_response;
|
||||||
|
|
||||||
typedef struct
|
typedef struct {
|
||||||
{
|
|
||||||
http_connection *connection;
|
http_connection *connection;
|
||||||
http_request *request;
|
http_request *request;
|
||||||
void *user_data;
|
void *user_data;
|
||||||
|
|
|
@ -23,39 +23,32 @@ void create_cached_http_request(khash_t(string_hashmap)* http_request_cache, con
|
||||||
void set_cached_request(khash_t(string_hashmap) * http_request_cache, char *http_status, hw_string *cache_entry);
|
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);
|
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);
|
uv_key_create(&thread_cache_key);
|
||||||
}
|
}
|
||||||
|
|
||||||
void http_request_cache_configure_listener(uv_loop_t* loop, uv_async_t* handle)
|
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_t *cache_invalidation_timer = malloc(sizeof(uv_timer_t));
|
||||||
uv_timer_init(loop, cache_invalidation_timer);
|
uv_timer_init(loop, cache_invalidation_timer);
|
||||||
uv_timer_start(cache_invalidation_timer, http_request_cache_timer, 500, 500);
|
uv_timer_start(cache_invalidation_timer, http_request_cache_timer, 500, 500);
|
||||||
|
|
||||||
if (handle != NULL)
|
if (handle != NULL) {
|
||||||
{
|
|
||||||
uv_unref((uv_handle_t *)cache_invalidation_timer);
|
uv_unref((uv_handle_t *)cache_invalidation_timer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void http_request_cache_timer(uv_timer_t* timer)
|
void http_request_cache_timer(uv_timer_t *timer) {
|
||||||
{
|
|
||||||
khash_t(string_hashmap) *http_request_cache = uv_key_get(&thread_cache_key);
|
khash_t(string_hashmap) *http_request_cache = uv_key_get(&thread_cache_key);
|
||||||
if (http_request_cache != NULL)
|
if (http_request_cache != NULL) {
|
||||||
{
|
|
||||||
free_http_request_cache(http_request_cache);
|
free_http_request_cache(http_request_cache);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void free_http_request_cache(khash_t(string_hashmap)* http_request_cache)
|
void free_http_request_cache(khash_t(string_hashmap) * http_request_cache) {
|
||||||
{
|
|
||||||
const char *k;
|
const char *k;
|
||||||
hw_string *v;
|
hw_string *v;
|
||||||
|
|
||||||
kh_foreach(http_request_cache, k, v,
|
kh_foreach(http_request_cache, k, v, {
|
||||||
{
|
|
||||||
free((char *)k);
|
free((char *)k);
|
||||||
free(v->value);
|
free(v->value);
|
||||||
free(v);
|
free(v);
|
||||||
|
@ -65,8 +58,7 @@ void free_http_request_cache(khash_t(string_hashmap)* http_request_cache)
|
||||||
uv_key_set(&thread_cache_key, NULL);
|
uv_key_set(&thread_cache_key, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void create_cached_http_request(khash_t(string_hashmap)* http_request_cache, const char* http_status)
|
void create_cached_http_request(khash_t(string_hashmap) * http_request_cache, const char *http_status) {
|
||||||
{
|
|
||||||
hw_string *cache_entry = malloc(sizeof(hw_string));
|
hw_string *cache_entry = malloc(sizeof(hw_string));
|
||||||
cache_entry->value = calloc(1024, 1);
|
cache_entry->value = calloc(1024, 1);
|
||||||
cache_entry->length = 0;
|
cache_entry->length = 0;
|
||||||
|
@ -93,21 +85,18 @@ void create_cached_http_request(khash_t(string_hashmap)* http_request_cache, con
|
||||||
set_cached_request(http_request_cache, http_status, cache_entry);
|
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)
|
void set_cached_request(khash_t(string_hashmap) * http_request_cache, char *http_status, hw_string *cache_entry) {
|
||||||
{
|
|
||||||
int ret;
|
int ret;
|
||||||
khiter_t key;
|
khiter_t key;
|
||||||
|
|
||||||
key = kh_get(string_hashmap, http_request_cache, http_status);
|
key = kh_get(string_hashmap, http_request_cache, http_status);
|
||||||
if (key == kh_end(http_request_cache))
|
if (key == kh_end(http_request_cache)) {
|
||||||
{
|
|
||||||
key = kh_put(string_hashmap, http_request_cache, dupstr(http_status), &ret);
|
key = kh_put(string_hashmap, http_request_cache, dupstr(http_status), &ret);
|
||||||
kh_value(http_request_cache, key) = cache_entry;
|
kh_value(http_request_cache, key) = cache_entry;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
hw_string* get_cached_request(const char* http_status)
|
hw_string *get_cached_request(const char *http_status) {
|
||||||
{
|
|
||||||
int is_missing = 0;
|
int is_missing = 0;
|
||||||
void *val;
|
void *val;
|
||||||
khash_t(string_hashmap) * http_request_cache;
|
khash_t(string_hashmap) * http_request_cache;
|
||||||
|
@ -115,38 +104,29 @@ hw_string* get_cached_request(const char* http_status)
|
||||||
|
|
||||||
/* This thread hasn't created a response cache so create one */
|
/* This thread hasn't created a response cache so create one */
|
||||||
http_request_cache = uv_key_get(&thread_cache_key);
|
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);
|
http_request_cache = kh_init(string_hashmap);
|
||||||
uv_key_set(&thread_cache_key, http_request_cache);
|
uv_key_set(&thread_cache_key, http_request_cache);
|
||||||
}
|
}
|
||||||
|
|
||||||
key = kh_get(string_hashmap, http_request_cache, http_status);
|
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);
|
create_cached_http_request(http_request_cache, http_status);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
val = kh_value(http_request_cache, key);
|
val = kh_value(http_request_cache, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
key = kh_get(string_hashmap, http_request_cache, http_status);
|
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;
|
is_missing = 1;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
val = kh_value(http_request_cache, key);
|
val = kh_value(http_request_cache, key);
|
||||||
is_missing = 0;
|
is_missing = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_missing)
|
if (is_missing) {
|
||||||
{
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,15 +19,18 @@
|
||||||
#include "configuration/configuration.h"
|
#include "configuration/configuration.h"
|
||||||
#include "http_connection.h"
|
#include "http_connection.h"
|
||||||
#include "http_request.h"
|
#include "http_request.h"
|
||||||
|
#include "misc.h"
|
||||||
|
|
||||||
#define UVERR(err, msg) dzlog_error("%s: %s\n", msg, uv_strerror(err))
|
#define UVERR(err, msg) dzlog_error("%s: %s\n", msg, uv_strerror(err))
|
||||||
//fprintf(stderr, "%s: %s\n", msg, uv_strerror(err))
|
//fprintf(stderr, "%s: %s\n", msg, uv_strerror(err))
|
||||||
|
#if 0
|
||||||
#define CHECK(r, msg) \
|
#define CHECK(r, msg) \
|
||||||
if (r) { \
|
if (r) { \
|
||||||
uv_err_t err = uv_last_error(uv_loop); \
|
uv_err_t err = uv_last_error(uv_loop); \
|
||||||
UVERR(err, msg); \
|
UVERR(err, msg); \
|
||||||
exit(1); \
|
exit(1); \
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
KHASH_MAP_INIT_STR(string_hashmap, hw_route_entry *)
|
KHASH_MAP_INIT_STR(string_hashmap, hw_route_entry *)
|
||||||
|
|
||||||
|
@ -38,16 +41,15 @@ static struct sockaddr_in listen_address;
|
||||||
|
|
||||||
uv_loop_t *uv_loop;
|
uv_loop_t *uv_loop;
|
||||||
void *routes;
|
void *routes;
|
||||||
hw_string* http_v1_0;
|
//hw_string* http_v1_0;
|
||||||
hw_string *http_v1_1;
|
hw_string *http_v1_1;
|
||||||
hw_string *server_name;
|
hw_string *server_name;
|
||||||
int listener_count;
|
int listener_count;
|
||||||
uv_async_t *listener_async_handles;
|
uv_async_t *listener_async_handles;
|
||||||
uv_loop_t* listener_event_loops;
|
//uv_loop_t* listener_event_loops;
|
||||||
uv_barrier_t *listeners_created_barrier;
|
uv_barrier_t *listeners_created_barrier;
|
||||||
|
|
||||||
int hw_init_with_config(configuration* c)
|
int hw_init_with_config(configuration *c) {
|
||||||
{
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
char route[] = "/stats";
|
char route[] = "/stats";
|
||||||
hw_http_add_route(route, get_server_stats, NULL);
|
hw_http_add_route(route, get_server_stats, NULL);
|
||||||
|
@ -67,26 +69,22 @@ int hw_init_with_config(configuration* c)
|
||||||
http_v1_1 = create_string("HTTP/1.1 ");
|
http_v1_1 = create_string("HTTP/1.1 ");
|
||||||
server_name = create_string("Server: Haywire/master");
|
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_stream_on_read = &http_stream_on_read_http_parser;
|
||||||
}
|
}
|
||||||
http_server_write_response = &http_server_write_response_single;
|
http_server_write_response = &http_server_write_response_single;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int hw_init_from_config(char* configuration_filename)
|
int hw_init_from_config(char *configuration_filename) {
|
||||||
{
|
|
||||||
configuration *config = load_configuration(configuration_filename);
|
configuration *config = load_configuration(configuration_filename);
|
||||||
if (config == NULL)
|
if (config == NULL) {
|
||||||
{
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
return hw_init_with_config(config);
|
return hw_init_with_config(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
void print_configuration()
|
void print_configuration() {
|
||||||
{
|
|
||||||
#if 0
|
#if 0
|
||||||
dzlog_debug("Address: %s\n\tPort: %d\n\tThreads: %d\n\tBalancer: %s\n\t"
|
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",
|
"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
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
http_connection* create_http_connection()
|
http_connection *create_http_connection() {
|
||||||
{
|
|
||||||
http_connection *connection = calloc(1, sizeof(http_connection));
|
http_connection *connection = calloc(1, sizeof(http_connection));
|
||||||
connection->buffer = http_request_buffer_init(config->max_request_size);
|
connection->buffer = http_request_buffer_init(config->max_request_size);
|
||||||
INCREMENT_STAT(stat_connections_created_total);
|
INCREMENT_STAT(stat_connections_created_total);
|
||||||
return connection;
|
return connection;
|
||||||
}
|
}
|
||||||
|
|
||||||
void free_http_connection(http_connection* connection)
|
void free_http_connection(http_connection *connection) {
|
||||||
{
|
if (connection->request) {
|
||||||
if (connection->request)
|
|
||||||
{
|
|
||||||
free_http_request(connection->request);
|
free_http_request(connection->request);
|
||||||
}
|
}
|
||||||
http_request_buffer_destroy(connection->buffer);
|
http_request_buffer_destroy(connection->buffer);
|
||||||
|
@ -120,8 +115,7 @@ void free_http_connection(http_connection* connection)
|
||||||
INCREMENT_STAT(stat_connections_destroyed_total);
|
INCREMENT_STAT(stat_connections_destroyed_total);
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_route(void* hashmap, char* name, hw_route_entry* route_entry)
|
void set_route(void *hashmap, char *name, hw_route_entry *route_entry) {
|
||||||
{
|
|
||||||
int ret;
|
int ret;
|
||||||
khiter_t k;
|
khiter_t k;
|
||||||
khash_t(string_hashmap) *h = hashmap;
|
khash_t(string_hashmap) *h = hashmap;
|
||||||
|
@ -129,37 +123,35 @@ void set_route(void* hashmap, char* name, hw_route_entry* route_entry)
|
||||||
kh_value(h, k) = route_entry;
|
kh_value(h, k) = route_entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
void hw_http_add_route(char *route, http_request_callback callback, void* user_data)
|
void hw_http_add_route(char *route, http_request_callback callback, void *user_data) {
|
||||||
{
|
|
||||||
hw_route_entry *route_entry = malloc(sizeof(hw_route_entry));
|
hw_route_entry *route_entry = malloc(sizeof(hw_route_entry));
|
||||||
route_entry->callback = callback;
|
route_entry->callback = callback;
|
||||||
route_entry->user_data = user_data;
|
route_entry->user_data = user_data;
|
||||||
|
|
||||||
if (routes == NULL)
|
if (routes == NULL) {
|
||||||
{
|
|
||||||
routes = kh_init(string_hashmap);
|
routes = kh_init(string_hashmap);
|
||||||
}
|
}
|
||||||
set_route(routes, route, route_entry);
|
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 */
|
/* TODO: Shut down accepting incoming requests */
|
||||||
khash_t(string_hashmap) *h = routes;
|
khash_t(string_hashmap) *h = routes;
|
||||||
const char *k;
|
const char *k;
|
||||||
const char *v;
|
const char *v;
|
||||||
kh_foreach(h, k, v, { free((char*)k); free((char*)v); });
|
kh_foreach(h, k, v, {
|
||||||
|
free((char *)k);
|
||||||
|
free((char *)v);
|
||||||
|
});
|
||||||
kh_destroy(string_hashmap, routes);
|
kh_destroy(string_hashmap, routes);
|
||||||
}
|
}
|
||||||
|
|
||||||
int hw_http_open()
|
int hw_http_open() {
|
||||||
{
|
int threads = (int)config->thread_count;
|
||||||
int threads = config->thread_count;
|
uv_async_t *service_handle;
|
||||||
uv_async_t* service_handle = 0;
|
|
||||||
|
|
||||||
if (routes == NULL)
|
if (routes == NULL) {
|
||||||
{
|
|
||||||
routes = kh_init(string_hashmap);
|
routes = kh_init(string_hashmap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -189,30 +181,25 @@ int hw_http_open()
|
||||||
service_handle = malloc(sizeof(uv_async_t));
|
service_handle = malloc(sizeof(uv_async_t));
|
||||||
uv_async_init(uv_loop, service_handle, NULL);
|
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
|
/* 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;
|
int rc;
|
||||||
rc = uv_tcp_init_ex(uv_loop, &server, AF_INET);
|
rc = uv_tcp_init_ex(uv_loop, &server, AF_INET);
|
||||||
if (rc != 0)
|
if (rc != 0) {
|
||||||
{
|
|
||||||
dzlog_warn("TWO %d\n", rc);
|
dzlog_warn("TWO %d\n", rc);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strcmp(config->balancer, "reuseport") == 0)
|
if (strcmp(config->balancer, "reuseport") == 0) {
|
||||||
{
|
|
||||||
uv_os_fd_t fd;
|
uv_os_fd_t fd;
|
||||||
int on = 1;
|
int on = 1;
|
||||||
rc = uv_fileno(&server, &fd);
|
rc = uv_fileno(&server, &fd);
|
||||||
if (rc != 0)
|
if (rc != 0) {
|
||||||
{
|
|
||||||
dzlog_warn("ONE %d\n", rc);
|
dzlog_warn("ONE %d\n", rc);
|
||||||
}
|
}
|
||||||
rc = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, (char *)&on, sizeof(on));
|
rc = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, (char *)&on, sizeof(on));
|
||||||
if (rc != 0)
|
if (rc != 0) {
|
||||||
{
|
|
||||||
dzlog_warn("THREE %d\n", errno);
|
dzlog_warn("THREE %d\n", errno);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -220,52 +207,52 @@ int hw_http_open()
|
||||||
initialize_http_request_cache();
|
initialize_http_request_cache();
|
||||||
http_request_cache_configure_listener(uv_loop, NULL);
|
http_request_cache_configure_listener(uv_loop, NULL);
|
||||||
|
|
||||||
uv_ip4_addr(config->http_listen_address, config->http_listen_port, &listen_address);
|
uv_ip4_addr(config->http_listen_address, (int)config->http_listen_port, &listen_address);
|
||||||
uv_tcp_bind(&server, (const struct sockaddr *)&listen_address, 0);
|
uv_tcp_bind(&server, (const struct sockaddr *)&listen_address, 0);
|
||||||
|
|
||||||
if (config->tcp_nodelay) {
|
if (config->tcp_nodelay) {
|
||||||
uv_tcp_nodelay(&server, 1);
|
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();
|
print_configuration();
|
||||||
dzlog_debug("Listening...\n");
|
dzlog_debug("Listening...\n");
|
||||||
//uv_run(uv_loop, UV_RUN_DEFAULT);
|
//uv_run(uv_loop, UV_RUN_DEFAULT);
|
||||||
}
|
} else if (listener_count > 0 && strcmp(config->balancer, "ipc") == 0) {
|
||||||
else if (listener_count > 0 && strcmp(config->balancer, "ipc") == 0)
|
int i;
|
||||||
{
|
|
||||||
int i = 0;
|
|
||||||
|
|
||||||
/* 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 */
|
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]));
|
servers = calloc(threads, sizeof(servers[0]));
|
||||||
for (i = 0; i < threads; i++)
|
for (i = 0; i < threads; i++) {
|
||||||
{
|
//int rc;
|
||||||
int rc = 0;
|
|
||||||
struct server_ctx *ctx = servers + i;
|
struct server_ctx *ctx = servers + i;
|
||||||
ctx->index = i;
|
ctx->index = i;
|
||||||
ctx->listen_backlog = config->listen_backlog;
|
ctx->listen_backlog = config->listen_backlog;
|
||||||
|
|
||||||
rc = uv_sem_init(&ctx->semaphore, 0);
|
uv_sem_init(&ctx->semaphore, 0);
|
||||||
rc = uv_thread_create(&ctx->thread_id, connection_consumer_start, ctx);
|
uv_thread_create(&ctx->thread_id, connection_consumer_start, ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
uv_barrier_wait(listeners_created_barrier);
|
uv_barrier_wait(listeners_created_barrier);
|
||||||
initialize_http_request_cache();
|
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);
|
start_connection_dispatching(UV_TCP,
|
||||||
}
|
threads,
|
||||||
else if (listener_count > 0 && strcmp(config->balancer, "reuseport") == 0)
|
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;
|
struct server_ctx *servers;
|
||||||
servers = calloc(threads, sizeof(servers[0]));
|
servers = calloc(threads, sizeof(servers[0]));
|
||||||
|
|
||||||
for (int i = 0; i < threads; i++)
|
for (int i = 0; i < threads; i++) {
|
||||||
{
|
|
||||||
struct server_ctx *ctx = servers + i;
|
struct server_ctx *ctx = servers + i;
|
||||||
ctx->index = i;
|
ctx->index = i;
|
||||||
int rc = uv_thread_create(&ctx->thread_id, reuseport_thread_start, ctx);
|
uv_thread_create(&ctx->thread_id, reuseport_thread_start, ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
print_configuration();
|
print_configuration();
|
||||||
|
@ -276,12 +263,10 @@ int hw_http_open()
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void reuseport_thread_start(void *arg)
|
void reuseport_thread_start(void *arg) {
|
||||||
{
|
|
||||||
int rc;
|
int rc;
|
||||||
struct server_ctx *ctx;
|
struct server_ctx *ctx;
|
||||||
uv_loop_t *loop;
|
uv_loop_t *loop;
|
||||||
uv_tcp_t svr;
|
|
||||||
|
|
||||||
ctx = arg;
|
ctx = arg;
|
||||||
loop = uv_loop_new();
|
loop = uv_loop_new();
|
||||||
|
@ -293,27 +278,25 @@ void reuseport_thread_start(void *arg)
|
||||||
struct sockaddr_in addr;
|
struct sockaddr_in addr;
|
||||||
uv_tcp_t server;
|
uv_tcp_t server;
|
||||||
|
|
||||||
rc = uv_tcp_init_ex(loop, &server, AF_INET);
|
uv_tcp_init_ex(loop, &server, AF_INET);
|
||||||
uv_ip4_addr(config->http_listen_address, config->http_listen_port, &addr);
|
uv_ip4_addr(config->http_listen_address, (int)config->http_listen_port, &addr);
|
||||||
|
|
||||||
uv_os_fd_t fd;
|
uv_os_fd_t fd;
|
||||||
int on = 1;
|
int on = 1;
|
||||||
uv_fileno(&server, &fd);
|
uv_fileno(&server, &fd);
|
||||||
rc = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, (char *)&on, sizeof(on));
|
rc = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, (char *)&on, sizeof(on));
|
||||||
if (rc != 0)
|
if (rc != 0) {
|
||||||
{
|
|
||||||
dzlog_warn("%d\n", errno);
|
dzlog_warn("%d\n", errno);
|
||||||
}
|
}
|
||||||
|
|
||||||
uv_tcp_bind(&server, (const struct sockaddr *)&addr, 0);
|
uv_tcp_bind(&server, (const struct sockaddr *)&addr, 0);
|
||||||
int r = uv_listen((uv_stream_t*) &server, 128, http_stream_on_connect);
|
uv_listen((uv_stream_t *)&server, 128, http_stream_on_connect);
|
||||||
|
|
||||||
rc = uv_run(loop, UV_RUN_DEFAULT);
|
uv_run(loop, UV_RUN_DEFAULT);
|
||||||
uv_loop_delete(loop);
|
uv_loop_delete(loop);
|
||||||
}
|
}
|
||||||
|
|
||||||
void http_stream_on_connect(uv_stream_t* stream, int status)
|
void http_stream_on_connect(uv_stream_t *stream, int UNUSED(status)) {
|
||||||
{
|
|
||||||
http_connection *connection = create_http_connection();
|
http_connection *connection = create_http_connection();
|
||||||
uv_tcp_init(stream->loop, &connection->stream);
|
uv_tcp_init(stream->loop, &connection->stream);
|
||||||
http_parser_init(&connection->parser, HTTP_REQUEST);
|
http_parser_init(&connection->parser, HTTP_REQUEST);
|
||||||
|
@ -327,8 +310,7 @@ void http_stream_on_connect(uv_stream_t* stream, int status)
|
||||||
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)
|
void http_stream_on_alloc(uv_handle_t *client, size_t suggested_size, uv_buf_t *buf) {
|
||||||
{
|
|
||||||
http_connection *connection = (http_connection *)client->data;
|
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);
|
||||||
|
@ -345,8 +327,7 @@ void http_stream_on_alloc(uv_handle_t* client, size_t suggested_size, uv_buf_t*
|
||||||
*buf = uv_buf_init(chunk.buffer, chunk.size);
|
*buf = uv_buf_init(chunk.buffer, chunk.size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void http_stream_on_close(uv_handle_t* handle)
|
void http_stream_on_close(uv_handle_t *handle) {
|
||||||
{
|
|
||||||
uv_handle_t *stream = handle;
|
uv_handle_t *stream = handle;
|
||||||
http_connection *connection = stream->data;
|
http_connection *connection = stream->data;
|
||||||
|
|
||||||
|
@ -364,8 +345,7 @@ void http_stream_close_connection(http_connection* connection) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void handle_request_error(http_connection* connection)
|
void handle_request_error(http_connection *connection) {
|
||||||
{
|
|
||||||
uv_handle_t *stream = &connection->stream;
|
uv_handle_t *stream = &connection->stream;
|
||||||
|
|
||||||
if (connection->state == OPEN) {
|
if (connection->state == OPEN) {
|
||||||
|
@ -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) {
|
if (connection->request) {
|
||||||
connection->request->state = BAD_REQUEST;
|
connection->request->state = BAD_REQUEST;
|
||||||
}
|
}
|
||||||
|
@ -393,8 +372,7 @@ void handle_bad_request(http_connection* connection)
|
||||||
handle_request_error(connection);
|
handle_request_error(connection);
|
||||||
}
|
}
|
||||||
|
|
||||||
void handle_buffer_exceeded_error(http_connection* connection)
|
void handle_buffer_exceeded_error(http_connection *connection) {
|
||||||
{
|
|
||||||
if (connection->request) {
|
if (connection->request) {
|
||||||
connection->request->state = SIZE_EXCEEDED;
|
connection->request->state = SIZE_EXCEEDED;
|
||||||
}
|
}
|
||||||
|
@ -402,8 +380,7 @@ void handle_buffer_exceeded_error(http_connection* connection)
|
||||||
handle_request_error(connection);
|
handle_request_error(connection);
|
||||||
}
|
}
|
||||||
|
|
||||||
void handle_internal_error(http_connection* connection)
|
void handle_internal_error(http_connection *connection) {
|
||||||
{
|
|
||||||
if (connection->request) {
|
if (connection->request) {
|
||||||
connection->request->state = INTERNAL_ERROR;
|
connection->request->state = INTERNAL_ERROR;
|
||||||
}
|
}
|
||||||
|
@ -411,18 +388,16 @@ void handle_internal_error(http_connection* connection)
|
||||||
handle_request_error(connection);
|
handle_request_error(connection);
|
||||||
}
|
}
|
||||||
|
|
||||||
void http_stream_on_shutdown(uv_shutdown_t* req, int status)
|
void http_stream_on_shutdown(uv_shutdown_t *req, int UNUSED(status)) {
|
||||||
{
|
|
||||||
http_connection *connection = req->data;
|
http_connection *connection = req->data;
|
||||||
uv_handle_t* stream = &connection->stream;
|
// uv_handle_t *stream = &connection->stream;
|
||||||
if (connection->state == OPEN) {
|
if (connection->state == OPEN) {
|
||||||
http_stream_close_connection(connection);
|
http_stream_close_connection(connection);
|
||||||
}
|
}
|
||||||
free(req);
|
free(req);
|
||||||
}
|
}
|
||||||
|
|
||||||
void http_stream_on_read_http_parser(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf)
|
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;
|
http_connection *connection = (http_connection *)tcp->data;
|
||||||
|
|
||||||
if (nread > 0) {
|
if (nread > 0) {
|
||||||
|
@ -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) {
|
} else if (nread == 0) {
|
||||||
/* no-op - there's no data to be read, but there might be later */
|
/* 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);
|
handle_buffer_exceeded_error(connection);
|
||||||
}
|
} else if (nread == UV_EOF) {
|
||||||
else if (nread == UV_EOF){
|
|
||||||
uv_shutdown_t *req = malloc(sizeof(uv_shutdown_t));
|
uv_shutdown_t *req = malloc(sizeof(uv_shutdown_t));
|
||||||
req->data = connection;
|
req->data = connection;
|
||||||
uv_shutdown(req, &connection->stream, http_stream_on_shutdown);
|
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 */
|
/* Let's close the connection as the other peer just disappeared */
|
||||||
http_stream_close_connection(connection);
|
http_stream_close_connection(connection);
|
||||||
} else {
|
} else {
|
||||||
|
@ -462,15 +434,13 @@ 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(response_string);
|
||||||
free(write_context);
|
free(write_context);
|
||||||
free(write_req);
|
free(write_req);
|
||||||
}
|
}
|
||||||
|
|
||||||
int http_server_write_response_single(hw_write_context* write_context, hw_string* response)
|
int http_server_write_response_single(hw_write_context *write_context, hw_string *response) {
|
||||||
{
|
|
||||||
http_connection *connection = write_context->connection;
|
http_connection *connection = write_context->connection;
|
||||||
|
|
||||||
if (connection->state == OPEN) {
|
if (connection->state == OPEN) {
|
||||||
|
@ -485,7 +455,7 @@ int http_server_write_response_single(hw_write_context* write_context, hw_string
|
||||||
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)) {
|
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);
|
uv_write(write_req, stream, resbuf, 1, http_server_after_write);
|
||||||
/* TODO: Use the return values from uv_write() */
|
/* TODO: Use the return values from uv_write() */
|
||||||
} else {
|
} else {
|
||||||
|
@ -497,11 +467,10 @@ int http_server_write_response_single(hw_write_context* write_context, hw_string
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void http_server_after_write(uv_write_t* req, int status)
|
void http_server_after_write(uv_write_t *req, int UNUSED(status)) {
|
||||||
{
|
|
||||||
hw_write_context *write_context = (hw_write_context *)req->data;
|
hw_write_context *write_context = (hw_write_context *)req->data;
|
||||||
uv_buf_t *resbuf = (uv_buf_t *)(req + 1);
|
uv_buf_t *resbuf = (uv_buf_t *)(req + 1);
|
||||||
uv_handle_t* stream = (uv_handle_t*) req->handle;
|
//uv_handle_t *stream = (uv_handle_t *)req->handle;
|
||||||
|
|
||||||
http_connection *connection = write_context->connection;
|
http_connection *connection = write_context->connection;
|
||||||
|
|
||||||
|
@ -509,11 +478,9 @@ void http_server_after_write(uv_write_t* req, int status)
|
||||||
http_stream_close_connection(connection);
|
http_stream_close_connection(connection);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (write_context->callback)
|
if (write_context->callback) {
|
||||||
{
|
|
||||||
write_context->callback(write_context->user_data);
|
write_context->callback(write_context->user_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
http_server_cleanup_write(resbuf->base, write_context, req);
|
http_server_cleanup_write(resbuf->base, write_context, req);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,14 +5,12 @@
|
||||||
#include "http_parser.h"
|
#include "http_parser.h"
|
||||||
#include "http_response.h"
|
#include "http_response.h"
|
||||||
|
|
||||||
typedef struct
|
typedef struct {
|
||||||
{
|
|
||||||
http_request_callback callback;
|
http_request_callback callback;
|
||||||
void *user_data;
|
void *user_data;
|
||||||
} hw_route_entry;
|
} hw_route_entry;
|
||||||
|
|
||||||
union stream_handle
|
union stream_handle {
|
||||||
{
|
|
||||||
uv_pipe_t pipe;
|
uv_pipe_t pipe;
|
||||||
uv_tcp_t tcp;
|
uv_tcp_t tcp;
|
||||||
};
|
};
|
||||||
|
|
|
@ -3,8 +3,7 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "haywire.h"
|
#include "haywire.h"
|
||||||
|
|
||||||
hw_string* create_string(const char* value)
|
hw_string *create_string(const char *value) {
|
||||||
{
|
|
||||||
int length = (int)strlen(value);
|
int length = (int)strlen(value);
|
||||||
hw_string *str = malloc(sizeof(hw_string));
|
hw_string *str = malloc(sizeof(hw_string));
|
||||||
str->value = malloc(length);
|
str->value = malloc(length);
|
||||||
|
@ -13,8 +12,7 @@ hw_string* create_string(const char* value)
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
hw_string* hw_strdup(hw_string* tocopy)
|
hw_string *hw_strdup(hw_string *tocopy) {
|
||||||
{
|
|
||||||
hw_string *str = malloc(sizeof(hw_string));
|
hw_string *str = malloc(sizeof(hw_string));
|
||||||
str->value = tocopy->value;
|
str->value = tocopy->value;
|
||||||
str->length = tocopy->length;
|
str->length = tocopy->length;
|
||||||
|
@ -41,32 +39,27 @@ int hw_strcmp(hw_string* a, hw_string* b) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void append_string(hw_string* destination, hw_string* source)
|
void append_string(hw_string *destination, hw_string *source) {
|
||||||
{
|
|
||||||
void *location = (void *)(destination->value + destination->length);
|
void *location = (void *)(destination->value + destination->length);
|
||||||
memcpy(location, source->value, source->length);
|
memcpy(location, source->value, source->length);
|
||||||
destination->length += source->length;
|
destination->length += source->length;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Added because of http://stackoverflow.com/questions/8359966/strdup-returning-address-out-of-bounds */
|
/* Added because of http://stackoverflow.com/questions/8359966/strdup-returning-address-out-of-bounds */
|
||||||
char* dupstr(const char *s)
|
char *dupstr(const char *s) {
|
||||||
{
|
|
||||||
char *result = malloc(strlen(s) + 1);
|
char *result = malloc(strlen(s) + 1);
|
||||||
if (result != NULL)
|
if (result != NULL) {
|
||||||
{
|
|
||||||
strcpy(result, s);
|
strcpy(result, s);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void string_from_int(hw_string* str, int val, int base)
|
void string_from_int(hw_string *str, int val, int base) {
|
||||||
{
|
|
||||||
static char buf[32] = {0};
|
static char buf[32] = {0};
|
||||||
int i = 30;
|
int i = 30;
|
||||||
int length = 0;
|
int length = 0;
|
||||||
|
|
||||||
for(; val && i ; --i, val /= base)
|
for (; val && i; --i, val /= base) {
|
||||||
{
|
|
||||||
buf[i] = "0123456789abcdef"[val % base];
|
buf[i] = "0123456789abcdef"[val % base];
|
||||||
length++;
|
length++;
|
||||||
}
|
}
|
||||||
|
|
|
@ -113,7 +113,6 @@
|
||||||
* Added destructor
|
* Added destructor
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#ifndef __AC_KHASH_H
|
#ifndef __AC_KHASH_H
|
||||||
#define __AC_KHASH_H
|
#define __AC_KHASH_H
|
||||||
|
|
||||||
|
@ -163,7 +162,8 @@ typedef khint_t khiter_t;
|
||||||
#define __ac_fsize(m) ((m) < 16 ? 1 : (m) >> 4)
|
#define __ac_fsize(m) ((m) < 16 ? 1 : (m) >> 4)
|
||||||
|
|
||||||
#ifndef kroundup32
|
#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
|
#endif
|
||||||
|
|
||||||
#ifndef kcalloc
|
#ifndef kcalloc
|
||||||
|
@ -199,57 +199,63 @@ 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);
|
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) \
|
#define __KHASH_IMPL(name, SCOPE, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal) \
|
||||||
SCOPE kh_##name##_t *kh_init_##name(void) { \
|
SCOPE kh_##name##_t *kh_init_##name(void) { return (kh_##name##_t *)kcalloc(1, sizeof(kh_##name##_t)); } \
|
||||||
return (kh_##name##_t*)kcalloc(1, sizeof(kh_##name##_t)); \
|
SCOPE void kh_destroy_##name(kh_##name##_t *h) { \
|
||||||
} \
|
|
||||||
SCOPE void kh_destroy_##name(kh_##name##_t *h) \
|
|
||||||
{ \
|
|
||||||
if (h) { \
|
if (h) { \
|
||||||
kfree((void *)h->keys); kfree(h->flags); \
|
kfree((void *)h->keys); \
|
||||||
|
kfree(h->flags); \
|
||||||
kfree((void *)h->vals); \
|
kfree((void *)h->vals); \
|
||||||
kfree(h); \
|
kfree(h); \
|
||||||
} \
|
} \
|
||||||
} \
|
} \
|
||||||
SCOPE void kh_clear_##name(kh_##name##_t *h) \
|
SCOPE void kh_clear_##name(kh_##name##_t *h) { \
|
||||||
{ \
|
|
||||||
if (h && h->flags) { \
|
if (h && h->flags) { \
|
||||||
memset(h->flags, 0xaa, __ac_fsize(h->n_buckets) * sizeof(khint32_t)); \
|
memset(h->flags, 0xaa, __ac_fsize(h->n_buckets) * sizeof(khint32_t)); \
|
||||||
h->size = h->n_occupied = 0; \
|
h->size = h->n_occupied = 0; \
|
||||||
} \
|
} \
|
||||||
} \
|
} \
|
||||||
SCOPE khint_t kh_get_##name(const kh_##name##_t *h, khkey_t key) \
|
SCOPE khint_t kh_get_##name(const kh_##name##_t *h, khkey_t key) { \
|
||||||
{ \
|
|
||||||
if (h->n_buckets) { \
|
if (h->n_buckets) { \
|
||||||
khint_t k, i, last, mask, step = 0; \
|
khint_t k, i, last, mask, step = 0; \
|
||||||
mask = h->n_buckets - 1; \
|
mask = h->n_buckets - 1; \
|
||||||
k = __hash_func(key); i = k & mask; \
|
k = __hash_func(key); \
|
||||||
|
i = k & mask; \
|
||||||
last = i; \
|
last = i; \
|
||||||
while (!__ac_isempty(h->flags, i) && (__ac_isdel(h->flags, i) || !__hash_equal(h->keys[i], key))) { \
|
while (!__ac_isempty(h->flags, i) && (__ac_isdel(h->flags, i) || !__hash_equal(h->keys[i], key))) { \
|
||||||
i = (i + (++step)) & mask; \
|
i = (i + (++step)) & mask; \
|
||||||
if (i == last) return h->n_buckets; \
|
if (i == last) \
|
||||||
|
return h->n_buckets; \
|
||||||
} \
|
} \
|
||||||
return __ac_iseither(h->flags, i) ? h->n_buckets : i; \
|
return __ac_iseither(h->flags, i) ? h->n_buckets : i; \
|
||||||
} else return 0; \
|
} else \
|
||||||
|
return 0; \
|
||||||
} \
|
} \
|
||||||
SCOPE int kh_resize_##name(kh_##name##_t *h, khint_t new_n_buckets) \
|
SCOPE int kh_resize_##name( \
|
||||||
{ /* This function uses 0.25*n_buckets bytes of working space instead of [sizeof(key_t+val_t)+.25]*n_buckets. */ \
|
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; \
|
khint32_t *new_flags = 0; \
|
||||||
khint_t j = 1; \
|
khint_t j = 1; \
|
||||||
{ \
|
{ \
|
||||||
kroundup32(new_n_buckets); \
|
kroundup32(new_n_buckets); \
|
||||||
if (new_n_buckets < 4) new_n_buckets = 4; \
|
if (new_n_buckets < 4) \
|
||||||
if (h->size >= (khint_t)(new_n_buckets * __ac_HASH_UPPER + 0.5)) j = 0; /* requested size is too small */ \
|
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 */ \
|
else { /* hash table size to be changed (shrink or expand); rehash */ \
|
||||||
new_flags = (khint32_t *)kmalloc(__ac_fsize(new_n_buckets) * sizeof(khint32_t)); \
|
new_flags = (khint32_t *)kmalloc(__ac_fsize(new_n_buckets) * sizeof(khint32_t)); \
|
||||||
if (!new_flags) return -1; \
|
if (!new_flags) \
|
||||||
|
return -1; \
|
||||||
memset(new_flags, 0xaa, __ac_fsize(new_n_buckets) * sizeof(khint32_t)); \
|
memset(new_flags, 0xaa, __ac_fsize(new_n_buckets) * sizeof(khint32_t)); \
|
||||||
if (h->n_buckets < new_n_buckets) { /* expand */ \
|
if (h->n_buckets < new_n_buckets) { /* expand */ \
|
||||||
khkey_t *new_keys = (khkey_t *)krealloc((void *)h->keys, new_n_buckets * sizeof(khkey_t)); \
|
khkey_t *new_keys = (khkey_t *)krealloc((void *)h->keys, new_n_buckets * sizeof(khkey_t)); \
|
||||||
if (!new_keys) return -1; \
|
if (!new_keys) \
|
||||||
|
return -1; \
|
||||||
h->keys = new_keys; \
|
h->keys = new_keys; \
|
||||||
if (kh_is_map) { \
|
if (kh_is_map) { \
|
||||||
khval_t *new_vals = (khval_t *)krealloc((void *)h->vals, new_n_buckets * sizeof(khval_t)); \
|
khval_t *new_vals = (khval_t *)krealloc((void *)h->vals, new_n_buckets * sizeof(khval_t)); \
|
||||||
if (!new_vals) return -1; \
|
if (!new_vals) \
|
||||||
|
return -1; \
|
||||||
h->vals = new_vals; \
|
h->vals = new_vals; \
|
||||||
} \
|
} \
|
||||||
} /* otherwise shrink */ \
|
} /* otherwise shrink */ \
|
||||||
|
@ -262,21 +268,32 @@ khkey_t key = h->keys[j]; \
|
||||||
khval_t val; \
|
khval_t val; \
|
||||||
khint_t new_mask; \
|
khint_t new_mask; \
|
||||||
new_mask = new_n_buckets - 1; \
|
new_mask = new_n_buckets - 1; \
|
||||||
if (kh_is_map) val = h->vals[j]; \
|
if (kh_is_map) \
|
||||||
|
val = h->vals[j]; \
|
||||||
__ac_set_isdel_true(h->flags, j); \
|
__ac_set_isdel_true(h->flags, j); \
|
||||||
while (1) { /* kick-out process; sort of like in Cuckoo hashing */ \
|
while (1) { /* kick-out process; sort of like in Cuckoo hashing */ \
|
||||||
khint_t k, i, step = 0; \
|
khint_t k, i, step = 0; \
|
||||||
k = __hash_func(key); \
|
k = __hash_func(key); \
|
||||||
i = k & new_mask; \
|
i = k & new_mask; \
|
||||||
while (!__ac_isempty(new_flags, i)) i = (i + (++step)) & new_mask; \
|
while (!__ac_isempty(new_flags, i)) \
|
||||||
|
i = (i + (++step)) & new_mask; \
|
||||||
__ac_set_isempty_false(new_flags, i); \
|
__ac_set_isempty_false(new_flags, i); \
|
||||||
if (i < h->n_buckets && __ac_iseither(h->flags, i) == 0) { /* kick out the existing element */ \
|
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; } \
|
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 */ \
|
__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 */ \
|
} else { /* write the element and jump out of the loop */ \
|
||||||
h->keys[i] = key; \
|
h->keys[i] = key; \
|
||||||
if (kh_is_map) h->vals[i] = val; \
|
if (kh_is_map) \
|
||||||
|
h->vals[i] = val; \
|
||||||
break; \
|
break; \
|
||||||
} \
|
} \
|
||||||
} \
|
} \
|
||||||
|
@ -284,7 +301,8 @@ break; \
|
||||||
} \
|
} \
|
||||||
if (h->n_buckets > new_n_buckets) { /* shrink the hash table */ \
|
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)); \
|
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)); \
|
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 */ \
|
kfree(h->flags); /* free the working space */ \
|
||||||
h->flags = new_flags; \
|
h->flags = new_flags; \
|
||||||
|
@ -294,50 +312,61 @@ h->upper_bound = (khint_t)(h->n_buckets * __ac_HASH_UPPER + 0.5); \
|
||||||
} \
|
} \
|
||||||
return 0; \
|
return 0; \
|
||||||
} \
|
} \
|
||||||
SCOPE khint_t kh_put_##name(kh_##name##_t *h, khkey_t key, int *ret) \
|
SCOPE khint_t kh_put_##name(kh_##name##_t *h, khkey_t key, int *ret) { \
|
||||||
{ \
|
|
||||||
khint_t x; \
|
khint_t x; \
|
||||||
if (h->n_occupied >= h->upper_bound) { /* update the hash table */ \
|
if (h->n_occupied >= h->upper_bound) { /* update the hash table */ \
|
||||||
if (h->n_buckets > (h->size << 1)) { \
|
if (h->n_buckets > (h->size << 1)) { \
|
||||||
if (kh_resize_##name(h, h->n_buckets - 1) < 0) { /* clear "deleted" elements */ \
|
if (kh_resize_##name(h, h->n_buckets - 1) < 0) { /* clear "deleted" elements */ \
|
||||||
*ret = -1; return h->n_buckets; \
|
*ret = -1; \
|
||||||
|
return h->n_buckets; \
|
||||||
} \
|
} \
|
||||||
} else if (kh_resize_##name(h, h->n_buckets + 1) < 0) { /* expand the hash table */ \
|
} else if (kh_resize_##name(h, h->n_buckets + 1) < 0) { /* expand the hash table */ \
|
||||||
*ret = -1; return h->n_buckets; \
|
*ret = -1; \
|
||||||
|
return h->n_buckets; \
|
||||||
} \
|
} \
|
||||||
} /* TODO: to implement automatically shrinking; resize() already support shrinking */ \
|
} /* TODO: to implement automatically shrinking; resize() already support shrinking */ \
|
||||||
{ \
|
{ \
|
||||||
khint_t k, i, site, last, mask = h->n_buckets - 1, step = 0; \
|
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; \
|
x = site = h->n_buckets; \
|
||||||
if (__ac_isempty(h->flags, i)) x = i; /* for speed up */ \
|
k = __hash_func(key); \
|
||||||
|
i = k & mask; \
|
||||||
|
if (__ac_isempty(h->flags, i)) \
|
||||||
|
x = i; /* for speed up */ \
|
||||||
else { \
|
else { \
|
||||||
last = i; \
|
last = i; \
|
||||||
while (!__ac_isempty(h->flags, i) && (__ac_isdel(h->flags, i) || !__hash_equal(h->keys[i], key))) { \
|
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; \
|
if (__ac_isdel(h->flags, i)) \
|
||||||
|
site = i; \
|
||||||
i = (i + (++step)) & mask; \
|
i = (i + (++step)) & mask; \
|
||||||
if (i == last) { x = site; break; } \
|
if (i == last) { \
|
||||||
|
x = site; \
|
||||||
|
break; \
|
||||||
|
} \
|
||||||
} \
|
} \
|
||||||
if (x == h->n_buckets) { \
|
if (x == h->n_buckets) { \
|
||||||
if (__ac_isempty(h->flags, i) && site != h->n_buckets) x = site; \
|
if (__ac_isempty(h->flags, i) && site != h->n_buckets) \
|
||||||
else x = i; \
|
x = site; \
|
||||||
|
else \
|
||||||
|
x = i; \
|
||||||
} \
|
} \
|
||||||
} \
|
} \
|
||||||
} \
|
} \
|
||||||
if (__ac_isempty(h->flags, x)) { /* not present at all */ \
|
if (__ac_isempty(h->flags, x)) { /* not present at all */ \
|
||||||
h->keys[x] = key; \
|
h->keys[x] = key; \
|
||||||
__ac_set_isboth_false(h->flags, x); \
|
__ac_set_isboth_false(h->flags, x); \
|
||||||
++h->size; ++h->n_occupied; \
|
++h->size; \
|
||||||
|
++h->n_occupied; \
|
||||||
*ret = 1; \
|
*ret = 1; \
|
||||||
} else if (__ac_isdel(h->flags, x)) { /* deleted */ \
|
} else if (__ac_isdel(h->flags, x)) { /* deleted */ \
|
||||||
h->keys[x] = key; \
|
h->keys[x] = key; \
|
||||||
__ac_set_isboth_false(h->flags, x); \
|
__ac_set_isboth_false(h->flags, x); \
|
||||||
++h->size; \
|
++h->size; \
|
||||||
*ret = 2; \
|
*ret = 2; \
|
||||||
} else *ret = 0; /* Don't touch h->keys[x] if present and not deleted */ \
|
} else \
|
||||||
|
*ret = 0; /* Don't touch h->keys[x] if present and not deleted */ \
|
||||||
return x; \
|
return x; \
|
||||||
} \
|
} \
|
||||||
SCOPE void kh_del_##name(kh_##name##_t *h, khint_t x) \
|
SCOPE void kh_del_##name(kh_##name##_t *h, khint_t x) { \
|
||||||
{ \
|
|
||||||
if (x != h->n_buckets && !__ac_iseither(h->flags, x)) { \
|
if (x != h->n_buckets && !__ac_iseither(h->flags, x)) { \
|
||||||
__ac_set_isdel_true(h->flags, x); \
|
__ac_set_isdel_true(h->flags, x); \
|
||||||
--h->size; \
|
--h->size; \
|
||||||
|
@ -382,10 +411,11 @@ KHASH_INIT2(name, static kh_inline, khkey_t, khval_t, kh_is_map, __hash_func, __
|
||||||
@param s Pointer to a null terminated string
|
@param s Pointer to a null terminated string
|
||||||
@return The hash value
|
@return The hash value
|
||||||
*/
|
*/
|
||||||
static kh_inline khint_t __ac_X31_hash_string(const char *s)
|
static kh_inline khint_t __ac_X31_hash_string(const char *s) {
|
||||||
{
|
|
||||||
khint_t h = (khint_t)*s;
|
khint_t h = (khint_t)*s;
|
||||||
if (h) for (++s ; *s; ++s) h = (h << 5) - h + (khint_t)*s;
|
if (h)
|
||||||
|
for (++s; *s; ++s)
|
||||||
|
h = (h << 5) - h + (khint_t)*s;
|
||||||
return h;
|
return h;
|
||||||
}
|
}
|
||||||
/*! @function
|
/*! @function
|
||||||
|
@ -399,8 +429,7 @@ static kh_inline khint_t __ac_X31_hash_string(const char *s)
|
||||||
*/
|
*/
|
||||||
#define kh_str_hash_equal(a, b) (strcmp(a, b) == 0)
|
#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 << 15);
|
||||||
key ^= (key >> 10);
|
key ^= (key >> 10);
|
||||||
key += (key << 3);
|
key += (key << 3);
|
||||||
|
@ -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 vvar Variable to which value will be assigned
|
||||||
@param code Block of code to execute
|
@param code Block of code to execute
|
||||||
*/
|
*/
|
||||||
#define kh_foreach(h, kvar, vvar, code) { khint_t __i; \
|
#define kh_foreach(h, kvar, vvar, code) \
|
||||||
|
{ \
|
||||||
|
khint_t __i; \
|
||||||
for (__i = kh_begin(h); __i != kh_end(h); ++__i) { \
|
for (__i = kh_begin(h); __i != kh_end(h); ++__i) { \
|
||||||
if (!kh_exist(h,__i)) continue; \
|
if (!kh_exist(h, __i)) \
|
||||||
|
continue; \
|
||||||
(kvar) = kh_key(h, __i); \
|
(kvar) = kh_key(h, __i); \
|
||||||
(vvar) = kh_val(h, __i); \
|
(vvar) = kh_val(h, __i); \
|
||||||
code; \
|
code; \
|
||||||
} }
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
/*! @function
|
/*! @function
|
||||||
@abstract Iterate over the values in the hash table
|
@abstract Iterate over the values in the hash table
|
||||||
|
@ -558,12 +591,16 @@ code; \
|
||||||
@param vvar Variable to which value will be assigned
|
@param vvar Variable to which value will be assigned
|
||||||
@param code Block of code to execute
|
@param code Block of code to execute
|
||||||
*/
|
*/
|
||||||
#define kh_foreach_value(h, vvar, code) { khint_t __i; \
|
#define kh_foreach_value(h, vvar, code) \
|
||||||
|
{ \
|
||||||
|
khint_t __i; \
|
||||||
for (__i = kh_begin(h); __i != kh_end(h); ++__i) { \
|
for (__i = kh_begin(h); __i != kh_end(h); ++__i) { \
|
||||||
if (!kh_exist(h,__i)) continue; \
|
if (!kh_exist(h, __i)) \
|
||||||
|
continue; \
|
||||||
(vvar) = kh_val(h, __i); \
|
(vvar) = kh_val(h, __i); \
|
||||||
code; \
|
code; \
|
||||||
} }
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
/* More conenient interfaces */
|
/* More conenient interfaces */
|
||||||
|
|
||||||
|
@ -571,23 +608,20 @@ code; \
|
||||||
@abstract Instantiate a hash set containing integer keys
|
@abstract Instantiate a hash set containing integer keys
|
||||||
@param name Name of the hash table [symbol]
|
@param name Name of the hash table [symbol]
|
||||||
*/
|
*/
|
||||||
#define KHASH_SET_INIT_INT(name) \
|
#define KHASH_SET_INIT_INT(name) KHASH_INIT(name, khint32_t, char, 0, kh_int_hash_func, kh_int_hash_equal)
|
||||||
KHASH_INIT(name, khint32_t, char, 0, kh_int_hash_func, kh_int_hash_equal)
|
|
||||||
|
|
||||||
/*! @function
|
/*! @function
|
||||||
@abstract Instantiate a hash map containing integer keys
|
@abstract Instantiate a hash map containing integer keys
|
||||||
@param name Name of the hash table [symbol]
|
@param name Name of the hash table [symbol]
|
||||||
@param khval_t Type of values [type]
|
@param khval_t Type of values [type]
|
||||||
*/
|
*/
|
||||||
#define KHASH_MAP_INIT_INT(name, khval_t) \
|
#define KHASH_MAP_INIT_INT(name, khval_t) KHASH_INIT(name, khint32_t, khval_t, 1, kh_int_hash_func, kh_int_hash_equal)
|
||||||
KHASH_INIT(name, khint32_t, khval_t, 1, kh_int_hash_func, kh_int_hash_equal)
|
|
||||||
|
|
||||||
/*! @function
|
/*! @function
|
||||||
@abstract Instantiate a hash map containing 64-bit integer keys
|
@abstract Instantiate a hash map containing 64-bit integer keys
|
||||||
@param name Name of the hash table [symbol]
|
@param name Name of the hash table [symbol]
|
||||||
*/
|
*/
|
||||||
#define KHASH_SET_INIT_INT64(name) \
|
#define KHASH_SET_INIT_INT64(name) KHASH_INIT(name, khint64_t, char, 0, kh_int64_hash_func, kh_int64_hash_equal)
|
||||||
KHASH_INIT(name, khint64_t, char, 0, kh_int64_hash_func, kh_int64_hash_equal)
|
|
||||||
|
|
||||||
/*! @function
|
/*! @function
|
||||||
@abstract Instantiate a hash map containing 64-bit integer keys
|
@abstract Instantiate a hash map containing 64-bit integer keys
|
||||||
|
@ -602,16 +636,13 @@ typedef const char *kh_cstr_t;
|
||||||
@abstract Instantiate a hash map containing const char* keys
|
@abstract Instantiate a hash map containing const char* keys
|
||||||
@param name Name of the hash table [symbol]
|
@param name Name of the hash table [symbol]
|
||||||
*/
|
*/
|
||||||
#define KHASH_SET_INIT_STR(name) \
|
#define KHASH_SET_INIT_STR(name) KHASH_INIT(name, kh_cstr_t, char, 0, kh_str_hash_func, kh_str_hash_equal)
|
||||||
KHASH_INIT(name, kh_cstr_t, char, 0, kh_str_hash_func, kh_str_hash_equal)
|
|
||||||
|
|
||||||
/*! @function
|
/*! @function
|
||||||
@abstract Instantiate a hash map containing const char* keys
|
@abstract Instantiate a hash map containing const char* keys
|
||||||
@param name Name of the hash table [symbol]
|
@param name Name of the hash table [symbol]
|
||||||
@param khval_t Type of values [type]
|
@param khval_t Type of values [type]
|
||||||
*/
|
*/
|
||||||
#define KHASH_MAP_INIT_STR(name, khval_t) \
|
#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)
|
||||||
KHASH_INIT(name, kh_cstr_t, khval_t, 1, kh_str_hash_func, kh_str_hash_equal)
|
|
||||||
|
|
||||||
#endif /* __AC_KHASH_H */
|
#endif /* __AC_KHASH_H */
|
||||||
|
|
||||||
|
|
|
@ -91,7 +91,8 @@
|
||||||
toklen = buf - tok_start; \
|
toklen = buf - tok_start; \
|
||||||
} while (0)
|
} 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"
|
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\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"
|
"\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"
|
"\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"
|
||||||
|
@ -100,8 +101,8 @@ 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\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;
|
*found = 0;
|
||||||
#if __SSE4_2__
|
#if __SSE4_2__
|
||||||
if (likely(buf_end - buf >= 16)) {
|
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;
|
size_t left = (buf_end - buf) & ~15;
|
||||||
do {
|
do {
|
||||||
__m128i b16 = _mm_loadu_si128((void *)buf);
|
__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)) {
|
if (unlikely(r != 16)) {
|
||||||
buf += r;
|
buf += r;
|
||||||
*found = 1;
|
*found = 1;
|
||||||
|
@ -124,12 +126,13 @@ static const char *findchar_fast(const char *buf, const char *buf_end, const cha
|
||||||
return buf;
|
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;
|
const char *token_start = buf;
|
||||||
|
|
||||||
#ifdef __SSE4_2__
|
#ifdef __SSE4_2__
|
||||||
static const char ranges1[] = "\0\010"
|
static const char ranges1
|
||||||
|
[] = "\0\010"
|
||||||
/* allow HT */
|
/* allow HT */
|
||||||
"\012\037"
|
"\012\037"
|
||||||
/* allow SP and up to but not including DEL */
|
/* allow SP and up to but not including DEL */
|
||||||
|
@ -191,8 +194,7 @@ FOUND_CTL:
|
||||||
return buf;
|
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;
|
int ret_cnt = 0;
|
||||||
buf = last_len < 3 ? buf : buf + last_len - 3;
|
buf = last_len < 3 ? buf : buf + last_len - 3;
|
||||||
|
|
||||||
|
@ -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 */
|
/* *_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;
|
int v;
|
||||||
CHECK_EOF();
|
CHECK_EOF();
|
||||||
if (!('0' <= *buf && *buf <= '9')) {
|
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 */
|
/* 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('H');
|
||||||
EXPECT_CHAR('T');
|
EXPECT_CHAR('T');
|
||||||
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,
|
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) {
|
for (;; ++*num_headers) {
|
||||||
CHECK_EOF();
|
CHECK_EOF();
|
||||||
if (*buf == '\015') {
|
if (*buf == '\015') {
|
||||||
|
@ -308,17 +307,17 @@ static const char *parse_headers(const char *buf, const char *buf_end, struct ph
|
||||||
headers[*num_headers].name = NULL;
|
headers[*num_headers].name = NULL;
|
||||||
headers[*num_headers].name_len = 0;
|
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 NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *parse_request(const char *buf, const char *buf_end, const char **method, size_t *method_len, const char **path,
|
static const char *parse_request(const char *buf, const char *buf_end, const char **method, size_t *method_len,
|
||||||
size_t *path_len, int *minor_version, struct phr_header *headers, size_t *num_headers,
|
const char **path, size_t *path_len, int *minor_version, struct phr_header *headers,
|
||||||
size_t max_headers, int *ret)
|
size_t *num_headers, size_t max_headers, int *ret) {
|
||||||
{
|
|
||||||
/* skip first empty line (some clients add CRLF after POST content) */
|
/* skip first empty line (some clients add CRLF after POST content) */
|
||||||
CHECK_EOF();
|
CHECK_EOF();
|
||||||
if (*buf == '\015') {
|
if (*buf == '\015') {
|
||||||
|
@ -350,8 +349,8 @@ 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,
|
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;
|
const char *buf = buf_start, *buf_end = buf_start + len;
|
||||||
size_t max_headers = *num_headers;
|
size_t max_headers = *num_headers;
|
||||||
int r;
|
int r;
|
||||||
|
@ -369,17 +368,18 @@ int phr_parse_request(const char *buf_start, size_t len, const char **method, si
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((buf = parse_request(buf, buf_end, method, method_len, path, path_len, minor_version, headers, num_headers, max_headers,
|
if ((buf = parse_request(
|
||||||
&r)) == NULL) {
|
buf, buf_end, method, method_len, path, path_len, minor_version, headers, num_headers, max_headers, &r))
|
||||||
|
== NULL) {
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (int)(buf - buf_start);
|
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,
|
static const char *parse_response(const char *buf, const char *buf_end, int *minor_version, int *status,
|
||||||
size_t *msg_len, struct phr_header *headers, size_t *num_headers, size_t max_headers, int *ret)
|
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" */
|
/* parse "HTTP/1.x" */
|
||||||
if ((buf = parse_http_version(buf, buf_end, minor_version, ret)) == NULL) {
|
if ((buf = parse_http_version(buf, buf_end, minor_version, ret)) == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -406,9 +406,8 @@ 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);
|
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,
|
int phr_parse_response(const char *buf_start, size_t len, int *minor_version, int *status, const char **msg,
|
||||||
struct phr_header *headers, size_t *num_headers, size_t last_len)
|
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;
|
const char *buf = buf_start, *buf_end = buf + len;
|
||||||
size_t max_headers = *num_headers;
|
size_t max_headers = *num_headers;
|
||||||
int r;
|
int r;
|
||||||
|
@ -425,15 +424,16 @@ int phr_parse_response(const char *buf_start, size_t len, int *minor_version, in
|
||||||
return r;
|
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 r;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (int)(buf - buf_start);
|
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;
|
const char *buf = buf_start, *buf_end = buf + len;
|
||||||
size_t max_headers = *num_headers;
|
size_t max_headers = *num_headers;
|
||||||
int r;
|
int r;
|
||||||
|
@ -462,8 +462,7 @@ enum {
|
||||||
CHUNKED_IN_TRAILERS_LINE_MIDDLE
|
CHUNKED_IN_TRAILERS_LINE_MIDDLE
|
||||||
};
|
};
|
||||||
|
|
||||||
static int decode_hex(int ch)
|
static int decode_hex(int ch) {
|
||||||
{
|
|
||||||
if ('0' <= ch && ch <= '9') {
|
if ('0' <= ch && ch <= '9') {
|
||||||
return ch - '0';
|
return ch - '0';
|
||||||
} else if ('A' <= ch && ch <= 'F') {
|
} else if ('A' <= ch && ch <= 'F') {
|
||||||
|
@ -475,8 +474,7 @@ static int decode_hex(int ch)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t phr_decode_chunked(struct phr_chunked_decoder *decoder, char *buf, size_t *_bufsz)
|
ssize_t phr_decode_chunked(struct phr_chunked_decoder *decoder, char *buf, size_t *_bufsz) {
|
||||||
{
|
|
||||||
size_t dst = 0, src = 0, bufsz = *_bufsz;
|
size_t dst = 0, src = 0, bufsz = *_bufsz;
|
||||||
ssize_t ret = -2; /* incomplete */
|
ssize_t ret = -2; /* incomplete */
|
||||||
|
|
||||||
|
|
|
@ -50,8 +50,9 @@ struct phr_header {
|
||||||
|
|
||||||
/* returns number of bytes consumed if successful, -2 if request is partial,
|
/* returns number of bytes consumed if successful, -2 if request is partial,
|
||||||
* -1 if failed */
|
* -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 phr_parse_request(const char *buf, size_t len, const char **method, size_t *method_len, const char **path,
|
||||||
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);
|
||||||
|
|
||||||
/* ditto */
|
/* ditto */
|
||||||
int phr_parse_response(const char *_buf, size_t len, int *minor_version, int *status, const char **msg, size_t *msg_len,
|
int phr_parse_response(const char *_buf, size_t len, int *minor_version, int *status, const char **msg, size_t *msg_len,
|
||||||
|
|
|
@ -25,16 +25,14 @@ void hw_route_next_token(hw_string* url, int start, hw_route_token* result) {
|
||||||
result->string.value = url->value + start;
|
result->string.value = url->value + start;
|
||||||
result->string.length = end - start;
|
result->string.length = end - start;
|
||||||
result->start = start;
|
result->start = start;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
result->string.value = NULL;
|
result->string.value = NULL;
|
||||||
result->string.length = 0;
|
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 equal = 0;
|
||||||
int match = 0;
|
int match = 0;
|
||||||
|
|
||||||
|
@ -49,21 +47,15 @@ int hw_route_compare_method(hw_string* url, char* route)
|
||||||
hw_route_next_token(url, 0, &request_token);
|
hw_route_next_token(url, 0, &request_token);
|
||||||
hw_route_next_token(&hw_route, 0, &route_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] == '*') {
|
if (route_token.string.value[0] == '*') {
|
||||||
// wildcard support: any route fragment marked with '*' matches the corresponding url fragment
|
// wildcard support: any route fragment marked with '*' matches the corresponding url fragment
|
||||||
equal = 1;
|
equal = 1;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
match = hw_strcmp(&route_token.string, &request_token.string);
|
match = hw_strcmp(&route_token.string, &request_token.string);
|
||||||
if (!match)
|
if (!match) {
|
||||||
{
|
|
||||||
equal = 1;
|
equal = 1;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
equal = 0;
|
equal = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -73,17 +65,15 @@ int hw_route_compare_method(hw_string* url, char* route)
|
||||||
hw_route_next_token(&hw_route, route_token.start + route_token.string.length + 1, &route_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);
|
match = hw_strcmp(url, &hw_route);
|
||||||
if (!match)
|
if (!match) {
|
||||||
{
|
|
||||||
equal = 1;
|
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;
|
equal = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,18 +9,11 @@ int stat_requests_destroyed_total;
|
||||||
|
|
||||||
#define CRLF "\r\n"
|
#define CRLF "\r\n"
|
||||||
|
|
||||||
static const char stats_response[] =
|
static const char stats_response[] = "HTTP/1.1 200 OK" CRLF "Server: Haywire/master" CRLF
|
||||||
"HTTP/1.1 200 OK" CRLF
|
"Date: Fri, 26 Aug 2011 00:31:53 GMT" CRLF "Connection: Keep-Alive" CRLF
|
||||||
"Server: Haywire/master" CRLF
|
"Content-Type: text/html" CRLF "Content-Length: 16" CRLF CRLF "stats printed" 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 status_code;
|
||||||
hw_string content_type_name;
|
hw_string content_type_name;
|
||||||
hw_string content_type_value;
|
hw_string content_type_value;
|
||||||
|
@ -39,21 +32,20 @@ void get_server_stats(http_request* request, hw_http_response* response, void* u
|
||||||
SETSTRING(body, "stats printed");
|
SETSTRING(body, "stats printed");
|
||||||
hw_set_body(response, &body);
|
hw_set_body(response, &body);
|
||||||
|
|
||||||
if (request->keep_alive)
|
if (request->keep_alive) {
|
||||||
{
|
|
||||||
SETSTRING(keep_alive_name, "Connection");
|
SETSTRING(keep_alive_name, "Connection");
|
||||||
|
|
||||||
SETSTRING(keep_alive_value, "Keep-Alive");
|
SETSTRING(keep_alive_value, "Keep-Alive");
|
||||||
hw_set_response_header(response, &keep_alive_name, &keep_alive_value);
|
hw_set_response_header(response, &keep_alive_name, &keep_alive_value);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
hw_set_http_version(response, 1, 0);
|
hw_set_http_version(response, 1, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
hw_http_response_send(response, NULL, NULL);
|
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_created_total,
|
||||||
stat_connections_destroyed_total,
|
stat_connections_destroyed_total,
|
||||||
stat_requests_created_total,
|
stat_requests_created_total,
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
#define INCREMENT_STAT(stat)
|
#define INCREMENT_STAT(stat)
|
||||||
#endif /* DEBUG */
|
#endif /* DEBUG */
|
||||||
|
|
||||||
|
|
||||||
extern int stat_connections_created_total;
|
extern int stat_connections_created_total;
|
||||||
extern int stat_connections_destroyed_total;
|
extern int stat_connections_destroyed_total;
|
||||||
extern int stat_requests_created_total;
|
extern int stat_requests_created_total;
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
#include "http_svr.h"
|
#include "http_svr.h"
|
||||||
#include "user_errno.h"
|
#include "user_errno.h"
|
||||||
#include "haywire.h"
|
#include "haywire.h"
|
||||||
#include "misc.h"
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
int http_svr_init() {
|
int http_svr_init() {
|
||||||
|
|
Loading…
Reference in New Issue