|
1 |
| -#include <Arduino.h> |
2 | 1 | #include <WiFi.h>
|
3 | 2 | #include <WiFiClient.h>
|
4 | 3 | #include <ESPmDNS.h>
|
5 | 4 | #include <SPIFFS.h>
|
6 | 5 | #ifdef USE_DEFAULT_WEBSERVER
|
7 | 6 | #include <WebServer.h>
|
| 7 | +typedef WebServer ESPWebServer; |
8 | 8 | #else
|
9 | 9 | #include <ESPWebServer.hpp>
|
10 | 10 | #endif
|
| 11 | + |
| 12 | +const char* ssid = "........"; |
| 13 | +const char* password = "........"; |
| 14 | + |
| 15 | +ESPWebServer server(80); |
| 16 | + |
| 17 | +static std::string htmlEncode(std::string data) { |
| 18 | + const char *p = data.c_str(); |
| 19 | + std::string rv = ""; |
| 20 | + while(p && *p) { |
| 21 | + char escapeChar = *p++; |
| 22 | + switch(escapeChar) { |
| 23 | + case '&': rv += "&"; break; |
| 24 | + case '<': rv += "<"; break; |
| 25 | + case '>': rv += ">"; break; |
| 26 | + case '"': rv += """; break; |
| 27 | + case '\'': rv += "'"; break; |
| 28 | + case '/': rv += "/"; break; |
| 29 | + default: rv += escapeChar; break; |
| 30 | + } |
| 31 | + } |
| 32 | + return rv; |
| 33 | +} |
| 34 | + |
| 35 | +void handleRoot() { |
| 36 | + String rv; |
| 37 | + rv += "<!DOCTYPE html>"; |
| 38 | + rv += "<html>"; |
| 39 | + rv += "<head><title>Very simple file server</title></head>"; |
| 40 | + rv += "<body>"; |
| 41 | + rv += "<h1>Very simple file server</h1>"; |
| 42 | + rv += "<p>This is a very simple file server to demonstrate the use of POST forms. </p>"; |
| 43 | + rv += "<h2>List existing files</h2>"; |
| 44 | + rv += "<p>See <a href=\"/public\">/public</a> to list existing files and retrieve or edit them.</p>"; |
| 45 | + rv += "<h2>Upload new file</h2>"; |
| 46 | + rv += "<p>This form allows you to upload files (text, jpg and png supported best). It demonstrates multipart/form-data.</p>"; |
| 47 | + rv += "<form method=\"POST\" action=\"/upload\" enctype=\"multipart/form-data\">"; |
| 48 | + rv += "file: <input type=\"file\" name=\"file\"><br>"; |
| 49 | + rv += "<input type=\"submit\" value=\"Upload\">"; |
| 50 | + rv += "</form>"; |
| 51 | + rv += "</body>"; |
| 52 | + rv += "</html>"; |
| 53 | + server.send(200, "text/html", rv); |
| 54 | +} |
| 55 | + |
| 56 | +void handleFormEdit() { |
| 57 | + if (!server.authenticate("admin", "admin")) return server.requestAuthentication(); |
| 58 | + bool hasFilename = server.hasArg("filename");; |
| 59 | + String filename = server.arg("filename"); |
| 60 | + String pathname = String("/public/") + filename; |
| 61 | + if (server.hasArg("content") ){ |
| 62 | + // Content has been edited. Save. |
| 63 | + File file = SPIFFS.open(pathname.c_str(), "w"); |
| 64 | + String content = server.arg("content"); |
| 65 | + file.write((uint8_t *)content.c_str(), content.length()); |
| 66 | + file.close(); |
| 67 | + } |
| 68 | + String content = server.arg("content"); |
| 69 | + String rv; |
| 70 | + rv += "<html><head><title>Edit File</title><head><body>\n"; |
| 71 | + File file = SPIFFS.open(pathname.c_str()); |
| 72 | + if (!hasFilename) { |
| 73 | + rv += "<p>No filename specified.</p>\n"; |
| 74 | + } else if (!file.available()) { |
| 75 | + rv += "<p>File not found:"; |
| 76 | + rv += pathname; |
| 77 | + rv += "</p>\n"; |
| 78 | + } else { |
| 79 | + rv += "<h2>Edit content of "; |
| 80 | + rv += pathname; |
| 81 | + rv += "</h2>\n"; |
| 82 | + rv += "<form method=\"POST\" enctype=\"application/x-www-form-urlencoded\">\n"; |
| 83 | + rv += "<input name=\"filename\" type=\"hidden\" value=\""; |
| 84 | + rv += filename; |
| 85 | + rv += "\">\n"; |
| 86 | + rv += "<textarea name=\"content\" rows=\"24\" cols=\"80\">"; |
| 87 | + // Read the file and write it to the response |
| 88 | + size_t length = 0; |
| 89 | + do { |
| 90 | + char buffer[256]; |
| 91 | + length = file.read((uint8_t *)buffer, 256); |
| 92 | + std::string bufferString(buffer, length); |
| 93 | + bufferString = htmlEncode(bufferString); |
| 94 | + rv += String(bufferString.c_str()); |
| 95 | + } while (length > 0); |
| 96 | + rv += "</textarea><br>"; |
| 97 | + rv += "<input type=\"submit\" value=\"Save\">"; |
| 98 | + rv += "</form>"; |
| 99 | + } |
| 100 | + rv += "</body></html>"; |
| 101 | + server.send(200, "text/html", rv); |
| 102 | +} |
| 103 | + |
| 104 | +void handleFormUpload() { |
| 105 | + Serial.println("handleUpload() called"); |
| 106 | + server.send(200); |
| 107 | +} |
| 108 | + |
| 109 | +File fsUploadFile; |
| 110 | + |
| 111 | +void handleFormUploadFile() { |
| 112 | + Serial.println("handleUploadFile() called"); |
| 113 | + HTTPUpload& upload = server.upload(); |
| 114 | + if(upload.status == UPLOAD_FILE_START){ |
| 115 | + String filename = String("/public/") + upload.filename; |
| 116 | + Serial.printf("upload filename=%s\n", filename.c_str()); |
| 117 | + Serial.print("handleFileUpload Name: "); Serial.println(filename); |
| 118 | + fsUploadFile = SPIFFS.open(filename, "w"); // Open the file for writing in SPIFFS (create if it doesn't exist) |
| 119 | + } else if(upload.status == UPLOAD_FILE_WRITE){ |
| 120 | + Serial.printf("uploaded %d bytes\n", upload.currentSize); |
| 121 | + if(fsUploadFile) |
| 122 | + fsUploadFile.write(upload.buf, upload.currentSize); // Write the received bytes to the file |
| 123 | + } else if(upload.status == UPLOAD_FILE_END){ |
| 124 | + Serial.printf("upload total %d bytes\n", upload.totalSize); |
| 125 | + if(fsUploadFile) { // If the file was successfully created |
| 126 | + fsUploadFile.close(); // Close the file again |
| 127 | + Serial.print("handleFileUpload Size: "); Serial.println(upload.totalSize); |
| 128 | + server.sendHeader("Location","/public"); // Redirect the client to the success page |
| 129 | + server.send(303); |
| 130 | + } else { |
| 131 | + server.send(500, "text/plain", "500: couldn't create file"); |
| 132 | + } |
| 133 | + server.send(200, "text/plain", "OK"); |
| 134 | + } |
| 135 | +} |
| 136 | + |
| 137 | +void handleDirectory() { |
| 138 | + String rv; |
| 139 | + rv += "<html><head><title>File Listing</title><head><body>\n"; |
| 140 | + File d = SPIFFS.open("/public"); |
| 141 | + if (!d.isDirectory()) { |
| 142 | + rv += "<p>No files found.</p>\n"; |
| 143 | + } else { |
| 144 | + rv += "<h1>File Listing</h1>\n"; |
| 145 | + rv += "<ul>\n"; |
| 146 | + File f = d.openNextFile(); |
| 147 | + while (f) { |
| 148 | + std::string pathname(f.name()); |
| 149 | + std::string filename = pathname.substr(8); // Remove /public/ |
| 150 | + rv += "<li><a href=\""; |
| 151 | + rv += String(pathname.c_str()); |
| 152 | + rv += "\">"; |
| 153 | + rv += String(filename.c_str()); |
| 154 | + rv += "</a>"; |
| 155 | + if (pathname.rfind(".txt") != std::string::npos) { |
| 156 | + rv += " <a href=\"/edit?filename="; |
| 157 | + rv += String(filename.c_str()); |
| 158 | + rv += "\">[edit]</a>"; |
| 159 | + } |
| 160 | + rv += "</li>"; |
| 161 | + f = d.openNextFile(); |
| 162 | + } |
| 163 | + rv += "</ul>"; |
| 164 | + } |
| 165 | + rv += "</body></html>"; |
| 166 | + server.send(200, "text/html", rv); |
| 167 | +} |
| 168 | + |
| 169 | +void handleNotFound() { |
| 170 | + String message = "File Not Found\n\n"; |
| 171 | + message += "URI: "; |
| 172 | + message += server.uri(); |
| 173 | + message += "\nMethod: "; |
| 174 | + message += (server.method() == HTTP_GET) ? "GET" : "POST"; |
| 175 | + message += "\nArguments: "; |
| 176 | + message += server.args(); |
| 177 | + message += "\n"; |
| 178 | + for (uint8_t i = 0; i < server.args(); i++) { |
| 179 | + message += " " + server.argName(i) + ": " + server.arg(i) + "\n"; |
| 180 | + } |
| 181 | + server.send(404, "text/plain", message); |
| 182 | +} |
| 183 | + |
| 184 | +void setup(void) { |
| 185 | + Serial.begin(115200); |
| 186 | + WiFi.mode(WIFI_STA); |
| 187 | + WiFi.begin(ssid, password); |
| 188 | + Serial.println(""); |
| 189 | + |
| 190 | + // Wait for connection |
| 191 | + while (WiFi.status() != WL_CONNECTED) { |
| 192 | + delay(500); |
| 193 | + Serial.print("."); |
| 194 | + } |
| 195 | + Serial.println(""); |
| 196 | + Serial.print("Connected to "); |
| 197 | + Serial.println(ssid); |
| 198 | + Serial.print("IP address: "); |
| 199 | + Serial.println(WiFi.localIP()); |
| 200 | + |
| 201 | + if (MDNS.begin("esp32")) { |
| 202 | + Serial.println("MDNS responder started"); |
| 203 | + } |
| 204 | + // Setup filesystem |
| 205 | + if (!SPIFFS.begin(true)) Serial.println("Mounting SPIFFS failed"); |
| 206 | + |
| 207 | + server.on("/", handleRoot); |
| 208 | + server.on("/upload", HTTP_POST, handleFormUpload, handleFormUploadFile); |
| 209 | + server.on("/edit", HTTP_GET, handleFormEdit); |
| 210 | + server.on("/edit", HTTP_POST, handleFormEdit); |
| 211 | + // Note: /public (without trailing /) gives directory listing, but /public/... retrieves static files. |
| 212 | + server.on("/public", HTTP_GET, handleDirectory); |
| 213 | + server.serveStatic("/public/", SPIFFS, "/public/"); |
| 214 | + |
| 215 | + server.onNotFound(handleNotFound); |
| 216 | + |
| 217 | + server.begin(); |
| 218 | + Serial.println("HTTP server started"); |
| 219 | +} |
| 220 | + |
| 221 | +void loop(void) { |
| 222 | + server.handleClient(); |
| 223 | +} |
0 commit comments