From 7f0643f9c0c2a30f311dc592a5dadb6d9047550f Mon Sep 17 00:00:00 2001 From: Cory McWilliams Date: Sat, 27 Jan 2024 17:27:56 +0000 Subject: [PATCH] Stop leaking the TLS context. git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4802 ed5197a5-7fde-0310-b194-c3ffbd925b24 --- src/http.c | 22 ++++++++++++++++++---- src/http.h | 2 +- src/httpd.js.c | 22 ++++++++++++++++++---- src/tests.c | 2 +- 4 files changed, 38 insertions(+), 10 deletions(-) diff --git a/src/http.c b/src/http.c index e61357f0..8618f01a 100644 --- a/src/http.c +++ b/src/http.c @@ -77,6 +77,8 @@ typedef struct _tf_http_listener_t tf_http_t* http; tf_tls_context_t* tls; uv_tcp_t tcp; + tf_http_cleanup_t* cleanup; + void* user_data; } tf_http_listener_t; typedef struct _tf_http_t @@ -606,10 +608,17 @@ static void _http_on_connection(uv_stream_t* stream, int status) http->connections[http->connections_count++] = connection; } -int tf_http_listen(tf_http_t* http, int port, tf_tls_context_t* tls) +int tf_http_listen(tf_http_t* http, int port, tf_tls_context_t* tls, tf_http_cleanup_t* cleanup, void* user_data) { tf_http_listener_t* listener = tf_malloc(sizeof(tf_http_listener_t)); - *listener = (tf_http_listener_t) { .http = http, .tls = tls, .tcp = { .data = listener } }; + *listener = (tf_http_listener_t) + { + .http = http, + .tls = tls, + .tcp = { .data = listener }, + .cleanup = cleanup, + .user_data = user_data, + }; int r = uv_tcp_init(http->loop, &listener->tcp); if (r) { @@ -651,7 +660,7 @@ int tf_http_listen(tf_http_t* http, int port, tf_tls_context_t* tls) if (r == 0) { - http->listeners = tf_realloc(http->listeners, sizeof(tf_http_listener_t*) * (http->listeners_count + 1)); + http->listeners = tf_resize_vec(http->listeners, sizeof(tf_http_listener_t*) * (http->listeners_count + 1)); http->listeners[http->listeners_count++] = listener; } return assigned_port; @@ -680,7 +689,12 @@ void tf_http_destroy(tf_http_t* http) { for (int i = 0; i < http->listeners_count; i++) { - uv_close((uv_handle_t*)&http->listeners[i]->tcp, _http_free_listener_on_close); + tf_http_listener_t* listener = http->listeners[i]; + if (listener->cleanup) + { + listener->cleanup(listener->user_data); + } + uv_close((uv_handle_t*)&listener->tcp, _http_free_listener_on_close); } tf_free(http->listeners); http->listeners = NULL; diff --git a/src/http.h b/src/http.h index f1e5b15c..5de1e092 100644 --- a/src/http.h +++ b/src/http.h @@ -37,7 +37,7 @@ typedef void (tf_http_cleanup_t)(void* user_data); tf_http_t* tf_http_create(uv_loop_t* loop); void tf_http_set_trace(tf_http_t* http, tf_trace_t* trace); -int tf_http_listen(tf_http_t* http, int port, tf_tls_context_t* tls); +int tf_http_listen(tf_http_t* http, int port, tf_tls_context_t* tls, tf_http_cleanup_t* cleanup, void* user_data); void tf_http_add_handler(tf_http_t* http, const char* pattern, tf_http_callback_t* callback, tf_http_cleanup_t* cleanup, void* user_data); void tf_http_respond(tf_http_request_t* request, int status, const char** headers, int headers_count, const void* body, size_t content_length); size_t tf_http_get_body(const tf_http_request_t* request, const void** out_data); diff --git a/src/httpd.js.c b/src/httpd.js.c index 9b027523..6962c99c 100644 --- a/src/httpd.js.c +++ b/src/httpd.js.c @@ -347,20 +347,34 @@ static JSValue _httpd_endpoint_all(JSContext* context, JSValueConst this_val, in const char* pattern = JS_ToCString(context, argv[0]); http_handler_data_t* data = tf_malloc(sizeof(http_handler_data_t)); *data = (http_handler_data_t) { .context = context, .callback = JS_DupValue(context, argv[1]) }; - /* TODO: This leaks the callback. */ tf_http_add_handler(http, pattern, _httpd_callback, _httpd_cleanup_callback, data); JS_FreeCString(context, pattern); return JS_UNDEFINED; } +typedef struct _httpd_listener_t +{ + JSContext* context; + JSValue tls; +} httpd_listener_t; + +static void _httpd_listener_cleanup(void* user_data) +{ + httpd_listener_t* listener = user_data; + JS_FreeValue(listener->context, listener->tls); + tf_free(listener); +} + static JSValue _httpd_endpoint_start(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv) { tf_http_t* http = JS_GetOpaque(this_val, _httpd_class_id); int port = 0; JS_ToInt32(context, &port, argv[0]); - /* TODO: This leaks the TLS context. */ - tf_tls_context_t* tls = tf_tls_context_get(JS_DupValue(context, argv[1])); - int assigned_port = tf_http_listen(http, port, tls); + + httpd_listener_t* listener = tf_malloc(sizeof(httpd_listener_t)); + *listener = (httpd_listener_t) { .context = context, .tls = JS_DupValue(context, argv[1]) }; + tf_tls_context_t* tls = tf_tls_context_get(listener->tls); + int assigned_port = tf_http_listen(http, port, tls, _httpd_listener_cleanup, listener); return JS_NewInt32(context, assigned_port); } diff --git a/src/tests.c b/src/tests.c index a9f35b14..90210937 100644 --- a/src/tests.c +++ b/src/tests.c @@ -739,7 +739,7 @@ static void _test_http(const tf_test_options_t* options) tf_http_t* http = tf_http_create(&loop); tf_http_add_handler(http, "/hello", _test_http_handler, NULL, NULL); tf_http_add_handler(http, "/post", _test_http_handler_post, NULL, NULL); - tf_http_listen(http, 23456, NULL); + tf_http_listen(http, 23456, NULL, NULL, NULL); test_http_t test = { .loop = &loop }; uv_async_init(&loop, &test.async, _test_http_async);