In order to be compatible with different editor, convert all Tab to spaces

Signed-off-by: Jianhui Zhao <jianhuizhao329@gmail.com>
main
Jianhui Zhao 2017-11-13 20:51:42 +08:00
parent 8eb57bef1e
commit ee31e3f1fa
11 changed files with 747 additions and 747 deletions

View File

@ -4,67 +4,67 @@
static void signal_cb(struct ev_loop *loop, ev_signal *w, int revents) static void signal_cb(struct ev_loop *loop, ev_signal *w, int revents)
{ {
printf("Got signal: %d\n", w->signum); printf("Got signal: %d\n", w->signum);
ev_break(loop, EVBREAK_ALL); ev_break(loop, EVBREAK_ALL);
} }
void route_test(struct uh_connection *con) void route_test(struct uh_connection *con)
{ {
struct uh_value *url = uh_get_url(con); struct uh_value *url = uh_get_url(con);
struct uh_value *header_host = uh_get_header(con, "Host"); struct uh_value *header_host = uh_get_header(con, "Host");
struct uh_value *header_ua = uh_get_header(con, "User-Agent"); struct uh_value *header_ua = uh_get_header(con, "User-Agent");
uh_send_head(con, UH_STATUS_OK, -1, NULL); uh_send_head(con, UH_STATUS_OK, -1, NULL);
uh_printf_chunk(con, "<h1>Hello World</h1>"); uh_printf_chunk(con, "<h1>Hello World</h1>");
uh_printf_chunk(con, "<h1>Libuhttp v%s</h1>", uh_version()); uh_printf_chunk(con, "<h1>Libuhttp v%s</h1>", uh_version());
uh_printf_chunk(con, "<h1>Url: %.*s</h1>", (int)url->len, url->at); uh_printf_chunk(con, "<h1>Url: %.*s</h1>", (int)url->len, url->at);
if (header_host) if (header_host)
uh_printf_chunk(con, "<h1>Host: %.*s</h1>", (int)header_host->len, header_host->at); uh_printf_chunk(con, "<h1>Host: %.*s</h1>", (int)header_host->len, header_host->at);
if (header_ua) if (header_ua)
uh_printf_chunk(con, "<h1>User-Agent: %.*s</h1>", (int)header_ua->len, header_ua->at); uh_printf_chunk(con, "<h1>User-Agent: %.*s</h1>", (int)header_ua->len, header_ua->at);
uh_send_chunk(con, NULL, 0); uh_send_chunk(con, NULL, 0);
} }
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
struct ev_loop *loop = EV_DEFAULT; struct ev_loop *loop = EV_DEFAULT;
ev_signal *sig_watcher = NULL; ev_signal *sig_watcher = NULL;
struct uh_server *srv = NULL; struct uh_server *srv = NULL;
uh_log_info("libuhttp version: %s\n", uh_version()); uh_log_info("libuhttp version: %s\n", uh_version());
sig_watcher = calloc(1, sizeof(ev_signal)); sig_watcher = calloc(1, sizeof(ev_signal));
if (!sig_watcher) if (!sig_watcher)
return -1; return -1;
ev_signal_init(sig_watcher, signal_cb, SIGINT); ev_signal_init(sig_watcher, signal_cb, SIGINT);
ev_signal_start(loop, sig_watcher); ev_signal_start(loop, sig_watcher);
srv = uh_server_new(loop, "0.0.0.0", 8000); srv = uh_server_new(loop, "0.0.0.0", 8000);
if (!srv) { if (!srv) {
uh_log_err("uh_server_new failed\n"); uh_log_err("uh_server_new failed\n");
goto err; goto err;
} }
#if (UHTTP_SSL_ENABLED) #if (UHTTP_SSL_ENABLED)
if (uh_ssl_init(srv, "server-cert.pem", "server-key.pem") < 0) if (uh_ssl_init(srv, "server-cert.pem", "server-key.pem") < 0)
goto err; goto err;
#endif #endif
uh_register_route(srv, "/test", route_test); uh_register_route(srv, "/test", route_test);
uh_log_info("Listen on 8000...\n"); uh_log_info("Listen on 8000...\n");
ev_run(loop, 0); ev_run(loop, 0);
err: err:
free(sig_watcher); free(sig_watcher);
uh_server_free(srv); uh_server_free(srv);
return 0; return 0;
} }

View File

