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)
endif (UNIX)
INCLUDE_DIRECTORIES(./include ./src)
INCLUDE_DIRECTORIES(./include ./src ../libs/include)
file(GLOB_RECURSE HW_HEADS
./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_body(hw_http_response* response, hw_string* body);
HAYWIRE_EXTERN void hw_http_response_send(hw_http_response* response, void* user_data, http_response_complete_callback callback);
HAYWIRE_EXTERN void hw_http_response_send_error(hw_http_response *response, const char *error, const char *err_msg);
HAYWIRE_EXTERN void hw_print_request_headers(http_request* request);
#ifdef __cplusplus

View File

@ -4,33 +4,25 @@
#include "../khash.h"
#include "ini.h"
KHASH_MAP_INIT_STR(route_hashes, char*)
KHASH_MAP_INIT_STR(route_hashes, char *)
int configuration_handler(void* user, const char* section, const char* name, const char* value)
{
configuration* config = (configuration*)user;
int configuration_handler(void *user, const char *section, const char *name, const char *value) {
configuration *config = (configuration *)user;
#define MATCH(s, n) strcmp(section, s) == 0 && strcmp(name, n) == 0
if (MATCH("http", "listen_address"))
{
if (MATCH("http", "listen_address")) {
config->http_listen_address = dupstr(value);
}
else if (MATCH("http", "listen_port"))
{
} else if (MATCH("http", "listen_port")) {
config->http_listen_port = atoi(value);
}
else
{
return 0; /* unknown section/name, error */
} else {
return 0; /* unknown section/name, error */
}
return 1;
}
configuration* load_configuration(const char* filename)
{
configuration* config = malloc(sizeof(configuration));
if (ini_parse(filename, configuration_handler, config) < 0)
{
configuration *load_configuration(const char *filename) {
configuration *config = malloc(sizeof(configuration));
if (ini_parse(filename, configuration_handler, config) < 0) {
dzlog_error("Can't load configuration\n");
return NULL;
}

View File

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

View File

@ -14,65 +14,57 @@
#include "ini.h"
#define MAX_LINE 200
#define MAX_LINE 200
#define MAX_SECTION 50
#define MAX_NAME 50
#define MAX_NAME 50
/* Strip whitespace chars off end of given string, in place. Return s. */
static char* rstrip(char* s)
{
char* p = s + strlen(s);
static char *rstrip(char *s) {
char *p = s + strlen(s);
while (p > s && isspace(*--p))
*p = '\0';
return s;
}
/* Return pointer to first non-whitespace char in given string. */
static char* lskip(const char* s)
{
static char *lskip(const char *s) {
while (*s && isspace(*s))
s++;
return (char*)s;
return (char *)s;
}
/* Return pointer to first char c or ';' comment in given string, or pointer to
null at end of string if neither found. ';' must be prefixed by a whitespace
character to register as a comment. */
static char* find_char_or_comment(const char* s, char c)
{
static char *find_char_or_comment(const char *s, char c) {
int was_whitespace = 0;
while (*s && *s != c && !(was_whitespace && *s == ';')) {
was_whitespace = isspace(*s);
s++;
}
return (char*)s;
return (char *)s;
}
/* Version of strncpy that ensures dest (size bytes) is null-terminated. */
static char* strncpy0(char* dest, const char* src, size_t size)
{
static char *strncpy0(char *dest, const char *src, size_t size) {
strncpy(dest, src, size);
dest[size - 1] = '\0';
return dest;
}
/* See documentation in header file. */
int ini_parse_file(FILE* file,
int (*handler)(void*, const char*, const char*,
const char*),
void* user)
{
int ini_parse_file(FILE *file, int (*handler)(void *, const char *, const char *, const char *), void *user) {
/* Uses a fair bit of stack (use heap instead if you need to) */
char line[MAX_LINE];
char section[MAX_SECTION] = "";
char prev_name[MAX_NAME] = "";
char prev_name[MAX_NAME] = "";
char* start;
char* end;
char* name;
char* value;
int lineno = 0;
int error = 0;
char *start;
char *end;
char *name;
char *value;
int lineno = 0;
int error = 0;
/* Scan through file line by line */
while (fgets(line, sizeof(line), file) != NULL) {
@ -97,23 +89,21 @@ int ini_parse_file(FILE* file,
*end = '\0';
strncpy0(section, start + 1, sizeof(section));
*prev_name = '\0';
}
else if (!error) {
} else if (!error) {
/* No ']' found on section line */
error = lineno;
}
}
else if (*start && *start != ';') {
} else if (*start && *start != ';') {
/* Not a comment, must be a name[=:]value pair */
end = find_char_or_comment(start, '=');
if (*end != '=') {
end = find_char_or_comment(start, ':');
}
if (*end == '=' || *end == ':') {
*end = '\0';
name = rstrip(start);
*end = '\0';
name = rstrip(start);
value = lskip(end + 1);
end = find_char_or_comment(value, '\0');
end = find_char_or_comment(value, '\0');
if (*end == ';')
*end = '\0';
rstrip(value);
@ -122,8 +112,7 @@ int ini_parse_file(FILE* file,
strncpy0(prev_name, name, sizeof(prev_name));
if (!handler(user, section, name, value) && !error)
error = lineno;
}
else if (!error) {
} else if (!error) {
/* No '=' or ':' found on name[=:]value line */
error = lineno;
}
@ -134,12 +123,9 @@ int ini_parse_file(FILE* file,
}
/* See documentation in header file. */
int ini_parse(const char* filename,
int (*handler)(void*, const char*, const char*, const char*),
void* user)
{
FILE* file;
int error;
int ini_parse(const char *filename, int (*handler)(void *, const char *, const char *, const char *), void *user) {
FILE *file;
int error;
file = fopen(filename, "r");
if (!file)

View File

@ -18,7 +18,7 @@ extern "C" {
#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
is "" if name=value pair parsed before any section heading. name:value
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
stop on first error), or -1 on file open error.
*/
int ini_parse(const char* filename,
int (*handler)(void* user, const char* section,
const char* name, const char* value),
void* user);
int ini_parse(const char *filename,
int (*handler)(void *user, const char *section, const char *name, const char *value), void *user);
/* Same as ini_parse(), but takes a FILE* instead of filename. This doesn't
/* Same as ini_parse(), but takes a FILE* instead of filename. This doesn't
close the file when it's finished -- the caller must do that. */
int ini_parse_file(FILE* file,
int (*handler)(void* user, const char* section,
const char* name, const char* value),
void* user);
int ini_parse_file(FILE *file, int (*handler)(void *user, const char *section, const char *name, const char *value),
void *user);
/* Nonzero to allow multi-line value parsing, in the style of Python's
/* Nonzero to allow multi-line value parsing, in the style of Python's
ConfigParser. If allowed, ini_parse() will call the handler with the same
name for each subsequent line parsed. */
#ifndef INI_ALLOW_MULTILINE

View File

@ -8,61 +8,55 @@
static bool tcp_nodelay;
void ipc_read_cb(uv_stream_t* handle, ssize_t nread, const uv_buf_t* buf)
{
int rc;
struct ipc_client_ctx* ctx;
uv_loop_t* loop;
uv_handle_type type;
uv_pipe_t* ipc_pipe;
void ipc_read_cb(uv_stream_t *handle, ssize_t nread, const uv_buf_t *buf) {
int rc;
struct ipc_client_ctx *ctx;
uv_loop_t *loop;
uv_handle_type type;
uv_pipe_t *ipc_pipe;
ipc_pipe = (uv_pipe_t*)handle;
ctx = container_of(ipc_pipe, struct ipc_client_ctx, ipc_pipe);
loop = ipc_pipe->loop;
ipc_pipe = (uv_pipe_t *)handle;
ctx = container_of(ipc_pipe, struct ipc_client_ctx, ipc_pipe);
loop = ipc_pipe->loop;
uv_pipe_pending_count(ipc_pipe);
type = uv_pipe_pending_type(ipc_pipe);
if (type == UV_TCP) {
rc = uv_tcp_init(loop, (uv_tcp_t*) ctx->server_handle);
rc = uv_tcp_init(loop, (uv_tcp_t *)ctx->server_handle);
if (tcp_nodelay) {
rc = uv_tcp_nodelay((uv_tcp_t*) ctx->server_handle, 1);
rc = uv_tcp_nodelay((uv_tcp_t *)ctx->server_handle, 1);
}
}
else if (type == UV_NAMED_PIPE)
rc = uv_pipe_init(loop, (uv_pipe_t*) ctx->server_handle, 0);
} else if (type == UV_NAMED_PIPE)
rc = uv_pipe_init(loop, (uv_pipe_t *)ctx->server_handle, 0);
rc = uv_accept(handle, ctx->server_handle);
uv_close((uv_handle_t*) &ctx->ipc_pipe, NULL);
uv_close((uv_handle_t *)&ctx->ipc_pipe, NULL);
}
void ipc_alloc_cb(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf)
{
struct ipc_client_ctx* ctx;
ctx = container_of(handle, struct ipc_client_ctx, ipc_pipe);
void ipc_alloc_cb(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) {
struct ipc_client_ctx *ctx;
ctx = container_of(handle, struct ipc_client_ctx, ipc_pipe);
buf->base = ctx->scratch;
buf->len = sizeof(ctx->scratch);
buf->len = sizeof(ctx->scratch);
}
void ipc_connect_cb(uv_connect_t* req, int status)
{
int rc;
struct ipc_client_ctx* ctx;
void ipc_connect_cb(uv_connect_t *req, int status) {
int rc;
struct ipc_client_ctx *ctx;
ctx = container_of(req, struct ipc_client_ctx, connect_req);
rc = uv_read_start((uv_stream_t*)&ctx->ipc_pipe, ipc_alloc_cb, ipc_read_cb);
rc = uv_read_start((uv_stream_t *)&ctx->ipc_pipe, ipc_alloc_cb, ipc_read_cb);
}
void connection_consumer_alloc(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf)
{
void connection_consumer_alloc(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) {
static char slab[32];
buf->base = slab;
buf->len = sizeof(slab);
buf->len = sizeof(slab);
}
void connection_consumer_new_connection(uv_stream_t* server_handle, int status)
{
int rc = 0;
http_connection* connection = create_http_connection();
void connection_consumer_new_connection(uv_stream_t *server_handle, int status) {
int rc = 0;
http_connection *connection = create_http_connection();
http_parser_init(&connection->parser, HTTP_REQUEST);
connection->parser.data = connection;
@ -71,27 +65,25 @@ void connection_consumer_new_connection(uv_stream_t* server_handle, int status)
rc = uv_tcp_init(server_handle->loop, &connection->stream);
if (tcp_nodelay) {
rc = uv_tcp_nodelay((uv_tcp_t*)&connection->stream, 1);
rc = uv_tcp_nodelay((uv_tcp_t *)&connection->stream, 1);
}
rc = uv_accept(server_handle, (uv_stream_t*)&connection->stream);
rc = uv_read_start((uv_stream_t*)&connection->stream, http_stream_on_alloc, http_stream_on_read);
rc = uv_accept(server_handle, (uv_stream_t *)&connection->stream);
rc = uv_read_start((uv_stream_t *)&connection->stream, http_stream_on_alloc, http_stream_on_read);
}
void connection_consumer_close(uv_async_t* handle, int status)
{
struct server_ctx* ctx;
void connection_consumer_close(uv_async_t *handle, int status) {
struct server_ctx *ctx;
ctx = container_of(handle, struct server_ctx, async_handle);
uv_close((uv_handle_t*) &ctx->server_handle, NULL);
uv_close((uv_handle_t*) &ctx->async_handle, NULL);
uv_close((uv_handle_t *)&ctx->server_handle, NULL);
uv_close((uv_handle_t *)&ctx->async_handle, NULL);
}
void get_listen_handle(uv_loop_t* loop, uv_stream_t* server_handle)
{
int rc;
void get_listen_handle(uv_loop_t *loop, uv_stream_t *server_handle) {
int rc;
struct ipc_client_ctx ctx;
ctx.server_handle = server_handle;
ctx.server_handle = server_handle;
ctx.server_handle->data = "server handle";
rc = uv_pipe_init(loop, &ctx.ipc_pipe, 1);
@ -99,30 +91,28 @@ void get_listen_handle(uv_loop_t* loop, uv_stream_t* server_handle)
rc = uv_run(loop, UV_RUN_DEFAULT);
}
void connection_consumer_start(void *arg)
{
int rc;
void connection_consumer_start(void *arg) {
struct server_ctx *ctx;
uv_loop_t* loop;
uv_loop_t *loop;
ctx = arg;
tcp_nodelay = ctx->tcp_nodelay;
loop = uv_loop_new();
ctx = arg;
tcp_nodelay = ctx->tcp_nodelay;
loop = uv_loop_new();
listener_event_loops[ctx->index] = *loop;
http_request_cache_configure_listener(loop, &listener_async_handles[ctx->index]);
uv_barrier_wait(listeners_created_barrier);
rc = uv_async_init(loop, &ctx->async_handle, connection_consumer_close);
uv_unref((uv_handle_t*) &ctx->async_handle);
uv_async_init(loop, &ctx->async_handle, connection_consumer_close);
uv_unref((uv_handle_t *)&ctx->async_handle);
/* Wait until the main thread is ready. */
uv_sem_wait(&ctx->semaphore);
get_listen_handle(loop, (uv_stream_t*) &ctx->server_handle);
get_listen_handle(loop, (uv_stream_t *)&ctx->server_handle);
uv_sem_post(&ctx->semaphore);
rc = uv_listen((uv_stream_t*)&ctx->server_handle, ctx->listen_backlog, connection_consumer_new_connection);
rc = uv_run(loop, UV_RUN_DEFAULT);
uv_listen((uv_stream_t *)&ctx->server_handle, ctx->listen_backlog, connection_consumer_new_connection);
uv_run(loop, UV_RUN_DEFAULT);
uv_loop_delete(loop);
}

View File

@ -4,47 +4,42 @@
#include "uv.h"
#ifndef offsetof
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#define offsetof(TYPE, MEMBER) ((size_t) & ((TYPE *)0)->MEMBER)
#endif
#define container_of(ptr, type, member) ((type*)(((char*)(ptr)) - offsetof(type, member)))
#define container_of(ptr, type, member) ((type *)(((char *)(ptr)) - offsetof(type, member)))
union stream_handle2
{
union stream_handle2 {
uv_pipe_t pipe;
uv_tcp_t tcp;
uv_tcp_t tcp;
};
typedef unsigned char handle_storage_t[sizeof(union stream_handle2)];
struct server_ctx
{
int index;
struct server_ctx {
int index;
handle_storage_t server_handle;
unsigned int num_connects;
uv_async_t async_handle;
uv_thread_t thread_id;
uv_sem_t semaphore;
bool tcp_nodelay;
unsigned int listen_backlog;
unsigned int num_connects;
uv_async_t async_handle;
uv_thread_t thread_id;
uv_sem_t semaphore;
bool tcp_nodelay;
unsigned int listen_backlog;
};
struct ipc_client_ctx
{
struct ipc_client_ctx {
uv_connect_t connect_req;
uv_stream_t* server_handle;
uv_pipe_t ipc_pipe;
char scratch[16];
uv_stream_t *server_handle;
uv_pipe_t ipc_pipe;
char scratch[16];
};
struct ipc_server_ctx
{
struct ipc_server_ctx {
handle_storage_t server_handle;
unsigned int num_connects;
uv_pipe_t ipc_pipe;
bool tcp_nodelay;
unsigned int num_connects;
uv_pipe_t ipc_pipe;
bool tcp_nodelay;
};
void connection_consumer_start(void *arg);
void connection_consumer_close(uv_async_t* handle, int status);
void connection_consumer_close(uv_async_t *handle, int status);

View File

@ -6,53 +6,45 @@
static struct sockaddr_in listen_addr;
void ipc_close_cb(uv_handle_t* handle)
{
struct ipc_peer_ctx* ctx;
void ipc_close_cb(uv_handle_t *handle) {
struct ipc_peer_ctx *ctx;
ctx = container_of(handle, struct ipc_peer_ctx, peer_handle);
free(ctx);
}
void ipc_write_cb(uv_write_t* req, int status)
{
struct ipc_peer_ctx* ctx;
void ipc_write_cb(uv_write_t *req, int status) {
struct ipc_peer_ctx *ctx;
ctx = container_of(req, struct ipc_peer_ctx, write_req);
uv_close((uv_handle_t*) &ctx->peer_handle, ipc_close_cb);
uv_close((uv_handle_t *)&ctx->peer_handle, ipc_close_cb);
}
void ipc_connection_cb(uv_stream_t* ipc_pipe, int status)
{
int rc;
struct ipc_server_ctx* sc;
struct ipc_peer_ctx* pc;
uv_loop_t* loop;
uv_buf_t buf;
void ipc_connection_cb(uv_stream_t *ipc_pipe, int status) {
int rc;
struct ipc_server_ctx *sc;
struct ipc_peer_ctx *pc;
uv_loop_t *loop;
uv_buf_t buf;
loop = ipc_pipe->loop;
buf = uv_buf_init("PING", 4);
sc = container_of(ipc_pipe, struct ipc_server_ctx, ipc_pipe);
pc = calloc(1, sizeof(*pc));
buf = uv_buf_init("PING", 4);
sc = container_of(ipc_pipe, struct ipc_server_ctx, ipc_pipe);
pc = calloc(1, sizeof(*pc));
//ASSERT(pc != NULL);
if (ipc_pipe->type == UV_TCP) {
rc = uv_tcp_init(loop, (uv_tcp_t*) &pc->peer_handle);
rc = uv_tcp_init(loop, (uv_tcp_t *)&pc->peer_handle);
if (sc->tcp_nodelay) {
rc = uv_tcp_nodelay((uv_tcp_t*) &pc->peer_handle, 1);
rc = uv_tcp_nodelay((uv_tcp_t *)&pc->peer_handle, 1);
}
}
else if (ipc_pipe->type == UV_NAMED_PIPE)
rc = uv_pipe_init(loop, (uv_pipe_t*) &pc->peer_handle, 1);
} else if (ipc_pipe->type == UV_NAMED_PIPE)
rc = uv_pipe_init(loop, (uv_pipe_t *)&pc->peer_handle, 1);
rc = uv_accept(ipc_pipe, (uv_stream_t*) &pc->peer_handle);
rc = uv_write2(&pc->write_req,
(uv_stream_t*) &pc->peer_handle,
&buf,
1,
(uv_stream_t*) &sc->server_handle,
ipc_write_cb);
rc = uv_accept(ipc_pipe, (uv_stream_t *)&pc->peer_handle);
rc = uv_write2(
&pc->write_req, (uv_stream_t *)&pc->peer_handle, &buf, 1, (uv_stream_t *)&sc->server_handle, ipc_write_cb);
if (--sc->num_connects == 0)
uv_close((uv_handle_t*) ipc_pipe, NULL);
uv_close((uv_handle_t *)ipc_pipe, NULL);
}
extern void print_configuration();
@ -60,41 +52,40 @@ extern void print_configuration();
* threads. It's kind of cumbersome for such a simple operation, maybe we
* should revive uv_import() and uv_export().
*/
void start_connection_dispatching(uv_handle_type type, unsigned int num_servers, struct server_ctx* servers, char* listen_address, int listen_port, bool tcp_nodelay, int listen_backlog)
{
int rc;
void start_connection_dispatching(uv_handle_type type, unsigned int num_servers, struct server_ctx *servers,
char *listen_address, int listen_port, bool tcp_nodelay, int listen_backlog) {
int rc;
struct ipc_server_ctx ctx;
uv_loop_t* loop;
unsigned int i;
uv_loop_t *loop;
unsigned int i;
loop = uv_default_loop();
loop = uv_default_loop();
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);
rc = uv_tcp_init(loop, (uv_tcp_t*) &ctx.server_handle);
rc = uv_tcp_init(loop, (uv_tcp_t *)&ctx.server_handle);
if (ctx.tcp_nodelay) {
rc = uv_tcp_nodelay((uv_tcp_t*) &ctx.server_handle, 1);
rc = uv_tcp_nodelay((uv_tcp_t *)&ctx.server_handle, 1);
}
rc = uv_tcp_bind((uv_tcp_t*) &ctx.server_handle, (const struct sockaddr*)&listen_addr, 0);
rc = uv_tcp_bind((uv_tcp_t *)&ctx.server_handle, (const struct sockaddr *)&listen_addr, 0);
print_configuration();
printf("Listening...\n");
}
rc = uv_pipe_init(loop, &ctx.ipc_pipe, 1);
rc = uv_pipe_bind(&ctx.ipc_pipe, "HAYWIRE_CONNECTION_DISPATCH_PIPE_NAME");
rc = uv_listen((uv_stream_t*) &ctx.ipc_pipe, listen_backlog, ipc_connection_cb);
rc = uv_listen((uv_stream_t *)&ctx.ipc_pipe, listen_backlog, ipc_connection_cb);
for (i = 0; i < num_servers; i++)
uv_sem_post(&servers[i].semaphore);
rc = uv_run(loop, UV_RUN_DEFAULT);
uv_close((uv_handle_t*) &ctx.server_handle, NULL);
uv_close((uv_handle_t *)&ctx.server_handle, NULL);
rc = uv_run(loop, UV_RUN_DEFAULT);
for (i = 0; i < num_servers; i++)

View File

@ -3,10 +3,10 @@
#include "uv.h"
#include "connection_consumer.h"
struct ipc_peer_ctx
{
struct ipc_peer_ctx {
handle_storage_t peer_handle;
uv_write_t write_req;
uv_write_t write_req;
};
void start_connection_dispatching(uv_handle_type type, unsigned int num_servers, struct server_ctx* servers, char* listen_address, int listen_port, bool tcp_nodelay, int listen_backlog);
void start_connection_dispatching(uv_handle_type type, unsigned int num_servers, struct server_ctx *servers,
char *listen_address, int listen_port, bool tcp_nodelay, int listen_backlog);

View File

@ -6,16 +6,19 @@
#include "http_request.h"
#include "http_request_buffers.h"
typedef struct
{
uv_tcp_t stream;
http_parser parser;
uv_write_t write_req;
http_request* request;
hw_string current_header_key;
hw_string current_header_value;
int keep_alive;
int last_was_value;
enum {OPEN, CLOSING, CLOSED} state;
hw_request_buffer* buffer;
typedef struct {
uv_tcp_t stream;
http_parser parser;
uv_write_t write_req;
http_request *request;
hw_string current_header_key;
hw_string current_header_value;
int keep_alive;
int last_was_value;
enum {
OPEN,
CLOSING,
CLOSED
} state;
hw_request_buffer *buffer;
} http_connection;

File diff suppressed because it is too large Load Diff

View File

@ -24,35 +24,35 @@
extern "C" {
#endif
/* Also update SONAME in the Makefile whenever you change these. */
/* Also update SONAME in the Makefile whenever you change these. */
#define HTTP_PARSER_VERSION_MAJOR 2
#define HTTP_PARSER_VERSION_MINOR 3
#define HTTP_PARSER_VERSION_PATCH 0
#include <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 <stddef.h>
typedef __int8 int8_t;
typedef unsigned __int8 uint8_t;
typedef __int16 int16_t;
typedef unsigned __int16 uint16_t;
typedef __int32 int32_t;
typedef unsigned __int32 uint32_t;
typedef __int64 int64_t;
typedef unsigned __int64 uint64_t;
typedef __int8 int8_t;
typedef unsigned __int8 uint8_t;
typedef __int16 int16_t;
typedef unsigned __int16 uint16_t;
typedef __int32 int32_t;
typedef unsigned __int32 uint32_t;
typedef __int64 int64_t;
typedef unsigned __int64 uint64_t;
#else
#include <stdint.h>
#endif
/* Compile with -DHTTP_PARSER_STRICT=0 to make less checks, but run
/* Compile with -DHTTP_PARSER_STRICT=0 to make less checks, but run
* faster
*/
#ifndef HTTP_PARSER_STRICT
# define HTTP_PARSER_STRICT 1
#define HTTP_PARSER_STRICT 1
#endif
/* Maximium header size allowed. If the macro is not defined
/* Maximium header size allowed. If the macro is not defined
* before including this header then the default is used. To
* change the maximum header size, define the macro in the build
* environment (e.g. -DHTTP_MAX_HEADER_SIZE=<value>). To remove
@ -60,14 +60,13 @@ extern "C" {
* to a very large number (e.g. -DHTTP_MAX_HEADER_SIZE=0x7fffffff)
*/
#ifndef HTTP_MAX_HEADER_SIZE
# define HTTP_MAX_HEADER_SIZE (80*1024)
#define HTTP_MAX_HEADER_SIZE (80 * 1024)
#endif
typedef struct http_parser http_parser;
typedef struct http_parser_settings http_parser_settings;
typedef struct http_parser http_parser;
typedef struct http_parser_settings http_parser_settings;
/* Callbacks should return non-zero to indicate an error. The parser will
/* Callbacks should return non-zero to indicate an error. The parser will
* then halt execution.
*
* The one exception is on_headers_complete. In a HTTP_RESPONSE parser
@ -80,199 +79,188 @@ extern "C" {
* many times for each string. E.G. you might get 10 callbacks for "on_url"
* each providing just a few characters more data.
*/
typedef int (*http_data_cb) (http_parser*, const char *at, size_t length);
typedef int (*http_cb) (http_parser*);
typedef int (*http_data_cb)(http_parser *, const char *at, size_t length);
typedef int (*http_cb)(http_parser *);
/* Request Methods */
#define HTTP_METHOD_MAP(XX) \
XX(0, DELETE, DELETE) \
XX(1, GET, GET) \
XX(2, HEAD, HEAD) \
XX(3, POST, POST) \
XX(4, PUT, PUT) \
/* pathological */ \
XX(5, CONNECT, CONNECT) \
XX(6, OPTIONS, OPTIONS) \
XX(7, TRACE, TRACE) \
/* webdav */ \
XX(8, COPY, COPY) \
XX(9, LOCK, LOCK) \
XX(10, MKCOL, MKCOL) \
XX(11, MOVE, MOVE) \
XX(12, PROPFIND, PROPFIND) \
XX(13, PROPPATCH, PROPPATCH) \
XX(14, SEARCH, SEARCH) \
XX(15, UNLOCK, UNLOCK) \
/* subversion */ \
XX(16, REPORT, REPORT) \
XX(17, MKACTIVITY, MKACTIVITY) \
XX(18, CHECKOUT, CHECKOUT) \
XX(19, MERGE, MERGE) \
/* upnp */ \
XX(20, MSEARCH, M-SEARCH) \
XX(21, NOTIFY, NOTIFY) \
XX(22, SUBSCRIBE, SUBSCRIBE) \
XX(23, UNSUBSCRIBE, UNSUBSCRIBE) \
/* RFC-5789 */ \
XX(24, PATCH, PATCH) \
XX(25, PURGE, PURGE) \
/* CalDAV */ \
XX(26, MKCALENDAR, MKCALENDAR) \
/* Request Methods */
#define HTTP_METHOD_MAP(XX) \
XX(0, DELETE, DELETE) \
XX(1, GET, GET) \
XX(2, HEAD, HEAD) \
XX(3, POST, POST) \
XX(4, PUT, PUT) \
/* pathological */ \
XX(5, CONNECT, CONNECT) \
XX(6, OPTIONS, OPTIONS) \
XX(7, TRACE, TRACE) \
/* webdav */ \
XX(8, COPY, COPY) \
XX(9, LOCK, LOCK) \
XX(10, MKCOL, MKCOL) \
XX(11, MOVE, MOVE) \
XX(12, PROPFIND, PROPFIND) \
XX(13, PROPPATCH, PROPPATCH) \
XX(14, SEARCH, SEARCH) \
XX(15, UNLOCK, UNLOCK) \
/* subversion */ \
XX(16, REPORT, REPORT) \
XX(17, MKACTIVITY, MKACTIVITY) \
XX(18, CHECKOUT, CHECKOUT) \
XX(19, MERGE, MERGE) \
/* upnp */ \
XX(20, MSEARCH, M - SEARCH) \
XX(21, NOTIFY, NOTIFY) \
XX(22, SUBSCRIBE, SUBSCRIBE) \
XX(23, UNSUBSCRIBE, UNSUBSCRIBE) \
/* RFC-5789 */ \
XX(24, PATCH, PATCH) \
XX(25, PURGE, PURGE) \
/* CalDAV */ \
XX(26, MKCALENDAR, MKCALENDAR)
enum http_method
{
enum http_method {
#define XX(num, name, string) HTTP_##name = num,
HTTP_METHOD_MAP(XX)
HTTP_METHOD_MAP(XX)
#undef XX
};
};
enum http_parser_type {
HTTP_REQUEST,
HTTP_RESPONSE,
HTTP_BOTH
};
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
};
/* Flag values for http_parser.flags field */
enum flags
{ F_CHUNKED = 1 << 0
, F_CONNECTION_KEEP_ALIVE = 1 << 1
, F_CONNECTION_CLOSE = 1 << 2
, F_CONNECTION_UPGRADE = 1 << 3
, F_TRAILING = 1 << 4
, F_UPGRADE = 1 << 5
, F_SKIPBODY = 1 << 6
};
/* Map for errno-related constants
/* Map for errno-related constants
*
* The provided argument should be a macro that takes 2 arguments.
*/
#define HTTP_ERRNO_MAP(XX) \
/* No error */ \
XX(OK, "success") \
\
/* Callback-related errors */ \
XX(CB_message_begin, "the on_message_begin callback failed") \
XX(CB_url, "the on_url callback failed") \
XX(CB_header_field, "the on_header_field callback failed") \
XX(CB_header_value, "the on_header_value callback failed") \
XX(CB_headers_complete, "the on_headers_complete callback failed") \
XX(CB_body, "the on_body callback failed") \
XX(CB_message_complete, "the on_message_complete callback failed") \
XX(CB_status, "the on_status callback failed") \
\
/* Parsing-related errors */ \
XX(INVALID_EOF_STATE, "stream ended at an unexpected time") \
XX(HEADER_OVERFLOW, \
"too many header bytes seen; overflow detected") \
XX(CLOSED_CONNECTION, \
"data received after completed connection: close message") \
XX(INVALID_VERSION, "invalid HTTP version") \
XX(INVALID_STATUS, "invalid HTTP status code") \
XX(INVALID_METHOD, "invalid HTTP method") \
XX(INVALID_URL, "invalid URL") \
XX(INVALID_HOST, "invalid host") \
XX(INVALID_PORT, "invalid port") \
XX(INVALID_PATH, "invalid path") \
XX(INVALID_QUERY_STRING, "invalid query string") \
XX(INVALID_FRAGMENT, "invalid fragment") \
XX(LF_EXPECTED, "LF character expected") \
XX(INVALID_HEADER_TOKEN, "invalid character in header") \
XX(INVALID_CONTENT_LENGTH, \
"invalid character in content-length header") \
XX(INVALID_CHUNK_SIZE, \
"invalid character in chunk size header") \
XX(INVALID_CONSTANT, "invalid constant string") \
XX(INVALID_INTERNAL_STATE, "encountered unexpected internal state")\
XX(STRICT, "strict mode assertion failed") \
XX(PAUSED, "parser is paused") \
XX(UNKNOWN, "an unknown error occurred")
#define HTTP_ERRNO_MAP(XX) \
/* No error */ \
XX(OK, "success") \
\
/* Callback-related errors */ \
XX(CB_message_begin, "the on_message_begin callback failed") \
XX(CB_url, "the on_url callback failed") \
XX(CB_header_field, "the on_header_field callback failed") \
XX(CB_header_value, "the on_header_value callback failed") \
XX(CB_headers_complete, "the on_headers_complete callback failed") \
XX(CB_body, "the on_body callback failed") \
XX(CB_message_complete, "the on_message_complete callback failed") \
XX(CB_status, "the on_status callback failed") \
\
/* Parsing-related errors */ \
XX(INVALID_EOF_STATE, "stream ended at an unexpected time") \
XX(HEADER_OVERFLOW, "too many header bytes seen; overflow detected") \
XX(CLOSED_CONNECTION, "data received after completed connection: close message") \
XX(INVALID_VERSION, "invalid HTTP version") \
XX(INVALID_STATUS, "invalid HTTP status code") \
XX(INVALID_METHOD, "invalid HTTP method") \
XX(INVALID_URL, "invalid URL") \
XX(INVALID_HOST, "invalid host") \
XX(INVALID_PORT, "invalid port") \
XX(INVALID_PATH, "invalid path") \
XX(INVALID_QUERY_STRING, "invalid query string") \
XX(INVALID_FRAGMENT, "invalid fragment") \
XX(LF_EXPECTED, "LF character expected") \
XX(INVALID_HEADER_TOKEN, "invalid character in header") \
XX(INVALID_CONTENT_LENGTH, "invalid character in content-length header") \
XX(INVALID_CHUNK_SIZE, "invalid character in chunk size header") \
XX(INVALID_CONSTANT, "invalid constant string") \
XX(INVALID_INTERNAL_STATE, "encountered unexpected internal state") \
XX(STRICT, "strict mode assertion failed") \
XX(PAUSED, "parser is paused") \
XX(UNKNOWN, "an unknown error occurred")
/* Define HPE_* values for each errno value above */
/* Define HPE_* values for each errno value above */
#define HTTP_ERRNO_GEN(n, s) HPE_##n,
enum http_errno {
HTTP_ERRNO_MAP(HTTP_ERRNO_GEN)
};
enum http_errno {
HTTP_ERRNO_MAP(HTTP_ERRNO_GEN)
};
#undef HTTP_ERRNO_GEN
/* Get an http_errno value from an http_parser */
#define HTTP_PARSER_ERRNO(p) ((enum http_errno)(p)->http_errno)
/* Get an http_errno value from an http_parser */
#define HTTP_PARSER_ERRNO(p) ((enum http_errno) (p)->http_errno)
struct http_parser {
/** PRIVATE **/
unsigned int type : 2; /* enum http_parser_type */
unsigned int flags : 6; /* F_* values from 'flags' enum; semi-public */
unsigned int state : 8; /* enum state from http_parser.c */
unsigned int header_state : 8; /* enum header_state from http_parser.c */
unsigned int index : 8; /* index into current matcher */
uint32_t nread; /* # bytes read in various scenarios */
uint64_t content_length; /* # bytes in body (0 if no Content-Length header) */
struct http_parser {
/** PRIVATE **/
unsigned int type : 2; /* enum http_parser_type */
unsigned int flags : 6; /* F_* values from 'flags' enum; semi-public */
unsigned int state : 8; /* enum state from http_parser.c */
unsigned int header_state : 8; /* enum header_state from http_parser.c */
unsigned int index : 8; /* index into current matcher */
/** READ-ONLY **/
unsigned short http_major;
unsigned short http_minor;
unsigned int status_code : 16; /* responses only */
unsigned int method : 8; /* requests only */
unsigned int http_errno : 7;
uint32_t nread; /* # bytes read in various scenarios */
uint64_t content_length; /* # bytes in body (0 if no Content-Length header) */
/** READ-ONLY **/
unsigned short http_major;
unsigned short http_minor;
unsigned int status_code : 16; /* responses only */
unsigned int method : 8; /* requests only */
unsigned int http_errno : 7;
/* 1 = Upgrade header was present and the parser has exited because of that.
/* 1 = Upgrade header was present and the parser has exited because of that.
* 0 = No upgrade header present.
* Should be checked when http_parser_execute() returns in addition to
* error checking.
*/
unsigned int upgrade : 1;
unsigned int upgrade : 1;
/** PUBLIC **/
void *data; /* A pointer to get hook to the "connection" or "socket" object */
};
/** PUBLIC **/
void *data; /* A pointer to get hook to the "connection" or "socket" object */
};
struct http_parser_settings {
http_cb on_message_begin;
http_data_cb on_url;
http_data_cb on_status;
http_data_cb on_header_field;
http_data_cb on_header_value;
http_cb on_headers_complete;
http_data_cb on_body;
http_cb on_message_complete;
};
struct http_parser_settings {
http_cb on_message_begin;
http_data_cb on_url;
http_data_cb on_status;
http_data_cb on_header_field;
http_data_cb on_header_value;
http_cb on_headers_complete;
http_data_cb on_body;
http_cb on_message_complete;
};
enum http_parser_url_fields {
UF_SCHEMA = 0,
UF_HOST = 1,
UF_PORT = 2,
UF_PATH = 3,
UF_QUERY = 4,
UF_FRAGMENT = 5,
UF_USERINFO = 6,
UF_MAX = 7
};
enum http_parser_url_fields
{ UF_SCHEMA = 0
, UF_HOST = 1
, UF_PORT = 2
, UF_PATH = 3
, UF_QUERY = 4
, UF_FRAGMENT = 5
, UF_USERINFO = 6
, UF_MAX = 7
};
/* Result structure for http_parser_parse_url().
/* Result structure for http_parser_parse_url().
*
* Callers should index into field_data[] with UF_* values iff field_set
* has the relevant (1 << UF_*) bit set. As a courtesy to clients (and
* because we probably have padding left over), we convert any port to
* a uint16_t.
*/
struct http_parser_url {
uint16_t field_set; /* Bitmask of (1 << UF_*) values */
uint16_t port; /* Converted UF_PORT string */
struct http_parser_url {
uint16_t field_set; /* Bitmask of (1 << UF_*) values */
uint16_t port; /* Converted UF_PORT string */
struct {
uint16_t off; /* Offset into buffer in which field starts */
uint16_t len; /* Length of run in buffer */
} field_data[UF_MAX];
};
struct {
uint16_t off; /* Offset into buffer in which field starts */
uint16_t len; /* Length of run in buffer */
} field_data[UF_MAX];
};
/* Returns the library version. Bits 16-23 contain the major version number,
/* Returns the library version. Bits 16-23 contain the major version number,
* bits 8-15 the minor version number and bits 0-7 the patch level.
* Usage example:
*
@ -282,46 +270,39 @@ XX(UNKNOWN, "an unknown error occurred")
* unsigned patch = version & 255;
* printf("http_parser v%u.%u.%u\n", major, minor, patch);
*/
unsigned long http_parser_version(void);
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. */
size_t http_parser_execute(http_parser *parser,
const http_parser_settings *settings,
const char *data,
size_t len);
size_t http_parser_execute(http_parser *parser, const http_parser_settings *settings, const char *data, size_t len);
/* If http_should_keep_alive() in the on_headers_complete or
/* If http_should_keep_alive() in the on_headers_complete or
* on_message_complete callback returns 0, then this should be
* the last message on the connection.
* If you are the server, respond with the "Connection: close" header.
* If you are the client, close the connection.
*/
int http_should_keep_alive(const http_parser *parser);
int http_should_keep_alive(const http_parser *parser);
/* Returns a string version of the HTTP method. */
const char *http_method_str(enum http_method m);
/* Returns a string version of the HTTP method. */
const char *http_method_str(enum http_method m);
/* Return a string name of the given error */
const char *http_errno_name(enum http_errno err);
/* Return a string name of the given error */
const char *http_errno_name(enum http_errno err);
/* Return a string description of the given error */
const char *http_errno_description(enum http_errno err);
/* Return a string description of the given error */
const char *http_errno_description(enum http_errno err);
/* Parse a URL; return nonzero on failure */
int http_parser_parse_url(const char *buf, size_t buflen,
int is_connect,
struct http_parser_url *u);
/* Parse a URL; return nonzero on failure */
int http_parser_parse_url(const char *buf, size_t buflen, int is_connect, struct http_parser_url *u);
/* Pause or un-pause the parser; a nonzero value pauses */
void http_parser_pause(http_parser *parser, int paused);
/* Pause or un-pause the parser; a nonzero value pauses */
void http_parser_pause(http_parser *parser, int paused);
/* Checks if this is the final chunk of the body. */
int http_body_is_final(const http_parser *parser);
/* Checks if this is the final chunk of the body. */
int http_body_is_final(const http_parser *parser);
#ifdef __cplusplus
}

View File

@ -10,67 +10,58 @@
#include "http_server.h"
#include "server_stats.h"
#include "route_compare_method.h"
#include "misc.h"
extern char* uv__strndup(const char* s, size_t n);
extern char *uv__strndup(const char *s, size_t n);
#define CRLF "\r\n"
static const char response_404[] =
"HTTP/1.1 404 Not Found" CRLF
"Server: Haywire/master" CRLF
"Date: Fri, 26 Aug 2011 00:31:53 GMT" CRLF
"Connection: Keep-Alive" CRLF
"Content-Type: text/html" CRLF
"Content-Length: 16" CRLF
CRLF
"404 Not Found" CRLF
;
static const char response_404[] = "HTTP/1.1 404 Not Found" CRLF "Server: Haywire/master" CRLF
"Date: Fri, 26 Aug 2011 00:31:53 GMT" CRLF "Connection: Keep-Alive" CRLF
"Content-Type: text/html" CRLF "Content-Length: 16" CRLF CRLF "404 Not Found" CRLF;
static kh_inline khint_t hw_string_hash_func(hw_string* s)
{
static kh_inline khint_t hw_string_hash_func(hw_string *s) {
khint_t h = s->length > 0 ? (khint_t)*s->value : 0;
if (h) for (int i = 0; i < s->length; i++) h = (h << 5) - h + (khint_t)*(s->value + i);
if (h)
for (int i = 0; i < s->length; i++)
h = (h << 5) - h + (khint_t) * (s->value + i);
return h;
}
#define hw_string_hash_equal(a, b) (hw_strcmp(a, b) == 0)
KHASH_INIT(hw_string_hashmap, hw_string*, hw_string*, 1, hw_string_hash_func, hw_string_hash_equal)
KHASH_MAP_INIT_STR(string_hashmap, char*)
KHASH_INIT(hw_string_hashmap, hw_string *, hw_string *, 1, hw_string_hash_func, hw_string_hash_equal)
KHASH_MAP_INIT_STR(string_hashmap, char *)
KHASH_MAP_INIT_INT64(offset_hashmap, int)
void hw_print_request_headers(http_request* request)
{
hw_string* k;
hw_string* v;
void hw_print_request_headers(http_request *request) {
hw_string *k;
hw_string *v;
khash_t(hw_string_hashmap) *h = request->headers;
kh_foreach(h, k, v, {
char* key = uv__strndup(k->value, k->length + 1);
char* value = uv__strndup(v->value, v->length + 1);
char *key = uv__strndup(k->value, k->length + 1);
char *value = uv__strndup(v->value, v->length + 1);
printf("KEY: %s VALUE: %s\n", key, value);
free(key);
free(value);
});
}
void hw_print_body(http_request* request)
{
void hw_print_body(http_request *request) {
if (request->body->length > 0) {
char* body = uv__strndup(request->body->value, request->body->length);
char *body = uv__strndup(request->body->value, request->body->length);
printf("BODY: %s\n", body);
free(body);
}
else {
} else {
printf("BODY is empty!\n");
}
}
void* get_header(http_request* request, hw_string* name)
{
void *get_header(http_request *request, hw_string *name) {
khash_t(hw_string_hashmap) *h = request->headers;
khiter_t k = kh_get(hw_string_hashmap, h, name);
khiter_t k = kh_get(hw_string_hashmap, h, name);
void* val;
void *val;
int is_missing = (k == kh_end(h));
if (is_missing) {
@ -81,48 +72,43 @@ void* get_header(http_request* request, hw_string* name)
return val;
}
void set_header(http_request* request, hw_string* name, hw_string* value)
{
int ret, i;
void set_header(http_request *request, hw_string *name, hw_string *value) {
int ret, i;
khiter_t k;
khash_t(hw_string_hashmap) *h = request->headers;
for (i = 0; i < name->length; i++)
{
for (i = 0; i < name->length; i++) {
name->value[i] = tolower(name->value[i]);
}
void* prev = get_header(request, name);
void *prev = get_header(request, name);
if (prev) {
free(prev);
}
k = kh_put(hw_string_hashmap, h, name, &ret);
k = kh_put(hw_string_hashmap, h, name, &ret);
kh_value(h, k) = value;
}
http_request* create_http_request(http_connection* connection)
{
http_request* request = calloc(1, sizeof(http_request));
request->headers = kh_init(hw_string_hashmap);
request->url = calloc(1, sizeof(hw_string));
request->body = calloc(1, sizeof(hw_string));
request->state = OK;
http_request *create_http_request(http_connection *UNUSED(connection)) {
http_request *request = calloc(1, sizeof(http_request));
request->headers = kh_init(hw_string_hashmap);
request->url = calloc(1, sizeof(hw_string));
request->body = calloc(1, sizeof(hw_string));
request->state = OK;
INCREMENT_STAT(stat_requests_created_total);
return request;
}
void free_http_request(http_request* request)
{
void free_http_request(http_request *request) {
khash_t(hw_string_hashmap) *h = request->headers;
hw_string* k;
hw_string* v;
hw_string *k;
hw_string *v;
kh_foreach(h, k, v,
{
free((hw_string*)k);
free((hw_string*)v);
kh_foreach(h, k, v, {
free((hw_string *)k);
free((hw_string *)v);
});
kh_destroy(hw_string_hashmap, h);
@ -135,15 +121,13 @@ void free_http_request(http_request* request)
INCREMENT_STAT(stat_requests_destroyed_total);
}
hw_string* hw_get_header(http_request* request, hw_string* key)
{
void* value = get_header(request, key);
hw_string *hw_get_header(http_request *request, hw_string *key) {
void *value = get_header(request, key);
return value;
}
int http_request_on_message_begin(http_parser* parser)
{
http_connection* connection = (http_connection*)parser->data;
int http_request_on_message_begin(http_parser *parser) {
http_connection *connection = (http_connection *)parser->data;
if (connection->request) {
/* We're seeing a new request on the same connection, so it's time to free up the old one
* and create a new one.
@ -156,18 +140,17 @@ int http_request_on_message_begin(http_parser* parser)
return 0;
}
int http_request_on_url(http_parser *parser, const char *at, size_t length)
{
http_connection* connection = (http_connection*)parser->data;
http_request* request = connection->request;
hw_string* url = request->url;
int http_request_on_url(http_parser *parser, const char *at, size_t length) {
http_connection *connection = (http_connection *)parser->data;
http_request *request = connection->request;
hw_string *url = request->url;
if (url->length) {
/* This is not the first URL chunk that has been seen in the buffer. Since we've already captured the initial pointer in the branch below,
so we can recover the URL later on, we only increment the URL length and ignore the pointer passed in as a parameter. */
url->length += length;
} else {
url->value = at;
url->value = at;
url->length = length;
/* We've seen the URL start, so we need to pin it to recover it later */
http_request_buffer_pin(connection->buffer, url, url->value);
@ -176,9 +159,9 @@ int http_request_on_url(http_parser *parser, const char *at, size_t length)
return 0;
}
void http_request_save_current_header(http_connection* connection) {
hw_string* header_key_copy = hw_strdup(&connection->current_header_key);
hw_string* header_value_copy = hw_strdup(&connection->current_header_value);
void http_request_save_current_header(http_connection *connection) {
hw_string *header_key_copy = hw_strdup(&connection->current_header_key);
hw_string *header_value_copy = hw_strdup(&connection->current_header_value);
/* We duplicate the current header key/value, so we actually need to use the new pointers as pin ids, as
* those will be the IDs we'll use later on to locate the headers */
@ -187,25 +170,23 @@ void http_request_save_current_header(http_connection* connection) {
/* Set headers is going to need to have the values of header key/value, so we need to make sure we get
* the pointers pointing at the right place in the buffer */
header_key_copy->value = http_request_buffer_locate(connection->buffer, header_key_copy,
connection->current_header_key.value);
header_key_copy->value = http_request_buffer_locate(
connection->buffer, header_key_copy, connection->current_header_key.value);
header_value_copy->value = http_request_buffer_locate(connection->buffer, header_value_copy,
connection->current_header_value.value);
header_value_copy->value = http_request_buffer_locate(
connection->buffer, header_value_copy, connection->current_header_value.value);
/* Save last header key/value pair that was read */
set_header(connection->request, header_key_copy, header_value_copy);
}
int http_request_on_header_field(http_parser *parser, const char *at, size_t length)
{
http_connection* connection = (http_connection*)parser->data;
int http_request_on_header_field(http_parser *parser, const char *at, size_t length) {
http_connection *connection = (http_connection *)parser->data;
if (connection->last_was_value && connection->current_header_key.length > 0) {
http_request_save_current_header(connection);
connection->current_header_key.length = 0;
connection->current_header_key.length = 0;
connection->current_header_value.length = 0;
}
@ -215,7 +196,7 @@ int http_request_on_header_field(http_parser *parser, const char *at, size_t len
connection->current_header_key.length += length;
} else {
/* Start of a new header key */
connection->current_header_key.value = at;
connection->current_header_key.value = at;
connection->current_header_key.length = length;
/* Pin the header key */
http_request_buffer_pin(connection->buffer, &connection->current_header_key, at);
@ -225,14 +206,13 @@ int http_request_on_header_field(http_parser *parser, const char *at, size_t len
return 0;
}
int http_request_on_header_value(http_parser *parser, const char *at, size_t length)
{
http_connection* connection = (http_connection*)parser->data;
int http_request_on_header_value(http_parser *parser, const char *at, size_t length) {
http_connection *connection = (http_connection *)parser->data;
if (!connection->last_was_value) {
connection->current_header_value.value = at;
connection->current_header_value.value = at;
connection->current_header_value.length = length;
connection->last_was_value = 1;
connection->last_was_value = 1;
/* Pin the header value */
http_request_buffer_pin(connection->buffer, &connection->current_header_value, at);
} else {
@ -244,33 +224,30 @@ int http_request_on_header_value(http_parser *parser, const char *at, size_t len
return 0;
}
int http_request_on_headers_complete(http_parser* parser)
{
http_connection* connection = (http_connection*)parser->data;
int http_request_on_headers_complete(http_parser *parser) {
http_connection *connection = (http_connection *)parser->data;
if (connection->current_header_key.length > 0 && connection->current_header_value.length > 0) {
http_request_save_current_header(connection);
}
connection->current_header_key.length = 0;
connection->current_header_key.length = 0;
connection->current_header_value.length = 0;
connection->request->http_major = parser->http_major;
connection->request->http_minor = parser->http_minor;
connection->request->method = parser->method;
connection->keep_alive = http_should_keep_alive(parser);
connection->request->method = parser->method;
connection->keep_alive = http_should_keep_alive(parser);
connection->request->keep_alive = connection->keep_alive;
return 0;
}
int http_request_on_body(http_parser *parser, const char *at, size_t length)
{
http_connection* connection = (http_connection*)parser->data;
http_request* request = connection->request;
hw_string* body = request->body;
if (length != 0)
{
int http_request_on_body(http_parser *parser, const char *at, size_t length) {
http_connection *connection = (http_connection *)parser->data;
http_request *request = connection->request;
hw_string *body = request->body;
if (length != 0) {
if (body->length == 0) {
body->value = at;
body->value = at;
body->length = length;
/* Let's pin the body so we can recover it later, even if the underlying buffers change */
http_request_buffer_pin(connection->buffer, body, body->value);
@ -284,30 +261,26 @@ int http_request_on_body(http_parser *parser, const char *at, size_t length)
return 0;
}
hw_route_entry* get_route_callback(hw_string* url)
{
hw_route_entry* route_entry = NULL;
hw_route_entry *get_route_callback(hw_string *url) {
hw_route_entry *route_entry = NULL;
const char* k;
const char* v;
const char *k;
const char *v;
khash_t(string_hashmap) *h = routes;
kh_foreach(h, k, v,
{
kh_foreach(h, k, v, {
int found = hw_route_compare_method(url, k);
if (found)
{
route_entry = (hw_route_entry*)v;
if (found) {
route_entry = (hw_route_entry *)v;
}
});
return route_entry;
}
void send_error_response(http_request* request, http_response* response, const char* error_code,
const char* error_message)
{
void send_error_response(http_request *request, http_response *response, const char *error_code,
const char *error_message) {
hw_string status_code;
hw_string content_type_name;
hw_string content_type_value;
@ -315,7 +288,7 @@ void send_error_response(http_request* request, http_response* response, const c
hw_string keep_alive_name;
hw_string keep_alive_value;
status_code.value = error_code;
status_code.value = error_code;
status_code.length = strlen(error_code);
hw_set_response_status_code(response, &status_code);
@ -324,19 +297,16 @@ void send_error_response(http_request* request, http_response* response, const c
SETSTRING(content_type_value, "text/html");
hw_set_response_header(response, &content_type_name, &content_type_value);
body.value = error_message;
body.value = error_message;
body.length = strlen(error_message);
hw_set_body(response, &body);
if (request->keep_alive)
{
if (request->keep_alive) {
SETSTRING(keep_alive_name, "Connection");
SETSTRING(keep_alive_value, "Keep-Alive");
hw_set_response_header(response, &keep_alive_name, &keep_alive_value);
}
else
{
} else {
hw_set_http_version(response, 1, 0);
}
@ -348,30 +318,28 @@ void send_error_response(http_request* request, http_response* response, const c
* This is because the underlying buffers might have been reallocated/resized,
* so we can't use the pointers of where data chunks (e.g. URL start) were originally seen.
*/
void http_request_locate_members(http_connection* connection)
{
hw_request_buffer* buffer = connection->buffer;
http_request* request = connection->request;
request->url->value = http_request_buffer_locate(buffer, request->url, request->url->value);
request->body->value = http_request_buffer_locate(buffer, request->body, request->body->value);
void http_request_locate_members(http_connection *connection) {
hw_request_buffer *buffer = connection->buffer;
http_request *request = connection->request;
request->url->value = http_request_buffer_locate(buffer, request->url, request->url->value);
request->body->value = http_request_buffer_locate(buffer, request->body, request->body->value);
hw_string* header_name;
hw_string* header_value;
hw_string *header_name;
hw_string *header_value;
khash_t(hw_string_hashmap) *h = request->headers;
kh_foreach(h, header_name, header_value, {
header_name->value = http_request_buffer_locate(buffer, header_name, header_name->value);
header_name->value = http_request_buffer_locate(buffer, header_name, header_name->value);
header_value->value = http_request_buffer_locate(buffer, header_value, header_value->value);
});
}
int http_request_on_message_complete(http_parser* parser)
{
http_connection* connection = (http_connection*)parser->data;
http_request* request = connection->request;
hw_http_response* response = hw_create_http_response(connection);
int http_request_on_message_complete(http_parser *parser) {
http_connection *connection = (http_connection *)parser->data;
http_request *request = connection->request;
hw_http_response *response = hw_create_http_response(connection);
char* error = NULL;
char *error = NULL;
if (connection->request->state == SIZE_EXCEEDED) {
// 413 Request entity too large
@ -384,14 +352,11 @@ int http_request_on_message_complete(http_parser* parser)
} else {
http_request_locate_members(connection);
hw_route_entry* route_entry = request != NULL ? get_route_callback(request->url) : NULL;
hw_route_entry *route_entry = request != NULL ? get_route_callback(request->url) : NULL;
if (route_entry != NULL)
{
if (route_entry != NULL) {
route_entry->callback(request, response, route_entry->user_data);
}
else
{
} else {
// 404 Not Found.
error = HTTP_STATUS_404;
}
@ -408,7 +373,7 @@ int http_request_on_message_complete(http_parser* parser)
}
if (error) {
send_error_response(request, (http_response*)response, error, error);
send_error_response(request, (http_response *)response, error, error);
}
return 0;

View File

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

View File

@ -7,7 +7,7 @@
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
KHASH_MAP_INIT_INT64(pointer_hashmap, void*)
KHASH_MAP_INIT_INT64(pointer_hashmap, void *)
typedef struct {
size_t max_size;
@ -15,30 +15,30 @@ typedef struct {
size_t mark;
size_t used;
size_t used_before;
void* current;
khash_t(pointer_hashmap)* offsets;
void *current;
khash_t(pointer_hashmap) * offsets;
bool offsets_active;
} http_request_buffer;
void http_request_buffer_consume(hw_request_buffer* buf, size_t consumed) {
http_request_buffer* buffer = (http_request_buffer*) buf;
buffer->used_before = buffer->used;
void http_request_buffer_consume(hw_request_buffer *buf, size_t consumed) {
http_request_buffer *buffer = (http_request_buffer *)buf;
buffer->used_before = buffer->used;
buffer->used += consumed;
}
void http_request_buffer_mark(hw_request_buffer* buf) {
http_request_buffer* buffer = (http_request_buffer*) buf;
void http_request_buffer_mark(hw_request_buffer *buf) {
http_request_buffer *buffer = (http_request_buffer *)buf;
/* unfortunately, the parser doesn't tell us where the request ends exactly,
* so the only thing we can be sure is that it ends in the current buffer chunk, so anything before it can
* effectively be swept, so we're placing the mark at that point now. */
buffer->mark = buffer->used_before;
}
void http_request_buffer_sweep(hw_request_buffer* buf) {
http_request_buffer* buffer = (http_request_buffer*) buf;
void* pointer;
int offset;
int used = buffer->used - buffer->mark;
void http_request_buffer_sweep(hw_request_buffer *buf) {
http_request_buffer *buffer = (http_request_buffer *)buf;
void *pointer;
int offset;
int used = buffer->used - buffer->mark;
if (buffer->mark > 0) {
bool offsets_active = false;
@ -53,10 +53,10 @@ void http_request_buffer_sweep(hw_request_buffer* buf) {
if (buffer->size > DEFAULT_BUFFER_SHRINKSIZE && buffer->used < DEFAULT_BUFFER_SHRINKSIZE) {
/* Shrink buffer */
buffer->size = DEFAULT_BUFFER_SHRINKSIZE;
buffer->size = DEFAULT_BUFFER_SHRINKSIZE;
buffer->current = realloc(buffer->current, buffer->size);
if (!buffer->current) {
errno = ENOMEM;
errno = ENOMEM;
buffer->size = 0;
}
}
@ -72,7 +72,7 @@ void http_request_buffer_sweep(hw_request_buffer* buf) {
} else {
/* There's at least one offset beyond the mark, so the offsets are active and should be considered
* when locating pointers. We need to shift the offset back by the width of the mark */
offsets_active = true;
offsets_active = true;
kh_value(buffer->offsets, offset_key) = offset - buffer->mark;
}
});
@ -81,35 +81,35 @@ void http_request_buffer_sweep(hw_request_buffer* buf) {
kh_clear(pointer_hashmap, buffer->offsets);
}
buffer->mark = 0;
buffer->used = used;
buffer->mark = 0;
buffer->used = used;
buffer->offsets_active = offsets_active;
}
}
hw_request_buffer* http_request_buffer_init(size_t max_size) {
http_request_buffer* buffer = malloc(sizeof(http_request_buffer));
buffer->max_size = max_size;
buffer->size = 0;
buffer->used = 0;
buffer->mark = 0;
buffer->used_before = 0;
buffer->current = NULL;
buffer->offsets = kh_init(pointer_hashmap);
buffer->offsets_active = false;
hw_request_buffer *http_request_buffer_init(size_t max_size) {
http_request_buffer *buffer = malloc(sizeof(http_request_buffer));
buffer->max_size = max_size;
buffer->size = 0;
buffer->used = 0;
buffer->mark = 0;
buffer->used_before = 0;
buffer->current = NULL;
buffer->offsets = kh_init(pointer_hashmap);
buffer->offsets_active = false;
return buffer;
}
void http_request_buffer_chunk(hw_request_buffer* buf, hw_request_buffer_chunk* chunk) {
http_request_buffer *buffer = (http_request_buffer *) buf;
chunk->size = buffer->size ? buffer->size - buffer->used : 0;
chunk->buffer = buffer->current + buffer->used;
void http_request_buffer_chunk(hw_request_buffer *buf, hw_request_buffer_chunk *chunk) {
http_request_buffer *buffer = (http_request_buffer *)buf;
chunk->size = buffer->size ? buffer->size - buffer->used : 0;
chunk->buffer = buffer->current + buffer->used;
}
bool http_request_buffer_alloc(hw_request_buffer* buf, size_t requested_size) {
http_request_buffer* buffer = (http_request_buffer*) buf;
bool ret = true;
void* previous = NULL;
bool http_request_buffer_alloc(hw_request_buffer *buf, size_t requested_size) {
http_request_buffer *buffer = (http_request_buffer *)buf;
bool ret = true;
void *previous = NULL;
size_t requested_size_capped = MIN(buffer->max_size, requested_size);
@ -117,8 +117,8 @@ bool http_request_buffer_alloc(hw_request_buffer* buf, size_t requested_size) {
buffer->current = malloc(requested_size_capped);
if (!buffer->current) {
buffer->size = 0;
errno = ENOMEM;
ret = false;
errno = ENOMEM;
ret = false;
} else {
buffer->size = requested_size_capped;
}
@ -133,33 +133,33 @@ bool http_request_buffer_alloc(hw_request_buffer* buf, size_t requested_size) {
if (!buffer->current) {
buffer->size = 0;
errno = ENOMEM;
ret = false;
errno = ENOMEM;
ret = false;
} else if (buffer->current != previous) {
buffer->offsets_active = true;
}
} else {
/* maximum request size exceeded */
errno = ERANGE;
errno = ERANGE;
buffer->size = 0;
ret = false;
ret = false;
}
return ret;
}
void http_request_buffer_print(hw_request_buffer* buf) {
http_request_buffer* buffer = (http_request_buffer*) buf;
void http_request_buffer_print(hw_request_buffer *buf) {
http_request_buffer *buffer = (http_request_buffer *)buf;
printf("Buffer: current=%u; size=%u; used=%u\n", buffer->current, buffer->size, buffer->used);
printf(" 0\t");
for (int i = 0; i < buffer->used; i++) {
if (((char*) buffer->current)[i] == '\n') {
if (((char *)buffer->current)[i] == '\n') {
printf("\\n");
} else if (((char*) buffer->current)[i] == '\r') {
} else if (((char *)buffer->current)[i] == '\r') {
printf("\\r");
} else {
printf("%c", ((char*) buffer->current)[i]);
printf("%c", ((char *)buffer->current)[i]);
}
if ((i + 1) % 10 == 0) {
@ -170,16 +170,14 @@ void http_request_buffer_print(hw_request_buffer* buf) {
}
printf("\n");
void* pointer;
int offset;
kh_foreach(buffer->offsets, pointer, offset, {
printf("\tPointer %u -> offset=%u\n", pointer, offset);
});
void *pointer;
int offset;
kh_foreach(buffer->offsets, pointer, offset, { printf("\tPointer %u -> offset=%u\n", pointer, offset); });
printf("----\n");
}
void http_request_buffer_pin(hw_request_buffer* buf, void* key, void* pointer) {
http_request_buffer* buffer = (http_request_buffer*) buf;
void http_request_buffer_pin(hw_request_buffer *buf, void *key, void *pointer) {
http_request_buffer *buffer = (http_request_buffer *)buf;
khiter_t offset_key = kh_get(pointer_hashmap, buffer->offsets, key);
@ -194,8 +192,8 @@ void http_request_buffer_pin(hw_request_buffer* buf, void* key, void* pointer) {
kh_value(buffer->offsets, offset_key) = offset;
}
void http_request_buffer_reassign_pin(hw_request_buffer* buf, void* old_key, void* new_key) {
http_request_buffer* buffer = (http_request_buffer*) buf;
void http_request_buffer_reassign_pin(hw_request_buffer *buf, void *old_key, void *new_key) {
http_request_buffer *buffer = (http_request_buffer *)buf;
khiter_t old_offset_key = kh_get(pointer_hashmap, buffer->offsets, old_key);
@ -206,24 +204,24 @@ void http_request_buffer_reassign_pin(hw_request_buffer* buf, void* old_key, voi
if (!is_missing) {
offset = kh_val(buffer->offsets, old_offset_key);
khiter_t new_offset_key = kh_put(pointer_hashmap, buffer->offsets, new_key, &ret);
khiter_t new_offset_key = kh_put(pointer_hashmap, buffer->offsets, new_key, &ret);
kh_value(buffer->offsets, new_offset_key) = offset;
old_offset_key = kh_get(pointer_hashmap, buffer->offsets, old_key);
old_offset_key = kh_get(pointer_hashmap, buffer->offsets, old_key);
kh_del(pointer_hashmap, buffer->offsets, old_offset_key);
}
}
void* http_request_buffer_locate(hw_request_buffer* buf, void* key, void* default_pointer) {
http_request_buffer* buffer = (http_request_buffer*) buf;
void* location = default_pointer;
khiter_t offset_key = kh_get(pointer_hashmap, buffer->offsets, key);
void *http_request_buffer_locate(hw_request_buffer *buf, void *key, void *default_pointer) {
http_request_buffer *buffer = (http_request_buffer *)buf;
void *location = default_pointer;
khiter_t offset_key = kh_get(pointer_hashmap, buffer->offsets, key);
int offset, is_missing;
if (buffer->offsets_active) {
is_missing = (offset_key == kh_end(buffer->offsets));
if (!is_missing) {
offset = kh_value(buffer->offsets, offset_key);
offset = kh_value(buffer->offsets, offset_key);
location = buffer->current + offset;
}
}
@ -231,8 +229,8 @@ void* http_request_buffer_locate(hw_request_buffer* buf, void* key, void* defaul
return location;
}
void http_request_buffer_destroy(hw_request_buffer* buf) {
http_request_buffer* buffer = (http_request_buffer*) buf;
void http_request_buffer_destroy(hw_request_buffer *buf) {
http_request_buffer *buffer = (http_request_buffer *)buf;
kh_destroy(pointer_hashmap, buffer->offsets);
free(buffer->current);
free(buffer);

View File

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

View File

@ -8,59 +8,54 @@
#include "hw_string.h"
#define CRLF "\r\n"
KHASH_MAP_INIT_STR(string_hashmap, char*)
KHASH_MAP_INIT_STR(string_hashmap, char *)
hw_http_response hw_create_http_response(http_connection* connection)
{
http_response* response = malloc(sizeof(http_response));
response->connection = connection;
response->request = connection->request;
response->http_major = 1;
response->http_minor = 1;
response->body.value = NULL;
response->body.length = 0;
hw_http_response hw_create_http_response(http_connection *connection) {
http_response *response = malloc(sizeof(http_response));
response->connection = connection;
response->request = connection->request;
response->http_major = 1;
response->http_minor = 1;
response->body.value = NULL;
response->body.length = 0;
response->number_of_headers = 0;
return response;
}
void hw_free_http_response(hw_http_response* response)
{
http_response* resp = (http_response*)response;
void hw_free_http_response(hw_http_response *response) {
http_response *resp = (http_response *)response;
free(resp);
}
void hw_set_http_version(hw_http_response* response, unsigned short major, unsigned short minor)
{
http_response* resp = (http_response*)response;
resp->http_major = major;
resp->http_minor = minor;
void hw_set_http_version(hw_http_response *response, unsigned short major, unsigned short minor) {
http_response *resp = (http_response *)response;
resp->http_major = major;
resp->http_minor = minor;
}
void hw_set_response_status_code(hw_http_response* response, hw_string* status_code)
{
http_response* resp = (http_response*)response;
resp->status_code = *status_code;
void hw_set_response_status_code(hw_http_response *response, hw_string *status_code) {
http_response *resp = (http_response *)response;
resp->status_code = *status_code;
}
void hw_set_response_header(hw_http_response* response, hw_string* name, hw_string* value)
{
http_response* resp = (http_response*)response;
http_header* header = &resp->headers[resp->number_of_headers];
header->name = *name;
header->value = *value;
void hw_set_response_header(hw_http_response *response, hw_string *name, hw_string *value) {
http_response *resp = (http_response *)response;
http_header *header = &resp->headers[resp->number_of_headers];
header->name = *name;
header->value = *value;
resp->headers[resp->number_of_headers] = *header;
resp->number_of_headers++;
}
void hw_set_body(hw_http_response* response, hw_string* body)
{
http_response* resp = (http_response*)response;
resp->body = *body;
void hw_set_body(hw_http_response *response, hw_string *body) {
http_response *resp = (http_response *)response;
resp->body = *body;
}
int num_chars(int n) {
int r = 1;
if (n < 0) n = (n == INT_MIN) ? INT_MAX : -n;
if (n < 0)
n = (n == INT_MIN) ? INT_MAX : -n;
while (n > 9) {
n /= 10;
r++;
@ -68,35 +63,34 @@ int num_chars(int n) {
return r;
}
hw_string* create_response_buffer(hw_http_response* response)
{
http_response* resp = (http_response*)response;
hw_string* response_string = malloc(sizeof(hw_string));
hw_string* cached_entry = get_cached_request(resp->status_code.value);
hw_string content_length;
hw_string *create_response_buffer(hw_http_response *response) {
http_response *resp = (http_response *)response;
hw_string *response_string = malloc(sizeof(hw_string));
hw_string *cached_entry = get_cached_request(resp->status_code.value);
hw_string content_length;
int i = 0;
char length_header[] = "Content-Length: ";
int line_sep_size = sizeof(CRLF);
int line_sep_size = sizeof(CRLF);
int header_buffer_incr = 512;
int body_size = resp->body.length;
int header_buffer_incr = 512;
int body_size = resp->body.length;
int header_size_remaining = header_buffer_incr;
int response_size = header_size_remaining + sizeof(length_header) + num_chars(resp->body.length) + 2 * line_sep_size + body_size + line_sep_size;
int response_size = header_size_remaining + sizeof(length_header) + num_chars(resp->body.length) + 2 * line_sep_size
+ body_size + line_sep_size;
response_string->value = malloc(response_size);
response_string->length = 0;
append_string(response_string, cached_entry);
for (i=0; i< resp->number_of_headers; i++)
{
for (i = 0; i < resp->number_of_headers; i++) {
http_header header = resp->headers[i];
header_size_remaining -= header.name.length + 2 + header.value.length + line_sep_size;
if (header_size_remaining < 0) {
header_size_remaining += header_buffer_incr * ((-header_size_remaining/header_buffer_incr) + 1);
header_size_remaining += header_buffer_incr * ((-header_size_remaining / header_buffer_incr) + 1);
response_size += header_size_remaining;
response_string->value = realloc(response_string->value, response_size);
}
@ -114,35 +108,31 @@ hw_string* create_response_buffer(hw_http_response* response)
if (body_size > 0) {
append_string(response_string, &content_length);
}
else {
} else {
hw_string zero_content;
zero_content.value = "0";
zero_content.value = "0";
zero_content.length = 1;
append_string(response_string, &zero_content);
}
APPENDSTRING(response_string, CRLF CRLF);
if (body_size > 0)
{
if (body_size > 0) {
append_string(response_string, &resp->body);
}
return response_string;
}
void hw_http_response_send(hw_http_response* response, void* user_data, http_response_complete_callback callback)
{
hw_write_context* write_context = malloc(sizeof(hw_write_context));
http_response* resp = (http_response*)response;
hw_string* response_buffer = create_response_buffer(response);
void hw_http_response_send(hw_http_response *response, void *user_data, http_response_complete_callback callback) {
hw_write_context *write_context = malloc(sizeof(hw_write_context));
http_response *resp = (http_response *)response;
hw_string *response_buffer = create_response_buffer(response);
write_context->connection = resp->connection;
write_context->user_data = user_data;
write_context->callback = callback;
write_context->request = resp->request;
write_context->user_data = user_data;
write_context->callback = callback;
write_context->request = resp->request;
http_server_write_response(write_context, response_buffer);
resp->sent = 1;
@ -150,3 +140,28 @@ void hw_http_response_send(hw_http_response* response, void* user_data, http_res
free(response_buffer);
hw_free_http_response(response);
}
void hw_http_response_send_error(hw_http_response *response, const char *error, const char *err_msg) {
hw_string status_code;
hw_string content_type_name;
hw_string content_type_value;
hw_string body;
hw_string keep_alive_name;
hw_string keep_alive_value;
SETSTRING(content_type_name, "Content-Type");
SETSTRING(content_type_value, "text/html");
hw_set_response_header(response, &content_type_name, &content_type_value);
SETSTRING(status_code, error);
SETSTRING(body, err_msg);
hw_set_body(response, &body);
hw_set_response_status_code(response, &status_code);
SETSTRING(keep_alive_name, "Connection");
SETSTRING(keep_alive_value, "close");
hw_set_response_header(response, &keep_alive_name, &keep_alive_value);
hw_http_response_send(response, NULL, NULL);
}

View File

@ -2,33 +2,30 @@
#include "haywire.h"
#include "http_connection.h"
typedef struct
{
typedef struct {
hw_string name;
hw_string value;
} http_header;
#define MAX_HEADERS 64
typedef struct
{
http_connection* connection;
http_request* request;
unsigned short http_major;
unsigned short http_minor;
hw_string status_code;
http_header headers[MAX_HEADERS];
int number_of_headers;
hw_string body;
int sent;
typedef struct {
http_connection *connection;
http_request *request;
unsigned short http_major;
unsigned short http_minor;
hw_string status_code;
http_header headers[MAX_HEADERS];
int number_of_headers;
hw_string body;
int sent;
} http_response;
typedef struct
{
http_connection* connection;
http_request* request;
void* user_data;
typedef struct {
http_connection *connection;
http_request *request;
void *user_data;
http_response_complete_callback callback;
} hw_write_context;
hw_http_response hw_create_http_response(http_connection* connection);
hw_string* create_response_buffer(hw_http_response* response);
hw_http_response hw_create_http_response(http_connection *connection);
hw_string *create_response_buffer(hw_http_response *response);

View File

@ -11,68 +11,60 @@
#include "http_server.h"
#define CRLF "\r\n"
KHASH_MAP_INIT_STR(string_hashmap, hw_string*)
KHASH_MAP_INIT_STR(string_hashmap, hw_string *)
static uv_timer_t cache_invalidation_timer;
static uv_key_t thread_cache_key;
static uv_key_t thread_cache_key;
void initialize_http_request_cache();
void free_http_request_cache();
void http_request_cache_timer(uv_timer_t* handle);
void create_cached_http_request(khash_t(string_hashmap)* http_request_cache, const char* http_status);
void set_cached_request(khash_t(string_hashmap)* http_request_cache, char* http_status, hw_string* cache_entry);
hw_string* get_cached_request(const char* http_status);
void initialize_http_request_cache();
void free_http_request_cache();
void http_request_cache_timer(uv_timer_t *handle);
void create_cached_http_request(khash_t(string_hashmap) * http_request_cache, const char *http_status);
void set_cached_request(khash_t(string_hashmap) * http_request_cache, char *http_status, hw_string *cache_entry);
hw_string *get_cached_request(const char *http_status);
void initialize_http_request_cache()
{
void initialize_http_request_cache() {
uv_key_create(&thread_cache_key);
}
void http_request_cache_configure_listener(uv_loop_t* loop, uv_async_t* handle)
{
uv_timer_t* cache_invalidation_timer = malloc(sizeof(uv_timer_t));
void http_request_cache_configure_listener(uv_loop_t *loop, uv_async_t *handle) {
uv_timer_t *cache_invalidation_timer = malloc(sizeof(uv_timer_t));
uv_timer_init(loop, cache_invalidation_timer);
uv_timer_start(cache_invalidation_timer, http_request_cache_timer, 500, 500);
if (handle != NULL)
{
uv_unref((uv_handle_t*) cache_invalidation_timer);
if (handle != NULL) {
uv_unref((uv_handle_t *)cache_invalidation_timer);
}
}
void http_request_cache_timer(uv_timer_t* timer)
{
khash_t(string_hashmap)* http_request_cache = uv_key_get(&thread_cache_key);
if (http_request_cache != NULL)
{
void http_request_cache_timer(uv_timer_t *timer) {
khash_t(string_hashmap) *http_request_cache = uv_key_get(&thread_cache_key);
if (http_request_cache != NULL) {
free_http_request_cache(http_request_cache);
}
}
void free_http_request_cache(khash_t(string_hashmap)* http_request_cache)
{
const char* k;
hw_string* v;
void free_http_request_cache(khash_t(string_hashmap) * http_request_cache) {
const char *k;
hw_string *v;
kh_foreach(http_request_cache, k, v,
{
free((char*)k);
free(v->value);
free(v);
});
kh_foreach(http_request_cache, k, v, {
free((char *)k);
free(v->value);
free(v);
});
kh_destroy_string_hashmap(http_request_cache);
uv_key_set(&thread_cache_key, NULL);
}
void create_cached_http_request(khash_t(string_hashmap)* http_request_cache, const char* http_status)
{
hw_string* cache_entry = malloc(sizeof(hw_string));
cache_entry->value = calloc(1024, 1);
cache_entry->length = 0;
void create_cached_http_request(khash_t(string_hashmap) * http_request_cache, const char *http_status) {
hw_string *cache_entry = malloc(sizeof(hw_string));
cache_entry->value = calloc(1024, 1);
cache_entry->length = 0;
hw_string status;
status.length = strlen(http_status);
status.value = http_status;
status.value = http_status;
append_string(cache_entry, http_v1_1);
append_string(cache_entry, &status);
@ -83,9 +75,9 @@ void create_cached_http_request(khash_t(string_hashmap)* http_request_cache, con
// Add the current time.
time_t curtime;
time(&curtime);
char* current_time = ctime(&curtime);
char *current_time = ctime(&curtime);
hw_string current_datetime;
current_datetime.value = current_time;
current_datetime.value = current_time;
current_datetime.length = strlen(current_time);
APPENDSTRING(cache_entry, "Date: ");
append_string(cache_entry, &current_datetime);
@ -93,60 +85,48 @@ void create_cached_http_request(khash_t(string_hashmap)* http_request_cache, con
set_cached_request(http_request_cache, http_status, cache_entry);
}
void set_cached_request(khash_t(string_hashmap)* http_request_cache, char* http_status, hw_string* cache_entry)
{
int ret;
void set_cached_request(khash_t(string_hashmap) * http_request_cache, char *http_status, hw_string *cache_entry) {
int ret;
khiter_t key;
key = kh_get(string_hashmap, http_request_cache, http_status);
if (key == kh_end(http_request_cache))
{
key = kh_put(string_hashmap, http_request_cache, dupstr(http_status), &ret);
if (key == kh_end(http_request_cache)) {
key = kh_put(string_hashmap, http_request_cache, dupstr(http_status), &ret);
kh_value(http_request_cache, key) = cache_entry;
}
}
hw_string* get_cached_request(const char* http_status)
{
int is_missing = 0;
void* val;
khash_t(string_hashmap)* http_request_cache;
hw_string *get_cached_request(const char *http_status) {
int is_missing = 0;
void *val;
khash_t(string_hashmap) * http_request_cache;
khiter_t key = 0;
/* This thread hasn't created a response cache so create one */
http_request_cache = uv_key_get(&thread_cache_key);
if (http_request_cache == NULL)
{
if (http_request_cache == NULL) {
http_request_cache = kh_init(string_hashmap);
uv_key_set(&thread_cache_key, http_request_cache);
}
key = kh_get(string_hashmap, http_request_cache, http_status);
if (key == kh_end(http_request_cache))
{
if (key == kh_end(http_request_cache)) {
create_cached_http_request(http_request_cache, http_status);
}
else
{
} else {
val = kh_value(http_request_cache, key);
}
key = kh_get(string_hashmap, http_request_cache, http_status);
if (key == kh_end(http_request_cache))
{
if (key == kh_end(http_request_cache)) {
is_missing = 1;
}
else
{
val = kh_value(http_request_cache, key);
} else {
val = kh_value(http_request_cache, key);
is_missing = 0;
}
if (is_missing)
{
if (is_missing) {
return NULL;
}
return val;
}

View File

@ -2,6 +2,6 @@
#include "uv.h"
#include "haywire.h"
void initialize_http_request_cache();
hw_string* get_cached_request(const char* http_status);
void http_request_cache_configure_listener(uv_loop_t* loop, uv_async_t* handle);
void initialize_http_request_cache();
hw_string *get_cached_request(const char *http_status);
void http_request_cache_configure_listener(uv_loop_t *loop, uv_async_t *handle);

View File

@ -1,6 +1,6 @@
#ifdef PLATFORM_POSIX
#include <signal.h>
#endif // PLATFORM_POSIX
#endif// PLATFORM_POSIX
#include <stdio.h>
#include <stdlib.h>
@ -19,74 +19,72 @@
#include "configuration/configuration.h"
#include "http_connection.h"
#include "http_request.h"
#include "misc.h"
#define UVERR(err, msg) dzlog_error("%s: %s\n", msg, uv_strerror(err))
//fprintf(stderr, "%s: %s\n", msg, uv_strerror(err))
#define CHECK(r, msg) \
if (r) { \
uv_err_t err = uv_last_error(uv_loop); \
UVERR(err, msg); \
exit(1); \
}
//fprintf(stderr, "%s: %s\n", msg, uv_strerror(err))
#if 0
#define CHECK(r, msg) \
if (r) { \
uv_err_t err = uv_last_error(uv_loop); \
UVERR(err, msg); \
exit(1); \
}
#endif
KHASH_MAP_INIT_STR(string_hashmap, hw_route_entry*)
KHASH_MAP_INIT_STR(string_hashmap, hw_route_entry *)
configuration* config;
static uv_tcp_t server;
configuration *config;
static uv_tcp_t server;
static http_parser_settings parser_settings;
static struct sockaddr_in listen_address;
static struct sockaddr_in listen_address;
uv_loop_t* uv_loop;
void* routes;
hw_string* http_v1_0;
hw_string* http_v1_1;
hw_string* server_name;
int listener_count;
uv_async_t* listener_async_handles;
uv_loop_t* listener_event_loops;
uv_barrier_t* listeners_created_barrier;
uv_loop_t *uv_loop;
void *routes;
//hw_string* http_v1_0;
hw_string *http_v1_1;
hw_string *server_name;
int listener_count;
uv_async_t *listener_async_handles;
//uv_loop_t* listener_event_loops;
uv_barrier_t *listeners_created_barrier;
int hw_init_with_config(configuration* c)
{
int hw_init_with_config(configuration *c) {
#ifdef DEBUG
char route[] = "/stats";
hw_http_add_route(route, get_server_stats, NULL);
#endif /* DEBUG */
/* Copy the configuration */
config = malloc(sizeof(configuration));
config = malloc(sizeof(configuration));
config->http_listen_address = dupstr(c->http_listen_address);
config->http_listen_port = c->http_listen_port;
config->thread_count = c->thread_count;
config->tcp_nodelay = c->tcp_nodelay;
config->listen_backlog = c->listen_backlog? c->listen_backlog : SOMAXCONN;
config->parser = dupstr(c->parser);
config->balancer = dupstr(c->balancer);
config->max_request_size = c->max_request_size;
config->http_listen_port = c->http_listen_port;
config->thread_count = c->thread_count;
config->tcp_nodelay = c->tcp_nodelay;
config->listen_backlog = c->listen_backlog ? c->listen_backlog : SOMAXCONN;
config->parser = dupstr(c->parser);
config->balancer = dupstr(c->balancer);
config->max_request_size = c->max_request_size;
http_v1_0 = create_string("HTTP/1.0 ");
http_v1_1 = create_string("HTTP/1.1 ");
http_v1_0 = create_string("HTTP/1.0 ");
http_v1_1 = create_string("HTTP/1.1 ");
server_name = create_string("Server: Haywire/master");
if (strcmp(config->parser, "http_parser") == 0)
{
if (strcmp(config->parser, "http_parser") == 0) {
http_stream_on_read = &http_stream_on_read_http_parser;
}
http_server_write_response = &http_server_write_response_single;
return 0;
}
int hw_init_from_config(char* configuration_filename)
{
configuration* config = load_configuration(configuration_filename);
if (config == NULL)
{
int hw_init_from_config(char *configuration_filename) {
configuration *config = load_configuration(configuration_filename);
if (config == NULL) {
return 1;
}
return hw_init_with_config(config);
}
void print_configuration()
{
void print_configuration() {
#if 0
dzlog_debug("Address: %s\n\tPort: %d\n\tThreads: %d\n\tBalancer: %s\n\t"
"Parser: %s\n\tTCP No Delay: %s\n\tListen backlog: %d\n\tMaximum request size: %d\n",
@ -101,18 +99,15 @@ void print_configuration()
#endif
}
http_connection* create_http_connection()
{
http_connection* connection = calloc(1, sizeof(http_connection));
connection->buffer = http_request_buffer_init(config->max_request_size);
http_connection *create_http_connection() {
http_connection *connection = calloc(1, sizeof(http_connection));
connection->buffer = http_request_buffer_init(config->max_request_size);
INCREMENT_STAT(stat_connections_created_total);
return connection;
}
void free_http_connection(http_connection* connection)
{
if (connection->request)
{
void free_http_connection(http_connection *connection) {
if (connection->request) {
free_http_request(connection->request);
}
http_request_buffer_destroy(connection->buffer);
@ -120,60 +115,57 @@ void free_http_connection(http_connection* connection)
INCREMENT_STAT(stat_connections_destroyed_total);
}
void set_route(void* hashmap, char* name, hw_route_entry* route_entry)
{
int ret;
void set_route(void *hashmap, char *name, hw_route_entry *route_entry) {
int ret;
khiter_t k;
khash_t(string_hashmap) *h = hashmap;
k = kh_put(string_hashmap, h, dupstr(name), &ret);
kh_value(h, k) = route_entry;
k = kh_put(string_hashmap, h, dupstr(name), &ret);
kh_value(h, k) = route_entry;
}
void hw_http_add_route(char *route, http_request_callback callback, void* user_data)
{
hw_route_entry* route_entry = malloc(sizeof(hw_route_entry));
route_entry->callback = callback;
route_entry->user_data = user_data;
void hw_http_add_route(char *route, http_request_callback callback, void *user_data) {
hw_route_entry *route_entry = malloc(sizeof(hw_route_entry));
route_entry->callback = callback;
route_entry->user_data = user_data;
if (routes == NULL)
{
if (routes == NULL) {
routes = kh_init(string_hashmap);
}
set_route(routes, route, route_entry);
dzlog_debug("Added route %s\n", route); // TODO: Replace with logging instead.
dzlog_debug("Added route %s\n", route);// TODO: Replace with logging instead.
}
void free_http_server()
{
void free_http_server() {
/* TODO: Shut down accepting incoming requests */
khash_t(string_hashmap) *h = routes;
const char* k;
const char* v;
kh_foreach(h, k, v, { free((char*)k); free((char*)v); });
const char *k;
const char *v;
kh_foreach(h, k, v, {
free((char *)k);
free((char *)v);
});
kh_destroy(string_hashmap, routes);
}
int hw_http_open()
{
int threads = config->thread_count;
uv_async_t* service_handle = 0;
int hw_http_open() {
int threads = (int)config->thread_count;
uv_async_t *service_handle;
if (routes == NULL)
{
if (routes == NULL) {
routes = kh_init(string_hashmap);
}
parser_settings.on_header_field = http_request_on_header_field;
parser_settings.on_header_value = http_request_on_header_value;
parser_settings.on_header_field = http_request_on_header_field;
parser_settings.on_header_value = http_request_on_header_value;
parser_settings.on_headers_complete = http_request_on_headers_complete;
parser_settings.on_body = http_request_on_body;
parser_settings.on_message_begin = http_request_on_message_begin;
parser_settings.on_body = http_request_on_body;
parser_settings.on_message_begin = http_request_on_message_begin;
parser_settings.on_message_complete = http_request_on_message_complete;
parser_settings.on_url = http_request_on_url;
parser_settings.on_url = http_request_on_url;
#ifdef UNIX
signal(SIGPIPE, SIG_IGN);
#endif // UNIX
#endif// UNIX
listener_count = threads;
@ -181,7 +173,7 @@ int hw_http_open()
uv_loop = uv_default_loop();
listener_async_handles = calloc(listener_count, sizeof(uv_async_t));
listener_event_loops = calloc(listener_count, sizeof(uv_loop_t));
listener_event_loops = calloc(listener_count, sizeof(uv_loop_t));
listeners_created_barrier = malloc(sizeof(uv_barrier_t));
uv_barrier_init(listeners_created_barrier, listener_count + 1);
@ -189,30 +181,25 @@ int hw_http_open()
service_handle = malloc(sizeof(uv_async_t));
uv_async_init(uv_loop, service_handle, NULL);
if (listener_count == 0)
{
if (listener_count == 0) {
/* If running single threaded there is no need to use the IPC pipe
to distribute requests between threads so lets avoid the IPC overhead */
to distribute requests between threads so let's avoid the IPC overhead */
int rc;
rc = uv_tcp_init_ex(uv_loop, &server, AF_INET);
if (rc != 0)
{
if (rc != 0) {
dzlog_warn("TWO %d\n", rc);
}
if (strcmp(config->balancer, "reuseport") == 0)
{
if (strcmp(config->balancer, "reuseport") == 0) {
uv_os_fd_t fd;
int on = 1;
rc = uv_fileno(&server, &fd);
if (rc != 0)
{
int on = 1;
rc = uv_fileno(&server, &fd);
if (rc != 0) {
dzlog_warn("ONE %d\n", rc);
}
rc = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, (char*)&on, sizeof(on));
if (rc != 0)
{
rc = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, (char *)&on, sizeof(on));
if (rc != 0) {
dzlog_warn("THREE %d\n", errno);
}
}
@ -220,52 +207,52 @@ int hw_http_open()
initialize_http_request_cache();
http_request_cache_configure_listener(uv_loop, NULL);
uv_ip4_addr(config->http_listen_address, config->http_listen_port, &listen_address);
uv_tcp_bind(&server, (const struct sockaddr*)&listen_address, 0);
uv_ip4_addr(config->http_listen_address, (int)config->http_listen_port, &listen_address);
uv_tcp_bind(&server, (const struct sockaddr *)&listen_address, 0);
if (config->tcp_nodelay) {
uv_tcp_nodelay(&server, 1);
}
uv_listen((uv_stream_t*)&server, config->listen_backlog, http_stream_on_connect);
uv_listen((uv_stream_t *)&server, (int)config->listen_backlog, http_stream_on_connect);
print_configuration();
dzlog_debug("Listening...\n");
//uv_run(uv_loop, UV_RUN_DEFAULT);
}
else if (listener_count > 0 && strcmp(config->balancer, "ipc") == 0)
{
int i = 0;
} else if (listener_count > 0 && strcmp(config->balancer, "ipc") == 0) {
int i;
/* If we are running multi-threaded spin up the dispatcher that uses
/* If we are running multithreaded spin up the dispatcher that uses
an IPC pipe to send socket connection requests to listening threads */
struct server_ctx* servers;
struct server_ctx *servers;
servers = calloc(threads, sizeof(servers[0]));
for (i = 0; i < threads; i++)
{
int rc = 0;
struct server_ctx* ctx = servers + i;
ctx->index = i;
ctx->listen_backlog = config->listen_backlog;
for (i = 0; i < threads; i++) {
//int rc;
struct server_ctx *ctx = servers + i;
ctx->index = i;
ctx->listen_backlog = config->listen_backlog;
rc = uv_sem_init(&ctx->semaphore, 0);
rc = uv_thread_create(&ctx->thread_id, connection_consumer_start, ctx);
uv_sem_init(&ctx->semaphore, 0);
uv_thread_create(&ctx->thread_id, connection_consumer_start, ctx);
}
uv_barrier_wait(listeners_created_barrier);
initialize_http_request_cache();
start_connection_dispatching(UV_TCP, threads, servers, config->http_listen_address, config->http_listen_port, config->tcp_nodelay, config->listen_backlog);
}
else if (listener_count > 0 && strcmp(config->balancer, "reuseport") == 0)
{
struct server_ctx* servers;
start_connection_dispatching(UV_TCP,
threads,
servers,
config->http_listen_address,
(int)config->http_listen_port,
config->tcp_nodelay,
(int)config->listen_backlog);
} else if (listener_count > 0 && strcmp(config->balancer, "reuseport") == 0) {
struct server_ctx *servers;
servers = calloc(threads, sizeof(servers[0]));
for (int i = 0; i < threads; i++)
{
struct server_ctx* ctx = servers + i;
ctx->index = i;
int rc = uv_thread_create(&ctx->thread_id, reuseport_thread_start, ctx);
for (int i = 0; i < threads; i++) {
struct server_ctx *ctx = servers + i;
ctx->index = i;
uv_thread_create(&ctx->thread_id, reuseport_thread_start, ctx);
}
print_configuration();
@ -276,45 +263,41 @@ int hw_http_open()
return 0;
}
void reuseport_thread_start(void *arg)
{
int rc;
struct server_ctx* ctx;
uv_loop_t* loop;
uv_tcp_t svr;
void reuseport_thread_start(void *arg) {
int rc;
struct server_ctx *ctx;
uv_loop_t *loop;
ctx = arg;
loop = uv_loop_new();
ctx = arg;
loop = uv_loop_new();
listener_event_loops[ctx->index] = *loop;
initialize_http_request_cache();
http_request_cache_configure_listener(loop, &listener_async_handles[ctx->index]);
struct sockaddr_in addr;
uv_tcp_t server;
uv_tcp_t server;
rc = uv_tcp_init_ex(loop, &server, AF_INET);
uv_ip4_addr(config->http_listen_address, config->http_listen_port, &addr);
uv_tcp_init_ex(loop, &server, AF_INET);
uv_ip4_addr(config->http_listen_address, (int)config->http_listen_port, &addr);
uv_os_fd_t fd;
int on = 1;
int on = 1;
uv_fileno(&server, &fd);
rc = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, (char*)&on, sizeof(on));
if (rc != 0)
{
rc = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, (char *)&on, sizeof(on));
if (rc != 0) {
dzlog_warn("%d\n", errno);
}
uv_tcp_bind(&server, (const struct sockaddr*)&addr, 0);
int r = uv_listen((uv_stream_t*) &server, 128, http_stream_on_connect);
uv_tcp_bind(&server, (const struct sockaddr *)&addr, 0);
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);
}
void http_stream_on_connect(uv_stream_t* stream, int status)
{
http_connection* connection = create_http_connection();
void http_stream_on_connect(uv_stream_t *stream, int UNUSED(status)) {
http_connection *connection = create_http_connection();
uv_tcp_init(stream->loop, &connection->stream);
http_parser_init(&connection->parser, HTTP_REQUEST);
@ -322,18 +305,17 @@ void http_stream_on_connect(uv_stream_t* stream, int status)
connection->stream.data = connection;
/* TODO: Use the return values from uv_accept() and uv_read_start() */
uv_accept(stream, (uv_stream_t*)&connection->stream);
uv_accept(stream, (uv_stream_t *)&connection->stream);
connection->state = OPEN;
uv_read_start((uv_stream_t*)&connection->stream, http_stream_on_alloc, http_stream_on_read);
uv_read_start((uv_stream_t *)&connection->stream, http_stream_on_alloc, http_stream_on_read);
}
void http_stream_on_alloc(uv_handle_t* client, size_t suggested_size, uv_buf_t* buf)
{
http_connection* connection = (http_connection*)client->data;
void http_stream_on_alloc(uv_handle_t *client, size_t suggested_size, uv_buf_t *buf) {
http_connection *connection = (http_connection *)client->data;
bool success = http_request_buffer_alloc(connection->buffer, suggested_size);
bool success = http_request_buffer_alloc(connection->buffer, suggested_size);
hw_request_buffer_chunk chunk;
chunk.size = 0;
chunk.size = 0;
chunk.buffer = NULL;
if (success) {
@ -345,28 +327,26 @@ void http_stream_on_alloc(uv_handle_t* client, size_t suggested_size, uv_buf_t*
*buf = uv_buf_init(chunk.buffer, chunk.size);
}
void http_stream_on_close(uv_handle_t* handle)
{
uv_handle_t* stream = handle;
http_connection* connection = stream->data;
void http_stream_on_close(uv_handle_t *handle) {
uv_handle_t *stream = handle;
http_connection *connection = stream->data;
if (connection->state != CLOSED) {
connection->state = CLOSED;
http_connection* connection = (http_connection*)handle->data;
connection->state = CLOSED;
http_connection *connection = (http_connection *)handle->data;
free_http_connection(connection);
}
}
void http_stream_close_connection(http_connection* connection) {
void http_stream_close_connection(http_connection *connection) {
if (connection->state == OPEN) {
connection->state = CLOSING;
uv_close(&connection->stream, http_stream_on_close);
}
}
void handle_request_error(http_connection* connection)
{
uv_handle_t* stream = &connection->stream;
void handle_request_error(http_connection *connection) {
uv_handle_t *stream = &connection->stream;
if (connection->state == OPEN) {
uv_read_stop(stream);
@ -384,8 +364,7 @@ void handle_request_error(http_connection* connection)
}
}
void handle_bad_request(http_connection* connection)
{
void handle_bad_request(http_connection *connection) {
if (connection->request) {
connection->request->state = BAD_REQUEST;
}
@ -393,8 +372,7 @@ void handle_bad_request(http_connection* connection)
handle_request_error(connection);
}
void handle_buffer_exceeded_error(http_connection* connection)
{
void handle_buffer_exceeded_error(http_connection *connection) {
if (connection->request) {
connection->request->state = SIZE_EXCEEDED;
}
@ -402,8 +380,7 @@ void handle_buffer_exceeded_error(http_connection* connection)
handle_request_error(connection);
}
void handle_internal_error(http_connection* connection)
{
void handle_internal_error(http_connection *connection) {
if (connection->request) {
connection->request->state = INTERNAL_ERROR;
}
@ -411,25 +388,23 @@ void handle_internal_error(http_connection* connection)
handle_request_error(connection);
}
void http_stream_on_shutdown(uv_shutdown_t* req, int status)
{
http_connection* connection = req->data;
uv_handle_t* stream = &connection->stream;
void http_stream_on_shutdown(uv_shutdown_t *req, int UNUSED(status)) {
http_connection *connection = req->data;
// uv_handle_t *stream = &connection->stream;
if (connection->state == OPEN) {
http_stream_close_connection(connection);
}
free(req);
}
void http_stream_on_read_http_parser(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf)
{
http_connection* connection = (http_connection*)tcp->data;
void http_stream_on_read_http_parser(uv_stream_t *tcp, ssize_t nread, const uv_buf_t *buf) {
http_connection *connection = (http_connection *)tcp->data;
if (nread > 0) {
/* Need to tell the buffer that we care about the next nread bytes */
http_request_buffer_consume(connection->buffer, nread);
http_parser_execute(&connection->parser, &parser_settings, (const char*) buf->base, nread);
http_parser_execute(&connection->parser, &parser_settings, (const char *)buf->base, nread);
if (connection->parser.http_errno) {
handle_bad_request(connection);
@ -443,16 +418,13 @@ void http_stream_on_read_http_parser(uv_stream_t* tcp, ssize_t nread, const uv_b
}
} else if (nread == 0) {
/* no-op - there's no data to be read, but there might be later */
}
else if (nread == UV_ENOBUFS) {
} else if (nread == UV_ENOBUFS) {
handle_buffer_exceeded_error(connection);
}
else if (nread == UV_EOF){
uv_shutdown_t* req = malloc(sizeof(uv_shutdown_t));
req->data = connection;
} else if (nread == UV_EOF) {
uv_shutdown_t *req = malloc(sizeof(uv_shutdown_t));
req->data = connection;
uv_shutdown(req, &connection->stream, http_stream_on_shutdown);
}
else if (nread == UV_ECONNRESET || nread == UV_ECONNABORTED) {
} else if (nread == UV_ECONNRESET || nread == UV_ECONNABORTED) {
/* Let's close the connection as the other peer just disappeared */
http_stream_close_connection(connection);
} else {
@ -462,30 +434,28 @@ void http_stream_on_read_http_parser(uv_stream_t* tcp, ssize_t nread, const uv_b
}
}
void http_server_cleanup_write(char* response_string, hw_write_context* write_context, uv_write_t* write_req)
{
void http_server_cleanup_write(char *response_string, hw_write_context *write_context, uv_write_t *write_req) {
free(response_string);
free(write_context);
free(write_req);
}
int http_server_write_response_single(hw_write_context* write_context, hw_string* response)
{
http_connection* connection = write_context->connection;
int http_server_write_response_single(hw_write_context *write_context, hw_string *response) {
http_connection *connection = write_context->connection;
if (connection->state == OPEN) {
uv_write_t *write_req = (uv_write_t *) malloc(sizeof(*write_req) + sizeof(uv_buf_t));
uv_buf_t *resbuf = (uv_buf_t *) (write_req + 1);
uv_write_t *write_req = (uv_write_t *)malloc(sizeof(*write_req) + sizeof(uv_buf_t));
uv_buf_t *resbuf = (uv_buf_t *)(write_req + 1);
resbuf->base = response->value;
resbuf->len = response->length;
resbuf->len = response->length;
write_req->data = write_context;
uv_stream_t *stream = (uv_stream_t *) &write_context->connection->stream;
uv_stream_t *stream = (uv_stream_t *)&write_context->connection->stream;
if (uv_is_writable(stream)) {
/* Ensuring that the the response can still be written. */
/* Ensuring that the response can still be written. */
uv_write(write_req, stream, resbuf, 1, http_server_after_write);
/* TODO: Use the return values from uv_write() */
} else {
@ -497,23 +467,20 @@ int http_server_write_response_single(hw_write_context* write_context, hw_string
return 0;
}
void http_server_after_write(uv_write_t* req, int status)
{
hw_write_context* write_context = (hw_write_context*)req->data;
uv_buf_t *resbuf = (uv_buf_t *)(req+1);
uv_handle_t* stream = (uv_handle_t*) req->handle;
void http_server_after_write(uv_write_t *req, int UNUSED(status)) {
hw_write_context *write_context = (hw_write_context *)req->data;
uv_buf_t *resbuf = (uv_buf_t *)(req + 1);
//uv_handle_t *stream = (uv_handle_t *)req->handle;
http_connection* connection = write_context->connection;
http_connection *connection = write_context->connection;
if (!connection->keep_alive && connection->state == OPEN) {
http_stream_close_connection(connection);
}
if (write_context->callback)
{
if (write_context->callback) {
write_context->callback(write_context->user_data);
}
http_server_cleanup_write(resbuf->base, write_context, req);
}

View File

@ -5,36 +5,34 @@
#include "http_parser.h"
#include "http_response.h"
typedef struct
{
typedef struct {
http_request_callback callback;
void* user_data;
void *user_data;
} hw_route_entry;
union stream_handle
{
union stream_handle {
uv_pipe_t pipe;
uv_tcp_t tcp;
uv_tcp_t tcp;
};
extern void* routes;
extern uv_loop_t* uv_loop;
extern hw_string* http_v1_0;
extern hw_string* http_v1_1;
extern hw_string* server_name;
extern int listener_count;
extern uv_async_t* listener_async_handles;
extern uv_loop_t* listener_event_loops;
extern uv_barrier_t* listeners_created_barrier;
extern void *routes;
extern uv_loop_t *uv_loop;
extern hw_string *http_v1_0;
extern hw_string *http_v1_1;
extern hw_string *server_name;
extern int listener_count;
extern uv_async_t *listener_async_handles;
extern uv_loop_t *listener_event_loops;
extern uv_barrier_t *listeners_created_barrier;
void (*http_stream_on_read)(uv_stream_t*, ssize_t, const uv_buf_t*);
int (*http_server_write_response)(hw_write_context*, hw_string*);
void (*http_stream_on_read)(uv_stream_t *, ssize_t, const uv_buf_t *);
int (*http_server_write_response)(hw_write_context *, hw_string *);
http_connection* create_http_connection();
void http_stream_on_connect(uv_stream_t* stream, int status);
void http_stream_on_alloc(uv_handle_t* client, size_t suggested_size, uv_buf_t* buf);
void http_stream_on_close(uv_handle_t* handle);
int http_server_write_response_single(hw_write_context* write_context, hw_string* response);
void http_server_after_write(uv_write_t* req, int status);
void http_stream_on_read_http_parser(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf);
void reuseport_thread_start(void *arg);
http_connection *create_http_connection();
void http_stream_on_connect(uv_stream_t *stream, int status);
void http_stream_on_alloc(uv_handle_t *client, size_t suggested_size, uv_buf_t *buf);
void http_stream_on_close(uv_handle_t *handle);
int http_server_write_response_single(hw_write_context *write_context, hw_string *response);
void http_server_after_write(uv_write_t *req, int status);
void http_stream_on_read_http_parser(uv_stream_t *tcp, ssize_t nread, const uv_buf_t *buf);
void reuseport_thread_start(void *arg);

View File

@ -3,25 +3,23 @@
#include <string.h>
#include "haywire.h"
hw_string* create_string(const char* value)
{
int length = (int)strlen(value);
hw_string* str = malloc(sizeof(hw_string));
str->value = malloc(length);
hw_string *create_string(const char *value) {
int length = (int)strlen(value);
hw_string *str = malloc(sizeof(hw_string));
str->value = malloc(length);
memcpy(str->value, value, length);
str->length = length;
return str;
}
hw_string* hw_strdup(hw_string* tocopy)
{
hw_string* str = malloc(sizeof(hw_string));
str->value = tocopy->value;
str->length = tocopy->length;
hw_string *hw_strdup(hw_string *tocopy) {
hw_string *str = malloc(sizeof(hw_string));
str->value = tocopy->value;
str->length = tocopy->length;
return str;
}
int hw_strcmp(hw_string* a, hw_string* b) {
int hw_strcmp(hw_string *a, hw_string *b) {
int ret;
if (a->length > b->length) {
@ -41,36 +39,31 @@ int hw_strcmp(hw_string* a, hw_string* b) {
return ret;
}
void append_string(hw_string* destination, hw_string* source)
{
void* location = (void*) (destination->value + destination->length);
void append_string(hw_string *destination, hw_string *source) {
void *location = (void *)(destination->value + destination->length);
memcpy(location, source->value, source->length);
destination->length += source->length;
}
/* Added because of http://stackoverflow.com/questions/8359966/strdup-returning-address-out-of-bounds */
char* dupstr(const char *s)
{
char* result = malloc(strlen(s) + 1);
if (result != NULL)
{
char *dupstr(const char *s) {
char *result = malloc(strlen(s) + 1);
if (result != NULL) {
strcpy(result, s);
}
return result;
}
void string_from_int(hw_string* str, int val, int base)
{
static char buf[32] = {0};
int i = 30;
int length = 0;
void string_from_int(hw_string *str, int val, int base) {
static char buf[32] = {0};
int i = 30;
int length = 0;
for(; val && i ; --i, val /= base)
{
buf[i] = "0123456789abcdef"[val % base];
for (; val && i; --i, val /= base) {
buf[i] = "0123456789abcdef"[val % base];
length++;
}
str->value = &buf[i+1];
str->value = &buf[i + 1];
str->length = length;
}

View File

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

View File

@ -113,7 +113,6 @@
* Added destructor
*/
#ifndef __AC_KHASH_H
#define __AC_KHASH_H
@ -134,7 +133,7 @@
#if UINT_MAX == 0xffffffffu
typedef unsigned int khint32_t;
#elif ULONG_MAX == 0xffffffffu
typedef unsigned long khint32_t;
typedef unsigned long khint32_t;
#endif
#if ULONG_MAX == ULLONG_MAX
@ -150,30 +149,31 @@ typedef unsigned long long khint64_t;
#endif
typedef khint32_t khint_t;
typedef khint_t khiter_t;
typedef khint_t khiter_t;
#define __ac_isempty(flag, i) ((flag[i>>4]>>((i&0xfU)<<1))&2)
#define __ac_isdel(flag, i) ((flag[i>>4]>>((i&0xfU)<<1))&1)
#define __ac_iseither(flag, i) ((flag[i>>4]>>((i&0xfU)<<1))&3)
#define __ac_set_isdel_false(flag, i) (flag[i>>4]&=~(1ul<<((i&0xfU)<<1)))
#define __ac_set_isempty_false(flag, i) (flag[i>>4]&=~(2ul<<((i&0xfU)<<1)))
#define __ac_set_isboth_false(flag, i) (flag[i>>4]&=~(3ul<<((i&0xfU)<<1)))
#define __ac_set_isdel_true(flag, i) (flag[i>>4]|=1ul<<((i&0xfU)<<1))
#define __ac_isempty(flag, i) ((flag[i >> 4] >> ((i & 0xfU) << 1)) & 2)
#define __ac_isdel(flag, i) ((flag[i >> 4] >> ((i & 0xfU) << 1)) & 1)
#define __ac_iseither(flag, i) ((flag[i >> 4] >> ((i & 0xfU) << 1)) & 3)
#define __ac_set_isdel_false(flag, i) (flag[i >> 4] &= ~(1ul << ((i & 0xfU) << 1)))
#define __ac_set_isempty_false(flag, i) (flag[i >> 4] &= ~(2ul << ((i & 0xfU) << 1)))
#define __ac_set_isboth_false(flag, i) (flag[i >> 4] &= ~(3ul << ((i & 0xfU) << 1)))
#define __ac_set_isdel_true(flag, i) (flag[i >> 4] |= 1ul << ((i & 0xfU) << 1))
#define __ac_fsize(m) ((m) < 16? 1 : (m)>>4)
#define __ac_fsize(m) ((m) < 16 ? 1 : (m) >> 4)
#ifndef kroundup32
#define kroundup32(x) (--(x), (x)|=(x)>>1, (x)|=(x)>>2, (x)|=(x)>>4, (x)|=(x)>>8, (x)|=(x)>>16, ++(x))
#define kroundup32(x) \
(--(x), (x) |= (x) >> 1, (x) |= (x) >> 2, (x) |= (x) >> 4, (x) |= (x) >> 8, (x) |= (x) >> 16, ++(x))
#endif
#ifndef kcalloc
#define kcalloc(N,Z) calloc(N,Z)
#define kcalloc(N, Z) calloc(N, Z)
#endif
#ifndef kmalloc
#define kmalloc(Z) malloc(Z)
#endif
#ifndef krealloc
#define krealloc(P,Z) realloc(P,Z)
#define krealloc(P, Z) realloc(P, Z)
#endif
#ifndef kfree
#define kfree(P) free(P)
@ -181,179 +181,208 @@ typedef khint_t khiter_t;
static const double __ac_HASH_UPPER = 0.77;
#define __KHASH_TYPE(name, khkey_t, khval_t) \
typedef struct { \
khint_t n_buckets, size, n_occupied, upper_bound; \
khint32_t *flags; \
khkey_t *keys; \
khval_t *vals; \
} kh_##name##_t;
#define __KHASH_TYPE(name, khkey_t, khval_t) \
typedef struct { \
khint_t n_buckets, size, n_occupied, upper_bound; \
khint32_t *flags; \
khkey_t *keys; \
khval_t *vals; \
} kh_##name##_t;
#define __KHASH_PROTOTYPES(name, khkey_t, khval_t) \
extern kh_##name##_t *kh_init_##name(void); \
extern void kh_destroy_##name(kh_##name##_t *h); \
extern void kh_clear_##name(kh_##name##_t *h); \
extern khint_t kh_get_##name(const kh_##name##_t *h, khkey_t key); \
extern int kh_resize_##name(kh_##name##_t *h, khint_t new_n_buckets); \
extern khint_t kh_put_##name(kh_##name##_t *h, khkey_t key, int *ret); \
extern void kh_del_##name(kh_##name##_t *h, khint_t x);
#define __KHASH_PROTOTYPES(name, khkey_t, khval_t) \
extern kh_##name##_t *kh_init_##name(void); \
extern void kh_destroy_##name(kh_##name##_t *h); \
extern void kh_clear_##name(kh_##name##_t *h); \
extern khint_t kh_get_##name(const kh_##name##_t *h, khkey_t key); \
extern int kh_resize_##name(kh_##name##_t *h, khint_t new_n_buckets); \
extern khint_t kh_put_##name(kh_##name##_t *h, khkey_t key, int *ret); \
extern void kh_del_##name(kh_##name##_t *h, khint_t x);
#define __KHASH_IMPL(name, SCOPE, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal) \
SCOPE kh_##name##_t *kh_init_##name(void) { \
return (kh_##name##_t*)kcalloc(1, sizeof(kh_##name##_t)); \
} \
SCOPE void kh_destroy_##name(kh_##name##_t *h) \
{ \
if (h) { \
kfree((void *)h->keys); kfree(h->flags); \
kfree((void *)h->vals); \
kfree(h); \
} \
} \
SCOPE void kh_clear_##name(kh_##name##_t *h) \
{ \
if (h && h->flags) { \
memset(h->flags, 0xaa, __ac_fsize(h->n_buckets) * sizeof(khint32_t)); \
h->size = h->n_occupied = 0; \
} \
} \
SCOPE khint_t kh_get_##name(const kh_##name##_t *h, khkey_t key) \
{ \
if (h->n_buckets) { \
khint_t k, i, last, mask, step = 0; \
mask = h->n_buckets - 1; \
k = __hash_func(key); i = k & mask; \
last = i; \
while (!__ac_isempty(h->flags, i) && (__ac_isdel(h->flags, i) || !__hash_equal(h->keys[i], key))) { \
i = (i + (++step)) & mask; \
if (i == last) return h->n_buckets; \
} \
return __ac_iseither(h->flags, i)? h->n_buckets : i; \
} else return 0; \
} \
SCOPE int kh_resize_##name(kh_##name##_t *h, khint_t new_n_buckets) \
{ /* This function uses 0.25*n_buckets bytes of working space instead of [sizeof(key_t+val_t)+.25]*n_buckets. */ \
khint32_t *new_flags = 0; \
khint_t j = 1; \
{ \
kroundup32(new_n_buckets); \
if (new_n_buckets < 4) new_n_buckets = 4; \
if (h->size >= (khint_t)(new_n_buckets * __ac_HASH_UPPER + 0.5)) j = 0; /* requested size is too small */ \
else { /* hash table size to be changed (shrink or expand); rehash */ \
new_flags = (khint32_t*)kmalloc(__ac_fsize(new_n_buckets) * sizeof(khint32_t)); \
if (!new_flags) return -1; \
memset(new_flags, 0xaa, __ac_fsize(new_n_buckets) * sizeof(khint32_t)); \
if (h->n_buckets < new_n_buckets) { /* expand */ \
khkey_t *new_keys = (khkey_t*)krealloc((void *)h->keys, new_n_buckets * sizeof(khkey_t)); \
if (!new_keys) return -1; \
h->keys = new_keys; \
if (kh_is_map) { \
khval_t *new_vals = (khval_t*)krealloc((void *)h->vals, new_n_buckets * sizeof(khval_t)); \
if (!new_vals) return -1; \
h->vals = new_vals; \
} \
} /* otherwise shrink */ \
} \
} \
if (j) { /* rehashing is needed */ \
for (j = 0; j != h->n_buckets; ++j) { \
if (__ac_iseither(h->flags, j) == 0) { \
khkey_t key = h->keys[j]; \
khval_t val; \
khint_t new_mask; \
new_mask = new_n_buckets - 1; \
if (kh_is_map) val = h->vals[j]; \
__ac_set_isdel_true(h->flags, j); \
while (1) { /* kick-out process; sort of like in Cuckoo hashing */ \
khint_t k, i, step = 0; \
k = __hash_func(key); \
i = k & new_mask; \
while (!__ac_isempty(new_flags, i)) i = (i + (++step)) & new_mask; \
__ac_set_isempty_false(new_flags, i); \
if (i < h->n_buckets && __ac_iseither(h->flags, i) == 0) { /* kick out the existing element */ \
{ khkey_t tmp = h->keys[i]; h->keys[i] = key; key = tmp; } \
if (kh_is_map) { khval_t tmp = h->vals[i]; h->vals[i] = val; val = tmp; } \
__ac_set_isdel_true(h->flags, i); /* mark it as deleted in the old hash table */ \
} else { /* write the element and jump out of the loop */ \
h->keys[i] = key; \
if (kh_is_map) h->vals[i] = val; \
break; \
} \
} \
} \
} \
if (h->n_buckets > new_n_buckets) { /* shrink the hash table */ \
h->keys = (khkey_t*)krealloc((void *)h->keys, new_n_buckets * sizeof(khkey_t)); \
if (kh_is_map) h->vals = (khval_t*)krealloc((void *)h->vals, new_n_buckets * sizeof(khval_t)); \
} \
kfree(h->flags); /* free the working space */ \
h->flags = new_flags; \
h->n_buckets = new_n_buckets; \
h->n_occupied = h->size; \
h->upper_bound = (khint_t)(h->n_buckets * __ac_HASH_UPPER + 0.5); \
} \
return 0; \
} \
SCOPE khint_t kh_put_##name(kh_##name##_t *h, khkey_t key, int *ret) \
{ \
khint_t x; \
if (h->n_occupied >= h->upper_bound) { /* update the hash table */ \
if (h->n_buckets > (h->size<<1)) { \
if (kh_resize_##name(h, h->n_buckets - 1) < 0) { /* clear "deleted" elements */ \
*ret = -1; return h->n_buckets; \
} \
} else if (kh_resize_##name(h, h->n_buckets + 1) < 0) { /* expand the hash table */ \
*ret = -1; return h->n_buckets; \
} \
} /* TODO: to implement automatically shrinking; resize() already support shrinking */ \
{ \
khint_t k, i, site, last, mask = h->n_buckets - 1, step = 0; \
x = site = h->n_buckets; k = __hash_func(key); i = k & mask; \
if (__ac_isempty(h->flags, i)) x = i; /* for speed up */ \
else { \
last = i; \
while (!__ac_isempty(h->flags, i) && (__ac_isdel(h->flags, i) || !__hash_equal(h->keys[i], key))) { \
if (__ac_isdel(h->flags, i)) site = i; \
i = (i + (++step)) & mask; \
if (i == last) { x = site; break; } \
} \
if (x == h->n_buckets) { \
if (__ac_isempty(h->flags, i) && site != h->n_buckets) x = site; \
else x = i; \
} \
} \
} \
if (__ac_isempty(h->flags, x)) { /* not present at all */ \
h->keys[x] = key; \
__ac_set_isboth_false(h->flags, x); \
++h->size; ++h->n_occupied; \
*ret = 1; \
} else if (__ac_isdel(h->flags, x)) { /* deleted */ \
h->keys[x] = key; \
__ac_set_isboth_false(h->flags, x); \
++h->size; \
*ret = 2; \
} else *ret = 0; /* Don't touch h->keys[x] if present and not deleted */ \
return x; \
} \
SCOPE void kh_del_##name(kh_##name##_t *h, khint_t x) \
{ \
if (x != h->n_buckets && !__ac_iseither(h->flags, x)) { \
__ac_set_isdel_true(h->flags, x); \
--h->size; \
} \
}
#define __KHASH_IMPL(name, SCOPE, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal) \
SCOPE kh_##name##_t *kh_init_##name(void) { return (kh_##name##_t *)kcalloc(1, sizeof(kh_##name##_t)); } \
SCOPE void kh_destroy_##name(kh_##name##_t *h) { \
if (h) { \
kfree((void *)h->keys); \
kfree(h->flags); \
kfree((void *)h->vals); \
kfree(h); \
} \
} \
SCOPE void kh_clear_##name(kh_##name##_t *h) { \
if (h && h->flags) { \
memset(h->flags, 0xaa, __ac_fsize(h->n_buckets) * sizeof(khint32_t)); \
h->size = h->n_occupied = 0; \
} \
} \
SCOPE khint_t kh_get_##name(const kh_##name##_t *h, khkey_t key) { \
if (h->n_buckets) { \
khint_t k, i, last, mask, step = 0; \
mask = h->n_buckets - 1; \
k = __hash_func(key); \
i = k & mask; \
last = i; \
while (!__ac_isempty(h->flags, i) && (__ac_isdel(h->flags, i) || !__hash_equal(h->keys[i], key))) { \
i = (i + (++step)) & mask; \
if (i == last) \
return h->n_buckets; \
} \
return __ac_iseither(h->flags, i) ? h->n_buckets : i; \
} else \
return 0; \
} \
SCOPE int kh_resize_##name( \
kh_##name##_t *h, \
khint_t \
new_n_buckets) { /* This function uses 0.25*n_buckets bytes of working space instead of [sizeof(key_t+val_t)+.25]*n_buckets. */ \
khint32_t *new_flags = 0; \
khint_t j = 1; \
{ \
kroundup32(new_n_buckets); \
if (new_n_buckets < 4) \
new_n_buckets = 4; \
if (h->size >= (khint_t)(new_n_buckets * __ac_HASH_UPPER + 0.5)) \
j = 0; /* requested size is too small */ \
else { /* hash table size to be changed (shrink or expand); rehash */ \
new_flags = (khint32_t *)kmalloc(__ac_fsize(new_n_buckets) * sizeof(khint32_t)); \
if (!new_flags) \
return -1; \
memset(new_flags, 0xaa, __ac_fsize(new_n_buckets) * sizeof(khint32_t)); \
if (h->n_buckets < new_n_buckets) { /* expand */ \
khkey_t *new_keys = (khkey_t *)krealloc((void *)h->keys, new_n_buckets * sizeof(khkey_t)); \
if (!new_keys) \
return -1; \
h->keys = new_keys; \
if (kh_is_map) { \
khval_t *new_vals = (khval_t *)krealloc((void *)h->vals, new_n_buckets * sizeof(khval_t)); \
if (!new_vals) \
return -1; \
h->vals = new_vals; \
} \
} /* otherwise shrink */ \
} \
} \
if (j) { /* rehashing is needed */ \
for (j = 0; j != h->n_buckets; ++j) { \
if (__ac_iseither(h->flags, j) == 0) { \
khkey_t key = h->keys[j]; \
khval_t val; \
khint_t new_mask; \
new_mask = new_n_buckets - 1; \
if (kh_is_map) \
val = h->vals[j]; \
__ac_set_isdel_true(h->flags, j); \
while (1) { /* kick-out process; sort of like in Cuckoo hashing */ \
khint_t k, i, step = 0; \
k = __hash_func(key); \
i = k & new_mask; \
while (!__ac_isempty(new_flags, i)) \
i = (i + (++step)) & new_mask; \
__ac_set_isempty_false(new_flags, i); \
if (i < h->n_buckets && __ac_iseither(h->flags, i) == 0) { /* kick out the existing element */ \
{ \
khkey_t tmp = h->keys[i]; \
h->keys[i] = key; \
key = tmp; \
} \
if (kh_is_map) { \
khval_t tmp = h->vals[i]; \
h->vals[i] = val; \
val = tmp; \
} \
__ac_set_isdel_true(h->flags, i); /* mark it as deleted in the old hash table */ \
} else { /* write the element and jump out of the loop */ \
h->keys[i] = key; \
if (kh_is_map) \
h->vals[i] = val; \
break; \
} \
} \
} \
} \
if (h->n_buckets > new_n_buckets) { /* shrink the hash table */ \
h->keys = (khkey_t *)krealloc((void *)h->keys, new_n_buckets * sizeof(khkey_t)); \
if (kh_is_map) \
h->vals = (khval_t *)krealloc((void *)h->vals, new_n_buckets * sizeof(khval_t)); \
} \
kfree(h->flags); /* free the working space */ \
h->flags = new_flags; \
h->n_buckets = new_n_buckets; \
h->n_occupied = h->size; \
h->upper_bound = (khint_t)(h->n_buckets * __ac_HASH_UPPER + 0.5); \
} \
return 0; \
} \
SCOPE khint_t kh_put_##name(kh_##name##_t *h, khkey_t key, int *ret) { \
khint_t x; \
if (h->n_occupied >= h->upper_bound) { /* update the hash table */ \
if (h->n_buckets > (h->size << 1)) { \
if (kh_resize_##name(h, h->n_buckets - 1) < 0) { /* clear "deleted" elements */ \
*ret = -1; \
return h->n_buckets; \
} \
} else if (kh_resize_##name(h, h->n_buckets + 1) < 0) { /* expand the hash table */ \
*ret = -1; \
return h->n_buckets; \
} \
} /* TODO: to implement automatically shrinking; resize() already support shrinking */ \
{ \
khint_t k, i, site, last, mask = h->n_buckets - 1, step = 0; \
x = site = h->n_buckets; \
k = __hash_func(key); \
i = k & mask; \
if (__ac_isempty(h->flags, i)) \
x = i; /* for speed up */ \
else { \
last = i; \
while (!__ac_isempty(h->flags, i) && (__ac_isdel(h->flags, i) || !__hash_equal(h->keys[i], key))) { \
if (__ac_isdel(h->flags, i)) \
site = i; \
i = (i + (++step)) & mask; \
if (i == last) { \
x = site; \
break; \
} \
} \
if (x == h->n_buckets) { \
if (__ac_isempty(h->flags, i) && site != h->n_buckets) \
x = site; \
else \
x = i; \
} \
} \
} \
if (__ac_isempty(h->flags, x)) { /* not present at all */ \
h->keys[x] = key; \
__ac_set_isboth_false(h->flags, x); \
++h->size; \
++h->n_occupied; \
*ret = 1; \
} else if (__ac_isdel(h->flags, x)) { /* deleted */ \
h->keys[x] = key; \
__ac_set_isboth_false(h->flags, x); \
++h->size; \
*ret = 2; \
} else \
*ret = 0; /* Don't touch h->keys[x] if present and not deleted */ \
return x; \
} \
SCOPE void kh_del_##name(kh_##name##_t *h, khint_t x) { \
if (x != h->n_buckets && !__ac_iseither(h->flags, x)) { \
__ac_set_isdel_true(h->flags, x); \
--h->size; \
} \
}
#define KHASH_DECLARE(name, khkey_t, khval_t) \
__KHASH_TYPE(name, khkey_t, khval_t) \
__KHASH_PROTOTYPES(name, khkey_t, khval_t)
#define KHASH_DECLARE(name, khkey_t, khval_t) \
__KHASH_TYPE(name, khkey_t, khval_t) \
__KHASH_PROTOTYPES(name, khkey_t, khval_t)
#define KHASH_INIT2(name, SCOPE, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal) \
__KHASH_TYPE(name, khkey_t, khval_t) \
__KHASH_IMPL(name, SCOPE, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal)
__KHASH_TYPE(name, khkey_t, khval_t) \
__KHASH_IMPL(name, SCOPE, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal)
#define KHASH_INIT(name, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal) \
KHASH_INIT2(name, static kh_inline, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal)
KHASH_INIT2(name, static kh_inline, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal)
/* --- BEGIN OF HASH FUNCTIONS --- */
@ -372,7 +401,7 @@ KHASH_INIT2(name, static kh_inline, khkey_t, khval_t, kh_is_map, __hash_func, __
@param key The integer [khint64_t]
@return The hash value [khint_t]
*/
#define kh_int64_hash_func(key) (khint32_t)((key)>>33^(key)^(key)<<11)
#define kh_int64_hash_func(key) (khint32_t)((key) >> 33 ^ (key) ^ (key) << 11)
/*! @function
@abstract 64-bit integer comparison function
*/
@ -382,11 +411,12 @@ KHASH_INIT2(name, static kh_inline, khkey_t, khval_t, kh_is_map, __hash_func, __
@param s Pointer to a null terminated string
@return The hash value
*/
static kh_inline khint_t __ac_X31_hash_string(const char *s)
{
khint_t h = (khint_t)*s;
if (h) for (++s ; *s; ++s) h = (h << 5) - h + (khint_t)*s;
return h;
static kh_inline khint_t __ac_X31_hash_string(const char *s) {
khint_t h = (khint_t)*s;
if (h)
for (++s; *s; ++s)
h = (h << 5) - h + (khint_t)*s;
return h;
}
/*! @function
@abstract Another interface to const char* hash function
@ -399,14 +429,13 @@ static kh_inline khint_t __ac_X31_hash_string(const char *s)
*/
#define kh_str_hash_equal(a, b) (strcmp(a, b) == 0)
static kh_inline khint_t __ac_Wang_hash(khint_t key)
{
static kh_inline khint_t __ac_Wang_hash(khint_t key) {
key += ~(key << 15);
key ^= (key >> 10);
key += (key << 3);
key ^= (key >> 6);
key ^= (key >> 10);
key += (key << 3);
key ^= (key >> 6);
key += ~(key << 11);
key ^= (key >> 16);
key ^= (key >> 16);
return key;
}
#define kh_int_hash_func2(k) __ac_Wang_hash((khint_t)key)
@ -544,13 +573,17 @@ static kh_inline khint_t __ac_Wang_hash(khint_t key)
@param vvar Variable to which value will be assigned
@param code Block of code to execute
*/
#define kh_foreach(h, kvar, vvar, code) { khint_t __i; \
for (__i = kh_begin(h); __i != kh_end(h); ++__i) { \
if (!kh_exist(h,__i)) continue; \
(kvar) = kh_key(h,__i); \
(vvar) = kh_val(h,__i); \
code; \
} }
#define kh_foreach(h, kvar, vvar, code) \
{ \
khint_t __i; \
for (__i = kh_begin(h); __i != kh_end(h); ++__i) { \
if (!kh_exist(h, __i)) \
continue; \
(kvar) = kh_key(h, __i); \
(vvar) = kh_val(h, __i); \
code; \
} \
}
/*! @function
@abstract Iterate over the values in the hash table
@ -558,12 +591,16 @@ code; \
@param vvar Variable to which value will be assigned
@param code Block of code to execute
*/
#define kh_foreach_value(h, vvar, code) { khint_t __i; \
for (__i = kh_begin(h); __i != kh_end(h); ++__i) { \
if (!kh_exist(h,__i)) continue; \
(vvar) = kh_val(h,__i); \
code; \
} }
#define kh_foreach_value(h, vvar, code) \
{ \
khint_t __i; \
for (__i = kh_begin(h); __i != kh_end(h); ++__i) { \
if (!kh_exist(h, __i)) \
continue; \
(vvar) = kh_val(h, __i); \
code; \
} \
}
/* More conenient interfaces */
@ -571,47 +608,41 @@ code; \
@abstract Instantiate a hash set containing integer keys
@param name Name of the hash table [symbol]
*/
#define KHASH_SET_INIT_INT(name) \
KHASH_INIT(name, khint32_t, char, 0, kh_int_hash_func, kh_int_hash_equal)
#define KHASH_SET_INIT_INT(name) KHASH_INIT(name, khint32_t, char, 0, kh_int_hash_func, kh_int_hash_equal)
/*! @function
@abstract Instantiate a hash map containing integer keys
@param name Name of the hash table [symbol]
@param khval_t Type of values [type]
*/
#define KHASH_MAP_INIT_INT(name, khval_t) \
KHASH_INIT(name, khint32_t, khval_t, 1, kh_int_hash_func, kh_int_hash_equal)
#define KHASH_MAP_INIT_INT(name, khval_t) KHASH_INIT(name, khint32_t, khval_t, 1, kh_int_hash_func, kh_int_hash_equal)
/*! @function
@abstract Instantiate a hash map containing 64-bit integer keys
@param name Name of the hash table [symbol]
*/
#define KHASH_SET_INIT_INT64(name) \
KHASH_INIT(name, khint64_t, char, 0, kh_int64_hash_func, kh_int64_hash_equal)
#define KHASH_SET_INIT_INT64(name) KHASH_INIT(name, khint64_t, char, 0, kh_int64_hash_func, kh_int64_hash_equal)
/*! @function
@abstract Instantiate a hash map containing 64-bit integer keys
@param name Name of the hash table [symbol]
@param khval_t Type of values [type]
*/
#define KHASH_MAP_INIT_INT64(name, khval_t) \
KHASH_INIT(name, khint64_t, khval_t, 1, kh_int64_hash_func, kh_int64_hash_equal)
#define KHASH_MAP_INIT_INT64(name, khval_t) \
KHASH_INIT(name, khint64_t, khval_t, 1, kh_int64_hash_func, kh_int64_hash_equal)
typedef const char *kh_cstr_t;
/*! @function
@abstract Instantiate a hash map containing const char* keys
@param name Name of the hash table [symbol]
*/
#define KHASH_SET_INIT_STR(name) \
KHASH_INIT(name, kh_cstr_t, char, 0, kh_str_hash_func, kh_str_hash_equal)
#define KHASH_SET_INIT_STR(name) KHASH_INIT(name, kh_cstr_t, char, 0, kh_str_hash_func, kh_str_hash_equal)
/*! @function
@abstract Instantiate a hash map containing const char* keys
@param name Name of the hash table [symbol]
@param khval_t Type of values [type]
*/
#define KHASH_MAP_INIT_STR(name, khval_t) \
KHASH_INIT(name, kh_cstr_t, khval_t, 1, kh_str_hash_func, kh_str_hash_equal)
#define KHASH_MAP_INIT_STR(name, khval_t) KHASH_INIT(name, kh_cstr_t, khval_t, 1, kh_str_hash_func, kh_str_hash_equal)
#endif /* __AC_KHASH_H */

View File

@ -38,10 +38,10 @@
/* $Id$ */
#if __GNUC__ >= 3
#define likely(x) __builtin_expect(!!(x), 1)
#define likely(x) __builtin_expect(!!(x), 1)
#define unlikely(x) __builtin_expect(!!(x), 0)
#else
#define likely(x) (x)
#define likely(x) (x)
#define unlikely(x) (x)
#endif
@ -53,55 +53,56 @@
#define IS_PRINTABLE_ASCII(c) ((unsigned char)(c)-040u < 0137u)
#define CHECK_EOF() \
if (buf == buf_end) { \
*ret = -2; \
return NULL; \
#define CHECK_EOF() \
if (buf == buf_end) { \
*ret = -2; \
return NULL; \
}
#define EXPECT_CHAR(ch) \
CHECK_EOF(); \
if (*buf++ != ch) { \
*ret = -1; \
return NULL; \
#define EXPECT_CHAR(ch) \
CHECK_EOF(); \
if (*buf++ != ch) { \
*ret = -1; \
return NULL; \
}
#define ADVANCE_TOKEN(tok, toklen) \
do { \
const char *tok_start = buf; \
static const char ALIGNED(16) ranges2[] = "\000\040\177\177"; \
int found2; \
buf = findchar_fast(buf, buf_end, ranges2, sizeof(ranges2) - 1, &found2); \
if (!found2) { \
CHECK_EOF(); \
} \
while (1) { \
if (*buf == ' ') { \
break; \
} else if (unlikely(!IS_PRINTABLE_ASCII(*buf))) { \
if ((unsigned char)*buf < '\040' || *buf == '\177') { \
*ret = -1; \
return NULL; \
} \
} \
++buf; \
CHECK_EOF(); \
} \
tok = tok_start; \
toklen = buf - tok_start; \
#define ADVANCE_TOKEN(tok, toklen) \
do { \
const char *tok_start = buf; \
static const char ALIGNED(16) ranges2[] = "\000\040\177\177"; \
int found2; \
buf = findchar_fast(buf, buf_end, ranges2, sizeof(ranges2) - 1, &found2); \
if (!found2) { \
CHECK_EOF(); \
} \
while (1) { \
if (*buf == ' ') { \
break; \
} else if (unlikely(!IS_PRINTABLE_ASCII(*buf))) { \
if ((unsigned char)*buf < '\040' || *buf == '\177') { \
*ret = -1; \
return NULL; \
} \
} \
++buf; \
CHECK_EOF(); \
} \
tok = tok_start; \
toklen = buf - tok_start; \
} while (0)
static const char *token_char_map = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\1\1\1\1\1\1\1\0\0\1\1\0\1\1\0\1\1\1\1\1\1\1\1\1\1\0\0\0\0\0\0"
"\0\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\0\0\0\1\1"
"\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\0\1\0\1\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
static const char *token_char_map =
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\1\1\1\1\1\1\1\0\0\1\1\0\1\1\0\1\1\1\1\1\1\1\1\1\1\0\0\0\0\0\0"
"\0\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\0\0\0\1\1"
"\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\0\1\0\1\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
static const char *findchar_fast(const char *buf, const char *buf_end, const char *ranges, size_t ranges_size, int *found)
{
static const char *findchar_fast(const char *buf, const char *buf_end, const char *ranges, size_t ranges_size,
int *found) {
*found = 0;
#if __SSE4_2__
if (likely(buf_end - buf >= 16)) {
@ -110,7 +111,8 @@ static const char *findchar_fast(const char *buf, const char *buf_end, const cha
size_t left = (buf_end - buf) & ~15;
do {
__m128i b16 = _mm_loadu_si128((void *)buf);
int r = _mm_cmpestri(ranges16, ranges_size, b16, 16, _SIDD_LEAST_SIGNIFICANT | _SIDD_CMP_RANGES | _SIDD_UBYTE_OPS);
int r = _mm_cmpestri(
ranges16, ranges_size, b16, 16, _SIDD_LEAST_SIGNIFICANT | _SIDD_CMP_RANGES | _SIDD_UBYTE_OPS);
if (unlikely(r != 16)) {
buf += r;
*found = 1;
@ -124,16 +126,17 @@ static const char *findchar_fast(const char *buf, const char *buf_end, const cha
return buf;
}
static const char *get_token_to_eol(const char *buf, const char *buf_end, const char **token, size_t *token_len, int *ret)
{
static const char *get_token_to_eol(const char *buf, const char *buf_end, const char **token, size_t *token_len,
int *ret) {
const char *token_start = buf;
#ifdef __SSE4_2__
static const char ranges1[] = "\0\010"
/* allow HT */
"\012\037"
/* allow SP and up to but not including DEL */
"\177\177"
static const char ranges1
[] = "\0\010"
/* allow HT */
"\012\037"
/* allow SP and up to but not including DEL */
"\177\177"
/* allow chars w. MSB set */
;
int found;
@ -143,11 +146,11 @@ static const char *get_token_to_eol(const char *buf, const char *buf_end, const
#else
/* find non-printable char within the next 8 bytes, this is the hottest code; manually inlined */
while (likely(buf_end - buf >= 8)) {
#define DOIT() \
do { \
if (unlikely(!IS_PRINTABLE_ASCII(*buf))) \
goto NonPrintable; \
++buf; \
#define DOIT() \
do { \
if (unlikely(!IS_PRINTABLE_ASCII(*buf))) \
goto NonPrintable; \
++buf; \
} while (0)
DOIT();
DOIT();
@ -191,10 +194,9 @@ FOUND_CTL:
return buf;
}
static const char *is_complete(const char *buf, const char *buf_end, size_t last_len, int *ret)
{
static const char *is_complete(const char *buf, const char *buf_end, size_t last_len, int *ret) {
int ret_cnt = 0;
buf = last_len < 3 ? buf : buf + last_len - 3;
buf = last_len < 3 ? buf : buf + last_len - 3;
while (1) {
CHECK_EOF();
@ -220,8 +222,7 @@ static const char *is_complete(const char *buf, const char *buf_end, size_t last
}
/* *_buf is always within [buf, buf_end) upon success */
static const char *parse_int(const char *buf, const char *buf_end, int *value, int *ret)
{
static const char *parse_int(const char *buf, const char *buf_end, int *value, int *ret) {
int v;
CHECK_EOF();
if (!('0' <= *buf && *buf <= '9')) {
@ -243,8 +244,7 @@ static const char *parse_int(const char *buf, const char *buf_end, int *value, i
}
/* returned pointer is always within [buf, buf_end), or null */
static const char *parse_http_version(const char *buf, const char *buf_end, int *minor_version, int *ret)
{
static const char *parse_http_version(const char *buf, const char *buf_end, int *minor_version, int *ret) {
EXPECT_CHAR('H');
EXPECT_CHAR('T');
EXPECT_CHAR('T');
@ -256,8 +256,7 @@ static const char *parse_http_version(const char *buf, const char *buf_end, int
}
static const char *parse_headers(const char *buf, const char *buf_end, struct phr_header *headers, size_t *num_headers,
size_t max_headers, int *ret)
{
size_t max_headers, int *ret) {
for (;; ++*num_headers) {
CHECK_EOF();
if (*buf == '\015') {
@ -279,9 +278,9 @@ static const char *parse_headers(const char *buf, const char *buf_end, struct ph
}
/* parsing name, but do not discard SP before colon, see
* http://www.mozilla.org/security/announce/2006/mfsa2006-33.html */
headers[*num_headers].name = buf;
headers[*num_headers].name = buf;
static const char ALIGNED(16) ranges1[] = "::\x00\037";
int found;
int found;
buf = findchar_fast(buf, buf_end, ranges1, sizeof(ranges1) - 1, &found);
if (!found) {
CHECK_EOF();
@ -305,20 +304,20 @@ static const char *parse_headers(const char *buf, const char *buf_end, struct ph
}
}
} else {
headers[*num_headers].name = NULL;
headers[*num_headers].name = NULL;
headers[*num_headers].name_len = 0;
}
if ((buf = get_token_to_eol(buf, buf_end, &headers[*num_headers].value, &headers[*num_headers].value_len, ret)) == NULL) {
if ((buf = get_token_to_eol(buf, buf_end, &headers[*num_headers].value, &headers[*num_headers].value_len, ret))
== NULL) {
return NULL;
}
}
return buf;
}
static const char *parse_request(const char *buf, const char *buf_end, const char **method, size_t *method_len, const char **path,
size_t *path_len, int *minor_version, struct phr_header *headers, size_t *num_headers,
size_t max_headers, int *ret)
{
static const char *parse_request(const char *buf, const char *buf_end, const char **method, size_t *method_len,
const char **path, size_t *path_len, int *minor_version, struct phr_header *headers,
size_t *num_headers, size_t max_headers, int *ret) {
/* skip first empty line (some clients add CRLF after POST content) */
CHECK_EOF();
if (*buf == '\015') {
@ -350,18 +349,18 @@ static const char *parse_request(const char *buf, const char *buf_end, const cha
}
int phr_parse_request(const char *buf_start, size_t len, const char **method, size_t *method_len, const char **path,
size_t *path_len, int *minor_version, struct phr_header *headers, size_t *num_headers, size_t last_len)
{
size_t *path_len, int *minor_version, struct phr_header *headers, size_t *num_headers,
size_t last_len) {
const char *buf = buf_start, *buf_end = buf_start + len;
size_t max_headers = *num_headers;
int r;
size_t max_headers = *num_headers;
int r;
*method = NULL;
*method_len = 0;
*path = NULL;
*path_len = 0;
*method = NULL;
*method_len = 0;
*path = NULL;
*path_len = 0;
*minor_version = -1;
*num_headers = 0;
*num_headers = 0;
/* if last_len != 0, check if the request is complete (a fast countermeasure
againt slowloris */
@ -369,17 +368,18 @@ int phr_parse_request(const char *buf_start, size_t len, const char **method, si
return r;
}
if ((buf = parse_request(buf, buf_end, method, method_len, path, path_len, minor_version, headers, num_headers, max_headers,
&r)) == NULL) {
if ((buf = parse_request(
buf, buf_end, method, method_len, path, path_len, minor_version, headers, num_headers, max_headers, &r))
== NULL) {
return r;
}
return (int)(buf - buf_start);
}
static const char *parse_response(const char *buf, const char *buf_end, int *minor_version, int *status, const char **msg,
size_t *msg_len, struct phr_header *headers, size_t *num_headers, size_t max_headers, int *ret)
{
static const char *parse_response(const char *buf, const char *buf_end, int *minor_version, int *status,
const char **msg, size_t *msg_len, struct phr_header *headers, size_t *num_headers,
size_t max_headers, int *ret) {
/* parse "HTTP/1.x" */
if ((buf = parse_http_version(buf, buf_end, minor_version, ret)) == NULL) {
return NULL;
@ -406,18 +406,17 @@ static const char *parse_response(const char *buf, const char *buf_end, int *min
return parse_headers(buf, buf_end, headers, num_headers, max_headers, ret);
}
int phr_parse_response(const char *buf_start, size_t len, int *minor_version, int *status, const char **msg, size_t *msg_len,
struct phr_header *headers, size_t *num_headers, size_t last_len)
{
int phr_parse_response(const char *buf_start, size_t len, int *minor_version, int *status, const char **msg,
size_t *msg_len, struct phr_header *headers, size_t *num_headers, size_t last_len) {
const char *buf = buf_start, *buf_end = buf + len;
size_t max_headers = *num_headers;
int r;
size_t max_headers = *num_headers;
int r;
*minor_version = -1;
*status = 0;
*msg = NULL;
*msg_len = 0;
*num_headers = 0;
*status = 0;
*msg = NULL;
*msg_len = 0;
*num_headers = 0;
/* if last_len != 0, check if the response is complete (a fast countermeasure
against slowloris */
@ -425,18 +424,19 @@ int phr_parse_response(const char *buf_start, size_t len, int *minor_version, in
return r;
}
if ((buf = parse_response(buf, buf_end, minor_version, status, msg, msg_len, headers, num_headers, max_headers, &r)) == NULL) {
if ((buf = parse_response(buf, buf_end, minor_version, status, msg, msg_len, headers, num_headers, max_headers, &r))
== NULL) {
return r;
}
return (int)(buf - buf_start);
}
int phr_parse_headers(const char *buf_start, size_t len, struct phr_header *headers, size_t *num_headers, size_t last_len)
{
int phr_parse_headers(const char *buf_start, size_t len, struct phr_header *headers, size_t *num_headers,
size_t last_len) {
const char *buf = buf_start, *buf_end = buf + len;
size_t max_headers = *num_headers;
int r;
size_t max_headers = *num_headers;
int r;
*num_headers = 0;
@ -462,8 +462,7 @@ enum {
CHUNKED_IN_TRAILERS_LINE_MIDDLE
};
static int decode_hex(int ch)
{
static int decode_hex(int ch) {
if ('0' <= ch && ch <= '9') {
return ch - '0';
} else if ('A' <= ch && ch <= 'F') {
@ -475,109 +474,108 @@ static int decode_hex(int ch)
}
}
ssize_t phr_decode_chunked(struct phr_chunked_decoder *decoder, char *buf, size_t *_bufsz)
{
size_t dst = 0, src = 0, bufsz = *_bufsz;
ssize_t phr_decode_chunked(struct phr_chunked_decoder *decoder, char *buf, size_t *_bufsz) {
size_t dst = 0, src = 0, bufsz = *_bufsz;
ssize_t ret = -2; /* incomplete */
while (1) {
switch (decoder->_state) {
case CHUNKED_IN_CHUNK_SIZE:
for (;; ++src) {
int v;
if (src == bufsz)
goto Exit;
if ((v = decode_hex(buf[src])) == -1) {
if (decoder->_hex_count == 0) {
case CHUNKED_IN_CHUNK_SIZE:
for (;; ++src) {
int v;
if (src == bufsz)
goto Exit;
if ((v = decode_hex(buf[src])) == -1) {
if (decoder->_hex_count == 0) {
ret = -1;
goto Exit;
}
break;
}
if (decoder->_hex_count == sizeof(size_t) * 2) {
ret = -1;
goto Exit;
}
break;
decoder->bytes_left_in_chunk = decoder->bytes_left_in_chunk * 16 + v;
++decoder->_hex_count;
}
if (decoder->_hex_count == sizeof(size_t) * 2) {
decoder->_hex_count = 0;
decoder->_state = CHUNKED_IN_CHUNK_EXT;
/* fallthru */
case CHUNKED_IN_CHUNK_EXT:
/* RFC 7230 A.2 "Line folding in chunk extensions is disallowed" */
for (;; ++src) {
if (src == bufsz)
goto Exit;
if (buf[src] == '\012')
break;
}
++src;
if (decoder->bytes_left_in_chunk == 0) {
if (decoder->consume_trailer) {
decoder->_state = CHUNKED_IN_TRAILERS_LINE_HEAD;
break;
} else {
goto Complete;
}
}
decoder->_state = CHUNKED_IN_CHUNK_DATA;
/* fallthru */
case CHUNKED_IN_CHUNK_DATA: {
size_t avail = bufsz - src;
if (avail < decoder->bytes_left_in_chunk) {
if (dst != src)
memmove(buf + dst, buf + src, avail);
src += avail;
dst += avail;
decoder->bytes_left_in_chunk -= avail;
goto Exit;
}
if (dst != src)
memmove(buf + dst, buf + src, decoder->bytes_left_in_chunk);
src += decoder->bytes_left_in_chunk;
dst += decoder->bytes_left_in_chunk;
decoder->bytes_left_in_chunk = 0;
decoder->_state = CHUNKED_IN_CHUNK_CRLF;
}
/* fallthru */
case CHUNKED_IN_CHUNK_CRLF:
for (;; ++src) {
if (src == bufsz)
goto Exit;
if (buf[src] != '\015')
break;
}
if (buf[src] != '\012') {
ret = -1;
goto Exit;
}
decoder->bytes_left_in_chunk = decoder->bytes_left_in_chunk * 16 + v;
++decoder->_hex_count;
}
decoder->_hex_count = 0;
decoder->_state = CHUNKED_IN_CHUNK_EXT;
/* fallthru */
case CHUNKED_IN_CHUNK_EXT:
/* RFC 7230 A.2 "Line folding in chunk extensions is disallowed" */
for (;; ++src) {
if (src == bufsz)
goto Exit;
if (buf[src] == '\012')
break;
}
++src;
if (decoder->bytes_left_in_chunk == 0) {
if (decoder->consume_trailer) {
decoder->_state = CHUNKED_IN_TRAILERS_LINE_HEAD;
break;
} else {
goto Complete;
++src;
decoder->_state = CHUNKED_IN_CHUNK_SIZE;
break;
case CHUNKED_IN_TRAILERS_LINE_HEAD:
for (;; ++src) {
if (src == bufsz)
goto Exit;
if (buf[src] != '\015')
break;
}
}
decoder->_state = CHUNKED_IN_CHUNK_DATA;
/* fallthru */
case CHUNKED_IN_CHUNK_DATA: {
size_t avail = bufsz - src;
if (avail < decoder->bytes_left_in_chunk) {
if (dst != src)
memmove(buf + dst, buf + src, avail);
src += avail;
dst += avail;
decoder->bytes_left_in_chunk -= avail;
goto Exit;
}
if (dst != src)
memmove(buf + dst, buf + src, decoder->bytes_left_in_chunk);
src += decoder->bytes_left_in_chunk;
dst += decoder->bytes_left_in_chunk;
decoder->bytes_left_in_chunk = 0;
decoder->_state = CHUNKED_IN_CHUNK_CRLF;
}
/* fallthru */
case CHUNKED_IN_CHUNK_CRLF:
for (;; ++src) {
if (src == bufsz)
goto Exit;
if (buf[src] != '\015')
break;
}
if (buf[src] != '\012') {
ret = -1;
goto Exit;
}
++src;
decoder->_state = CHUNKED_IN_CHUNK_SIZE;
break;
case CHUNKED_IN_TRAILERS_LINE_HEAD:
for (;; ++src) {
if (src == bufsz)
goto Exit;
if (buf[src] != '\015')
break;
}
if (buf[src++] == '\012')
goto Complete;
decoder->_state = CHUNKED_IN_TRAILERS_LINE_MIDDLE;
/* fallthru */
case CHUNKED_IN_TRAILERS_LINE_MIDDLE:
for (;; ++src) {
if (src == bufsz)
goto Exit;
if (buf[src] == '\012')
break;
}
++src;
decoder->_state = CHUNKED_IN_TRAILERS_LINE_HEAD;
break;
default:
assert(!"decoder is corrupt");
if (buf[src++] == '\012')
goto Complete;
decoder->_state = CHUNKED_IN_TRAILERS_LINE_MIDDLE;
/* fallthru */
case CHUNKED_IN_TRAILERS_LINE_MIDDLE:
for (;; ++src) {
if (src == bufsz)
goto Exit;
if (buf[src] == '\012')
break;
}
++src;
decoder->_state = CHUNKED_IN_TRAILERS_LINE_HEAD;
break;
default:
assert(!"decoder is corrupt");
}
}

View File

@ -43,15 +43,16 @@ extern "C" {
* of a multiline header */
struct phr_header {
const char *name;
size_t name_len;
size_t name_len;
const char *value;
size_t value_len;
size_t value_len;
};
/* returns number of bytes consumed if successful, -2 if request is partial,
* -1 if failed */
int phr_parse_request(const char *buf, size_t len, const char **method, size_t *method_len, const char **path, size_t *path_len,
int *minor_version, struct phr_header *headers, size_t *num_headers, size_t last_len);
int phr_parse_request(const char *buf, size_t len, const char **method, size_t *method_len, const char **path,
size_t *path_len, int *minor_version, struct phr_header *headers, size_t *num_headers,
size_t last_len);
/* ditto */
int phr_parse_response(const char *_buf, size_t len, int *minor_version, int *status, const char **msg, size_t *msg_len,
@ -63,9 +64,9 @@ int phr_parse_headers(const char *buf, size_t len, struct phr_header *headers, s
/* should be zero-filled before start */
struct phr_chunked_decoder {
size_t bytes_left_in_chunk; /* number of bytes left in current chunk */
char consume_trailer; /* if trailing headers should be consumed */
char _hex_count;
char _state;
char consume_trailer; /* if trailing headers should be consumed */
char _hex_count;
char _state;
};
/* the function rewrites the buffer given as (buf, bufsz) removing the chunked-

View File

@ -7,10 +7,10 @@
typedef struct hw_route_token_st {
hw_string string;
int start;
int start;
} hw_route_token;
void hw_route_next_token(hw_string* url, int start, hw_route_token* result) {
void hw_route_next_token(hw_string *url, int start, hw_route_token *result) {
while (start < url->length && (url->value[start] == '/')) {
start++;
}
@ -22,25 +22,23 @@ void hw_route_next_token(hw_string* url, int start, hw_route_token* result) {
}
if (end != start) {
result->string.value = url->value + start;
result->string.value = url->value + start;
result->string.length = end - start;
result->start = start;
}
else {
result->string.value = NULL;
result->start = start;
} else {
result->string.value = NULL;
result->string.length = 0;
result->start = -1;
result->start = -1;
}
}
int hw_route_compare_method(hw_string* url, char* route)
{
int hw_route_compare_method(hw_string *url, char *route) {
int equal = 0;
int match = 0;
// TODO route should probably be a hw_string* too
hw_string hw_route;
hw_route.value = route;
hw_route.value = route;
hw_route.length = strlen(route);
hw_route_token route_token;
@ -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(&hw_route, 0, &route_token);
while (route_token.string.value != NULL && request_token.string.value != NULL)
{
while (route_token.string.value != NULL && request_token.string.value != NULL) {
if (route_token.string.value[0] == '*') {
// wildcard support: any route fragment marked with '*' matches the corresponding url fragment
equal = 1;
}
else
{
} else {
match = hw_strcmp(&route_token.string, &request_token.string);
if (!match)
{
if (!match) {
equal = 1;
}
else
{
} else {
equal = 0;
break;
}
@ -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);
}
if (!equal)
{
if (!equal) {
match = hw_strcmp(url, &hw_route);
if (!match)
{
if (!match) {
equal = 1;
}
}
if ((route_token.string.value == NULL && request_token.string.value != NULL) || (route_token.string.value != NULL && request_token.string.value == NULL))
{
if ((route_token.string.value == NULL && request_token.string.value != NULL)
|| (route_token.string.value != NULL && request_token.string.value == NULL)) {
equal = 0;
}

View File

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

View File

@ -9,18 +9,11 @@ int stat_requests_destroyed_total;
#define CRLF "\r\n"
static const char stats_response[] =
"HTTP/1.1 200 OK" CRLF
"Server: Haywire/master" CRLF
"Date: Fri, 26 Aug 2011 00:31:53 GMT" CRLF
"Connection: Keep-Alive" CRLF
"Content-Type: text/html" CRLF
"Content-Length: 16" CRLF
CRLF
"stats printed" CRLF;
static const char stats_response[] = "HTTP/1.1 200 OK" CRLF "Server: Haywire/master" CRLF
"Date: Fri, 26 Aug 2011 00:31:53 GMT" CRLF "Connection: Keep-Alive" CRLF
"Content-Type: text/html" CRLF "Content-Length: 16" CRLF CRLF "stats printed" CRLF;
void get_server_stats(http_request* request, hw_http_response* response, void* user_data)
{
void get_server_stats(http_request *request, hw_http_response *response, void *user_data) {
hw_string status_code;
hw_string content_type_name;
hw_string content_type_value;
@ -39,21 +32,20 @@ void get_server_stats(http_request* request, hw_http_response* response, void* u
SETSTRING(body, "stats printed");
hw_set_body(response, &body);
if (request->keep_alive)
{
if (request->keep_alive) {
SETSTRING(keep_alive_name, "Connection");
SETSTRING(keep_alive_value, "Keep-Alive");
hw_set_response_header(response, &keep_alive_name, &keep_alive_value);
}
else
{
} else {
hw_set_http_version(response, 1, 0);
}
hw_http_response_send(response, NULL, NULL);
printf("connections_created_total: %d\nconnections_destroyed_total: %d\nrequests_created_total: %d\nrequests_destroyed_total: %d\n\n",
printf(
"connections_created_total: %d\nconnections_destroyed_total: %d\nrequests_created_total: "
"%d\nrequests_destroyed_total: %d\n\n",
stat_connections_created_total,
stat_connections_destroyed_total,
stat_requests_created_total,

View File

@ -7,10 +7,9 @@
#define INCREMENT_STAT(stat)
#endif /* DEBUG */
extern int stat_connections_created_total;
extern int stat_connections_destroyed_total;
extern int stat_requests_created_total;
extern int stat_requests_destroyed_total;
void get_server_stats(http_request* request, hw_http_response* response, void* user_data);
void get_server_stats(http_request *request, hw_http_response *response, void *user_data);

View File

@ -4,7 +4,6 @@
#include "http_svr.h"
#include "user_errno.h"
#include "haywire.h"
#include "misc.h"
#include "config.h"
int http_svr_init() {