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:
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);
}