@ -10,178 +10,178 @@
#include "uhttp_ssl.h" #include "uhttp_ssl.h"
static struct { static struct {
int code; int code;
const char *reason; const char *reason;
} http_status_message[] = { } http_status_message[] = {
{UH_STATUS_CONTINUE, "Continue"}, {UH_STATUS_CONTINUE, "Continue"},
{UH_STATUS_SWITCHING_PROTOCOLS, "Switching Protocols"}, {UH_STATUS_SWITCHING_PROTOCOLS, "Switching Protocols"},
{UH_STATUS_PROCESSING, "Processing"}, {UH_STATUS_PROCESSING, "Processing"},
{UH_STATUS_OK, "OK"}, {UH_STATUS_OK, "OK"},
{UH_STATUS_CREATED, "Created"}, {UH_STATUS_CREATED, "Created"},
{UH_STATUS_ACCEPTED, "Accepted"}, {UH_STATUS_ACCEPTED, "Accepted"},
{UH_STATUS_NON_AUTHORITATIVE_INFORMATION, "Non-Authoritative Information"}, {UH_STATUS_NON_AUTHORITATIVE_INFORMATION, "Non-Authoritative Information"},
{UH_STATUS_NO_CONTENT, "No Content"}, {UH_STATUS_NO_CONTENT, "No Content"},
{UH_STATUS_RESET_CONTENT, "Reset Content"}, {UH_STATUS_RESET_CONTENT, "Reset Content"},
{UH_STATUS_PARTIAL_CONTENT, "Partial Content"}, {UH_STATUS_PARTIAL_CONTENT, "Partial Content"},
{UH_STATUS_MULTI_STATUS, "Multi-Status"}, {UH_STATUS_MULTI_STATUS, "Multi-Status"},
{UH_STATUS_ALREADY_REPORTED, "Already Reported"}, {UH_STATUS_ALREADY_REPORTED, "Already Reported"},
{UH_STATUS_IM_USED, "IM Used"}, {UH_STATUS_IM_USED, "IM Used"},
{UH_STATUS_MULTIPLE_CHOICES, "Multiple Choices"}, {UH_STATUS_MULTIPLE_CHOICES, "Multiple Choices"},
{UH_STATUS_MOVED_PERMANENTLY, "Moved Permanently"}, {UH_STATUS_MOVED_PERMANENTLY, "Moved Permanently"},
{UH_STATUS_FOUND, "Found"}, {UH_STATUS_FOUND, "Found"},
{UH_STATUS_SEE_OTHER, "See Other"}, {UH_STATUS_SEE_OTHER, "See Other"},
{UH_STATUS_NOT_MODIFIED, "Not Modified"}, {UH_STATUS_NOT_MODIFIED, "Not Modified"},
{UH_STATUS_USE_PROXY, "Use Proxy"}, {UH_STATUS_USE_PROXY, "Use Proxy"},
{UH_STATUS_TEMPORARY_REDIRECT, "Temporary Redirect"}, {UH_STATUS_TEMPORARY_REDIRECT, "Temporary Redirect"},
{UH_STATUS_PERMANENT_REDIRECT, "Permanent Redirect"}, {UH_STATUS_PERMANENT_REDIRECT, "Permanent Redirect"},
{UH_STATUS_BAD_REQUEST, "Bad Request"}, {UH_STATUS_BAD_REQUEST, "Bad Request"},
{UH_STATUS_UNAUTHORIZED, "Unauthorized"}, {UH_STATUS_UNAUTHORIZED, "Unauthorized"},
{UH_STATUS_PAYMENT_REQUIRED, "Payment Required"}, {UH_STATUS_PAYMENT_REQUIRED, "Payment Required"},
{UH_STATUS_FORBIDDEN, "Forbidden"}, {UH_STATUS_FORBIDDEN, "Forbidden"},
{UH_STATUS_NOT_FOUND, "Not Found"}, {UH_STATUS_NOT_FOUND, "Not Found"},
{UH_STATUS_METHOD_NOT_ALLOWED, "Method Not Allowed"}, {UH_STATUS_METHOD_NOT_ALLOWED, "Method Not Allowed"},
{UH_STATUS_NOT_ACCEPTABLE, "Not Acceptable"}, {UH_STATUS_NOT_ACCEPTABLE, "Not Acceptable"},
{UH_STATUS_PROXY_AUTHENTICATION_REQUIRED, "Proxy Authentication Required"}, {UH_STATUS_PROXY_AUTHENTICATION_REQUIRED, "Proxy Authentication Required"},
{UH_STATUS_REQUEST_TIMEOUT, "Request Timeout"}, {UH_STATUS_REQUEST_TIMEOUT, "Request Timeout"},
{UH_STATUS_CONFLICT, "Conflict"}, {UH_STATUS_CONFLICT, "Conflict"},
{UH_STATUS_GONE, "Gone"}, {UH_STATUS_GONE, "Gone"},
{UH_STATUS_LENGTH_REQUIRED, "Length Required"}, {UH_STATUS_LENGTH_REQUIRED, "Length Required"},
{UH_STATUS_PRECONDITION_FAILED, "Precondition Failed"}, {UH_STATUS_PRECONDITION_FAILED, "Precondition Failed"},
{UH_STATUS_PAYLOAD_TOO_LARGE, "Payload Too Large"}, {UH_STATUS_PAYLOAD_TOO_LARGE, "Payload Too Large"},
{UH_STATUS_URI_TOO_LONG, "URI Too Long"}, {UH_STATUS_URI_TOO_LONG, "URI Too Long"},
{UH_STATUS_UNSUPPORTED_MEDIA_TYPE, "Unsupported Media Type"}, {UH_STATUS_UNSUPPORTED_MEDIA_TYPE, "Unsupported Media Type"},
{UH_STATUS_RANGE_NOT_SATISFIABLE, "Range Not Satisfiable"}, {UH_STATUS_RANGE_NOT_SATISFIABLE, "Range Not Satisfiable"},
{UH_STATUS_EXPECTATION_FAILED, "Expectation Failed"}, {UH_STATUS_EXPECTATION_FAILED, "Expectation Failed"},
{UH_STATUS_MISDIRECTED_REQUEST, "Misdirected Request"}, {UH_STATUS_MISDIRECTED_REQUEST, "Misdirected Request"},
{UH_STATUS_UNPROCESSABLE_ENTITY, "Unprocessable Entity"}, {UH_STATUS_UNPROCESSABLE_ENTITY, "Unprocessable Entity"},
{UH_STATUS_LOCKED, "Locked"}, {UH_STATUS_LOCKED, "Locked"},
{UH_STATUS_FAILED_DEPENDENCY, "Failed Dependency"}, {UH_STATUS_FAILED_DEPENDENCY, "Failed Dependency"},
{UH_STATUS_UPGRADE_REQUIRED, "Upgrade Required"}, {UH_STATUS_UPGRADE_REQUIRED, "Upgrade Required"},
{UH_STATUS_PRECONDITION_REQUIRED, "Precondition Required"}, {UH_STATUS_PRECONDITION_REQUIRED, "Precondition Required"},
{UH_STATUS_TOO_MANY_REQUESTS, "Too Many Requests"}, {UH_STATUS_TOO_MANY_REQUESTS, "Too Many Requests"},
{UH_STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE, "Request Header Fields Too Large"}, {UH_STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE, "Request Header Fields Too Large"},
{UH_STATUS_UNAVAILABLE_FOR_LEGAL_REASONS, "Unavailable For Legal Reasons"}, {UH_STATUS_UNAVAILABLE_FOR_LEGAL_REASONS, "Unavailable For Legal Reasons"},
{UH_STATUS_INTERNAL_SERVER_ERROR, "Internal Server Error"}, {UH_STATUS_INTERNAL_SERVER_ERROR, "Internal Server Error"},
{UH_STATUS_NOT_IMPLEMENTED, "Not Implemented"}, {UH_STATUS_NOT_IMPLEMENTED, "Not Implemented"},
{UH_STATUS_BAD_GATEWAY, "Bad Gateway"}, {UH_STATUS_BAD_GATEWAY, "Bad Gateway"},
{UH_STATUS_SERVICE_UNAVAILABLE, "Service Unavailable"}, {UH_STATUS_SERVICE_UNAVAILABLE, "Service Unavailable"},
{UH_STATUS_GATEWAY_TIMEOUT, "Gateway Timeout"}, {UH_STATUS_GATEWAY_TIMEOUT, "Gateway Timeout"},
{UH_STATUS_HTTP_VERSION_NOT_SUPPORTED, "HTTP Version Not Supported"}, {UH_STATUS_HTTP_VERSION_NOT_SUPPORTED, "HTTP Version Not Supported"},
{UH_STATUS_VARIANT_ALSO_NEGOTIATES, "Variant Also Negotiates"}, {UH_STATUS_VARIANT_ALSO_NEGOTIATES, "Variant Also Negotiates"},
{UH_STATUS_INSUFFICIENT_STORAGE, "Insufficient Storage"}, {UH_STATUS_INSUFFICIENT_STORAGE, "Insufficient Storage"},
{UH_STATUS_LOOP_DETECTED, "Loop Detected"}, {UH_STATUS_LOOP_DETECTED, "Loop Detected"},
{UH_STATUS_NOT_EXTENDED, "Not Extended"}, {UH_STATUS_NOT_EXTENDED, "Not Extended"},
{UH_STATUS_NETWORK_AUTHENTICATION_REQUIRED, "Network Authentication Required"} {UH_STATUS_NETWORK_AUTHENTICATION_REQUIRED, "Network Authentication Required"}
}; };
const char *uh_version() const char *uh_version()
{ {
return UHTTP_VERSION_STRING; return UHTTP_VERSION_STRING;
} }
static const char *get_http_status_message(int code) static const char *get_http_status_message(int code)
{ {
int i; int i;
const char *reason = "OK"; const char *reason = "OK";
for (i = 0; http_status_message[i].reason; i++) { for (i = 0; http_status_message[i].reason; i++) {
if (code == http_status_message[i].code) if (code == http_status_message[i].code)
reason = http_status_message[i].reason; reason = http_status_message[i].reason;
} }
return reason; return reason;
} }
static void uh_connection_destroy(struct uh_connection *con) static void uh_connection_destroy(struct uh_connection *con)
{ {
if (con) { if (con) {
struct ev_loop *loop = con->srv->loop; struct ev_loop *loop = con->srv->loop;
if (con->sock > 0) if (con->sock > 0)
close(con->sock); close(con->sock);
uh_buf_free(&con->read_buf); uh_buf_free(&con->read_buf);
uh_buf_free(&con->write_buf); uh_buf_free(&con->write_buf);
ev_io_stop(loop, &con->read_watcher); ev_io_stop(loop, &con->read_watcher);
ev_io_stop(loop, &con->write_watcher); ev_io_stop(loop, &con->write_watcher);
ev_timer_stop(loop, &con->timer_watcher); ev_timer_stop(loop, &con->timer_watcher);
list_del(&con->list); list_del(&con->list);
uh_ssl_free(con); uh_ssl_free(con);
free(con); free(con);
} }
} }
static void connection_timeout_cb(struct ev_loop *loop, ev_timer *w, int revents) static void connection_timeout_cb(struct ev_loop *loop, ev_timer *w, int revents)
{ {
struct uh_connection *con = container_of(w, struct uh_connection, timer_watcher); struct uh_connection *con = container_of(w, struct uh_connection, timer_watcher);
uh_log_info("connection(%p) timeout", con); uh_log_info("connection(%p) timeout", con);
uh_send_error(con, UH_STATUS_REQUEST_TIMEOUT, NULL); uh_send_error(con, UH_STATUS_REQUEST_TIMEOUT, NULL);
uh_connection_destroy(con); uh_connection_destroy(con);
} }
static int on_message_begin(http_parser *parser) static int on_message_begin(http_parser *parser)
{ {
struct uh_connection *con = container_of(parser, struct uh_connection, parser); struct uh_connection *con = container_of(parser, struct uh_connection, parser);
memset(&con->req, 0, sizeof(struct uh_request)); memset(&con->req, 0, sizeof(struct uh_request));
return 0; return 0;
} }
static int on_url(http_parser *parser, const char *at, size_t len) static int on_url(http_parser *parser, const char *at, size_t len)
{ {
struct uh_connection *con = container_of(parser, struct uh_connection, parser); struct uh_connection *con = container_of(parser, struct uh_connection, parser);
con->req.url.at = at; con->req.url.at = at;
con->req.url.len = len; con->req.url.len = len;
return 0; return 0;
} }
static int on_header_field(http_parser *parser, const char *at, size_t len) static int on_header_field(http_parser *parser, const char *at, size_t len)
{ {
struct uh_connection *con = container_of(parser, struct uh_connection, parser); struct uh_connection *con = container_of(parser, struct uh_connection, parser);
struct uh_header *header = con->req.header; struct uh_header *header = con->req.header;
header[con->req.header_num].field.at = at; header[con->req.header_num].field.at = at;
header[con->req.header_num].field.len = len; header[con->req.header_num].field.len = len;
return 0; return 0;
} }
static int on_header_value(http_parser *parser, const char *at, size_t len) static int on_header_value(http_parser *parser, const char *at, size_t len)
{ {
struct uh_connection *con = container_of(parser, struct uh_connection, parser); struct uh_connection *con = container_of(parser, struct uh_connection, parser);
struct uh_header *header = con->req.header; struct uh_header *header = con->req.header;
header[con->req.header_num].value.at = at; header[con->req.header_num].value.at = at;
header[con->req.header_num].value.len = len; header[con->req.header_num].value.len = len;
con->req.header_num += 1; con->req.header_num += 1;
return 0; return 0;
} }
static int on_headers_complete(http_parser *parser) static int on_headers_complete(http_parser *parser)
{ {
struct uh_connection *con = container_of(parser, struct uh_connection, parser); struct uh_connection *con = container_of(parser, struct uh_connection, parser);
if (parser->method != HTTP_GET && parser->method != HTTP_POST) { if (parser->method != HTTP_GET && parser->method != HTTP_POST) {
uh_send_error(con, UH_STATUS_METHOD_NOT_ALLOWED, NULL); uh_send_error(con, UH_STATUS_METHOD_NOT_ALLOWED, NULL);
return -1; return -1;
} }
return 0; return 0;
} }
static int on_body(http_parser *parser, const char *at, size_t len) static int on_body(http_parser *parser, const char *at, size_t len)
{ {
struct uh_connection *con = container_of(parser, struct uh_connection, parser); struct uh_connection *con = container_of(parser, struct uh_connection, parser);
if (!con->req.body.at) if (!con->req.body.at)
con->req.body.at = at; con->req.body.at = at;
con->req.body.len += len; con->req.body.len += len;
return 0; return 0;
} }
@ -189,415 +189,415 @@ static int on_body(http_parser *parser, const char *at, size_t len)
/* Return 1 for equal */ /* Return 1 for equal */
static int uh_value_cmp(struct uh_value *uv, const char *str) static int uh_value_cmp(struct uh_value *uv, const char *str)
{ {
if (uv->len != strlen(str)) if (uv->len != strlen(str))
return 0; return 0;
return (!strncasecmp(uv->at, str, uv->len)); return (!strncasecmp(uv->at, str, uv->len));
} }
static int on_message_complete(http_parser *parser) static int on_message_complete(http_parser *parser)
{ {
struct uh_connection *con = container_of(parser, struct uh_connection, parser); struct uh_connection *con = container_of(parser, struct uh_connection, parser);
struct uh_route *r; struct uh_route *r;
#if (UHTTP_DEBUG) #if (UHTTP_DEBUG)
int i; int i;
struct uh_header *header = con->req.header; struct uh_header *header = con->req.header;
uh_log_debug("Url:[%.*s]\n", (int)con->req.url.len, con->req.url.at); uh_log_debug("Url:[%.*s]\n", (int)con->req.url.len, con->req.url.at);
for (i = 0; i < con->req.header_num; i++) { for (i = 0; i < con->req.header_num; i++) {
uh_log_debug("[%.*s:%.*s]\n", (int)header[i].field.len, header[i].field.at, uh_log_debug("[%.*s:%.*s]\n", (int)header[i].field.len, header[i].field.at,
(int)header[i].value.len, header[i].value.at); (int)header[i].value.len, header[i].value.at);
} }
uh_log_debug("Body:[%.*s]\n", (int)con->req.body.len, con->req.body.at); uh_log_debug("Body:[%.*s]\n", (int)con->req.body.len, con->req.body.at);
#endif #endif
list_for_each_entry(r, &con->srv->routes, list) { list_for_each_entry(r, &con->srv->routes, list) {
if (uh_value_cmp(&con->req.url, r->path)) { if (uh_value_cmp(&con->req.url, r->path)) {
r->cb(con); r->cb(con);
return 0; return 0;
} }
} }
uh_send_error(con, UH_STATUS_NOT_FOUND, NULL); uh_send_error(con, UH_STATUS_NOT_FOUND, NULL);
return 0; return 0;
} }
static http_parser_settings parser_settings = { static http_parser_settings parser_settings = {
.on_message_begin = on_message_begin, .on_message_begin = on_message_begin,
.on_url = on_url, .on_url = on_url,
.on_header_field = on_header_field, .on_header_field = on_header_field,
.on_header_value = on_header_value, .on_header_value = on_header_value,
.on_headers_complete = on_headers_complete, .on_headers_complete = on_headers_complete,
.on_body = on_body, .on_body = on_body,
.on_message_complete = on_message_complete .on_message_complete = on_message_complete
}; };
static void connection_read_cb(struct ev_loop *loop, ev_io *w, int revents) static void connection_read_cb(struct ev_loop *loop, ev_io *w, int revents)
{ {
struct uh_connection *con = container_of(w, struct uh_connection, read_watcher); struct uh_connection *con = container_of(w, struct uh_connection, read_watcher);
struct uh_buf *buf = &con->read_buf; struct uh_buf *buf = &con->read_buf;
char *base; char *base;
int len, parsered; int len, parsered;
#if (UHTTP_SSL_ENABLED) #if (UHTTP_SSL_ENABLED)
if (con->flags & UH_CON_SSL_HANDSHAKE_DONE) if (con->flags & UH_CON_SSL_HANDSHAKE_DONE)
goto handshake_done; goto handshake_done;
uh_ssl_handshake(con); uh_ssl_handshake(con);
if (con->flags & UH_CON_CLOSE) if (con->flags & UH_CON_CLOSE)
uh_connection_destroy(con); uh_connection_destroy(con);
return; return;
handshake_done: handshake_done:
#endif #endif
if (uh_buf_available(buf) < UH_BUFFER_SIZE) if (uh_buf_available(buf) < UH_BUFFER_SIZE)
uh_buf_grow(buf, UH_BUFFER_SIZE); uh_buf_grow(buf, UH_BUFFER_SIZE);
base = buf->base + buf->len; base = buf->base + buf->len;
len = uh_ssl_read(con, base, UH_BUFFER_SIZE); len = uh_ssl_read(con, base, UH_BUFFER_SIZE);
if (unlikely(len <= 0)) { if (unlikely(len <= 0)) {
if (con->flags & UH_CON_CLOSE) if (con->flags & UH_CON_CLOSE)
uh_connection_destroy(con); uh_connection_destroy(con);
return; return;
} }
buf->len += len; buf->len += len;
#if (UHTTP_DEBUG) #if (UHTTP_DEBUG)
uh_log_debug("read:[%.*s]\n", len, base); uh_log_debug("read:[%.*s]\n", len, base);
#endif #endif
if (!(con->flags & UH_CON_PARSERING)) { if (!(con->flags & UH_CON_PARSERING)) {
if (!memmem(buf->base, buf->len, "\r\n\r\n", 4)) { if (!memmem(buf->base, buf->len, "\r\n\r\n", 4)) {
if (buf->len > UH_MAX_HTTP_HEAD_SIZE) { if (buf->len > UH_MAX_HTTP_HEAD_SIZE) {
uh_log_err("HTTP head size too big"); uh_log_err("HTTP head size too big");
uh_send_error(con, UH_STATUS_BAD_REQUEST, NULL); uh_send_error(con, UH_STATUS_BAD_REQUEST, NULL);
} }
return; return;
} }
base = buf->base; base = buf->base;
len = buf->len; len = buf->len;
con->flags |= UH_CON_PARSERING; con->flags |= UH_CON_PARSERING;
} }
parsered = http_parser_execute(&con->parser, &parser_settings, base, len); parsered = http_parser_execute(&con->parser, &parser_settings, base, len);
if (unlikely(parsered != len && !(con->flags & UH_CON_CLOSE))) { if (unlikely(parsered != len && !(con->flags & UH_CON_CLOSE))) {
uh_log_err("http parser failed:%s", http_errno_description(HTTP_PARSER_ERRNO(&con->parser))); uh_log_err("http parser failed:%s", http_errno_description(HTTP_PARSER_ERRNO(&con->parser)));
uh_send_error(con, UH_STATUS_BAD_REQUEST, NULL); uh_send_error(con, UH_STATUS_BAD_REQUEST, NULL);
} else { } else {
ev_timer_mode(loop, &con->timer_watcher, UH_CONNECTION_TIMEOUT, 0); ev_timer_mode(loop, &con->timer_watcher, UH_CONNECTION_TIMEOUT, 0);
} }
} }
static void connection_write_cb(struct ev_loop *loop, ev_io *w, int revents) static void connection_write_cb(struct ev_loop *loop, ev_io *w, int revents)
{ {
struct uh_connection *con = container_of(w, struct uh_connection, write_watcher); struct uh_connection *con = container_of(w, struct uh_connection, write_watcher);
struct uh_buf *buf = &con->write_buf; struct uh_buf *buf = &con->write_buf;
if (buf->len > 0) { if (buf->len > 0) {
int len = uh_ssl_write(con, buf->base, buf->len); int len = uh_ssl_write(con, buf->base, buf->len);
if (len > 0) if (len > 0)
uh_buf_remove(buf, len); uh_buf_remove(buf, len);
} }
if (buf->len == 0) { if (buf->len == 0) {
ev_io_stop(loop, w); ev_io_stop(loop, w);
if (!http_should_keep_alive(&con->parser)) if (!http_should_keep_alive(&con->parser))
con->flags |= UH_CON_CLOSE; con->flags |= UH_CON_CLOSE;
} }
if (con->flags & UH_CON_CLOSE) if (con->flags & UH_CON_CLOSE)
uh_connection_destroy(con); uh_connection_destroy(con);
} }
static void uh_accept_cb(struct ev_loop *loop, ev_io *w, int revents) static void uh_accept_cb(struct ev_loop *loop, ev_io *w, int revents)
{ {
int sock = -1; int sock = -1;
struct uh_server *srv = container_of(w, struct uh_server, read_watcher); struct uh_server *srv = container_of(w, struct uh_server, read_watcher);
struct uh_connection *con = NULL; struct uh_connection *con = NULL;
ev_io *read_watcher, *write_watcher; ev_io *read_watcher, *write_watcher;
ev_timer *timer_watcher; ev_timer *timer_watcher;
con = calloc(1, sizeof(struct uh_connection)); con = calloc(1, sizeof(struct uh_connection));
if (unlikely(!con)) { if (unlikely(!con)) {
uh_log_err("calloc"); uh_log_err("calloc");
return; return;
} }
con->srv = srv; con->srv = srv;
list_add(&con->list, &srv->connections); list_add(&con->list, &srv->connections);
sock = uh_ssl_accept(con); sock = uh_ssl_accept(con);
if (unlikely(sock < 0)) if (unlikely(sock < 0))
goto err; goto err;
read_watcher = &con->read_watcher; read_watcher = &con->read_watcher;
ev_io_init(read_watcher, connection_read_cb, sock, EV_READ); ev_io_init(read_watcher, connection_read_cb, sock, EV_READ);
ev_io_start(loop,read_watcher); ev_io_start(loop,read_watcher);
write_watcher = &con->write_watcher; write_watcher = &con->write_watcher;
ev_io_init(write_watcher, connection_write_cb, sock, EV_WRITE); ev_io_init(write_watcher, connection_write_cb, sock, EV_WRITE);
timer_watcher = &con->timer_watcher; timer_watcher = &con->timer_watcher;
ev_timer_init(timer_watcher, connection_timeout_cb, UH_CONNECTION_TIMEOUT, 0); ev_timer_init(timer_watcher, connection_timeout_cb, UH_CONNECTION_TIMEOUT, 0);
ev_timer_start(loop, timer_watcher); ev_timer_start(loop, timer_watcher);
http_parser_init(&con->parser, HTTP_REQUEST); http_parser_init(&con->parser, HTTP_REQUEST);
uh_log_info("new connection:%p", con); uh_log_info("new connection:%p", con);
return; return;
err: err:
uh_connection_destroy(con); uh_connection_destroy(con);
} }
struct uh_server *uh_server_new(struct ev_loop *loop, const char *ipaddr, int port) struct uh_server *uh_server_new(struct ev_loop *loop, const char *ipaddr, int port)
{ {
struct uh_server *srv = NULL; struct uh_server *srv = NULL;
struct sockaddr_in addr; struct sockaddr_in addr;
int sock = -1, on = 1; int sock = -1, on = 1;
ev_io *read_watcher; ev_io *read_watcher;
addr.sin_family = AF_INET; addr.sin_family = AF_INET;
addr.sin_port = htons(port); addr.sin_port = htons(port);
if (inet_pton(AF_INET, ipaddr, &addr.sin_addr) <= 0) { if (inet_pton(AF_INET, ipaddr, &addr.sin_addr) <= 0) {
uh_log_err("invalid ipaddr"); uh_log_err("invalid ipaddr");
return NULL; return NULL;
} }
srv = calloc(1, sizeof(struct uh_server)); srv = calloc(1, sizeof(struct uh_server));
if (!srv) { if (!srv) {
uh_log_err("calloc"); uh_log_err("calloc");
return NULL; return NULL;
} }
INIT_LIST_HEAD(&srv->routes); INIT_LIST_HEAD(&srv->routes);
INIT_LIST_HEAD(&srv->connections); INIT_LIST_HEAD(&srv->connections);
sock = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0); sock = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0);
if (sock < 0) { if (sock < 0) {
uh_log_err("socket"); uh_log_err("socket");
goto err; goto err;
} }
srv->sock = sock; srv->sock = sock;
srv->loop = loop; srv->loop = loop;
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
if (bind(sock, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) < 0) { if (bind(sock, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) < 0) {
uh_log_err("bind"); uh_log_err("bind");
goto err; goto err;
} }
if (listen(sock, SOMAXCONN) < 0) { if (listen(sock, SOMAXCONN) < 0) {
uh_log_err("listen"); uh_log_err("listen");
goto err; goto err;
} }
read_watcher = &srv->read_watcher; read_watcher = &srv->read_watcher;
ev_io_init(read_watcher, uh_accept_cb, sock, EV_READ); ev_io_init(read_watcher, uh_accept_cb, sock, EV_READ);
ev_io_start(loop, read_watcher); ev_io_start(loop, read_watcher);
return srv; return srv;
err: err:
uh_server_free(srv); uh_server_free(srv);
return NULL; return NULL;
} }
void uh_server_free(struct uh_server *srv) void uh_server_free(struct uh_server *srv)
{ {
if (srv) { if (srv) {
struct uh_connection *con, *tmp_c; struct uh_connection *con, *tmp_c;
struct uh_route *r, *tmp_r; struct uh_route *r, *tmp_r;
if (srv->sock > 0) if (srv->sock > 0)
close(srv->sock); close(srv->sock);
ev_io_stop(srv->loop, &srv->read_watcher); ev_io_stop(srv->loop, &srv->read_watcher);
list_for_each_entry_safe(con, tmp_c, &srv->connections, list) { list_for_each_entry_safe(con, tmp_c, &srv->connections, list) {
uh_connection_destroy(con); uh_connection_destroy(con);
} }
list_for_each_entry_safe(r, tmp_r, &srv->routes, list) { list_for_each_entry_safe(r, tmp_r, &srv->routes, list) {
list_del(&r->list); list_del(&r->list);
free(r->path); free(r->path);
free(r); free(r);
} }
uh_ssl_ctx_free(srv); uh_ssl_ctx_free(srv);
free(srv); free(srv);
} }
} }
int uh_send(struct uh_connection *con, const void *buf, int len) int uh_send(struct uh_connection *con, const void *buf, int len)
{ {
len = uh_buf_append(&con->write_buf, buf, len); len = uh_buf_append(&con->write_buf, buf, len);
if (len > 0) if (len > 0)
ev_io_start(con->srv->loop, &con->write_watcher); ev_io_start(con->srv->loop, &con->write_watcher);
return len; return len;
} }
int uh_printf(struct uh_connection *con, const char *fmt, ...) int uh_printf(struct uh_connection *con, const char *fmt, ...)
{ {
int len = 0; int len = 0;
va_list ap; va_list ap;
char *str = NULL; char *str = NULL;
assert(fmt); assert(fmt);
if (*fmt) { if (*fmt) {
va_start(ap, fmt); va_start(ap, fmt);
len = vasprintf(&str, fmt, ap); len = vasprintf(&str, fmt, ap);
va_end(ap); va_end(ap);
} }
if (len >= 0) { if (len >= 0) {
len = uh_send(con, str, len); len = uh_send(con, str, len);
free(str); free(str);
} }
return len; return len;
} }
static void send_status_line(struct uh_connection *con, int code) static void send_status_line(struct uh_connection *con, int code)
{ {
const char *reason = get_http_status_message(code); const char *reason = get_http_status_message(code);
uh_printf(con, "HTTP/1.1 %d %s\r\nServer: Libuhttp %s\r\n", uh_printf(con, "HTTP/1.1 %d %s\r\nServer: Libuhttp %s\r\n",
code, reason, UHTTP_VERSION_STRING); code, reason, UHTTP_VERSION_STRING);
} }
void uh_send_head(struct uh_connection *con, int status, int length, const char *extra_headers) void uh_send_head(struct uh_connection *con, int status, int length, const char *extra_headers)
{ {
send_status_line(con, status); send_status_line(con, status);
if (length < 0) if (length < 0)
uh_printf(con, "%s", "Transfer-Encoding: chunked\r\n"); uh_printf(con, "%s", "Transfer-Encoding: chunked\r\n");
else else
uh_printf(con, "Content-Length: %d\r\n", length); uh_printf(con, "Content-Length: %d\r\n", length);
if (extra_headers) if (extra_headers)
uh_send(con, extra_headers, strlen(extra_headers)); uh_send(con, extra_headers, strlen(extra_headers));
uh_send(con, "\r\n", 2); uh_send(con, "\r\n", 2);
} }
void uh_send_error(struct uh_connection *con, int code, const char *reason) void uh_send_error(struct uh_connection *con, int code, const char *reason)
{ {
http_parser *parser = &con->parser; http_parser *parser = &con->parser;
if (!reason) if (!reason)
reason = get_http_status_message(code); reason = get_http_status_message(code);
if (http_should_keep_alive(parser) && code < UH_STATUS_BAD_REQUEST) { if (http_should_keep_alive(parser) && code < UH_STATUS_BAD_REQUEST) {
uh_send_head(con, code, strlen(reason), "Content-Type: text/plain\r\nConnection: keep-alive\r\n"); uh_send_head(con, code, strlen(reason), "Content-Type: text/plain\r\nConnection: keep-alive\r\n");
} else { } else {
uh_send_head(con, code, strlen(reason), "Content-Type: text/plain\r\nConnection: close\r\n"); uh_send_head(con, code, strlen(reason), "Content-Type: text/plain\r\nConnection: close\r\n");
con->flags |= UH_CON_CLOSE; con->flags |= UH_CON_CLOSE;
} }
} }
void uh_redirect(struct uh_connection *con, int code, const char *location) void uh_redirect(struct uh_connection *con, int code, const char *location)
{ {
char body[128] = ""; char body[128] = "";
http_parser *parser = &con->parser; http_parser *parser = &con->parser;
snprintf(body, sizeof(body), "<p>Moved <a href=\"%s\">here</a></p>", location); snprintf(body, sizeof(body), "<p>Moved <a href=\"%s\">here</a></p>", location);
send_status_line(con, code); send_status_line(con, code);
uh_printf(con, uh_printf(con,
"Location: %s\r\n" "Location: %s\r\n"
"Content-Type: text/html\r\n" "Content-Type: text/html\r\n"
"Content-Length: %zu\r\n" "Content-Length: %zu\r\n"
"Cache-Control: no-cache\r\n", location, strlen(body)); "Cache-Control: no-cache\r\n", location, strlen(body));
uh_send(con, "\r\n", 2); uh_send(con, "\r\n", 2);
if (parser->method != HTTP_HEAD) if (parser->method != HTTP_HEAD)
uh_send(con, body, strlen(body)); uh_send(con, body, strlen(body));
} }
int uh_send_chunk(struct uh_connection *con, const char *buf, int len) int uh_send_chunk(struct uh_connection *con, const char *buf, int len)
{ {
int slen = 0; int slen = 0;
slen += uh_printf(con, "%X\r\n", len); slen += uh_printf(con, "%X\r\n", len);
slen += uh_send(con, buf, len); slen += uh_send(con, buf, len);
slen += uh_send(con, "\r\n", 2); slen += uh_send(con, "\r\n", 2);
return slen; return slen;
} }
int uh_printf_chunk(struct uh_connection *con, const char *fmt, ...) int uh_printf_chunk(struct uh_connection *con, const char *fmt, ...)
{ {
int len = 0; int len = 0;
va_list ap; va_list ap;
char *str = NULL; char *str = NULL;
assert(fmt); assert(fmt);
if (*fmt) { if (*fmt) {
va_start(ap, fmt); va_start(ap, fmt);
len = vasprintf(&str, fmt, ap); len = vasprintf(&str, fmt, ap);
va_end(ap); va_end(ap);
} }
if (len >= 0) { if (len >= 0) {
len = uh_send_chunk(con, str, len); len = uh_send_chunk(con, str, len);
free(str); free(str);
} }
return len; return len;
} }
int uh_register_route(struct uh_server *srv, const char *path, uh_route_handler_t cb) int uh_register_route(struct uh_server *srv, const char *path, uh_route_handler_t cb)
{ {
struct uh_route *r; struct uh_route *r;
assert(path); assert(path);
r = calloc(1, sizeof(struct uh_route)); r = calloc(1, sizeof(struct uh_route));
if (!r) { if (!r) {
uh_log_err("calloc"); uh_log_err("calloc");
return -1; return -1;
} }
r->path = strdup(path); r->path = strdup(path);
if (!r->path) { if (!r->path) {
uh_log_err("strdup"); uh_log_err("strdup");
free(r); free(r);
return -1; return -1;
} }
r->cb = cb; r->cb = cb;
list_add(&r->list, &srv->routes); list_add(&r->list, &srv->routes);
return 0; return 0;
} }
inline struct uh_value *uh_get_url(struct uh_connection *con) inline struct uh_value *uh_get_url(struct uh_connection *con)
{ {
return &con->req.url; return &con->req.url;
} }
struct uh_value *uh_get_header(struct uh_connection *con, const char *name) struct uh_value *uh_get_header(struct uh_connection *con, const char *name)
{ {
int i; int i;
struct uh_header *header = con->req.header; struct uh_header *header = con->req.header;
for (i = 0; i < con->req.header_num; i++) { for (i = 0; i < con->req.header_num; i++) {
if (uh_value_cmp(&header[i].field, name)) if (uh_value_cmp(&header[i].field, name))
return &header[i].value; return &header[i].value;
} }
return NULL; return NULL;
} }

