diff --git a/CMakeLists.txt b/CMakeLists.txt index 7aa6080..c8a30b3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,6 +3,7 @@ idf_component_register( "src/romfs.c" "src/spifs.c" "src/HTTPServer.c" + "src/FileServer.c" "src/HTTPPrintSystem.c" "src/HTTPPostSystem.c" "src/Helpers.c" @@ -18,6 +19,8 @@ idf_component_register( INCLUDE_DIRS "." "include" "src" + + EMBED_FILES "upload_script.html" REQUIRES nvs_flash libespfs diff --git a/include/HTTPServer.h b/include/HTTPServer.h index ad7131a..2edfcab 100644 --- a/include/HTTPServer.h +++ b/include/HTTPServer.h @@ -67,6 +67,18 @@ typedef enum HTTP_IO_DONE_NOREFRESH } HTTP_IO_RESULT; + + +struct file_server_data +{ + /* Base path of file storage */ + char base_path[ESP_VFS_PATH_MAX + 1]; + char base_path2[ESP_VFS_PATH_MAX + 1]; + /* Scratch buffer for temporary storage during file transfer */ + char scratch[SCRATCH_BUFSIZE]; +/* Pointer to external POST handler*/ +}; + typedef struct { const char tag[16]; @@ -81,4 +93,9 @@ esp_err_t start_file_server(void); HTTP_IO_RESULT HTTPPostApp(httpd_req_t *req, const char *filename, char *PostData); int HTTPPrint(httpd_req_t *req, char* buf, char* var); + +esp_err_t http_resp_dir_html(httpd_req_t *req, const char *dirpath); +esp_err_t upload_post_handler(httpd_req_t *req); +esp_err_t delete_post_handler(httpd_req_t *req); + #endif /* COMPONENTS_WEB_GUI_APPLICATION_INCLUDE_HTTPSERVER_H_ */ diff --git a/src/FileServer.c b/src/FileServer.c index 3213230..4fe25c6 100644 --- a/src/FileServer.c +++ b/src/FileServer.c @@ -24,13 +24,47 @@ #include "HTTPServer.h" -static const char *TAG = "HTTPServer"; +static const char *TAG = "FileServer"; + +/* Copies the full path into destination buffer and returns + * pointer to path (skipping the preceding base path) */ +static const char* get_path_from_uri(char *dest, const char *base_path, + const char *uri, + size_t destsize) +{ + const size_t base_pathlen = strlen(base_path); + size_t pathlen = strlen(uri); + + const char *quest = strchr(uri, '?'); + if (quest) + { + pathlen = MIN(pathlen, quest - uri); + } + const char *hash = strchr(uri, '#'); + if (hash) + { + pathlen = MIN(pathlen, hash - uri); + } + + if (base_pathlen + pathlen + 1 > destsize) + { + /* Full path string won't fit into destination buffer */ + return NULL; + } + + /* Construct full path (base + path) */ + strcpy(dest, base_path); + strlcpy(dest + base_pathlen, uri, pathlen + 1); + + /* Return pointer to path, skipping the base */ + return dest + base_pathlen; +} /* Send HTTP response with a run-time generated html consisting of * a list of all files and folders under the requested path. * In case of SPIFFS this returns empty list when path is any * string other than '/', since SPIFFS doesn't support directories */ -static esp_err_t http_resp_dir_html(httpd_req_t *req, const char *dirpath) +esp_err_t http_resp_dir_html(httpd_req_t *req, const char *dirpath) { char entrypath[FILE_PATH_MAX]; char entrysize[16]; @@ -52,6 +86,8 @@ static esp_err_t http_resp_dir_html(httpd_req_t *req, const char *dirpath) return ESP_FAIL; } + + /* Send HTML file header */ httpd_resp_sendstr_chunk(req, ""); @@ -116,7 +152,7 @@ static esp_err_t http_resp_dir_html(httpd_req_t *req, const char *dirpath) } /* Handler to upload a file onto the server */ -static esp_err_t upload_post_handler(httpd_req_t *req) +esp_err_t upload_post_handler(httpd_req_t *req) { char filepath[FILE_PATH_MAX]; FILE *fd = NULL; @@ -124,7 +160,7 @@ static esp_err_t upload_post_handler(httpd_req_t *req) /* Skip leading "/upload" from URI to get filename */ /* Note sizeof() counts NULL termination hence the -1 */ - const char *filename = get_path_from_uri(filepath, ((struct file_server_data *)req->user_ctx)->base_path, + const char *filename = get_path_from_uri(filepath, ((struct file_server_data *)req->user_ctx)->base_path2, req->uri + sizeof("/upload") - 1, sizeof(filepath)); if (!filename) { /* Respond with 500 Internal Server Error */ @@ -230,14 +266,14 @@ static esp_err_t upload_post_handler(httpd_req_t *req) } /* Handler to delete a file from the server */ -static esp_err_t delete_post_handler(httpd_req_t *req) +esp_err_t delete_post_handler(httpd_req_t *req) { char filepath[FILE_PATH_MAX]; struct stat file_stat; /* Skip leading "/delete" from URI to get filename */ /* Note sizeof() counts NULL termination hence the -1 */ - const char *filename = get_path_from_uri(filepath, ((struct file_server_data *)req->user_ctx)->base_path, + const char *filename = get_path_from_uri(filepath, ((struct file_server_data *)req->user_ctx)->base_path2, req->uri + sizeof("/delete") - 1, sizeof(filepath)); if (!filename) { /* Respond with 500 Internal Server Error */ diff --git a/src/HTTPServer.c b/src/HTTPServer.c index 582d8e0..9c90587 100644 --- a/src/HTTPServer.c +++ b/src/HTTPServer.c @@ -29,16 +29,6 @@ const char GZIP_SIGN[] = { 0x1f, 0x8b, 0x08 }; static esp_err_t GETHandler(httpd_req_t *req); static esp_err_t CheckAuth(httpd_req_t *req); - - -struct file_server_data -{ - /* Base path of file storage */ - char base_path[ESP_VFS_PATH_MAX + 1]; - /* Scratch buffer for temporary storage during file transfer */ - char scratch[SCRATCH_BUFSIZE]; -/* Pointer to external POST handler*/ -}; struct file_server_data *server_data = NULL; httpd_handle_t server = NULL; static const char *TAG = "HTTPServer"; @@ -183,6 +173,7 @@ static esp_err_t POSTHandler(httpd_req_t *req) #if HTTP_SERVER_DEBUG_LEVEL > 0 ESP_LOGI(TAG, "POST request handle"); #endif + char *buf = ((struct file_server_data*) req->user_ctx)->scratch; int received; int remaining = req->content_len; @@ -215,10 +206,20 @@ static esp_err_t POSTHandler(httpd_req_t *req) if (received) { char filepath[FILE_PATH_MAX]; + const char *filename = get_path_from_uri(filepath, ((struct file_server_data*) req->user_ctx)->base_path, req->uri, sizeof(filepath)); + ESP_LOGW(TAG, "filepath %s", filepath); + + filename = get_path_from_uri(filepath, + ((struct file_server_data*) req->user_ctx)->base_path, + req->uri, + sizeof(filepath)); + + + if (!memcmp(filename, "/api", 4)) { @@ -295,6 +296,13 @@ static esp_err_t GETHandler(httpd_req_t *req) return ESP_OK; } + + if (!strcmp(filename, "/files.html")) + { + return http_resp_dir_html(req, "/data"); + } + + //check auth for all files except status.json if (strcmp(filename, "/status.json")) { @@ -528,6 +536,7 @@ esp_err_t start_file_server(void) return ESP_ERR_NO_MEM; } strlcpy(server_data->base_path, "/", sizeof("/")); + strlcpy(server_data->base_path2, "/data", sizeof("/data")); server = start_webserver(); return ESP_OK; } diff --git a/upload_script.html b/upload_script.html new file mode 100644 index 0000000..5513ee8 --- /dev/null +++ b/upload_script.html @@ -0,0 +1,80 @@ + + + +
+

ESP32 File Server

+
+ + + + + + + + + + +
+ + + +
+ + + + + +
+
+