From 01bfeb620b74f1a29dc236e791fca23d9204c9d5 Mon Sep 17 00:00:00 2001 From: Jianhui Zhao Date: Fri, 1 Jan 2021 18:16:07 +0800 Subject: [PATCH] OOP: Only expose APIs Hide the implementation details of the structure Signed-off-by: Jianhui Zhao --- example/example.c | 2 +- src/CMakeLists.txt | 1 - src/connection.c | 203 ++++++++++++++++++++++++------------------ src/connection.h | 52 +++-------- src/file.c | 7 +- src/uhttpd.c | 99 +++++++++++--------- src/uhttpd.h | 84 +++++++++++------ src/uhttpd_internal.h | 48 ++++++++++ 8 files changed, 292 insertions(+), 204 deletions(-) create mode 100644 src/uhttpd_internal.h diff --git a/example/example.c b/example/example.c index 4fe325b..f54f8eb 100644 --- a/example/example.c +++ b/example/example.c @@ -199,7 +199,7 @@ int main(int argc, char **argv) srv->set_docroot(srv, docroot); srv->set_index_page(srv, index_page); - srv->default_handler = default_handler; + srv->set_default_handler(srv, default_handler); srv->add_path_handler(srv, "/upload", upload_handler); diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8594fee..a80becf 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -141,7 +141,6 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in ${CMAKE_CURRENT_BINARY_DI install( FILES uhttpd.h - connection.h log.h buffer/buffer.h http-parser/http_parser.h diff --git a/src/connection.c b/src/connection.c index 3e8449f..8e8b647 100644 --- a/src/connection.c +++ b/src/connection.c @@ -30,65 +30,71 @@ #include #include -#include "connection.h" -#include "uhttpd.h" +#include "uhttpd_internal.h" #include "utils.h" #include "file.h" #include "ssl.h" static void conn_done(struct uh_connection *conn) { - struct ev_loop *loop = conn->srv->loop; + struct uh_connection_internal *conni = (struct uh_connection_internal *)conn; + struct ev_loop *loop = conni->srv->loop; - if (!http_should_keep_alive(&conn->parser)) - conn->flags |= CONN_F_SEND_AND_CLOSE; + if (!http_should_keep_alive(&conni->parser)) + conni->flags |= CONN_F_SEND_AND_CLOSE; - if (conn->flags & CONN_F_SEND_AND_CLOSE) - ev_io_stop(loop, &conn->ior); + if (conni->flags & CONN_F_SEND_AND_CLOSE) + ev_io_stop(loop, &conni->ior); - ev_io_start(loop, &conn->iow); + ev_io_start(loop, &conni->iow); - ev_timer_stop(loop, &conn->timer); + ev_timer_stop(loop, &conni->timer); /* This is needed for a connection requested multiple times on different path */ - conn->handler = NULL; + conni->handler = NULL; } static void conn_send(struct uh_connection *conn, const void *data, ssize_t len) { - buffer_put_data(&conn->wb, data, len); - ev_io_start(conn->srv->loop, &conn->iow); + struct uh_connection_internal *conni = (struct uh_connection_internal *)conn; + + buffer_put_data(&conni->wb, data, len); + ev_io_start(conni->srv->loop, &conni->iow); } static void conn_send_file(struct uh_connection *conn, const char *path) { + struct uh_connection_internal *conni = (struct uh_connection_internal *)conn; struct stat st; - conn->file.fd = open(path, O_RDONLY); + conni->file.fd = open(path, O_RDONLY); - fstat(conn->file.fd, &st); + fstat(conni->file.fd, &st); - conn->file.size = st.st_size; + conni->file.size = st.st_size; - ev_io_start(conn->srv->loop, &conn->iow); + ev_io_start(conni->srv->loop, &conni->iow); } static void conn_printf(struct uh_connection *conn, const char *format, ...) { - struct buffer *wb = &conn->wb; + struct uh_connection_internal *conni = (struct uh_connection_internal *)conn; + struct buffer *wb = &conni->wb; va_list arg; va_start(arg, format); buffer_put_vprintf(wb, format, arg); va_end(arg); - ev_io_start(conn->srv->loop, &conn->iow); + ev_io_start(conni->srv->loop, &conni->iow); } static void conn_vprintf(struct uh_connection *conn, const char *format, va_list arg) { - buffer_put_vprintf(&conn->wb, format, arg); - ev_io_start(conn->srv->loop, &conn->iow); + struct uh_connection_internal *conni = (struct uh_connection_internal *)conn; + + buffer_put_vprintf(&conni->wb, format, arg); + ev_io_start(conni->srv->loop, &conni->iow); } static void conn_chunk_send(struct uh_connection *conn, const void *data, ssize_t len) @@ -139,13 +145,15 @@ static void conn_send_status_line(struct uh_connection *conn, int code, const ch static void conn_send_head(struct uh_connection *conn, int code, int content_length, const char *extra_headers) { + struct uh_connection_internal *conni = (struct uh_connection_internal *)conn; + conn_send_status_line(conn, code, extra_headers); if (content_length < 0) conn_printf(conn, "%s", "Transfer-Encoding: chunked\r\n"); else conn_printf(conn, "Content-Length: %d\r\n", content_length); - if (!http_should_keep_alive(&conn->parser)) + if (!http_should_keep_alive(&conni->parser)) conn_printf(conn, "%s", "Connection: close\r\n"); conn_send(conn, "\r\n", 2); @@ -153,7 +161,9 @@ static void conn_send_head(struct uh_connection *conn, int code, int content_len static void conn_error(struct uh_connection *conn, int code, const char *reason) { - if (conn->flags & CONN_F_SEND_AND_CLOSE) + struct uh_connection_internal *conni = (struct uh_connection_internal *)conn; + + if (conni->flags & CONN_F_SEND_AND_CLOSE) return; if (!reason) @@ -161,14 +171,15 @@ static void conn_error(struct uh_connection *conn, int code, const char *reason) conn_send_head(conn, code, strlen(reason), "Content-Type: text/plain\r\nConnection: close\r\n"); conn_send(conn, reason, strlen(reason)); - conn->flags |= CONN_F_SEND_AND_CLOSE; + conni->flags |= CONN_F_SEND_AND_CLOSE; conn_done(conn); } static void conn_redirect(struct uh_connection *conn, int code, const char *location, ...) { - struct buffer *wb = &conn->wb; + struct uh_connection_internal *conni = (struct uh_connection_internal *)conn; + struct buffer *wb = &conni->wb; va_list arg; assert((code == HTTP_STATUS_MOVED_PERMANENTLY || code == HTTP_STATUS_FOUND) && location); @@ -189,17 +200,23 @@ static void conn_redirect(struct uh_connection *conn, int code, const char *loca static const struct sockaddr *conn_get_addr(struct uh_connection *conn) { - return &conn->addr.sa; + struct uh_connection_internal *conni = (struct uh_connection_internal *)conn; + + return &conni->addr.sa; } static enum http_method conn_get_method(struct uh_connection *conn) { - return conn->parser.method; + struct uh_connection_internal *conni = (struct uh_connection_internal *)conn; + + return conni->parser.method; } static const char *conn_get_method_str(struct uh_connection *conn) { - return http_method_str(conn->parser.method); + struct uh_connection_internal *conni = (struct uh_connection_internal *)conn; + + return http_method_str(conni->parser.method); } /* offset of the request field */ @@ -210,11 +227,12 @@ static const char *conn_get_method_str(struct uh_connection *conn) static struct uh_str conn_get_path(struct uh_connection *conn) { - struct http_parser_url *u = &conn->url_parser; - struct uh_request *req = &conn->req; + struct uh_connection_internal *conni = (struct uh_connection_internal *)conn; + struct http_parser_url *u = &conni->url_parser; + struct uh_request *req = &conni->req; struct uh_str path; - path.p = O2D(conn, u->field_data[UF_PATH].off) + req->url.offset; + path.p = O2D(conni, u->field_data[UF_PATH].off) + req->url.offset; path.len = u->field_data[UF_PATH].len; return path; @@ -222,14 +240,15 @@ static struct uh_str conn_get_path(struct uh_connection *conn) static struct uh_str conn_get_query(struct uh_connection *conn) { - struct http_parser_url *u = &conn->url_parser; - struct uh_request *req = &conn->req; + struct uh_connection_internal *conni = (struct uh_connection_internal *)conn; + struct http_parser_url *u = &conni->url_parser; + struct uh_request *req = &conni->req; struct uh_str query = {}; if (!(u->field_set & (1 << UF_QUERY))) return query; - query.p = O2D(conn, u->field_data[UF_QUERY].off) + req->url.offset; + query.p = O2D(conni, u->field_data[UF_QUERY].off) + req->url.offset; query.len = u->field_data[UF_QUERY].len; return query; @@ -237,7 +256,8 @@ static struct uh_str conn_get_query(struct uh_connection *conn) static struct uh_str conn_get_header(struct uh_connection *conn, const char *name) { - struct uh_request *req = &conn->req; + struct uh_connection_internal *conni = (struct uh_connection_internal *)conn; + struct uh_request *req = &conni->req; int name_len = strlen(name); struct uh_str value = {}; int i; @@ -249,8 +269,8 @@ static struct uh_str conn_get_header(struct uh_connection *conn, const char *nam if (req->headers[i].field.length != name_len) continue; - if (!strncasecmp(O2D(conn, req->headers[i].field.offset), name, name_len)) { - value.p = O2D(conn, req->headers[i].value.offset); + if (!strncasecmp(O2D(conni, req->headers[i].field.offset), name, name_len)) { + value.p = O2D(conni, req->headers[i].value.offset); value.len = req->headers[i].value.length; } } @@ -260,10 +280,11 @@ static struct uh_str conn_get_header(struct uh_connection *conn, const char *nam static struct uh_str conn_get_body(struct uh_connection *conn) { - struct uh_request *req = &conn->req; + struct uh_connection_internal *conni = (struct uh_connection_internal *)conn; + struct uh_request *req = &conni->req; struct uh_str body; - body.p = O2D(conn, req->body.offset); + body.p = O2D(conni, req->body.offset); body.len = req->body.length; return body; @@ -271,16 +292,17 @@ static struct uh_str conn_get_body(struct uh_connection *conn) static struct uh_str conn_extract_body(struct uh_connection *conn) { + struct uh_connection_internal *conni = (struct uh_connection_internal *)conn; struct uh_str body = conn_get_body(conn); - conn->req.body.consumed = true; + conni->req.body.consumed = true; return body; } static int on_message_begin_cb(struct http_parser *parser) { - struct uh_connection *conn = (struct uh_connection *)parser->data; + struct uh_connection_internal *conn = (struct uh_connection_internal *)parser->data; struct uh_request *req = &conn->req; memset(req, 0, sizeof(struct uh_request)); @@ -296,7 +318,7 @@ static int on_message_begin_cb(struct http_parser *parser) static int on_url_cb(struct http_parser *parser, const char *at, size_t length) { - struct uh_connection *conn = (struct uh_connection *)parser->data; + struct uh_connection_internal *conn = (struct uh_connection_internal *)parser->data; struct uh_request *req = &conn->req; if (req->url.offset == 0) @@ -308,7 +330,7 @@ static int on_url_cb(struct http_parser *parser, const char *at, size_t length) static int on_header_field_cb(struct http_parser *parser, const char *at, size_t length) { - struct uh_connection *conn = (struct uh_connection *)parser->data; + struct uh_connection_internal *conn = (struct uh_connection_internal *)parser->data; struct uh_request *req = &conn->req; if (req->last_was_header_value) { @@ -330,7 +352,7 @@ static int on_header_field_cb(struct http_parser *parser, const char *at, size_t static int on_header_value_cb(struct http_parser *parser, const char *at, size_t length) { - struct uh_connection *conn = (struct uh_connection *)parser->data; + struct uh_connection_internal *conn = (struct uh_connection_internal *)parser->data; struct uh_request *req = &conn->req; if (!req->last_was_header_value) { @@ -345,8 +367,8 @@ static int on_header_value_cb(struct http_parser *parser, const char *at, size_t static int on_headers_complete(struct http_parser *parser) { - struct uh_connection *conn = (struct uh_connection *)parser->data; - struct uh_server *srv = conn->srv; + struct uh_connection_internal *conn = (struct uh_connection_internal *)parser->data; + struct uh_server_internal *srv = conn->srv; struct uh_request *req = &conn->req; struct uh_path_handler *h = srv->handlers; struct uh_plugin *p = srv->plugins; @@ -354,7 +376,7 @@ static int on_headers_complete(struct http_parser *parser) http_parser_parse_url(O2D(conn, req->url.offset), req->url.length, false, &conn->url_parser); - path = conn->get_path(conn); + path = conn->com.get_path(&conn->com); while (h) { if (strlen(h->path) == path.len && !strncmp(path.p, h->path, path.len)) { @@ -377,11 +399,11 @@ done: conn->handler = srv->default_handler; if (!conn->handler) { - conn_error(conn, HTTP_STATUS_NOT_FOUND, NULL); + conn_error(&conn->com, HTTP_STATUS_NOT_FOUND, NULL); return -1; } - conn->handler(conn, UH_EV_HEAD_COMPLETE); + conn->handler(&conn->com, UH_EV_HEAD_COMPLETE); if (conn->flags & CONN_F_SEND_AND_CLOSE) return -1; @@ -391,14 +413,14 @@ done: static int on_body_cb(struct http_parser *parser, const char *at, size_t length) { - struct uh_connection *conn = (struct uh_connection *)parser->data; + struct uh_connection_internal *conn = (struct uh_connection_internal *)parser->data; struct uh_request *req = &conn->req; if (req->body.offset == 0) req->body.offset = ROF(conn, at); req->body.length += length; - conn->handler(conn, UH_EV_BODY); + conn->handler(&conn->com, UH_EV_BODY); if (conn->flags & CONN_F_SEND_AND_CLOSE) return -1; @@ -415,12 +437,12 @@ static int on_body_cb(struct http_parser *parser, const char *at, size_t length) static int on_message_complete_cb(struct http_parser *parser) { - struct uh_connection *conn = (struct uh_connection *)parser->data; - struct uh_server *srv = conn->srv; + struct uh_connection_internal *conn = (struct uh_connection_internal *)parser->data; + struct uh_server_internal *srv = conn->srv; ev_timer_stop(srv->loop, &conn->timer); - conn->handler(conn, UH_EV_COMPLETE); + conn->handler(&conn->com, UH_EV_COMPLETE); http_parser_pause(parser, true); @@ -437,7 +459,7 @@ static struct http_parser_settings settings = { .on_message_complete = on_message_complete_cb }; -void conn_free(struct uh_connection *conn) +void conn_free(struct uh_connection_internal *conn) { struct ev_loop *loop = conn->srv->loop; char addr_str[INET6_ADDRSTRLEN]; @@ -476,7 +498,7 @@ void conn_free(struct uh_connection *conn) free(conn); } -static void conn_http_parse(struct uh_connection *conn) +static void conn_http_parse(struct uh_connection_internal *conn) { struct http_parser *parser = &conn->parser; struct uh_request *req = &conn->req; @@ -494,7 +516,7 @@ static void conn_http_parse(struct uh_connection *conn) case HPE_PAUSED: case HPE_OK: if (parser->upgrade) { - conn_error(conn, HTTP_STATUS_NOT_IMPLEMENTED, NULL); + conn_error(&conn->com, HTTP_STATUS_NOT_IMPLEMENTED, NULL); return; } @@ -508,7 +530,7 @@ static void conn_http_parse(struct uh_connection *conn) return; default: - conn_error(conn, HTTP_STATUS_BAD_REQUEST, http_errno_description(parser->http_errno)); + conn_error(&conn->com, HTTP_STATUS_BAD_REQUEST, http_errno_description(parser->http_errno)); return; } } @@ -529,7 +551,7 @@ static int conn_ssl_write(int fd, void *buf, size_t count, void *ssl) static void conn_write_cb(struct ev_loop *loop, struct ev_io *w, int revents) { - struct uh_connection *conn = container_of(w, struct uh_connection, iow); + struct uh_connection_internal *conn = container_of(w, struct uh_connection_internal, iow); int ret; #if UHTTPD_SSL_SUPPORT @@ -593,7 +615,7 @@ static int conn_ssl_read(int fd, void *buf, size_t count, void *ssl) static void conn_read_cb(struct ev_loop *loop, struct ev_io *w, int revents) { - struct uh_connection *conn = container_of(w, struct uh_connection, ior); + struct uh_connection_internal *conn = container_of(w, struct uh_connection_internal, ior); struct buffer *rb = &conn->rb; bool eof; int ret; @@ -643,7 +665,7 @@ done: static void keepalive_cb(struct ev_loop *loop, struct ev_timer *w, int revents) { - struct uh_connection *conn = container_of(w, struct uh_connection, timer); + struct uh_connection_internal *conn = container_of(w, struct uh_connection_internal, timer); ev_tstamp after = conn->activity + UHTTPD_CONNECTION_TIMEOUT - ev_now(loop); if (conn->flags & CONN_F_SEND_AND_CLOSE) { @@ -657,14 +679,42 @@ static void keepalive_cb(struct ev_loop *loop, struct ev_timer *w, int revents) return; } - conn_error(conn, HTTP_STATUS_REQUEST_TIMEOUT, NULL); + conn_error(&conn->com, HTTP_STATUS_REQUEST_TIMEOUT, NULL); } -struct uh_connection *uh_new_connection(struct uh_server *srv, int sock, struct sockaddr *addr) +static void conn_init_cb(struct uh_connection *conn) { - struct uh_connection *conn; + conn->done = conn_done; + conn->send = conn_send; + conn->send_file = conn_send_file; + conn->printf = conn_printf; + conn->vprintf = conn_vprintf; + conn->send_status_line = conn_send_status_line; + conn->send_head = conn_send_head; + conn->error = conn_error; + conn->redirect = conn_redirect; + conn->serve_file = serve_file; - conn = calloc(1, sizeof(struct uh_connection)); + conn->chunk_send = conn_chunk_send; + conn->chunk_printf = conn_chunk_printf; + conn->chunk_vprintf = conn_chunk_vprintf; + conn->chunk_end = conn_chunk_end; + + conn->get_addr = conn_get_addr; + conn->get_method = conn_get_method; + conn->get_method_str = conn_get_method_str; + conn->get_path = conn_get_path; + conn->get_query = conn_get_query; + conn->get_header = conn_get_header; + conn->get_body = conn_get_body; + conn->extract_body = conn_extract_body; +} + +struct uh_connection_internal *uh_new_connection(struct uh_server_internal *srv, int sock, struct sockaddr *addr) +{ + struct uh_connection_internal *conn; + + conn = calloc(1, sizeof(struct uh_connection_internal)); if (!conn) { uh_log_err("malloc: %s\n", strerror(errno)); return NULL; @@ -696,30 +746,7 @@ struct uh_connection *uh_new_connection(struct uh_server *srv, int sock, struct conn->parser.data = conn; - conn->done = conn_done; - conn->send = conn_send; - conn->send_file = conn_send_file; - conn->printf = conn_printf; - conn->vprintf = conn_vprintf; - conn->send_status_line = conn_send_status_line; - conn->send_head = conn_send_head; - conn->error = conn_error; - conn->redirect = conn_redirect; - conn->serve_file = serve_file; - - conn->chunk_send = conn_chunk_send; - conn->chunk_printf = conn_chunk_printf; - conn->chunk_vprintf = conn_chunk_vprintf; - conn->chunk_end = conn_chunk_end; - - conn->get_addr = conn_get_addr; - conn->get_method = conn_get_method; - conn->get_method_str = conn_get_method_str; - conn->get_path = conn_get_path; - conn->get_query = conn_get_query; - conn->get_header = conn_get_header; - conn->get_body = conn_get_body; - conn->extract_body = conn_extract_body; + conn_init_cb(&conn->com); return conn; } diff --git a/src/connection.h b/src/connection.h index 9f376c6..a596616 100644 --- a/src/connection.h +++ b/src/connection.h @@ -25,13 +25,10 @@ #ifndef LIBUHTTPD_CONNECTION_H #define LIBUHTTPD_CONNECTION_H -#include -#include #include -#include "http_parser.h" #include "buffer.h" -#include "config.h" +#include "uhttpd.h" #define UHTTPD_CONNECTION_TIMEOUT 30.0 #define UHTTPD_MAX_HEADER_NUM 50 @@ -39,12 +36,7 @@ #define CONN_F_SEND_AND_CLOSE (1 << 0) /* Push remaining data and close */ #define CONN_F_SSL_HANDSHAKE_DONE (1 << 1) /* SSL hanshake has completed */ -struct uh_server; - -struct uh_str { - const char *p; - size_t len; -}; +struct uh_server_internal; struct uh_request { size_t length; /* The total length of the request which still remain in buffer */ @@ -73,7 +65,8 @@ struct uh_request { } body; }; -struct uh_connection { +struct uh_connection_internal { + struct uh_connection com; int sock; #if UHTTPD_SSL_SUPPORT void *ssl; @@ -90,7 +83,7 @@ struct uh_connection { ev_tstamp activity; struct ev_timer timer; struct uh_request req; - struct uh_server *srv; + struct uh_server_internal *srv; union { struct sockaddr sa; struct sockaddr_in sin; @@ -98,38 +91,13 @@ struct uh_connection { } addr; /* peer address */ struct http_parser parser; struct http_parser_url url_parser; - struct uh_connection *prev; - struct uh_connection *next; + struct uh_connection_internal *prev; + struct uh_connection_internal *next; void (*handler)(struct uh_connection *conn, int event); - /* - ** Indicates the end of request processing - ** Must be called at last, if not call 'error', 'redirect' and 'serve_file' - */ - void (*done)(struct uh_connection *conn); - void (*send)(struct uh_connection *conn, const void *data, ssize_t len); - void (*send_file)(struct uh_connection *conn, const char *path); - void (*printf)(struct uh_connection *conn, const char *format, ...); - void (*vprintf)(struct uh_connection *conn, const char *format, va_list arg); - void (*send_status_line)(struct uh_connection *conn, int code, const char *extra_headers); - void (*send_head)(struct uh_connection *conn, int code, int content_length, const char *extra_headers); - void (*error)(struct uh_connection *conn, int code, const char *reason); - void (*redirect)(struct uh_connection *conn, int code, const char *location, ...); - void (*serve_file)(struct uh_connection *conn); - void (*chunk_send)(struct uh_connection *conn, const void *data, ssize_t len); - void (*chunk_printf)(struct uh_connection *conn, const char *format, ...); - void (*chunk_vprintf)(struct uh_connection *conn, const char *format, va_list arg); - void (*chunk_end)(struct uh_connection *conn); - const struct sockaddr *(*get_addr)(struct uh_connection *conn); /* peer address */ - enum http_method (*get_method)(struct uh_connection *conn); - const char *(*get_method_str)(struct uh_connection *conn); - struct uh_str (*get_path)(struct uh_connection *conn); - struct uh_str (*get_query)(struct uh_connection *conn); - struct uh_str (*get_header)(struct uh_connection *conn, const char *name); - struct uh_str (*get_body)(struct uh_connection *conn); - /* The remain body data will be discurd after this function called */ - struct uh_str (*extract_body)(struct uh_connection *conn); }; -struct uh_connection *uh_new_connection(struct uh_server *srv, int sock, struct sockaddr *addr); +struct uh_connection_internal *uh_new_connection(struct uh_server_internal *srv, int sock, struct sockaddr *addr); + +void conn_free(struct uh_connection_internal *conn); #endif diff --git a/src/file.c b/src/file.c index 9562745..ccbcc51 100644 --- a/src/file.c +++ b/src/file.c @@ -35,9 +35,9 @@ #include #include +#include "uhttpd_internal.h" #include "mimetypes.h" -#include "uhttpd.h" -#include "log.h" +#include "file.h" static const char *file_mktag(struct stat *s, char *buf, int len) { @@ -154,8 +154,9 @@ static void file_if_gzip(struct uh_connection *conn, const char *path, const cha void serve_file(struct uh_connection *conn) { + struct uh_connection_internal *conni = (struct uh_connection_internal *)conn; const struct uh_str path = conn->get_path(conn); - struct uh_server *srv = conn->srv; + struct uh_server_internal *srv = conni->srv; const char *docroot = srv->docroot; const char *index_page = srv->index_page; static char fullpath[512]; diff --git a/src/uhttpd.c b/src/uhttpd.c index 32a2c47..70358db 100644 --- a/src/uhttpd.c +++ b/src/uhttpd.c @@ -33,34 +33,33 @@ #include #endif -#include "uhttpd.h" +#include "uhttpd_internal.h" +#include "connection.h" #include "utils.h" #include "ssl.h" -#include "log.h" - -void conn_free(struct uh_connection *conn); static void uh_server_free(struct uh_server *srv) { - struct uh_connection *conn = srv->conns; - struct uh_path_handler *h = srv->handlers; + struct uh_server_internal *srvi = (struct uh_server_internal *)srv; + struct uh_connection_internal *conn = srvi->conns; + struct uh_path_handler *h = srvi->handlers; #ifdef HAVE_DLOPEN - struct uh_plugin *p = srv->plugins; + struct uh_plugin *p = srvi->plugins; #endif - ev_io_stop(srv->loop, &srv->ior); + ev_io_stop(srvi->loop, &srvi->ior); - if (srv->sock > 0) - close(srv->sock); + if (srvi->sock > 0) + close(srvi->sock); - if (srv->docroot) - free(srv->docroot); + if (srvi->docroot) + free(srvi->docroot); - if (srv->index_page) - free(srv->index_page); + if (srvi->index_page) + free(srvi->index_page); while (conn) { - struct uh_connection *next = conn->next; + struct uh_connection_internal *next = conn->next; conn_free(conn); conn = next; } @@ -81,14 +80,14 @@ static void uh_server_free(struct uh_server *srv) #endif #if UHTTPD_SSL_SUPPORT - uh_ssl_ctx_free(srv->ssl_ctx); + uh_ssl_ctx_free(srvi->ssl_ctx); #endif } static void uh_accept_cb(struct ev_loop *loop, struct ev_io *w, int revents) { - struct uh_server *srv = container_of(w, struct uh_server, ior); - struct uh_connection *conn; + struct uh_server_internal *srv = container_of(w, struct uh_server_internal, ior); + struct uh_connection_internal *conn; union { struct sockaddr sa; struct sockaddr_in sin; @@ -128,7 +127,7 @@ struct uh_server *uh_server_new(struct ev_loop *loop, const char *host, int port { struct uh_server *srv; - srv = malloc(sizeof(struct uh_server)); + srv = malloc(sizeof(struct uh_server_internal)); if (!srv) { uh_log_err("malloc: %s\n", strerror(errno)); return NULL; @@ -145,13 +144,15 @@ struct uh_server *uh_server_new(struct ev_loop *loop, const char *host, int port #if UHTTPD_SSL_SUPPORT static int uh_server_ssl_init(struct uh_server *srv, const char *cert, const char *key) { - srv->ssl_ctx = uh_ssl_ctx_init(cert, key); - return srv->ssl_ctx ? 0 : -1; + struct uh_server_internal *srvi = (struct uh_server_internal *)srv; + srvi->ssl_ctx = uh_ssl_ctx_init(cert, key); + return srvi->ssl_ctx ? 0 : -1; } #endif static int uh_load_plugin(struct uh_server *srv, const char *path) { + struct uh_server_internal *srvi = (struct uh_server_internal *)srv; #ifdef HAVE_DLOPEN struct uh_plugin_handler *h; struct uh_plugin *p; @@ -185,13 +186,13 @@ static int uh_load_plugin(struct uh_server *srv, const char *path) p->h = h; p->dlh = dlh; - if (!srv->plugins) { - srv->plugins = p; + if (!srvi->plugins) { + srvi->plugins = p; return 0; } - p->next = srv->plugins; - srv->plugins = p; + p->next = srvi->plugins; + srvi->plugins = p; return 0; #else @@ -202,6 +203,7 @@ static int uh_load_plugin(struct uh_server *srv, const char *path) static int uh_add_path_handler(struct uh_server *srv, const char *path, uh_path_handler_prototype handler) { + struct uh_server_internal *srvi = (struct uh_server_internal *)srv; struct uh_path_handler *h; h = calloc(1, sizeof(struct uh_path_handler) + strlen(path) + 1); @@ -213,24 +215,33 @@ static int uh_add_path_handler(struct uh_server *srv, const char *path, uh_path_ h->handler = handler; strcpy(h->path, path); - if (!srv->handlers) { - srv->handlers = h; + if (!srvi->handlers) { + srvi->handlers = h; return 0; } - h->next = srv->handlers; - srv->handlers = h; + h->next = srvi->handlers; + srvi->handlers = h; return 0; } +static void uh_set_default_handler(struct uh_server *srv, uh_path_handler_prototype handler) +{ + struct uh_server_internal *srvi = (struct uh_server_internal *)srv; + + srvi->default_handler = handler; +} + static int uh_set_docroot(struct uh_server *srv, const char *path) { - if (srv->docroot) - free(srv->docroot); + struct uh_server_internal *srvi = (struct uh_server_internal *)srv; - srv->docroot = strdup(path); - if (!srv->docroot) { + if (srvi->docroot) + free(srvi->docroot); + + srvi->docroot = strdup(path); + if (!srvi->docroot) { uh_log_err("strdup: %s\n", strerror(errno)); return -1; } @@ -240,11 +251,13 @@ static int uh_set_docroot(struct uh_server *srv, const char *path) static int uh_set_index_page(struct uh_server *srv, const char *name) { - if (srv->index_page) - free(srv->index_page); + struct uh_server_internal *srvi = (struct uh_server_internal *)srv; - srv->index_page = strdup(name); - if (!srv->index_page) { + if (srvi->index_page) + free(srvi->index_page); + + srvi->index_page = strdup(name); + if (!srvi->index_page) { uh_log_err("strdup: %s\n", strerror(errno)); return -1; } @@ -254,6 +267,7 @@ static int uh_set_index_page(struct uh_server *srv, const char *name) int uh_server_init(struct uh_server *srv, struct ev_loop *loop, const char *host, int port) { + struct uh_server_internal *srvi = (struct uh_server_internal *)srv; union { struct sockaddr sa; struct sockaddr_in sin; @@ -326,10 +340,10 @@ int uh_server_init(struct uh_server *srv, struct ev_loop *loop, const char *host uh_log_debug("Listen on: %s %d\n", addr_str, port); } - memset(srv, 0, sizeof(struct uh_server)); + memset(srvi, 0, sizeof(struct uh_server_internal)); - srv->loop = loop ? loop : EV_DEFAULT; - srv->sock = sock; + srvi->loop = loop ? loop : EV_DEFAULT; + srvi->sock = sock; srv->free = uh_server_free; #if UHTTPD_SSL_SUPPORT @@ -338,13 +352,14 @@ int uh_server_init(struct uh_server *srv, struct ev_loop *loop, const char *host srv->load_plugin = uh_load_plugin; + srv->set_default_handler = uh_set_default_handler; srv->add_path_handler = uh_add_path_handler; srv->set_docroot = uh_set_docroot; srv->set_index_page = uh_set_index_page; - ev_io_init(&srv->ior, uh_accept_cb, sock, EV_READ); - ev_io_start(srv->loop, &srv->ior); + ev_io_init(&srvi->ior, uh_accept_cb, sock, EV_READ); + ev_io_start(srvi->loop, &srvi->ior); return 0; diff --git a/src/uhttpd.h b/src/uhttpd.h index 5e2442d..b07e41e 100644 --- a/src/uhttpd.h +++ b/src/uhttpd.h @@ -25,14 +25,70 @@ #ifndef LIBUHTTPD_UHTTPD_H #define LIBUHTTPD_UHTTPD_H +#include +#include +#include #include -#include "connection.h" +#include "http_parser.h" #include "config.h" #include "log.h" +struct uh_str { + const char *p; + size_t len; +}; + +enum { + UH_EV_HEAD_COMPLETE, + UH_EV_BODY, + UH_EV_COMPLETE +}; + +struct uh_connection { + /* + ** Indicates the end of request processing + ** Must be called at last, if not call 'error', 'redirect' and 'serve_file' + */ + void (*done)(struct uh_connection *conn); + void (*send)(struct uh_connection *conn, const void *data, ssize_t len); + void (*send_file)(struct uh_connection *conn, const char *path); + void (*printf)(struct uh_connection *conn, const char *format, ...); + void (*vprintf)(struct uh_connection *conn, const char *format, va_list arg); + void (*send_status_line)(struct uh_connection *conn, int code, const char *extra_headers); + void (*send_head)(struct uh_connection *conn, int code, int content_length, const char *extra_headers); + void (*error)(struct uh_connection *conn, int code, const char *reason); + void (*redirect)(struct uh_connection *conn, int code, const char *location, ...); + void (*serve_file)(struct uh_connection *conn); + void (*chunk_send)(struct uh_connection *conn, const void *data, ssize_t len); + void (*chunk_printf)(struct uh_connection *conn, const char *format, ...); + void (*chunk_vprintf)(struct uh_connection *conn, const char *format, va_list arg); + void (*chunk_end)(struct uh_connection *conn); + const struct sockaddr *(*get_addr)(struct uh_connection *conn); /* peer address */ + enum http_method (*get_method)(struct uh_connection *conn); + const char *(*get_method_str)(struct uh_connection *conn); + struct uh_str (*get_path)(struct uh_connection *conn); + struct uh_str (*get_query)(struct uh_connection *conn); + struct uh_str (*get_header)(struct uh_connection *conn, const char *name); + struct uh_str (*get_body)(struct uh_connection *conn); + /* The remain body data will be discurd after this function called */ + struct uh_str (*extract_body)(struct uh_connection *conn); +}; + typedef void (*uh_path_handler_prototype)(struct uh_connection *conn, int event); +struct uh_server { + void (*free)(struct uh_server *srv); +#if UHTTPD_SSL_SUPPORT + int (*ssl_init)(struct uh_server *srv, const char *cert, const char *key); +#endif + int (*load_plugin)(struct uh_server *srv, const char *path); + void (*set_default_handler)(struct uh_server *srv, uh_path_handler_prototype handler); + int (*add_path_handler)(struct uh_server *srv, const char *path, uh_path_handler_prototype handler); + int (*set_docroot)(struct uh_server *srv, const char *path); + int (*set_index_page)(struct uh_server *srv, const char *name); +}; + struct uh_plugin_handler { const char *path; uh_path_handler_prototype handler; @@ -44,38 +100,12 @@ struct uh_plugin { struct uh_plugin *next; }; -enum { - UH_EV_HEAD_COMPLETE, - UH_EV_BODY, - UH_EV_COMPLETE -}; - struct uh_path_handler { uh_path_handler_prototype handler; struct uh_path_handler *next; char path[0]; }; -struct uh_server { - int sock; - char *docroot; - char *index_page; - struct ev_loop *loop; - struct ev_io ior; - struct uh_connection *conns; - void (*free)(struct uh_server *srv); - void (*default_handler)(struct uh_connection *conn, int event); -#if UHTTPD_SSL_SUPPORT - void *ssl_ctx; - int (*ssl_init)(struct uh_server *srv, const char *cert, const char *key); -#endif - struct uh_plugin *plugins; - int (*load_plugin)(struct uh_server *srv, const char *path); - struct uh_path_handler *handlers; - int (*add_path_handler)(struct uh_server *srv, const char *path, uh_path_handler_prototype handler); - int (*set_docroot)(struct uh_server *srv, const char *path); - int (*set_index_page)(struct uh_server *srv, const char *name); -}; /* * uh_server_new - creat an uh_server struct and init it diff --git a/src/uhttpd_internal.h b/src/uhttpd_internal.h new file mode 100644 index 0000000..818a7a8 --- /dev/null +++ b/src/uhttpd_internal.h @@ -0,0 +1,48 @@ +/* + * MIT License + * + * Copyright (c) 2019 Jianhui Zhao + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef LIBUHTTPD_UHTTPD_INTERNAL_H +#define LIBUHTTPD_UHTTPD_INTERNAL_H + +#include "uhttpd.h" + +struct uh_connection_internal; + +struct uh_server_internal { + struct uh_server com; + int sock; + char *docroot; + char *index_page; + struct ev_loop *loop; + struct ev_io ior; + struct uh_connection_internal *conns; + void (*default_handler)(struct uh_connection *conn, int event); +#if UHTTPD_SSL_SUPPORT + void *ssl_ctx; +#endif + struct uh_plugin *plugins; + struct uh_path_handler *handlers; +}; + +#endif \ No newline at end of file