http+js: Move app blob handling from JS to C. handler.js support has been temporarily removed.

This commit is contained in:
2024-11-02 21:37:14 -04:00
parent 30d108fc35
commit 5da63faf1f
3 changed files with 134 additions and 164 deletions

View File

@ -1034,6 +1034,131 @@ static user_app_t* _parse_user_app_from_path(const char* path, const char* expec
return result;
}
typedef struct _app_blob_t
{
tf_http_request_t* request;
bool found;
bool not_modified;
void* data;
size_t size;
char etag[256];
} app_blob_t;
static void _httpd_endpoint_app_blob_work(tf_ssb_t* ssb, void* user_data)
{
app_blob_t* data = user_data;
tf_http_request_t* request = data->request;
char app_id[256] = "";
const char* file = NULL;
if (request->path[0] == '/' && request->path[1] == '~')
{
const char* last_slash = strchr(request->path + 1, '/');
if (last_slash)
{
last_slash = strchr(last_slash + 1, '/');
}
user_app_t* user_app = last_slash ? _parse_user_app_from_path(request->path, last_slash) : NULL;
if (user_app)
{
size_t path_length = strlen("path:") + strlen(user_app->app) + 1;
char* app_path = tf_malloc(path_length);
snprintf(app_path, path_length, "path:%s", user_app->app);
const char* value = tf_ssb_db_get_property(ssb, user_app->user, app_path);
snprintf(app_id, sizeof(app_id), "%s", value);
tf_free(app_path);
tf_free((void*)value);
file = last_slash + 1;
tf_free(user_app);
}
}
else if (request->path[0] == '/' && request->path[1] == '&')
{
const char* end = strstr(request->path, ".sha256/");
if (end)
{
snprintf(app_id, sizeof(app_id), "%.*s", (int)(end + strlen(".sha256") - request->path - 1), request->path + 1);
file = end + strlen(".sha256/");
}
}
char* app_blob = NULL;
size_t app_blob_size = 0;
if (*app_id && tf_ssb_db_blob_get(ssb, app_id, (uint8_t**)&app_blob, &app_blob_size))
{
JSMallocFunctions funcs = { 0 };
tf_get_js_malloc_functions(&funcs);
JSRuntime* runtime = JS_NewRuntime2(&funcs, NULL);
JSContext* context = JS_NewContext(runtime);
JSValue app_object = JS_ParseJSON(context, app_blob, app_blob_size, NULL);
JSValue files = JS_GetPropertyStr(context, app_object, "files");
JSValue blob_id = JS_GetPropertyStr(context, files, file);
const char* blob_id_str = JS_ToCString(context, blob_id);
if (blob_id_str)
{
snprintf(data->etag, sizeof(data->etag), "\"%s\"", blob_id_str);
const char* match = tf_http_request_get_header(data->request, "if-none-match");
if (match && strcmp(match, data->etag) == 0)
{
data->not_modified = true;
}
else
{
data->found = tf_ssb_db_blob_get(ssb, blob_id_str, (uint8_t**)&data->data, &data->size);
}
}
JS_FreeCString(context, blob_id_str);
JS_FreeValue(context, blob_id);
JS_FreeValue(context, files);
JS_FreeValue(context, app_object);
JS_FreeContext(context);
JS_FreeRuntime(runtime);
tf_free(app_blob);
}
}
static void _httpd_endpoint_app_blob_after_work(tf_ssb_t* ssb, int status, void* user_data)
{
app_blob_t* data = user_data;
if (data->not_modified)
{
tf_http_respond(data->request, 304, NULL, 0, NULL, 0);
}
else if (data->found)
{
const char* mime_type = _ext_to_content_type(strrchr(data->request->path, '.'), false);
if (!mime_type)
{
mime_type = _httpd_mime_type_from_magic_bytes_internal(data->data, data->size);
}
const char* headers[] = {
"Access-Control-Allow-Origin",
"*",
"Content-Security-Policy",
"sandbox allow-downloads allow-top-navigation-by-user-activation",
"Content-Type",
mime_type ? mime_type : "application/binary",
"etag",
data->etag,
};
tf_http_respond(data->request, 200, headers, tf_countof(headers) / 2, data->data, data->size);
}
tf_free(data->data);
tf_http_request_unref(data->request);
tf_free(data);
}
static void _httpd_endpoint_app_blob(tf_http_request_t* request)
{
tf_http_request_ref(request);
tf_task_t* task = request->user_data;
tf_ssb_t* ssb = tf_task_get_ssb(task);
app_blob_t* data = tf_malloc(sizeof(app_blob_t));
*data = (app_blob_t) { .request = request };
tf_ssb_run_work(ssb, _httpd_endpoint_app_blob_work, _httpd_endpoint_app_blob_after_work, data);
}
typedef struct _view_t
{
tf_http_request_t* request;
@ -2117,14 +2242,17 @@ void tf_httpd_register(JSContext* context)
tf_http_add_handler(http, "/speedscope/*", _httpd_endpoint_static, NULL, task);
tf_http_add_handler(http, "/static/*", _httpd_endpoint_static, NULL, task);
tf_http_add_handler(http, "/.well-known/*", _httpd_endpoint_static, NULL, task);
tf_http_add_handler(http, "/&*.sha256", _httpd_endpoint_add_slash, NULL, task);
tf_http_add_handler(http, "/&*.sha256/", _httpd_endpoint_static, NULL, task);
tf_http_add_handler(http, "/*/view", _httpd_endpoint_view, NULL, task);
tf_http_add_handler(http, "/&*.sha256/view", _httpd_endpoint_view, NULL, task);
tf_http_add_handler(http, "/&*.sha256/*", _httpd_endpoint_app_blob, NULL, task);
tf_http_add_handler(http, "/~{word}/{word}", _httpd_endpoint_add_slash, NULL, task);
tf_http_add_handler(http, "/~{word}/{word}/", _httpd_endpoint_static, NULL, task);
tf_http_add_handler(http, "/~{word}/{word}/save", _httpd_endpoint_save, NULL, task);
tf_http_add_handler(http, "/~{word}/{word}/delete", _httpd_endpoint_delete, NULL, task);
tf_http_add_handler(http, "/~{word}/{word}/view", _httpd_endpoint_view, NULL, task);
tf_http_add_handler(http, "/~{word}/{word}/*", _httpd_endpoint_app_blob, NULL, task);
tf_http_add_handler(http, "/save", _httpd_endpoint_save, NULL, task);
tf_http_add_handler(http, "/~{word}/{word}", _httpd_endpoint_add_slash, NULL, task);
tf_http_add_handler(http, "/&*.sha256", _httpd_endpoint_add_slash, NULL, task);
tf_http_add_handler(http, "/robots.txt", _httpd_endpoint_robots_txt, NULL, NULL);
tf_http_add_handler(http, "/debug", _httpd_endpoint_debug, NULL, task);