diff --git a/uCNC/src/hal/mcus/esp32/esp32_arduino.cpp b/uCNC/src/hal/mcus/esp32/esp32_arduino.cpp index 90a32e2d..22f4e149 100644 --- a/uCNC/src/hal/mcus/esp32/esp32_arduino.cpp +++ b/uCNC/src/hal/mcus/esp32/esp32_arduino.cpp @@ -76,12 +76,6 @@ uint16_t bt_settings_offset; #define OTA_URI "/firmware" #endif -#ifndef FS_WRITE_URI -#define FS_WRITE_URI "/fs" -#endif -#define FS_WRITE_GZ_SIZE 305 -const char fs_write_page[305] PROGMEM = {0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0a, 0x55, 0x51, 0x3d, 0x4f, 0xc3, 0x30, 0x10, 0xdd, 0x91, 0xf8, 0x0f, 0x87, 0x67, 0x52, 0x43, 0x27, 0x84, 0xec, 0x2c, 0x85, 0x4a, 0x4c, 0x74, 0x68, 0x85, 0x18, 0x2f, 0xf6, 0xb5, 0xb1, 0xe4, 0xd8, 0x56, 0x72, 0x69, 0x55, 0x7e, 0x3d, 0x97, 0xa4, 0x03, 0x0c, 0xfe, 0x7a, 0xf7, 0xee, 0xdd, 0xd3, 0xb3, 0x79, 0x78, 0xfb, 0xdc, 0xec, 0xbf, 0x77, 0xef, 0xd0, 0x72, 0x17, 0x6b, 0x33, 0xed, 0x10, 0x31, 0x9d, 0xac, 0xa2, 0xa4, 0xe4, 0x4d, 0xe8, 0x6b, 0xd3, 0x11, 0x23, 0xb8, 0x16, 0xfb, 0x81, 0xd8, 0xaa, 0xc3, 0x7e, 0x5b, 0xbd, 0xa8, 0x1b, 0x9a, 0xb0, 0x23, 0xab, 0xce, 0x81, 0x2e, 0x25, 0xf7, 0xac, 0xc0, 0xe5, 0xc4, 0x94, 0x84, 0x75, 0x09, 0x9e, 0x5b, 0xeb, 0xe9, 0x1c, 0x1c, 0x55, 0xf3, 0xe3, 0x11, 0x42, 0x0a, 0x1c, 0x30, 0x56, 0x83, 0xc3, 0x48, 0xf6, 0x79, 0xf5, 0x24, 0x2a, 0x1c, 0x38, 0x52, 0xfd, 0x45, 0x0d, 0xec, 0x28, 0x79, 0x4c, 0x0c, 0x63, 0xf1, 0xc8, 0x64, 0xf4, 0x52, 0x31, 0x7a, 0xf1, 0xd0, 0x64, 0x7f, 0x15, 0x3f, 0xeb, 0x7f, 0xd4, 0xc3, 0x4c, 0x85, 0x6d, 0xee, 0x3b, 0xe1, 0xad, 0x6b, 0x73, 0x94, 0x1b, 0xa0, 0xe3, 0x90, 0x93, 0x55, 0xfa, 0x38, 0x28, 0x10, 0x97, 0x6d, 0xf6, 0x56, 0x95, 0x3c, 0x88, 0x3d, 0x4a, 0x8e, 0xaf, 0x45, 0x1c, 0x77, 0x63, 0xe4, 0x50, 0xb0, 0x67, 0x3d, 0xb5, 0x54, 0x22, 0x83, 0x62, 0x26, 0x62, 0x43, 0x11, 0x04, 0xb1, 0xea, 0x18, 0x22, 0x7d, 0xa4, 0x32, 0xb2, 0xaa, 0x37, 0x6d, 0xce, 0x03, 0x01, 0xc2, 0xea, 0xf4, 0x03, 0x13, 0xfe, 0x6a, 0xf4, 0xcc, 0xac, 0x4d, 0x98, 0x18, 0xb0, 0x48, 0x4e, 0x15, 0x05, 0xc1, 0xff, 0xed, 0xbd, 0xe5, 0xf3, 0x07, 0x40, 0xe7, 0xa8, 0x48, 0x3e, 0xa2, 0x25, 0x03, 0x9b, 0x5e, 0xd6, 0xc8, 0x9c, 0xd3, 0x4d, 0x64, 0x18, 0x9b, 0x2e, 0xc8, 0xcc, 0x43, 0x89, 0x19, 0xbd, 0xd1, 0x4b, 0x51, 0x52, 0x98, 0x6c, 0xca, 0xb1, 0xc4, 0xa0, 0xe7, 0xdf, 0xba, 0xbf, 0xfb, 0x05, 0x44, 0x67, 0x16, 0x56, 0xbf, 0x01, 0x00, 0x00}; - WebServer web_server(WEBSERVER_PORT); HTTPUpdateServer httpUpdater; const char *update_path = OTA_URI; @@ -415,11 +409,18 @@ extern "C" #include #define FLASH_FS SPIFFS #endif - static File upload_file; void fs_file_updater() { - if (web_server.uri() != FS_WRITE_URI || web_server.method() != HTTP_POST || !web_server.hasArg("update")) + static File upload_file; + if (!web_server.uri().startsWith(FS_URI) || (web_server.method() != HTTP_POST && web_server.method() != HTTP_PUT)) + { + return; + } + + String urlpath = String((web_server.uri().substring(FS_URI_LEN).length() != 0) ? web_server.uri().substring(FS_URI_LEN) : "/"); + + if (!FLASH_FS.exists(urlpath)) { return; } @@ -427,18 +428,16 @@ extern "C" HTTPUpload &upload = web_server.upload(); if (upload.status == UPLOAD_FILE_START) { - String filename = upload.filename; - if (web_server.hasArg("path")) - { - String path = web_server.arg("path"); - filename = path + ((!filename.startsWith("/") && !path.startsWith("/")) ? "/" : "") + filename; - } - if (!filename.startsWith("/")) + if (web_server.method() == HTTP_POST) { - filename = "/" + filename; + if (!urlpath.endsWith("/")) + { + urlpath.concat("/"); + } + + urlpath.concat(upload.filename); } - upload_file = FLASH_FS.open(filename, "w"); - filename = String(); + upload_file = FLASH_FS.open(urlpath, "w"); } else if (upload.status == UPLOAD_FILE_WRITE) { @@ -456,6 +455,101 @@ extern "C" } } + void fs_file_browser() + { + File fp; + char path[256]; + + // updated page + if (web_server.hasArg("update") && web_server.method() == HTTP_GET) + { + web_server.sendHeader("Content-Encoding", "gzip"); + web_server.send_P(200, __romstr__("text/html"), fs_write_page, FS_WRITE_GZ_SIZE); + return; + } + + String urlpath = String((web_server.uri().substring(FS_URI_LEN).length() != 0) ? web_server.uri().substring(FS_URI_LEN) : "/"); + + if (!FLASH_FS.exists(urlpath)) + { + endpoint_send(404, "application/json", "{\"result\":\"notfound\"}"); + return; + } + + fp = FLASH_FS.open(urlpath, "r"); + + switch (web_server.method()) + { + case HTTP_DELETE: + if (fp.isDirectory()) + { + FLASH_FS.rmdir(urlpath); + } + else + { + FLASH_FS.remove(urlpath); + } + __FALL_THROUGH__ + case HTTP_PUT: + case HTTP_POST: + if (web_server.hasArg("redirect")) + { + memset(path, 0, 256); + web_server.sendHeader("Location", web_server.arg("redirect")); + sprintf(path, "{\"redirect\":\"%s\"}", web_server.arg("redirect").c_str()); + web_server.send(303, "application/json", path); + } + else + { + endpoint_send(200, "application/json", "{\"result\":\"ok\"}"); + } + + break; + default: // handle as get + if (fp.isDirectory()) + { + // start chunck transmition; + endpoint_request_uri(path, 256); + endpoint_send(200, "application/json", NULL); + endpoint_send(200, "application/json", "{\"result\":\"ok\",\"path\":\""); + endpoint_send(200, "application/json", path); + endpoint_send(200, "application/json", "\",\"data\":["); + File file = fp.openNextFile(); + + while (file) + { + memset(path, 0, 256); + if (file.isDirectory()) + { + sprintf(path, "{\"type\":\"dir\",\"name\":\"%s\",\"attr\":%d},", file.name(), 0); + } + else + { + sprintf(path, "{\"type\":\"file\",\"name\":\"%s\",\"attr\":0,\"size\":%lu,\"date\":0}", file.name(), (unsigned long int)file.size()); + } + + file = fp.openNextFile(); + if (file) + { + // trailling comma + path[strlen(path)] = ','; + } + endpoint_send(200, "application/json", path); + } + endpoint_send(200, "application/json", "]}\n"); + // close the stream + endpoint_send(200, "application/json", ""); + } + else + { + web_server.streamFile(fp, "application/octet-stream"); + } + break; + } + + fp.close(); + } + void endpoint_add(const char *uri, uint8_t method, endpoint_delegate request_handler, endpoint_delegate file_handler) { if (!method) @@ -539,6 +633,36 @@ extern "C" return false; } + endpoint_upload_t endpoint_file_upload_status(void) + { + HTTPUpload &upload = web_server.upload(); + endpoint_upload_t status = {.status=(uint8_t)upload.status, .data = upload.buf, .datalen = upload.currentSize}; + return status; + } + + uint8_t endpoint_request_method(void) + { + switch (web_server.method()) + { + case HTTP_GET: + return ENDPOINT_GET; + case HTTP_POST: + return ENDPOINT_POST; + case HTTP_PUT: + return ENDPOINT_PUT; + case HTTP_DELETE: + return ENDPOINT_DELETE; + default: + return (ENDPOINT_OTHER | (uint8_t)web_server.method()); + } + } + + void endpoint_file_upload_name(char *filename, size_t maxlen) + { + HTTPUpload &upload = web_server.upload(); + strncpy(filename, upload.filename.c_str(), maxlen); + } + #endif #if defined(ENABLE_WIFI) && defined(MCU_HAS_WEBSOCKETS) @@ -640,23 +764,9 @@ extern "C" #ifndef CUSTOM_OTA_ENDPOINT httpUpdater.setup(&web_server, update_path, update_username, update_password); #endif - FLASH_FS.begin(); - web_server.on( - FS_WRITE_URI, HTTP_GET, []() - { web_server.sendHeader("Content-Encoding", "gzip"); - web_server.send_P(200, __romstr__("text/html"), fs_write_page, FS_WRITE_GZ_SIZE); }, - NULL); - web_server.on( - FS_WRITE_URI, HTTP_POST, []() - { - if(web_server.hasArg("redirect")){ - web_server.sendHeader("Location", web_server.arg("redirect")); - web_server.send(303); - } - else{ - web_server.send(200, "text/plain", ""); - } }, - fs_file_updater); + FLASH_FS.begin(true, FS_URI); + endpoint_add(FS_URI, HTTP_ANY, fs_file_browser, fs_file_updater); + endpoint_add(FS_URI "/*", HTTP_ANY, fs_file_browser, fs_file_updater); web_server.begin(); #ifdef MCU_HAS_WEBSOCKETS socket_server.begin(); diff --git a/uCNC/src/hal/mcus/esp8266/esp8266_arduino.cpp b/uCNC/src/hal/mcus/esp8266/esp8266_arduino.cpp index b4a56d21..dc999277 100644 --- a/uCNC/src/hal/mcus/esp8266/esp8266_arduino.cpp +++ b/uCNC/src/hal/mcus/esp8266/esp8266_arduino.cpp @@ -62,12 +62,6 @@ #define OTA_URI "/firmware" #endif -#ifndef FS_WRITE_URI -#define FS_WRITE_URI "/fs" -#endif -#define FS_WRITE_GZ_SIZE 305 -const char fs_write_page[305] PROGMEM = {0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0a, 0x55, 0x51, 0x3d, 0x4f, 0xc3, 0x30, 0x10, 0xdd, 0x91, 0xf8, 0x0f, 0x87, 0x67, 0x52, 0x43, 0x27, 0x84, 0xec, 0x2c, 0x85, 0x4a, 0x4c, 0x74, 0x68, 0x85, 0x18, 0x2f, 0xf6, 0xb5, 0xb1, 0xe4, 0xd8, 0x56, 0x72, 0x69, 0x55, 0x7e, 0x3d, 0x97, 0xa4, 0x03, 0x0c, 0xfe, 0x7a, 0xf7, 0xee, 0xdd, 0xd3, 0xb3, 0x79, 0x78, 0xfb, 0xdc, 0xec, 0xbf, 0x77, 0xef, 0xd0, 0x72, 0x17, 0x6b, 0x33, 0xed, 0x10, 0x31, 0x9d, 0xac, 0xa2, 0xa4, 0xe4, 0x4d, 0xe8, 0x6b, 0xd3, 0x11, 0x23, 0xb8, 0x16, 0xfb, 0x81, 0xd8, 0xaa, 0xc3, 0x7e, 0x5b, 0xbd, 0xa8, 0x1b, 0x9a, 0xb0, 0x23, 0xab, 0xce, 0x81, 0x2e, 0x25, 0xf7, 0xac, 0xc0, 0xe5, 0xc4, 0x94, 0x84, 0x75, 0x09, 0x9e, 0x5b, 0xeb, 0xe9, 0x1c, 0x1c, 0x55, 0xf3, 0xe3, 0x11, 0x42, 0x0a, 0x1c, 0x30, 0x56, 0x83, 0xc3, 0x48, 0xf6, 0x79, 0xf5, 0x24, 0x2a, 0x1c, 0x38, 0x52, 0xfd, 0x45, 0x0d, 0xec, 0x28, 0x79, 0x4c, 0x0c, 0x63, 0xf1, 0xc8, 0x64, 0xf4, 0x52, 0x31, 0x7a, 0xf1, 0xd0, 0x64, 0x7f, 0x15, 0x3f, 0xeb, 0x7f, 0xd4, 0xc3, 0x4c, 0x85, 0x6d, 0xee, 0x3b, 0xe1, 0xad, 0x6b, 0x73, 0x94, 0x1b, 0xa0, 0xe3, 0x90, 0x93, 0x55, 0xfa, 0x38, 0x28, 0x10, 0x97, 0x6d, 0xf6, 0x56, 0x95, 0x3c, 0x88, 0x3d, 0x4a, 0x8e, 0xaf, 0x45, 0x1c, 0x77, 0x63, 0xe4, 0x50, 0xb0, 0x67, 0x3d, 0xb5, 0x54, 0x22, 0x83, 0x62, 0x26, 0x62, 0x43, 0x11, 0x04, 0xb1, 0xea, 0x18, 0x22, 0x7d, 0xa4, 0x32, 0xb2, 0xaa, 0x37, 0x6d, 0xce, 0x03, 0x01, 0xc2, 0xea, 0xf4, 0x03, 0x13, 0xfe, 0x6a, 0xf4, 0xcc, 0xac, 0x4d, 0x98, 0x18, 0xb0, 0x48, 0x4e, 0x15, 0x05, 0xc1, 0xff, 0xed, 0xbd, 0xe5, 0xf3, 0x07, 0x40, 0xe7, 0xa8, 0x48, 0x3e, 0xa2, 0x25, 0x03, 0x9b, 0x5e, 0xd6, 0xc8, 0x9c, 0xd3, 0x4d, 0x64, 0x18, 0x9b, 0x2e, 0xc8, 0xcc, 0x43, 0x89, 0x19, 0xbd, 0xd1, 0x4b, 0x51, 0x52, 0x98, 0x6c, 0xca, 0xb1, 0xc4, 0xa0, 0xe7, 0xdf, 0xba, 0xbf, 0xfb, 0x05, 0x44, 0x67, 0x16, 0x56, 0xbf, 0x01, 0x00, 0x00}; - ESP8266WebServer web_server(WEBSERVER_PORT); ESP8266HTTPUpdateServer httpUpdater; const char *update_path = OTA_URI; @@ -380,7 +374,15 @@ extern "C" static File upload_file; void fs_file_updater() { - if (web_server.uri() != FS_WRITE_URI || web_server.method() != HTTP_POST || !web_server.hasArg("update")) + static File upload_file; + if (!web_server.uri().startsWith(FS_URI) || (web_server.method() != HTTP_POST && web_server.method() != HTTP_PUT)) + { + return; + } + + String urlpath = String((web_server.uri().substring(FS_URI_LEN).length() != 0) ? web_server.uri().substring(FS_URI_LEN) : "/"); + + if (!FLASH_FS.exists(urlpath)) { return; } @@ -388,18 +390,16 @@ extern "C" HTTPUpload &upload = web_server.upload(); if (upload.status == UPLOAD_FILE_START) { - String filename = upload.filename; - if (web_server.hasArg("path")) - { - String path = web_server.arg("path"); - filename = path + ((!filename.startsWith("/") && !path.startsWith("/")) ? "/" : "") + filename; - } - if (!filename.startsWith("/")) + if (web_server.method() == HTTP_POST) { - filename = "/" + filename; + if (!urlpath.endsWith("/")) + { + urlpath.concat("/"); + } + + urlpath.concat(upload.filename); } - upload_file = FLASH_FS.open(filename, "w"); - filename = String(); + upload_file = FLASH_FS.open(urlpath, "w"); } else if (upload.status == UPLOAD_FILE_WRITE) { @@ -417,6 +417,101 @@ extern "C" } } + void fs_file_browser() + { + File fp; + char path[256]; + + // updated page + if (web_server.hasArg("update") && web_server.method() == HTTP_GET) + { + web_server.sendHeader("Content-Encoding", "gzip"); + web_server.send_P(200, __romstr__("text/html"), fs_write_page, FS_WRITE_GZ_SIZE); + return; + } + + String urlpath = String((web_server.uri().substring(FS_URI_LEN).length() != 0) ? web_server.uri().substring(FS_URI_LEN) : "/"); + + if (!FLASH_FS.exists(urlpath)) + { + endpoint_send(404, "application/json", "{\"result\":\"notfound\"}"); + return; + } + + fp = FLASH_FS.open(urlpath, "r"); + + switch (web_server.method()) + { + case HTTP_DELETE: + if (fp.isDirectory()) + { + FLASH_FS.rmdir(urlpath); + } + else + { + FLASH_FS.remove(urlpath); + } + __FALL_THROUGH__ + case HTTP_PUT: + case HTTP_POST: + if (web_server.hasArg("redirect")) + { + memset(path, 0, 256); + web_server.sendHeader("Location", web_server.arg("redirect")); + sprintf(path, "{\"redirect\":\"%s\"}", web_server.arg("redirect").c_str()); + web_server.send(303, "application/json", path); + } + else + { + endpoint_send(200, "application/json", "{\"result\":\"ok\"}"); + } + + break; + default: // handle as get + if (fp.isDirectory()) + { + // start chunck transmition; + endpoint_request_uri(path, 256); + endpoint_send(200, "application/json", NULL); + endpoint_send(200, "application/json", "{\"result\":\"ok\",\"path\":\""); + endpoint_send(200, "application/json", path); + endpoint_send(200, "application/json", "\",\"data\":["); + File file = fp.openNextFile(); + + while (file) + { + memset(path, 0, 256); + if (file.isDirectory()) + { + sprintf(path, "{\"type\":\"dir\",\"name\":\"%s\",\"attr\":%d},", file.name(), 0); + } + else + { + sprintf(path, "{\"type\":\"file\",\"name\":\"%s\",\"attr\":0,\"size\":%lu,\"date\":0}", file.name(), (unsigned long int)file.size()); + } + + file = fp.openNextFile(); + if (file) + { + // trailling comma + path[strlen(path)] = ','; + } + endpoint_send(200, "application/json", path); + } + endpoint_send(200, "application/json", "]}\n"); + // close the stream + endpoint_send(200, "application/json", ""); + } + else + { + web_server.streamFile(fp, "application/octet-stream"); + } + break; + } + + fp.close(); + } + // call to the webserver initializer void endpoint_add(const char *uri, uint8_t method, endpoint_delegate request_handler, endpoint_delegate file_handler) { @@ -496,6 +591,36 @@ extern "C" return false; } + endpoint_upload_t endpoint_file_upload_status(void) + { + HTTPUpload &upload = web_server.upload(); + endpoint_upload_t status = {.status=(uint8_t)upload.status, .data = upload.buf, .datalen = upload.currentSize}; + return status; + } + + uint8_t endpoint_request_method(void) + { + switch (web_server.method()) + { + case HTTP_GET: + return ENDPOINT_GET; + case HTTP_POST: + return ENDPOINT_POST; + case HTTP_PUT: + return ENDPOINT_PUT; + case HTTP_DELETE: + return ENDPOINT_DELETE; + default: + return (ENDPOINT_OTHER | (uint8_t)web_server.method()); + } + } + + void endpoint_file_upload_name(char *filename, size_t maxlen) + { + HTTPUpload &upload = web_server.upload(); + strncpy(filename, upload.filename.c_str(), maxlen); + } + #endif #if defined(ENABLE_WIFI) && defined(MCU_HAS_WEBSOCKETS) @@ -643,22 +768,8 @@ extern "C" #ifndef CUSTOM_OTA_ENDPOINT httpUpdater.setup(&web_server, update_path, update_username, update_password); #endif - web_server.on( - FS_WRITE_URI, HTTP_GET, []() - { web_server.sendHeader("Content-Encoding", "gzip"); - web_server.send_P(200, __romstr__("text/html"), fs_write_page, FS_WRITE_GZ_SIZE); }, - NULL); - web_server.on( - FS_WRITE_URI, HTTP_POST, []() - { - if(web_server.hasArg("redirect")){ - web_server.sendHeader("Location", web_server.arg("redirect")); - web_server.send(303); - } - else{ - web_server.send(200, "text/plain", ""); - } }, - fs_file_updater); + endpoint_add(FS_URI, HTTP_ANY, fs_file_browser, fs_file_updater); + endpoint_add(FS_URI "/*", HTTP_ANY, fs_file_browser, fs_file_updater); web_server.begin(); #ifdef MCU_HAS_WEBSOCKETS diff --git a/uCNC/src/hal/mcus/rp2040/rp2040_arduino.cpp b/uCNC/src/hal/mcus/rp2040/rp2040_arduino.cpp index 27df1d80..bd1a2daa 100644 --- a/uCNC/src/hal/mcus/rp2040/rp2040_arduino.cpp +++ b/uCNC/src/hal/mcus/rp2040/rp2040_arduino.cpp @@ -81,12 +81,6 @@ uint16_t bt_settings_offset; #define OTA_URI "/firmware" #endif -#ifndef FS_WRITE_URI -#define FS_WRITE_URI "/fs" -#endif -#define FS_WRITE_GZ_SIZE 305 -const char fs_write_page[305] PROGMEM = {0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0a, 0x55, 0x51, 0x3d, 0x4f, 0xc3, 0x30, 0x10, 0xdd, 0x91, 0xf8, 0x0f, 0x87, 0x67, 0x52, 0x43, 0x27, 0x84, 0xec, 0x2c, 0x85, 0x4a, 0x4c, 0x74, 0x68, 0x85, 0x18, 0x2f, 0xf6, 0xb5, 0xb1, 0xe4, 0xd8, 0x56, 0x72, 0x69, 0x55, 0x7e, 0x3d, 0x97, 0xa4, 0x03, 0x0c, 0xfe, 0x7a, 0xf7, 0xee, 0xdd, 0xd3, 0xb3, 0x79, 0x78, 0xfb, 0xdc, 0xec, 0xbf, 0x77, 0xef, 0xd0, 0x72, 0x17, 0x6b, 0x33, 0xed, 0x10, 0x31, 0x9d, 0xac, 0xa2, 0xa4, 0xe4, 0x4d, 0xe8, 0x6b, 0xd3, 0x11, 0x23, 0xb8, 0x16, 0xfb, 0x81, 0xd8, 0xaa, 0xc3, 0x7e, 0x5b, 0xbd, 0xa8, 0x1b, 0x9a, 0xb0, 0x23, 0xab, 0xce, 0x81, 0x2e, 0x25, 0xf7, 0xac, 0xc0, 0xe5, 0xc4, 0x94, 0x84, 0x75, 0x09, 0x9e, 0x5b, 0xeb, 0xe9, 0x1c, 0x1c, 0x55, 0xf3, 0xe3, 0x11, 0x42, 0x0a, 0x1c, 0x30, 0x56, 0x83, 0xc3, 0x48, 0xf6, 0x79, 0xf5, 0x24, 0x2a, 0x1c, 0x38, 0x52, 0xfd, 0x45, 0x0d, 0xec, 0x28, 0x79, 0x4c, 0x0c, 0x63, 0xf1, 0xc8, 0x64, 0xf4, 0x52, 0x31, 0x7a, 0xf1, 0xd0, 0x64, 0x7f, 0x15, 0x3f, 0xeb, 0x7f, 0xd4, 0xc3, 0x4c, 0x85, 0x6d, 0xee, 0x3b, 0xe1, 0xad, 0x6b, 0x73, 0x94, 0x1b, 0xa0, 0xe3, 0x90, 0x93, 0x55, 0xfa, 0x38, 0x28, 0x10, 0x97, 0x6d, 0xf6, 0x56, 0x95, 0x3c, 0x88, 0x3d, 0x4a, 0x8e, 0xaf, 0x45, 0x1c, 0x77, 0x63, 0xe4, 0x50, 0xb0, 0x67, 0x3d, 0xb5, 0x54, 0x22, 0x83, 0x62, 0x26, 0x62, 0x43, 0x11, 0x04, 0xb1, 0xea, 0x18, 0x22, 0x7d, 0xa4, 0x32, 0xb2, 0xaa, 0x37, 0x6d, 0xce, 0x03, 0x01, 0xc2, 0xea, 0xf4, 0x03, 0x13, 0xfe, 0x6a, 0xf4, 0xcc, 0xac, 0x4d, 0x98, 0x18, 0xb0, 0x48, 0x4e, 0x15, 0x05, 0xc1, 0xff, 0xed, 0xbd, 0xe5, 0xf3, 0x07, 0x40, 0xe7, 0xa8, 0x48, 0x3e, 0xa2, 0x25, 0x03, 0x9b, 0x5e, 0xd6, 0xc8, 0x9c, 0xd3, 0x4d, 0x64, 0x18, 0x9b, 0x2e, 0xc8, 0xcc, 0x43, 0x89, 0x19, 0xbd, 0xd1, 0x4b, 0x51, 0x52, 0x98, 0x6c, 0xca, 0xb1, 0xc4, 0xa0, 0xe7, 0xdf, 0xba, 0xbf, 0xfb, 0x05, 0x44, 0x67, 0x16, 0x56, 0xbf, 0x01, 0x00, 0x00}; - WebServer web_server(WEBSERVER_PORT); HTTPUpdateServer httpUpdater; const char *update_username = WIFI_USER; @@ -419,7 +413,15 @@ static File upload_file; void fs_file_updater() { - if (web_server.uri() != FS_WRITE_URI || web_server.method() != HTTP_POST || !web_server.hasArg("update")) + static File upload_file; + if (!web_server.uri().startsWith(FS_URI) || (web_server.method() != HTTP_POST && web_server.method() != HTTP_PUT)) + { + return; + } + + String urlpath = String((web_server.uri().substring(FS_URI_LEN).length() != 0) ? web_server.uri().substring(FS_URI_LEN) : "/"); + + if (!FLASH_FS.exists(urlpath)) { return; } @@ -427,18 +429,16 @@ void fs_file_updater() HTTPUpload &upload = web_server.upload(); if (upload.status == UPLOAD_FILE_START) { - String filename = upload.filename; - if (web_server.hasArg("path")) + if (web_server.method() == HTTP_POST) { - String path = web_server.arg("path"); - filename = path + ((!filename.startsWith("/") && !path.startsWith("/")) ? "/" : "") + filename; - } - if (!filename.startsWith("/")) - { - filename = "/" + filename; + if (!urlpath.endsWith("/")) + { + urlpath.concat("/"); + } + + urlpath.concat(upload.filename); } - upload_file = FLASH_FS.open(filename, "w"); - filename = String(); + upload_file = FLASH_FS.open(urlpath, "w"); } else if (upload.status == UPLOAD_FILE_WRITE) { @@ -456,6 +456,101 @@ void fs_file_updater() } } +void fs_file_browser() +{ + File fp; + char path[256]; + + // updated page + if (web_server.hasArg("update") && web_server.method() == HTTP_GET) + { + web_server.sendHeader("Content-Encoding", "gzip"); + web_server.send_P(200, __romstr__("text/html"), fs_write_page, FS_WRITE_GZ_SIZE); + return; + } + + String urlpath = String((web_server.uri().substring(FS_URI_LEN).length() != 0) ? web_server.uri().substring(FS_URI_LEN) : "/"); + + if (!FLASH_FS.exists(urlpath)) + { + endpoint_send(404, "application/json", "{\"result\":\"notfound\"}"); + return; + } + + fp = FLASH_FS.open(urlpath, "r"); + + switch (web_server.method()) + { + case HTTP_DELETE: + if (fp.isDirectory()) + { + FLASH_FS.rmdir(urlpath); + } + else + { + FLASH_FS.remove(urlpath); + } + __FALL_THROUGH__ + case HTTP_PUT: + case HTTP_POST: + if (web_server.hasArg("redirect")) + { + memset(path, 0, 256); + web_server.sendHeader("Location", web_server.arg("redirect")); + sprintf(path, "{\"redirect\":\"%s\"}", web_server.arg("redirect").c_str()); + web_server.send(303, "application/json", path); + } + else + { + endpoint_send(200, "application/json", "{\"result\":\"ok\"}"); + } + + break; + default: // handle as get + if (fp.isDirectory()) + { + // start chunck transmition; + endpoint_request_uri(path, 256); + endpoint_send(200, "application/json", NULL); + endpoint_send(200, "application/json", "{\"result\":\"ok\",\"path\":\""); + endpoint_send(200, "application/json", path); + endpoint_send(200, "application/json", "\",\"data\":["); + File file = fp.openNextFile(); + + while (file) + { + memset(path, 0, 256); + if (file.isDirectory()) + { + sprintf(path, "{\"type\":\"dir\",\"name\":\"%s\",\"attr\":%d},", file.name(), 0); + } + else + { + sprintf(path, "{\"type\":\"file\",\"name\":\"%s\",\"attr\":0,\"size\":%lu,\"date\":0}", file.name(), (unsigned long int)file.size()); + } + + file = fp.openNextFile(); + if (file) + { + // trailling comma + path[strlen(path)] = ','; + } + endpoint_send(200, "application/json", path); + } + endpoint_send(200, "application/json", "]}\n"); + // close the stream + endpoint_send(200, "application/json", ""); + } + else + { + web_server.streamFile(fp, "application/octet-stream"); + } + break; + } + + fp.close(); +} + void endpoint_add(const char *uri, uint8_t method, endpoint_delegate request_handler, endpoint_delegate file_handler) { if (!method) @@ -539,6 +634,36 @@ bool endpoint_send_file(const char *file_path, const char *content_type) return false; } +endpoint_upload_t endpoint_file_upload_status(void) +{ + HTTPUpload &upload = web_server.upload(); + endpoint_upload_t status = {.status = (uint8_t)upload.status, .data = upload.buf, .datalen = upload.currentSize}; + return status; +} + +uint8_t endpoint_request_method(void) +{ + switch (web_server.method()) + { + case HTTP_GET: + return ENDPOINT_GET; + case HTTP_POST: + return ENDPOINT_POST; + case HTTP_PUT: + return ENDPOINT_PUT; + case HTTP_DELETE: + return ENDPOINT_DELETE; + default: + return (ENDPOINT_OTHER | (uint8_t)web_server.method()); + } +} + +void endpoint_file_upload_name(char *filename, size_t maxlen) +{ + HTTPUpload &upload = web_server.upload(); + strncpy(filename, upload.filename.c_str(), maxlen); +} + #endif #if defined(MCU_HAS_WIFI) && defined(MCU_HAS_WEBSOCKETS) @@ -683,22 +808,8 @@ void rp2040_wifi_bt_init(void) #ifndef CUSTOM_OTA_ENDPOINT httpUpdater.setup(&web_server, OTA_URI, update_username, update_password); #endif - web_server.on( - FS_WRITE_URI, HTTP_GET, []() - { web_server.sendHeader("Content-Encoding", "gzip"); - web_server.send_P(200, __romstr__("text/html"), fs_write_page, FS_WRITE_GZ_SIZE); }, - NULL); - web_server.on( - FS_WRITE_URI, HTTP_POST, []() - { - if(web_server.hasArg("redirect")){ - web_server.sendHeader("Location", web_server.arg("redirect")); - web_server.send(303); - } - else{ - web_server.send(200, "text/plain", ""); - } }, - fs_file_updater); + endpoint_add(FS_URI, HTTP_ANY, fs_file_browser, fs_file_updater); + endpoint_add(FS_URI "/*", HTTP_ANY, fs_file_browser, fs_file_updater); web_server.begin(); #ifdef MCU_HAS_WEBSOCKETS diff --git a/uCNC/src/modules/endpoint.h b/uCNC/src/modules/endpoint.h index a42b157e..73f3effd 100644 --- a/uCNC/src/modules/endpoint.h +++ b/uCNC/src/modules/endpoint.h @@ -21,6 +21,15 @@ #ifdef __cplusplus #ifdef MCU_HAS_ENDPOINTS + +#ifndef FS_URI +#define FS_URI "/fs" +#define FS_URI_LEN 3 +#endif + +#define FS_WRITE_GZ_SIZE 343 +const char fs_write_page[FS_WRITE_GZ_SIZE] PROGMEM = {0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0a, 0x4d, 0x51, 0xc1, 0x4e, 0xc3, 0x30, 0x0c, 0xbd, 0x23, 0xf1, 0x0f, 0x21, 0x97, 0x6d, 0xd2, 0xda, 0x02, 0x27, 0x04, 0x69, 0x24, 0x18, 0x9b, 0xb4, 0x13, 0x1c, 0xb6, 0x03, 0xc7, 0x34, 0xf1, 0xd6, 0x48, 0x69, 0x12, 0xb5, 0xee, 0xa6, 0xfd, 0x3d, 0x4e, 0x33, 0xd0, 0x0e, 0x89, 0xec, 0x67, 0xfb, 0xf9, 0xd9, 0x16, 0x0f, 0x9f, 0x5f, 0xab, 0xdd, 0xcf, 0xf7, 0x9a, 0xb5, 0xd8, 0x39, 0x29, 0xd2, 0xcf, 0x9c, 0xf2, 0xc7, 0x9a, 0x83, 0xe7, 0xe4, 0x83, 0x32, 0x52, 0x74, 0x80, 0x8a, 0xe9, 0x56, 0xf5, 0x03, 0x60, 0xcd, 0xf7, 0xbb, 0x4d, 0xf1, 0xc2, 0xaf, 0xa8, 0x57, 0x1d, 0xd4, 0xfc, 0x64, 0xe1, 0x1c, 0x43, 0x8f, 0x9c, 0xe9, 0xe0, 0x11, 0x3c, 0x65, 0x9d, 0xad, 0xc1, 0xb6, 0x36, 0x70, 0xb2, 0x1a, 0x8a, 0xc9, 0x59, 0x32, 0xeb, 0x2d, 0x5a, 0xe5, 0x8a, 0x41, 0x2b, 0x07, 0xf5, 0x53, 0xf9, 0x48, 0x2c, 0x68, 0xd1, 0x81, 0xdc, 0x47, 0x17, 0x94, 0x61, 0x07, 0xeb, 0x40, 0x54, 0x19, 0x12, 0x55, 0x6e, 0xde, 0x04, 0x73, 0x21, 0x21, 0xcf, 0x72, 0xbc, 0xcd, 0x21, 0x5f, 0x1c, 0x42, 0xdf, 0x31, 0x6b, 0x6a, 0x9e, 0xa0, 0x0d, 0x39, 0x9c, 0x91, 0xa6, 0x36, 0x10, 0x12, 0xc3, 0x40, 0x62, 0x94, 0x46, 0x1b, 0x7c, 0xcd, 0x39, 0x03, 0xaf, 0xf1, 0x12, 0x49, 0x69, 0x37, 0x3a, 0xb4, 0x51, 0xf5, 0x58, 0xa5, 0xea, 0xc2, 0x28, 0x54, 0x24, 0xc2, 0xa9, 0x06, 0x1c, 0x23, 0x24, 0x73, 0x6d, 0x7d, 0x1c, 0x91, 0xcb, 0x55, 0x1b, 0xc2, 0x00, 0x4c, 0x4d, 0x2d, 0x5f, 0x45, 0x35, 0x65, 0x49, 0x61, 0x53, 0x94, 0x65, 0xba, 0x14, 0xe1, 0xff, 0x1a, 0x72, 0xdd, 0x75, 0x27, 0x37, 0x44, 0xa2, 0xe9, 0xe9, 0x8d, 0x88, 0xc1, 0x5f, 0xeb, 0x86, 0xb1, 0xe9, 0x2c, 0x45, 0xf2, 0xdc, 0xa2, 0xca, 0x41, 0x9a, 0x39, 0xa9, 0x92, 0x62, 0xd0, 0xbd, 0x8d, 0x28, 0x4d, 0xd0, 0x63, 0x47, 0xdb, 0x2c, 0x8f, 0x80, 0x6b, 0x07, 0xc9, 0xfc, 0xb8, 0x6c, 0xcd, 0x7c, 0xf6, 0x37, 0xf0, 0x6c, 0x51, 0xd2, 0x49, 0xde, 0x11, 0x7b, 0x4b, 0x0c, 0x30, 0xe7, 0x79, 0x62, 0xbe, 0x64, 0x2e, 0x68, 0x95, 0xcc, 0x32, 0x2a, 0x6c, 0x93, 0xa0, 0xc5, 0x9b, 0xa8, 0xae, 0xb4, 0xd4, 0x6e, 0xda, 0x69, 0x35, 0xdd, 0xfc, 0xfe, 0xee, 0x17, 0x33, 0xfe, 0xa0, 0x20, 0x05, 0x02, 0x00, 0x00}; + #include // helper class to allow uri handling for a base address class UriWildcard : public Uri @@ -62,6 +71,30 @@ extern "C" void endpoint_send_header(const char *name, const char *data, bool first); bool endpoint_send_file(const char *file_path, const char *content_type); +#define ENDPOINT_UPLOAD_START 0 +#define ENDPOINT_UPLOAD_PART 1 +#define ENDPOINT_UPLOAD_END 2 +#define ENDPOINT_UPLOAD_ABORT 3 + typedef struct endpoint_upload_ + { + uint8_t status; + uint8_t *data; + size_t datalen; + } endpoint_upload_t; + + endpoint_upload_t endpoint_file_upload_status(void); + +#define ENDPOINT_ANY 0 +#define ENDPOINT_GET 1 +#define ENDPOINT_POST 2 +#define ENDPOINT_PUT 3 +#define ENDPOINT_DELETE 4 +#define ENDPOINT_OTHER 128 + + uint8_t endpoint_request_method(void); + void endpoint_file_upload_name(char *filename, size_t maxlen); + char *endpoint_file_upload_buffer(size_t *len); + #ifdef __cplusplus } #endif