View File

@ -8,73 +8,73 @@
/* HTTP Status Codes */ /* HTTP Status Codes */
enum uh_status { enum uh_status {
UH_STATUS_CONTINUE = 100, UH_STATUS_CONTINUE = 100,
UH_STATUS_SWITCHING_PROTOCOLS = 101, UH_STATUS_SWITCHING_PROTOCOLS = 101,
UH_STATUS_PROCESSING = 102, UH_STATUS_PROCESSING = 102,
UH_STATUS_OK = 200, UH_STATUS_OK = 200,
UH_STATUS_CREATED = 201, UH_STATUS_CREATED = 201,
UH_STATUS_ACCEPTED = 202, UH_STATUS_ACCEPTED = 202,
UH_STATUS_NON_AUTHORITATIVE_INFORMATION = 203, UH_STATUS_NON_AUTHORITATIVE_INFORMATION = 203,
UH_STATUS_NO_CONTENT = 204, UH_STATUS_NO_CONTENT = 204,
UH_STATUS_RESET_CONTENT = 205, UH_STATUS_RESET_CONTENT = 205,
UH_STATUS_PARTIAL_CONTENT = 206, UH_STATUS_PARTIAL_CONTENT = 206,
UH_STATUS_MULTI_STATUS = 207, UH_STATUS_MULTI_STATUS = 207,
UH_STATUS_ALREADY_REPORTED = 208, UH_STATUS_ALREADY_REPORTED = 208,
UH_STATUS_IM_USED = 226, UH_STATUS_IM_USED = 226,
UH_STATUS_MULTIPLE_CHOICES = 300, UH_STATUS_MULTIPLE_CHOICES = 300,
UH_STATUS_MOVED_PERMANENTLY = 301, UH_STATUS_MOVED_PERMANENTLY = 301,
UH_STATUS_FOUND = 302, UH_STATUS_FOUND = 302,
UH_STATUS_SEE_OTHER = 303, UH_STATUS_SEE_OTHER = 303,
UH_STATUS_NOT_MODIFIED = 304, UH_STATUS_NOT_MODIFIED = 304,
UH_STATUS_USE_PROXY = 305, UH_STATUS_USE_PROXY = 305,
UH_STATUS_TEMPORARY_REDIRECT = 307, UH_STATUS_TEMPORARY_REDIRECT = 307,
UH_STATUS_PERMANENT_REDIRECT = 308, UH_STATUS_PERMANENT_REDIRECT = 308,
UH_STATUS_BAD_REQUEST = 400, UH_STATUS_BAD_REQUEST = 400,
UH_STATUS_UNAUTHORIZED = 401, UH_STATUS_UNAUTHORIZED = 401,
UH_STATUS_PAYMENT_REQUIRED = 402, UH_STATUS_PAYMENT_REQUIRED = 402,
UH_STATUS_FORBIDDEN = 403, UH_STATUS_FORBIDDEN = 403,
UH_STATUS_NOT_FOUND = 404, UH_STATUS_NOT_FOUND = 404,
UH_STATUS_METHOD_NOT_ALLOWED = 405, UH_STATUS_METHOD_NOT_ALLOWED = 405,
UH_STATUS_NOT_ACCEPTABLE = 406, UH_STATUS_NOT_ACCEPTABLE = 406,
UH_STATUS_PROXY_AUTHENTICATION_REQUIRED = 407, UH_STATUS_PROXY_AUTHENTICATION_REQUIRED = 407,
UH_STATUS_REQUEST_TIMEOUT = 408, UH_STATUS_REQUEST_TIMEOUT = 408,
UH_STATUS_CONFLICT = 409, UH_STATUS_CONFLICT = 409,
UH_STATUS_GONE = 410, UH_STATUS_GONE = 410,
UH_STATUS_LENGTH_REQUIRED = 411, UH_STATUS_LENGTH_REQUIRED = 411,
UH_STATUS_PRECONDITION_FAILED = 412, UH_STATUS_PRECONDITION_FAILED = 412,
UH_STATUS_PAYLOAD_TOO_LARGE = 413, UH_STATUS_PAYLOAD_TOO_LARGE = 413,
UH_STATUS_URI_TOO_LONG = 414, UH_STATUS_URI_TOO_LONG = 414,
UH_STATUS_UNSUPPORTED_MEDIA_TYPE = 415, UH_STATUS_UNSUPPORTED_MEDIA_TYPE = 415,
UH_STATUS_RANGE_NOT_SATISFIABLE = 416, UH_STATUS_RANGE_NOT_SATISFIABLE = 416,
UH_STATUS_EXPECTATION_FAILED = 417, UH_STATUS_EXPECTATION_FAILED = 417,
UH_STATUS_MISDIRECTED_REQUEST = 421, UH_STATUS_MISDIRECTED_REQUEST = 421,
UH_STATUS_UNPROCESSABLE_ENTITY = 422, UH_STATUS_UNPROCESSABLE_ENTITY = 422,
UH_STATUS_LOCKED = 423, UH_STATUS_LOCKED = 423,
UH_STATUS_FAILED_DEPENDENCY = 424, UH_STATUS_FAILED_DEPENDENCY = 424,
UH_STATUS_UPGRADE_REQUIRED = 426, UH_STATUS_UPGRADE_REQUIRED = 426,
UH_STATUS_PRECONDITION_REQUIRED = 428, UH_STATUS_PRECONDITION_REQUIRED = 428,
UH_STATUS_TOO_MANY_REQUESTS = 429, UH_STATUS_TOO_MANY_REQUESTS = 429,
UH_STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE = 431, UH_STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE = 431,
UH_STATUS_UNAVAILABLE_FOR_LEGAL_REASONS = 451, UH_STATUS_UNAVAILABLE_FOR_LEGAL_REASONS = 451,
UH_STATUS_INTERNAL_SERVER_ERROR = 500, UH_STATUS_INTERNAL_SERVER_ERROR = 500,
UH_STATUS_NOT_IMPLEMENTED = 501, UH_STATUS_NOT_IMPLEMENTED = 501,
UH_STATUS_BAD_GATEWAY = 502, UH_STATUS_BAD_GATEWAY = 502,
UH_STATUS_SERVICE_UNAVAILABLE = 503, UH_STATUS_SERVICE_UNAVAILABLE = 503,
UH_STATUS_GATEWAY_TIMEOUT = 504, UH_STATUS_GATEWAY_TIMEOUT = 504,
UH_STATUS_HTTP_VERSION_NOT_SUPPORTED = 505, UH_STATUS_HTTP_VERSION_NOT_SUPPORTED = 505,
UH_STATUS_VARIANT_ALSO_NEGOTIATES = 506, UH_STATUS_VARIANT_ALSO_NEGOTIATES = 506,
UH_STATUS_INSUFFICIENT_STORAGE = 507, UH_STATUS_INSUFFICIENT_STORAGE = 507,
UH_STATUS_LOOP_DETECTED = 508, UH_STATUS_LOOP_DETECTED = 508,
UH_STATUS_NOT_EXTENDED = 510, UH_STATUS_NOT_EXTENDED = 510,
UH_STATUS_NETWORK_AUTHENTICATION_REQUIRED = 511 UH_STATUS_NETWORK_AUTHENTICATION_REQUIRED = 511
}; };
struct uh_server; struct uh_server;
struct uh_connection; struct uh_connection;
struct uh_value { struct uh_value {
const char *at; const char *at;
size_t len; size_t len;
}; };
typedef void (*uh_route_handler_t)(struct uh_connection *con); typedef void (*uh_route_handler_t)(struct uh_connection *con);
@ -131,9 +131,9 @@ void uh_redirect(struct uh_connection *con, int code, const char *location);
* to tell the client that everything was sent. * to tell the client that everything was sent.
* *
* Example: * Example:
* char data[] = "Hello World"; * char data[] = "Hello World";
* uh_send_chunk(con, data, strlen(data)); * uh_send_chunk(con, data, strlen(data));
* uh_send_chunk(con, NULL, 0); // Tell the client we're finished * uh_send_chunk(con, NULL, 0); // Tell the client we're finished
*/ */
int uh_send_chunk(struct uh_connection *con, const char *buf, int len); int uh_send_chunk(struct uh_connection *con, const char *buf, int len);

