forked from cory/tildefriends
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:
parent
067f546580
commit
7b3a9e0f63
64
src/http.c
64
src/http.c
@ -6,6 +6,7 @@
|
|||||||
#include "picohttpparser.h"
|
#include "picohttpparser.h"
|
||||||
#include "uv.h"
|
#include "uv.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#if !defined(__APPLE__) && !defined(__OpenBSD__) && !defined(_WIN32)
|
#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,
|
.user_data = connection->user_data,
|
||||||
};
|
};
|
||||||
connection->callback(&request);
|
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
|
else
|
||||||
@ -231,3 +222,56 @@ void tf_http_destroy(tf_http_t* http)
|
|||||||
{
|
{
|
||||||
tf_free(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);
|
||||||
|
}
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
typedef struct uv_loop_s uv_loop_t;
|
typedef struct uv_loop_s uv_loop_t;
|
||||||
typedef struct _tf_http_t tf_http_t;
|
typedef struct _tf_http_t tf_http_t;
|
||||||
typedef struct _tf_http_connection_t tf_http_connection_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);
|
tf_http_t* tf_http_create(uv_loop_t* loop);
|
||||||
void tf_http_listen(tf_http_t* http, int port);
|
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_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);
|
void tf_http_destroy(tf_http_t* http);
|
||||||
|
17
src/tests.c
17
src/tests.c
@ -674,14 +674,20 @@ static void _test_http_thread(void* data)
|
|||||||
{
|
{
|
||||||
#if defined(__linux__)
|
#if defined(__linux__)
|
||||||
int r = system("curl -v http://localhost:23456/");
|
int r = system("curl -v http://localhost:23456/");
|
||||||
tf_printf("curl returned %d\n", WEXITSTATUS(r));
|
*(int*)data = WEXITSTATUS(r);
|
||||||
assert(WEXITSTATUS(r) == 0);
|
assert(WEXITSTATUS(r) == 0);
|
||||||
|
tf_printf("curl returned %d\n", WEXITSTATUS(r));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _test_http_handler(tf_http_request_t* request)
|
static void _test_http_handler(tf_http_request_t* request)
|
||||||
{
|
{
|
||||||
tf_printf("HANDLER %d\n", request->phase);
|
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)
|
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_add_handler(http, NULL, _test_http_handler, NULL);
|
||||||
tf_http_listen(http, 23456);
|
tf_http_listen(http, 23456);
|
||||||
|
|
||||||
|
int result = -1;
|
||||||
uv_thread_t thread = { 0 };
|
uv_thread_t thread = { 0 };
|
||||||
uv_thread_create(&thread, _test_http_thread, NULL);
|
uv_thread_create(&thread, _test_http_thread, &result);
|
||||||
uv_run(&loop, UV_RUN_DEFAULT);
|
while (result == -1)
|
||||||
|
{
|
||||||
|
uv_run(&loop, UV_RUN_ONCE);
|
||||||
|
}
|
||||||
|
tf_printf("Done running.\n");
|
||||||
|
|
||||||
tf_http_destroy(http);
|
tf_http_destroy(http);
|
||||||
uv_loop_close(&loop);
|
uv_loop_close(&loop);
|
||||||
|
Loading…
Reference in New Issue
Block a user