merged from lp
commit
1844a53dd3
|
@ -0,0 +1,8 @@
|
|||
#ifndef _LIGHTTPD_ANGEL_H_
|
||||
#define _LIGHTTPD_ANGEL_H_
|
||||
|
||||
/* interface to the angel; implementation needs to work without angel too */
|
||||
|
||||
|
||||
|
||||
#endif
|
|
@ -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 *
|
||||
|
|
|
@ -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;
|
||||
|
@ -29,7 +34,7 @@ handler_t chunk_parser_next(server *srv, connection *con, chunk_parser_ctx *ctx,
|
|||
/* Wait at the end of the last chunk if it gets extended */
|
||||
if (!chunkiter_next(&i)) return HANDLER_WAIT_FOR_EVENT;
|
||||
ctx->curi = i;
|
||||
ctx->start = 0;
|
||||
ctx->start -= l;
|
||||
}
|
||||
|
||||
if (NULL == ctx->curi.element) return HANDLER_WAIT_FOR_EVENT;
|
||||
|
@ -48,8 +53,9 @@ void chunk_parser_done(chunk_parser_ctx *ctx, goffset len) {
|
|||
ctx->start += len;
|
||||
}
|
||||
|
||||
GString* chunk_extract(server *srv, connection *con, chunk_parser_mark from, chunk_parser_mark to) {
|
||||
GString *str = g_string_sized_new(0);
|
||||
gboolean chunk_extract_to(server *srv, connection *con, chunk_parser_mark from, chunk_parser_mark to, GString *dest) {
|
||||
g_string_set_size(dest, 0);
|
||||
|
||||
chunk_parser_mark i;
|
||||
for ( i = from; i.ci.element != to.ci.element; chunkiter_next(&i.ci) ) {
|
||||
goffset len = chunkiter_length(i.ci);
|
||||
|
@ -57,7 +63,7 @@ GString* chunk_extract(server *srv, connection *con, chunk_parser_mark from, chu
|
|||
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;
|
||||
g_string_append_len(str, buf, we_have);
|
||||
g_string_append_len(dest, buf, we_have);
|
||||
i.pos += we_have;
|
||||
}
|
||||
i.pos = 0;
|
||||
|
@ -66,13 +72,20 @@ GString* chunk_extract(server *srv, connection *con, chunk_parser_mark from, chu
|
|||
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;
|
||||
g_string_append_len(str, buf, we_have);
|
||||
g_string_append_len(dest, buf, we_have);
|
||||
i.pos += we_have;
|
||||
}
|
||||
|
||||
return str;
|
||||
return TRUE;
|
||||
|
||||
error:
|
||||
g_string_assign(dest, "");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
GString* chunk_extract(server *srv, 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;
|
||||
g_string_free(str, TRUE);
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -30,11 +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 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);
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
||||
}
|
|
@ -1,23 +1,54 @@
|
|||
#ifndef _LIGHTTPD_CONNECTION_H_
|
||||
#define _LIGHTTPD_CONNECTION_H_
|
||||
|
||||
struct connection {
|
||||
#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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) */
|
||||
|
|
|
@ -5,18 +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;
|
||||
struct request *request;
|
||||
|
||||
chunk_parser_mark mark;
|
||||
|
||||
request *request;
|
||||
GString *h_key, *h_value;
|
||||
};
|
||||
|
||||
LI_API void http_request_parser_init(http_request_ctx *ctx, request *req, chunkqueue *cq);
|
||||
LI_API handler_t http_request_parse(server *srv, connection *con, 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(struct server *srv, struct connection *con, http_request_ctx *ctx);
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
|
||||
#include "base.h"
|
||||
#include "http_request_parser.h"
|
||||
|
||||
/** Machine **/
|
||||
|
@ -6,6 +7,10 @@
|
|||
#define _getString(M, FPC) (chunk_extract(srv, 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(FPC, s) _getStringTo(mark, FPC, s)
|
||||
|
||||
|
||||
%%{
|
||||
|
||||
machine http_request_parser;
|
||||
|
@ -14,8 +19,19 @@
|
|||
action mark { ctx->mark = GETMARK(fpc); }
|
||||
action done { fbreak; }
|
||||
|
||||
action method { ctx->request->http_method_str = getString(fpc); }
|
||||
action uri { ctx->request->uri.uri = getString(fpc); }
|
||||
action method { getStringTo(fpc, ctx->request->http_method_str); }
|
||||
action uri { getStringTo(fpc, ctx->request->uri.uri); }
|
||||
|
||||
action header_key {
|
||||
getStringTo(fpc, ctx->h_key);
|
||||
g_string_truncate(ctx->h_value, 0);
|
||||
}
|
||||
action header_value {
|
||||
getStringTo(fpc, ctx->h_value);
|
||||
}
|
||||
action header {
|
||||
http_header_insert(ctx->request->headers, ctx->h_key, ctx->h_value);
|
||||
}
|
||||
|
||||
# RFC 2616
|
||||
OCTET = any;
|
||||
|
@ -48,7 +64,10 @@
|
|||
QDText = TEXT - DQUOTE;
|
||||
Quoted_String = DQUOTE ( QDText | Quoted_Pair )* DQUOTE;
|
||||
|
||||
HTTP_Version = "HTTP" "/" DIGIT+ "." DIGIT+;
|
||||
HTTP_Version = (
|
||||
"HTTP/1.0"
|
||||
| "HTTP/1.1"
|
||||
| "HTTP" "/" DIGIT+ "." DIGIT+ );
|
||||
#HTTP_URL = "http:" "//" Host ( ":" Port )? ( abs_path ( "?" query )? )?;
|
||||
|
||||
# RFC 2396
|
||||
|
@ -62,13 +81,37 @@
|
|||
Path_Segments = Segment ("/" Segment)*;
|
||||
Abs_Path = "/" Path_Segments;
|
||||
|
||||
Method = Token >mark %method;
|
||||
Request_URI = ("*" | ( any - CTL - SP )) >mark %uri;
|
||||
Method = (
|
||||
"GET" %{ ctx->request->http_method = HTTP_METHOD_GET; }
|
||||
| "POST" %{ ctx->request->http_method = HTTP_METHOD_POST; }
|
||||
| "HEAD" %{ ctx->request->http_method = HTTP_METHOD_HEAD; }
|
||||
| "OPTIONS" %{ ctx->request->http_method = HTTP_METHOD_OPTIONS; }
|
||||
| "PROPFIND" %{ ctx->request->http_method = HTTP_METHOD_PROPFIND; }
|
||||
| "MKCOL" %{ ctx->request->http_method = HTTP_METHOD_MKCOL; }
|
||||
| "PUT" %{ ctx->request->http_method = HTTP_METHOD_PUT; }
|
||||
| "DELETE" %{ ctx->request->http_method = HTTP_METHOD_DELETE; }
|
||||
| "COPY" %{ ctx->request->http_method = HTTP_METHOD_COPY; }
|
||||
| "MOVE" %{ ctx->request->http_method = HTTP_METHOD_MOVE; }
|
||||
| "PROPPATCH" %{ ctx->request->http_method = HTTP_METHOD_PROPPATCH; }
|
||||
| "REPORT" %{ ctx->request->http_method = HTTP_METHOD_REPORT; }
|
||||
| "CHKECOUT" %{ ctx->request->http_method = HTTP_METHOD_CHECKOUT; }
|
||||
| "CHECKIN" %{ ctx->request->http_method = HTTP_METHOD_CHECKIN; }
|
||||
| "VERSION-CONTROL" %{ ctx->request->http_method = HTTP_METHOD_VERSION_CONTROL; }
|
||||
| "UNCHECKOUT" %{ ctx->request->http_method = HTTP_METHOD_UNCHECKOUT; }
|
||||
| "MKACTIVITY" %{ ctx->request->http_method = HTTP_METHOD_MKACTIVITY; }
|
||||
| "MERGE" %{ ctx->request->http_method = HTTP_METHOD_MERGE; }
|
||||
| "LOCK" %{ ctx->request->http_method = HTTP_METHOD_LOCK; }
|
||||
| "UNLOCK" %{ ctx->request->http_method = HTTP_METHOD_UNLOCK; }
|
||||
| "LABEL" %{ ctx->request->http_method = HTTP_METHOD_LABEL; }
|
||||
| "CONNECT" %{ ctx->request->http_method = HTTP_METHOD_CONNECT; }
|
||||
| Token ) >mark >{ ctx->request->http_method = HTTP_METHOD_UNSET; } %method;
|
||||
|
||||
Request_URI = ("*" | ( any - CTL - SP )+) >mark %uri;
|
||||
Request_Line = Method " " Request_URI " " HTTP_Version CRLF;
|
||||
|
||||
Field_Content = ( TEXT+ | ( Token | Separators | Quoted_String )+ );
|
||||
Field_Value = " "* (Field_Content+ ( Field_Content | LWS )*)? >mark;
|
||||
Message_Header = Token ":" Field_Value?;
|
||||
Field_Value = " "* (Field_Content+ ( Field_Content | LWS )*)? >mark %header_value;
|
||||
Message_Header = Token >mark %header_key ":" Field_Value? % header;
|
||||
|
||||
main := (CRLF)* Request_Line (Message_Header CRLF)* CRLF @ done;
|
||||
}%%
|
||||
|
@ -83,15 +126,33 @@ static int http_request_parser_is_finished(http_request_ctx *ctx) {
|
|||
return ctx->chunk_ctx.cs >= http_request_parser_first_final;
|
||||
}
|
||||
|
||||
void http_request_parser_init(http_request_ctx *ctx, request *req, chunkqueue *cq) {
|
||||
%% 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);
|
||||
|
||||
%% write init;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
handler_t http_request_parse(server *srv, connection *con, http_request_ctx *ctx) {
|
||||
handler_t res;
|
||||
|
||||
if (http_request_parser_is_finished(ctx)) return HANDLER_GO_ON;
|
||||
|
||||
if (HANDLER_GO_ON != (res = chunk_parser_prepare(&ctx->chunk_ctx))) return res;
|
||||
|
||||
while (!http_request_parser_has_error(ctx) && !http_request_parser_is_finished(ctx)) {
|
||||
|
@ -101,10 +162,13 @@ handler_t http_request_parse(server *srv, connection *con, http_request_ctx *ctx
|
|||
|
||||
%% write exec;
|
||||
|
||||
chunk_parser_done(&ctx->chunk_ctx, pe - p);
|
||||
chunk_parser_done(&ctx->chunk_ctx, p - ctx->chunk_ctx.buf);
|
||||
}
|
||||
|
||||
if (http_request_parser_has_error(ctx)) return HANDLER_ERROR;
|
||||
if (http_request_parser_is_finished(ctx)) return HANDLER_GO_ON;
|
||||
if (http_request_parser_is_finished(ctx)) {
|
||||
chunkqueue_skip(ctx->chunk_ctx.cq, ctx->chunk_ctx.bytes_in);
|
||||
return HANDLER_GO_ON;
|
||||
}
|
||||
return HANDLER_ERROR;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -1,12 +1,60 @@
|
|||
|
||||
#include "base.h"
|
||||
#include "request.h"
|
||||
|
||||
request* request_new() {
|
||||
request *req = g_slice_new0(request);
|
||||
return req;
|
||||
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;
|
||||
|
||||
req->uri.uri = g_string_sized_new(0);
|
||||
req->uri.orig_uri = g_string_sized_new(0);
|
||||
req->uri.scheme = g_string_sized_new(0);
|
||||
req->uri.path = g_string_sized_new(0);
|
||||
req->uri.query = g_string_sized_new(0);
|
||||
|
||||
req->headers = http_headers_new();
|
||||
|
||||
req->host = g_string_sized_new(0);
|
||||
req->content_length = -1;
|
||||
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
125
src/server.c
125
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,11 +16,28 @@ 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->mainaction = NULL;
|
||||
|
||||
srv->exiting = FALSE;
|
||||
|
||||
return srv;
|
||||
}
|
||||
|
||||
|
@ -49,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 */
|
||||
}
|
||||
|
|
45
src/server.h
45
src/server.h
|
@ -1,19 +1,42 @@
|
|||
#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;
|
||||
|
@ -29,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
|
||||
|
|
|
@ -134,13 +134,14 @@
|
|||
#endif
|
||||
|
||||
|
||||
typedef enum { HANDLER_UNSET,
|
||||
HANDLER_GO_ON,
|
||||
HANDLER_FINISHED,
|
||||
HANDLER_COMEBACK,
|
||||
HANDLER_WAIT_FOR_EVENT,
|
||||
HANDLER_ERROR,
|
||||
HANDLER_WAIT_FOR_FD
|
||||
typedef enum {
|
||||
HANDLER_UNSET,
|
||||
HANDLER_GO_ON,
|
||||
HANDLER_FINISHED,
|
||||
HANDLER_COMEBACK,
|
||||
HANDLER_WAIT_FOR_EVENT,
|
||||
HANDLER_ERROR,
|
||||
HANDLER_WAIT_FOR_FD
|
||||
} handler_t;
|
||||
|
||||
/* Shared library support */
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
#ifndef FD_SETSIZE
|
||||
/* By default this is 64 */
|
||||
#define FD_SETSIZE 4096
|
||||
#endif
|
||||
#endif /* FD_SETSIZE */
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
//#include <wspiapi.h>
|
||||
|
@ -30,7 +30,7 @@
|
|||
#define STDERR_FILENO 2
|
||||
#ifndef __MINGW32__
|
||||
#define ssize_t int
|
||||
#endif
|
||||
#endif /* __MINGW32__ */
|
||||
|
||||
#define sockread( fd, buf, bytes ) recv( fd, buf, bytes, 0 )
|
||||
|
||||
|
@ -39,7 +39,7 @@ int inet_aton(const char *cp, struct in_addr *inp);
|
|||
#define HAVE_INET_ADDR
|
||||
#undef HAVE_INET_ATON
|
||||
|
||||
#else
|
||||
#else /* _WIN32 */
|
||||
#include <sys/types.h> /* required by netinet/tcp.h on FreeBSD */
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
@ -51,7 +51,7 @@ int inet_aton(const char *cp, struct in_addr *inp);
|
|||
#ifndef SUN_LEN
|
||||
#define SUN_LEN(su) \
|
||||
(sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path))
|
||||
#endif
|
||||
#endif /* SUN_LEN */
|
||||
|
||||
#define sockread( fd, buf, bytes ) read( fd, buf, bytes )
|
||||
#define closesocket(x) close(x)
|
||||
|
@ -63,8 +63,8 @@ int inet_aton(const char *cp, struct in_addr *inp);
|
|||
/* only define it if it isn't defined yet */
|
||||
#ifndef HAVE_IPV6
|
||||
#define HAVE_IPV6
|
||||
#endif
|
||||
#endif
|
||||
#endif /* HAVE_IPV6 */
|
||||
#endif /* HAVE_INET_NTOP */
|
||||
|
||||
typedef union {
|
||||
#ifdef HAVE_IPV6
|
||||
|
|
26
src/tests.c
26
src/tests.c
|
@ -9,27 +9,31 @@
|
|||
|
||||
int request_test() {
|
||||
chunkqueue *cq;
|
||||
request *req;
|
||||
http_request_ctx ctx;
|
||||
request req;
|
||||
handler_t res;
|
||||
|
||||
cq = chunkqueue_new();
|
||||
req = request_new();
|
||||
|
||||
http_request_parser_init(&ctx, req, cq);
|
||||
request_init(&req, cq);
|
||||
|
||||
chunkqueue_append_mem(cq, CONST_STR_LEN(
|
||||
"GET / HTTP/1.1\r\n"
|
||||
"Host: www.example.com\r\n"
|
||||
"\r\n"
|
||||
"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);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
assert(req.http_method == HTTP_METHOD_GET);
|
||||
assert(cq->length == 3);
|
||||
|
||||
request_clear(&req);
|
||||
chunkqueue_free(cq);
|
||||
|
||||
return res == HANDLER_GO_ON ? 0 : 1;
|
||||
}
|
||||
|
||||
int main() {
|
||||
|
@ -47,10 +51,10 @@ int main() {
|
|||
s = ipv6_tostring(ipv6);
|
||||
printf("parsed ipv6: %s/%u\n", s->str, network);
|
||||
|
||||
request_test();
|
||||
|
||||
return 0;
|
||||
|
||||
srv = server_new();
|
||||
|
||||
|
||||
return request_test();
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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
|
|
@ -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…
Reference in New Issue