diff --git a/src/http.c b/src/http.c index 187675f6..cd9cf211 100644 --- a/src/http.c +++ b/src/http.c @@ -44,9 +44,12 @@ typedef struct _tf_http_t tf_http_handler_t* handlers; int handlers_count; + int pending_closes; uv_loop_t* loop; } tf_http_t; +static void _http_connection_destroy(tf_http_connection_t* connection); + tf_http_t* tf_http_create(uv_loop_t* loop) { tf_http_t* http = tf_malloc(sizeof(tf_http_t)); @@ -82,6 +85,33 @@ static void _http_on_write(uv_write_t* write, int status) tf_free(write); } +static void _http_connection_on_close(uv_handle_t* handle) +{ + tf_http_connection_t* connection = handle->data; + handle->data = NULL; + _http_connection_destroy(connection); +} + +static void _http_connection_destroy(tf_http_connection_t* connection) +{ + if (connection->tcp.data) + { + uv_close((uv_handle_t*)&connection->tcp, _http_connection_on_close); + } + else + { + tf_http_t* http = connection->http; + for (int i = 0; i < http->connections_count; i++) + { + if (http->connections[i] == connection) + { + http->connections[i] = http->connections[--http->connections_count]; + } + } + tf_free(connection); + } +} + void _http_on_read(uv_stream_t* stream, ssize_t read_size, const uv_buf_t* buffer) { tf_http_connection_t* connection = stream->data; @@ -129,6 +159,10 @@ void _http_on_read(uv_stream_t* stream, ssize_t read_size, const uv_buf_t* buffe tf_printf("phr_parse_request: %d\n", parse_result); } } + else + { + _http_connection_destroy(connection); + } } static void _http_on_connection(uv_stream_t* stream, int status) @@ -218,8 +252,28 @@ void tf_http_add_handler(tf_http_t* http, const char* pattern, tf_http_callback_ }; } +static void _http_free_on_close(uv_handle_t* handle) +{ + handle->data = NULL; + tf_free(handle); +} + 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], _http_free_on_close); + } + tf_free(http->listeners); + http->listeners = NULL; + http->listeners_count = 0; + + tf_free(http->handlers); + http->handlers_count = 0; + + tf_free(http->connections); + http->connections_count = 0; + tf_free(http); } @@ -238,7 +292,7 @@ static void _http_on_shutdown(uv_shutdown_t* request, int status) tf_free(request); } -void tf_http_respond(tf_http_request_t* request, int status, const char** headers, int headers_count, void* body, size_t content_length) +void tf_http_respond(tf_http_request_t* request, int status, const char** headers, int headers_count, const void* body, size_t content_length) { const char* status_text = _http_status_text(status); /* HTTP/1.x 200 OK\r\n */ diff --git a/src/http.h b/src/http.h index 38ed3ca8..a4d98602 100644 --- a/src/http.h +++ b/src/http.h @@ -28,5 +28,5 @@ typedef void (tf_http_callback_t)(tf_http_request_t* request); tf_http_t* tf_http_create(uv_loop_t* loop); void tf_http_listen(tf_http_t* http, int port); void tf_http_add_handler(tf_http_t* http, const char* pattern, tf_http_callback_t* callback, void* user_data); -void tf_http_respond(tf_http_request_t* request, int status, const char** headers, int headers_count, void* body, size_t content_length); +void tf_http_respond(tf_http_request_t* request, int status, const char** headers, int headers_count, const void* body, size_t content_length); void tf_http_destroy(tf_http_t* http); diff --git a/src/tests.c b/src/tests.c index 410f0c56..7256ee98 100644 --- a/src/tests.c +++ b/src/tests.c @@ -670,24 +670,40 @@ static void _test_b64(const tf_test_options_t* options) unlink("out/test.js"); } +typedef struct _test_http_t +{ + uv_loop_t* loop; + uv_async_t async; + bool done; +} test_http_t; + +static void _test_http_async(uv_async_t* async) +{ +} + static void _test_http_thread(void* data) { #if defined(__linux__) + test_http_t* test = data; int r = system("curl -v http://localhost:23456/"); - *(int*)data = WEXITSTATUS(r); assert(WEXITSTATUS(r) == 0); tf_printf("curl returned %d\n", WEXITSTATUS(r)); + + test->done = true; + + /* All to wake up the loop. */ + uv_async_send(&test->async); #endif } static void _test_http_handler(tf_http_request_t* request) { - tf_printf("HANDLER %d\n", request->phase); const char* headers[] = { "Connection", "close", }; - tf_http_respond(request, 200, headers, 1, "Hello, world!", strlen("Hello, world!")); + const char* k_payload = "Hello, world!\n"; + tf_http_respond(request, 200, headers, 1, k_payload, strlen(k_payload)); } static void _test_http(const tf_test_options_t* options) @@ -698,16 +714,19 @@ static void _test_http(const tf_test_options_t* options) tf_http_add_handler(http, NULL, _test_http_handler, NULL); tf_http_listen(http, 23456); - int result = -1; + test_http_t test = { .loop = &loop }; + uv_async_init(&loop, &test.async, _test_http_async); uv_thread_t thread = { 0 }; - uv_thread_create(&thread, _test_http_thread, &result); - while (result == -1) + uv_thread_create(&thread, _test_http_thread, &test); + while (!test.done) { uv_run(&loop, UV_RUN_ONCE); } + uv_close((uv_handle_t*)&test.async, NULL); tf_printf("Done running.\n"); tf_http_destroy(http); + uv_run(&loop, UV_RUN_DEFAULT); uv_loop_close(&loop); uv_thread_join(&thread);