View File

@ -5,64 +5,64 @@
int uh_buf_init(struct uh_buf *buf, size_t initial_size) int uh_buf_init(struct uh_buf *buf, size_t initial_size)
{ {
buf->len = buf->size = 0; buf->len = buf->size = 0;
if (buf->base) { if (buf->base) {
free(buf->base); free(buf->base);
buf->base = NULL; buf->base = NULL;
} }
if (initial_size > 0) { if (initial_size > 0) {
buf->base = malloc(initial_size); buf->base = malloc(initial_size);
if (!buf->base) if (!buf->base)
return -1; return -1;
buf->size = initial_size; buf->size = initial_size;
} }
return 0; return 0;
} }
int uh_buf_grow(struct uh_buf *buf, size_t size) int uh_buf_grow(struct uh_buf *buf, size_t size)
{ {
void *base = realloc(buf->base, buf->size + size); void *base = realloc(buf->base, buf->size + size);
if (!base) if (!base)
return -1; return -1;
buf->base = base; buf->base = base;
buf->size += size; buf->size += size;
uh_log_debug("uh_buf_grow:%p +%d", buf, size); uh_log_debug("uh_buf_grow:%p +%d", buf, size);
return 0; return 0;
} }
void uh_buf_free(struct uh_buf *buf) void uh_buf_free(struct uh_buf *buf)
{ {
uh_buf_init(buf, 0); uh_buf_init(buf, 0);
} }
size_t uh_buf_append(struct uh_buf *buf, const void *data, size_t len) size_t uh_buf_append(struct uh_buf *buf, const void *data, size_t len)
{ {
assert(buf); assert(buf);
if (!data) if (!data)
return 0; return 0;
if (buf->len + len > buf->size) { if (buf->len + len > buf->size) {
if (uh_buf_grow(buf, len * UH_BUF_SIZE_MULTIPLIER) == -1) if (uh_buf_grow(buf, len * UH_BUF_SIZE_MULTIPLIER) == -1)
len = buf->size - buf->len; len = buf->size - buf->len;
} }
memcpy(buf->base + buf->len, data, len); memcpy(buf->base + buf->len, data, len);
buf->len += len; buf->len += len;
return len; return len;
} }
void uh_buf_remove(struct uh_buf *buf, size_t n) void uh_buf_remove(struct uh_buf *buf, size_t n)
{ {
if (n > 0 && n <= buf->len) { if (n > 0 && n <= buf->len) {
memmove(buf->base, buf->base + n, buf->len - n); memmove(buf->base, buf->base + n, buf->len - n);
buf->len -= n; buf->len -= n;
} }
} }

