OCT 重新格式化代码

This commit is contained in:
huangxin 2022-11-08 10:37:52 +08:00
parent 1aaad54c7e
commit b8ece8e445
33 changed files with 2389 additions and 2484 deletions

View File

@ -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

View File

@ -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

View File

@ -4,33 +4,25 @@
#include "../khash.h" #include "../khash.h"
#include "ini.h" #include "ini.h"
KHASH_MAP_INIT_STR(route_hashes, char*) KHASH_MAP_INIT_STR(route_hashes, char *)
int configuration_handler(void* user, const char* section, const char* name, const char* value) 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;
} }

View File

@ -1,4 +1,4 @@
#pragma once #pragma once
#include "haywire.h" #include "haywire.h"
configuration* load_configuration(const char* filename); configuration *load_configuration(const char *filename);

View File

@ -19,58 +19,50 @@
#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';
return s; return 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;
} }
/* 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);
s++; s++;
} }
return (char*)s; return (char *)s;
} }
/* 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] = "";
char prev_name[MAX_NAME] = ""; char prev_name[MAX_NAME] = "";
char* start; char *start;
char* end; char *end;
char* name; char *name;
char* value; char *value;
int lineno = 0; int lineno = 0;
int error = 0; int error = 0;
@ -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,11 +123,8 @@ 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*), FILE *file;
void* user)
{
FILE* file;
int error; int error;
file = fopen(filename, "r"); file = fopen(filename, "r");

View File

@ -18,7 +18,7 @@ extern "C" {
#include <stdio.h> #include <stdio.h>
/* Parse given INI-style file. May have [section]s, name=value pairs /* Parse given INI-style file. May have [section]s, name=value pairs
(whitespace stripped), and comments starting with ';' (semicolon). Section (whitespace stripped), and comments starting with ';' (semicolon). Section
is "" if name=value pair parsed before any section heading. name:value is "" if name=value pair parsed before any section heading. name:value
pairs are also supported as a concession to Python's ConfigParser. pairs are also supported as a concession to Python's ConfigParser.
@ -30,19 +30,15 @@ extern "C" {
Returns 0 on success, line number of first error on parse error (doesn't Returns 0 on success, line number of first error on parse error (doesn't
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, void *user);
const char* name, const char* value),
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
ConfigParser. If allowed, ini_parse() will call the handler with the same ConfigParser. If allowed, ini_parse() will call the handler with the same
name for each subsequent line parsed. */ name for each subsequent line parsed. */
#ifndef INI_ALLOW_MULTILINE #ifndef INI_ALLOW_MULTILINE

View File

@ -8,15 +8,14 @@
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;
uv_handle_type type; uv_handle_type type;
uv_pipe_t* ipc_pipe; uv_pipe_t *ipc_pipe;
ipc_pipe = (uv_pipe_t*)handle; ipc_pipe = (uv_pipe_t *)handle;
ctx = container_of(ipc_pipe, struct ipc_client_ctx, ipc_pipe); ctx = container_of(ipc_pipe, struct ipc_client_ctx, ipc_pipe);
loop = ipc_pipe->loop; loop = ipc_pipe->loop;
@ -24,45 +23,40 @@ void ipc_read_cb(uv_stream_t* handle, ssize_t nread, const uv_buf_t* buf)
type = uv_pipe_pending_type(ipc_pipe); type = uv_pipe_pending_type(ipc_pipe);
if (type == UV_TCP) { if (type == UV_TCP) {
rc = uv_tcp_init(loop, (uv_tcp_t*) ctx->server_handle); rc = uv_tcp_init(loop, (uv_tcp_t *)ctx->server_handle);
if (tcp_nodelay) { 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);
connection->parser.data = connection; connection->parser.data = connection;
@ -71,23 +65,21 @@ void connection_consumer_new_connection(uv_stream_t* server_handle, int status)
rc = uv_tcp_init(server_handle->loop, &connection->stream); rc = uv_tcp_init(server_handle->loop, &connection->stream);
if (tcp_nodelay) { if (tcp_nodelay) {
rc = uv_tcp_nodelay((uv_tcp_t*)&connection->stream, 1); rc = uv_tcp_nodelay((uv_tcp_t *)&connection->stream, 1);
} }
rc = uv_accept(server_handle, (uv_stream_t*)&connection->stream); rc = uv_accept(server_handle, (uv_stream_t *)&connection->stream);
rc = uv_read_start((uv_stream_t*)&connection->stream, http_stream_on_alloc, http_stream_on_read); rc = uv_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,11 +91,9 @@ 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;
ctx = arg; ctx = arg;
tcp_nodelay = ctx->tcp_nodelay; tcp_nodelay = ctx->tcp_nodelay;
@ -113,16 +103,16 @@ 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. */
uv_sem_wait(&ctx->semaphore); uv_sem_wait(&ctx->semaphore);
get_listen_handle(loop, (uv_stream_t*) &ctx->server_handle); get_listen_handle(loop, (uv_stream_t *)&ctx->server_handle);
uv_sem_post(&ctx->semaphore); 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);
} }

View File

@ -4,22 +4,19 @@
#include "uv.h" #include "uv.h"
#ifndef offsetof #ifndef offsetof
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) #define offsetof(TYPE, MEMBER) ((size_t) & ((TYPE *)0)->MEMBER)
#endif #endif
#define container_of(ptr, type, member) ((type*)(((char*)(ptr)) - offsetof(type, member))) #define container_of(ptr, type, member) ((type *)(((char *)(ptr)) - offsetof(type, member)))
union stream_handle2 {
union stream_handle2
{
uv_pipe_t pipe; uv_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;
@ -47,4 +42,4 @@ struct ipc_server_ctx
}; };
void connection_consumer_start(void *arg); void connection_consumer_start(void *arg);
void connection_consumer_close(uv_async_t* handle, int status); void connection_consumer_close(uv_async_t *handle, int status);

View File

@ -6,26 +6,23 @@
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;
uv_loop_t* loop; uv_loop_t *loop;
uv_buf_t buf; uv_buf_t buf;
loop = ipc_pipe->loop; loop = ipc_pipe->loop;
@ -35,24 +32,19 @@ void ipc_connection_cb(uv_stream_t* ipc_pipe, int status)
//ASSERT(pc != NULL); //ASSERT(pc != NULL);
if (ipc_pipe->type == UV_TCP) { if (ipc_pipe->type == UV_TCP) {
rc = uv_tcp_init(loop, (uv_tcp_t*) &pc->peer_handle); rc = uv_tcp_init(loop, (uv_tcp_t *)&pc->peer_handle);
if (sc->tcp_nodelay) { 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);
} }
extern void print_configuration(); extern void print_configuration();
@ -60,41 +52,40 @@ 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;
unsigned int i; unsigned int i;
loop = uv_default_loop(); loop = uv_default_loop();
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);
if (ctx.tcp_nodelay) { if (ctx.tcp_nodelay) {
rc = uv_tcp_nodelay((uv_tcp_t*) &ctx.server_handle, 1); rc = uv_tcp_nodelay((uv_tcp_t *)&ctx.server_handle, 1);
} }
rc = uv_tcp_bind((uv_tcp_t*) &ctx.server_handle, (const struct sockaddr*)&listen_addr, 0); rc = uv_tcp_bind((uv_tcp_t *)&ctx.server_handle, (const struct sockaddr *)&listen_addr, 0);
print_configuration(); print_configuration();
printf("Listening...\n"); printf("Listening...\n");
} }
rc = uv_pipe_init(loop, &ctx.ipc_pipe, 1); rc = uv_pipe_init(loop, &ctx.ipc_pipe, 1);
rc = uv_pipe_bind(&ctx.ipc_pipe, "HAYWIRE_CONNECTION_DISPATCH_PIPE_NAME"); rc = uv_pipe_bind(&ctx.ipc_pipe, "HAYWIRE_CONNECTION_DISPATCH_PIPE_NAME");
rc = uv_listen((uv_stream_t*) &ctx.ipc_pipe, listen_backlog, ipc_connection_cb); rc = uv_listen((uv_stream_t *)&ctx.ipc_pipe, listen_backlog, ipc_connection_cb);
for (i = 0; i < num_servers; i++) for (i = 0; i < num_servers; i++)
uv_sem_post(&servers[i].semaphore); uv_sem_post(&servers[i].semaphore);
rc = uv_run(loop, UV_RUN_DEFAULT); rc = uv_run(loop, UV_RUN_DEFAULT);
uv_close((uv_handle_t*) &ctx.server_handle, NULL); uv_close((uv_handle_t *)&ctx.server_handle, NULL);
rc = uv_run(loop, UV_RUN_DEFAULT); rc = uv_run(loop, UV_RUN_DEFAULT);
for (i = 0; i < num_servers; i++) for (i = 0; i < num_servers; i++)

View File

@ -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);

View File

@ -6,16 +6,19 @@
#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;
http_request* request; http_request *request;
hw_string current_header_key; hw_string current_header_key;
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 {
hw_request_buffer* buffer; OPEN,
CLOSING,
CLOSED
} state;
hw_request_buffer *buffer;
} http_connection; } http_connection;

File diff suppressed because it is too large Load Diff

View File

