diff --git a/src/actions.c b/src/actions.c index 29211b8..3460ad8 100644 --- a/src/actions.c +++ b/src/actions.c @@ -145,7 +145,7 @@ static action* action_stack_element_action(action_stack_element *ase) { } } -action_result action_execute(server *srv, connection *con) { +action_result action_execute(connection *con) { action *a; action_stack *as = &con->action_stack; action_stack_element *ase; @@ -154,31 +154,31 @@ action_result action_execute(server *srv, connection *con) { while (NULL != (ase = action_stack_top(as))) { a = action_stack_element_action(ase); if (!a) { - action_stack_pop(srv, as); + action_stack_pop(con->srv, as); continue; } - srv->stats.actions_executed++; + con->srv->stats.actions_executed++; switch (a->type) { case ACTION_TSETTING: con->options[a->value.setting.ndx] = a->value.setting.value; break; case ACTION_TFUNCTION: - res = a->value.function.func(srv, con, a->value.function.param); + res = a->value.function.func(con, a->value.function.param); switch (res) { case ACTION_GO_ON: case ACTION_FINISHED: break; case ACTION_ERROR: - action_stack_reset(srv, as); + action_stack_reset(con->srv, as); return res; case ACTION_WAIT_FOR_EVENT: return ACTION_WAIT_FOR_EVENT; } break; case ACTION_TCONDITION: - if (condition_check(srv, con, a->value.condition.cond)) { + if (condition_check(con, a->value.condition.cond)) { action_enter(con, a->value.condition.target); } else if (a->value.condition.target_else) { diff --git a/src/actions.h b/src/actions.h index fbfe47b..98b6243 100644 --- a/src/actions.h +++ b/src/actions.h @@ -29,7 +29,7 @@ struct action_stack { }; struct server; struct connection; -typedef action_result (*ActionFunc)(struct server *srv, struct connection *con, gpointer param); +typedef action_result (*ActionFunc)(struct connection *con, gpointer param); typedef void (*ActionFree)(struct server *srv, gpointer param); struct action_func { @@ -69,7 +69,7 @@ LI_API void action_stack_clear(server *srv, action_stack *as); /** handle sublist now, remember current position (stack) */ LI_API void action_enter(connection *con, action *a); -LI_API action_result action_execute(server *srv, connection *con); +LI_API action_result action_execute(connection *con); LI_API void action_release(server *srv, action *a); diff --git a/src/base.h b/src/base.h index 6726663..106de00 100644 --- a/src/base.h +++ b/src/base.h @@ -38,6 +38,7 @@ typedef struct connection connection; #include "server.h" +#include "worker.h" #include "actions.h" #include "options.h" #include "plugin.h" diff --git a/src/chunk.c b/src/chunk.c index dff72cd..c67bad0 100644 --- a/src/chunk.c +++ b/src/chunk.c @@ -42,16 +42,16 @@ static void chunkfile_release(chunkfile *cf) { /* open the file cf->name if it is not already opened for reading * may return HANDLER_GO_ON, HANDLER_ERROR, HANDLER_WAIT_FOR_FD */ -handler_t chunkfile_open(server *srv, connection *con, chunkfile *cf) { +handler_t chunkfile_open(connection *con, chunkfile *cf) { if (!cf) return HANDLER_ERROR; if (-1 != cf->fd) return HANDLER_GO_ON; if (!cf->name) { - CON_ERROR(srv, con, "%s", "Missing filename for FILE_CHUNK"); + CON_ERROR(con, "%s", "Missing filename for FILE_CHUNK"); return HANDLER_ERROR; } if (-1 == (cf->fd = open(cf->name->str, O_RDONLY))) { if (EMFILE == errno) return HANDLER_WAIT_FOR_FD; - CON_ERROR(srv, con, "Couldn't open file '%s': %s", GSTR_SAFE_STR(cf->name), g_strerror(errno)); + CON_ERROR(con, "Couldn't open file '%s': %s", GSTR_SAFE_STR(cf->name), g_strerror(errno)); return HANDLER_ERROR; } #ifdef FD_CLOEXEC @@ -61,7 +61,7 @@ handler_t chunkfile_open(server *srv, connection *con, chunkfile *cf) { /* tell the kernel that we want to stream the file */ if (-1 == posix_fadvise(cf->fd, 0, 0, POSIX_FADV_SEQUENTIAL)) { if (ENOSYS != errno) { - CON_ERROR(srv, con, "posix_fadvise failed for '%s': %s (%i)", GSTR_SAFE_STR(cf->name), g_strerror(errno), cf->fd); + CON_ERROR(con, "posix_fadvise failed for '%s': %s (%i)", GSTR_SAFE_STR(cf->name), g_strerror(errno), cf->fd); } } #endif @@ -82,7 +82,7 @@ handler_t chunkfile_open(server *srv, connection *con, chunkfile *cf) { * the data is _not_ marked as "done" * may return HANDLER_GO_ON, HANDLER_ERROR, HANDLER_WAIT_FOR_FD */ -handler_t chunkiter_read(server *srv, connection *con, chunkiter iter, off_t start, off_t length, char **data_start, off_t *data_len) { +handler_t chunkiter_read(connection *con, chunkiter iter, off_t start, off_t length, char **data_start, off_t *data_len) { chunk *c = chunkiter_chunk(iter); off_t we_want, we_have, our_start, our_offset; handler_t res = HANDLER_GO_ON; @@ -102,7 +102,7 @@ handler_t chunkiter_read(server *srv, connection *con, chunkiter iter, off_t sta *data_len = length; break; case FILE_CHUNK: - if (HANDLER_GO_ON != (res = chunkfile_open(srv, con, c->file.file))) return res; + if (HANDLER_GO_ON != (res = chunkfile_open(con, c->file.file))) return res; if (length > MAX_MMAP_CHUNK) length = MAX_MMAP_CHUNK; @@ -139,11 +139,11 @@ handler_t chunkiter_read(server *srv, connection *con, chunkiter iter, off_t sta if (-1 == lseek(c->file.file->fd, our_start, SEEK_SET)) { /* prefer the error of the first syscall */ if (0 != mmap_errno) { - CON_ERROR(srv, con, "mmap failed for '%s' (fd = %i): %s", + CON_ERROR(con, "mmap failed for '%s' (fd = %i): %s", GSTR_SAFE_STR(c->file.file->name), c->file.file->fd, g_strerror(mmap_errno)); } else { - CON_ERROR(srv, con, "lseek failed for '%s' (fd = %i): %s", + CON_ERROR(con, "lseek failed for '%s' (fd = %i): %s", GSTR_SAFE_STR(c->file.file->name), c->file.file->fd, g_strerror(errno)); } @@ -156,11 +156,11 @@ read_chunk: if (EINTR == errno) goto read_chunk; /* prefer the error of the first syscall */ if (0 != mmap_errno) { - CON_ERROR(srv, con, "mmap failed for '%s' (fd = %i): %s", + CON_ERROR(con, "mmap failed for '%s' (fd = %i): %s", GSTR_SAFE_STR(c->file.file->name), c->file.file->fd, g_strerror(mmap_errno)); } else { - CON_ERROR(srv, con, "read failed for '%s' (fd = %i): %s", + CON_ERROR(con, "read failed for '%s' (fd = %i): %s", GSTR_SAFE_STR(c->file.file->name), c->file.file->fd, g_strerror(errno)); } @@ -169,7 +169,7 @@ read_chunk: return HANDLER_ERROR; } else if (we_have != we_want) { /* may return less than requested bytes due to signals */ - /* CON_TRACE(srv, con, "read return unexpected number of bytes"); */ + /* CON_TRACE(srv, "read return unexpected number of bytes"); */ we_want = we_have; if (length > we_have) length = we_have; c->file.mmap.length = we_want; @@ -180,7 +180,7 @@ read_chunk: /* don't advise files < 64Kb */ if (c->file.mmap.length > (64*1024) && 0 != madvise(c->file.mmap.data, c->file.mmap.length, MADV_WILLNEED)) { - CON_ERROR(srv, con, "madvise failed for '%s' (fd = %i): %s", + CON_ERROR(con, "madvise failed for '%s' (fd = %i): %s", GSTR_SAFE_STR(c->file.file->name), c->file.file->fd, g_strerror(errno)); } diff --git a/src/chunk.h b/src/chunk.h index 68f6945..18e9743 100644 --- a/src/chunk.h +++ b/src/chunk.h @@ -76,7 +76,7 @@ struct chunkiter { /* open the file cf->name if it is not already opened for reading * may return HANDLER_GO_ON, HANDLER_ERROR, HANDLER_WAIT_FOR_FD */ -LI_API handler_t chunkfile_open(struct server *srv, struct connection *con, chunkfile *cf); +LI_API handler_t chunkfile_open(struct connection *con, chunkfile *cf); /****************** * chunk iterator * @@ -92,7 +92,7 @@ INLINE goffset chunkiter_length(chunkiter iter); * the data is _not_ marked as "done" * may return HANDLER_GO_ON, HANDLER_ERROR, HANDLER_WAIT_FOR_FD */ -LI_API handler_t chunkiter_read(struct server *srv, struct connection *con, chunkiter iter, off_t start, off_t length, char **data_start, off_t *data_len); +LI_API handler_t chunkiter_read(struct connection *con, chunkiter iter, off_t start, off_t length, char **data_start, off_t *data_len); /****************** * chunk * diff --git a/src/chunk_parser.c b/src/chunk_parser.c index 6e038b2..5058db5 100644 --- a/src/chunk_parser.c +++ b/src/chunk_parser.c @@ -23,7 +23,7 @@ handler_t chunk_parser_prepare(chunk_parser_ctx *ctx) { return HANDLER_GO_ON; } -handler_t chunk_parser_next(server *srv, connection *con, chunk_parser_ctx *ctx, char **p, char **pe) { +handler_t chunk_parser_next(connection *con, chunk_parser_ctx *ctx, char **p, char **pe) { off_t l; handler_t res; @@ -39,7 +39,7 @@ handler_t chunk_parser_next(server *srv, connection *con, chunk_parser_ctx *ctx, if (NULL == ctx->curi.element) return HANDLER_WAIT_FOR_EVENT; - if (HANDLER_GO_ON != (res = chunkiter_read(srv, con, ctx->curi, ctx->start, l - ctx->start, &ctx->buf, &ctx->length))) { + if (HANDLER_GO_ON != (res = chunkiter_read(con, ctx->curi, ctx->start, l - ctx->start, &ctx->buf, &ctx->length))) { return res; } @@ -53,7 +53,7 @@ void chunk_parser_done(chunk_parser_ctx *ctx, goffset len) { ctx->start += len; } -gboolean chunk_extract_to(server *srv, connection *con, chunk_parser_mark from, chunk_parser_mark to, GString *dest) { +gboolean chunk_extract_to(connection *con, chunk_parser_mark from, chunk_parser_mark to, GString *dest) { g_string_set_size(dest, 0); chunk_parser_mark i; @@ -62,7 +62,7 @@ gboolean chunk_extract_to(server *srv, connection *con, chunk_parser_mark from, while (i.pos < len) { char *buf; off_t we_have; - if (HANDLER_GO_ON != chunkiter_read(srv, con, i.ci, i.pos, len - i.pos, &buf, &we_have)) goto error; + if (HANDLER_GO_ON != chunkiter_read(con, i.ci, i.pos, len - i.pos, &buf, &we_have)) goto error; g_string_append_len(dest, buf, we_have); i.pos += we_have; } @@ -71,7 +71,7 @@ gboolean chunk_extract_to(server *srv, connection *con, chunk_parser_mark from, while (i.pos < to.pos) { char *buf; off_t we_have; - if (HANDLER_GO_ON != chunkiter_read(srv, con, i.ci, i.pos, to.pos - i.pos, &buf, &we_have)) goto error; + if (HANDLER_GO_ON != chunkiter_read(con, i.ci, i.pos, to.pos - i.pos, &buf, &we_have)) goto error; g_string_append_len(dest, buf, we_have); i.pos += we_have; } @@ -83,9 +83,9 @@ error: return FALSE; } -GString* chunk_extract(server *srv, connection *con, chunk_parser_mark from, chunk_parser_mark to) { +GString* chunk_extract(connection *con, chunk_parser_mark from, chunk_parser_mark to) { GString *str = g_string_sized_new(0); - if (chunk_extract_to(srv, con, from, to, str)) return str; + if (chunk_extract_to(con, from, to, str)) return str; g_string_free(str, TRUE); return NULL; } diff --git a/src/chunk_parser.h b/src/chunk_parser.h index cd8f8d2..c736e96 100644 --- a/src/chunk_parser.h +++ b/src/chunk_parser.h @@ -32,11 +32,11 @@ struct chunk_parser_mark { LI_API void chunk_parser_init(chunk_parser_ctx *ctx, chunkqueue *cq); LI_API void chunk_parser_reset(chunk_parser_ctx *ctx); LI_API handler_t chunk_parser_prepare(chunk_parser_ctx *ctx); -LI_API handler_t chunk_parser_next(struct server *srv, struct connection *con, chunk_parser_ctx *ctx, char **p, char **pe); +LI_API handler_t chunk_parser_next(struct connection *con, chunk_parser_ctx *ctx, char **p, char **pe); LI_API void chunk_parser_done(chunk_parser_ctx *ctx, goffset len); -LI_API gboolean chunk_extract_to(struct server *srv, struct connection *con, chunk_parser_mark from, chunk_parser_mark to, GString *dest); -LI_API GString* chunk_extract(struct server *srv, struct connection *con, chunk_parser_mark from, chunk_parser_mark to); +LI_API gboolean chunk_extract_to(struct connection *con, chunk_parser_mark from, chunk_parser_mark to, GString *dest); +LI_API GString* chunk_extract(struct connection *con, chunk_parser_mark from, chunk_parser_mark to); INLINE chunk_parser_mark chunk_parser_getmark(chunk_parser_ctx *ctx, const char *fpc); diff --git a/src/condition.c b/src/condition.c index 9516e65..91114d3 100644 --- a/src/condition.c +++ b/src/condition.c @@ -248,11 +248,9 @@ const char* cond_lvalue_to_string(cond_lvalue_t t) { } /* COND_VALUE_STRING and COND_VALUE_REGEXP only */ -static gboolean condition_check_eval_string(server *srv, connection *con, condition *cond) { +static gboolean condition_check_eval_string(connection *con, condition *cond) { const char *value = ""; gboolean result = FALSE; - UNUSED(srv); - UNUSED(con); switch (cond->lvalue->type) { case COMP_REQUEST_LOCALIP: @@ -283,17 +281,17 @@ static gboolean condition_check_eval_string(server *srv, connection *con, condit /* TODO: physical path exists */ break; case COMP_REQUEST_HEADER: - http_header_get_fast(srv->tmp_str, con->request.headers, GSTR_LEN(cond->lvalue->key)); - value = srv->tmp_str->str; + http_header_get_fast(con->wrk->tmp_str, con->request.headers, GSTR_LEN(cond->lvalue->key)); + value = con->wrk->tmp_str->str; break; case COMP_PHYSICAL_SIZE: /* TODO: physical size */ - g_string_printf(srv->tmp_str, "%"L_GOFFSET_FORMAT, (goffset) 0); - value = srv->tmp_str->str; + g_string_printf(con->wrk->tmp_str, "%"L_GOFFSET_FORMAT, (goffset) 0); + value = con->wrk->tmp_str->str; break; case COMP_REQUEST_CONTENT_LENGTH: - g_string_printf(srv->tmp_str, "%"L_GOFFSET_FORMAT, con->request.content_length); - value = srv->tmp_str->str; + g_string_printf(con->wrk->tmp_str, "%"L_GOFFSET_FORMAT, con->request.content_length); + value = con->wrk->tmp_str->str; break; } @@ -320,9 +318,9 @@ static gboolean condition_check_eval_string(server *srv, connection *con, condit case CONFIG_COND_NOMATCH: #ifdef HAVE_PCRE_H /* TODO: pcre */ - ERROR(srv, "%s", "regexp match not supported yet"); + CON_ERROR(con, "%s", "regexp match not supported yet"); #else - ERROR(srv, "compiled without pcre, cannot use '%s'", comp_op_to_string(cond->op)); + CON_ERROR(con, "compiled without pcre, cannot use '%s'", comp_op_to_string(cond->op)); #endif break; case CONFIG_COND_IP: @@ -331,7 +329,7 @@ static gboolean condition_check_eval_string(server *srv, connection *con, condit case CONFIG_COND_GT: case CONFIG_COND_LE: case CONFIG_COND_LT: - ERROR(srv, "cannot compare string/regexp with '%s'", comp_op_to_string(cond->op)); + CON_ERROR(con, "cannot compare string/regexp with '%s'", comp_op_to_string(cond->op)); break; } @@ -339,9 +337,7 @@ static gboolean condition_check_eval_string(server *srv, connection *con, condit } -static gboolean condition_check_eval_int(server *srv, connection *con, condition *cond) { - UNUSED(srv); - UNUSED(con); +static gboolean condition_check_eval_int(connection *con, condition *cond) { gint64 value; switch (cond->lvalue->type) { @@ -351,7 +347,7 @@ static gboolean condition_check_eval_int(server *srv, connection *con, condition value = con->physical.size; break; default: - CON_ERROR(srv, con, "couldn't get int value for '%s', using -1", cond_lvalue_to_string(cond->lvalue->type)); + CON_ERROR(con, "couldn't get int value for '%s', using -1", cond_lvalue_to_string(cond->lvalue->type)); value = -1; } @@ -376,7 +372,7 @@ static gboolean condition_check_eval_int(server *srv, connection *con, condition case CONFIG_COND_NOMATCH: case CONFIG_COND_IP: case CONFIG_COND_NOTIP: - ERROR(srv, "cannot compare int with '%s'", comp_op_to_string(cond->op)); + CON_ERROR(con, "cannot compare int with '%s'", comp_op_to_string(cond->op)); return FALSE; } @@ -425,12 +421,10 @@ static gboolean ip_in_net(condition_rvalue *target, condition_rvalue *network) { } /* CONFIG_COND_IP and CONFIG_COND_NOTIP only */ -static gboolean condition_check_eval_ip(server *srv, connection *con, condition *cond) { +static gboolean condition_check_eval_ip(connection *con, condition *cond) { condition_rvalue ipval; const char *value = NULL; gboolean result = FALSE; - UNUSED(srv); - UNUSED(con); ipval.type = COND_VALUE_INT; @@ -444,34 +438,34 @@ static gboolean condition_check_eval_ip(server *srv, connection *con, condition return (cond->op == CONFIG_COND_NOTIP); break; case COMP_REQUEST_PATH: - ERROR(srv, "%s", "Cannot parse request.path as ip"); + CON_ERROR(con, "%s", "Cannot parse request.path as ip"); return (cond->op == CONFIG_COND_NOTIP); break; case COMP_REQUEST_HOST: value = con->request.uri.host->str; break; case COMP_REQUEST_SCHEME: - ERROR(srv, "%s", "Cannot parse request.scheme as ip"); + CON_ERROR(con, "%s", "Cannot parse request.scheme as ip"); return (cond->op == CONFIG_COND_NOTIP); case COMP_REQUEST_QUERY_STRING: value = con->request.uri.query->str; break; case COMP_REQUEST_METHOD: - ERROR(srv, "%s", "Cannot request.method as ip"); + CON_ERROR(con, "%s", "Cannot request.method as ip"); return (cond->op == CONFIG_COND_NOTIP); break; case COMP_PHYSICAL_PATH: case COMP_PHYSICAL_PATH_EXISTS: - ERROR(srv, "%s", "Cannot physical.path(-exists) as ip"); + CON_ERROR(con, "%s", "Cannot physical.path(-exists) as ip"); return (cond->op == CONFIG_COND_NOTIP); break; case COMP_REQUEST_HEADER: - http_header_get_fast(srv->tmp_str, con->request.headers, GSTR_LEN(cond->lvalue->key)); - value = srv->tmp_str->str; + http_header_get_fast(con->wrk->tmp_str, con->request.headers, GSTR_LEN(cond->lvalue->key)); + value = con->wrk->tmp_str->str; break; case COMP_PHYSICAL_SIZE: case COMP_REQUEST_CONTENT_LENGTH: - ERROR(srv, "%s", "Cannot parse integers as ip"); + CON_ERROR(con, "%s", "Cannot parse integers as ip"); return (cond->op == CONFIG_COND_NOTIP); break; } @@ -498,25 +492,25 @@ static gboolean condition_check_eval_ip(server *srv, connection *con, condition case CONFIG_COND_GT: case CONFIG_COND_LE: case CONFIG_COND_LT: - ERROR(srv, "cannot match ips with '%s'", comp_op_to_string(cond->op)); + CON_ERROR(con, "cannot match ips with '%s'", comp_op_to_string(cond->op)); break; } return result; } -gboolean condition_check(server *srv, connection *con, condition *cond) { +gboolean condition_check(connection *con, condition *cond) { switch (cond->rvalue.type) { case COND_VALUE_STRING: #ifdef HAVE_PCRE_H case COND_VALUE_REGEXP: #endif - return condition_check_eval_string(srv, con, cond); + return condition_check_eval_string(con, cond); case COND_VALUE_INT: - return condition_check_eval_int(srv, con, cond); + return condition_check_eval_int(con, cond); case COND_VALUE_SOCKET_IPV4: case COND_VALUE_SOCKET_IPV6: - return condition_check_eval_ip(srv, con, cond); + return condition_check_eval_ip(con, cond); } return FALSE; } diff --git a/src/condition.h b/src/condition.h index 152fcb2..aca3901 100644 --- a/src/condition.h +++ b/src/condition.h @@ -125,7 +125,7 @@ LI_API void condition_release(server *srv, condition* c); LI_API const char* comp_op_to_string(comp_operator_t op); LI_API const char* cond_lvalue_to_string(cond_lvalue_t t); -LI_API gboolean condition_check(server *srv, connection *con, condition *cond); +LI_API gboolean condition_check(connection *con, condition *cond); /* parser */ /** parse an IPv4 (if netmask is not NULL with cidr netmask) */ diff --git a/src/connection.c b/src/connection.c index 6be33af..0926b2f 100644 --- a/src/connection.c +++ b/src/connection.c @@ -1,25 +1,24 @@ -#include "connection.h" +#include "base.h" #include "network.h" #include "utils.h" #include "plugin_core.h" -void con_put(server *srv, connection *con); /* server.c */ +void con_put(connection *con); /* server.c */ -void internal_error(server *srv, connection *con) { +void internal_error(connection *con) { if (con->response_headers_sent) { - CON_ERROR(srv, con, "%s", "Couldn't send '500 Internal Error': headers already sent"); - connection_set_state(srv, con, CON_STATE_ERROR); + CON_ERROR(con, "%s", "Couldn't send '500 Internal Error': headers already sent"); + connection_set_state(con, CON_STATE_ERROR); } else { http_headers_reset(con->response.headers); con->response.http_status = 500; con->content_handler = NULL; - connection_set_state(srv, con, CON_STATE_WRITE_RESPONSE); + connection_set_state(con, CON_STATE_WRITE_RESPONSE); } } -static void parse_request_body(server *srv, connection *con) { - UNUSED(srv); +static void parse_request_body(connection *con) { if ( con->state >= CON_STATE_READ_REQUEST_CONTENT && con->state <= CON_STATE_WRITE_RESPONSE && !con->in->is_closed) { @@ -35,8 +34,7 @@ static void parse_request_body(server *srv, connection *con) { } } -static void forward_response_body(server *srv, connection *con) { - UNUSED(srv); +static void forward_response_body(connection *con) { if (con->state == CON_STATE_WRITE_RESPONSE && !con->raw_out->is_closed) { if (con->out->length > 0) { /* TODO: chunked encoding, filters */ @@ -45,17 +43,15 @@ static void forward_response_body(server *srv, connection *con) { if (con->in->is_closed && 0 == con->raw_out->length) con->raw_out->is_closed = TRUE; if (con->raw_out->length > 0) { - ev_io_add_events(srv->loop, &con->sock.watcher, EV_WRITE); + ev_io_add_events(con->wrk->loop, &con->sock_watcher, EV_WRITE); } else { - ev_io_rem_events(srv->loop, &con->sock.watcher, EV_WRITE); + ev_io_rem_events(con->wrk->loop, &con->sock_watcher, EV_WRITE); } } } static void connection_cb(struct ev_loop *loop, ev_io *w, int revents) { - connection_socket *con_sock = (connection_socket*) w->data; - server *srv = con_sock->srv; - connection *con = con_sock->con; + connection *con = (connection*) w->data; gboolean dojoblist = FALSE; UNUSED(loop); @@ -64,19 +60,19 @@ static void connection_cb(struct ev_loop *loop, ev_io *w, int revents) { /* don't read the next request before current one is done */ ev_io_rem_events(loop, w, EV_READ); } else { - switch (network_read(srv, con, w->fd, con->raw_in)) { + switch (network_read(con, w->fd, con->raw_in)) { case NETWORK_STATUS_SUCCESS: dojoblist = TRUE; break; case NETWORK_STATUS_FATAL_ERROR: - CON_ERROR(srv, con, "%s", "network read fatal error"); - connection_set_state(srv, con, CON_STATE_ERROR); + CON_ERROR(con, "%s", "network read fatal error"); + connection_set_state(con, CON_STATE_ERROR); dojoblist = TRUE; break; case NETWORK_STATUS_CONNECTION_CLOSE: con->raw_in->is_closed = TRUE; shutdown(w->fd, SHUT_RD); - connection_set_state(srv, con, CON_STATE_CLOSE); + connection_set_state(con, CON_STATE_CLOSE); dojoblist = TRUE; break; case NETWORK_STATUS_WAIT_FOR_EVENT: @@ -95,17 +91,17 @@ static void connection_cb(struct ev_loop *loop, ev_io *w, int revents) { if (revents & EV_WRITE) { if (con->raw_out->length > 0) { - switch (network_write(srv, con, w->fd, con->raw_out)) { + switch (network_write(con, w->fd, con->raw_out)) { case NETWORK_STATUS_SUCCESS: dojoblist = TRUE; break; case NETWORK_STATUS_FATAL_ERROR: - CON_ERROR(srv, con, "%s", "network write fatal error"); - connection_set_state(srv, con, CON_STATE_ERROR); + CON_ERROR(con, "%s", "network write fatal error"); + connection_set_state(con, CON_STATE_ERROR); dojoblist = TRUE; break; case NETWORK_STATUS_CONNECTION_CLOSE: - connection_set_state(srv, con, CON_STATE_CLOSE); + connection_set_state(con, CON_STATE_CLOSE); dojoblist = TRUE; break; case NETWORK_STATUS_WAIT_FOR_EVENT: @@ -127,26 +123,26 @@ static void connection_cb(struct ev_loop *loop, ev_io *w, int revents) { } if (dojoblist) - joblist_append(srv, con); + joblist_append(con); } static void connection_keepalive_cb(struct ev_loop *loop, ev_timer *w, int revents) { connection *con = (connection*) w->data; UNUSED(loop); UNUSED(revents); - con_put(con->sock.srv, con); + con_put(con); } connection* connection_new(server *srv) { connection *con = g_slice_new0(connection); - UNUSED(srv); + con->srv = srv; con->state = CON_STATE_DEAD; con->response_headers_sent = FALSE; con->expect_100_cont = FALSE; - ev_init(&con->sock.watcher, connection_cb); - ev_io_set(&con->sock.watcher, -1, 0); - con->sock.srv = srv; con->sock.con = con; con->sock.watcher.data = &con->sock; + ev_init(&con->sock_watcher, connection_cb); + ev_io_set(&con->sock_watcher, -1, 0); + con->sock_watcher.data = con; con->remote_addr_str = g_string_sized_new(0); con->local_addr_str = g_string_sized_new(0); con->keep_alive = TRUE; @@ -173,21 +169,21 @@ connection* connection_new(server *srv) { return con; } -void connection_reset(server *srv, connection *con) { +void connection_reset(connection *con) { con->state = CON_STATE_DEAD; con->response_headers_sent = FALSE; con->expect_100_cont = FALSE; - ev_io_stop(srv->loop, &con->sock.watcher); - if (con->sock.watcher.fd != -1) { + ev_io_stop(con->wrk->loop, &con->sock_watcher); + if (con->sock_watcher.fd != -1) { if (con->raw_in->is_closed) { /* read already shutdown */ - shutdown(con->sock.watcher.fd, SHUT_WR); - close(con->sock.watcher.fd); + shutdown(con->sock_watcher.fd, SHUT_WR); + close(con->sock_watcher.fd); } else { - server_add_closing_socket(srv, con->sock.watcher.fd); + worker_add_closing_socket(con->wrk, con->sock_watcher.fd); } } - ev_io_set(&con->sock.watcher, -1, 0); + ev_io_set(&con->sock_watcher, -1, 0); g_string_truncate(con->remote_addr_str, 0); g_string_truncate(con->local_addr_str, 0); con->keep_alive = TRUE; @@ -197,43 +193,43 @@ void connection_reset(server *srv, connection *con) { chunkqueue_reset(con->in); chunkqueue_reset(con->out); - action_stack_reset(srv, &con->action_stack); + action_stack_reset(con->srv, &con->action_stack); - memcpy(con->options, srv->option_def_values, srv->option_count * sizeof(*srv->option_def_values)); + memcpy(con->options, con->srv->option_def_values, con->srv->option_count * sizeof(*con->srv->option_def_values)); request_reset(&con->request); physical_reset(&con->physical); response_reset(&con->response); if (con->keep_alive_data.link) { - g_queue_delete_link(&srv->keep_alive_queue, con->keep_alive_data.link); + g_queue_delete_link(&con->wrk->keep_alive_queue, con->keep_alive_data.link); con->keep_alive_data.link = NULL; } con->keep_alive_data.timeout = 0; con->keep_alive_data.max_idle = 0; - ev_timer_stop(srv->loop, &con->keep_alive_data.watcher); + ev_timer_stop(con->wrk->loop, &con->keep_alive_data.watcher); } void server_check_keepalive(server *srv); -void connection_reset_keep_alive(server *srv, connection *con) { - ev_timer_stop(srv->loop, &con->keep_alive_data.watcher); +void connection_reset_keep_alive(connection *con) { + ev_timer_stop(con->wrk->loop, &con->keep_alive_data.watcher); { con->keep_alive_data.max_idle = GPOINTER_TO_INT(CORE_OPTION(CORE_OPTION_MAX_KEEP_ALIVE_IDLE)); if (con->keep_alive_data.max_idle == 0) { - con_put(srv, con); + con_put(con); return; } - if (con->keep_alive_data.max_idle >= srv->keep_alive_queue_timeout) { + if (con->keep_alive_data.max_idle >= con->srv->keep_alive_queue_timeout) { /* queue is sorted by con->keep_alive_data.timeout */ - gboolean need_start = (0 == srv->keep_alive_queue.length); - con->keep_alive_data.timeout = ev_now((srv)->loop) + srv->keep_alive_queue_timeout; - g_queue_push_tail(&srv->keep_alive_queue, con); - con->keep_alive_data.link = g_queue_peek_tail_link(&srv->keep_alive_queue); + gboolean need_start = (0 == con->wrk->keep_alive_queue.length); + con->keep_alive_data.timeout = ev_now(con->wrk->loop) + con->srv->keep_alive_queue_timeout; + g_queue_push_tail(&con->wrk->keep_alive_queue, con); + con->keep_alive_data.link = g_queue_peek_tail_link(&con->wrk->keep_alive_queue); if (need_start) - server_check_keepalive(srv); + worker_check_keepalive(con->wrk); } else { ev_timer_set(&con->keep_alive_data.watcher, con->keep_alive_data.max_idle, 0); - ev_timer_start(srv->loop, &con->keep_alive_data.watcher); + ev_timer_start(con->wrk->loop, &con->keep_alive_data.watcher); } } @@ -241,7 +237,7 @@ void connection_reset_keep_alive(server *srv, connection *con) { con->response_headers_sent = FALSE; con->expect_100_cont = FALSE; - ev_io_set_events(srv->loop, &con->sock.watcher, EV_READ); + ev_io_set_events(con->wrk->loop, &con->sock_watcher, EV_READ); g_string_truncate(con->remote_addr_str, 0); g_string_truncate(con->local_addr_str, 0); con->keep_alive = TRUE; @@ -250,30 +246,30 @@ void connection_reset_keep_alive(server *srv, connection *con) { chunkqueue_reset(con->in); chunkqueue_reset(con->out); - action_stack_reset(srv, &con->action_stack); + action_stack_reset(con->srv, &con->action_stack); - memcpy(con->options, srv->option_def_values, srv->option_count * sizeof(*srv->option_def_values)); + memcpy(con->options, con->srv->option_def_values, con->srv->option_count * sizeof(*con->srv->option_def_values)); request_reset(&con->request); physical_reset(&con->physical); response_reset(&con->response); } -void connection_free(server *srv, connection *con) { +void connection_free(connection *con) { con->state = CON_STATE_DEAD; con->response_headers_sent = FALSE; con->expect_100_cont = FALSE; - ev_io_stop(srv->loop, &con->sock.watcher); - if (con->sock.watcher.fd != -1) { + ev_io_stop(con->wrk->loop, &con->sock_watcher); + if (con->sock_watcher.fd != -1) { if (con->raw_in->is_closed) { /* read already shutdown */ - shutdown(con->sock.watcher.fd, SHUT_WR); - close(con->sock.watcher.fd); + shutdown(con->sock_watcher.fd, SHUT_WR); + close(con->sock_watcher.fd); } else { - server_add_closing_socket(srv, con->sock.watcher.fd); + worker_add_closing_socket(con->wrk, con->sock_watcher.fd); } } - ev_io_set(&con->sock.watcher, -1, 0); + ev_io_set(&con->sock_watcher, -1, 0); g_string_free(con->remote_addr_str, TRUE); g_string_free(con->local_addr_str, TRUE); con->keep_alive = TRUE; @@ -283,34 +279,34 @@ void connection_free(server *srv, connection *con) { chunkqueue_free(con->in); chunkqueue_free(con->out); - action_stack_clear(srv, &con->action_stack); + action_stack_clear(con->srv, &con->action_stack); - g_slice_free1(srv->option_count * sizeof(*srv->option_def_values), con->options); + g_slice_free1(con->srv->option_count * sizeof(*con->srv->option_def_values), con->options); request_clear(&con->request); physical_clear(&con->physical); response_clear(&con->response); if (con->keep_alive_data.link) { - g_queue_delete_link(&srv->keep_alive_queue, con->keep_alive_data.link); + g_queue_delete_link(&con->wrk->keep_alive_queue, con->keep_alive_data.link); con->keep_alive_data.link = NULL; } con->keep_alive_data.timeout = 0; con->keep_alive_data.max_idle = 0; - ev_timer_stop(srv->loop, &con->keep_alive_data.watcher); + ev_timer_stop(con->wrk->loop, &con->keep_alive_data.watcher); g_slice_free(connection, con); } -void connection_set_state(server *srv, connection *con, connection_state_t state) { +void connection_set_state(connection *con, connection_state_t state) { if (state < con->state) { - CON_ERROR(srv, con, "Cannot move into requested state: %i => %i, move to error state", con->state, state); + CON_ERROR(con, "Cannot move into requested state: %i => %i, move to error state", con->state, state); state = CON_STATE_ERROR; } con->state = state; } -void connection_state_machine(server *srv, connection *con) { +void connection_state_machine(connection *con) { gboolean done = FALSE; do { switch (con->state) { @@ -322,31 +318,31 @@ void connection_state_machine(server *srv, connection *con) { if (con->raw_in->length > 0) { /* stop keep alive timeout watchers */ if (con->keep_alive_data.link) { - g_queue_delete_link(&srv->keep_alive_queue, con->keep_alive_data.link); + g_queue_delete_link(&con->wrk->keep_alive_queue, con->keep_alive_data.link); con->keep_alive_data.link = NULL; } con->keep_alive_data.timeout = 0; - ev_timer_stop(srv->loop, &con->keep_alive_data.watcher); + ev_timer_stop(con->wrk->loop, &con->keep_alive_data.watcher); - connection_set_state(srv, con, CON_STATE_REQUEST_START); + connection_set_state(con, CON_STATE_REQUEST_START); } else done = TRUE; break; case CON_STATE_REQUEST_START: - connection_set_state(srv, con, CON_STATE_READ_REQUEST_HEADER); - action_enter(con, srv->mainaction); + connection_set_state(con, CON_STATE_READ_REQUEST_HEADER); + action_enter(con, con->srv->mainaction); break; case CON_STATE_READ_REQUEST_HEADER: if (CORE_OPTION(CORE_OPTION_DEBUG_REQUEST_HANDLING)) { - TRACE(srv, "%s", "reading request header"); + CON_TRACE(con, "%s", "reading request header"); } - switch(http_request_parse(srv, con, &con->request.parser_ctx)) { + switch(http_request_parse(con, &con->request.parser_ctx)) { case HANDLER_FINISHED: case HANDLER_GO_ON: - connection_set_state(srv, con, CON_STATE_VALIDATE_REQUEST_HEADER); + connection_set_state(con, CON_STATE_VALIDATE_REQUEST_HEADER); break; case HANDLER_WAIT_FOR_FD: /* TODO: wait for fd */ @@ -358,37 +354,37 @@ void connection_state_machine(server *srv, connection *con) { case HANDLER_ERROR: case HANDLER_COMEBACK: /* unexpected */ /* unparsable header */ - connection_set_state(srv, con, CON_STATE_ERROR); + connection_set_state(con, CON_STATE_ERROR); break; } break; case CON_STATE_VALIDATE_REQUEST_HEADER: if (CORE_OPTION(CORE_OPTION_DEBUG_REQUEST_HANDLING)) { - TRACE(srv, "%s", "validating request header"); + CON_TRACE(con, "%s", "validating request header"); } - connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST_HEADER); - request_validate_header(srv, con); - srv->stats.requests++; + connection_set_state(con, CON_STATE_HANDLE_REQUEST_HEADER); + request_validate_header(con); + con->srv->stats.requests++; break; case CON_STATE_HANDLE_REQUEST_HEADER: if (CORE_OPTION(CORE_OPTION_DEBUG_REQUEST_HANDLING)) { - TRACE(srv, "%s", "handle request header"); + CON_TRACE(con, "%s", "handle request header"); } - switch (action_execute(srv, con)) { + switch (action_execute(con)) { case ACTION_WAIT_FOR_EVENT: done = TRUE; break; case ACTION_GO_ON: case ACTION_FINISHED: if (con->state == CON_STATE_HANDLE_REQUEST_HEADER) { - internal_error(srv, con); + internal_error(con); } - connection_set_state(srv, con, CON_STATE_WRITE_RESPONSE); + connection_set_state(con, CON_STATE_WRITE_RESPONSE); break; case ACTION_ERROR: - internal_error(srv, con); + internal_error(con); break; } break; @@ -396,62 +392,62 @@ void connection_state_machine(server *srv, connection *con) { case CON_STATE_READ_REQUEST_CONTENT: case CON_STATE_HANDLE_RESPONSE_HEADER: if (CORE_OPTION(CORE_OPTION_DEBUG_REQUEST_HANDLING)) { - TRACE(srv, "%s", "read request/handle response header"); + CON_TRACE(con, "%s", "read request/handle response header"); } if (con->expect_100_cont) { if (CORE_OPTION(CORE_OPTION_DEBUG_REQUEST_HANDLING)) { - TRACE(srv, "%s", "send 100 Continue"); + CON_TRACE(con, "%s", "send 100 Continue"); } chunkqueue_append_mem(con->raw_out, CONST_STR_LEN("HTTP/1.1 100 Continue\r\n\r\n")); con->expect_100_cont = FALSE; - ev_io_add_events(srv->loop, &con->sock.watcher, EV_WRITE); + ev_io_add_events(con->wrk->loop, &con->sock_watcher, EV_WRITE); } - parse_request_body(srv, con); + parse_request_body(con); if (con->content_handler) - con->content_handler->handle_content(srv, con, con->content_handler); + con->content_handler->handle_content(con, con->content_handler); - switch (action_execute(srv, con)) { + switch (action_execute(con)) { case ACTION_WAIT_FOR_EVENT: done = TRUE; break; case ACTION_GO_ON: case ACTION_FINISHED: - connection_set_state(srv, con, CON_STATE_WRITE_RESPONSE); + connection_set_state(con, CON_STATE_WRITE_RESPONSE); break; case ACTION_ERROR: - internal_error(srv, con); + internal_error(con); break; } break; case CON_STATE_WRITE_RESPONSE: if (con->in->is_closed && con->raw_out->is_closed) { - connection_set_state(srv, con, CON_STATE_RESPONSE_END); + connection_set_state(con, CON_STATE_RESPONSE_END); break; } if (!con->response_headers_sent) { con->response_headers_sent = TRUE; if (CORE_OPTION(CORE_OPTION_DEBUG_REQUEST_HANDLING)) { - TRACE(srv, "%s", "write response headers"); + CON_TRACE(con, "%s", "write response headers"); } - response_send_headers(srv, con); + response_send_headers(con); } if (CORE_OPTION(CORE_OPTION_DEBUG_REQUEST_HANDLING)) { - TRACE(srv, "%s", "write response"); + CON_TRACE(con, "%s", "write response"); } - parse_request_body(srv, con); + parse_request_body(con); if (con->content_handler) - con->content_handler->handle_content(srv, con, con->content_handler); + con->content_handler->handle_content(con, con->content_handler); - forward_response_body(srv, con); + forward_response_body(con); if (con->in->is_closed && con->raw_out->is_closed) { - connection_set_state(srv, con, CON_STATE_RESPONSE_END); + connection_set_state(con, CON_STATE_RESPONSE_END); break; } if (con->state == CON_STATE_WRITE_RESPONSE) done = TRUE; @@ -459,57 +455,57 @@ void connection_state_machine(server *srv, connection *con) { case CON_STATE_RESPONSE_END: if (CORE_OPTION(CORE_OPTION_DEBUG_REQUEST_HANDLING)) { - TRACE(srv, "response end (keep_alive = %i)", con->keep_alive); + CON_TRACE(con, "response end (keep_alive = %i)", con->keep_alive); } - plugins_handle_close(srv, con); + plugins_handle_close(con); if (con->keep_alive) { - connection_reset_keep_alive(srv, con); + connection_reset_keep_alive(con); } else { - con_put(srv, con); + con_put(con); done = TRUE; } break; case CON_STATE_CLOSE: if (CORE_OPTION(CORE_OPTION_DEBUG_REQUEST_HANDLING)) { - TRACE(srv, "%s", "connection closed"); + CON_TRACE(con, "%s", "connection closed"); } - plugins_handle_close(srv, con); + plugins_handle_close(con); - con_put(srv, con); + con_put(con); done = TRUE; break; case CON_STATE_ERROR: if (CORE_OPTION(CORE_OPTION_DEBUG_REQUEST_HANDLING)) { - TRACE(srv, "%s", "connection closed (error)"); + CON_TRACE(con, "%s", "connection closed (error)"); } - plugins_handle_close(srv, con); + plugins_handle_close(con); - con_put(srv, con); + con_put(con); done = TRUE; break; } } while (!done); } -void connection_handle_direct(server *srv, connection *con) { - connection_set_state(srv, con, CON_STATE_WRITE_RESPONSE); +void connection_handle_direct(connection *con) { + connection_set_state(con, CON_STATE_WRITE_RESPONSE); con->out->is_closed = TRUE; } -void connection_handle_indirect(server *srv, connection *con, plugin *p) { +void connection_handle_indirect(connection *con, plugin *p) { if (!p) { - connection_handle_direct(srv, con); + connection_handle_direct(con); } else if (p->handle_content) { - connection_set_state(srv, con, CON_STATE_READ_REQUEST_CONTENT); + connection_set_state(con, CON_STATE_READ_REQUEST_CONTENT); con->content_handler = p; } else { - CON_ERROR(srv, con, "Indirect plugin '%s' handler has no handle_content callback", p->name); - internal_error(srv, con); + CON_ERROR(con, "Indirect plugin '%s' handler has no handle_content callback", p->name); + internal_error(con); } } diff --git a/src/connection.h b/src/connection.h index 2b350d2..b54b27f 100644 --- a/src/connection.h +++ b/src/connection.h @@ -22,15 +22,15 @@ typedef enum { * - direct response: for things like errors/auth/redirect * just set the status code, perhaps fill in some headers, * append your content (if any) to the queue and do: - * connection_handle_direct(srv, con); + * connection_handle_direct(con); * this moves into the CON_STATE_HANDLE_RESPONSE_HEADER * request body gets dropped * - indirect response: you register your plugin as the content handler: - * connection_handle_indirect(srv, con, plugin); + * connection_handle_indirect(con, plugin); * this moves into the CON_STATE_READ_REQUEST_CONTENT state automatically * as soon as you build the response headers (e.g. from a backend), * change to the CON_STATE_HANDLE_RESPONSE_HEADER state: - * connection_set_state(srv, con, CON_STATE_HANDLE_RESPONSE_HEADER); + * connection_set_state(con, CON_STATE_HANDLE_RESPONSE_HEADER); */ CON_STATE_HANDLE_REQUEST_HEADER, @@ -60,24 +60,18 @@ typedef enum { CON_STATE_ERROR } connection_state_t; -struct connection_socket; -typedef struct connection_socket connection_socket; - -struct connection_socket { - server *srv; - connection *con; - ev_io watcher; -}; - struct connection { guint idx; /** index in connection table */ + server *srv; + worker *wrk; + connection_state_t state; gboolean response_headers_sent, expect_100_cont; chunkqueue *raw_in, *raw_out; chunkqueue *in, *out; - connection_socket sock; + ev_io sock_watcher; sock_addr remote_addr, local_addr; GString *remote_addr_str, *local_addr_str; gboolean is_ssl, keep_alive; @@ -106,13 +100,13 @@ struct connection { }; LI_API connection* connection_new(server *srv); -LI_API void connection_reset(server *srv, connection *con); -LI_API void connection_free(server *srv, connection *con); +LI_API void connection_reset(connection *con); +LI_API void connection_free(connection *con); -LI_API void connection_set_state(server *srv, connection *con, connection_state_t state); -LI_API void connection_state_machine(server *srv, connection *con); +LI_API void connection_set_state(connection *con, connection_state_t state); +LI_API void connection_state_machine(connection *con); -LI_API void connection_handle_direct(server *srv, connection *con); -LI_API void connection_handle_indirect(server *srv, connection *con, plugin *p); +LI_API void connection_handle_direct(connection *con); +LI_API void connection_handle_indirect(connection *con, plugin *p); #endif diff --git a/src/filter_chunked.c b/src/filter_chunked.c index 0a5376f..bd70a08 100644 --- a/src/filter_chunked.c +++ b/src/filter_chunked.c @@ -25,8 +25,7 @@ static void http_chunk_append_len(chunkqueue *cq, size_t len) { } -handler_t filter_chunked_encode(server *srv, connection *con, chunkqueue *out, chunkqueue *in) { - UNUSED(srv); +handler_t filter_chunked_encode(connection *con, chunkqueue *out, chunkqueue *in) { UNUSED(con); if (in->length > 0) { @@ -43,8 +42,7 @@ handler_t filter_chunked_encode(server *srv, connection *con, chunkqueue *out, c return HANDLER_GO_ON; } -handler_t filter_chunked_decode(server *srv, connection *con, chunkqueue *out, chunkqueue *in) { - UNUSED(srv); +handler_t filter_chunked_decode(connection *con, chunkqueue *out, chunkqueue *in) { UNUSED(con); UNUSED(out); UNUSED(in); diff --git a/src/filter_chunked.h b/src/filter_chunked.h index 0aa7f45..eb1cad6 100644 --- a/src/filter_chunked.h +++ b/src/filter_chunked.h @@ -3,7 +3,7 @@ #include "base.h" -LI_API handler_t filter_chunked_encode(server *srv, connection *con, chunkqueue *out, chunkqueue *in); -LI_API handler_t filter_chunked_decode(server *srv, connection *con, chunkqueue *out, chunkqueue *in); +LI_API handler_t filter_chunked_encode(connection *con, chunkqueue *out, chunkqueue *in); +LI_API handler_t filter_chunked_decode(connection *con, chunkqueue *out, chunkqueue *in); #endif diff --git a/src/http_request_parser.h b/src/http_request_parser.h index 08e0106..1fa0f92 100644 --- a/src/http_request_parser.h +++ b/src/http_request_parser.h @@ -22,7 +22,7 @@ LI_API void http_request_parser_init(http_request_ctx* ctx, request *req, chunkq LI_API void http_request_parser_reset(http_request_ctx* ctx); LI_API void http_request_parser_clear(http_request_ctx *ctx); -LI_API handler_t http_request_parse(struct server *srv, struct connection *con, http_request_ctx *ctx); +LI_API handler_t http_request_parse(struct connection *con, http_request_ctx *ctx); #endif diff --git a/src/http_request_parser.rl b/src/http_request_parser.rl index 9fd8fb0..6ccd1e7 100644 --- a/src/http_request_parser.rl +++ b/src/http_request_parser.rl @@ -4,10 +4,10 @@ /** Machine **/ -#define _getString(M, FPC) (chunk_extract(srv, con, ctx->M, GETMARK(FPC))) +#define _getString(M, FPC) (chunk_extract(con, ctx->M, GETMARK(FPC))) #define getString(FPC) _getString(mark, FPC) -#define _getStringTo(M, FPC, s) (chunk_extract_to(srv, con, ctx->M, GETMARK(FPC), s)) +#define _getStringTo(M, FPC, s) (chunk_extract_to(con, ctx->M, GETMARK(FPC), s)) #define getStringTo(FPC, s) _getStringTo(mark, FPC, s) @@ -148,7 +148,7 @@ void http_request_parser_clear(http_request_ctx *ctx) { g_string_free(ctx->h_value, TRUE); } -handler_t http_request_parse(server *srv, connection *con, http_request_ctx *ctx) { +handler_t http_request_parse(connection *con, http_request_ctx *ctx) { handler_t res; if (http_request_parser_is_finished(ctx)) return HANDLER_GO_ON; @@ -158,7 +158,7 @@ handler_t http_request_parse(server *srv, connection *con, http_request_ctx *ctx while (!http_request_parser_has_error(ctx) && !http_request_parser_is_finished(ctx)) { char *p, *pe; - if (HANDLER_GO_ON != (res = chunk_parser_next(srv, con, &ctx->chunk_ctx, &p, &pe))) return res; + if (HANDLER_GO_ON != (res = chunk_parser_next(con, &ctx->chunk_ctx, &p, &pe))) return res; %% write exec; diff --git a/src/log.c b/src/log.c index 6679178..542ecf3 100644 --- a/src/log.c +++ b/src/log.c @@ -39,6 +39,7 @@ gboolean log_write_(server *srv, connection *con, log_level_t log_level, const g log_level_t log_level_want; if (con != NULL) { + if (!srv) srv = con->srv; /* get log index from connection */ log = CORE_OPTION(CORE_OPTION_LOG_TARGET) ? CORE_OPTION(CORE_OPTION_LOG_TARGET) : srv->log_stderr; log_level_want = (log_level_t) CORE_OPTION(CORE_OPTION_LOG_LEVEL); diff --git a/src/log.h b/src/log.h index 8341f64..c3e28b2 100644 --- a/src/log.h +++ b/src/log.h @@ -29,15 +29,15 @@ LI_API const char *remove_path(const char *path); abort();\ } while(0) -#define CON_ERROR(srv, con, fmt, ...) \ - log_write(srv, con, "%s.%d: (error) "fmt, REMOVE_PATH(__FILE__), __LINE__, __VA_ARGS__) +#define CON_ERROR(con, fmt, ...) \ + log_write(NULL, con, "%s.%d: (error) "fmt, REMOVE_PATH(__FILE__), __LINE__, __VA_ARGS__) \ -#define CON_TRACE(srv, con, fmt, ...) \ - log_write(srv, con, "%s.%d: (trace) "fmt, REMOVE_PATH(__FILE__), __LINE__, __VA_ARGS__) +#define CON_TRACE(con, fmt, ...) \ + log_write(NULL, con, "%s.%d: (trace) "fmt, REMOVE_PATH(__FILE__), __LINE__, __VA_ARGS__) -#define CON_SEGFAULT(srv, con, fmt, ...) \ +#define CON_SEGFAULT(con, fmt, ...) \ do { \ - log_write(srv, con, "%s.%d: (crashing) "fmt, REMOVE_PATH(__FILE__), __LINE__, __VA_ARGS__); \ + log_write(NULL, con, "%s.%d: (crashing) "fmt, REMOVE_PATH(__FILE__), __LINE__, __VA_ARGS__); \ /* VALGRIND_PRINTF_BACKTRACE(fmt, __VA_ARGS__); */ \ abort();\ } while(0) diff --git a/src/network.c b/src/network.c index 91da54e..af19119 100644 --- a/src/network.c +++ b/src/network.c @@ -35,7 +35,7 @@ ssize_t net_read(int fd, void *buf, ssize_t nbyte) { return r; } -network_status_t network_write(server *srv, connection *con, int fd, chunkqueue *cq) { +network_status_t network_write(connection *con, int fd, chunkqueue *cq) { network_status_t res; #ifdef TCP_CORK int corked = 0; @@ -51,8 +51,8 @@ network_status_t network_write(server *srv, connection *con, int fd, chunkqueue } #endif - /* res = network_write_writev(srv, con, fd, cq); */ - res = network_write_sendfile(srv, con, fd, cq); + /* res = network_write_writev(con, fd, cq); */ + res = network_write_sendfile(con, fd, cq); #ifdef TCP_CORK if (corked) { @@ -64,7 +64,7 @@ network_status_t network_write(server *srv, connection *con, int fd, chunkqueue return res; } -network_status_t network_read(server *srv, connection *con, int fd, chunkqueue *cq) { +network_status_t network_read(connection *con, int fd, chunkqueue *cq) { const ssize_t blocksize = 16*1024; /* 16k */ const off_t max_read = 16 * blocksize; /* 256k */ ssize_t r; @@ -84,7 +84,7 @@ network_status_t network_read(server *srv, connection *con, int fd, chunkqueue * case ECONNRESET: return NETWORK_STATUS_CONNECTION_CLOSE; default: - CON_ERROR(srv, con, "oops, read from fd=%d failed: %s", fd, g_strerror(errno) ); + CON_ERROR(con, "oops, read from fd=%d failed: %s", fd, g_strerror(errno) ); return NETWORK_STATUS_FATAL_ERROR; } } else if (0 == r) { diff --git a/src/network.h b/src/network.h index 294fdeb..65680ba 100644 --- a/src/network.h +++ b/src/network.h @@ -18,23 +18,23 @@ LI_API ssize_t net_write(int fd, void *buf, ssize_t nbyte); /** repeats read after EINTR */ LI_API ssize_t net_read(int fd, void *buf, ssize_t nbyte); -LI_API network_status_t network_write(server *srv, connection *con, int fd, chunkqueue *cq); -LI_API network_status_t network_read(server *srv, connection *con, int fd, chunkqueue *cq); +LI_API network_status_t network_write(connection *con, int fd, chunkqueue *cq); +LI_API network_status_t network_read(connection *con, int fd, chunkqueue *cq); /* use writev for mem chunks, buffered read/write for files */ -LI_API network_status_t network_write_writev(server *srv, connection *con, int fd, chunkqueue *cq); +LI_API network_status_t network_write_writev(connection *con, int fd, chunkqueue *cq); /* use sendfile for files, writev for mem chunks */ -LI_API network_status_t network_write_sendfile(server *srv, connection *con, int fd, chunkqueue *cq); +LI_API network_status_t network_write_sendfile(connection *con, int fd, chunkqueue *cq); /* write backends */ -LI_API network_status_t network_backend_write(server *srv, connection *con, int fd, chunkqueue *cq, goffset *write_max); -LI_API network_status_t network_backend_writev(server *srv, connection *con, int fd, chunkqueue *cq, goffset *write_max); -LI_API network_status_t network_backend_writev(server *srv, connection *con, int fd, chunkqueue *cq, goffset *write_max); +LI_API network_status_t network_backend_write(connection *con, int fd, chunkqueue *cq, goffset *write_max); +LI_API network_status_t network_backend_writev(connection *con, int fd, chunkqueue *cq, goffset *write_max); +LI_API network_status_t network_backend_writev(connection *con, int fd, chunkqueue *cq, goffset *write_max); #define NETWORK_FALLBACK(f, write_max) do { \ network_status_t res; \ - switch(res = f(srv, con, fd, cq, write_max)) { \ + switch(res = f(con, fd, cq, write_max)) { \ case NETWORK_STATUS_SUCCESS: \ break; \ default: \ diff --git a/src/network_linux_sendfile.c b/src/network_linux_sendfile.c index 18f99e2..7c193bb 100644 --- a/src/network_linux_sendfile.c +++ b/src/network_linux_sendfile.c @@ -2,7 +2,7 @@ #include "network.h" /* first chunk must be a FILE_CHUNK ! */ -network_status_t network_backend_sendfile(server *srv, connection *con, int fd, chunkqueue *cq, goffset *write_max) { +network_status_t network_backend_sendfile(connection *con, int fd, chunkqueue *cq, goffset *write_max) { off_t file_offset, toSend; ssize_t r; gboolean did_write_something = FALSE; @@ -18,7 +18,7 @@ network_status_t network_backend_sendfile(server *srv, connection *con, int fd, return did_write_something ? NETWORK_STATUS_SUCCESS : NETWORK_STATUS_FATAL_ERROR; } - switch (chunkfile_open(srv, con, c->file.file)) { + switch (chunkfile_open(con, c->file.file)) { case HANDLER_GO_ON: break; case HANDLER_WAIT_FOR_FD: @@ -49,7 +49,7 @@ network_status_t network_backend_sendfile(server *srv, connection *con, int fd, NETWORK_FALLBACK(network_backend_write, write_max); return NETWORK_STATUS_SUCCESS; default: - CON_ERROR(srv, con, "oops, write to fd=%d failed: %s", fd, g_strerror(errno)); + CON_ERROR(con, "oops, write to fd=%d failed: %s", fd, g_strerror(errno)); return NETWORK_STATUS_FATAL_ERROR; } } @@ -57,13 +57,13 @@ network_status_t network_backend_sendfile(server *srv, connection *con, int fd, /* don't care about cached stat - file is open */ struct stat st; if (-1 == fstat(fd, &st)) { - CON_ERROR(srv, con, "Couldn't fstat file: %s", g_strerror(errno)); + CON_ERROR(con, "Couldn't fstat file: %s", g_strerror(errno)); return NETWORK_STATUS_FATAL_ERROR; } if (file_offset > st.st_size) { /* file shrinked, close the connection */ - CON_ERROR(srv, con, "%s", "File shrinked, aborting"); + CON_ERROR(con, "%s", "File shrinked, aborting"); return NETWORK_STATUS_FATAL_ERROR; } return did_write_something ? NETWORK_STATUS_SUCCESS : NETWORK_STATUS_WAIT_FOR_EVENT; @@ -77,7 +77,7 @@ network_status_t network_backend_sendfile(server *srv, connection *con, int fd, return NETWORK_STATUS_SUCCESS; } -network_status_t network_write_sendfile(server *srv, connection *con, int fd, chunkqueue *cq) { +network_status_t network_write_sendfile(connection *con, int fd, chunkqueue *cq) { goffset write_max = 256*1024; // 256kB //; if (cq->length == 0) return NETWORK_STATUS_FATAL_ERROR; do { diff --git a/src/network_write.c b/src/network_write.c index 9bc5ff6..be2a088 100644 --- a/src/network_write.c +++ b/src/network_write.c @@ -1,7 +1,7 @@ #include "network.h" -network_status_t network_backend_write(server *srv, connection *con, int fd, chunkqueue *cq, goffset *write_max) { +network_status_t network_backend_write(connection *con, int fd, chunkqueue *cq, goffset *write_max) { const ssize_t blocksize = 16*1024; /* 16k */ char *block_data; off_t block_len; @@ -14,7 +14,7 @@ network_status_t network_backend_write(server *srv, connection *con, int fd, chu return did_write_something ? NETWORK_STATUS_SUCCESS : NETWORK_STATUS_FATAL_ERROR; ci = chunkqueue_iter(cq); - switch (chunkiter_read(srv, con, ci, 0, blocksize, &block_data, &block_len)) { + switch (chunkiter_read(con, ci, 0, blocksize, &block_data, &block_len)) { case HANDLER_GO_ON: break; case HANDLER_WAIT_FOR_FD: @@ -35,7 +35,7 @@ network_status_t network_backend_write(server *srv, connection *con, int fd, chu case EPIPE: return NETWORK_STATUS_CONNECTION_CLOSE; default: - CON_ERROR(srv, con, "oops, write to fd=%d failed: %s", fd, g_strerror(errno)); + CON_ERROR(con, "oops, write to fd=%d failed: %s", fd, g_strerror(errno)); return NETWORK_STATUS_FATAL_ERROR; } } else if (0 == r) { diff --git a/src/network_writev.c b/src/network_writev.c index 8c4e2e0..2940596 100644 --- a/src/network_writev.c +++ b/src/network_writev.c @@ -25,7 +25,7 @@ #endif /* first chunk must be a MEM_CHUNK ! */ -network_status_t network_backend_writev(server *srv, connection *con, int fd, chunkqueue *cq, goffset *write_max) { +network_status_t network_backend_writev(connection *con, int fd, chunkqueue *cq, goffset *write_max) { off_t we_have; ssize_t r; gboolean did_write_something = FALSE; @@ -76,7 +76,7 @@ network_status_t network_backend_writev(server *srv, connection *con, int fd, ch case EINTR: break; /* try again */ default: - CON_ERROR(srv, con, "oops, write to fd=%d failed: %s", fd, g_strerror(errno)); + CON_ERROR(con, "oops, write to fd=%d failed: %s", fd, g_strerror(errno)); goto cleanup; } } @@ -108,7 +108,7 @@ cleanup: return res; } -network_status_t network_write_writev(server *srv, connection *con, int fd, chunkqueue *cq) { +network_status_t network_write_writev(connection *con, int fd, chunkqueue *cq) { goffset write_max = 256*1024; // 256k //; if (cq->length == 0) return NETWORK_STATUS_FATAL_ERROR; do { diff --git a/src/plugin.c b/src/plugin.c index cda40d8..16080e2 100644 --- a/src/plugin.c +++ b/src/plugin.c @@ -283,11 +283,11 @@ void plugins_prepare_callbacks(server *srv) { } } -void plugins_handle_close(server *srv, connection *con) { - GArray *a = srv->plugins_handle_close; +void plugins_handle_close(connection *con) { + GArray *a = con->srv->plugins_handle_close; guint i, len = a->len; for (i = 0; i < len; i++) { plugin *p = g_array_index(a, plugin*, i); - p->handle_close(srv, con, p); + p->handle_close(con, p); } } diff --git a/src/plugin.h b/src/plugin.h index fbfed2e..4aebc7a 100644 --- a/src/plugin.h +++ b/src/plugin.h @@ -38,12 +38,12 @@ typedef void (*PluginInit) (server *srv, plugin *p); typedef void (*PluginFree) (server *srv, plugin *p); typedef gboolean (*PluginParseOption) (server *srv, plugin *p, size_t ndx, option *opt, gpointer *value); typedef void (*PluginFreeOption) (server *srv, plugin *p, size_t ndx, gpointer value); -typedef gpointer (*PluginDefaultValue) (server *srv, plugin *p, gsize ndx); +typedef gpointer (*PluginDefaultValue) (server *srv, plugin *p, gsize ndx); typedef action* (*PluginCreateAction) (server *srv, plugin *p, option *opt); typedef gboolean (*PluginSetup) (server *srv, plugin *p, option *opt); -typedef void (*PluginHandleContent) (server *srv, connection *con, plugin *p); -typedef void (*PluginHandleClose) (server *srv, connection *con, plugin *p); +typedef void (*PluginHandleContent) (connection *con, plugin *p); +typedef void (*PluginHandleClose) (connection *con, plugin *p); struct plugin { size_t version; @@ -57,7 +57,7 @@ struct plugin { /** called if plugin registered as indirect handler with connection_handle_indirect(srv, con, p) * - after response headers are created: - * connection_set_state(srv, con, CON_STATE_HANDLE_RESPONSE_HEADER) + * connection_set_state(con, CON_STATE_HANDLE_RESPONSE_HEADER) * - after content is generated close output queue: * con->out->is_closed = TRUE */ @@ -130,7 +130,7 @@ LI_API gboolean parse_option(server *srv, const char *name, option *opt, option_ LI_API void release_option(server *srv, option_set *mark); /**< Does not free the option_set memory */ LI_API void plugins_prepare_callbacks(server *srv); -LI_API void plugins_handle_close(server *srv, connection *con); +LI_API void plugins_handle_close(connection *con); /* Needed for config frontends */ /** For parsing 'somemod.option = "somevalue"' */ diff --git a/src/plugin_core.c b/src/plugin_core.c index 2263af3..af9f464 100644 --- a/src/plugin_core.c +++ b/src/plugin_core.c @@ -114,9 +114,8 @@ static action* core_set(server *srv, plugin* p, option *opt) { return a; } -static action_result core_handle_physical(server *srv, connection *con, gpointer param) { +static action_result core_handle_physical(connection *con, gpointer param) { GString *docroot = (GString*) param; - UNUSED(srv); if (con->state != CON_STATE_HANDLE_REQUEST_HEADER) return ACTION_GO_ON; @@ -150,7 +149,7 @@ static action* core_physical(server *srv, plugin* p, option *opt) { return action_new_function(core_handle_physical, core_physical_free, docroot); } -static action_result core_handle_static(server *srv, connection *con, gpointer param) { +static action_result core_handle_static(connection *con, gpointer param) { UNUSED(param); int fd; @@ -170,7 +169,7 @@ static action_result core_handle_static(server *srv, connection *con, gpointer p con->response.http_status = 200; chunkqueue_append_file_fd(con->out, NULL, 0, st.st_size, fd); } - connection_handle_direct(srv, con); + connection_handle_direct(con); return ACTION_GO_ON; } @@ -185,7 +184,8 @@ static action* core_static(server *srv, plugin* p, option *opt) { return action_new_function(core_handle_static, NULL, NULL); } -static action_result core_handle_test(server *srv, connection *con, gpointer param) { +static action_result core_handle_test(connection *con, gpointer param) { + server *srv = con->srv; GHashTableIter iter; gpointer k, v; GList *hv; @@ -207,7 +207,7 @@ static action_result core_handle_test(server *srv, connection *con, gpointer par chunkqueue_append_mem(con->out, GSTR_LEN(con->request.uri.query)); chunkqueue_append_mem(con->out, CONST_STR_LEN("\r\n\r\nactions executed: ")); - uptime = (guint64)(ev_now(srv->loop) - srv->started); + uptime = (guint64)(ev_now(con->wrk->loop) - srv->started); if (uptime == 0) uptime = 1; avg1 = srv->stats.actions_executed; @@ -231,7 +231,7 @@ static action_result core_handle_test(server *srv, connection *con, gpointer par g_string_printf(str, "%"G_GUINT64_FORMAT"%s (%"G_GUINT64_FORMAT"%s/s)", avg1, suffix1, avg2, suffix2); chunkqueue_append_string(con->out, str); - backend = ev_backend_string(ev_backend(srv->loop)); + backend = ev_backend_string(ev_backend(con->wrk->loop)); chunkqueue_append_mem(con->out, CONST_STR_LEN("\r\nevent handler: ")); chunkqueue_append_mem(con->out, backend, strlen(backend)); @@ -248,9 +248,9 @@ static action_result core_handle_test(server *srv, connection *con, gpointer par } } chunkqueue_append_mem(con->out, CONST_STR_LEN("\r\n")); - connection_handle_direct(srv, con); + connection_handle_direct(con); - log_debug(srv, con, "core_handle_test: %s%s%s log_level: %s", + CON_TRACE(con, "core_handle_test: %s%s%s log_level: %s", con->request.uri.path->str, con->request.uri.query->len ? "?" : "", con->request.uri.query->len ? con->request.uri.query->str : "", log_level_str((log_level_t)CORE_OPTION(CORE_OPTION_LOG_LEVEL)) ); @@ -269,13 +269,13 @@ static action* core_test(server *srv, plugin* p, option *opt) { return action_new_function(core_handle_test, NULL, NULL); } -static action_result core_handle_blank(server *srv, connection *con, gpointer param) { +static action_result core_handle_blank(connection *con, gpointer param) { UNUSED(param); if (con->state != CON_STATE_HANDLE_REQUEST_HEADER) return ACTION_GO_ON; con->response.http_status = 200; - connection_handle_direct(srv, con); + connection_handle_direct(con); return ACTION_GO_ON; } diff --git a/src/request.c b/src/request.c index cdd8fdd..aabdc75 100644 --- a/src/request.c +++ b/src/request.c @@ -61,15 +61,14 @@ void request_clear(request *req) { } /* closes connection after response */ -static void bad_request(server *srv, connection *con, int status) { +static void bad_request(connection *con, int status) { con->keep_alive = FALSE; con->response.http_status = status; - connection_handle_direct(srv, con); + connection_handle_direct(con); } -gboolean request_parse_url(server *srv, connection *con) { +gboolean request_parse_url(connection *con) { request *req = &con->request; - UNUSED(srv); UNUSED(req); g_string_truncate(req->uri.query, 0); g_string_truncate(req->uri.path, 0); @@ -87,7 +86,7 @@ gboolean request_parse_url(server *srv, connection *con) { return TRUE; } -void request_validate_header(server *srv, connection *con) { +void request_validate_header(connection *con) { request *req = &con->request; http_header *hh; @@ -101,37 +100,37 @@ void request_validate_header(server *srv, connection *con) { con->keep_alive = FALSE; break; case HTTP_VERSION_UNSET: - bad_request(srv, con, 505); /* Version not Supported */ + bad_request(con, 505); /* Version not Supported */ return; } if (req->uri.raw->len == 0) { - bad_request(srv, con, 400); /* bad request */ + bad_request(con, 400); /* bad request */ return; } /* get hostname */ hh = http_header_lookup_fast(req->headers, CONST_STR_LEN("host")); if (hh && hh->values.length != 1) { - bad_request(srv, con, 400); /* bad request */ + bad_request(con, 400); /* bad request */ return; } else if (hh) { g_string_append_len(req->uri.authority, GSTR_LEN((GString*) g_queue_peek_head(&hh->values))); if (!parse_hostname(&req->uri)) { - bad_request(srv, con, 400); /* bad request */ + bad_request(con, 400); /* bad request */ return; } } /* Need hostname in HTTP/1.1 */ if (req->uri.host->len == 0 && req->http_version == HTTP_VERSION_1_1) { - bad_request(srv, con, 400); /* bad request */ + bad_request(con, 400); /* bad request */ return; } /* may override hostname */ - if (!request_parse_url(srv, con)) { - bad_request(srv, con, 400); /* bad request */ + if (!request_parse_url(con)) { + bad_request(con, 400); /* bad request */ return; } @@ -144,8 +143,8 @@ void request_validate_header(server *srv, connection *con) { r = str_to_off_t(val->str, &err, 10); if (*err != '\0') { - CON_TRACE(srv, con, "content-length is not a number: %s (Status: 400)", err); - bad_request(srv, con, 400); /* bad request */ + CON_TRACE(con, "content-length is not a number: %s (Status: 400)", err); + bad_request(con, 400); /* bad request */ return; } @@ -154,7 +153,7 @@ void request_validate_header(server *srv, connection *con) { * and is a bad request */ if (r < 0) { - bad_request(srv, con, 400); /* bad request */ + bad_request(con, 400); /* bad request */ return; } @@ -164,7 +163,7 @@ void request_validate_header(server *srv, connection *con) { if (r == STR_OFF_T_MIN || r == STR_OFF_T_MAX) { if (errno == ERANGE) { - bad_request(srv, con, 413); /* Request Entity Too Large */ + bad_request(con, 413); /* Request Entity Too Large */ return; } } @@ -183,14 +182,14 @@ void request_validate_header(server *srv, connection *con) { expect_100_cont = TRUE; } else { /* we only support 100-continue */ - bad_request(srv, con, 417); /* Expectation Failed */ + bad_request(con, 417); /* Expectation Failed */ return; } } if (expect_100_cont && req->http_version == HTTP_VERSION_1_0) { /* only HTTP/1.1 clients can send us this header */ - bad_request(srv, con, 417); /* Expectation Failed */ + bad_request(con, 417); /* Expectation Failed */ return; } con->expect_100_cont = expect_100_cont; @@ -207,9 +206,9 @@ void request_validate_header(server *srv, connection *con) { case HTTP_METHOD_HEAD: /* content-length is forbidden for those */ if (con->request.content_length > 0) { - CON_ERROR(srv, con, "%s", "GET/HEAD with content-length -> 400"); + CON_ERROR(con, "%s", "GET/HEAD with content-length -> 400"); - bad_request(srv, con, 400); /* bad request */ + bad_request(con, 400); /* bad request */ return; } con->request.content_length = 0; @@ -218,9 +217,9 @@ void request_validate_header(server *srv, connection *con) { /* content-length is required for them */ if (con->request.content_length == -1) { /* content-length is missing */ - CON_ERROR(srv, con, "%s", "POST-request, but content-length missing -> 411"); + CON_ERROR(con, "%s", "POST-request, but content-length missing -> 411"); - bad_request(srv, con, 411); /* Length Required */ + bad_request(con, 411); /* Length Required */ return; } break; diff --git a/src/request.h b/src/request.h index f1590ee..2adc6fd 100644 --- a/src/request.h +++ b/src/request.h @@ -90,7 +90,7 @@ LI_API void request_init(request *req, chunkqueue *in); LI_API void request_reset(request *req); LI_API void request_clear(request *req); -LI_API void request_validate_header(server *srv, connection *con); +LI_API void request_validate_header(connection *con); LI_API void physical_init(physical *phys); LI_API void physical_reset(physical *phys); diff --git a/src/response.c b/src/response.c index 2738d4d..0b40757 100644 --- a/src/response.c +++ b/src/response.c @@ -21,7 +21,7 @@ void response_clear(response *resp) { resp->transfer_encoding = HTTP_TRANSFER_ENCODING_IDENTITY; } -void response_send_headers(server *srv, connection *con) { +void response_send_headers(connection *con) { GString *head = g_string_sized_new(8*1024); if (con->response.http_status < 100 || con->response.http_status > 999) { @@ -48,8 +48,8 @@ void response_send_headers(server *srv, connection *con) { chunkqueue_reset(con->out); con->out->is_closed = TRUE; } else if (con->out->is_closed) { - g_string_printf(srv->tmp_str, "%"L_GOFFSET_FORMAT, con->out->length); - http_header_overwrite(con->response.headers, CONST_STR_LEN("Content-Length"), GSTR_LEN(srv->tmp_str)); + g_string_printf(con->wrk->tmp_str, "%"L_GOFFSET_FORMAT, con->out->length); + http_header_overwrite(con->response.headers, CONST_STR_LEN("Content-Length"), GSTR_LEN(con->wrk->tmp_str)); } else if (con->keep_alive && con->request.http_version == HTTP_VERSION_1_1) { if (!(con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED)) { con->response.transfer_encoding |= HTTP_TRANSFER_ENCODING_CHUNKED; @@ -105,7 +105,7 @@ void response_send_headers(server *srv, connection *con) { } if (!have_date) { - GString *d = server_current_timestamp(srv); + GString *d = worker_current_timestamp(con->wrk); /* HTTP/1.1 requires a Date: header */ g_string_append_len(head, CONST_STR_LEN("Date: ")); g_string_append_len(head, GSTR_LEN(d)); diff --git a/src/response.h b/src/response.h index cc450d1..4f0960c 100644 --- a/src/response.h +++ b/src/response.h @@ -16,6 +16,6 @@ LI_API void response_init(response *resp); LI_API void response_reset(response *resp); LI_API void response_clear(response *resp); -LI_API void response_send_headers(server *srv, connection *con); +LI_API void response_send_headers(connection *con); #endif diff --git a/src/server.c b/src/server.c index 5822bdf..dab9066 100644 --- a/src/server.c +++ b/src/server.c @@ -3,45 +3,7 @@ #include "utils.h" #include "plugin_core.h" -struct server_closing_socket; -typedef struct server_closing_socket server_closing_socket; - -struct server_closing_socket { - server *srv; - GList *link; - int fd; -}; - -static void server_closing_socket_cb(int revents, void* arg) { - server_closing_socket *scs = (server_closing_socket*) arg; - UNUSED(revents); - - /* Whatever happend: we just close the socket */ - shutdown(scs->fd, SHUT_RD); - close(scs->fd); - g_queue_delete_link(&scs->srv->closing_sockets, scs->link); - g_slice_free(server_closing_socket, scs); -} - -void server_add_closing_socket(server *srv, int fd) { - server_closing_socket *scs = g_slice_new0(server_closing_socket); - - shutdown(fd, SHUT_WR); - - scs->srv = srv; - scs->fd = fd; - g_queue_push_tail(&srv->closing_sockets, scs); - scs->link = g_queue_peek_tail_link(&srv->closing_sockets); - - ev_once(srv->loop, fd, EV_READ, 10.0, server_closing_socket_cb, scs); -} - -/* Kill it - frees fd */ -static void server_rem_closing_socket(server *srv, server_closing_socket *scs) { - ev_feed_fd_event(srv->loop, scs->fd, EV_READ); -} - -void con_put(server *srv, connection *con); +void con_put(connection *con); static void server_option_free(gpointer _so) { g_slice_free(server_option, _so); @@ -81,49 +43,6 @@ static void sigpipe_cb(struct ev_loop *loop, struct ev_signal *w, int revents) { ev_unref(loop); /* Signal watchers shouldn't keep loop alive */ \ } while (0) -void server_check_keepalive(server *srv) { - ev_tstamp now = ev_now((srv)->loop); - - if (0 == srv->keep_alive_queue.length) { - ev_timer_stop(srv->loop, &srv->keep_alive_timer); - } else { - srv->keep_alive_timer.repeat = ((connection*)g_queue_peek_head(&srv->keep_alive_queue))->keep_alive_data.timeout - now + 1; - ev_timer_again(srv->loop, &srv->keep_alive_timer); - } -} - -static void server_keepalive_cb(struct ev_loop *loop, ev_timer *w, int revents) { - server *srv = (server*) w->data; - ev_tstamp now = ev_now((srv)->loop); - GQueue *q = &srv->keep_alive_queue; - GList *l; - connection *con; - - UNUSED(loop); - UNUSED(revents); - - while ( NULL != (l = g_queue_peek_head_link(q)) && - (con = (connection*) l->data)->keep_alive_data.timeout <= now ) { - ev_tstamp remaining = con->keep_alive_data.max_idle - srv->keep_alive_queue_timeout - (now - con->keep_alive_data.timeout); - if (remaining > 0) { - g_queue_delete_link(q, l); - con->keep_alive_data.link = NULL; - ev_timer_set(&con->keep_alive_data.watcher, remaining, 0); - ev_timer_start(srv->loop, &con->keep_alive_data.watcher); - } else { - /* close it */ - con_put(srv, con); - } - } - - if (NULL == l) { - ev_timer_stop(srv->loop, &srv->keep_alive_timer); - } else { - srv->keep_alive_timer.repeat = con->keep_alive_data.timeout - now + 1; - ev_timer_again(srv->loop, &srv->keep_alive_timer); - } -} - server* server_new() { server* srv = g_slice_new0(server); @@ -133,7 +52,6 @@ server* server_new() { srv->connections_active = 0; srv->connections = g_array_new(FALSE, TRUE, sizeof(connection*)); srv->sockets = g_array_new(FALSE, TRUE, sizeof(server_socket*)); - g_queue_init(&srv->closing_sockets); srv->plugins = g_hash_table_new(g_str_hash, g_str_equal); srv->options = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, server_option_free); @@ -145,17 +63,9 @@ server* server_new() { srv->mainaction = NULL; srv->exiting = FALSE; - srv->tmp_str = g_string_sized_new(255); - - srv->last_generated_date_ts = 0; - srv->ts_date_str = g_string_sized_new(255); log_init(srv); - g_queue_init(&srv->keep_alive_queue); - ev_init(&srv->keep_alive_timer, server_keepalive_cb); - srv->keep_alive_timer.data = srv; - return srv; } @@ -171,12 +81,12 @@ void server_free(server* srv) { ERROR(srv, "Server shutdown with unclosed connections: %u", srv->connections_active); for (i = srv->connections_active; i-- > 0;) { connection *con = g_array_index(srv->connections, connection*, i); - connection_set_state(srv, con, CON_STATE_ERROR); - connection_state_machine(srv, con); /* cleanup plugins */ + connection_set_state(con, CON_STATE_ERROR); + connection_state_machine(con); /* cleanup plugins */ } } for (i = 0; i < srv->connections->len; i++) { - connection_free(srv, g_array_index(srv->connections, connection*, i)); + connection_free(g_array_index(srv->connections, connection*, i)); } g_array_free(srv->connections, TRUE); } @@ -189,13 +99,6 @@ void server_free(server* srv) { } g_array_free(srv->sockets, TRUE); } - { /* force closing sockets */ - GList *iter; - for (iter = g_queue_peek_head_link(&srv->closing_sockets); iter; iter = g_list_next(iter)) { - server_closing_socket_cb(EV_TIMEOUT, (server_closing_socket*) iter->data); - } - g_queue_clear(&srv->closing_sockets); - } g_hash_table_destroy(srv->plugins); g_hash_table_destroy(srv->options); @@ -206,9 +109,6 @@ void server_free(server* srv) { action_release(srv, srv->mainaction); - g_string_free(srv->tmp_str, TRUE); - g_string_free(srv->ts_date_str, TRUE); - /* free logs */ g_thread_join(srv->log_thread); { @@ -224,23 +124,22 @@ void server_free(server* srv) { g_mutex_free(srv->log_mutex); g_async_queue_unref(srv->log_queue); - g_queue_clear(&srv->keep_alive_queue); - ev_timer_stop(srv->loop, &srv->keep_alive_timer); - g_slice_free(server, srv); } gboolean server_loop_init(server *srv) { - srv->loop = ev_default_loop(srv->loop_flags); + struct ev_loop *loop = ev_default_loop(srv->loop_flags); - if (!srv->loop) { + if (!loop) { fatal ("could not initialise libev, bad $LIBEV_FLAGS in environment?"); return FALSE; } - CATCH_SIGNAL(srv->loop, sigint_cb, INT); - CATCH_SIGNAL(srv->loop, sigint_cb, TERM); - CATCH_SIGNAL(srv->loop, sigpipe_cb, PIPE); + CATCH_SIGNAL(loop, sigint_cb, INT); + CATCH_SIGNAL(loop, sigint_cb, TERM); + CATCH_SIGNAL(loop, sigpipe_cb, PIPE); + + srv->main_worker = worker_new(srv, loop); return TRUE; } @@ -257,8 +156,11 @@ static connection* con_get(server *srv) { return con; } -void con_put(server *srv, connection *con) { - connection_reset(srv, con); +void con_put(connection *con) { + server *srv = con->srv; + + connection_reset(con); + con->wrk = NULL; srv->connections_active--; if (con->idx != srv->connections_active) { /* Swap [con->idx] and [srv->connections_active] */ @@ -283,10 +185,11 @@ static void server_listen_cb(struct ev_loop *loop, ev_io *w, int revents) { while (-1 != (s = accept(w->fd, (struct sockaddr*) &remote_addr, &l))) { connection *con = con_get(srv); + con->wrk = srv->main_worker; /* TODO: balance workers; push con in a queue for the worker */ con->state = CON_STATE_REQUEST_START; con->remote_addr = remote_addr; - ev_io_set(&con->sock.watcher, s, EV_READ); - ev_io_start(srv->loop, &con->sock.watcher); + ev_io_set(&con->sock_watcher, s, EV_READ); + ev_io_start(con->wrk->loop, &con->sock_watcher); } #ifdef _WIN32 @@ -322,7 +225,7 @@ void server_listen(server *srv, int fd) { fd_init(fd); ev_init(&sock->watcher, server_listen_cb); ev_io_set(&sock->watcher, fd, EV_READ); - if (srv->state == SERVER_RUNNING) ev_io_start(srv->loop, &sock->watcher); + if (srv->state == SERVER_RUNNING) ev_io_start(srv->main_worker->loop, &sock->watcher); g_array_append_val(srv->sockets, sock); } @@ -357,14 +260,14 @@ void server_start(server *srv) { for (i = 0; i < srv->sockets->len; i++) { server_socket *sock = g_array_index(srv->sockets, server_socket*, i); - ev_io_start(srv->loop, &sock->watcher); + ev_io_start(srv->main_worker->loop, &sock->watcher); } - srv->started = ev_now(srv->loop); + srv->started = ev_now(srv->main_worker->loop); log_thread_start(srv); - ev_loop(srv->loop, 0); + worker_run(srv->main_worker); } void server_stop(server *srv) { @@ -374,13 +277,13 @@ void server_stop(server *srv) { for (i = 0; i < srv->sockets->len; i++) { server_socket *sock = g_array_index(srv->sockets, server_socket*, i); - ev_io_stop(srv->loop, &sock->watcher); + ev_io_stop(srv->main_worker->loop, &sock->watcher); } for (i = srv->connections_active; i-- > 0;) { connection *con = g_array_index(srv->connections, connection*, i); if (con->state == CON_STATE_KEEP_ALIVE) - con_put(srv, con); + con_put(con); } } @@ -388,30 +291,9 @@ void server_exit(server *srv) { g_atomic_int_set(&srv->exiting, TRUE); server_stop(srv); - { /* force closing sockets */ - GList *iter; - for (iter = g_queue_peek_head_link(&srv->closing_sockets); iter; iter = g_list_next(iter)) { - server_rem_closing_socket(srv, (server_closing_socket*) iter->data); - } - } - log_thread_wakeup(srv); } -void joblist_append(server *srv, connection *con) { - connection_state_machine(srv, con); -} - -GString *server_current_timestamp(server *srv) { - time_t cur_ts = CUR_TS(srv); - if (cur_ts != srv->last_generated_date_ts) { - g_string_set_size(srv->ts_date_str, 255); - strftime(srv->ts_date_str->str, srv->ts_date_str->allocated_len, - "%a, %d %b %Y %H:%M:%S GMT", gmtime(&(cur_ts))); - - g_string_set_size(srv->ts_date_str, strlen(srv->ts_date_str->str)); - - srv->last_generated_date_ts = cur_ts; - } - return srv->ts_date_str; +void joblist_append(connection *con) { + connection_state_machine(con); } diff --git a/src/server.h b/src/server.h index 5afd7e0..75feca0 100644 --- a/src/server.h +++ b/src/server.h @@ -5,8 +5,6 @@ #define LIGHTTPD_SERVER_MAGIC ((guint)0x12AB34CD) #endif -#define CUR_TS(srv) ((time_t)ev_now((srv)->loop)) - typedef enum { SERVER_STARTING, /** start up: don't write log files, don't accept connections */ SERVER_RUNNING, /** running: write logs, accept connections */ @@ -33,13 +31,15 @@ struct statistics_t { guint64 actions_executed; /** actions executed */ }; +struct worker; + struct server { guint32 magic; /** server magic version, check against LIGHTTPD_SERVER_MAGIC in plugins */ server_state state; + struct worker *main_worker; + guint loop_flags; - struct ev_loop *loop; - ev_timer keep_alive_timer; ev_signal sig_w_INT, sig_w_TERM, @@ -50,7 +50,6 @@ struct server { guint connections_active; /** 0..con_act-1: active connections, con_act..used-1: free connections */ GArray *connections; /** array of (connection*) */ GArray *sockets; /** array of (server_socket*) */ - GQueue closing_sockets; /** wait for EOF before shutdown(SHUT_RD) and close() */ GHashTable *plugins; /**< const gchar* => (plugin*) */ @@ -67,11 +66,6 @@ struct server { gboolean exiting; - GString *tmp_str; /**< can be used everywhere for local temporary needed strings */ - - time_t last_generated_date_ts; - GString *ts_date_str; /**< use server_current_timestamp(srv) */ - /* logs */ gboolean rotate_logs; GHashTable *logs; @@ -84,9 +78,8 @@ struct server { ev_tstamp started; statistics_t stats; - /* keep alive timeout queue */ + /* keep alive timeout */ guint keep_alive_queue_timeout; - GQueue keep_alive_queue; }; @@ -103,11 +96,6 @@ LI_API void server_stop(server *srv); /* close connections, close logs, stop log-thread */ LI_API void server_exit(server *srv); -LI_API void joblist_append(server *srv, connection *con); - -LI_API GString *server_current_timestamp(server *srv); - -/* shutdown write and wait for eof before shutdown read and close */ -LI_API void server_add_closing_socket(server *srv, int fd); +LI_API void joblist_append(connection *con); #endif diff --git a/src/worker.c b/src/worker.c new file mode 100644 index 0000000..829baef --- /dev/null +++ b/src/worker.c @@ -0,0 +1,146 @@ + +#include "base.h" + +void con_put(connection *con); + +/* closing sockets - wait for proper shutdown */ + +struct worker_closing_socket; +typedef struct worker_closing_socket worker_closing_socket; + +struct worker_closing_socket { + worker *wrk; + GList *link; + int fd; +}; + +static void worker_closing_socket_cb(int revents, void* arg) { + worker_closing_socket *scs = (worker_closing_socket*) arg; + UNUSED(revents); + + /* Whatever happend: we just close the socket */ + shutdown(scs->fd, SHUT_RD); + close(scs->fd); + g_queue_delete_link(&scs->wrk->closing_sockets, scs->link); + g_slice_free(worker_closing_socket, scs); +} + +void worker_add_closing_socket(worker *wrk, int fd) { + worker_closing_socket *scs = g_slice_new0(worker_closing_socket); + + shutdown(fd, SHUT_WR); + + scs->wrk = wrk; + scs->fd = fd; + g_queue_push_tail(&wrk->closing_sockets, scs); + scs->link = g_queue_peek_tail_link(&wrk->closing_sockets); + + ev_once(wrk->loop, fd, EV_READ, 10.0, worker_closing_socket_cb, scs); +} + +/* Kill it - frees fd */ +/* +static void worker_rem_closing_socket(worker *wrk, worker_closing_socket *scs) { + ev_feed_fd_event(wrk->loop, scs->fd, EV_READ); +} +*/ + +/* Keep alive */ + +void worker_check_keepalive(worker *wrk) { + ev_tstamp now = ev_now(wrk->loop); + + if (0 == wrk->keep_alive_queue.length) { + ev_timer_stop(wrk->loop, &wrk->keep_alive_timer); + } else { + wrk->keep_alive_timer.repeat = ((connection*)g_queue_peek_head(&wrk->keep_alive_queue))->keep_alive_data.timeout - now + 1; + ev_timer_again(wrk->loop, &wrk->keep_alive_timer); + } +} + +static void worker_keepalive_cb(struct ev_loop *loop, ev_timer *w, int revents) { + worker *wrk = (worker*) w->data; + ev_tstamp now = ev_now(wrk->loop); + GQueue *q = &wrk->keep_alive_queue; + GList *l; + connection *con; + + UNUSED(loop); + UNUSED(revents); + + while ( NULL != (l = g_queue_peek_head_link(q)) && + (con = (connection*) l->data)->keep_alive_data.timeout <= now ) { + ev_tstamp remaining = con->keep_alive_data.max_idle - wrk->srv->keep_alive_queue_timeout - (now - con->keep_alive_data.timeout); + if (remaining > 0) { + g_queue_delete_link(q, l); + con->keep_alive_data.link = NULL; + ev_timer_set(&con->keep_alive_data.watcher, remaining, 0); + ev_timer_start(wrk->loop, &con->keep_alive_data.watcher); + } else { + /* close it */ + con_put(con); + } + } + + if (NULL == l) { + ev_timer_stop(wrk->loop, &wrk->keep_alive_timer); + } else { + wrk->keep_alive_timer.repeat = con->keep_alive_data.timeout - now + 1; + ev_timer_again(wrk->loop, &wrk->keep_alive_timer); + } +} + +/* cache timestamp */ +GString *worker_current_timestamp(worker *wrk) { + time_t cur_ts = CUR_TS(wrk); + if (cur_ts != wrk->last_generated_date_ts) { + g_string_set_size(wrk->ts_date_str, 255); + strftime(wrk->ts_date_str->str, wrk->ts_date_str->allocated_len, + "%a, %d %b %Y %H:%M:%S GMT", gmtime(&(cur_ts))); + + g_string_set_size(wrk->ts_date_str, strlen(wrk->ts_date_str->str)); + + wrk->last_generated_date_ts = cur_ts; + } + return wrk->ts_date_str; +} + +/* init */ + +worker* worker_new(struct server *srv, struct ev_loop *loop) { + worker *wrk = g_slice_new0(worker); + wrk->srv = srv; + wrk->loop = loop; + + g_queue_init(&wrk->keep_alive_queue); + ev_init(&wrk->keep_alive_timer, worker_keepalive_cb); + wrk->keep_alive_timer.data = wrk; + + wrk->tmp_str = g_string_sized_new(255); + + wrk->last_generated_date_ts = 0; + wrk->ts_date_str = g_string_sized_new(255); + + return wrk; +} + +void worker_free(worker *wrk) { + if (!wrk) return; + + { /* force closing sockets */ + GList *iter; + for (iter = g_queue_peek_head_link(&wrk->closing_sockets); iter; iter = g_list_next(iter)) { + worker_closing_socket_cb(EV_TIMEOUT, (worker_closing_socket*) iter->data); + } + g_queue_clear(&wrk->closing_sockets); + } + + g_string_free(wrk->tmp_str, TRUE); + g_string_free(wrk->ts_date_str, TRUE); + + g_slice_free(worker, wrk); +} + +void worker_run(worker *wrk) { + ev_loop(wrk->loop, 0); +} diff --git a/src/worker.h b/src/worker.h new file mode 100644 index 0000000..7662645 --- /dev/null +++ b/src/worker.h @@ -0,0 +1,46 @@ +#ifndef _LIGHTTPD_WORKER_H_ +#define _LIGHTTPD_WORKER_H_ + +struct worker; +typedef struct worker worker; + +struct server; + +#include "settings.h" + +#define CUR_TS(wrk) ((time_t)ev_now((wrk)->loop)) + +struct worker { + struct server *srv; + + struct ev_loop *loop; + ev_prepare loop_prepare; + ev_check loop_check; + + GQueue closing_sockets; /** wait for EOF before shutdown(SHUT_RD) and close() */ + + GString *tmp_str; /**< can be used everywhere for local temporary needed strings */ + + /* keep alive timeout queue */ + ev_timer keep_alive_timer; + GQueue keep_alive_queue; + + guint connection_load; + + time_t last_generated_date_ts; + GString *ts_date_str; /**< use server_current_timestamp(srv) */ +}; + +LI_API worker* worker_new(struct server *srv, struct ev_loop *loop); +LI_API void worker_free(worker *wrk); + +LI_API void worker_run(worker *wrk); + +LI_API void worker_check_keepalive(worker *wrk); + +LI_API GString *worker_current_timestamp(worker *wrk); + +/* shutdown write and wait for eof before shutdown read and close */ +LI_API void worker_add_closing_socket(worker *wrk, int fd); + +#endif diff --git a/src/wscript b/src/wscript index ccf3d5b..202d56f 100644 --- a/src/wscript +++ b/src/wscript @@ -31,6 +31,7 @@ common_source=''' sys-socket.c url_parser.rl utils.c + worker.c plugin_core.c '''