Fix some http request lifetime issues, and follow the same lowercase convention for headers.

git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4690 ed5197a5-7fde-0310-b194-c3ffbd925b24
This commit is contained in:
Cory McWilliams 2023-12-21 17:45:06 +00:00
parent 86046e52f0
commit 38ab32dad9
3 changed files with 59 additions and 9 deletions

View File

@ -21,6 +21,8 @@ typedef struct _tf_http_connection_t
uv_tcp_t tcp;
uv_shutdown_t shutdown;
int ref_count;
const char* method;
const char* path;
int minor_version;
@ -127,7 +129,7 @@ static void _http_connection_destroy(tf_http_connection_t* connection)
{
uv_close((uv_handle_t*)&connection->tcp, _http_connection_on_close);
}
else
else if (connection->ref_count == 0)
{
tf_http_t* http = connection->http;
for (int i = 0; i < http->connections_count; i++)
@ -182,7 +184,9 @@ static void _http_add_body_bytes(tf_http_connection_t* connection, const void* d
.headers_count = connection->headers_length,
.user_data = connection->user_data,
};
tf_http_request_ref(request);
connection->callback(request);
tf_http_request_release(request);
_http_reset_connection(connection);
}
}
@ -207,6 +211,7 @@ static void _http_on_read(uv_stream_t* stream, ssize_t read_size, const uv_buf_t
if (parse_result > 0)
{
connection->headers_done = true;
connection->headers_length = header_count;
connection->method = method;
((char*)connection->method)[method_length] = '\0';
connection->path = path;
@ -216,6 +221,14 @@ static void _http_on_read(uv_stream_t* stream, ssize_t read_size, const uv_buf_t
for (int i = 0; i < (int)header_count; i++)
{
for (size_t j = 0; j < connection->headers[i].name_len; j++)
{
if (connection->headers[i].name[j] >= 'A' &&
connection->headers[i].name[j] <= 'Z')
{
((char*)connection->headers[i].name)[j] += 'a' - 'A';
}
}
((char*)connection->headers[i].name)[connection->headers[i].name_len] = '\0';
((char*)connection->headers[i].value)[connection->headers[i].value_len] = '\0';
if (strcasecmp(connection->headers[i].name, "content-length") == 0)
@ -464,7 +477,6 @@ void tf_http_respond(tf_http_request_t* request, int status, const char** header
request->connection->shutdown.data = request->connection;
uv_shutdown(&request->connection->shutdown, (uv_stream_t*)&request->connection->tcp, _http_on_shutdown);
}
tf_free(request);
}
size_t tf_http_get_body(const tf_http_request_t* request, const void** out_data)
@ -472,3 +484,21 @@ size_t tf_http_get_body(const tf_http_request_t* request, const void** out_data)
*out_data = request->connection->body;
return request->connection->content_length;
}
void tf_http_request_ref(tf_http_request_t* request)
{
request->ref_count++;
request->connection->ref_count++;
}
void tf_http_request_release(tf_http_request_t* request)
{
if (--request->connection->ref_count == 0)
{
/* Reset the connection? */
}
if (--request->ref_count == 0)
{
tf_free(request);
}
}

View File

@ -21,6 +21,7 @@ typedef struct _tf_http_request_t
struct phr_header* headers;
int headers_count;
void* user_data;
int ref_count;
} tf_http_request_t;
typedef void (tf_http_callback_t)(tf_http_request_t* request);
@ -31,3 +32,6 @@ void tf_http_add_handler(tf_http_t* http, const char* pattern, tf_http_callback_
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);
void tf_http_request_ref(tf_http_request_t* request);
void tf_http_request_release(tf_http_request_t* request);

View File

@ -15,7 +15,7 @@
#endif
static JSClassID _httpd_class_id;
static JSClassID _httpd_response_class_id;
static JSClassID _httpd_request_class_id;
typedef struct _http_handler_data_t
{
@ -32,7 +32,7 @@ static JSValue _httpd_response_write_head(JSContext* context, JSValueConst this_
static JSValue _httpd_response_end(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
{
tf_http_request_t* request = JS_GetOpaque(this_val, _httpd_response_class_id);
tf_http_request_t* request = JS_GetOpaque(this_val, _httpd_request_class_id);
size_t length = 0;
const void* data = NULL;
JSValue buffer;
@ -104,17 +104,18 @@ static void _httpd_callback(tf_http_request_t* request)
JSValue request_object = JS_NewObject(context);
JS_SetPropertyStr(context, request_object, "uri", JS_NewString(context, request->path));
JSValue headers = JS_NewObject(context);
JS_SetPropertyStr(context, request_object, "headers", headers);
for (int i = 0; i < request->headers_count; i++)
{
JS_SetPropertyStr(context, headers, request->headers[i].name, JS_NewString(context, request->headers[i].value));
}
JS_SetPropertyStr(context, request_object, "headers", headers);
JSValue client = JS_NewObject(context);
JS_SetPropertyStr(context, client, "tls", JS_FALSE);
JS_SetPropertyStr(context, request_object, "client", client);
JSValue response_object = JS_NewObjectClass(context, _httpd_response_class_id);
JSValue response_object = JS_NewObjectClass(context, _httpd_request_class_id);
tf_http_request_ref(request);
JS_SetOpaque(response_object, request);
JS_SetPropertyStr(context, response_object, "writeHead", JS_NewCFunction(context, _httpd_response_write_head, "writeHead", 2));
JS_SetPropertyStr(context, response_object, "end", JS_NewCFunction(context, _httpd_response_end, "end", 1));
@ -161,19 +162,34 @@ void _httpd_finalizer(JSRuntime* runtime, JSValue value)
tf_http_destroy(http);
}
void _httpd_request_finalizer(JSRuntime* runtime, JSValue value)
{
tf_http_request_t* request = JS_GetOpaque(value, _httpd_request_class_id);
tf_http_request_release(request);
}
void tf_httpd_register(JSContext* context)
{
JS_NewClassID(&_httpd_class_id);
JS_NewClassID(&_httpd_response_class_id);
JSClassDef def =
JS_NewClassID(&_httpd_request_class_id);
JSClassDef httpd_def =
{
.class_name = "Httpd",
.finalizer = &_httpd_finalizer,
};
if (JS_NewClass(JS_GetRuntime(context), _httpd_class_id, &def) != 0)
if (JS_NewClass(JS_GetRuntime(context), _httpd_class_id, &httpd_def) != 0)
{
fprintf(stderr, "Failed to register Httpd.\n");
}
JSClassDef request_def =
{
.class_name = "Request",
.finalizer = &_httpd_request_finalizer,
};
if (JS_NewClass(JS_GetRuntime(context), _httpd_request_class_id, &request_def) != 0)
{
fprintf(stderr, "Failed to register Request.\n");
}
JSValue global = JS_GetGlobalObject(context);
JSValue httpd = JS_NewObjectClass(context, _httpd_class_id);