diff --git a/include/http_loop.h b/include/http_loop.h index 7b41d4a..5dd0b76 100644 --- a/include/http_loop.h +++ b/include/http_loop.h @@ -16,15 +16,15 @@ typedef struct http_route { http_route_type type; char *path; regex_t *regex; - size_t step_count; - void (**steps)(event_loop_conn *); + bool (*steps[5])(event_loop_conn *); } http_route; /* * Global context passed to every connection using the same pointer */ typedef struct http_loop_gctx { - http_route **routes; + http_route *routes; + size_t route_count; Trie *trie; } http_loop_gctx; @@ -58,6 +58,8 @@ void http_loop_ctx_free(http_loop_ctx *ctx); */ bool http_loop_handle_request(event_loop_conn *conn); +bool http_loop_route_request(event_loop_conn *conn); + void http_loop_process_request(event_loop_conn *conn); /** diff --git a/src/http_loop/http_loop.c b/src/http_loop/http_loop.c index aab5bf2..bb098d4 100644 --- a/src/http_loop/http_loop.c +++ b/src/http_loop/http_loop.c @@ -25,24 +25,28 @@ bool http_loop_handle_request(event_loop_conn *conn) { http_loop_ctx *ctx = conn->ctx; - http_parse_error res = - http_parse_request(&ctx->req, (const char *)&conn->rbuf[conn->rbuf_read], - conn->rbuf_size - conn->rbuf_read); + // If route is defined, we're currently processing a request + if (ctx->route == NULL) { + http_parse_error res = http_parse_request( + &ctx->req, (const char *)&conn->rbuf[conn->rbuf_read], + conn->rbuf_size - conn->rbuf_read); - if (res == http_parse_error_ok) { - // Perform the request - /* http_route(conn); */ - } - // Both in the case of an invalid HTTP request or one that's larger than the - // read buffer, we cannot determine when the next, possibly valid, HTTP - // request begins in the data stream. Therefore, we close the connection, - // even if additional pipelined requests are incoming. - else if (res == http_parse_error_invalid || - (res == http_parse_error_incomplete && - conn->rbuf_size == EVENT_LOOP_BUFFER_SIZE)) { - conn->state = event_loop_conn_state_end; + if (res == http_parse_error_invalid || + (res == http_parse_error_incomplete && + conn->rbuf_size == EVENT_LOOP_BUFFER_SIZE)) { + conn->state = event_loop_conn_state_end; + + return false; + } + + // If the routing fails, we exit the handler + if (!http_loop_route_request(conn)) { + return false; + } } + http_loop_process_request(conn); + // TODO in highly concurrent situations, it might actually be better to always // return false here, as this allows cycling better through all connections return conn->state == event_loop_conn_state_req; diff --git a/src/http_loop/http_loop_route.c b/src/http_loop/http_loop_route.c index a8eb86e..68965c3 100644 --- a/src/http_loop/http_loop_route.c +++ b/src/http_loop/http_loop_route.c @@ -1,13 +1,48 @@ #include -#include "event_loop.h" -#include "http.h" +#include "http_loop.h" -void http_loop_process_request(event_loop_conn *conn) {} +void http_loop_process_request(event_loop_conn *conn) { + http_loop_ctx *ctx = conn->ctx; -/* void http_route(event_loop_conn *conn) { */ -/* // TODO routing */ + // The end of the list of steps is marked with a NULL. When this is reached, + // we simply set the route to NULL, letting the http loop know a new request + // can be handled. + if (ctx->route->steps[ctx->current_step] == NULL) { + ctx->route = NULL; + ctx->current_step = 0; + return; + } -/* // Fallthrough is to return a 404 */ -/* http_write_standard_response(conn, http_not_found); */ -/* } */ + // We execute the next step + // NOTE can/should we execute more than one step at once here? + if (ctx->route->steps[ctx->current_step](conn)) { + ctx->current_step++; + } +} + +bool http_loop_route_request(event_loop_conn *conn) { + http_loop_ctx *ctx = conn->ctx; + http_loop_gctx *gctx = ctx->g; + + http_route *route; + + for (size_t i = 0; i < gctx->route_count; i++) { + route = &gctx->routes[i]; + + switch (route->type) { + case http_route_literal: + if (strncmp(route->path, ctx->req.method, ctx->req.method_len)) { + ctx->route = route; + return true; + } + // TODO + case http_route_regex:; + } + } + + // Fallthrough is to write a 404 + http_write_standard_response(conn, http_not_found); + + return false; +} diff --git a/src/main.c b/src/main.c index c72e604..ee31a15 100644 --- a/src/main.c +++ b/src/main.c @@ -4,17 +4,18 @@ #include "http_loop.h" #include "log.h" -void http_write_404(event_loop_conn *conn) { - memcpy(conn->wbuf, http_404, http_404_len); +bool http_write_404(event_loop_conn *conn) { + memcpy(conn->wbuf, http_405, http_405_len); conn->state = event_loop_conn_state_res; - conn->wbuf_size = http_404_len; + conn->wbuf_size = http_405_len; conn->wbuf_sent = 0; + + return true; } -void (*steps[])(event_loop_conn *) = {http_write_404, NULL}; http_route routes[] = { - {.type = http_route_literal, .path = "/", .step_count = 1, .steps = steps}}; + {.type = http_route_literal, .path = "/", .steps = {http_write_404, NULL}}}; int main() { setvbuf(stdout, NULL, _IONBF, 0); @@ -32,6 +33,8 @@ int main() { http_loop_gctx *gctx = http_loop_gctx_init(); gctx->trie = trie; + gctx->routes = routes; + gctx->route_count = sizeof(routes) / sizeof(routes[0]); event_loop *el = http_loop_init(gctx); event_loop_run(el, 8000);