Send a valid HTTP response and shutdown the connection.

git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4679 ed5197a5-7fde-0310-b194-c3ffbd925b24
This commit is contained in:
Cory McWilliams 2023-12-17 17:44:54 +00:00
parent 067f546580
commit 7b3a9e0f63
3 changed files with 71 additions and 13 deletions

View File

@ -6,6 +6,7 @@
#include "picohttpparser.h"
#include "uv.h"
#include <assert.h>
#include <string.h>
#if !defined(__APPLE__) && !defined(__OpenBSD__) && !defined(_WIN32)
@ -121,16 +122,6 @@ void _http_on_read(uv_stream_t* stream, ssize_t read_size, const uv_buf_t* buffe
.user_data = connection->user_data,
};
connection->callback(&request);
const char* payload = "HTTP/1.0 200 OK\r\nContent-Length: 13\r\n\r\nHello, world!";
uv_write_t* write = tf_malloc(sizeof(uv_write_t) + strlen(payload));
*write = (uv_write_t) { 0 };
memcpy(write + 1, payload, strlen(payload));
int r = uv_write(write, stream, &(uv_buf_t) { .base = (char*)(write + 1), .len = strlen(payload) }, 1, _http_on_write);
if (r)
{
tf_printf("uv_write: %s\n", uv_strerror(r));
}
}
}
else
@ -231,3 +222,56 @@ void tf_http_destroy(tf_http_t* http)
{
tf_free(http);
}
static const char* _http_status_text(int status)
{
switch (status)
{
case 200: return "OK";
case 404: return "File not found";
default: return "Unknown";
}
}
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)
{
const char* status_text = _http_status_text(status);
/* HTTP/1.x 200 OK\r\n */
int headers_length = 8 + 1 + 3 + 1 + strlen(status_text) + 2;
for (int i = 0; i < headers_count; i += 2)
{
/* Key: Value\r\n */
headers_length += strlen(headers[i]) + 2 + strlen(headers[i + 1]) + 2;
}
/* \r\n */
headers_length += 2;
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);
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]);
}
offset += snprintf(buffer + offset, headers_length + 1 - offset, "\r\n");
assert(offset == headers_length);
if (content_length)
{
memcpy(buffer + offset, body, content_length);
}
int r = uv_write(write, (uv_stream_t*)&request->connection->tcp, &(uv_buf_t) { .base = buffer, .len = headers_length + content_length }, 1, _http_on_write);
if (r)
{
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);
}

View File

@ -1,5 +1,7 @@
#pragma once
#include <stddef.h>
typedef struct uv_loop_s uv_loop_t;
typedef struct _tf_http_t tf_http_t;
typedef struct _tf_http_connection_t tf_http_connection_t;
@ -26,4 +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_destroy(tf_http_t* http);

View File

@ -674,14 +674,20 @@ static void _test_http_thread(void* data)
{
#if defined(__linux__)
int r = system("curl -v http://localhost:23456/");
tf_printf("curl returned %d\n", WEXITSTATUS(r));
*(int*)data = WEXITSTATUS(r);
assert(WEXITSTATUS(r) == 0);
tf_printf("curl returned %d\n", WEXITSTATUS(r));
#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!"));
}
static void _test_http(const tf_test_options_t* options)
@ -692,9 +698,14 @@ 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;
uv_thread_t thread = { 0 };
uv_thread_create(&thread, _test_http_thread, NULL);
uv_run(&loop, UV_RUN_DEFAULT);
uv_thread_create(&thread, _test_http_thread, &result);
while (result == -1)
{
uv_run(&loop, UV_RUN_ONCE);
}
tf_printf("Done running.\n");
tf_http_destroy(http);
uv_loop_close(&loop);