View File

@ -8,9 +8,9 @@
#define UH_BUF_SIZE_MULTIPLIER 1.5 #define UH_BUF_SIZE_MULTIPLIER 1.5
struct uh_buf { struct uh_buf {
char *base; /* Buffer pointer */ char *base; /* Buffer pointer */
size_t len; /* Data length */ size_t len; /* Data length */
size_t size; /* Buffer size */ size_t size; /* Buffer size */
}; };
#define uh_buf_available(b) ((b)->size - (b)->len) #define uh_buf_available(b) ((b)->size - (b)->len)

View File

@ -1,9 +1,9 @@
#ifndef _UHTTP_CONFIG_H #ifndef _UHTTP_CONFIG_H
#define _UHTTP_CONFIG_H #define _UHTTP_CONFIG_H
#define UHTTP_VERSION_MAJOR @UHTTP_VERSION_MAJOR@ #define UHTTP_VERSION_MAJOR @UHTTP_VERSION_MAJOR@
#define UHTTP_VERSION_MINOR @UHTTP_VERSION_MINOR@ #define UHTTP_VERSION_MINOR @UHTTP_VERSION_MINOR@
#define UHTTP_VERSION_STRING "@UHTTP_VERSION_MAJOR@.@UHTTP_VERSION_MINOR@" #define UHTTP_VERSION_STRING "@UHTTP_VERSION_MAJOR@.@UHTTP_VERSION_MINOR@"
#define UHTTP_DEBUG @UHTTP_DEBUG_CONFIG@ #define UHTTP_DEBUG @UHTTP_DEBUG_CONFIG@

