#include #include "http.h" #include "http_loop.h" #include "log.h" bool http_loop_handle_request(event_loop_conn *conn) { // Prevents the request handler function from looping indefinitely without // ever consuming new data if (conn->rbuf_size - conn->rbuf_read == 0) { return false; } http_loop_ctx *ctx = conn->ctx; // If route is defined, we're currently processing a request if (ctx->route == NULL) { http_parse_error res = http_loop_parse_request(conn); 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; } conn->rbuf_read += ctx->req.len; // It's fun to respond with extremely specific error messages // https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/501 if (res == http_parse_error_unknown_method) { ctx->res.type = http_method_not_implemented; conn->state = event_loop_conn_state_res; } else { http_loop_route_request(conn); } } if (conn->state == event_loop_conn_state_req) { 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; } event_loop *http_loop_init(http_loop_gctx *gctx) { event_loop *el = event_loop_init(); el->ctx_init = (void *(*)(void *))http_loop_ctx_init; el->ctx_free = (void (*)(void *))http_loop_ctx_free; el->handle_data = http_loop_handle_request; el->write_data = http_loop_write_response; el->gctx = gctx; return el; } void http_loop_run(event_loop *el, int port) { debug("Compiling RegEx routes"); http_loop_gctx *gctx = el->gctx; http_route *route; for (size_t i = 0; i < gctx->route_count; i++) { route = &gctx->routes[i]; if (route->type == http_route_regex) { regex_t *r = calloc(sizeof(regex_t), 1); if (regcomp(r, route->path, 0) != 0) { critical(1, "RegEx expression '%s' failed to compile", route->path); } route->regex = r; } } debug("RegEx routes compiled successfully"); event_loop_run(el, port); }