diff --git a/code/components/jomjol_fileserver_ota/server_file.cpp b/code/components/jomjol_fileserver_ota/server_file.cpp index eb69913a..137aeb5f 100644 --- a/code/components/jomjol_fileserver_ota/server_file.cpp +++ b/code/components/jomjol_fileserver_ota/server_file.cpp @@ -6,11 +6,8 @@ software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */ - - #include "server_file.h" - #include #include #include @@ -58,7 +55,6 @@ struct file_server_data { char scratch[SERVER_FILER_SCRATCH_BUFSIZE]; }; - #include #include #include @@ -67,11 +63,9 @@ using namespace std; string SUFFIX_ZW = "_0xge"; - static esp_err_t send_logfile(httpd_req_t *req, bool send_full_file); static esp_err_t send_datafile(httpd_req_t *req, bool send_full_file); - esp_err_t get_numbers_file_handler(httpd_req_t *req) { std::string ret = flowctrl.getNumbersName(); @@ -87,7 +81,6 @@ esp_err_t get_numbers_file_handler(httpd_req_t *req) return ESP_OK; } - esp_err_t get_data_file_handler(httpd_req_t *req) { struct dirent *entry; @@ -131,7 +124,6 @@ esp_err_t get_data_file_handler(httpd_req_t *req) return ESP_OK; } - esp_err_t get_tflite_file_handler(httpd_req_t *req) { struct dirent *entry; @@ -175,12 +167,11 @@ esp_err_t get_tflite_file_handler(httpd_req_t *req) return ESP_OK; } - /* 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, const char* uripath, bool readonly) +static esp_err_t http_resp_dir_html(httpd_req_t *req, const char *dirpath, const char *uripath, bool readonly) { char entrypath[FILE_PATH_MAX]; char entrysize[16]; @@ -192,82 +183,85 @@ static esp_err_t http_resp_dir_html(httpd_req_t *req, const char *dirpath, const char dirpath_corrected[FILE_PATH_MAX]; strcpy(dirpath_corrected, dirpath); - file_server_data * server_data = (file_server_data *) req->user_ctx; - if ((strlen(dirpath_corrected)-1) > strlen(server_data->base_path)) // if dirpath is not mountpoint, the last "\" needs to be removed - dirpath_corrected[strlen(dirpath_corrected)-1] = '\0'; + file_server_data *server_data = (file_server_data *)req->user_ctx; - DIR *dir = opendir(dirpath_corrected); + if ((strlen(dirpath_corrected) - 1) > strlen(server_data->base_path)) { + // if dirpath is not mountpoint, the last "\" needs to be removed + dirpath_corrected[strlen(dirpath_corrected) - 1] = '\0'; + } + + DIR *pdir = opendir(dirpath_corrected); const size_t dirpath_len = strlen(dirpath); ESP_LOGD(TAG, "Dirpath: <%s>, Pathlength: %d", dirpath, dirpath_len); - /* Retrieve the base path of file storage to construct the full path */ + // Retrieve the base path of file storage to construct the full path strlcpy(entrypath, dirpath, sizeof(entrypath)); ESP_LOGD(TAG, "entrypath: <%s>", entrypath); - if (!dir) { + if (!pdir) { LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Failed to stat dir: " + std::string(dirpath) + "!"); - /* Respond with 404 Not Found */ + // Respond with 404 Not Found httpd_resp_send_err(req, HTTPD_404_NOT_FOUND, get404()); return ESP_FAIL; } httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); - /* Send HTML file header */ - httpd_resp_sendstr_chunk(req, ""); + // Send HTML file header + httpd_resp_sendstr_chunk(req, ""); + httpd_resp_sendstr_chunk(req, ""); + httpd_resp_sendstr_chunk(req, ""); + httpd_resp_sendstr_chunk(req, ""); + httpd_resp_sendstr_chunk(req, ""); -///////////////////////////////////////////////// - if (!readonly) { - FILE *fd = fopen("/sdcard/html/file_server.html", "r"); - char *chunk = ((struct file_server_data *)req->user_ctx)->scratch; - size_t chunksize; - do { - chunksize = fread(chunk, 1, SERVER_FILER_SCRATCH_BUFSIZE, fd); - // ESP_LOGD(TAG, "Chunksize %d", chunksize); - if (chunksize > 0){ - if (httpd_resp_send_chunk(req, chunk, chunksize) != ESP_OK) { - fclose(fd); - LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "File sending failed!"); - return ESP_FAIL; - } - } - } while (chunksize != 0); - fclose(fd); - // ESP_LOGI(TAG, "File sending complete"); - } -/////////////////////////////// + httpd_resp_sendstr_chunk(req, ""); + + httpd_resp_sendstr_chunk(req, ""); + httpd_resp_sendstr_chunk(req, "" + ""); + httpd_resp_sendstr_chunk(req, "

