kore

a fork of the worlds most advanced web framework
Log | Files | Refs | README | LICENSE

commit aa49e181b6269dcd298748bfe7bba0eebb6b9aea
parent a191445f76991637be3e1a09cfbf266e3ffd52a5
Author: Joris Vink <joris@coders.se>
Date:   Thu, 11 Apr 2019 20:51:49 +0200

Add http_[header|body]_timeout.

If the HTTP request headers or the HTTP body have not arrived before
these timeouts expire, Kore will send a 408 back to the client.

Diffstat:
Mconf/kore.conf.example | 9+++++++++
Minclude/kore/http.h | 5+++++
Minclude/kore/kore.h | 2++
Msrc/config.c | 32++++++++++++++++++++++++++++++++
Msrc/connection.c | 11+++++++----
Msrc/http.c | 26+++++++++++++++++++++++++-
6 files changed, 80 insertions(+), 5 deletions(-)

diff --git a/conf/kore.conf.example b/conf/kore.conf.example @@ -108,10 +108,17 @@ workers 4 # HTTP specific settings. # http_header_max Maximum size of HTTP headers (in bytes). # +# http_header_timeout Timeout in seconds for receiving the +# HTTP headers before the connection is closed. +# # http_body_max Maximum size of an HTTP body (in bytes). # If set to 0 disallows requests with a body # all together. # +# http_body_timeout Timeout in seconds for receiving the +# HTTP body in full before the connection +# is closed with an 408. +# # http_body_disk_offload Number of bytes after which Kore will use # a temporary file to hold the HTTP body # instead of holding it in memory. If set to @@ -136,7 +143,9 @@ workers 4 # spend inside the HTTP processing loop. # #http_header_max 4096 +#http_header_timeout 10 #http_body_max 1024000 +#http_body_timeout 60 #http_keepalive_time 0 #http_hsts_enable 31536000 #http_request_limit 1000 diff --git a/include/kore/http.h b/include/kore/http.h @@ -51,6 +51,8 @@ extern "C" { #define HTTP_BODY_DISK_OFFLOAD 0 #define HTTP_BODY_PATH_MAX 256 #define HTTP_BOUNDARY_MAX 80 +#define HTTP_HEADER_TIMEOUT 10 +#define HTTP_BODY_TIMEOUT 60 #define HTTP_ARG_TYPE_RAW 0 #define HTTP_ARG_TYPE_BYTE 1 @@ -279,7 +281,9 @@ struct http_media_type { }; extern size_t http_body_max; +extern u_int16_t http_body_timeout; extern u_int16_t http_header_max; +extern u_int16_t http_header_timeout; extern u_int32_t http_request_ms; extern u_int64_t http_hsts_enable; extern u_int16_t http_keepalive_time; @@ -304,6 +308,7 @@ void http_request_wakeup(struct http_request *); void http_process_request(struct http_request *); int http_body_rewind(struct http_request *); int http_media_register(const char *, const char *); +int http_check_timeout(struct connection *, u_int64_t); ssize_t http_body_read(struct http_request *, void *, size_t); int http_body_digest(struct http_request *, char *, size_t); void http_response(struct http_request *, int, const void *, size_t); diff --git a/include/kore/kore.h b/include/kore/kore.h @@ -243,6 +243,8 @@ struct connection { struct netbuf *rnb; #if !defined(KORE_NO_HTTP) + u_int64_t http_start; + u_int64_t http_timeout; struct kore_runtime_call *ws_connect; struct kore_runtime_call *ws_message; struct kore_runtime_call *ws_disconnect; diff --git a/src/config.c b/src/config.c @@ -91,7 +91,9 @@ static int configure_static_handler(char *); static int configure_dynamic_handler(char *); static int configure_accesslog(char *); static int configure_http_header_max(char *); +static int configure_http_header_timeout(char *); static int configure_http_body_max(char *); +static int configure_http_body_timeout(char *); static int configure_filemap_ext(char *); static int configure_filemap_index(char *); static int configure_http_media_type(char *); @@ -176,7 +178,9 @@ static struct { { "restrict", configure_restrict }, { "http_media_type", configure_http_media_type }, { "http_header_max", configure_http_header_max }, + { "http_header_timeout", configure_http_header_timeout }, { "http_body_max", configure_http_body_max }, + { "http_body_timeout", configure_http_body_timeout }, { "http_hsts_enable", configure_http_hsts_enable }, { "http_keepalive_time", configure_http_keepalive_time }, { "http_request_ms", configure_http_request_ms }, @@ -873,6 +877,20 @@ configure_http_header_max(char *option) } static int +configure_http_header_timeout(char *option) +{ + int err; + + http_header_timeout = kore_strtonum(option, 10, 1, 65535, &err); + if (err != KORE_RESULT_OK) { + printf("bad http_header_timeout value: %s\n", option); + return (KORE_RESULT_ERROR); + } + + return (KORE_RESULT_OK); +} + +static int configure_http_body_max(char *option) { int err; @@ -887,6 +905,20 @@ configure_http_body_max(char *option) } static int +configure_http_body_timeout(char *option) +{ + int err; + + http_body_timeout = kore_strtonum(option, 10, 1, 65535, &err); + if (err != KORE_RESULT_OK) { + printf("bad http_body_timeout value: %s\n", option); + return (KORE_RESULT_ERROR); + } + + return (KORE_RESULT_OK); +} + +static int configure_http_body_disk_offload(char *option) { int err; diff --git a/src/connection.c b/src/connection.c @@ -84,6 +84,8 @@ kore_connection_new(void *owner) c->ws_connect = NULL; c->ws_message = NULL; c->ws_disconnect = NULL; + c->http_start = kore_time_ms(); + c->http_timeout = http_header_timeout * 1000; TAILQ_INIT(&(c->http_requests)); #endif @@ -182,13 +184,14 @@ kore_connection_check_timeout(u_int64_t now) next = TAILQ_NEXT(c, list); if (c->proto == CONN_PROTO_MSG) continue; - if (!(c->flags & CONN_IDLE_TIMER_ACT)) - continue; #if !defined(KORE_NO_HTTP) + if (!http_check_timeout(c, now)) + continue; if (!TAILQ_EMPTY(&c->http_requests)) continue; #endif - kore_connection_check_idletimer(now, c); + if (c->flags & CONN_IDLE_TIMER_ACT) + kore_connection_check_idletimer(now, c); } } @@ -418,7 +421,7 @@ kore_connection_check_idletimer(u_int64_t now, struct connection *c) d = 0; if (d >= c->idle_timer.length) { - kore_debug("%p idle for %" PRIu64 " ms, expiring", c, d); + printf("%p idle for %" PRIu64 " ms, expiring\n", (void *)c, d); kore_connection_disconnect(c); } } diff --git a/src/http.c b/src/http.c @@ -150,13 +150,16 @@ static struct kore_pool http_body_path; u_int32_t http_request_count = 0; u_int32_t http_request_ms = HTTP_REQUEST_MS; +u_int16_t http_body_timeout = HTTP_BODY_TIMEOUT; u_int32_t http_request_limit = HTTP_REQUEST_LIMIT; u_int64_t http_hsts_enable = HTTP_HSTS_ENABLE; u_int16_t http_header_max = HTTP_HEADER_MAX_LEN; u_int16_t http_keepalive_time = HTTP_KEEPALIVE_TIME; +u_int16_t http_header_timeout = HTTP_HEADER_TIMEOUT; + size_t http_body_max = HTTP_BODY_MAX_LEN; -u_int64_t http_body_disk_offload = HTTP_BODY_DISK_OFFLOAD; char *http_body_disk_path = HTTP_BODY_DISK_PATH; +u_int64_t http_body_disk_offload = HTTP_BODY_DISK_OFFLOAD; void http_parent_init(void) @@ -233,6 +236,21 @@ http_server_version(const char *version) http_version_len = l; } +int +http_check_timeout(struct connection *c, u_int64_t now) +{ + if (c->http_timeout == 0) + return (KORE_RESULT_OK); + + if ((now - c->http_start) >= c->http_timeout) { + http_error_response(c, 408); + kore_connection_disconnect(c); + return (KORE_RESULT_ERROR); + } + + return (KORE_RESULT_OK); +} + void http_request_sleep(struct http_request *req) { @@ -834,7 +852,9 @@ http_header_recv(struct netbuf *nb) c->rnb->extra = req; http_request_sleep(req); req->content_length = bytes_left; + c->http_timeout = http_body_timeout * 1000; } else { + c->http_timeout = 0; req->flags |= HTTP_REQUEST_COMPLETE; req->flags &= ~HTTP_REQUEST_EXPECT_BODY; SHA256_Final(req->http_body_digest, &req->hashctx); @@ -844,6 +864,8 @@ http_header_recv(struct netbuf *nb) return (KORE_RESULT_OK); } } + } else { + c->http_timeout = 0; } return (KORE_RESULT_OK); @@ -1919,6 +1941,8 @@ http_response_normal(struct http_request *req, struct connection *c, net_send_queue(c, d, len); if (!(c->flags & CONN_CLOSE_EMPTY)) { + c->http_start = kore_time_ms(); + c->http_timeout = http_header_timeout * 1000; net_recv_reset(c, http_header_max, http_header_recv); (void)net_recv_flush(c); }