@ -24,35 +24,35 @@
extern "C" { extern "C" {
#endif #endif
/* Also update SONAME in the Makefile whenever you change these. */ /* Also update SONAME in the Makefile whenever you change these. */
#define HTTP_PARSER_VERSION_MAJOR 2 #define HTTP_PARSER_VERSION_MAJOR 2
#define HTTP_PARSER_VERSION_MINOR 3 #define HTTP_PARSER_VERSION_MINOR 3
#define HTTP_PARSER_VERSION_PATCH 0 #define HTTP_PARSER_VERSION_PATCH 0
#include <sys/types.h> #include <sys/types.h>
#if defined(_WIN32) && !defined(__MINGW32__) && (!defined(_MSC_VER) || _MSC_VER<1600) #if defined(_WIN32) && !defined(__MINGW32__) && (!defined(_MSC_VER) || _MSC_VER < 1600)
#include <BaseTsd.h> #include <BaseTsd.h>
#include <stddef.h> #include <stddef.h>
typedef __int8 int8_t; typedef __int8 int8_t;
typedef unsigned __int8 uint8_t; typedef unsigned __int8 uint8_t;
typedef __int16 int16_t; typedef __int16 int16_t;
typedef unsigned __int16 uint16_t; typedef unsigned __int16 uint16_t;
typedef __int32 int32_t; typedef __int32 int32_t;
typedef unsigned __int32 uint32_t; typedef unsigned __int32 uint32_t;
typedef __int64 int64_t; typedef __int64 int64_t;
typedef unsigned __int64 uint64_t; typedef unsigned __int64 uint64_t;
#else #else
#include <stdint.h> #include <stdint.h>
#endif #endif
/* Compile with -DHTTP_PARSER_STRICT=0 to make less checks, but run /* Compile with -DHTTP_PARSER_STRICT=0 to make less checks, but run
* faster * faster
*/ */
#ifndef HTTP_PARSER_STRICT #ifndef HTTP_PARSER_STRICT
# define HTTP_PARSER_STRICT 1 #define HTTP_PARSER_STRICT 1
#endif #endif
/* Maximium header size allowed. If the macro is not defined /* Maximium header size allowed. If the macro is not defined
* before including this header then the default is used. To * before including this header then the default is used. To
* change the maximum header size, define the macro in the build * change the maximum header size, define the macro in the build
* environment (e.g. -DHTTP_MAX_HEADER_SIZE=<value>). To remove * environment (e.g. -DHTTP_MAX_HEADER_SIZE=<value>). To remove
@ -60,14 +60,13 @@ extern "C" {
* to a very large number (e.g. -DHTTP_MAX_HEADER_SIZE=0x7fffffff) * to a very large number (e.g. -DHTTP_MAX_HEADER_SIZE=0x7fffffff)
*/ */
#ifndef HTTP_MAX_HEADER_SIZE #ifndef HTTP_MAX_HEADER_SIZE
# define HTTP_MAX_HEADER_SIZE (80*1024) #define HTTP_MAX_HEADER_SIZE (80 * 1024)
#endif #endif
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.
* *
* The one exception is on_headers_complete. In a HTTP_RESPONSE parser * The one exception is on_headers_complete. In a HTTP_RESPONSE parser
@ -80,127 +79,120 @@ extern "C" {
* many times for each string. E.G. you might get 10 callbacks for "on_url" * many times for each string. E.G. you might get 10 callbacks for "on_url"
* each providing just a few characters more data. * each providing just a few characters more data.
*/ */
typedef int (*http_data_cb) (http_parser*, const char *at, size_t length); typedef int (*http_data_cb)(http_parser *, const char *at, size_t length);
typedef int (*http_cb) (http_parser*); typedef int (*http_cb)(http_parser *);
/* Request Methods */ /* Request Methods */
#define HTTP_METHOD_MAP(XX) \ #define HTTP_METHOD_MAP(XX) \
XX(0, DELETE, DELETE) \ XX(0, DELETE, DELETE) \
XX(1, GET, GET) \ XX(1, GET, GET) \
XX(2, HEAD, HEAD) \ XX(2, HEAD, HEAD) \
XX(3, POST, POST) \ XX(3, POST, POST) \
XX(4, PUT, PUT) \ XX(4, PUT, PUT) \
/* pathological */ \ /* pathological */ \
XX(5, CONNECT, CONNECT) \ XX(5, CONNECT, CONNECT) \
XX(6, OPTIONS, OPTIONS) \ XX(6, OPTIONS, OPTIONS) \
XX(7, TRACE, TRACE) \ XX(7, TRACE, TRACE) \
/* webdav */ \ /* webdav */ \
XX(8, COPY, COPY) \ XX(8, COPY, COPY) \
XX(9, LOCK, LOCK) \ XX(9, LOCK, LOCK) \
XX(10, MKCOL, MKCOL) \ XX(10, MKCOL, MKCOL) \
XX(11, MOVE, MOVE) \ XX(11, MOVE, MOVE) \
XX(12, PROPFIND, PROPFIND) \ XX(12, PROPFIND, PROPFIND) \
XX(13, PROPPATCH, PROPPATCH) \ XX(13, PROPPATCH, PROPPATCH) \
XX(14, SEARCH, SEARCH) \ XX(14, SEARCH, SEARCH) \
XX(15, UNLOCK, UNLOCK) \ XX(15, UNLOCK, UNLOCK) \
/* subversion */ \ /* subversion */ \
XX(16, REPORT, REPORT) \ XX(16, REPORT, REPORT) \
XX(17, MKACTIVITY, MKACTIVITY) \ XX(17, MKACTIVITY, MKACTIVITY) \
XX(18, CHECKOUT, CHECKOUT) \ XX(18, CHECKOUT, CHECKOUT) \
XX(19, MERGE, MERGE) \ XX(19, MERGE, MERGE) \
/* upnp */ \ /* upnp */ \
XX(20, MSEARCH, M-SEARCH) \ XX(20, MSEARCH, M - SEARCH) \
XX(21, NOTIFY, NOTIFY) \ XX(21, NOTIFY, NOTIFY) \
XX(22, SUBSCRIBE, SUBSCRIBE) \ XX(22, SUBSCRIBE, SUBSCRIBE) \
XX(23, UNSUBSCRIBE, UNSUBSCRIBE) \ XX(23, UNSUBSCRIBE, UNSUBSCRIBE) \
/* RFC-5789 */ \ /* RFC-5789 */ \
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 {
HTTP_REQUEST,
HTTP_RESPONSE,
HTTP_BOTH
};
enum http_parser_type { HTTP_REQUEST, HTTP_RESPONSE, HTTP_BOTH }; /* Flag values for http_parser.flags field */
enum flags {
F_CHUNKED = 1 << 0,
F_CONNECTION_KEEP_ALIVE = 1 << 1,
F_CONNECTION_CLOSE = 1 << 2,
F_CONNECTION_UPGRADE = 1 << 3,
F_TRAILING = 1 << 4,
F_UPGRADE = 1 << 5,
F_SKIPBODY = 1 << 6
};
/* Map for errno-related constants
/* Flag values for http_parser.flags field */
enum flags
{ F_CHUNKED = 1 << 0
, F_CONNECTION_KEEP_ALIVE = 1 << 1
, F_CONNECTION_CLOSE = 1 << 2
, F_CONNECTION_UPGRADE = 1 << 3
, F_TRAILING = 1 << 4
, F_UPGRADE = 1 << 5
, F_SKIPBODY = 1 << 6
};
/* Map for errno-related constants
* *
* The provided argument should be a macro that takes 2 arguments. * The provided argument should be a macro that takes 2 arguments.
*/ */
#define HTTP_ERRNO_MAP(XX) \ #define HTTP_ERRNO_MAP(XX) \
/* No error */ \ /* No error */ \
XX(OK, "success") \ XX(OK, "success") \
\ \
/* Callback-related errors */ \ /* Callback-related errors */ \
XX(CB_message_begin, "the on_message_begin callback failed") \ XX(CB_message_begin, "the on_message_begin callback failed") \
XX(CB_url, "the on_url callback failed") \ XX(CB_url, "the on_url callback failed") \
XX(CB_header_field, "the on_header_field callback failed") \ XX(CB_header_field, "the on_header_field callback failed") \
XX(CB_header_value, "the on_header_value callback failed") \ XX(CB_header_value, "the on_header_value callback failed") \
XX(CB_headers_complete, "the on_headers_complete callback failed") \ XX(CB_headers_complete, "the on_headers_complete callback failed") \
XX(CB_body, "the on_body callback failed") \ XX(CB_body, "the on_body callback failed") \
XX(CB_message_complete, "the on_message_complete callback failed") \ XX(CB_message_complete, "the on_message_complete callback failed") \
XX(CB_status, "the on_status callback failed") \ 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, \ XX(INVALID_VERSION, "invalid HTTP version") \
"data received after completed connection: close message") \ XX(INVALID_STATUS, "invalid HTTP status code") \
XX(INVALID_VERSION, "invalid HTTP version") \ XX(INVALID_METHOD, "invalid HTTP method") \
XX(INVALID_STATUS, "invalid HTTP status code") \ XX(INVALID_URL, "invalid URL") \
XX(INVALID_METHOD, "invalid HTTP method") \ XX(INVALID_HOST, "invalid host") \
XX(INVALID_URL, "invalid URL") \ XX(INVALID_PORT, "invalid port") \
XX(INVALID_HOST, "invalid host") \ XX(INVALID_PATH, "invalid path") \
XX(INVALID_PORT, "invalid port") \ XX(INVALID_QUERY_STRING, "invalid query string") \
XX(INVALID_PATH, "invalid path") \ XX(INVALID_FRAGMENT, "invalid fragment") \
XX(INVALID_QUERY_STRING, "invalid query string") \ XX(LF_EXPECTED, "LF character expected") \
XX(INVALID_FRAGMENT, "invalid fragment") \ XX(INVALID_HEADER_TOKEN, "invalid character in header") \
XX(LF_EXPECTED, "LF character expected") \ XX(INVALID_CONTENT_LENGTH, "invalid character in content-length header") \
XX(INVALID_HEADER_TOKEN, "invalid character in header") \ XX(INVALID_CHUNK_SIZE, "invalid character in chunk size header") \
XX(INVALID_CONTENT_LENGTH, \ XX(INVALID_CONSTANT, "invalid constant string") \
"invalid character in content-length header") \ XX(INVALID_INTERNAL_STATE, "encountered unexpected internal state") \
XX(INVALID_CHUNK_SIZE, \ XX(STRICT, "strict mode assertion failed") \
"invalid character in chunk size header") \ XX(PAUSED, "parser is paused") \
XX(INVALID_CONSTANT, "invalid constant string") \ XX(UNKNOWN, "an unknown error occurred")
XX(INVALID_INTERNAL_STATE, "encountered unexpected internal state")\
XX(STRICT, "strict mode assertion failed") \
XX(PAUSED, "parser is paused") \
XX(UNKNOWN, "an unknown error occurred")
/* Define HPE_* values for each errno value above */
/* Define 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 {
HTTP_ERRNO_MAP(HTTP_ERRNO_GEN) HTTP_ERRNO_MAP(HTTP_ERRNO_GEN)
}; };
#undef HTTP_ERRNO_GEN #undef HTTP_ERRNO_GEN
/* Get an http_errno value from an http_parser */
#define HTTP_PARSER_ERRNO(p) ((enum http_errno)(p)->http_errno)
/* Get an http_errno value from an http_parser */ struct http_parser {
#define HTTP_PARSER_ERRNO(p) ((enum http_errno) (p)->http_errno)
struct http_parser {
/** PRIVATE **/ /** PRIVATE **/
unsigned int type : 2; /* enum http_parser_type */ unsigned int type : 2; /* enum http_parser_type */
unsigned int flags : 6; /* F_* values from 'flags' enum; semi-public */ unsigned int flags : 6; /* F_* values from 'flags' enum; semi-public */
@ -227,10 +219,9 @@ XX(UNKNOWN, "an unknown error occurred")
/** PUBLIC **/ /** PUBLIC **/
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;
http_data_cb on_status; http_data_cb on_status;
@ -239,29 +230,27 @@ XX(UNKNOWN, "an unknown error occurred")
http_cb on_headers_complete; http_cb on_headers_complete;
http_data_cb on_body; http_data_cb on_body;
http_cb on_message_complete; http_cb on_message_complete;
}; };
enum http_parser_url_fields {
UF_SCHEMA = 0,
UF_HOST = 1,
UF_PORT = 2,
UF_PATH = 3,
UF_QUERY = 4,
UF_FRAGMENT = 5,
UF_USERINFO = 6,
UF_MAX = 7
};
enum http_parser_url_fields /* Result structure for http_parser_parse_url().
{ UF_SCHEMA = 0
, UF_HOST = 1
, UF_PORT = 2
, UF_PATH = 3
, UF_QUERY = 4
, UF_FRAGMENT = 5
, UF_USERINFO = 6
, UF_MAX = 7
};
/* Result structure for http_parser_parse_url().
* *
* Callers should index into field_data[] with UF_* values iff field_set * Callers should index into field_data[] with UF_* values iff field_set
* has the relevant (1 << UF_*) bit set. As a courtesy to clients (and * has the relevant (1 << UF_*) bit set. As a courtesy to clients (and
* because we probably have padding left over), we convert any port to * because we probably have padding left over), we convert any port to
* a uint16_t. * a uint16_t.
*/ */
struct http_parser_url { struct http_parser_url {
uint16_t field_set; /* Bitmask of (1 << UF_*) values */ uint16_t field_set; /* Bitmask of (1 << UF_*) values */
uint16_t port; /* Converted UF_PORT string */ uint16_t port; /* Converted UF_PORT string */
@ -269,10 +258,9 @@ XX(UNKNOWN, "an unknown error occurred")
uint16_t off; /* Offset into buffer in which field starts */ uint16_t off; /* Offset into buffer in which field starts */
uint16_t len; /* Length of run in buffer */ uint16_t len; /* Length of run in buffer */
} 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:
* *
@ -282,46 +270,39 @@ XX(UNKNOWN, "an unknown error occurred")
* unsigned patch = version & 255; * unsigned patch = version & 255;
* printf("http_parser v%u.%u.%u\n", major, minor, patch); * printf("http_parser v%u.%u.%u\n", major, minor, patch);
*/ */
unsigned long http_parser_version(void); unsigned long http_parser_version(void);
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
* the last message on the connection. * the last message on the connection.
* If you are the server, respond with the "Connection: close" header. * If you are the server, respond with the "Connection: close" header.
* If you are the client, close the connection. * If you are the client, close the connection.
*/ */
int http_should_keep_alive(const http_parser *parser); int http_should_keep_alive(const http_parser *parser);
/* Returns a string version of the HTTP method. */ /* Returns a string version of the HTTP method. */
const char *http_method_str(enum http_method m); const char *http_method_str(enum http_method m);
/* Return a string name of the given error */ /* Return a string name of the given error */
const char *http_errno_name(enum http_errno err); const char *http_errno_name(enum http_errno err);
/* Return a string description of the given error */ /* Return a string description of the given error */
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);
/* Checks if this is the final chunk of the body. */ /* Checks if this is the final chunk of the body. */
int http_body_is_final(const http_parser *parser); int http_body_is_final(const http_parser *parser);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -10,67 +10,58 @@
#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;
} }
#define hw_string_hash_equal(a, b) (hw_strcmp(a, b) == 0) #define hw_string_hash_equal(a, b) (hw_strcmp(a, b) == 0)
KHASH_INIT(hw_string_hashmap, hw_string*, hw_string*, 1, hw_string_hash_func, hw_string_hash_equal) KHASH_INIT(hw_string_hashmap, hw_string *, hw_string *, 1, hw_string_hash_func, hw_string_hash_equal)
KHASH_MAP_INIT_STR(string_hashmap, char*) KHASH_MAP_INIT_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;
khash_t(hw_string_hashmap) *h = request->headers; khash_t(hw_string_hashmap) *h = request->headers;
kh_foreach(h, k, v, { kh_foreach(h, k, v, {
char* key = uv__strndup(k->value, k->length + 1); char *key = uv__strndup(k->value, k->length + 1);
char* value = uv__strndup(v->value, v->length + 1); char *value = uv__strndup(v->value, v->length + 1);
printf("KEY: %s VALUE: %s\n", key, value); printf("KEY: %s VALUE: %s\n", key, value);
free(key); free(key);
free(value); free(value);
}); });
} }
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);
void* val; void *val;
int is_missing = (k == kh_end(h)); int is_missing = (k == kh_end(h));
if (is_missing) { if (is_missing) {
@ -81,18 +72,16 @@ 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]);
} }
void* prev = get_header(request, name); void *prev = get_header(request, name);
if (prev) { if (prev) {
free(prev); free(prev);
} }
@ -101,9 +90,8 @@ 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));
request->body = calloc(1, sizeof(hw_string)); request->body = calloc(1, sizeof(hw_string));
@ -112,17 +100,15 @@ 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);
}); });
kh_destroy(hw_string_hashmap, h); kh_destroy(hw_string_hashmap, h);
@ -135,15 +121,13 @@ 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
* and create a new one. * and create a new one.
@ -156,11 +140,10 @@ 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;
if (url->length) { if (url->length) {
/* This is not the first URL chunk that has been seen in the buffer. Since we've already captured the initial pointer in the branch below, /* This is not the first URL chunk that has been seen in the buffer. Since we've already captured the initial pointer in the branch below,
@ -176,9 +159,9 @@ int http_request_on_url(http_parser *parser, const char *at, size_t length)
return 0; return 0;
} }
void http_request_save_current_header(http_connection* connection) { void http_request_save_current_header(http_connection *connection) {
hw_string* header_key_copy = hw_strdup(&connection->current_header_key); hw_string *header_key_copy = hw_strdup(&connection->current_header_key);
hw_string* header_value_copy = hw_strdup(&connection->current_header_value); hw_string *header_value_copy = hw_strdup(&connection->current_header_value);
/* We duplicate the current header key/value, so we actually need to use the new pointers as pin ids, as /* We duplicate the current header key/value, so we actually need to use the new pointers as pin ids, as
* those will be the IDs we'll use later on to locate the headers */ * those will be the IDs we'll use later on to locate the headers */
@ -187,20 +170,18 @@ 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) {
http_request_save_current_header(connection); http_request_save_current_header(connection);
@ -225,9 +206,8 @@ 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) {
connection->current_header_value.value = at; connection->current_header_value.value = at;
@ -244,9 +224,8 @@ 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) {
http_request_save_current_header(connection); http_request_save_current_header(connection);
@ -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,30 +261,26 @@ 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;
const char* v; const char *v;
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;
} }
}); });
return route_entry; return route_entry;
} }
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,15 +318,14 @@ 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);
request->body->value = http_request_buffer_locate(buffer, request->body, request->body->value); request->body->value = http_request_buffer_locate(buffer, request->body, request->body->value);
hw_string* header_name; hw_string *header_name;
hw_string* header_value; hw_string *header_value;
khash_t(hw_string_hashmap) *h = request->headers; khash_t(hw_string_hashmap) *h = request->headers;
kh_foreach(h, header_name, header_value, { kh_foreach(h, header_name, header_value, {
@ -365,13 +334,12 @@ 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);
char* error = NULL; char *error = NULL;
if (connection->request->state == SIZE_EXCEEDED) { if (connection->request->state == SIZE_EXCEEDED) {
// 413 Request entity too large // 413 Request entity too large
@ -384,14 +352,11 @@ int http_request_on_message_complete(http_parser* parser)
} else { } else {
http_request_locate_members(connection); http_request_locate_members(connection);
hw_route_entry* route_entry = request != NULL ? get_route_callback(request->url) : NULL; hw_route_entry *route_entry = request != NULL ? get_route_callback(request->url) : NULL;
if (route_entry != NULL) if (route_entry != NULL) {
{
route_entry->callback(request, response, route_entry->user_data); 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;
} }
@ -408,7 +373,7 @@ int http_request_on_message_complete(http_parser* parser)
} }
if (error) { if (error) {
send_error_response(request, (http_response*)response, error, error); send_error_response(request, (http_response *)response, error, error);
} }
return 0; return 0;

View File

@ -6,7 +6,7 @@
extern int last_was_value; extern int last_was_value;
void free_http_request(http_request* request); void free_http_request(http_request *request);
int http_request_on_message_begin(http_parser *parser); int http_request_on_message_begin(http_parser *parser);
int http_request_on_url(http_parser *parser, const char *at, size_t length); int http_request_on_url(http_parser *parser, const char *at, size_t length);
int http_request_on_header_field(http_parser *parser, const char *at, size_t length); int http_request_on_header_field(http_parser *parser, const char *at, size_t length);

View File

@ -7,7 +7,7 @@
#define MIN(x, y) (((x) < (y)) ? (x) : (y)) #define MIN(x, y) (((x) < (y)) ? (x) : (y))
KHASH_MAP_INIT_INT64(pointer_hashmap, void*) KHASH_MAP_INIT_INT64(pointer_hashmap, void *)
typedef struct { typedef struct {
size_t max_size; size_t max_size;
@ -15,28 +15,28 @@ typedef struct {
size_t mark; size_t mark;
size_t used; size_t used;
size_t used_before; size_t used_before;
void* current; void *current;
khash_t(pointer_hashmap)* offsets; khash_t(pointer_hashmap) * offsets;
bool offsets_active; bool offsets_active;
} http_request_buffer; } http_request_buffer;
void http_request_buffer_consume(hw_request_buffer* buf, size_t consumed) { void http_request_buffer_consume(hw_request_buffer *buf, size_t consumed) {
http_request_buffer* buffer = (http_request_buffer*) buf; http_request_buffer *buffer = (http_request_buffer *)buf;
buffer->used_before = buffer->used; buffer->used_before = buffer->used;
buffer->used += consumed; buffer->used += consumed;
} }
void http_request_buffer_mark(hw_request_buffer* buf) { void http_request_buffer_mark(hw_request_buffer *buf) {
http_request_buffer* buffer = (http_request_buffer*) buf; http_request_buffer *buffer = (http_request_buffer *)buf;
/* unfortunately, the parser doesn't tell us where the request ends exactly, /* unfortunately, the parser doesn't tell us where the request ends exactly,
* so the only thing we can be sure is that it ends in the current buffer chunk, so anything before it can * so the only thing we can be sure is that it ends in the current buffer chunk, so anything before it can
* effectively be swept, so we're placing the mark at that point now. */ * effectively be swept, so we're placing the mark at that point now. */
buffer->mark = buffer->used_before; buffer->mark = buffer->used_before;
} }
void http_request_buffer_sweep(hw_request_buffer* buf) { void http_request_buffer_sweep(hw_request_buffer *buf) {
http_request_buffer* buffer = (http_request_buffer*) buf; http_request_buffer *buffer = (http_request_buffer *)buf;
void* pointer; void *pointer;
int offset; int offset;
int used = buffer->used - buffer->mark; int used = buffer->used - buffer->mark;
@ -87,8 +87,8 @@ void http_request_buffer_sweep(hw_request_buffer* buf) {
} }
} }
hw_request_buffer* http_request_buffer_init(size_t max_size) { hw_request_buffer *http_request_buffer_init(size_t max_size) {
http_request_buffer* buffer = malloc(sizeof(http_request_buffer)); http_request_buffer *buffer = malloc(sizeof(http_request_buffer));
buffer->max_size = max_size; buffer->max_size = max_size;
buffer->size = 0; buffer->size = 0;
buffer->used = 0; buffer->used = 0;
@ -100,16 +100,16 @@ hw_request_buffer* http_request_buffer_init(size_t max_size) {
return buffer; return buffer;
} }
void http_request_buffer_chunk(hw_request_buffer* buf, hw_request_buffer_chunk* chunk) { void http_request_buffer_chunk(hw_request_buffer *buf, hw_request_buffer_chunk *chunk) {
http_request_buffer *buffer = (http_request_buffer *) buf; http_request_buffer *buffer = (http_request_buffer *)buf;
chunk->size = buffer->size ? buffer->size - buffer->used : 0; chunk->size = buffer->size ? buffer->size - buffer->used : 0;
chunk->buffer = buffer->current + buffer->used; chunk->buffer = buffer->current + buffer->used;
} }
bool http_request_buffer_alloc(hw_request_buffer* buf, size_t requested_size) { bool http_request_buffer_alloc(hw_request_buffer *buf, size_t requested_size) {
http_request_buffer* buffer = (http_request_buffer*) buf; http_request_buffer *buffer = (http_request_buffer *)buf;
bool ret = true; bool ret = true;
void* previous = NULL; void *previous = NULL;
size_t requested_size_capped = MIN(buffer->max_size, requested_size); size_t requested_size_capped = MIN(buffer->max_size, requested_size);
@ -148,18 +148,18 @@ bool http_request_buffer_alloc(hw_request_buffer* buf, size_t requested_size) {
return ret; return ret;
} }
void http_request_buffer_print(hw_request_buffer* buf) { void http_request_buffer_print(hw_request_buffer *buf) {
http_request_buffer* buffer = (http_request_buffer*) buf; http_request_buffer *buffer = (http_request_buffer *)buf;
printf("Buffer: current=%u; size=%u; used=%u\n", buffer->current, buffer->size, buffer->used); printf("Buffer: current=%u; size=%u; used=%u\n", buffer->current, buffer->size, buffer->used);
printf(" 0\t"); printf(" 0\t");
for (int i = 0; i < buffer->used; i++) { for (int i = 0; i < buffer->used; i++) {
if (((char*) buffer->current)[i] == '\n') { if (((char *)buffer->current)[i] == '\n') {
printf("\\n"); printf("\\n");
} else if (((char*) buffer->current)[i] == '\r') { } else if (((char *)buffer->current)[i] == '\r') {
printf("\\r"); printf("\\r");
} else { } else {
printf("%c", ((char*) buffer->current)[i]); printf("%c", ((char *)buffer->current)[i]);
} }
if ((i + 1) % 10 == 0) { if ((i + 1) % 10 == 0) {
@ -170,16 +170,14 @@ void http_request_buffer_print(hw_request_buffer* buf) {
} }
printf("\n"); printf("\n");
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");
} }
void http_request_buffer_pin(hw_request_buffer* buf, void* key, void* pointer) { void http_request_buffer_pin(hw_request_buffer *buf, void *key, void *pointer) {
http_request_buffer* buffer = (http_request_buffer*) buf; http_request_buffer *buffer = (http_request_buffer *)buf;
khiter_t offset_key = kh_get(pointer_hashmap, buffer->offsets, key); khiter_t offset_key = kh_get(pointer_hashmap, buffer->offsets, key);
@ -194,8 +192,8 @@ void http_request_buffer_pin(hw_request_buffer* buf, void* key, void* pointer) {
kh_value(buffer->offsets, offset_key) = offset; kh_value(buffer->offsets, offset_key) = offset;
} }
void http_request_buffer_reassign_pin(hw_request_buffer* buf, void* old_key, void* new_key) { void http_request_buffer_reassign_pin(hw_request_buffer *buf, void *old_key, void *new_key) {
http_request_buffer* buffer = (http_request_buffer*) buf; http_request_buffer *buffer = (http_request_buffer *)buf;
khiter_t old_offset_key = kh_get(pointer_hashmap, buffer->offsets, old_key); khiter_t old_offset_key = kh_get(pointer_hashmap, buffer->offsets, old_key);
@ -213,9 +211,9 @@ void http_request_buffer_reassign_pin(hw_request_buffer* buf, void* old_key, voi
} }
} }
void* http_request_buffer_locate(hw_request_buffer* buf, void* key, void* default_pointer) { void *http_request_buffer_locate(hw_request_buffer *buf, void *key, void *default_pointer) {
http_request_buffer* buffer = (http_request_buffer*) buf; http_request_buffer *buffer = (http_request_buffer *)buf;
void* location = default_pointer; void *location = default_pointer;
khiter_t offset_key = kh_get(pointer_hashmap, buffer->offsets, key); khiter_t offset_key = kh_get(pointer_hashmap, buffer->offsets, key);
int offset, is_missing; int offset, is_missing;
@ -231,8 +229,8 @@ void* http_request_buffer_locate(hw_request_buffer* buf, void* key, void* defaul
return location; return location;
} }
void http_request_buffer_destroy(hw_request_buffer* buf) { void http_request_buffer_destroy(hw_request_buffer *buf) {
http_request_buffer* buffer = (http_request_buffer*) buf; http_request_buffer *buffer = (http_request_buffer *)buf;
kh_destroy(pointer_hashmap, buffer->offsets); kh_destroy(pointer_hashmap, buffer->offsets);
free(buffer->current); free(buffer->current);
free(buffer); free(buffer);

View File

@ -4,38 +4,38 @@
#include "haywire.h" #include "haywire.h"
typedef struct { typedef struct {
void* buffer; void *buffer;
size_t size; size_t size;
} hw_request_buffer_chunk; } hw_request_buffer_chunk;
typedef void* hw_request_buffer; typedef void *hw_request_buffer;
/** /**
* Initializes a new buffer. The caller is responsible for calling http_request_buffer_destroy to free up memory. * Initializes a new buffer. The caller is responsible for calling http_request_buffer_destroy to free up memory.
*/ */
hw_request_buffer* http_request_buffer_init(size_t max_size); hw_request_buffer *http_request_buffer_init(size_t max_size);
/** /**
* Signals that "size" bytes from the buffer are now in use. * Signals that "size" bytes from the buffer are now in use.
*/ */
void http_request_buffer_consume(hw_request_buffer* buffer, size_t size); void http_request_buffer_consume(hw_request_buffer *buffer, size_t size);
/** /**
* Marks all buffer chunks up to the last one allocated (exclusive) for removal when * Marks all buffer chunks up to the last one allocated (exclusive) for removal when
* http_request_buffer_sweep gets called. * http_request_buffer_sweep gets called.
*/ */
void http_request_buffer_mark(hw_request_buffer* buffer); void http_request_buffer_mark(hw_request_buffer *buffer);
/** /**
* Sweeps all buffer chunks up to the mark. Data for the last chunk is copied to the beginning of the buffer * Sweeps all buffer chunks up to the mark. Data for the last chunk is copied to the beginning of the buffer
* and the offsets are updates accordingly. * and the offsets are updates accordingly.
*/ */
void http_request_buffer_sweep(hw_request_buffer* buffer); void http_request_buffer_sweep(hw_request_buffer *buffer);
/** /**
* Prints the buffer. * Prints the buffer.
*/ */
void http_request_buffer_print(hw_request_buffer* buffer); void http_request_buffer_print(hw_request_buffer *buffer);
/** /**
* Ensures that there's will be a sizable chunk available when the it's requested via http_request_buffer_chunk. * Ensures that there's will be a sizable chunk available when the it's requested via http_request_buffer_chunk.
@ -45,24 +45,24 @@ void http_request_buffer_print(hw_request_buffer* buffer);
* *
* Returns true if the allocation succeeds, false otherwise (errno is set accordingly). * Returns true if the allocation succeeds, false otherwise (errno is set accordingly).
*/ */
bool http_request_buffer_alloc(hw_request_buffer* buf, size_t requested_size); bool http_request_buffer_alloc(hw_request_buffer *buf, size_t requested_size);
/** /**
* Returns a new buffer chunk to be used by request reader. * Returns a new buffer chunk to be used by request reader.
*/ */
void http_request_buffer_chunk(hw_request_buffer* buffer, hw_request_buffer_chunk* chunk); void http_request_buffer_chunk(hw_request_buffer *buffer, hw_request_buffer_chunk *chunk);
/** /**
* Informs the buffer manager that *pointer is a memory region of interest and that will have to be made available to * Informs the buffer manager that *pointer is a memory region of interest and that will have to be made available to
* the caller eventually, when http_request_buffer_locate is called. The pin is given a key by the caller so it can be * the caller eventually, when http_request_buffer_locate is called. The pin is given a key by the caller so it can be
* retrieved later. Pins will be overwritten if the same key is used multiple times. * retrieved later. Pins will be overwritten if the same key is used multiple times.
*/ */
void http_request_buffer_pin(hw_request_buffer* buffer, void* key, void* pointer); void http_request_buffer_pin(hw_request_buffer *buffer, void *key, void *pointer);
/** /**
* Allows the caller to assign a new key to a pin. * Allows the caller to assign a new key to a pin.
*/ */
void http_request_buffer_reassign_pin(hw_request_buffer* buffer, void* old_key, void* new_key); void http_request_buffer_reassign_pin(hw_request_buffer *buffer, void *old_key, void *new_key);
/** /**
* Returns the pointer to the memory region associated with a pin. If there isn't a pin with that key, then * Returns the pointer to the memory region associated with a pin. If there isn't a pin with that key, then
@ -73,9 +73,9 @@ void http_request_buffer_reassign_pin(hw_request_buffer* buffer, void* old_key,
* sequentially. It's the responsibility of the caller to know how long that region is, by keeping track of its * sequentially. It's the responsibility of the caller to know how long that region is, by keeping track of its
* length as it's being read in. * length as it's being read in.
*/ */
void* http_request_buffer_locate(hw_request_buffer* buffer, void* key, void* default_pointer); void *http_request_buffer_locate(hw_request_buffer *buffer, void *key, void *default_pointer);
/** /**
* Destroys the buffer and any underlying buffer chunks. * Destroys the buffer and any underlying buffer chunks.
*/ */
void http_request_buffer_destroy(hw_request_buffer* buffer); void http_request_buffer_destroy(hw_request_buffer *buffer);

View File

@ -8,11 +8,10 @@
#include "hw_string.h" #include "hw_string.h"
#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;
response->http_major = 1; response->http_major = 1;
@ -23,44 +22,40 @@ 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;
header->value = *value; header->value = *value;
resp->headers[resp->number_of_headers] = *header; resp->headers[resp->number_of_headers] = *header;
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,11 +63,10 @@ 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);
hw_string content_length; hw_string content_length;
int i = 0; int i = 0;
@ -83,20 +77,20 @@ 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;
if (header_size_remaining < 0) { if (header_size_remaining < 0) {
header_size_remaining += header_buffer_incr * ((-header_size_remaining/header_buffer_incr) + 1); header_size_remaining += header_buffer_incr * ((-header_size_remaining / header_buffer_incr) + 1);
response_size += header_size_remaining; response_size += header_size_remaining;
response_string->value = realloc(response_string->value, response_size); response_string->value = realloc(response_string->value, response_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,20 +117,17 @@ 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));
{ http_response *resp = (http_response *)response;
hw_write_context* write_context = malloc(sizeof(hw_write_context)); hw_string *response_buffer = create_response_buffer(response);
http_response* resp = (http_response*)response;
hw_string* response_buffer = create_response_buffer(response);
write_context->connection = resp->connection; write_context->connection = resp->connection;
write_context->user_data = user_data; write_context->user_data = user_data;
@ -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);
}

View File

@ -2,17 +2,15 @@
#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;
unsigned short http_minor; unsigned short http_minor;
hw_string status_code; hw_string status_code;
@ -22,13 +20,12 @@ 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;
http_response_complete_callback callback; http_response_complete_callback callback;
} hw_write_context; } hw_write_context;
hw_http_response hw_create_http_response(http_connection* connection); hw_http_response hw_create_http_response(http_connection *connection);
hw_string* create_response_buffer(hw_http_response* response); hw_string *create_response_buffer(hw_http_response *response);

View File

@ -11,52 +11,45 @@
#include "http_server.h" #include "http_server.h"
#define CRLF "\r\n" #define CRLF "\r\n"
KHASH_MAP_INIT_STR(string_hashmap, hw_string*) KHASH_MAP_INIT_STR(string_hashmap, hw_string *)
static uv_timer_t cache_invalidation_timer; static uv_timer_t cache_invalidation_timer;
static uv_key_t thread_cache_key; static uv_key_t thread_cache_key;
void initialize_http_request_cache(); void initialize_http_request_cache();
void free_http_request_cache(); void free_http_request_cache();
void http_request_cache_timer(uv_timer_t* handle); void http_request_cache_timer(uv_timer_t *handle);
void create_cached_http_request(khash_t(string_hashmap)* http_request_cache, const char* http_status); void create_cached_http_request(khash_t(string_hashmap) * http_request_cache, const char *http_status);
void set_cached_request(khash_t(string_hashmap)* http_request_cache, char* http_status, hw_string* cache_entry); 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,9 +58,8 @@ 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;
hw_string status; hw_string status;
@ -83,7 +75,7 @@ void create_cached_http_request(khash_t(string_hashmap)* http_request_cache, con
// Add the current time. // Add the current time.
time_t curtime; time_t curtime;
time(&curtime); time(&curtime);
char* current_time = ctime(&curtime); char *current_time = ctime(&curtime);
hw_string current_datetime; hw_string current_datetime;
current_datetime.value = current_time; current_datetime.value = current_time;
current_datetime.length = strlen(current_time); current_datetime.length = strlen(current_time);
@ -93,60 +85,48 @@ void create_cached_http_request(khash_t(string_hashmap)* http_request_cache, con
set_cached_request(http_request_cache, http_status, cache_entry); 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;
khiter_t key = 0; khiter_t key = 0;
/* 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;
} }

View File

@ -3,5 +3,5 @@
#include "haywire.h" #include "haywire.h"
void initialize_http_request_cache(); void initialize_http_request_cache();
hw_string* get_cached_request(const char* http_status); hw_string *get_cached_request(const char *http_status);
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);

View File

@ -1,6 +1,6 @@
#ifdef PLATFORM_POSIX #ifdef PLATFORM_POSIX
#include <signal.h> #include <signal.h>
#endif // PLATFORM_POSIX #endif// PLATFORM_POSIX
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@ -19,35 +19,37 @@
#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 *)
configuration* config; configuration *config;
static uv_tcp_t server; static uv_tcp_t server;
static http_parser_settings parser_settings; static http_parser_settings parser_settings;
static struct sockaddr_in listen_address; 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);
@ -58,7 +60,7 @@ int hw_init_with_config(configuration* c)
config->http_listen_port = c->http_listen_port; config->http_listen_port = c->http_listen_port;
config->thread_count = c->thread_count; config->thread_count = c->thread_count;
config->tcp_nodelay = c->tcp_nodelay; config->tcp_nodelay = c->tcp_nodelay;
config->listen_backlog = c->listen_backlog? c->listen_backlog : SOMAXCONN; config->listen_backlog = c->listen_backlog ? c->listen_backlog : SOMAXCONN;
config->parser = dupstr(c->parser); config->parser = dupstr(c->parser);
config->balancer = dupstr(c->balancer); config->balancer = dupstr(c->balancer);
config->max_request_size = c->max_request_size; config->max_request_size = c->max_request_size;
@ -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);
} }
@ -173,7 +165,7 @@ int hw_http_open()
#ifdef UNIX #ifdef UNIX
signal(SIGPIPE, SIG_IGN); signal(SIGPIPE, SIG_IGN);
#endif // UNIX #endif// UNIX
listener_count = threads; listener_count = threads;
@ -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,
struct server_ctx* servers; (int)config->http_listen_port,
config->tcp_nodelay,
(int)config->listen_backlog);
} else if (listener_count > 0 && strcmp(config->balancer, "reuseport") == 0) {
struct server_ctx *servers;
servers = calloc(threads, sizeof(servers[0])); 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,28 +278,26 @@ 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);
@ -322,14 +305,13 @@ void http_stream_on_connect(uv_stream_t* stream, int status)
connection->stream.data = connection; connection->stream.data = connection;
/* TODO: Use the return values from uv_accept() and uv_read_start() */ /* TODO: Use the return values from uv_accept() and uv_read_start() */
uv_accept(stream, (uv_stream_t*)&connection->stream); uv_accept(stream, (uv_stream_t *)&connection->stream);
connection->state = OPEN; connection->state = OPEN;
uv_read_start((uv_stream_t*)&connection->stream, http_stream_on_alloc, http_stream_on_read); uv_read_start((uv_stream_t *)&connection->stream, http_stream_on_alloc, http_stream_on_read);
} }
void http_stream_on_alloc(uv_handle_t* client, size_t suggested_size, uv_buf_t* buf) 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);
hw_request_buffer_chunk chunk; hw_request_buffer_chunk chunk;
@ -345,28 +327,26 @@ void http_stream_on_alloc(uv_handle_t* client, size_t suggested_size, uv_buf_t*
*buf = uv_buf_init(chunk.buffer, chunk.size); *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;
if (connection->state != CLOSED) { if (connection->state != CLOSED) {
connection->state = CLOSED; connection->state = CLOSED;
http_connection* connection = (http_connection*)handle->data; http_connection *connection = (http_connection *)handle->data;
free_http_connection(connection); free_http_connection(connection);
} }
} }
void http_stream_close_connection(http_connection* connection) { void http_stream_close_connection(http_connection *connection) {
if (connection->state == OPEN) { if (connection->state == OPEN) {
connection->state = CLOSING; connection->state = CLOSING;
uv_close(&connection->stream, http_stream_on_close); uv_close(&connection->stream, http_stream_on_close);
} }
} }
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) {
uv_read_stop(stream); uv_read_stop(stream);
@ -384,8 +364,7 @@ void handle_request_error(http_connection* connection)
} }
} }
void handle_bad_request(http_connection* connection) void handle_bad_request(http_connection *connection) {
{
if (connection->request) { 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,25 +388,23 @@ 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) {
/* Need to tell the buffer that we care about the next nread bytes */ /* Need to tell the buffer that we care about the next nread bytes */
http_request_buffer_consume(connection->buffer, nread); http_request_buffer_consume(connection->buffer, nread);
http_parser_execute(&connection->parser, &parser_settings, (const char*) buf->base, nread); http_parser_execute(&connection->parser, &parser_settings, (const char *)buf->base, nread);
if (connection->parser.http_errno) { if (connection->parser.http_errno) {
handle_bad_request(connection); handle_bad_request(connection);
@ -443,16 +418,13 @@ void http_stream_on_read_http_parser(uv_stream_t* tcp, ssize_t nread, const uv_b
} }
} else if (nread == 0) { } 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,30 +434,28 @@ void http_stream_on_read_http_parser(uv_stream_t* tcp, ssize_t nread, const uv_b
} }
} }
void http_server_cleanup_write(char* response_string, hw_write_context* write_context, uv_write_t* write_req) void http_server_cleanup_write(char *response_string, hw_write_context *write_context, uv_write_t *write_req) {
{
free(response_string); free(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) {
uv_write_t *write_req = (uv_write_t *) malloc(sizeof(*write_req) + sizeof(uv_buf_t)); uv_write_t *write_req = (uv_write_t *)malloc(sizeof(*write_req) + sizeof(uv_buf_t));
uv_buf_t *resbuf = (uv_buf_t *) (write_req + 1); uv_buf_t *resbuf = (uv_buf_t *)(write_req + 1);
resbuf->base = response->value; resbuf->base = response->value;
resbuf->len = response->length; resbuf->len = response->length;
write_req->data = write_context; write_req->data = write_context;
uv_stream_t *stream = (uv_stream_t *) &write_context->connection->stream; uv_stream_t *stream = (uv_stream_t *)&write_context->connection->stream;
if (uv_is_writable(stream)) { 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,23 +467,20 @@ 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;
if (!connection->keep_alive && connection->state == OPEN) { if (!connection->keep_alive && connection->state == OPEN) {
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);
} }

View File

@ -5,36 +5,34 @@
#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;
}; };
extern void* routes; extern void *routes;
extern uv_loop_t* uv_loop; extern uv_loop_t *uv_loop;
extern hw_string* http_v1_0; extern hw_string *http_v1_0;
extern hw_string* http_v1_1; extern hw_string *http_v1_1;
extern hw_string* server_name; extern hw_string *server_name;
extern int listener_count; extern int listener_count;
extern uv_async_t* listener_async_handles; extern uv_async_t *listener_async_handles;
extern uv_loop_t* listener_event_loops; extern uv_loop_t *listener_event_loops;
extern uv_barrier_t* listeners_created_barrier; extern uv_barrier_t *listeners_created_barrier;
void (*http_stream_on_read)(uv_stream_t*, ssize_t, const uv_buf_t*); void (*http_stream_on_read)(uv_stream_t *, ssize_t, const uv_buf_t *);
int (*http_server_write_response)(hw_write_context*, hw_string*); int (*http_server_write_response)(hw_write_context *, hw_string *);
http_connection* create_http_connection(); http_connection *create_http_connection();
void http_stream_on_connect(uv_stream_t* stream, int status); void http_stream_on_connect(uv_stream_t *stream, int status);
void http_stream_on_alloc(uv_handle_t* client, size_t suggested_size, uv_buf_t* buf); void http_stream_on_alloc(uv_handle_t *client, size_t suggested_size, uv_buf_t *buf);
void http_stream_on_close(uv_handle_t* handle); void http_stream_on_close(uv_handle_t *handle);
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);
void http_server_after_write(uv_write_t* req, int status); void http_server_after_write(uv_write_t *req, int status);
void http_stream_on_read_http_parser(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf); void http_stream_on_read_http_parser(uv_stream_t *tcp, ssize_t nread, const uv_buf_t *buf);
void reuseport_thread_start(void *arg); void reuseport_thread_start(void *arg);

View File

@ -3,25 +3,23 @@
#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);
memcpy(str->value, value, length); memcpy(str->value, value, length);
str->length = length; str->length = length;
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;
return str; return str;
} }
int hw_strcmp(hw_string* a, hw_string* b) { int hw_strcmp(hw_string *a, hw_string *b) {
int ret; int ret;
if (a->length > b->length) { if (a->length > b->length) {
@ -41,36 +39,31 @@ 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++;
} }
str->value = &buf[i+1]; str->value = &buf[i + 1];
str->length = length; str->length = length;
} }

