diff --git a/src/http.c b/src/http.c index d61500cd..e61357f0 100644 --- a/src/http.c +++ b/src/http.c @@ -68,6 +68,7 @@ typedef struct _tf_http_handler_t { const char* pattern; tf_http_callback_t* callback; + tf_http_cleanup_t* cleanup; void* user_data; } tf_http_handler_t; @@ -656,13 +657,14 @@ int tf_http_listen(tf_http_t* http, int port, tf_tls_context_t* tls) return assigned_port; } -void tf_http_add_handler(tf_http_t* http, const char* pattern, tf_http_callback_t* callback, 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) { http->handlers = tf_realloc(http->handlers, sizeof(tf_http_handler_t) * (http->handlers_count + 1)); http->handlers[http->handlers_count++] = (tf_http_handler_t) { .pattern = tf_strdup(pattern), .callback = callback, + .cleanup = cleanup, .user_data = user_data, }; } @@ -691,6 +693,10 @@ void tf_http_destroy(tf_http_t* http) tf_free((void*)http->handlers[i].pattern); http->handlers[i].pattern = NULL; } + if (http->handlers[i].cleanup) + { + http->handlers[i].cleanup(http->handlers[i].user_data); + } } tf_free(http->handlers); http->handlers_count = 0; diff --git a/src/http.h b/src/http.h index fa588fce..f1e5b15c 100644 --- a/src/http.h +++ b/src/http.h @@ -38,7 +38,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); -void tf_http_add_handler(tf_http_t* http, const char* pattern, tf_http_callback_t* callback, 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); void tf_http_destroy(tf_http_t* http); diff --git a/src/httpd.js.c b/src/httpd.js.c index 6b8c8497..9b027523 100644 --- a/src/httpd.js.c +++ b/src/httpd.js.c @@ -334,6 +334,13 @@ static JSValue _httpd_websocket_upgrade(JSContext* context, JSValueConst this_va return JS_UNDEFINED; } +static void _httpd_cleanup_callback(void* user_data) +{ + http_handler_data_t* data = user_data; + JS_FreeValue(data->context, data->callback); + tf_free(data); +} + static JSValue _httpd_endpoint_all(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv) { tf_http_t* http = JS_GetOpaque(this_val, _httpd_class_id); @@ -341,7 +348,7 @@ static JSValue _httpd_endpoint_all(JSContext* context, JSValueConst this_val, in 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, data); + tf_http_add_handler(http, pattern, _httpd_callback, _httpd_cleanup_callback, data); JS_FreeCString(context, pattern); return JS_UNDEFINED; } @@ -527,11 +534,11 @@ void tf_httpd_register(JSContext* context) tf_http_set_trace(http, tf_task_get_trace(task)); JS_SetOpaque(httpd, http); - tf_http_add_handler(http, "/debug", _httpd_endpoint_debug, task); - tf_http_add_handler(http, "/disconnections", _httpd_endpoint_disconnections, task); - tf_http_add_handler(http, "/hitches", _httpd_endpoint_hitches, task); - tf_http_add_handler(http, "/mem", _httpd_endpoint_mem, task); - tf_http_add_handler(http, "/trace", _httpd_endpoint_trace, task); + tf_http_add_handler(http, "/debug", _httpd_endpoint_debug, NULL, task); + tf_http_add_handler(http, "/disconnections", _httpd_endpoint_disconnections, NULL, task); + tf_http_add_handler(http, "/hitches", _httpd_endpoint_hitches, NULL, task); + tf_http_add_handler(http, "/mem", _httpd_endpoint_mem, NULL, task); + tf_http_add_handler(http, "/trace", _httpd_endpoint_trace, NULL, task); JS_SetPropertyStr(context, httpd, "handlers", JS_NewObject(context)); JS_SetPropertyStr(context, httpd, "all", JS_NewCFunction(context, _httpd_endpoint_all, "all", 2)); diff --git a/src/socket.js.c b/src/socket.js.c index 7006eff8..5bf6d577 100644 --- a/src/socket.js.c +++ b/src/socket.js.c @@ -1,5 +1,6 @@ #include "socket.js.h" +#include "log.h" #include "mem.h" #include "task.h" #include "tls.h" diff --git a/src/task.c b/src/task.c index e16a92b0..d5135d24 100644 --- a/src/task.c +++ b/src/task.c @@ -1838,6 +1838,15 @@ void tf_task_destroy(tf_task_t* task) { tf_ssb_destroy(task->_ssb); } + + /* This ensures the HTTP handlers get cleaned up. */ + if (task->_trusted) + { + JSValue global = JS_GetGlobalObject(task->_context); + JS_SetPropertyStr(task->_context, global, "httpd", JS_UNDEFINED); + JS_FreeValue(task->_context, global); + } + JS_FreeContext(task->_context); JS_FreeRuntime(task->_runtime); diff --git a/src/tests.c b/src/tests.c index 34320b88..a9f35b14 100644 --- a/src/tests.c +++ b/src/tests.c @@ -737,8 +737,8 @@ static void _test_http(const tf_test_options_t* options) uv_loop_t loop = { 0 }; uv_loop_init(&loop); tf_http_t* http = tf_http_create(&loop); - tf_http_add_handler(http, "/hello", _test_http_handler, NULL); - tf_http_add_handler(http, "/post", _test_http_handler_post, NULL); + 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); test_http_t test = { .loop = &loop }; diff --git a/src/tlscontext.js.c b/src/tlscontext.js.c index 0c5e5fb1..fad87c12 100644 --- a/src/tlscontext.js.c +++ b/src/tlscontext.js.c @@ -1,5 +1,6 @@ #include "tlscontext.js.h" +#include "log.h" #include "mem.h" #include "task.h" #include "tls.h"