From 2f6a92168ef33bd9485400b95e11e2dd8ee384e7 Mon Sep 17 00:00:00 2001 From: Cory McWilliams Date: Sat, 30 Dec 2023 16:52:05 +0000 Subject: [PATCH] Implement connection activity timeouts. git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4706 ed5197a5-7fde-0310-b194-c3ffbd925b24 --- src/http.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 61 insertions(+), 8 deletions(-) diff --git a/src/http.c b/src/http.c index 91b84d3b..15683660 100644 --- a/src/http.c +++ b/src/http.c @@ -16,11 +16,14 @@ #include #endif +static const int k_timeout_ms = 60000; + typedef struct _tf_http_connection_t { tf_http_t* http; uv_tcp_t tcp; uv_shutdown_t shutdown; + uv_timer_t timeout; int ref_count; @@ -77,6 +80,7 @@ typedef struct _tf_http_t static const char* _http_connection_get_header(const tf_http_connection_t* connection, const char* name); static void _http_connection_destroy(tf_http_connection_t* connection, const char* reason); static const char* _http_status_text(int status); +static void _http_timer_reset(tf_http_connection_t* connection); tf_http_t* tf_http_create(uv_loop_t* loop) { @@ -119,6 +123,7 @@ bool _http_find_handler(tf_http_t* http, const char* path, tf_http_callback_t** static void _http_on_write(uv_write_t* write, int status) { + _http_timer_reset(write->data); tf_free(write); } @@ -131,11 +136,19 @@ static void _http_connection_on_close(uv_handle_t* handle) static void _http_connection_destroy(tf_http_connection_t* connection, const char* reason) { - if (connection->tcp.data) + if (connection->tcp.data && !uv_is_closing((uv_handle_t*)&connection->tcp)) { uv_close((uv_handle_t*)&connection->tcp, _http_connection_on_close); } - else if (connection->ref_count == 0) + if (connection->timeout.data && !uv_is_closing((uv_handle_t*)&connection->timeout)) + { + uv_close((uv_handle_t*)&connection->timeout, _http_connection_on_close); + } + + if (connection->ref_count == 0 && + !connection->tcp.data && + !connection->shutdown.data && + !connection->timeout.data) { tf_http_t* http = connection->http; for (int i = 0; i < http->connections_count; i++) @@ -298,6 +311,7 @@ static void _http_add_body_bytes(tf_http_connection_t* connection, const void* d static void _http_on_read(uv_stream_t* stream, ssize_t read_size, const uv_buf_t* buffer) { tf_http_connection_t* connection = stream->data; + _http_timer_reset(connection); if (read_size > 0) { if (!connection->headers_done) @@ -389,6 +403,29 @@ static void _http_on_read(uv_stream_t* stream, ssize_t read_size, const uv_buf_t } } +static void _http_timer_callback(uv_timer_t* timer) +{ + tf_printf("_http_timer_callback\n"); + _http_connection_destroy(timer->data, "_http_timer_callback"); +} + +static void _http_timer_reset(tf_http_connection_t* connection) +{ + if (connection->timeout.data) + { + int r = uv_timer_stop(&connection->timeout); + if (r) + { + tf_printf("uv_timer_stop: %s\n", uv_strerror(r)); + } + r = uv_timer_start(&connection->timeout, _http_timer_callback, k_timeout_ms, 0); + if (r) + { + tf_printf("uv_timer_start: %s\n", uv_strerror(r)); + } + } +} + static void _http_on_connection(uv_stream_t* stream, int status) { tf_http_t* http = stream->data; @@ -398,7 +435,23 @@ static void _http_on_connection(uv_stream_t* stream, int status) if (r) { tf_printf("uv_tcp_init: %s\n", uv_strerror(r)); - tf_free(connection); + _http_connection_destroy(connection, "uv_tcp_init"); + return; + } + + r = uv_timer_init(connection->http->loop, &connection->timeout); + connection->timeout.data = connection; + if (r) + { + tf_printf("uv_timer_init: %s\n", uv_strerror(r)); + _http_connection_destroy(connection, "uv_timer_init"); + return; + } + r = uv_timer_start(&connection->timeout, _http_timer_callback, k_timeout_ms, 0); + if (r) + { + tf_printf("uv_timer_start: %s\n", uv_strerror(r)); + _http_connection_destroy(connection, "uv_timer_start"); return; } @@ -406,17 +459,15 @@ static void _http_on_connection(uv_stream_t* stream, int status) if (r) { tf_printf("uv_accept: %s\n", uv_strerror(r)); - uv_close((uv_handle_t*)&connection->tcp, NULL); - tf_free(connection); + _http_connection_destroy(connection, "uv_accept"); return; } r = uv_read_start((uv_stream_t*)&connection->tcp, _http_allocate_buffer, _http_on_read); if (r) { - tf_printf("uv_read-start: %s\n", uv_strerror(r)); - uv_close((uv_handle_t*)&connection->tcp, NULL); - tf_free(connection); + tf_printf("uv_read_start: %s\n", uv_strerror(r)); + _http_connection_destroy(connection, "uv_read_start"); return; } @@ -533,6 +584,7 @@ static void _http_on_shutdown(uv_shutdown_t* request, int status) static void _http_write(tf_http_connection_t* connection, const void* data, size_t size) { + _http_timer_reset(connection); uv_write_t* write = tf_malloc(sizeof(uv_write_t) + size); *write = (uv_write_t) { .data = connection }; memcpy(write + 1, data, size); @@ -599,6 +651,7 @@ void tf_http_respond(tf_http_request_t* request, int status, const char** header { memcpy(buffer + offset, body, content_length); } + _http_timer_reset(request->connection); int r = uv_write(write, (uv_stream_t*)&request->connection->tcp, &(uv_buf_t) { .base = buffer, .len = headers_length + content_length }, 1, _http_on_write); if (r) {