View File

@ -1,9 +1,9 @@
#pragma once #pragma once
hw_string* create_string(const char* value); hw_string *create_string(const char *value);
int hw_strcmp(hw_string* a, hw_string* b); int hw_strcmp(hw_string *a, hw_string *b);
hw_string* hw_strdup(hw_string* tocopy); hw_string *hw_strdup(hw_string *tocopy);
void append_string(hw_string* destination, hw_string* source); void append_string(hw_string *destination, hw_string *source);
char* dupstr(const char *s); char *dupstr(const char *s);
void string_from_int(hw_string* str, int val, int base); void string_from_int(hw_string *str, int val, int base);
int hw_strcmp(hw_string* a, hw_string* b); int hw_strcmp(hw_string *a, hw_string *b);

View File

@ -113,7 +113,6 @@
* Added destructor * Added destructor
*/ */
#ifndef __AC_KHASH_H #ifndef __AC_KHASH_H
#define __AC_KHASH_H #define __AC_KHASH_H
@ -152,28 +151,29 @@ typedef unsigned long long khint64_t;
typedef khint32_t khint_t; typedef khint32_t khint_t;
typedef khint_t khiter_t; typedef khint_t khiter_t;
#define __ac_isempty(flag, i) ((flag[i>>4]>>((i&0xfU)<<1))&2) #define __ac_isempty(flag, i) ((flag[i >> 4] >> ((i & 0xfU) << 1)) & 2)
#define __ac_isdel(flag, i) ((flag[i>>4]>>((i&0xfU)<<1))&1) #define __ac_isdel(flag, i) ((flag[i >> 4] >> ((i & 0xfU) << 1)) & 1)
#define __ac_iseither(flag, i) ((flag[i>>4]>>((i&0xfU)<<1))&3) #define __ac_iseither(flag, i) ((flag[i >> 4] >> ((i & 0xfU) << 1)) & 3)
#define __ac_set_isdel_false(flag, i) (flag[i>>4]&=~(1ul<<((i&0xfU)<<1))) #define __ac_set_isdel_false(flag, i) (flag[i >> 4] &= ~(1ul << ((i & 0xfU) << 1)))
#define __ac_set_isempty_false(flag, i) (flag[i>>4]&=~(2ul<<((i&0xfU)<<1))) #define __ac_set_isempty_false(flag, i) (flag[i >> 4] &= ~(2ul << ((i & 0xfU) << 1)))
#define __ac_set_isboth_false(flag, i) (flag[i>>4]&=~(3ul<<((i&0xfU)<<1))) #define __ac_set_isboth_false(flag, i) (flag[i >> 4] &= ~(3ul << ((i & 0xfU) << 1)))
#define __ac_set_isdel_true(flag, i) (flag[i>>4]|=1ul<<((i&0xfU)<<1)) #define __ac_set_isdel_true(flag, i) (flag[i >> 4] |= 1ul << ((i & 0xfU) << 1))
#define __ac_fsize(m) ((m) < 16? 1 : (m)>>4) #define __ac_fsize(m) ((m) < 16 ? 1 : (m) >> 4)
#ifndef kroundup32 #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
#define kcalloc(N,Z) calloc(N,Z) #define kcalloc(N, Z) calloc(N, Z)
#endif #endif
#ifndef kmalloc #ifndef kmalloc
#define kmalloc(Z) malloc(Z) #define kmalloc(Z) malloc(Z)
#endif #endif
#ifndef krealloc #ifndef krealloc
#define krealloc(P,Z) realloc(P,Z) #define krealloc(P, Z) realloc(P, Z)
#endif #endif
#ifndef kfree #ifndef kfree
#define kfree(P) free(P) #define kfree(P) free(P)
@ -182,178 +182,207 @@ typedef khint_t khiter_t;
static const double __ac_HASH_UPPER = 0.77; static const double __ac_HASH_UPPER = 0.77;
#define __KHASH_TYPE(name, khkey_t, khval_t) \ #define __KHASH_TYPE(name, khkey_t, khval_t) \
typedef struct { \ typedef struct { \
khint_t n_buckets, size, n_occupied, upper_bound; \ khint_t n_buckets, size, n_occupied, upper_bound; \
khint32_t *flags; \ khint32_t *flags; \
khkey_t *keys; \ khkey_t *keys; \
khval_t *vals; \ khval_t *vals; \
} kh_##name##_t; } kh_##name##_t;
#define __KHASH_PROTOTYPES(name, khkey_t, khval_t) \ #define __KHASH_PROTOTYPES(name, khkey_t, khval_t) \
extern kh_##name##_t *kh_init_##name(void); \ extern kh_##name##_t *kh_init_##name(void); \
extern void kh_destroy_##name(kh_##name##_t *h); \ extern void kh_destroy_##name(kh_##name##_t *h); \
extern void kh_clear_##name(kh_##name##_t *h); \ extern void kh_clear_##name(kh_##name##_t *h); \
extern khint_t kh_get_##name(const kh_##name##_t *h, khkey_t key); \ extern khint_t kh_get_##name(const kh_##name##_t *h, khkey_t key); \
extern int kh_resize_##name(kh_##name##_t *h, khint_t new_n_buckets); \ extern int kh_resize_##name(kh_##name##_t *h, khint_t new_n_buckets); \
extern khint_t kh_put_##name(kh_##name##_t *h, khkey_t key, int *ret); \ extern 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) { \
} \ if (h) { \
SCOPE void kh_destroy_##name(kh_##name##_t *h) \ kfree((void *)h->keys); \
{ \ kfree(h->flags); \
if (h) { \ kfree((void *)h->vals); \
kfree((void *)h->keys); kfree(h->flags); \ kfree(h); \
kfree((void *)h->vals); \ } \
kfree(h); \ } \
} \ SCOPE void kh_clear_##name(kh_##name##_t *h) { \
} \ if (h && h->flags) { \
SCOPE void kh_clear_##name(kh_##name##_t *h) \ memset(h->flags, 0xaa, __ac_fsize(h->n_buckets) * sizeof(khint32_t)); \
{ \ h->size = h->n_occupied = 0; \
if (h && h->flags) { \ } \
memset(h->flags, 0xaa, __ac_fsize(h->n_buckets) * sizeof(khint32_t)); \ } \
h->size = h->n_occupied = 0; \ SCOPE khint_t kh_get_##name(const kh_##name##_t *h, khkey_t key) { \
} \ if (h->n_buckets) { \
} \ khint_t k, i, last, mask, step = 0; \
SCOPE khint_t kh_get_##name(const kh_##name##_t *h, khkey_t key) \ mask = h->n_buckets - 1; \
{ \ k = __hash_func(key); \
if (h->n_buckets) { \ i = k & mask; \
khint_t k, i, last, mask, step = 0; \ last = i; \
mask = h->n_buckets - 1; \ while (!__ac_isempty(h->flags, i) && (__ac_isdel(h->flags, i) || !__hash_equal(h->keys[i], key))) { \
k = __hash_func(key); i = k & mask; \ i = (i + (++step)) & mask; \
last = i; \ if (i == last) \
while (!__ac_isempty(h->flags, i) && (__ac_isdel(h->flags, i) || !__hash_equal(h->keys[i], key))) { \ return h->n_buckets; \
i = (i + (++step)) & mask; \ } \
if (i == last) return h->n_buckets; \ return __ac_iseither(h->flags, i) ? h->n_buckets : i; \
} \ } else \
return __ac_iseither(h->flags, i)? h->n_buckets : i; \ return 0; \
} else return 0; \ } \
} \ SCOPE int kh_resize_##name( \
SCOPE int kh_resize_##name(kh_##name##_t *h, khint_t new_n_buckets) \ kh_##name##_t *h, \
{ /* This function uses 0.25*n_buckets bytes of working space instead of [sizeof(key_t+val_t)+.25]*n_buckets. */ \ khint_t \
khint32_t *new_flags = 0; \ new_n_buckets) { /* This function uses 0.25*n_buckets bytes of working space instead of [sizeof(key_t+val_t)+.25]*n_buckets. */ \
khint_t j = 1; \ khint32_t *new_flags = 0; \
{ \ khint_t j = 1; \
kroundup32(new_n_buckets); \ { \
if (new_n_buckets < 4) new_n_buckets = 4; \ kroundup32(new_n_buckets); \
if (h->size >= (khint_t)(new_n_buckets * __ac_HASH_UPPER + 0.5)) j = 0; /* requested size is too small */ \ if (new_n_buckets < 4) \
else { /* hash table size to be changed (shrink or expand); rehash */ \ new_n_buckets = 4; \
new_flags = (khint32_t*)kmalloc(__ac_fsize(new_n_buckets) * sizeof(khint32_t)); \ if (h->size >= (khint_t)(new_n_buckets * __ac_HASH_UPPER + 0.5)) \
if (!new_flags) return -1; \ j = 0; /* requested size is too small */ \
memset(new_flags, 0xaa, __ac_fsize(new_n_buckets) * sizeof(khint32_t)); \ else { /* hash table size to be changed (shrink or expand); rehash */ \
if (h->n_buckets < new_n_buckets) { /* expand */ \ new_flags = (khint32_t *)kmalloc(__ac_fsize(new_n_buckets) * sizeof(khint32_t)); \
khkey_t *new_keys = (khkey_t*)krealloc((void *)h->keys, new_n_buckets * sizeof(khkey_t)); \ if (!new_flags) \
if (!new_keys) return -1; \ return -1; \
h->keys = new_keys; \ memset(new_flags, 0xaa, __ac_fsize(new_n_buckets) * sizeof(khint32_t)); \
if (kh_is_map) { \ if (h->n_buckets < new_n_buckets) { /* expand */ \
khval_t *new_vals = (khval_t*)krealloc((void *)h->vals, new_n_buckets * sizeof(khval_t)); \ khkey_t *new_keys = (khkey_t *)krealloc((void *)h->keys, new_n_buckets * sizeof(khkey_t)); \
if (!new_vals) return -1; \ if (!new_keys) \
h->vals = new_vals; \ return -1; \
} \ h->keys = new_keys; \
} /* otherwise shrink */ \ if (kh_is_map) { \
} \ khval_t *new_vals = (khval_t *)krealloc((void *)h->vals, new_n_buckets * sizeof(khval_t)); \
} \ if (!new_vals) \
if (j) { /* rehashing is needed */ \ return -1; \
for (j = 0; j != h->n_buckets; ++j) { \ h->vals = new_vals; \
if (__ac_iseither(h->flags, j) == 0) { \ } \
khkey_t key = h->keys[j]; \ } /* otherwise shrink */ \
khval_t val; \ } \
khint_t new_mask; \ } \
new_mask = new_n_buckets - 1; \ if (j) { /* rehashing is needed */ \
if (kh_is_map) val = h->vals[j]; \ for (j = 0; j != h->n_buckets; ++j) { \
__ac_set_isdel_true(h->flags, j); \ if (__ac_iseither(h->flags, j) == 0) { \
while (1) { /* kick-out process; sort of like in Cuckoo hashing */ \ khkey_t key = h->keys[j]; \
khint_t k, i, step = 0; \ khval_t val; \
k = __hash_func(key); \ khint_t new_mask; \
i = k & new_mask; \ new_mask = new_n_buckets - 1; \
while (!__ac_isempty(new_flags, i)) i = (i + (++step)) & new_mask; \ if (kh_is_map) \
__ac_set_isempty_false(new_flags, i); \ val = h->vals[j]; \
if (i < h->n_buckets && __ac_iseither(h->flags, i) == 0) { /* kick out the existing element */ \ __ac_set_isdel_true(h->flags, j); \
{ khkey_t tmp = h->keys[i]; h->keys[i] = key; key = tmp; } \ while (1) { /* kick-out process; sort of like in Cuckoo hashing */ \
if (kh_is_map) { khval_t tmp = h->vals[i]; h->vals[i] = val; val = tmp; } \ khint_t k, i, step = 0; \
__ac_set_isdel_true(h->flags, i); /* mark it as deleted in the old hash table */ \ k = __hash_func(key); \
} else { /* write the element and jump out of the loop */ \ i = k & new_mask; \
h->keys[i] = key; \ while (!__ac_isempty(new_flags, i)) \
if (kh_is_map) h->vals[i] = val; \ i = (i + (++step)) & new_mask; \
break; \ __ac_set_isempty_false(new_flags, i); \
} \ if (i < h->n_buckets && __ac_iseither(h->flags, i) == 0) { /* kick out the existing element */ \
} \ { \
} \ khkey_t tmp = h->keys[i]; \
} \ h->keys[i] = key; \
if (h->n_buckets > new_n_buckets) { /* shrink the hash table */ \ key = tmp; \
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) { \
} \ khval_t tmp = h->vals[i]; \
kfree(h->flags); /* free the working space */ \ h->vals[i] = val; \
h->flags = new_flags; \ val = tmp; \
h->n_buckets = new_n_buckets; \ } \
h->n_occupied = h->size; \ __ac_set_isdel_true(h->flags, i); /* mark it as deleted in the old hash table */ \
h->upper_bound = (khint_t)(h->n_buckets * __ac_HASH_UPPER + 0.5); \ } else { /* write the element and jump out of the loop */ \
} \ h->keys[i] = key; \
return 0; \ if (kh_is_map) \
} \ h->vals[i] = val; \
SCOPE khint_t kh_put_##name(kh_##name##_t *h, khkey_t key, int *ret) \ break; \
{ \ } \
khint_t x; \ } \
if (h->n_occupied >= h->upper_bound) { /* update the hash table */ \ } \
if (h->n_buckets > (h->size<<1)) { \ } \
if (kh_resize_##name(h, h->n_buckets - 1) < 0) { /* clear "deleted" elements */ \ if (h->n_buckets > new_n_buckets) { /* shrink the hash table */ \
*ret = -1; return h->n_buckets; \ h->keys = (khkey_t *)krealloc((void *)h->keys, new_n_buckets * sizeof(khkey_t)); \
} \ if (kh_is_map) \
} else if (kh_resize_##name(h, h->n_buckets + 1) < 0) { /* expand the hash table */ \ h->vals = (khval_t *)krealloc((void *)h->vals, new_n_buckets * sizeof(khval_t)); \
*ret = -1; return h->n_buckets; \ } \
} \ kfree(h->flags); /* free the working space */ \
} /* TODO: to implement automatically shrinking; resize() already support shrinking */ \ h->flags = new_flags; \
{ \ h->n_buckets = new_n_buckets; \
khint_t k, i, site, last, mask = h->n_buckets - 1, step = 0; \ h->n_occupied = h->size; \
x = site = h->n_buckets; k = __hash_func(key); i = k & mask; \ h->upper_bound = (khint_t)(h->n_buckets * __ac_HASH_UPPER + 0.5); \
if (__ac_isempty(h->flags, i)) x = i; /* for speed up */ \ } \
else { \ return 0; \
last = i; \ } \
while (!__ac_isempty(h->flags, i) && (__ac_isdel(h->flags, i) || !__hash_equal(h->keys[i], key))) { \ SCOPE khint_t kh_put_##name(kh_##name##_t *h, khkey_t key, int *ret) { \
if (__ac_isdel(h->flags, i)) site = i; \ khint_t x; \
i = (i + (++step)) & mask; \ if (h->n_occupied >= h->upper_bound) { /* update the hash table */ \
if (i == last) { x = site; break; } \ if (h->n_buckets > (h->size << 1)) { \
} \ if (kh_resize_##name(h, h->n_buckets - 1) < 0) { /* clear "deleted" elements */ \
if (x == h->n_buckets) { \ *ret = -1; \
if (__ac_isempty(h->flags, i) && site != h->n_buckets) x = site; \ return h->n_buckets; \
else x = i; \ } \
} \ } else if (kh_resize_##name(h, h->n_buckets + 1) < 0) { /* expand the hash table */ \
} \ *ret = -1; \
} \ return h->n_buckets; \
if (__ac_isempty(h->flags, x)) { /* not present at all */ \ } \
h->keys[x] = key; \ } /* TODO: to implement automatically shrinking; resize() already support shrinking */ \
__ac_set_isboth_false(h->flags, x); \ { \
++h->size; ++h->n_occupied; \ khint_t k, i, site, last, mask = h->n_buckets - 1, step = 0; \
*ret = 1; \ x = site = h->n_buckets; \
} else if (__ac_isdel(h->flags, x)) { /* deleted */ \ k = __hash_func(key); \
h->keys[x] = key; \ i = k & mask; \
__ac_set_isboth_false(h->flags, x); \ if (__ac_isempty(h->flags, i)) \
++h->size; \ x = i; /* for speed up */ \
*ret = 2; \ else { \
} else *ret = 0; /* Don't touch h->keys[x] if present and not deleted */ \ last = i; \
return x; \ while (!__ac_isempty(h->flags, i) && (__ac_isdel(h->flags, i) || !__hash_equal(h->keys[i], key))) { \
} \ if (__ac_isdel(h->flags, i)) \
SCOPE void kh_del_##name(kh_##name##_t *h, khint_t x) \ site = i; \
{ \ i = (i + (++step)) & mask; \
if (x != h->n_buckets && !__ac_iseither(h->flags, x)) { \ if (i == last) { \
__ac_set_isdel_true(h->flags, x); \ x = site; \
--h->size; \ break; \
} \ } \
} } \
if (x == h->n_buckets) { \
if (__ac_isempty(h->flags, i) && site != h->n_buckets) \
x = site; \
else \
x = i; \
} \
} \
} \
if (__ac_isempty(h->flags, x)) { /* not present at all */ \
h->keys[x] = key; \
__ac_set_isboth_false(h->flags, x); \
++h->size; \
++h->n_occupied; \
*ret = 1; \
} else if (__ac_isdel(h->flags, x)) { /* deleted */ \
h->keys[x] = key; \
__ac_set_isboth_false(h->flags, x); \
++h->size; \
*ret = 2; \
} else \
*ret = 0; /* Don't touch h->keys[x] if present and not deleted */ \
return x; \
} \
SCOPE void kh_del_##name(kh_##name##_t *h, khint_t x) { \
if (x != h->n_buckets && !__ac_iseither(h->flags, x)) { \
__ac_set_isdel_true(h->flags, x); \
--h->size; \
} \
}
#define KHASH_DECLARE(name, khkey_t, khval_t) \ #define KHASH_DECLARE(name, khkey_t, khval_t) \
__KHASH_TYPE(name, khkey_t, khval_t) \ __KHASH_TYPE(name, khkey_t, khval_t) \
__KHASH_PROTOTYPES(name, khkey_t, khval_t) __KHASH_PROTOTYPES(name, khkey_t, khval_t)
#define KHASH_INIT2(name, SCOPE, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal) \ #define KHASH_INIT2(name, SCOPE, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal) \
__KHASH_TYPE(name, khkey_t, khval_t) \ __KHASH_TYPE(name, khkey_t, khval_t) \
__KHASH_IMPL(name, SCOPE, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal) __KHASH_IMPL(name, SCOPE, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal)
#define KHASH_INIT(name, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal) \ #define KHASH_INIT(name, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal) \
KHASH_INIT2(name, static kh_inline, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal) KHASH_INIT2(name, static kh_inline, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal)
/* --- BEGIN OF HASH FUNCTIONS --- */ /* --- BEGIN OF HASH FUNCTIONS --- */
@ -372,7 +401,7 @@ KHASH_INIT2(name, static kh_inline, khkey_t, khval_t, kh_is_map, __hash_func, __
@param key The integer [khint64_t] @param key The integer [khint64_t]
@return The hash value [khint_t] @return The hash value [khint_t]
*/ */
#define kh_int64_hash_func(key) (khint32_t)((key)>>33^(key)^(key)<<11) #define kh_int64_hash_func(key) (khint32_t)((key) >> 33 ^ (key) ^ (key) << 11)
/*! @function /*! @function
@abstract 64-bit integer comparison function @abstract 64-bit integer comparison function
*/ */
@ -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) \
for (__i = kh_begin(h); __i != kh_end(h); ++__i) { \ { \
if (!kh_exist(h,__i)) continue; \ khint_t __i; \
(kvar) = kh_key(h,__i); \ for (__i = kh_begin(h); __i != kh_end(h); ++__i) { \
(vvar) = kh_val(h,__i); \ if (!kh_exist(h, __i)) \
code; \ continue; \
} } (kvar) = kh_key(h, __i); \
(vvar) = kh_val(h, __i); \
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) \
for (__i = kh_begin(h); __i != kh_end(h); ++__i) { \ { \
if (!kh_exist(h,__i)) continue; \ khint_t __i; \
(vvar) = kh_val(h,__i); \ for (__i = kh_begin(h); __i != kh_end(h); ++__i) { \
code; \ if (!kh_exist(h, __i)) \
} } continue; \
(vvar) = kh_val(h, __i); \
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
@ -595,23 +629,20 @@ KHASH_INIT(name, khint64_t, char, 0, kh_int64_hash_func, kh_int64_hash_equal)
@param khval_t Type of values [type] @param khval_t Type of values [type]
*/ */
#define KHASH_MAP_INIT_INT64(name, khval_t) \ #define KHASH_MAP_INIT_INT64(name, khval_t) \
KHASH_INIT(name, khint64_t, khval_t, 1, kh_int64_hash_func, kh_int64_hash_equal) KHASH_INIT(name, khint64_t, khval_t, 1, kh_int64_hash_func, kh_int64_hash_equal)
typedef const char *kh_cstr_t; typedef const char *kh_cstr_t;
/*! @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]
*/ */
#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 */

View File

@ -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 */

View File

@ -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,

View File

@ -10,7 +10,7 @@ typedef struct hw_route_token_st {
int start; int start;
} hw_route_token; } hw_route_token;
void hw_route_next_token(hw_string* url, int start, hw_route_token* result) { void hw_route_next_token(hw_string *url, int start, hw_route_token *result) {
while (start < url->length && (url->value[start] == '/')) { while (start < url->length && (url->value[start] == '/')) {
start++; start++;
} }
@ -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;
} }

View File

@ -1,3 +1,3 @@
#include "haywire.h" #include "haywire.h"
int hw_route_compare_method(hw_string* url, char* route); int hw_route_compare_method(hw_string *url, char *route);

View File

@ -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,

View File

@ -7,10 +7,9 @@
#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;
extern int stat_requests_destroyed_total; extern int stat_requests_destroyed_total;
void get_server_stats(http_request* request, hw_http_response* response, void* user_data); void get_server_stats(http_request *request, hw_http_response *response, void *user_data);

View File

@ -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() {