View File

@ -10,65 +10,65 @@
#define UH_CONNECTION_TIMEOUT 30 #define UH_CONNECTION_TIMEOUT 30
#define UH_MAX_HTTP_HEAD_SIZE 1024 #define UH_MAX_HTTP_HEAD_SIZE 1024
#define UH_MAX_HTTP_BODY_SIZE (2 * 1024 * 1024) #define UH_MAX_HTTP_BODY_SIZE (2 * 1024 * 1024)
#define UH_MAX_HTTP_HEADERS 20 #define UH_MAX_HTTP_HEADERS 20
#define UH_CON_CLOSE (1 << 0) #define UH_CON_CLOSE (1 << 0)
#define UH_CON_SSL_HANDSHAKE_DONE (1 << 1) /* SSL hanshake has completed */ #define UH_CON_SSL_HANDSHAKE_DONE (1 << 1) /* SSL hanshake has completed */
#define UH_CON_PARSERING (1 << 2) /* Whether executed http_parser_execute() */ #define UH_CON_PARSERING (1 << 2) /* Whether executed http_parser_execute() */
#define likely(x) (__builtin_expect(!!(x), 1)) #define likely(x) (__builtin_expect(!!(x), 1))
#define unlikely(x) (__builtin_expect(!!(x), 0)) #define unlikely(x) (__builtin_expect(!!(x), 0))
#define ev_timer_mode(l,w,after,repeat) do { \ #define ev_timer_mode(l,w,after,repeat) do { \
ev_timer_stop(l, w); \ ev_timer_stop(l, w); \
ev_timer_init(w, ev_cb(w), after, repeat); \ ev_timer_init(w, ev_cb(w), after, repeat); \
ev_timer_start(l, w); \ ev_timer_start(l, w); \
} while (0) } while (0)
struct uh_route { struct uh_route {
char *path; char *path;
uh_route_handler_t cb; uh_route_handler_t cb;
struct list_head list; struct list_head list;
}; };
struct uh_server { struct uh_server {
int sock; int sock;
#if (UHTTP_SSL_ENABLED) #if (UHTTP_SSL_ENABLED)
void *ssl_ctx; void *ssl_ctx;
#endif #endif
ev_io read_watcher; ev_io read_watcher;
struct ev_loop *loop; struct ev_loop *loop;
struct list_head routes; struct list_head routes;
struct list_head connections; struct list_head connections;
}; };
struct uh_header { struct uh_header {
struct uh_value field; struct uh_value field;
struct uh_value value; struct uh_value value;
}; };
struct uh_request { struct uh_request {
struct uh_value url; struct uh_value url;
struct uh_value body; struct uh_value body;
int header_num; int header_num;
struct uh_header header[UH_MAX_HTTP_HEADERS]; struct uh_header header[UH_MAX_HTTP_HEADERS];
}; };
struct uh_connection { struct uh_connection {
int sock; int sock;
#if (UHTTP_SSL_ENABLED) #if (UHTTP_SSL_ENABLED)
void *ssl; void *ssl;
#endif #endif
unsigned char flags; unsigned char flags;
struct uh_buf read_buf; struct uh_buf read_buf;
struct uh_buf write_buf; struct uh_buf write_buf;
ev_io read_watcher; ev_io read_watcher;
ev_io write_watcher; ev_io write_watcher;
ev_timer timer_watcher; ev_timer timer_watcher;
struct uh_request req; struct uh_request req;
http_parser parser; http_parser parser;
struct list_head list; struct list_head list;
struct uh_server *srv; struct uh_server *srv;
}; };
#endif #endif

