diff --git a/include/http.h b/include/http.h index 4d38f07..dbd7f0a 100644 --- a/include/http.h +++ b/include/http.h @@ -5,8 +5,6 @@ #include "picohttpparser.h" -#include "event_loop.h" - #define HTTP_MAX_ALLOWED_HEADERS 8 extern const char http_404[]; @@ -17,6 +15,7 @@ extern const char http_500[]; extern const size_t http_500_len; extern const char http_501[]; extern const size_t http_501_len; +extern const char *http_response_type_names[5][32]; typedef enum http_request_method { http_request_method_get = 0, @@ -53,12 +52,70 @@ typedef enum http_parse_error { /* void http_route(event_loop_conn *conn); */ typedef enum http_response_type { + // 1xx + http_continue = 100, + http_switching_protocols = 101, + http_processing = 102, + http_early_hints = 103, + // 2xx + http_ok = 200, + http_created = 201, + http_accepted = 202, + http_non_authoritative_information = 203, + http_no_content = 204, + http_reset_content = 205, + http_partial_content = 206, + http_multi_status = 207, + http_already_reported = 208, + // 3xx + http_multiple_choices = 300, + http_moved_permanently = 301, + http_found = 302, + http_see_other = 303, + http_not_modified = 304, + http_temporary_redirect = 307, + http_permanent_redirect = 308, + // 4xx + http_bad_request = 400, + http_unauthorized = 401, + http_payment_required = 402, + http_forbidden = 403, http_not_found = 404, http_method_not_allowed = 405, - http_method_not_implemented = 501 + http_not_acceptable = 406, + http_proxy_authentication_required = 407, + http_request_timeout = 408, + http_conflict = 409, + http_gone = 410, + http_length_required = 411, + http_precondition_failed = 412, + http_content_too_large = 413, + http_uri_too_long = 414, + http_unsupported_media_type = 415, + http_range_not_satisfiable = 416, + http_expection_failed = 417, + http_im_a_teapot = 418, + http_misdirected_request = 421, + http_unprocessable_content = 422, + http_locked = 423, + http_failed_dependency = 424, + http_too_early = 425, + http_upgrade_required = 426, + http_precondition_required = 428, + http_too_many_requests = 429, + http_request_header_fields_too_large = 431, + // 5xx + http_internal_server_error = 500, + http_method_not_implemented = 501, + http_bad_gateway = 502, + http_service_unavailable = 503, + http_gateway_timeout = 504, + http_http_version_not_supported = 505, + http_variant_also_negotiates = 506, + http_insufficient_storage = 507, + http_loop_detected = 508, + http_not_extended = 510, + http_network_authentication_required = 511 } http_response_type; -void http_write_standard_response(event_loop_conn *conn, - http_response_type type); - #endif diff --git a/include/http_loop.h b/include/http_loop.h index 4faa876..7e5b10b 100644 --- a/include/http_loop.h +++ b/include/http_loop.h @@ -64,6 +64,9 @@ bool http_loop_route_request(event_loop_conn *conn); void http_loop_process_request(event_loop_conn *conn); +void http_loop_write_standard_response(event_loop_conn *conn, + http_response_type type); + /** * Initialize a new http loop */ diff --git a/src/http/http_res_names.c b/src/http/http_res_names.c new file mode 100644 index 0000000..028e217 --- /dev/null +++ b/src/http/http_res_names.c @@ -0,0 +1,88 @@ +#include "http.h" + +// clang-format off + +const char *http_response_type_names[5][32] = { + { + "Continue", // 100 + "Switching Protocols", // 101, + "Processing", // 102 + "Early Hints", // 103 + }, + // 2xx + { + "OK", // 200 + "Created", // 201 + "Accepted", // 202 + "Non-Authoritative Information", // 203 + "No Content", // 204 + "Reset Content", // 205 + "Partial Content", // 206 + "Multi-Status", // 207 + "Already Reported", // 208 + }, + // 3xx + { + "Multiple Choices", // 300 + "Moved Permanently", // 301 + "Found", // 302 + "See Other", // 303 + "Not Modified", // 304 + NULL, // 305 + NULL, // 306 + "Temporary Redirect", // 307 + "Permanent Redirect", // 308 + }, + // 4xx + { + "Bad Request", // 400 + "Unauthorized", // 401 + "Payment Required", // 402 + "Forbidden", // 403 + "Not Found", // 404 + "Method Not Allowed", // 405 + "Not Acceptable", // 406 + "Proxy Authentication Required", // 407 + "Request Timeout", // 408 + "Conflict", // 409 + "Gone", // 410 + "Length Required", // 411 + "Precondition Failed", // 412 + "Content Too Large", // 413 + "URI Too Long", // 414 + "Unsupported Media Type", // 415 + "Range Not Satisfiable", // 416 + "Expectation Failed", // 417 + "I'm a teapot", // 418 + NULL, // 419 + NULL, // 420 + "Misdirected Request", // 421 + "Unprocessable Content", // 422 + "Locked", // 423 + "Failed Dependency", // 424 + "Too Early", // 425 + "Upgrade Required", // 426 + NULL, // 427 + "Precondition Required", // 428 + "Too Many Requests", // 429 + NULL, // 430 + "Request Header Fields Too Large", // 431 + }, + // 5xx + { + "Internal Server Error", // 500 + "Not Implemented", // 501 + "Bad Gateway", // 502 + "Service Unavailable", // 503 + "Gateway Timeout", // 504 + "HTTP Version Not Supported", // 505 + "Variant Also Negotiates", // 506 + "Insufficient Storage", // 507 + "Loop Detected", // 508 + NULL, // 509 + "Not Extended", // 510 + "Network Authentication Required" // 511 + }, +}; + +// clang-format on diff --git a/src/http_loop/http_loop.c b/src/http_loop/http_loop.c index d74cca1..b7a83e8 100644 --- a/src/http_loop/http_loop.c +++ b/src/http_loop/http_loop.c @@ -39,7 +39,7 @@ bool http_loop_handle_request(event_loop_conn *conn) { // It's fun to respond with extremely specific error messages // https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/501 else if (res == http_parse_error_unknown_method) { - http_write_standard_response(conn, 501); + http_loop_write_standard_response(conn, 501); return false; } diff --git a/src/http_loop/http_loop_route.c b/src/http_loop/http_loop_route.c index 5d61ced..fa31a8d 100644 --- a/src/http_loop/http_loop_route.c +++ b/src/http_loop/http_loop_route.c @@ -74,19 +74,18 @@ http_parse_error http_loop_parse_request(event_loop_conn *conn) { void http_loop_process_request(event_loop_conn *conn) { http_loop_ctx *ctx = conn->ctx; - // 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. + // We keep processing step functions as long as they don't need to wait for + // I/O + while ((ctx->route->steps[ctx->current_step] != NULL) && + ctx->route->steps[ctx->current_step](conn)) { + ctx->current_step++; + } + + // If we've reached the end of the list of step functions, we report the + // request as finished by clearing its route if (ctx->route->steps[ctx->current_step] == NULL) { ctx->route = NULL; ctx->current_step = 0; - return; - } - - // 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++; } } @@ -114,7 +113,7 @@ bool http_loop_route_request(event_loop_conn *conn) { } // Fallthrough is to write a 404 - http_write_standard_response(conn, http_not_found); + http_loop_write_standard_response(conn, http_not_found); return false; } diff --git a/src/http_loop/http_loop_util.c b/src/http_loop/http_loop_util.c index 69389c6..4bd25bc 100644 --- a/src/http_loop/http_loop_util.c +++ b/src/http_loop/http_loop_util.c @@ -1,8 +1,8 @@ -#include "http.h" +#include "http_loop.h" #include "string.h" -void http_write_standard_response(event_loop_conn *conn, - http_response_type type) { +void http_loop_write_standard_response(event_loop_conn *conn, + http_response_type type) { const char *s; size_t len;