Browse Source

server/connection/request functions

personal/stbuehler/wip
Stefan Bühler 14 years ago
parent
commit
0a514f657e
  1. 8
      src/angel.h
  2. 9
      src/chunk.h
  3. 5
      src/chunk_parser.c
  4. 7
      src/chunk_parser.h
  5. 127
      src/connection.c
  6. 37
      src/connection.h
  7. 4
      src/http_headers.c
  8. 1
      src/http_headers.h
  9. 14
      src/http_request_parser.h
  10. 20
      src/http_request_parser.rl
  11. 2
      src/log.c
  12. 114
      src/network.c
  13. 18
      src/network.h
  14. 46
      src/request.c
  15. 8
      src/request.h
  16. 128
      src/server.c
  17. 46
      src/server.h
  18. 14
      src/tests.c
  19. 25
      src/utils.c
  20. 11
      src/utils.h
  21. 5
      src/wscript

8
src/angel.h

@ -0,0 +1,8 @@
#ifndef _LIGHTTPD_ANGEL_H_
#define _LIGHTTPD_ANGEL_H_
/* interface to the angel; implementation needs to work without angel too */
#endif

9
src/chunk.h

@ -15,9 +15,12 @@ typedef struct chunkqueue chunkqueue;
struct chunkiter;
typedef struct chunkiter chunkiter;
struct server;
struct connection;
#define CONST_STR_LEN(x) x, x ? sizeof(x) - 1 : 0
#include "base.h"
#include "settings.h"
/* Open a file only once, so it shouldn't get lost;
* as a file may get split into many chunks, we
@ -75,7 +78,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(server *srv, connection *con, chunkfile *cf);
LI_API handler_t chunkfile_open(struct server *srv, struct connection *con, chunkfile *cf);
/******************
* chunk iterator *
@ -91,7 +94,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(server *srv, connection *con, chunkiter iter, off_t start, off_t length, char **data_start, off_t *data_len);
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);
/******************
* chunk *

5
src/chunk_parser.c

@ -1,8 +1,13 @@
#include "base.h"
#include "chunk_parser.h"
void chunk_parser_init(chunk_parser_ctx *ctx, chunkqueue *cq) {
ctx->cq = cq;
chunk_parser_reset(ctx);
}
void chunk_parser_reset(chunk_parser_ctx *ctx) {
ctx->bytes_in = 0;
ctx->curi.element = NULL;
ctx->start = 0;

7
src/chunk_parser.h

@ -30,12 +30,13 @@ 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(server *srv, connection *con, chunk_parser_ctx *ctx, char **p, char **pe);
LI_API handler_t chunk_parser_next(struct server *srv, 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(server *srv, connection *con, chunk_parser_mark from, chunk_parser_mark to, GString *dest);
LI_API GString* chunk_extract(server *srv, connection *con, chunk_parser_mark from, chunk_parser_mark to);
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);
INLINE chunk_parser_mark chunk_parser_getmark(chunk_parser_ctx *ctx, const char *fpc);

127
src/connection.c

@ -0,0 +1,127 @@
#include "connection.h"
#include "network.h"
#include "log.h"
static void parse_request_body(server *srv, connection *con) {
if (con->state == CON_STATE_HANDLE_RESPONSE && !con->in->is_closed) {
/* TODO: parse chunked encoded request body */
if (con->in->bytes_in < con->request.content_length) {
chunkqueue_steal_len(con->in, con->raw_in, con->request.content_length - con->in->bytes_in);
if (con->in->bytes_in == con->request.content_length) con->in->is_closed = TRUE;
} else if (con->request.content_length == -1) {
chunkqueue_steal_all(con->in, con->raw_in);
}
}
}
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;
if (revents && EV_READ) {
if (con->in->is_closed) {
/* don't read the next request before current one is done */
ev_io_set(w, w->fd, w->events && ~EV_READ);
} else {
switch(network_read(srv, con, w->fd, con->raw_in)) {
case NETWORK_STATUS_SUCCESS:
parse_request_body(srv, con);
joblist_append(srv, con);
break;
case NETWORK_STATUS_FATAL_ERROR:
connection_set_state(srv, con, CON_STATE_ERROR);
joblist_append(srv, con);
break;
case NETWORK_STATUS_CONNECTION_CLOSE:
connection_set_state(srv, con, CON_STATE_CLOSE);
joblist_append(srv, con);
break;
case NETWORK_STATUS_WAIT_FOR_EVENT:
break;
case NETWORK_STATUS_WAIT_FOR_AIO_EVENT:
/* TODO ? */
ev_io_set(w, w->fd, w->events && ~EV_READ);
break;
case NETWORK_STATUS_WAIT_FOR_FD:
/* TODO */
break;
}
}
}
if (revents && EV_WRITE) {
if (con->raw_out->length > 0) {
network_write(srv, con, w->fd, con->raw_out);
joblist_append(srv, con);
}
if (con->raw_out->length == 0) {
ev_io_set(w, w->fd, w->events && ~EV_WRITE);
}
}
}
connection* connection_new(server *srv) {
connection *con = g_slice_new0(connection);
UNUSED(srv);
con->raw_in = chunkqueue_new();
con->raw_out = chunkqueue_new();
con->in = chunkqueue_new();
con->out = chunkqueue_new();
con->sock.srv = srv; con->sock.con = con; con->sock.watcher.data = con;
ev_io_init(&con->sock.watcher, connection_cb, -1, 0);
con->remote_addr_str = g_string_sized_new(0);
con->local_addr_str = g_string_sized_new(0);
action_stack_init(&con->action_stack);
request_init(&con->request, con->raw_in);
return con;
}
void connection_reset(server *srv, connection *con) {
chunkqueue_reset(con->raw_in);
chunkqueue_reset(con->raw_out);
chunkqueue_reset(con->in);
chunkqueue_reset(con->out);
ev_io_stop(srv->loop, &con->sock.watcher);
close(con->sock.watcher.fd);
ev_io_set(&con->sock.watcher, -1, 0);
g_string_truncate(con->remote_addr_str, 0);
g_string_truncate(con->local_addr_str, 0);
action_stack_reset(srv, &con->action_stack);
request_reset(&con->request);
}
void connection_free(server *srv, connection *con) {
chunkqueue_free(con->raw_in);
chunkqueue_free(con->raw_out);
chunkqueue_free(con->in);
chunkqueue_free(con->out);
ev_io_stop(srv->loop, &con->sock.watcher);
close(con->sock.watcher.fd);
ev_io_set(&con->sock.watcher, -1, 0);
g_string_free(con->remote_addr_str, TRUE);
g_string_free(con->local_addr_str, TRUE);
action_stack_clear(srv, &con->action_stack);
request_clear(&con->request);
g_slice_free(connection, con);
}
void connection_set_state(server *srv, connection *con, connection_state_t state) {
}
void connection_state_machine(server *srv, connection *con) {
}