View File

@ -2,29 +2,29 @@
void __uh_log(const char *filename, int line, int priority, const char *format, ...) void __uh_log(const char *filename, int line, int priority, const char *format, ...)
{ {
va_list ap; va_list ap;
static char buf[128]; static char buf[128];
snprintf(buf, sizeof(buf), "(%s:%d) ", filename, line); snprintf(buf, sizeof(buf), "(%s:%d) ", filename, line);
va_start(ap, format); va_start(ap, format);
vsnprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), format, ap); vsnprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), format, ap);
va_end(ap); va_end(ap);
if (priority == LOG_ERR && errno > 0) { if (priority == LOG_ERR && errno > 0) {
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), ":%s", strerror(errno)); snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), ":%s", strerror(errno));
errno = 0; errno = 0;
} }
syslog(priority, "%s", buf); syslog(priority, "%s", buf);
#if (UHTTP_DEBUG) #if (UHTTP_DEBUG)
fprintf(stderr, "%s\n", buf); fprintf(stderr, "%s\n", buf);
#else #else
if (priority == LOG_ERR) if (priority == LOG_ERR)
fprintf(stderr, "%s\n", buf); fprintf(stderr, "%s\n", buf);
#endif #endif
} }

View File

@ -16,13 +16,13 @@
#define uh_log(priority, format...) __uh_log(__FILENAME__, __LINE__, priority, format) #define uh_log(priority, format...) __uh_log(__FILENAME__, __LINE__, priority, format)
#if (UHTTP_DEBUG) #if (UHTTP_DEBUG)
#define uh_log_debug(format...) uh_log(LOG_DEBUG, format) #define uh_log_debug(format...) uh_log(LOG_DEBUG, format)
#else #else
#define uh_log_debug(format...) #define uh_log_debug(format...)
#endif #endif
#define uh_log_info(format...) uh_log(LOG_INFO, format) #define uh_log_info(format...) uh_log(LOG_INFO, format)
#define uh_log_err(format...) uh_log(LOG_ERR, format) #define uh_log_err(format...) uh_log(LOG_ERR, format)
void __uh_log(const char *filename, int line, int priority, const char *format, ...); void __uh_log(const char *filename, int line, int priority, const char *format, ...);

View File