Fileserver

" + "" + "
" + "" + "
" + "" + "
" + "" + "
"); + + httpd_resp_sendstr_chunk(req, ""); + httpd_resp_sendstr_chunk(req, ""); std::string _zw = std::string(dirpath); _zw = _zw.substr(8, _zw.length() - 8); - _zw = "/delete/" + _zw + "?task=deldircontent"; + _zw = "/delete/" + _zw + "?task=deldircontent"; + // Send file-list table definition and column labels + httpd_resp_sendstr_chunk(req, "" + "" + ""); - /* Send file-list table definition and column labels */ - httpd_resp_sendstr_chunk(req, - "
NameTypeSize
" - "" - ""); if (!readonly) { - httpd_resp_sendstr_chunk(req, ""); + httpd_resp_sendstr_chunk(req, "\">"); } + httpd_resp_sendstr_chunk(req, "\n"); - /* Iterate over all files / folders and fetch their names and sizes */ - while ((entry = readdir(dir)) != NULL) { - if (strcmp("wlan.ini", entry->d_name) != 0 ) // wlan.ini soll nicht angezeigt werden! - { + // Iterate over all files / folders and fetch their names and sizes + while ((entry = readdir(pdir)) != NULL) { + // wlan.ini soll nicht angezeigt werden! + if (strcmp("wlan.ini", entry->d_name) != 0) { entrytype = (entry->d_type == DT_DIR ? "directory" : "file"); strlcpy(entrypath + dirpath_len, entry->d_name, sizeof(entrypath) - dirpath_len); ESP_LOGD(TAG, "Entrypath: %s", entrypath); + if (stat(entrypath, &entry_stat) == -1) { - LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Failed to stat " + string(entrytype) + ": " + string(entry->d_name)); + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Failed to stat " + std::string(entrytype) + ": " + std::string(entry->d_name)); continue; } @@ -283,22 +277,25 @@ static esp_err_t http_resp_dir_html(httpd_req_t *req, const char *dirpath, const } } - ESP_LOGI(TAG, "Found %s: %s (%s bytes)", entrytype, entry->d_name, entrysize); + ESP_LOGD(TAG, "Found %s: %s (%s bytes)", entrytype, entry->d_name, entrysize); - /* Send chunk of HTML file containing table entries with file name and size */ + // Send chunk of HTML file containing table entries with file name and size httpd_resp_sendstr_chunk(req, "\n"); } } - closedir(dir); - /* Finish the file list table */ + closedir(pdir); + + // Finish the file list table httpd_resp_sendstr_chunk(req, "
NameTypeSize" - "
" - "
d_name); + if (entry->d_type == DT_DIR) { httpd_resp_sendstr_chunk(req, "/"); } + httpd_resp_sendstr_chunk(req, "\">"); httpd_resp_sendstr_chunk(req, entry->d_name); httpd_resp_sendstr_chunk(req, ""); httpd_resp_sendstr_chunk(req, entrytype); httpd_resp_sendstr_chunk(req, ""); httpd_resp_sendstr_chunk(req, entrysize); + if (!readonly) { httpd_resp_sendstr_chunk(req, ""); httpd_resp_sendstr_chunk(req, "
d_name); httpd_resp_sendstr_chunk(req, "\">
"); } + httpd_resp_sendstr_chunk(req, "
"); - /* Send remaining chunk of HTML file to complete it */ + // Send remaining chunk of HTML file to complete it httpd_resp_sendstr_chunk(req, ""); - /* Send empty chunk to signal HTTP response completion */ + // Send empty chunk to signal HTTP response completion httpd_resp_sendstr_chunk(req, NULL); return ESP_OK; } -/* -#define IS_FILE_EXT(filename, ext) \ - (strcasecmp(&filename[strlen(filename) - sizeof(ext) + 1], ext) == 0) -*/ static esp_err_t logfileact_get_full_handler(httpd_req_t *req) { return send_logfile(req, true); } - static esp_err_t logfileact_get_last_part_handler(httpd_req_t *req) { return send_logfile(req, false); } @@ -339,7 +333,6 @@ static esp_err_t datafileact_get_full_handler(httpd_req_t *req) { return send_datafile(req, true); } - static esp_err_t datafileact_get_last_part_handler(httpd_req_t *req) { return send_datafile(req, false); } @@ -424,7 +417,6 @@ static esp_err_t send_datafile(httpd_req_t *req, bool send_full_file) return ESP_OK; } - static esp_err_t send_logfile(httpd_req_t *req, bool send_full_file) { LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "log_get_last_part_handler"); @@ -510,7 +502,6 @@ static esp_err_t send_logfile(httpd_req_t *req, bool send_full_file) return ESP_OK; } - /* Handler to download a file kept on the server */ static esp_err_t download_get_handler(httpd_req_t *req) { @@ -528,7 +519,6 @@ static esp_err_t download_get_handler(httpd_req_t *req) // filename = get_path_from_uri(filepath, ((struct file_server_data *)req->user_ctx)->base_path, // req->uri, sizeof(filepath)); - if (!filename) { LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Filename is too long"); /* Respond with 414 Error */ @@ -759,7 +749,6 @@ static esp_err_t upload_post_handler(httpd_req_t *req) httpd_resp_set_hdr(req, "Location", directory.c_str()); httpd_resp_sendstr(req, "File uploaded successfully"); - return ESP_OK; } @@ -770,7 +759,6 @@ static esp_err_t delete_post_handler(httpd_req_t *req) char filepath[FILE_PATH_MAX]; struct stat file_stat; - ////////////////////////////////////////////////////////////// char _query[200]; char _valuechar[30]; @@ -893,13 +881,11 @@ static esp_err_t delete_post_handler(httpd_req_t *req) } } - httpd_resp_set_hdr(req, "Location", directory.c_str()); httpd_resp_sendstr(req, "File successfully deleted"); return ESP_OK; } - void delete_all_in_directory(std::string _directory) { struct dirent *entry; @@ -1137,8 +1123,6 @@ void unzip(std::string _in_zip_file, std::string _target_directory){ ESP_LOGD(TAG, "Success."); } - - void register_server_file_uri(httpd_handle_t server, const char *base_path) { static struct file_server_data *server_data = NULL; @@ -1164,8 +1148,6 @@ void register_server_file_uri(httpd_handle_t server, const char *base_path) strlcpy(server_data->base_path, base_path, sizeof(server_data->base_path)); - - /* URI handler for getting uploaded files */ // char zw[sizeof(serverprefix)+1]; // strcpy(zw, serverprefix); @@ -1180,7 +1162,6 @@ void register_server_file_uri(httpd_handle_t server, const char *base_path) }; httpd_register_uri_handler(server, &file_download); - httpd_uri_t file_datafileact = { .uri = "/datafileact", // Match all URIs of type /path/to/file .method = HTTP_GET, @@ -1189,7 +1170,6 @@ void register_server_file_uri(httpd_handle_t server, const char *base_path) }; httpd_register_uri_handler(server, &file_datafileact); - httpd_uri_t file_datafile_last_part_handle = { .uri = "/data", // Match all URIs of type /path/to/file .method = HTTP_GET, @@ -1206,7 +1186,6 @@ void register_server_file_uri(httpd_handle_t server, const char *base_path) }; httpd_register_uri_handler(server, &file_logfileact); - httpd_uri_t file_logfile_last_part_handle = { .uri = "/log", // Match all URIs of type /path/to/file .method = HTTP_GET, @@ -1215,7 +1194,6 @@ void register_server_file_uri(httpd_handle_t server, const char *base_path) }; httpd_register_uri_handler(server, &file_logfile_last_part_handle); - /* URI handler for uploading files to server */ httpd_uri_t file_upload = { .uri = "/upload/*", // Match all URIs of type /upload/path/to/file @@ -1233,5 +1211,4 @@ void register_server_file_uri(httpd_handle_t server, const char *base_path) .user_ctx = server_data // Pass server data as context }; httpd_register_uri_handler(server, &file_delete); - } diff --git a/sd-card/html/file_server.css b/sd-card/html/file_server.css new file mode 100644 index 00000000..ee1ed6b7 --- /dev/null +++ b/sd-card/html/file_server.css @@ -0,0 +1,50 @@ +h1 {font-size: 2em;} +h2 {font-size: 1.5em; margin-block-start: 0.0em; margin-block-end: 0.2em;} +h3 {font-size: 1.2em;} +p {font-size: 1em;} + +#files_table { + font-family: Arial, Helvetica, sans-serif; + border-collapse: collapse; + width: 100%; +} + +#files_table td, #files_table th { + border: 1px solid #ddd; + padding: 8px; +} + +#files_table tr:nth-child(even){ + background-color: #f2f2f2; +} + +#files_table tr:hover { + background-color: #ddd; +} + +#files_table th { + padding-top: 12px; + padding-bottom: 12px; + text-align: left; + background-color:lightgrey; + color: black; +} + +input[type=file] { + padding: 5px 0px; + display: inline-block; + font-size: 16px; +} + +input[type=text] { + padding: 5px 10px; + display: inline-block; + border: 1px solid #ccc; + font-size: 16px; +} + +.button { + padding: 4px 10px; + width: 100px; + font-size: 16px; +} \ No newline at end of file diff --git a/sd-card/html/file_server.html b/sd-card/html/file_server.html deleted file mode 100644 index 56414086..00000000 --- a/sd-card/html/file_server.html +++ /dev/null @@ -1,206 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - -
-