37
src/connection.h

@ -1,23 +1,54 @@
#ifndef _LIGHTTPD_CONNECTION_H_
#define _LIGHTTPD_CONNECTION_H_
#include "base.h"
typedef enum {
CON_STATE_REQUEST_START, /** after the connect, the request is initialized, keep-alive starts here again */
CON_STATE_READ_REQUEST_HEADER, /** loop in the read-request-header until the full header is received */
CON_STATE_VALIDATE_REQUEST_HEADER, /** validate the request-header */
CON_STATE_HANDLE_RESPONSE, /** find a handler for the request */
CON_STATE_RESPONSE_END, /** successful request, connection closed */
CON_STATE_ERROR, /** fatal error, connection closed */
CON_STATE_CLOSE /** connection reset by peer */
} 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 */
connection_state_t state;
chunkqueue *raw_in, *raw_out;
chunkqueue *in, *out;
connection_socket sock;
sock_addr remote_addr, local_addr;
GString *remote_addr_str, *local_addr_str;
gboolean is_ssl;
action_stack action_stack;
gpointer *options;
gpointer *options; /* TODO */
request request;
physical physical;
GMutex *mutex;
struct log_t *log;
gint log_level;
};
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_set_state(server *srv, connection *con, connection_state_t state);
#endif

4
src/http_headers.c