@ -5,196 +5,196 @@
#if (UHTTP_SSL_ENABLED) #if (UHTTP_SSL_ENABLED)
int uh_ssl_init(struct uh_server *srv, const char *cert, const char *key) int uh_ssl_init(struct uh_server *srv, const char *cert, const char *key)
{ {
SSL_CTX *ctx = NULL; SSL_CTX *ctx = NULL;
SSL_library_init(); SSL_library_init();
/* registers the error strings for all libssl functions */ /* registers the error strings for all libssl functions */
SSL_load_error_strings(); SSL_load_error_strings();
/* creates a new SSL_CTX object */ /* creates a new SSL_CTX object */
ctx = SSL_CTX_new(SSLv23_server_method()); ctx = SSL_CTX_new(SSLv23_server_method());
if (!ctx) { if (!ctx) {
uh_log_err("Failed to create SSL context"); uh_log_err("Failed to create SSL context");
return -1; return -1;
} }
/* loads the first certificate stored in file into ctx */ /* loads the first certificate stored in file into ctx */
if (SSL_CTX_use_certificate_file(ctx, cert, SSL_FILETYPE_PEM) != SSL_SUCCESS) { if (SSL_CTX_use_certificate_file(ctx, cert, SSL_FILETYPE_PEM) != SSL_SUCCESS) {
uh_log_err("OpenSSL Error: loading certificate file failed"); uh_log_err("OpenSSL Error: loading certificate file failed");
goto err; goto err;
} }
/* /*
* adds the first private RSA key found in file to ctx. * adds the first private RSA key found in file to ctx.
* *
* checks the consistency of a private key with the corresponding * checks the consistency of a private key with the corresponding
* certificate loaded into ctx. If more than one key/certificate * certificate loaded into ctx. If more than one key/certificate
* pair (RSA/DSA) is installed, the last item installed will be checked. * pair (RSA/DSA) is installed, the last item installed will be checked.
*/ */
if (SSL_CTX_use_RSAPrivateKey_file(ctx, key, SSL_FILETYPE_PEM) != SSL_SUCCESS) { if (SSL_CTX_use_RSAPrivateKey_file(ctx, key, SSL_FILETYPE_PEM) != SSL_SUCCESS) {
uh_log_err("OpenSSL Error: loading key failed"); uh_log_err("OpenSSL Error: loading key failed");
goto err; goto err;
} }
srv->ssl_ctx = ctx; srv->ssl_ctx = ctx;
return 0; return 0;
err: err:
SSL_CTX_free(ctx); SSL_CTX_free(ctx);
return -1; return -1;
} }
#endif #endif
void uh_ssl_ctx_free(struct uh_server *srv) void uh_ssl_ctx_free(struct uh_server *srv)
{ {
#if (UHTTP_SSL_ENABLED) #if (UHTTP_SSL_ENABLED)
if (!srv->ssl_ctx) if (!srv->ssl_ctx)
return; return;
SSL_CTX_free(srv->ssl_ctx); SSL_CTX_free(srv->ssl_ctx);
#endif #endif
} }
void uh_ssl_free(struct uh_connection *con) void uh_ssl_free(struct uh_connection *con)
{ {
#if (UHTTP_SSL_ENABLED) #if (UHTTP_SSL_ENABLED)
if (!con->ssl) if (!con->ssl)
return; return;
SSL_shutdown(con->ssl); SSL_shutdown(con->ssl);
SSL_free(con->ssl); SSL_free(con->ssl);
#endif #endif
} }
#if (UHTTP_SSL_ENABLED) #if (UHTTP_SSL_ENABLED)
static int uh_ssl_err(struct uh_connection *con, int ret, const char *fun) static int uh_ssl_err(struct uh_connection *con, int ret, const char *fun)
{ {
int err; int err;
err = SSL_get_error(con->ssl, ret); err = SSL_get_error(con->ssl, ret);
if (err == SSL_ERROR_ZERO_RETURN || ERR_peek_error()) { if (err == SSL_ERROR_ZERO_RETURN || ERR_peek_error()) {
con->flags |= UH_CON_CLOSE; con->flags |= UH_CON_CLOSE;
return 0; return 0;
} }
#if (UHTTP_USE_OPENSSL) #if (UHTTP_USE_OPENSSL)
if (ret == 0) { if (ret == 0) {
con->flags |= UH_CON_CLOSE; con->flags |= UH_CON_CLOSE;
return 0; return 0;
} }
#endif #endif
if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE)
return -1; return -1;
if (err == SSL_ERROR_SYSCALL) { if (err == SSL_ERROR_SYSCALL) {
if (errno > 0) if (errno > 0)
uh_log_err("%s", fun); uh_log_err("%s", fun);
con->flags |= UH_CON_CLOSE; con->flags |= UH_CON_CLOSE;
return -1; return -1;
} }
con->flags |= UH_CON_CLOSE; con->flags |= UH_CON_CLOSE;
uh_log_err("%s() Error: %s", fun, ERR_reason_error_string(err)); uh_log_err("%s() Error: %s", fun, ERR_reason_error_string(err));
return -1; return -1;
} }
#endif #endif
int uh_ssl_read(struct uh_connection *con, void *buf, int count) int uh_ssl_read(struct uh_connection *con, void *buf, int count)
{ {
int ret = -1; int ret = -1;
#if (UHTTP_SSL_ENABLED) #if (UHTTP_SSL_ENABLED)
if (!con->ssl) if (!con->ssl)
goto no_ssl; goto no_ssl;
ret = SSL_read(con->ssl, buf, count); ret = SSL_read(con->ssl, buf, count);
if (ret > 0) if (ret > 0)
return ret; return ret;
return uh_ssl_err(con, ret, "SSL_read"); return uh_ssl_err(con, ret, "SSL_read");
no_ssl: no_ssl:
#endif #endif
ret = read(con->sock, buf, count); ret = read(con->sock, buf, count);
if (ret <= 0) { if (ret <= 0) {
if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK) if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)
return ret; return ret;
if (ret != 0) { if (ret != 0) {
con->flags |= UH_CON_CLOSE; con->flags |= UH_CON_CLOSE;
uh_log_err("read"); uh_log_err("read");
} }
} }
return ret; return ret;
} }
int uh_ssl_write(struct uh_connection *con, void *buf, int count) int uh_ssl_write(struct uh_connection *con, void *buf, int count)
{ {
int ret = -1; int ret = -1;
#if (UHTTP_SSL_ENABLED) #if (UHTTP_SSL_ENABLED)
if (!con->ssl) if (!con->ssl)
goto no_ssl; goto no_ssl;
ret = SSL_write(con->ssl, buf, count); ret = SSL_write(con->ssl, buf, count);
if (ret > 0) if (ret > 0)
return ret; return ret;
return uh_ssl_err(con, ret, "SSL_write"); return uh_ssl_err(con, ret, "SSL_write");
no_ssl: no_ssl:
#endif #endif
ret = write(con->sock, buf, count); ret = write(con->sock, buf, count);
if (ret <= 0) { if (ret <= 0) {
if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK) if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)
return ret; return ret;
if (ret != 0) { if (ret != 0) {
con->flags |= UH_CON_CLOSE; con->flags |= UH_CON_CLOSE;
uh_log_err("write"); uh_log_err("write");
} }
} }
return ret; return ret;
} }
int uh_ssl_accept(struct uh_connection *con) int uh_ssl_accept(struct uh_connection *con)
{ {
int sock = -1; int sock = -1;
struct uh_server *srv = con->srv; struct uh_server *srv = con->srv;
sock = accept4(srv->sock, NULL, NULL, SOCK_NONBLOCK | SOCK_CLOEXEC); sock = accept4(srv->sock, NULL, NULL, SOCK_NONBLOCK | SOCK_CLOEXEC);
if (unlikely(sock < 0)) { if (unlikely(sock < 0)) {
if (errno != EINTR && errno != EAGAIN && errno != EWOULDBLOCK) if (errno != EINTR && errno != EAGAIN && errno != EWOULDBLOCK)
uh_log_err("accept4"); uh_log_err("accept4");
return -1; return -1;
} }
con->sock = sock; con->sock = sock;
#if (UHTTP_SSL_ENABLED) #if (UHTTP_SSL_ENABLED)
if (!srv->ssl_ctx) if (!srv->ssl_ctx)
return sock; return sock;
con->ssl = SSL_new(srv->ssl_ctx); con->ssl = SSL_new(srv->ssl_ctx);
if (!con->ssl) if (!con->ssl)
return -1; return -1;
if (!SSL_set_fd(con->ssl, sock)) { if (!SSL_set_fd(con->ssl, sock)) {
uh_log_err("SSL_set_fd() failed"); uh_log_err("SSL_set_fd() failed");
return -1; return -1;
} }
SSL_set_accept_state(con->ssl); SSL_set_accept_state(con->ssl);
#endif #endif
return sock; return sock;
} }
void uh_ssl_handshake(struct uh_connection *con) void uh_ssl_handshake(struct uh_connection *con)
{ {
#if (UHTTP_SSL_ENABLED) #if (UHTTP_SSL_ENABLED)
int ret = SSL_accept(con->ssl); int ret = SSL_accept(con->ssl);
if (ret == 1) { if (ret == 1) {
con->flags |= UH_CON_SSL_HANDSHAKE_DONE; con->flags |= UH_CON_SSL_HANDSHAKE_DONE;
return; return;
} }
uh_ssl_err(con, ret, "SSL_accept"); uh_ssl_err(con, ret, "SSL_accept");
#endif #endif
} }

View File

@ -8,7 +8,7 @@
#include <openssl/err.h> #include <openssl/err.h>
#ifndef SSL_SUCCESS #ifndef SSL_SUCCESS
#define SSL_SUCCESS 1 #define SSL_SUCCESS 1
#endif #endif
#elif (UHTTP_USE_CYASSL) #elif (UHTTP_USE_CYASSL)