Fileserver

-
- - - - - - - - - - - -
- - - -
- - - - - -
-
- - -
- - - - - - \ No newline at end of file diff --git a/sd-card/html/file_server.js b/sd-card/html/file_server.js new file mode 100644 index 00000000..7469670d --- /dev/null +++ b/sd-card/html/file_server.js @@ -0,0 +1,93 @@ +function setpath() { + var fileserverpraefix = "/fileserver"; + var anz_zeichen_fileserver = fileserverpraefix.length; + var default_path = window.location.pathname.substring(anz_zeichen_fileserver) + document.getElementById("newfile").files[0].name; + document.getElementById("filepath").value = default_path; +} + +function dirup() { + var str = window.location.href; + str = str.substring(0, str.length-1); + var zw = str.indexOf("/"); + var found = zw; + while (zw >= 0) { + zw = str.indexOf("/", found+1); + if (zw >= 0) { + found = zw; + } + } + var res = str.substring(0, found+1); + window.location.href = res; +} + +function upload() { + var filePath = document.getElementById("filepath").value; + var upload_path = "/upload/" + filePath; + var fileInput = document.getElementById("newfile").files; + + // Max size of an individual file. Make sure this value is same as that set in file_server.c + var MAX_FILE_SIZE = 8000*1024; + var MAX_FILE_SIZE_STR = "8000KB"; + + if (fileInput.length == 0) { + firework.launch('No file selected!', 'danger', 30000); + } else if (filePath.length == 0) { + firework.launch('File path on server is not set!', 'danger', 30000); + } else if (filePath.length > 100) { + firework.launch('Filename is to long! Max 100 characters.', 'danger', 30000); + } else if (filePath.indexOf(' ') >= 0) { + firework.launch('File path on server cannot have spaces!', 'danger', 30000); + } else if (filePath[filePath.length-1] == '/') { + firework.launch('File name not specified after path!', 'danger', 30000); + } else if (fileInput[0].size > MAX_FILE_SIZE) { + firework.launch("File size must be less than " + MAX_FILE_SIZE_STR + "!", 'danger', 30000); + } else { + document.getElementById("newfile").disabled = true; + document.getElementById("filepath").disabled = true; + document.getElementById("upload").disabled = true; + + var file = fileInput[0]; + var xhttp = new XMLHttpRequest(); + xhttp.onreadystatechange = function() { + if (xhttp.readyState == 4) { + if (xhttp.status == 200) { + document.open(); + document.write(xhttp.responseText); + document.close(); + firework.launch('File upload completed', 'success', 5000); + } else if (xhttp.status == 0) { + firework.launch('Server closed the connection abruptly!', 'danger', 30000); + UpdatePage(false); + } else { + firework.launch('An error occured: ' + xhttp.responseText, 'danger', 30000); + UpdatePage(false); + } + } + }; + xhttp.open("POST", upload_path, true); + xhttp.send(file); + } +} + +function checkAtRootLevel(res) { + if (getPath() == "/fileserver/") { + // Already at root level + document.getElementById("dirup").disabled = true; + console.log("Already on sd-card root level!"); + return true; + } + + document.getElementById("dirup").disabled = false; + return false; +} + +function getPath() { + return window.location.pathname.replace(/\/+$/, '') + "/" +} + +function initFileServer() { + checkAtRootLevel(); + console.log("Current path: " + getPath().replace("/fileserver", "")); + document.getElementById("currentpath").innerHTML = "Current path: " + getPath().replace("/fileserver", "") + ""; + document.cookie = "page=" + getPath() + "; path=/"; +} \ No newline at end of file