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)
{
printf("Got signal: %d\n", w->signum);
ev_break(loop, EVBREAK_ALL);
printf("Got signal: %d\n", w->signum);
ev_break(loop, EVBREAK_ALL);
}
void route_test(struct uh_connection *con)
{
struct uh_value *url = uh_get_url(con);
struct uh_value *header_host = uh_get_header(con, "Host");
struct uh_value *header_ua = uh_get_header(con, "User-Agent");
struct uh_value *url = uh_get_url(con);
struct uh_value *header_host = uh_get_header(con, "Host");
struct uh_value *header_ua = uh_get_header(con, "User-Agent");
uh_send_head(con, UH_STATUS_OK, -1, NULL);
uh_printf_chunk(con, "<h1>Hello World</h1>");
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_send_head(con, UH_STATUS_OK, -1, NULL);
uh_printf_chunk(con, "<h1>Hello World</h1>");
uh_printf_chunk(con, "<h1>Libuhttp v%s</h1>", uh_version());
uh_printf_chunk(con, "<h1>Url: %.*s</h1>", (int)url->len, url->at);
if (header_host)
uh_printf_chunk(con, "<h1>Host: %.*s</h1>", (int)header_host->len, header_host->at);
if (header_host)
uh_printf_chunk(con, "<h1>Host: %.*s</h1>", (int)header_host->len, header_host->at);
if (header_ua)
uh_printf_chunk(con, "<h1>User-Agent: %.*s</h1>", (int)header_ua->len, header_ua->at);
if (header_ua)
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)
{
struct ev_loop *loop = EV_DEFAULT;
ev_signal *sig_watcher = NULL;
struct uh_server *srv = NULL;
struct ev_loop *loop = EV_DEFAULT;
ev_signal *sig_watcher = 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));
if (!sig_watcher)
return -1;
sig_watcher = calloc(1, sizeof(ev_signal));
if (!sig_watcher)
return -1;
ev_signal_init(sig_watcher, signal_cb, SIGINT);
ev_signal_start(loop, sig_watcher);
ev_signal_init(sig_watcher, signal_cb, SIGINT);
ev_signal_start(loop, sig_watcher);
srv = uh_server_new(loop, "0.0.0.0", 8000);
if (!srv) {
uh_log_err("uh_server_new failed\n");
goto err;
}
srv = uh_server_new(loop, "0.0.0.0", 8000);
if (!srv) {
uh_log_err("uh_server_new failed\n");
goto err;
}
#if (UHTTP_SSL_ENABLED)
if (uh_ssl_init(srv, "server-cert.pem", "server-key.pem") < 0)
goto err;
if (uh_ssl_init(srv, "server-cert.pem", "server-key.pem") < 0)
goto err;
#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:
free(sig_watcher);
uh_server_free(srv);
free(sig_watcher);
uh_server_free(srv);
return 0;
return 0;
}

View File

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

View File

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

View File

@ -5,64 +5,64 @@
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) {
free(buf->base);
buf->base = NULL;
}
if (buf->base) {
free(buf->base);
buf->base = NULL;
}
if (initial_size > 0) {
buf->base = malloc(initial_size);
if (!buf->base)
return -1;
buf->size = initial_size;
}
if (initial_size > 0) {
buf->base = malloc(initial_size);
if (!buf->base)
return -1;
buf->size = initial_size;
}
return 0;
return 0;
}
int uh_buf_grow(struct uh_buf *buf, size_t size)
{
void *base = realloc(buf->base, buf->size + size);
if (!base)
return -1;
void *base = realloc(buf->base, buf->size + size);
if (!base)
return -1;
buf->base = base;
buf->size += size;
buf->base = base;
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)
{
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)
{
assert(buf);
assert(buf);
if (!data)
return 0;
if (!data)
return 0;
if (buf->len + len > buf->size) {
if (uh_buf_grow(buf, len * UH_BUF_SIZE_MULTIPLIER) == -1)
len = buf->size - buf->len;
}
if (buf->len + len > buf->size) {
if (uh_buf_grow(buf, len * UH_BUF_SIZE_MULTIPLIER) == -1)
len = buf->size - buf->len;
}
memcpy(buf->base + buf->len, data, len);
buf->len += len;
memcpy(buf->base + buf->len, data, len);
buf->len += len;
return len;
return len;
}
void uh_buf_remove(struct uh_buf *buf, size_t n)
{
if (n > 0 && n <= buf->len) {
memmove(buf->base, buf->base + n, buf->len - n);
buf->len -= n;
}
if (n > 0 && n <= buf->len) {
memmove(buf->base, buf->base + n, buf->len - n);
buf->len -= n;
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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