diff --git a/src/http.c b/src/http.c index b96c759f..3930b0d8 100644 --- a/src/http.c +++ b/src/http.c @@ -22,6 +22,7 @@ typedef struct _tf_http_connection_t const char* method; const char* path; + int minor_version; char headers_buffer[8192]; size_t headers_buffer_length; @@ -40,6 +41,7 @@ typedef struct _tf_http_connection_t void* body; size_t body_length; size_t content_length; + bool connection_close; } tf_http_connection_t; typedef struct _tf_http_handler_t @@ -147,6 +149,14 @@ static void _http_builtin_404_handler(tf_http_request_t* request) tf_http_respond(request, 404, NULL, 0, k_payload, strlen(k_payload)); } +static void _http_reset_connection(tf_http_connection_t* connection) +{ + connection->headers_done = false; + connection->headers_buffer_length = 0; + connection->body_length = 0; + connection->content_length = 0; +} + static void _http_add_body_bytes(tf_http_connection_t* connection, const void* data, size_t size) { size_t fit = tf_min(connection->content_length - connection->body_length, size); @@ -169,6 +179,7 @@ static void _http_add_body_bytes(tf_http_connection_t* connection, const void* d .user_data = connection->user_data, }; connection->callback(&request); + _http_reset_connection(connection); } } @@ -185,10 +196,9 @@ static void _http_on_read(uv_stream_t* stream, ssize_t read_size, const uv_buf_t size_t method_length = 0; const char* path = NULL; size_t path_length = 0; - int minor_version = 0; size_t header_count = sizeof(connection->headers) / sizeof(*connection->headers); - int parse_result = phr_parse_request(connection->headers_buffer, connection->headers_buffer_length, &method, &method_length, &path, &path_length, &minor_version, connection->headers, &header_count, connection->parsed_length); + int parse_result = phr_parse_request(connection->headers_buffer, connection->headers_buffer_length, &method, &method_length, &path, &path_length, &connection->minor_version, connection->headers, &header_count, connection->parsed_length); connection->parsed_length = connection->headers_buffer_length; if (parse_result > 0) { @@ -198,13 +208,23 @@ static void _http_on_read(uv_stream_t* stream, ssize_t read_size, const uv_buf_t connection->path = path; ((char*)connection->path)[path_length] = '\0'; + connection->connection_close = connection->minor_version == 0; + for (int i = 0; i < (int)header_count; i++) { - if (connection->headers[i].name_len == strlen("content-length") && - strncasecmp(connection->headers[i].name, "content-length", connection->headers[i].name_len) == 0) + ((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) { connection->content_length = strtoull(connection->headers[i].value, NULL, 10); } + else if (strcasecmp(connection->headers[i].name, "connection") == 0) + { + if (strcasecmp(connection->headers[i].value, "close") == 0) + { + connection->connection_close = true; + } + } } if (connection->content_length) @@ -405,7 +425,7 @@ void tf_http_respond(tf_http_request_t* request, int status, const char** header uv_write_t* write = tf_malloc(sizeof(uv_write_t) + headers_length + content_length + 1); *write = (uv_write_t) { .data = request->connection }; char* buffer = (char*)(write + 1); - int offset = snprintf(buffer, headers_length + 1, "HTTP/1.0 %03d %s\r\n", status, status_text); + int offset = snprintf(buffer, headers_length + 1, "HTTP/1.%d %03d %s\r\n", request->connection->minor_version, status, status_text); for (int i = 0; i < headers_count; i += 2) { offset += snprintf(buffer + offset, headers_length + 1 - offset, "%s: %s\r\n", headers[i], headers[i + 1]); @@ -427,9 +447,12 @@ void tf_http_respond(tf_http_request_t* request, int status, const char** header tf_printf("uv_write: %s\n", uv_strerror(r)); } - uv_shutdown_t* shutdown_request = tf_malloc(sizeof(uv_shutdown_t)); - *shutdown_request = (uv_shutdown_t) { .data = request }; - uv_shutdown(shutdown_request, (uv_stream_t*)&request->connection->tcp, _http_on_shutdown); + if (request->connection->connection_close) + { + uv_shutdown_t* shutdown_request = tf_malloc(sizeof(uv_shutdown_t)); + *shutdown_request = (uv_shutdown_t) { .data = request }; + uv_shutdown(shutdown_request, (uv_stream_t*)&request->connection->tcp, _http_on_shutdown); + } } size_t tf_http_get_body(const tf_http_request_t* request, const void** out_data) diff --git a/src/tests.c b/src/tests.c index dbc555b8..0763c6fc 100644 --- a/src/tests.c +++ b/src/tests.c @@ -697,6 +697,10 @@ static void _test_http_thread(void* data) assert(WEXITSTATUS(r) == 0); tf_printf("curl returned %d\n", WEXITSTATUS(r)); + r = system("curl -v http://localhost:23456/hello http://localhost:23456/hello http://localhost:23456/hello"); + assert(WEXITSTATUS(r) == 0); + tf_printf("curl returned %d\n", WEXITSTATUS(r)); + test->done = true; /* All to wake up the loop. */ @@ -708,7 +712,7 @@ static void _test_http_handler(tf_http_request_t* request) { const char* headers[] = { - "Connection", "close", + "User-Agent", "TildeFriends/1.0", }; const char* k_payload = "Hello, world!\n"; tf_http_respond(request, 200, headers, 1, k_payload, strlen(k_payload));