Return legit responses for some static files.

git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4687 ed5197a5-7fde-0310-b194-c3ffbd925b24
This commit is contained in:
Cory McWilliams 2023-12-21 02:04:20 +00:00
parent 6ecbfe3de6
commit 7dc8b86ee2
2 changed files with 121 additions and 8 deletions

View File

@ -170,7 +170,8 @@ static void _http_add_body_bytes(tf_http_connection_t* connection, const void* d
if (connection->body_length == connection->content_length)
{
tf_http_request_t request =
tf_http_request_t* request = tf_malloc(sizeof(tf_http_request_t));
*request = (tf_http_request_t)
{
.connection = connection,
.phase = k_http_callback_phase_headers_received,
@ -180,7 +181,7 @@ static void _http_add_body_bytes(tf_http_connection_t* connection, const void* d
.headers_count = connection->headers_length,
.user_data = connection->user_data,
};
connection->callback(&request);
connection->callback(request);
_http_reset_connection(connection);
}
}
@ -387,8 +388,15 @@ static const char* _http_status_text(int status)
{
switch (status)
{
case 101: return "Switching Protocols";
case 200: return "OK";
case 303: return "See other";
case 304: return "Not Modified";
case 400: return "Bad Request";
case 401: return "Unauthorized";
case 403: return "Forbidden";
case 404: return "File not found";
case 500: return "Internal server error";
default: return "Unknown";
}
}
@ -455,6 +463,7 @@ void tf_http_respond(tf_http_request_t* request, int status, const char** header
*shutdown_request = (uv_shutdown_t) { .data = request };
uv_shutdown(shutdown_request, (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)

View File

@ -6,7 +6,14 @@
#include "task.h"
#include "util.js.h"
#include "picohttpparser.h"
#if !defined(__APPLE__) && !defined(__OpenBSD__) && !defined(_WIN32)
#include <alloca.h>
#endif
static JSClassID _httpd_class_id;
static JSClassID _httpd_response_class_id;
typedef struct _http_handler_data_t
{
@ -14,14 +21,111 @@ typedef struct _http_handler_data_t
JSValue callback;
} http_handler_data_t;
static JSValue _httpd_response_write_head(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
{
JS_SetPropertyStr(context, this_val, "response_status", JS_DupValue(context, argv[0]));
JS_SetPropertyStr(context, this_val, "response_headers", JS_DupValue(context, argv[1]));
return JS_UNDEFINED;
}
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);
size_t length = 0;
const void* data = NULL;
JSValue buffer;
if (JS_IsString(argv[0]))
{
data = JS_ToCStringLen(context, &length, argv[0]);
}
else if ((data = tf_util_try_get_array_buffer(context, &length, argv[0])) != 0)
{
}
else
{
size_t offset;
size_t size;
size_t element_size;
buffer = tf_util_try_get_typed_array_buffer(context, argv[0], &offset, &size, &element_size);
if (!JS_IsException(buffer))
{
data = tf_util_try_get_array_buffer(context, &length, buffer);
}
}
JSValue response_status = JS_GetPropertyStr(context, this_val, "response_status");
int status = 0;
JS_ToInt32(context, &status, response_status);
JS_FreeValue(context, response_status);
const char** headers = NULL;
int headers_length = 0;
JSValue response_headers = JS_GetPropertyStr(context, this_val, "response_headers");
JSPropertyEnum* ptab;
uint32_t plen;
JS_GetOwnPropertyNames(context, &ptab, &plen, response_headers, JS_GPN_STRING_MASK);
headers = alloca(sizeof(const char*) * plen * 2);
headers_length = plen;
for (uint32_t i = 0; i < plen; ++i)
{
JSValue key = JS_AtomToString(context, ptab[i].atom);
JSPropertyDescriptor desc;
JSValue key_value = JS_NULL;
if (JS_GetOwnProperty(context, &desc, response_headers, ptab[i].atom) == 1)
{
key_value = desc.value;
JS_FreeValue(context, desc.setter);
JS_FreeValue(context, desc.getter);
}
headers[i * 2 + 0] = JS_ToCString(context, key);
headers[i * 2 + 1] = JS_ToCString(context, key_value);
}
tf_http_respond(request, status, headers, headers_length, data, length);
for (int i = 0; i < headers_length * 2; i++)
{
JS_FreeCString(context, headers[i]);
}
for (uint32_t i = 0; i < plen; ++i)
{
JS_FreeAtom(context, ptab[i].atom);
}
js_free(context, ptab);
JS_FreeValue(context, buffer);
return JS_UNDEFINED;
}
static void _httpd_callback(tf_http_request_t* request)
{
tf_printf("httpd_callback!\n");
http_handler_data_t* data = request->user_data;
JSValue response = JS_Call(data->context, data->callback, JS_UNDEFINED, 0, NULL);
tf_printf("%d %d\n", JS_IsUndefined(response), JS_IsException(response));
tf_util_report_error(data->context, response);
JS_FreeValue(data->context, response);
JSContext* context = data->context;
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));
}
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);
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));
JSValue args[] =
{
request_object,
response_object,
};
JSValue response = JS_Call(context, data->callback, JS_UNDEFINED, 2, args);
tf_util_report_error(context, response);
JS_FreeValue(context, request_object);
JS_FreeValue(context, response_object);
JS_FreeValue(context, response);
}
static JSValue _httpd_all(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
@ -31,7 +135,6 @@ static JSValue _httpd_all(JSContext* context, JSValueConst this_val, int argc, J
http_handler_data_t* data = tf_malloc(sizeof(http_handler_data_t));
*data = (http_handler_data_t) { .context = context, .callback = JS_DupValue(context, argv[1]) };
tf_http_add_handler(http, pattern, _httpd_callback, data);
tf_printf("HTTPD_ALL: %s\n", pattern);
JS_FreeCString(context, pattern);
return JS_UNDEFINED;
@ -59,6 +162,7 @@ void _httpd_finalizer(JSRuntime* runtime, JSValue value)
void tf_httpd_register(JSContext* context)
{
JS_NewClassID(&_httpd_class_id);
JS_NewClassID(&_httpd_response_class_id);
JSClassDef def =
{
.class_name = "Httpd",