OOP: Only expose APIs
Hide the implementation details of the structure Signed-off-by: Jianhui Zhao <zhaojh329@gmail.com>main^2
parent
2fd658c347
commit
01bfeb620b
|
@ -199,7 +199,7 @@ int main(int argc, char **argv)
|
||||||
srv->set_docroot(srv, docroot);
|
srv->set_docroot(srv, docroot);
|
||||||
srv->set_index_page(srv, index_page);
|
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);
|
srv->add_path_handler(srv, "/upload", upload_handler);
|
||||||
|
|
||||||
|
|
|
@ -141,7 +141,6 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in ${CMAKE_CURRENT_BINARY_DI
|
||||||
install(
|
install(
|
||||||
FILES
|
FILES
|
||||||
uhttpd.h
|
uhttpd.h
|
||||||
connection.h
|
|
||||||
log.h
|
log.h
|
||||||
buffer/buffer.h
|
buffer/buffer.h
|
||||||
http-parser/http_parser.h
|
http-parser/http_parser.h
|
||||||
|
|
203
src/connection.c
203
src/connection.c
|
@ -30,65 +30,71 @@
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <sys/sendfile.h>
|
#include <sys/sendfile.h>
|
||||||
|
|
||||||
#include "connection.h"
|
#include "uhttpd_internal.h"
|
||||||
#include "uhttpd.h"
|
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "file.h"
|
#include "file.h"
|
||||||
#include "ssl.h"
|
#include "ssl.h"
|
||||||
|
|
||||||
static void conn_done(struct uh_connection *conn)
|
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))
|
if (!http_should_keep_alive(&conni->parser))
|
||||||
conn->flags |= CONN_F_SEND_AND_CLOSE;
|
conni->flags |= CONN_F_SEND_AND_CLOSE;
|
||||||
|
|
||||||
if (conn->flags & CONN_F_SEND_AND_CLOSE)
|
if (conni->flags & CONN_F_SEND_AND_CLOSE)
|
||||||
ev_io_stop(loop, &conn->ior);
|
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 */
|
/* 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)
|
static void conn_send(struct uh_connection *conn, const void *data, ssize_t len)
|
||||||
{
|
{
|
||||||
buffer_put_data(&conn->wb, data, len);
|
struct uh_connection_internal *conni = (struct uh_connection_internal *)conn;
|
||||||
ev_io_start(conn->srv->loop, &conn->iow);
|
|
||||||
|
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)
|
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;
|
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, ...)
|
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_list arg;
|
||||||
|
|
||||||
va_start(arg, format);
|
va_start(arg, format);
|
||||||
buffer_put_vprintf(wb, format, arg);
|
buffer_put_vprintf(wb, format, arg);
|
||||||
va_end(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)
|
static void conn_vprintf(struct uh_connection *conn, const char *format, va_list arg)
|
||||||
{
|
{
|
||||||
buffer_put_vprintf(&conn->wb, format, arg);
|
struct uh_connection_internal *conni = (struct uh_connection_internal *)conn;
|
||||||
ev_io_start(conn->srv->loop, &conn->iow);
|
|
||||||
|
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)
|
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)
|
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);
|
conn_send_status_line(conn, code, extra_headers);
|
||||||
if (content_length < 0)
|
if (content_length < 0)
|
||||||
conn_printf(conn, "%s", "Transfer-Encoding: chunked\r\n");
|
conn_printf(conn, "%s", "Transfer-Encoding: chunked\r\n");
|
||||||
else
|
else
|
||||||
conn_printf(conn, "Content-Length: %d\r\n", content_length);
|
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_printf(conn, "%s", "Connection: close\r\n");
|
||||||
|
|
||||||
conn_send(conn, "\r\n", 2);
|
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)
|
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;
|
return;
|
||||||
|
|
||||||
if (!reason)
|
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_head(conn, code, strlen(reason), "Content-Type: text/plain\r\nConnection: close\r\n");
|
||||||
conn_send(conn, reason, strlen(reason));
|
conn_send(conn, reason, strlen(reason));
|
||||||
|
|
||||||
conn->flags |= CONN_F_SEND_AND_CLOSE;
|
conni->flags |= CONN_F_SEND_AND_CLOSE;
|
||||||
|
|
||||||
conn_done(conn);
|
conn_done(conn);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void conn_redirect(struct uh_connection *conn, int code, const char *location, ...)
|
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;
|
va_list arg;
|
||||||
|
|
||||||
assert((code == HTTP_STATUS_MOVED_PERMANENTLY || code == HTTP_STATUS_FOUND) && location);
|
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)
|
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)
|
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)
|
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 */
|
/* 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)
|
static struct uh_str conn_get_path(struct uh_connection *conn)
|
||||||
{
|
{
|
||||||
struct http_parser_url *u = &conn->url_parser;
|
struct uh_connection_internal *conni = (struct uh_connection_internal *)conn;
|
||||||
struct uh_request *req = &conn->req;
|
struct http_parser_url *u = &conni->url_parser;
|
||||||
|
struct uh_request *req = &conni->req;
|
||||||
struct uh_str path;
|
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;
|
path.len = u->field_data[UF_PATH].len;
|
||||||
|
|
||||||
return path;
|
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)
|
static struct uh_str conn_get_query(struct uh_connection *conn)
|
||||||
{
|
{
|
||||||
struct http_parser_url *u = &conn->url_parser;
|
struct uh_connection_internal *conni = (struct uh_connection_internal *)conn;
|
||||||
struct uh_request *req = &conn->req;
|
struct http_parser_url *u = &conni->url_parser;
|
||||||
|
struct uh_request *req = &conni->req;
|
||||||
struct uh_str query = {};
|
struct uh_str query = {};
|
||||||
|
|
||||||
if (!(u->field_set & (1 << UF_QUERY)))
|
if (!(u->field_set & (1 << UF_QUERY)))
|
||||||
return 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;
|
query.len = u->field_data[UF_QUERY].len;
|
||||||
|
|
||||||
return query;
|
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)
|
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);
|
int name_len = strlen(name);
|
||||||
struct uh_str value = {};
|
struct uh_str value = {};
|
||||||
int i;
|
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)
|
if (req->headers[i].field.length != name_len)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!strncasecmp(O2D(conn, req->headers[i].field.offset), name, name_len)) {
|
if (!strncasecmp(O2D(conni, req->headers[i].field.offset), name, name_len)) {
|
||||||
value.p = O2D(conn, req->headers[i].value.offset);
|
value.p = O2D(conni, req->headers[i].value.offset);
|
||||||
value.len = req->headers[i].value.length;
|
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)
|
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;
|
struct uh_str body;
|
||||||
|
|
||||||
body.p = O2D(conn, req->body.offset);
|
body.p = O2D(conni, req->body.offset);
|
||||||
body.len = req->body.length;
|
body.len = req->body.length;
|
||||||
|
|
||||||
return body;
|
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)
|
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);
|
struct uh_str body = conn_get_body(conn);
|
||||||
|
|
||||||
conn->req.body.consumed = true;
|
conni->req.body.consumed = true;
|
||||||
|
|
||||||
return body;
|
return body;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int on_message_begin_cb(struct http_parser *parser)
|
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;
|
struct uh_request *req = &conn->req;
|
||||||
|
|
||||||
memset(req, 0, sizeof(struct uh_request));
|
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)
|
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;
|
struct uh_request *req = &conn->req;
|
||||||
|
|
||||||
if (req->url.offset == 0)
|
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)
|
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;
|
struct uh_request *req = &conn->req;
|
||||||
|
|
||||||
if (req->last_was_header_value) {
|
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)
|
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;
|
struct uh_request *req = &conn->req;
|
||||||
|
|
||||||
if (!req->last_was_header_value) {
|
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)
|
static int on_headers_complete(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_server *srv = conn->srv;
|
struct uh_server_internal *srv = conn->srv;
|
||||||
struct uh_request *req = &conn->req;
|
struct uh_request *req = &conn->req;
|
||||||
struct uh_path_handler *h = srv->handlers;
|
struct uh_path_handler *h = srv->handlers;
|
||||||
struct uh_plugin *p = srv->plugins;
|
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);
|
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) {
|
while (h) {
|
||||||
if (strlen(h->path) == path.len && !strncmp(path.p, h->path, path.len)) {
|
if (strlen(h->path) == path.len && !strncmp(path.p, h->path, path.len)) {
|
||||||
|
@ -377,11 +399,11 @@ done:
|
||||||
conn->handler = srv->default_handler;
|
conn->handler = srv->default_handler;
|
||||||
|
|
||||||
if (!conn->handler) {
|
if (!conn->handler) {
|
||||||
conn_error(conn, HTTP_STATUS_NOT_FOUND, NULL);
|
conn_error(&conn->com, HTTP_STATUS_NOT_FOUND, NULL);
|
||||||
return -1;
|
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)
|
if (conn->flags & CONN_F_SEND_AND_CLOSE)
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -391,14 +413,14 @@ done:
|
||||||
|
|
||||||
static int on_body_cb(struct http_parser *parser, const char *at, size_t length)
|
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;
|
struct uh_request *req = &conn->req;
|
||||||
|
|
||||||
if (req->body.offset == 0)
|
if (req->body.offset == 0)
|
||||||
req->body.offset = ROF(conn, at);
|
req->body.offset = ROF(conn, at);
|
||||||
req->body.length += length;
|
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)
|
if (conn->flags & CONN_F_SEND_AND_CLOSE)
|
||||||
return -1;
|
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)
|
static int on_message_complete_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_server *srv = conn->srv;
|
struct uh_server_internal *srv = conn->srv;
|
||||||
|
|
||||||
ev_timer_stop(srv->loop, &conn->timer);
|
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);
|
http_parser_pause(parser, true);
|
||||||
|
|
||||||
|
@ -437,7 +459,7 @@ static struct http_parser_settings settings = {
|
||||||
.on_message_complete = on_message_complete_cb
|
.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;
|
struct ev_loop *loop = conn->srv->loop;
|
||||||
char addr_str[INET6_ADDRSTRLEN];
|
char addr_str[INET6_ADDRSTRLEN];
|
||||||
|
@ -476,7 +498,7 @@ void conn_free(struct uh_connection *conn)
|
||||||
free(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 http_parser *parser = &conn->parser;
|
||||||
struct uh_request *req = &conn->req;
|
struct uh_request *req = &conn->req;
|
||||||
|
@ -494,7 +516,7 @@ static void conn_http_parse(struct uh_connection *conn)
|
||||||
case HPE_PAUSED:
|
case HPE_PAUSED:
|
||||||
case HPE_OK:
|
case HPE_OK:
|
||||||
if (parser->upgrade) {
|
if (parser->upgrade) {
|
||||||
conn_error(conn, HTTP_STATUS_NOT_IMPLEMENTED, NULL);
|
conn_error(&conn->com, HTTP_STATUS_NOT_IMPLEMENTED, NULL);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -508,7 +530,7 @@ static void conn_http_parse(struct uh_connection *conn)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
default:
|
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;
|
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)
|
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;
|
int ret;
|
||||||
|
|
||||||
#if UHTTPD_SSL_SUPPORT
|
#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)
|
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;
|
struct buffer *rb = &conn->rb;
|
||||||
bool eof;
|
bool eof;
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -643,7 +665,7 @@ done:
|
||||||
|
|
||||||
static void keepalive_cb(struct ev_loop *loop, struct ev_timer *w, int revents)
|
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);
|
ev_tstamp after = conn->activity + UHTTPD_CONNECTION_TIMEOUT - ev_now(loop);
|
||||||
|
|
||||||
if (conn->flags & CONN_F_SEND_AND_CLOSE) {
|
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;
|
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) {
|
if (!conn) {
|
||||||
uh_log_err("malloc: %s\n", strerror(errno));
|
uh_log_err("malloc: %s\n", strerror(errno));
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -696,30 +746,7 @@ struct uh_connection *uh_new_connection(struct uh_server *srv, int sock, struct
|
||||||
|
|
||||||
conn->parser.data = conn;
|
conn->parser.data = conn;
|
||||||
|
|
||||||
conn->done = conn_done;
|
conn_init_cb(&conn->com);
|
||||||
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;
|
|
||||||
|
|
||||||
return conn;
|
return conn;
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,13 +25,10 @@
|
||||||
#ifndef LIBUHTTPD_CONNECTION_H
|
#ifndef LIBUHTTPD_CONNECTION_H
|
||||||
#define LIBUHTTPD_CONNECTION_H
|
#define LIBUHTTPD_CONNECTION_H
|
||||||
|
|
||||||
#include <ev.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
|
|
||||||
#include "http_parser.h"
|
|
||||||
#include "buffer.h"
|
#include "buffer.h"
|
||||||
#include "config.h"
|
#include "uhttpd.h"
|
||||||
|
|
||||||
#define UHTTPD_CONNECTION_TIMEOUT 30.0
|
#define UHTTPD_CONNECTION_TIMEOUT 30.0
|
||||||
#define UHTTPD_MAX_HEADER_NUM 50
|
#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_SEND_AND_CLOSE (1 << 0) /* Push remaining data and close */
|
||||||
#define CONN_F_SSL_HANDSHAKE_DONE (1 << 1) /* SSL hanshake has completed */
|
#define CONN_F_SSL_HANDSHAKE_DONE (1 << 1) /* SSL hanshake has completed */
|
||||||
|
|
||||||
struct uh_server;
|
struct uh_server_internal;
|
||||||
|
|
||||||
struct uh_str {
|
|
||||||
const char *p;
|
|
||||||
size_t len;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct uh_request {
|
struct uh_request {
|
||||||
size_t length; /* The total length of the request which still remain in buffer */
|
size_t length; /* The total length of the request which still remain in buffer */
|
||||||
|
@ -73,7 +65,8 @@ struct uh_request {
|
||||||
} body;
|
} body;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct uh_connection {
|
struct uh_connection_internal {
|
||||||
|
struct uh_connection com;
|
||||||
int sock;
|
int sock;
|
||||||
#if UHTTPD_SSL_SUPPORT
|
#if UHTTPD_SSL_SUPPORT
|
||||||
void *ssl;
|
void *ssl;
|
||||||
|
@ -90,7 +83,7 @@ struct uh_connection {
|
||||||
ev_tstamp activity;
|
ev_tstamp activity;
|
||||||
struct ev_timer timer;
|
struct ev_timer timer;
|
||||||
struct uh_request req;
|
struct uh_request req;
|
||||||
struct uh_server *srv;
|
struct uh_server_internal *srv;
|
||||||
union {
|
union {
|
||||||
struct sockaddr sa;
|
struct sockaddr sa;
|
||||||
struct sockaddr_in sin;
|
struct sockaddr_in sin;
|
||||||
|
@ -98,38 +91,13 @@ struct uh_connection {
|
||||||
} addr; /* peer address */
|
} addr; /* peer address */
|
||||||
struct http_parser parser;
|
struct http_parser parser;
|
||||||
struct http_parser_url url_parser;
|
struct http_parser_url url_parser;
|
||||||
struct uh_connection *prev;
|
struct uh_connection_internal *prev;
|
||||||
struct uh_connection *next;
|
struct uh_connection_internal *next;
|
||||||
void (*handler)(struct uh_connection *conn, int event);
|
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
|
#endif
|
||||||
|
|
|
@ -35,9 +35,9 @@
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
|
|
||||||
|
#include "uhttpd_internal.h"
|
||||||
#include "mimetypes.h"
|
#include "mimetypes.h"
|
||||||
#include "uhttpd.h"
|
#include "file.h"
|
||||||
#include "log.h"
|
|
||||||
|
|
||||||
static const char *file_mktag(struct stat *s, char *buf, int len)
|
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)
|
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);
|
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 *docroot = srv->docroot;
|
||||||
const char *index_page = srv->index_page;
|
const char *index_page = srv->index_page;
|
||||||
static char fullpath[512];
|
static char fullpath[512];
|
||||||
|
|
99
src/uhttpd.c
99
src/uhttpd.c
|
@ -33,34 +33,33 @@
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "uhttpd.h"
|
#include "uhttpd_internal.h"
|
||||||
|
#include "connection.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "ssl.h"
|
#include "ssl.h"
|
||||||
#include "log.h"
|
|
||||||
|
|
||||||
void conn_free(struct uh_connection *conn);
|
|
||||||
|
|
||||||
static void uh_server_free(struct uh_server *srv)
|
static void uh_server_free(struct uh_server *srv)
|
||||||
{
|
{
|
||||||
struct uh_connection *conn = srv->conns;
|
struct uh_server_internal *srvi = (struct uh_server_internal *)srv;
|
||||||
struct uh_path_handler *h = srv->handlers;
|
struct uh_connection_internal *conn = srvi->conns;
|
||||||
|
struct uh_path_handler *h = srvi->handlers;
|
||||||
#ifdef HAVE_DLOPEN
|
#ifdef HAVE_DLOPEN
|
||||||
struct uh_plugin *p = srv->plugins;
|
struct uh_plugin *p = srvi->plugins;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ev_io_stop(srv->loop, &srv->ior);
|
ev_io_stop(srvi->loop, &srvi->ior);
|
||||||
|
|
||||||
if (srv->sock > 0)
|
if (srvi->sock > 0)
|
||||||
close(srv->sock);
|
close(srvi->sock);
|
||||||
|
|
||||||
if (srv->docroot)
|
if (srvi->docroot)
|
||||||
free(srv->docroot);
|
free(srvi->docroot);
|
||||||
|
|
||||||
if (srv->index_page)
|
if (srvi->index_page)
|
||||||
free(srv->index_page);
|
free(srvi->index_page);
|
||||||
|
|
||||||
while (conn) {
|
while (conn) {
|
||||||
struct uh_connection *next = conn->next;
|
struct uh_connection_internal *next = conn->next;
|
||||||
conn_free(conn);
|
conn_free(conn);
|
||||||
conn = next;
|
conn = next;
|
||||||
}
|
}
|
||||||
|
@ -81,14 +80,14 @@ static void uh_server_free(struct uh_server *srv)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if UHTTPD_SSL_SUPPORT
|
#if UHTTPD_SSL_SUPPORT
|
||||||
uh_ssl_ctx_free(srv->ssl_ctx);
|
uh_ssl_ctx_free(srvi->ssl_ctx);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void uh_accept_cb(struct ev_loop *loop, struct ev_io *w, int revents)
|
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_server_internal *srv = container_of(w, struct uh_server_internal, ior);
|
||||||
struct uh_connection *conn;
|
struct uh_connection_internal *conn;
|
||||||
union {
|
union {
|
||||||
struct sockaddr sa;
|
struct sockaddr sa;
|
||||||
struct sockaddr_in sin;
|
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;
|
struct uh_server *srv;
|
||||||
|
|
||||||
srv = malloc(sizeof(struct uh_server));
|
srv = malloc(sizeof(struct uh_server_internal));
|
||||||
if (!srv) {
|
if (!srv) {
|
||||||
uh_log_err("malloc: %s\n", strerror(errno));
|
uh_log_err("malloc: %s\n", strerror(errno));
|
||||||
return NULL;
|
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
|
#if UHTTPD_SSL_SUPPORT
|
||||||
static int uh_server_ssl_init(struct uh_server *srv, const char *cert, const char *key)
|
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);
|
struct uh_server_internal *srvi = (struct uh_server_internal *)srv;
|
||||||
return srv->ssl_ctx ? 0 : -1;
|
srvi->ssl_ctx = uh_ssl_ctx_init(cert, key);
|
||||||
|
return srvi->ssl_ctx ? 0 : -1;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int uh_load_plugin(struct uh_server *srv, const char *path)
|
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
|
#ifdef HAVE_DLOPEN
|
||||||
struct uh_plugin_handler *h;
|
struct uh_plugin_handler *h;
|
||||||
struct uh_plugin *p;
|
struct uh_plugin *p;
|
||||||
|
@ -185,13 +186,13 @@ static int uh_load_plugin(struct uh_server *srv, const char *path)
|
||||||
p->h = h;
|
p->h = h;
|
||||||
p->dlh = dlh;
|
p->dlh = dlh;
|
||||||
|
|
||||||
if (!srv->plugins) {
|
if (!srvi->plugins) {
|
||||||
srv->plugins = p;
|
srvi->plugins = p;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
p->next = srv->plugins;
|
p->next = srvi->plugins;
|
||||||
srv->plugins = p;
|
srvi->plugins = p;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
#else
|
#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)
|
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;
|
struct uh_path_handler *h;
|
||||||
|
|
||||||
h = calloc(1, sizeof(struct uh_path_handler) + strlen(path) + 1);
|
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;
|
h->handler = handler;
|
||||||
strcpy(h->path, path);
|
strcpy(h->path, path);
|
||||||
|
|
||||||
if (!srv->handlers) {
|
if (!srvi->handlers) {
|
||||||
srv->handlers = h;
|
srvi->handlers = h;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
h->next = srv->handlers;
|
h->next = srvi->handlers;
|
||||||
srv->handlers = h;
|
srvi->handlers = h;
|
||||||
|
|
||||||
return 0;
|
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)
|
static int uh_set_docroot(struct uh_server *srv, const char *path)
|
||||||
{
|
{
|
||||||
if (srv->docroot)
|
struct uh_server_internal *srvi = (struct uh_server_internal *)srv;
|
||||||
free(srv->docroot);
|
|
||||||
|
|
||||||
srv->docroot = strdup(path);
|
if (srvi->docroot)
|
||||||
if (!srv->docroot) {
|
free(srvi->docroot);
|
||||||
|
|
||||||
|
srvi->docroot = strdup(path);
|
||||||
|
if (!srvi->docroot) {
|
||||||
uh_log_err("strdup: %s\n", strerror(errno));
|
uh_log_err("strdup: %s\n", strerror(errno));
|
||||||
return -1;
|
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)
|
static int uh_set_index_page(struct uh_server *srv, const char *name)
|
||||||
{
|
{
|
||||||
if (srv->index_page)
|
struct uh_server_internal *srvi = (struct uh_server_internal *)srv;
|
||||||
free(srv->index_page);
|
|
||||||
|
|
||||||
srv->index_page = strdup(name);
|
if (srvi->index_page)
|
||||||
if (!srv->index_page) {
|
free(srvi->index_page);
|
||||||
|
|
||||||
|
srvi->index_page = strdup(name);
|
||||||
|
if (!srvi->index_page) {
|
||||||
uh_log_err("strdup: %s\n", strerror(errno));
|
uh_log_err("strdup: %s\n", strerror(errno));
|
||||||
return -1;
|
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)
|
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 {
|
union {
|
||||||
struct sockaddr sa;
|
struct sockaddr sa;
|
||||||
struct sockaddr_in sin;
|
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);
|
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;
|
srvi->loop = loop ? loop : EV_DEFAULT;
|
||||||
srv->sock = sock;
|
srvi->sock = sock;
|
||||||
srv->free = uh_server_free;
|
srv->free = uh_server_free;
|
||||||
|
|
||||||
#if UHTTPD_SSL_SUPPORT
|
#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->load_plugin = uh_load_plugin;
|
||||||
|
|
||||||
|
srv->set_default_handler = uh_set_default_handler;
|
||||||
srv->add_path_handler = uh_add_path_handler;
|
srv->add_path_handler = uh_add_path_handler;
|
||||||
|
|
||||||
srv->set_docroot = uh_set_docroot;
|
srv->set_docroot = uh_set_docroot;
|
||||||
srv->set_index_page = uh_set_index_page;
|
srv->set_index_page = uh_set_index_page;
|
||||||
|
|
||||||
ev_io_init(&srv->ior, uh_accept_cb, sock, EV_READ);
|
ev_io_init(&srvi->ior, uh_accept_cb, sock, EV_READ);
|
||||||
ev_io_start(srv->loop, &srv->ior);
|
ev_io_start(srvi->loop, &srvi->ior);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
|
84
src/uhttpd.h
84
src/uhttpd.h
|
@ -25,14 +25,70 @@
|
||||||
#ifndef LIBUHTTPD_UHTTPD_H
|
#ifndef LIBUHTTPD_UHTTPD_H
|
||||||
#define LIBUHTTPD_UHTTPD_H
|
#define LIBUHTTPD_UHTTPD_H
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdarg.h>
|
||||||
#include <ev.h>
|
#include <ev.h>
|
||||||
|
|
||||||
#include "connection.h"
|
#include "http_parser.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "log.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);
|
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 {
|
struct uh_plugin_handler {
|
||||||
const char *path;
|
const char *path;
|
||||||
uh_path_handler_prototype handler;
|
uh_path_handler_prototype handler;
|
||||||
|
@ -44,38 +100,12 @@ struct uh_plugin {
|
||||||
struct uh_plugin *next;
|
struct uh_plugin *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
|
||||||
UH_EV_HEAD_COMPLETE,
|
|
||||||
UH_EV_BODY,
|
|
||||||
UH_EV_COMPLETE
|
|
||||||
};
|
|
||||||
|
|
||||||
struct uh_path_handler {
|
struct uh_path_handler {
|
||||||
uh_path_handler_prototype handler;
|
uh_path_handler_prototype handler;
|
||||||
struct uh_path_handler *next;
|
struct uh_path_handler *next;
|
||||||
char path[0];
|
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
|
* uh_server_new - creat an uh_server struct and init it
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
/*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2019 Jianhui Zhao <zhaojh329@gmail.com>
|
||||||
|
*
|
||||||
|
* 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
|
Loading…
Reference in New Issue