diff --git a/core/client.js b/core/client.js index 3327a58f4..bef78e0ba 100644 --- a/core/client.js +++ b/core/client.js @@ -1050,6 +1050,8 @@ function save(save_to) { if (save_path != window.location.pathname) { alert('Saved to ' + save_path + '.'); + } else if (!gFiles['app.js']) { + window.location.reload(); } else { reconnect(save_path); } diff --git a/src/httpd.js.c b/src/httpd.js.c index 05fdde149..d9266f584 100644 --- a/src/httpd.js.c +++ b/src/httpd.js.c @@ -596,13 +596,8 @@ static void _httpd_endpoint_mem(tf_http_request_t* request) static const char* _after(const char* text, const char* prefix) { - if (!text || !prefix) - { - return NULL; - } - size_t prefix_length = strlen(prefix); - if (strncmp(text, prefix, prefix_length) == 0) + if (text && strncmp(text, prefix, prefix_length) == 0) { return text + prefix_length; } @@ -703,7 +698,7 @@ static void _httpd_endpoint_static_stat(tf_task_t* task, const char* path, int r static void _httpd_endpoint_static(tf_http_request_t* request) { - if (strncmp(request->path, "/.well-known/", strlen("/.well-known/")) && _httpd_redirect(request)) + if (request->path && strncmp(request->path, "/.well-known/", strlen("/.well-known/")) && _httpd_redirect(request)) { return; } @@ -859,6 +854,7 @@ typedef struct _app_blob_t bool found; bool not_modified; bool use_handler; + bool use_static; void* data; size_t size; char app_blob_id[k_blob_id_len]; @@ -1005,6 +1001,10 @@ static void _httpd_endpoint_app_blob_after_work(tf_ssb_t* ssb, int status, void* { tf_http_respond(data->request, 304, NULL, 0, NULL, 0); } + else if (data->use_static) + { + _httpd_endpoint_static(data->request); + } else if (data->use_handler) { _httpd_call_app_handler(ssb, data->request, data->app_blob_id, data->file, data->user_app->user, data->user_app->app); @@ -1044,6 +1044,209 @@ static void _httpd_endpoint_app_blob(tf_http_request_t* request) tf_ssb_run_work(ssb, _httpd_endpoint_app_blob_work, _httpd_endpoint_app_blob_after_work, data); } +static bool _has_property(JSContext* context, JSValue object, const char* name) +{ + JSAtom atom = JS_NewAtom(context, name); + bool result = JS_HasProperty(context, object, atom) > 0; + JS_FreeAtom(context, atom); + return result; +} + +static void _httpd_endpoint_app_index_work(tf_ssb_t* ssb, void* user_data) +{ + app_blob_t* data = user_data; + data->use_static = true; + user_app_t* user_app = data->user_app; + + size_t app_path_length = strlen("path:") + strlen(user_app->app) + 1; + char* app_path = tf_malloc(app_path_length); + snprintf(app_path, app_path_length, "path:%s", user_app->app); + const char* app_blob_id = tf_ssb_db_get_property(ssb, user_app->user, app_path); + tf_free(app_path); + + uint8_t* app_blob = NULL; + size_t app_blob_size = 0; + + if (tf_ssb_db_blob_get(ssb, app_blob_id, &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 = JS_ParseJSON(context, (const char*)app_blob, app_blob_size, NULL); + JSValue files = JS_GetPropertyStr(context, app, "files"); + + if (!_has_property(context, files, "app.js")) + { + JSValue index = JS_GetPropertyStr(context, files, "index.html"); + if (JS_IsString(index)) + { + const char* index_string = JS_ToCString(context, index); + tf_ssb_db_blob_get(ssb, index_string, (uint8_t**)&data->data, &data->size); + JS_FreeCString(context, index_string); + } + JS_FreeValue(context, index); + } + + JS_FreeValue(context, files); + JS_FreeValue(context, app); + + JS_FreeContext(context); + JS_FreeRuntime(runtime); + + tf_free(app_blob); + } + tf_free((void*)app_blob_id); +} + +static char* _replace(const char* original, size_t size, const char* find, const char* replace, size_t* out_size) +{ + char* pos = strstr(original, find); + if (!pos) + { + return tf_strdup(original); + } + + size_t replace_length = strlen(replace); + size_t find_length = strlen(find); + size_t new_size = size + replace_length - find_length; + char* buffer = tf_malloc(new_size); + memcpy(buffer, original, pos - original); + memcpy(buffer + (pos - original), replace, replace_length); + memcpy(buffer + (pos - original) + replace_length, pos + find_length, size - (pos - original) - find_length); + *out_size = new_size; + return buffer; +} + +static char* _append_raw(char* document, size_t* current_size, const char* data, size_t size) +{ + document = tf_resize_vec(document, *current_size + size); + memcpy(document + *current_size, data, size); + document[*current_size + size] = '\0'; + *current_size += size; + return document; +} + +static char* _append_encoded(char* document, const char* data, size_t size, size_t* out_size) +{ + size_t current_size = strlen(document); + int accum = 0; + for (int i = 0; (size_t)i < size; i++) + { + switch (data[i]) + { + case '"': + if (i > accum) + { + document = _append_raw(document, ¤t_size, data + accum, i - accum); + } + document = _append_raw(document, ¤t_size, """, strlen(""")); + accum = i + 1; + break; + case '\'': + if (i > accum) + { + document = _append_raw(document, ¤t_size, data + accum, i - accum); + } + document = _append_raw(document, ¤t_size, "'", strlen("'")); + accum = i + 1; + break; + case '<': + if (i > accum) + { + document = _append_raw(document, ¤t_size, data + accum, i - accum); + } + document = _append_raw(document, ¤t_size, "<", strlen("<")); + accum = i + 1; + break; + case '>': + if (i > accum) + { + document = _append_raw(document, ¤t_size, data + accum, i - accum); + } + document = _append_raw(document, ¤t_size, ">", strlen(">")); + accum = i + 1; + break; + case '&': + if (i > accum) + { + document = _append_raw(document, ¤t_size, data + accum, i - accum); + } + document = _append_raw(document, ¤t_size, "&", strlen("&")); + accum = i + 1; + break; + default: + break; + } + } + *out_size = current_size; + return document; +} + +static void _httpd_endpoint_app_index_file_read(tf_task_t* task, const char* path, int result, const void* data, void* user_data) +{ + app_blob_t* state = user_data; + if (result > 0) + { + char* replacement = tf_strdup("