@ -13,6 +13,10 @@ http_headers* http_headers_new() {
return headers;
}
void http_headers_reset(http_headers* headers) {
g_hash_table_remove_all(headers->table);
}
void http_headers_free(http_headers* headers) {
if (!headers) return;
g_hash_table_destroy(headers->table);

1
src/http_headers.h

@ -14,6 +14,7 @@ struct http_headers {
/* strings alweays get copied, so you should free key and value yourself */
LI_API http_headers* http_headers_new();
LI_API void http_headers_reset(http_headers* headers);
LI_API void http_headers_free(http_headers* headers);
/** If header does not exist, just insert normal header. If it exists, append (", %s", value) */

14
src/http_request_parser.h

@ -5,20 +5,24 @@ struct http_request_ctx;
typedef struct http_request_ctx http_request_ctx;
#include "chunk_parser.h"
#include "request.h"
struct request;
struct http_request_ctx {
chunk_parser_ctx chunk_ctx;
request *request;
struct request *request;
chunk_parser_mark mark;
GString *h_key, *h_value;
};
LI_API http_request_ctx* http_request_parser_new(request *req, chunkqueue *cq);
LI_API void http_request_parser_free(http_request_ctx *ctx);
#include "request.h"
LI_API void http_request_parser_init(http_request_ctx* ctx, request *req, chunkqueue *cq);
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(server *srv, connection *con, http_request_ctx *ctx);
LI_API handler_t http_request_parse(struct server *srv, struct connection *con, http_request_ctx *ctx);
#endif

20
src/http_request_parser.rl

@ -1,4 +1,5 @@
#include "base.h"
#include "http_request_parser.h"
/** Machine **/
@ -125,25 +126,26 @@ static int http_request_parser_is_finished(http_request_ctx *ctx) {
return ctx->chunk_ctx.cs >= http_request_parser_first_final;
}
http_request_ctx* http_request_parser_new(request *req, chunkqueue *cq) {
http_request_ctx *ctx = g_slice_new0(http_request_ctx);
%% write init;
void http_request_parser_init(http_request_ctx* ctx, request *req, chunkqueue *cq) {
chunk_parser_init(&ctx->chunk_ctx, cq);
ctx->request = req;
ctx->h_key = g_string_sized_new(0);
ctx->h_value = g_string_sized_new(0);
return ctx;
%% write init;
}
void http_request_parser_free(http_request_ctx *ctx) {
if (!ctx) return;
void http_request_parser_reset(http_request_ctx* ctx) {
chunk_parser_reset(&ctx->chunk_ctx);
g_string_truncate(ctx->h_key, 0);
g_string_truncate(ctx->h_value, 0);
%% write init;
}
void http_request_parser_clear(http_request_ctx *ctx) {
g_string_free(ctx->h_key, TRUE);
g_string_free(ctx->h_value, TRUE);
g_slice_free(http_request_ctx, ctx);
}
handler_t http_request_parse(server *srv, connection *con, http_request_ctx *ctx) {

2
src/log.c

@ -206,7 +206,7 @@ log_t *log_new(server *srv, log_type_t type, GString *path) {
if (log != NULL)
{
g_atomic_int_inc(&log->refcount);
g_mutex_unlock(srv->mutex);
g_mutex_unlock(srv->log_mutex);
return log;
}

114
src/network.c

@ -0,0 +1,114 @@
#include "network.h"
/** repeats write after EINTR */
static ssize_t net_write(int fd, void *buf, ssize_t nbyte) {
ssize_t r;
while (-1 == (r = write(fd, buf, nbyte))) {
switch (errno) {
case EINTR:
/* Try again */
break;
default:
/* report error */
return r;
}
}
/* return bytes written */
return r;
}
network_status_t network_write(server *srv, connection *con, int fd, chunkqueue *cq) {
const ssize_t blocksize = 16*1024; /* 16k */
const off_t max_write = 16 * blocksize; /* 256k */
char *block_data;
off_t block_len;
ssize_t r;
off_t len;
chunkiter ci;
do {
ci = chunkqueue_iter(cq);
switch (chunkiter_read(srv, con, ci, 0, blocksize, &block_data, &block_len)) {
case HANDLER_GO_ON:
break;
case HANDLER_WAIT_FOR_FD:
return len ? NETWORK_STATUS_SUCCESS : NETWORK_STATUS_WAIT_FOR_EVENT;
case HANDLER_ERROR:
default:
return NETWORK_STATUS_FATAL_ERROR;
}
if (-1 == (r = net_write(fd, block_data, block_len))) {
switch (errno) {
case EAGAIN:
#if EWOULDBLOCK != EAGAIN
case EWOULDBLOCK
#endif
return len ? NETWORK_STATUS_SUCCESS : NETWORK_STATUS_WAIT_FOR_EVENT;
case ECONNRESET:
return NETWORK_STATUS_CONNECTION_CLOSE;
default:
CON_ERROR(srv, con, "oops, read from fd=%d failed: %s (%d)", fd, strerror(errno), errno );
return NETWORK_STATUS_FATAL_ERROR;
}
} else if (0 == r) {
return len ? NETWORK_STATUS_SUCCESS : NETWORK_STATUS_WAIT_FOR_EVENT;
}
chunkqueue_skip(cq, r);
len += r;
} while (r == blocksize && len < max_write);
return NETWORK_STATUS_SUCCESS;
}
/** repeats read after EINTR */
static ssize_t net_read(int fd, void *buf, ssize_t nbyte) {
ssize_t r;
while (-1 == (r = read(fd, buf, nbyte))) {
switch (errno) {
case EINTR:
/* Try again */
break;
default:
/* report error */
return r;
}
}
/* return bytes read */
return r;
}
network_status_t network_read(server *srv, connection *con, int fd, chunkqueue *cq) {
const ssize_t blocksize = 16*1024; /* 16k */
const off_t max_read = 16 * blocksize; /* 256k */
ssize_t r;
off_t len;
do {
GString *buf = g_string_sized_new(blocksize);
if (-1 == (r = net_read(fd, buf->str, blocksize))) {
g_string_free(buf, TRUE);
switch (errno) {
case EAGAIN:
#if EWOULDBLOCK != EAGAIN
case EWOULDBLOCK
#endif
return len ? NETWORK_STATUS_SUCCESS : NETWORK_STATUS_WAIT_FOR_EVENT;
case ECONNRESET:
return NETWORK_STATUS_CONNECTION_CLOSE;
default:
CON_ERROR(srv, con, "oops, read from fd=%d failed: %s (%d)", fd, strerror(errno), errno );
return NETWORK_STATUS_FATAL_ERROR;
}
} else if (0 == r) {
g_string_free(buf, TRUE);
return len ? NETWORK_STATUS_SUCCESS : NETWORK_STATUS_CONNECTION_CLOSE;
}
g_string_truncate(buf, r);
chunkqueue_append_string(cq, buf);
len += r;
} while (r == blocksize && len < max_read);
return NETWORK_STATUS_SUCCESS;
}

18
src/network.h

@ -0,0 +1,18 @@
#ifndef _LIGHTTPD_NETWORK_H_
#define _LIGHTTPD_NETWORK_H_
#include "base.h"
typedef enum {
NETWORK_STATUS_SUCCESS,
NETWORK_STATUS_FATAL_ERROR,
NETWORK_STATUS_CONNECTION_CLOSE,
NETWORK_STATUS_WAIT_FOR_EVENT,
NETWORK_STATUS_WAIT_FOR_AIO_EVENT,
NETWORK_STATUS_WAIT_FOR_FD,
} network_status_t;
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);
#endif

46
src/request.c

@ -1,9 +1,8 @@
#include "base.h"
#include "request.h"
request* request_new() {
request *req = g_slice_new0(request);
void request_init(request *req, chunkqueue *in) {
req->http_method = HTTP_METHOD_UNSET;
req->http_method_str = g_string_sized_new(0);
req->http_version = HTTP_VERSION_UNSET;
@ -19,10 +18,43 @@ request* request_new() {
req->host = g_string_sized_new(0);
req->content_length = -1;
return req;
http_request_parser_init(&req->parser_ctx, req, in);
}
void request_free(request *req) {
/* TODO */
g_slice_free(request, req);
void request_reset(request *req) {
req->http_method = HTTP_METHOD_UNSET;
g_string_truncate(req->http_method_str, 0);
req->http_version = HTTP_VERSION_UNSET;
g_string_truncate(req->uri.uri, 0);
g_string_truncate(req->uri.orig_uri, 0);
g_string_truncate(req->uri.scheme, 0);
g_string_truncate(req->uri.path, 0);
g_string_truncate(req->uri.query, 0);
http_headers_reset(req->headers);
g_string_truncate(req->host, 0);
req->content_length = -1;
http_request_parser_reset(&req->parser_ctx);
}
void request_clear(request *req) {
req->http_method = HTTP_METHOD_UNSET;
g_string_free(req->http_method_str, TRUE);
req->http_version = HTTP_VERSION_UNSET;
g_string_free(req->uri.uri, TRUE);
g_string_free(req->uri.orig_uri, TRUE);
g_string_free(req->uri.scheme, TRUE);
g_string_free(req->uri.path, TRUE);
g_string_free(req->uri.query, TRUE);
http_headers_free(req->headers);
g_string_free(req->host, TRUE);
req->content_length = -1;
http_request_parser_clear(&req->parser_ctx);
}

8
src/request.h

@ -44,6 +44,7 @@ struct physical;
typedef struct physical physical;
#include "http_headers.h"
#include "http_request_parser.h"
struct request_uri {
GString *uri, *orig_uri;
@ -76,9 +77,12 @@ struct request {
/* Parsed headers: */
GString *host;
goffset content_length;
http_request_ctx parser_ctx;
};
LI_API request* request_new();
LI_API void request_free(request *req);
LI_API void request_init(request *req, chunkqueue *in);
LI_API void request_reset(request *req);
LI_API void request_clear(request *req);
#endif

128
src/server.c

@ -1,6 +1,6 @@
#include "base.h"
#include "log.h"
#include "utils.h"
static void server_option_free(gpointer _so) {
g_slice_free(server_option, _so);
@ -16,12 +16,27 @@ static void server_setup_free(gpointer _ss) {
server* server_new() {
server* srv = g_slice_new0(server);
srv->magic = LIGHTTPD_SERVER_MAGIC;
srv->state = SERVER_STARTING;
srv->loop = ev_default_loop (0);
if (!srv->loop) {
fatal ("could not initialise libev, bad $LIBEV_FLAGS in environment?");
}
srv->connections_active = 0;
srv->connections = g_array_new(FALSE, TRUE, sizeof(connection*));
srv->sockets = g_array_new(FALSE, TRUE, sizeof(server_socket*));
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);
srv->actions = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, server_action_free);
srv->setups = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, server_setup_free);
srv->mutex = g_mutex_new();
srv->mainaction = action_new_list();
srv->mainaction = NULL;
srv->exiting = FALSE;
return srv;
}
@ -34,7 +49,6 @@ void server_free(server* srv) {
g_hash_table_destroy(srv->actions);
g_hash_table_destroy(srv->setups);
g_hash_table_destroy(srv->plugins);
g_mutex_free(srv->mutex);
action_release(srv, srv->mainaction);
@ -52,3 +66,109 @@ void server_free(server* srv) {
g_slice_free(server, srv);
}
static connection* con_get(server *srv) {
connection *con;
if (srv->connections_active >= srv->connections->len) {
con = connection_new(srv);
con->idx = srv->connections_active++;
g_array_append_val(srv->connections, con);
} else {
con = g_array_index(srv->connections, connection*, srv->connections_active++);
}
return con;
}
static void con_put(server *srv, connection *con) {
connection_reset(srv, con);
srv->connections_active--;
if (con->idx != srv->connections_active) {
/* Swap [con->idx] and [srv->connections_active] */
connection *tmp;
assert(con->idx < srv->connections_active); /* con must be an active connection) */
tmp = g_array_index(srv->connections, connection*, srv->connections_active);
tmp->idx = con->idx;
con->idx = srv->connections_active;
g_array_index(srv->connections, connection*, con->idx) = con;
g_array_index(srv->connections, connection*, tmp->idx) = tmp;
}
}
static void server_listen_cb(struct ev_loop *loop, ev_io *w, int revents) {
server_socket *sock = (server_socket*) w->data;
server *srv = sock->srv;
int s;
sock_addr remote_addr;
socklen_t l = sizeof(remote_addr);
UNUSED(loop);
UNUSED(revents);
while (-1 != (s = accept(w->fd, (struct sockaddr*) &remote_addr, &l))) {
connection *con = con_get(srv);
con->remote_addr = remote_addr;
ev_io_set(&con->sock.watcher, s, EV_READ);
ev_io_start(srv->loop, &con->sock.watcher);
}
#ifdef _WIN32
errno = WSAGetLastError();
#endif
switch (errno) {
case EAGAIN:
#if EWOULDBLOCK != EAGAIN
case EWOULDBLOCK:
#endif
case EINTR:
/* we were stopped _before_ we had a connection */
case ECONNABORTED: /* this is a FreeBSD thingy */
/* we were stopped _after_ we had a connection */
break;
case EMFILE: /* we are out of FDs */
/* TODO: server_out_of_fds(srv, NULL); */
break;
default:
ERROR(srv, "accept failed on fd=%d with error: (%d) %s", w->fd, errno, strerror(errno));
break;
}
}
void server_listen(server *srv, int fd) {
server_socket *sock;
sock = g_slice_new0(server_socket);
sock->srv = srv;
sock->watcher.data = sock;
fd_init(fd);
ev_io_init(&sock->watcher, server_listen_cb, fd, EV_READ);
if (srv->state == SERVER_RUNNING) ev_io_start(srv->loop, &sock->watcher);
g_array_append_val(srv->sockets, sock);
}
void server_start(server *srv) {
guint i;
if (srv->state == SERVER_STOPPING || srv->state == SERVER_RUNNING) return; /* no restart after stop */
srv->state = SERVER_RUNNING;
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);
}
}
void server_stop(server *srv) {
guint i;
if (srv->state == SERVER_STOPPING) return;
srv->state = SERVER_STOPPING;
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);
}
}
void joblist_append(server *srv, connection *con) {
/* TODO */
}

46
src/server.h

@ -1,23 +1,45 @@
#ifndef _LIGHTTPD_SERVER_H_
#define _LIGHTTPD_SERVER_H_
#ifndef LIGHTTPD_SERVER_MAGIC
#define LIGHTTPD_SERVER_MAGIC ((guint)0x12AB34CD)
#endif
typedef enum {
SERVER_STARTING, /** start up: don't write log files, don't accept connections */
SERVER_RUNNING, /** running: write logs, accept connections */
SERVER_STOPPING /** stopping: flush logs, don't accept new connections */
} server_state;
struct server_socket;
typedef struct server_socket server_socket;
struct server_socket {
server *srv;
ev_io watcher;
};
struct server {
guint version;
guint32 magic; /** server magic version, check against LIGHTTPD_SERVER_MAGIC in plugins */
server_state state;
GHashTable *plugins;
struct ev_loop *loop;
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*) */
GHashTable *plugins; /**< const gchar* => (plugin*) */
/* registered by plugins */
GHashTable *options; /**< const gchar* => server_option* */
GHashTable *actions; /**< const gchar* => server_action* */
GHashTable *setups; /**< const gchar* => server_setup* */
GHashTable *options; /**< const gchar* => (server_option*) */
GHashTable *actions; /**< const gchar* => (server_action*) */
GHashTable *setups; /**< const gchar* => (server_setup*) */
gpointer *option_def_values;
gpointer *option_def_values; /* TODO */
struct action *mainaction;
gboolean exiting;
GMutex *mutex; /* general mutex for accessing the various members */
/* logs */
gboolean rotate_logs;
@ -30,7 +52,13 @@ struct server {
};
server* server_new();
void server_free(server* srv);
LI_API server* server_new();
LI_API void server_free(server* srv);
LI_API void server_listen(server *srv, int fd);
LI_API void server_start(server *srv);
LI_API void joblist_append(server *srv, connection *con);
#endif

14
src/tests.c

@ -9,14 +9,11 @@
int request_test() {
chunkqueue *cq;
request *req;
http_request_ctx *ctx;
request req;
handler_t res;
cq = chunkqueue_new();
req = request_new();
ctx = http_request_parser_new(req, cq);
request_init(&req, cq);
chunkqueue_append_mem(cq, CONST_STR_LEN(
"GET / HTTP/1.1\r\n"
@ -25,15 +22,16 @@ int request_test() {
"abc"
));
res = http_request_parse(NULL, NULL, ctx);
res = http_request_parse(NULL, NULL, &req.parser_ctx);
if (res != HANDLER_GO_ON) {
fprintf(stderr, "Parser return %i", res);
}
assert(req->http_method == HTTP_METHOD_GET);
assert(req.http_method == HTTP_METHOD_GET);
assert(cq->length == 3);
http_request_parser_free(ctx);
request_clear(&req);
chunkqueue_free(cq);
return res == HANDLER_GO_ON ? 0 : 1;
}

25
src/utils.c

@ -0,0 +1,25 @@
#include "utils.h"
#include <stdio.h>
#include <stdlib.h>
void fatal(const gchar* msg) {
fprintf(stderr, "%s\n", msg);
abort();
}
void fd_init(int fd) {
#ifdef _WIN32
int i = 1;
#endif
#ifdef FD_CLOEXEC
/* close fd on exec (cgi) */
fcntl(fd, F_SETFD, FD_CLOEXEC);
#endif
#ifdef O_NONBLOCK
fcntl(fd, F_SETFL, O_NONBLOCK | O_RDWR);
#elif defined _WIN32
ioctlsocket(fd, FIONBIO, &i);
#endif
}

11
src/utils.h

@ -0,0 +1,11 @@
#ifndef _LIGHTTPD_UTILS_H_
#define _LIGHTTPD_UTILS_H_
#include "settings.h"
LI_API void fatal(const gchar* msg);
/* set O_NONBLOCK and FD_CLOEXEC */
LI_API void fd_init(int fd);
#endif

5
src/wscript

@ -14,15 +14,18 @@ common_source='''
condition.c
condition_parsers.rl
config_parser.rl
connection.c
http_headers.c
http_request_parser.rl
log.c
network.c
options.c
plugin.c
request.c
server.c
sys-files.c
sys-socket.c
utils.c
plugin_core.c
'''
@ -143,7 +146,7 @@ def build(bld):
if env['LIB_lua']:
tests.source += common_source_lua
tests.target = 'tests'
tests.uselib += 'lighty dl openssl pcre lua ' + common_uselib
tests.uselib += 'lighty dl ev openssl pcre lua ' + common_uselib
def configure(conf):
env = conf.env

Loading…
Cancel
Save