Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
307 changes: 159 additions & 148 deletions httpserver.h

Large diffs are not rendered by default.

28 changes: 15 additions & 13 deletions src/api.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ http_string_t http_request_header(http_request_t *request, char const *key) {
}

void http_request_connection(http_request_t *request, int directive) {
hs_request_connection(request, directive);
hs_request_set_keep_alive_flag(request, directive);
}

http_string_t http_request_chunk(struct http_request_s *request) {
Expand All @@ -64,30 +64,30 @@ http_response_t *http_response_init() { return hs_response_init(); }

void http_response_header(http_response_t *response, char const *key,
char const *value) {
return hs_response_header(response, key, value);
return hs_response_set_header(response, key, value);
}

void http_response_status(http_response_t *response, int status) {
hs_response_status(response, status);
hs_response_set_status(response, status);
}

void http_response_body(http_response_t *response, char const *body,
int length) {
hs_response_body(response, body, length);
hs_response_set_body(response, body, length);
}

void http_respond(http_request_t *request, http_response_t *response) {
hs_respond(request, response, hs_begin_write);
hs_request_respond(request, response, hs_request_begin_write);
}

void http_respond_chunk(http_request_t *request, http_response_t *response,
void (*cb)(http_request_t *)) {
hs_respond_chunk(request, response, cb, hs_begin_write);
hs_request_respond_chunk(request, response, cb, hs_request_begin_write);
}

void http_respond_chunk_end(http_request_t *request,
http_response_t *response) {
hs_respond_chunk_end(request, response, hs_begin_write);
hs_request_respond_chunk_end(request, response, hs_request_begin_write);
}

http_string_t http_request_method(http_request_t *request) {
Expand All @@ -103,28 +103,30 @@ http_string_t http_request_body(http_request_t *request) {
}

int http_server_listen(http_server_t *serv) {
return hs_listen_loop(serv, NULL);
return hs_server_run_event_loop(serv, NULL);
}

int http_server_listen_addr(http_server_t *serv, const char *ipaddr) {
return hs_listen_loop(serv, ipaddr);
return hs_server_run_event_loop(serv, ipaddr);
}

int http_server_poll(http_server_t *serv) { return hs_poll(serv); }
int http_server_poll(http_server_t *serv) {
return hs_server_poll_events(serv);
}

int http_server_listen_poll(http_server_t *serv) {
hs_listen_addr(serv, NULL);
hs_server_listen_on_addr(serv, NULL);
return 0;
}

int http_server_listen_addr_poll(http_server_t *serv, const char *ipaddr) {
hs_listen_addr(serv, ipaddr);
hs_server_listen_on_addr(serv, ipaddr);
return 0;
}

void http_request_read_chunk(struct http_request_s *request,
void (*chunk_cb)(struct http_request_s *)) {
request->state = HTTP_SESSION_READ;
request->chunk_cb = chunk_cb;
hs_begin_read(request);
hs_request_begin_read(request);
}
45 changes: 23 additions & 22 deletions src/connection.c
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ void _hs_add_timer_event(http_request_t *request, hs_io_cb_t timer_cb) {

#endif

void hs_terminate_connection(http_request_t *request) {
void hs_request_terminate_connection(http_request_t *request) {
_hs_delete_events(request);
close(request->socket);
_hs_buffer_free(&request->buffer, &request->server->memused);
Expand All @@ -84,35 +84,36 @@ void _hs_token_array_init(struct hs_token_array_s *array, int capacity) {
array->capacity = capacity;
}

void _hs_init_connection(http_request_t *connection) {
connection->flags = HTTP_AUTOMATIC;
connection->parser = (struct hsh_parser_s){};
connection->buffer = (struct hsh_buffer_s){};
if (connection->tokens.buf) {
free(connection->tokens.buf);
connection->tokens.buf = NULL;
}
_hs_token_array_init(&connection->tokens, 32);
http_request_t *_hs_request_init(int sock, http_server_t *server,
hs_io_cb_t io_cb) {
http_request_t *request = (http_request_t *)calloc(1, sizeof(http_request_t));
assert(request != NULL);
request->socket = sock;
request->server = server;
request->handler = io_cb;
request->timeout = HTTP_REQUEST_TIMEOUT;
request->flags = HTTP_AUTOMATIC;
request->parser = (struct hsh_parser_s){};
request->buffer = (struct hsh_buffer_s){};
request->tokens.buf = NULL;
_hs_token_array_init(&request->tokens, 32);
return request;
}

http_request_t *hs_accept_connection(http_server_t *server, hs_io_cb_t io_cb,
hs_io_cb_t epoll_timer_cb) {
http_request_t *connection = NULL;
http_request_t *hs_server_accept_connection(http_server_t *server,
hs_io_cb_t io_cb,
hs_io_cb_t epoll_timer_cb) {
http_request_t *request = NULL;
int sock = 0;

sock = accept(server->socket, (struct sockaddr *)&server->addr, &server->len);

if (sock > 0) {
connection = (http_request_t *)calloc(1, sizeof(http_request_t));
assert(connection != NULL);
connection->socket = sock;
connection->server = server;
connection->timeout = HTTP_REQUEST_TIMEOUT;
connection->handler = io_cb;
int flags = fcntl(sock, F_GETFL, 0);
fcntl(sock, F_SETFL, flags | O_NONBLOCK);
_hs_add_timer_event(connection, epoll_timer_cb);
_hs_init_connection(connection);

request = _hs_request_init(sock, server, io_cb);
_hs_add_timer_event(request, epoll_timer_cb);
}
return connection;
return request;
}
8 changes: 4 additions & 4 deletions src/connection.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ typedef void (*hs_io_cb_t)(struct epoll_event *ev);
*
* @param request The request to close
*/
void hs_terminate_connection(struct http_request_s *request);
void hs_request_terminate_connection(struct http_request_s *request);

/* Accepts connections on the server socket in a loop until it would block.
*
Expand All @@ -40,8 +40,8 @@ void hs_terminate_connection(struct http_request_s *request);
* @param max_mem_usage The limit at which err_responder should be called
* instead of regular operation.
*/
struct http_request_s *hs_accept_connection(struct http_server_s *server,
hs_io_cb_t io_cb,
hs_io_cb_t epoll_timer_cb);
struct http_request_s *hs_server_accept_connection(struct http_server_s *server,
hs_io_cb_t io_cb,
hs_io_cb_t epoll_timer_cb);

#endif
43 changes: 29 additions & 14 deletions src/io_events.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#endif

#ifndef HTTPSERVER_IMPL
#include "buffer_util.h"
#include "common.h"
#include "connection.h"
#include "io_events.h"
Expand All @@ -27,31 +28,44 @@ void _hs_read_socket_and_handle_return_code(http_request_t *request) {
enum hs_read_rc_e rc = hs_read_request_and_exec_user_cb(request, opts);
switch (rc) {
case HS_READ_RC_PARSE_ERR:
hs_respond_error(request, 400, "Bad Request", hs_begin_write);
hs_request_respond_error(request, 400, "Bad Request",
hs_request_begin_write);
break;
case HS_READ_RC_SOCKET_ERR:
hs_terminate_connection(request);
hs_request_terminate_connection(request);
break;
case HS_READ_RC_SUCCESS:
break;
}
}

void hs_begin_read(http_request_t *request);
void hs_request_begin_read(http_request_t *request);

void _hs_write_socket_and_handle_return_code(http_request_t *request) {
enum hs_write_rc_e rc = hs_write_socket(request);

request->timeout = rc == HS_WRITE_RC_SUCCESS ? HTTP_KEEP_ALIVE_TIMEOUT
: HTTP_REQUEST_TIMEOUT;

if (rc != HS_WRITE_RC_CONTINUE)
_hs_buffer_free(&request->buffer, &request->server->memused);

switch (rc) {
case HS_WRITE_RC_SUCCESS_CLOSE:
case HS_WRITE_RC_SOCKET_ERR:
// Error or response complete, connection: close
hs_terminate_connection(request);
hs_request_terminate_connection(request);
break;
case HS_WRITE_RC_SUCCESS:
// Response complete, keep-alive connection
hs_begin_read(request);
hs_request_begin_read(request);
break;
case HS_WRITE_RC_SUCCESS_CHUNK:
// Finished writing chunk, request next
request->state = HTTP_SESSION_NOP;
request->chunk_cb(request);
break;
default:
case HS_WRITE_RC_CONTINUE:
break;
}
}
Expand All @@ -60,12 +74,13 @@ void _hs_accept_and_begin_request_cycle(http_server_t *server,
hs_io_cb_t on_client_connection_cb,
hs_io_cb_t on_timer_event_cb) {
http_request_t *request = NULL;
while ((request = hs_accept_connection(server, on_client_connection_cb,
on_timer_event_cb))) {
while ((request = hs_server_accept_connection(server, on_client_connection_cb,
on_timer_event_cb))) {
if (server->memused > HTTP_MAX_TOTAL_EST_MEM_USAGE) {
hs_respond_error(request, 503, "Service Unavailable", hs_begin_write);
hs_request_respond_error(request, 503, "Service Unavailable",
hs_request_begin_write);
} else {
hs_begin_read(request);
hs_request_begin_read(request);
}
}
}
Expand All @@ -77,7 +92,7 @@ void _hs_on_kqueue_client_connection_event(struct kevent *ev) {
if (ev->filter == EVFILT_TIMER) {
request->timeout -= 1;
if (request->timeout == 0)
hs_terminate_connection(request);
hs_request_terminate_connection(request);
} else {
if (request->state == HTTP_SESSION_READ) {
_hs_read_socket_and_handle_return_code(request);
Expand Down Expand Up @@ -116,7 +131,7 @@ void _hs_on_epoll_request_timer_event(struct epoll_event *ev) {
(void)bytes; // suppress warning
request->timeout -= 1;
if (request->timeout == 0)
hs_terminate_connection(request);
hs_request_terminate_connection(request);
}

void hs_on_epoll_server_connection_event(struct epoll_event *ev) {
Expand Down Expand Up @@ -151,7 +166,7 @@ void _hs_add_write_event(http_request_t *request) {
#endif
}

void hs_begin_write(http_request_t *request) {
void hs_request_begin_write(http_request_t *request) {
request->state = HTTP_SESSION_WRITE;
_hs_add_write_event(request);
_hs_write_socket_and_handle_return_code(request);
Expand All @@ -173,7 +188,7 @@ void _hs_add_read_event(http_request_t *request) {
#endif
}

void hs_begin_read(http_request_t *request) {
void hs_request_begin_read(http_request_t *request) {
request->state = HTTP_SESSION_READ;
_hs_add_read_event(request);
_hs_read_socket_and_handle_return_code(request);
Expand Down
4 changes: 2 additions & 2 deletions src/io_events.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@

struct http_request_s;

void hs_begin_write(struct http_request_s *request);
void hs_begin_read(struct http_request_s *request);
void hs_request_begin_write(struct http_request_s *request);
void hs_request_begin_read(struct http_request_s *request);

#ifdef KQUEUE

Expand Down
23 changes: 13 additions & 10 deletions src/request_util.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ http_string_t hs_request_header(http_request_t *request, char const *key) {
return (http_string_t){};
}

void hs_auto_detect_keep_alive(http_request_t *request) {
void hs_request_detect_keep_alive_flag(http_request_t *request) {
http_string_t str = hs_get_token_string(request, HSH_TOK_VERSION);
if (str.buf == NULL)
return;
Expand All @@ -62,15 +62,14 @@ void hs_auto_detect_keep_alive(http_request_t *request) {
}
}

int _hs_assign_iteration_headers(http_request_t *request, http_string_t *key,
http_string_t *val, int *iter) {
struct hsh_token_s token = request->tokens.buf[*iter];
if (request->tokens.buf[*iter].type == HSH_TOK_HEADERS_DONE)
int _hs_get_header_key_val(http_request_t *request, http_string_t *key,
http_string_t *val, int iter) {
struct hsh_token_s token = request->tokens.buf[iter];
if (request->tokens.buf[iter].type == HSH_TOK_HEADERS_DONE)
return 0;
*key = (http_string_t){.buf = &request->buffer.buf[token.index],
.len = token.len};
(*iter)++;
token = request->tokens.buf[*iter];
token = request->tokens.buf[iter + 1];
*val = (http_string_t){.buf = &request->buffer.buf[token.index],
.len = token.len};
return 1;
Expand All @@ -82,17 +81,21 @@ int hs_request_iterate_headers(http_request_t *request, http_string_t *key,
for (; *iter < request->tokens.size; (*iter)++) {
struct hsh_token_s token = request->tokens.buf[*iter];
if (token.type == HSH_TOK_HEADER_KEY) {
return _hs_assign_iteration_headers(request, key, val, iter);
int more = _hs_get_header_key_val(request, key, val, *iter);
(*iter)++;
return more;
}
}
return 0;
} else {
(*iter)++;
return _hs_assign_iteration_headers(request, key, val, iter);
int more = _hs_get_header_key_val(request, key, val, *iter);
(*iter)++;
return more;
}
}

void hs_request_connection(http_request_t *request, int directive) {
void hs_request_set_keep_alive_flag(http_request_t *request, int directive) {
if (directive == HTTP_KEEP_ALIVE) {
HTTP_FLAG_CLEAR(request->flags, HTTP_AUTOMATIC);
HTTP_FLAG_SET(request->flags, HTTP_KEEP_ALIVE);
Expand Down
6 changes: 4 additions & 2 deletions src/request_util.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
#ifndef HS_REQUEST_UTIL_H
#define HS_REQUEST_UTIL_H

#ifndef HTTPSERVER_IMPL
#include "common.h"
#endif

// http version indicators
#define HTTP_1_0 0
Expand All @@ -17,10 +19,10 @@ typedef struct http_string_s http_string_t;
http_string_t hs_get_token_string(http_request_t *request,
enum hsh_token_e token_type);
http_string_t hs_request_header(http_request_t *request, char const *key);
void hs_auto_detect_keep_alive(http_request_t *request);
void hs_request_detect_keep_alive_flag(http_request_t *request);
int hs_request_iterate_headers(http_request_t *request, http_string_t *key,
http_string_t *val, int *iter);
void hs_request_connection(http_request_t *request, int directive);
void hs_request_set_keep_alive_flag(http_request_t *request, int directive);
http_string_t hs_request_chunk(struct http_request_s *request);

#endif
Loading