Tryingn to button down websocket lifetime issues.

git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4795 ed5197a5-7fde-0310-b194-c3ffbd925b24
This commit is contained in:
Cory McWilliams 2024-01-27 02:36:08 +00:00
parent f479165aac
commit 48b967f5b6
3 changed files with 28 additions and 1 deletions

View File

@ -158,6 +158,15 @@ static void _http_connection_destroy(tf_http_connection_t* connection, const cha
{ {
connection->is_shutting_down = true; connection->is_shutting_down = true;
if (connection->request && connection->request->on_close)
{
tf_http_close_callback* on_close = connection->request->on_close;
connection->request->on_close = NULL;
tf_trace_begin(connection->http->trace, connection->trace_name ? connection->trace_name : "websocket");
on_close(connection->request);
tf_trace_end(connection->http->trace);
}
if (connection->tcp.data && !uv_is_closing((uv_handle_t*)&connection->tcp)) if (connection->tcp.data && !uv_is_closing((uv_handle_t*)&connection->tcp))
{ {
uv_close((uv_handle_t*)&connection->tcp, _http_connection_on_close); uv_close((uv_handle_t*)&connection->tcp, _http_connection_on_close);
@ -896,6 +905,7 @@ void tf_http_request_release(tf_http_request_t* request)
} }
if (--request->ref_count == 0) if (--request->ref_count == 0)
{ {
request->connection->request = NULL;
tf_free(request); tf_free(request);
} }
} }

View File

@ -11,6 +11,7 @@ typedef struct _tf_trace_t tf_trace_t;
typedef struct uv_loop_s uv_loop_t; typedef struct uv_loop_s uv_loop_t;
typedef void (tf_http_message_callback)(tf_http_request_t* request, int op_code, const void* data, size_t size); typedef void (tf_http_message_callback)(tf_http_request_t* request, int op_code, const void* data, size_t size);
typedef void (tf_http_close_callback)(tf_http_request_t* request);
typedef struct _tf_http_request_t typedef struct _tf_http_request_t
{ {
@ -25,6 +26,7 @@ typedef struct _tf_http_request_t
struct phr_header* headers; struct phr_header* headers;
int headers_count; int headers_count;
tf_http_message_callback* on_message; tf_http_message_callback* on_message;
tf_http_close_callback* on_close;
void* context; void* context;
void* user_data; void* user_data;
int ref_count; int ref_count;

View File

@ -163,12 +163,23 @@ static JSValue _httpd_response_send(JSContext* context, JSValueConst this_val, i
return JS_UNDEFINED; return JS_UNDEFINED;
} }
static void _httpd_close_callback(tf_http_request_t* request)
{
JSContext* context = request->context;
JSValue response_object = JS_MKPTR(JS_TAG_OBJECT, request->user_data);
JSValue on_close = JS_GetPropertyStr(context, response_object, "onClose");
JSValue response = JS_Call(context, on_close, JS_UNDEFINED, 0, NULL);
tf_util_report_error(context, response);
JS_FreeValue(context, response);
JS_FreeValue(context, on_close);
tf_http_request_release(request);
}
static void _httpd_message_callback(tf_http_request_t* request, int op_code, const void* data, size_t size) static void _httpd_message_callback(tf_http_request_t* request, int op_code, const void* data, size_t size)
{ {
JSContext* context = request->context; JSContext* context = request->context;
JSValue response_object = JS_MKPTR(JS_TAG_OBJECT, request->user_data); JSValue response_object = JS_MKPTR(JS_TAG_OBJECT, request->user_data);
JSValue on_message = JS_GetPropertyStr(context, response_object, "onMessage"); JSValue on_message = JS_GetPropertyStr(context, response_object, "onMessage");
JSValue event = JS_NewObject(context); JSValue event = JS_NewObject(context);
JS_SetPropertyStr(context, event, "opCode", JS_NewInt32(context, op_code)); JS_SetPropertyStr(context, event, "opCode", JS_NewInt32(context, op_code));
JS_SetPropertyStr(context, event, "data", JS_NewStringLen(context, data, size)); JS_SetPropertyStr(context, event, "data", JS_NewStringLen(context, data, size));
@ -307,12 +318,14 @@ static JSValue _httpd_websocket_upgrade(JSContext* context, JSValueConst this_va
tf_http_respond(request, 101, headers, headers_count, NULL, 0); tf_http_respond(request, 101, headers, headers_count, NULL, 0);
request->on_message = _httpd_message_callback; request->on_message = _httpd_message_callback;
request->on_close = _httpd_close_callback;
request->context = context; request->context = context;
request->user_data = JS_VALUE_GET_PTR(JS_DupValue(context, this_val)); request->user_data = JS_VALUE_GET_PTR(JS_DupValue(context, this_val));
} }
else else
{ {
tf_http_respond(request, 400, NULL, 0, NULL, 0); tf_http_respond(request, 400, NULL, 0, NULL, 0);
tf_http_request_release(request);
} }
return JS_UNDEFINED; return JS_UNDEFINED;
@ -324,6 +337,7 @@ static JSValue _httpd_endpoint_all(JSContext* context, JSValueConst this_val, in
const char* pattern = JS_ToCString(context, argv[0]); const char* pattern = JS_ToCString(context, argv[0]);
http_handler_data_t* data = tf_malloc(sizeof(http_handler_data_t)); 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]) }; *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, data);
JS_FreeCString(context, pattern); JS_FreeCString(context, pattern);
return JS_UNDEFINED; return JS_UNDEFINED;
@ -334,6 +348,7 @@ static JSValue _httpd_endpoint_start(JSContext* context, JSValueConst this_val,
tf_http_t* http = JS_GetOpaque(this_val, _httpd_class_id); tf_http_t* http = JS_GetOpaque(this_val, _httpd_class_id);
int port = 0; int port = 0;
JS_ToInt32(context, &port, argv[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])); tf_tls_context_t* tls = tf_tls_context_get(JS_DupValue(context, argv[1]));
int assigned_port = tf_http_listen(http, port, tls); int assigned_port = tf_http_listen(http, port, tls);
return JS_NewInt32(context, assigned_port); return JS_NewInt32(context, assigned_port);