Unverified Commit 5b05a34d authored by Matthias Hertel's avatar Matthias Hertel Committed by GitHub

Improving WebServer Example (#10111)

* Update WebServer.ino

* Enable FAT and LittleFS filesystems as configured.
* use new versions of RequestHandler::canHandle and RequestHandler::canUpload

* Update Documentation

* Documentation changed accoring review comments.

* README.md changed accoring to review comments.
parent c4cbc3e6
...@@ -4,11 +4,11 @@ This example shows different techniques on how to use and extend the WebServer f ...@@ -4,11 +4,11 @@ This example shows different techniques on how to use and extend the WebServer f
It is a small project in it's own and has some files to use on the web server to show how to use simple REST based services. It is a small project in it's own and has some files to use on the web server to show how to use simple REST based services.
This example requires some space for a filesystem and runs fine boards with 4 MByte flash using the following options: This example requires some space for a filesystem and runs fine on supported SoCs with 4 MByte or more flash by selecting the proper partition table:
* For using SPIFFS(LittleFS): Default 4MB with spiffs (1.2MB APP/1.5MB SPIFFS)
* For using FATFS: Default 4MB with ffat (1.2MB APP/1.5MB FATFS)
* Board: ESP32 Dev Module
* Partition Scheme: Default 4MB with spiffs (1.2MB APP/1.5MB SPIFFS)
but LittleFS will be used in the partition (not SPIFFS)
It features It features
...@@ -28,9 +28,9 @@ It features ...@@ -28,9 +28,9 @@ It features
Currently, this example supports the following targets. Currently, this example supports the following targets.
| Supported Targets | ESP32 | ESP32-S2 | ESP32-C3 | | Supported Targets | ESP32 | ESP32-S2 | ESP32-S3 | ESP32-C3 | ESP32-C6 |
| ----------------- | ----- | -------- | -------- | | ----------------- | ----- | -------- | -------- | -------- | -------- |
| | yes | yes | yes | | | yes | yes | yes | yes | yes |
## Use the Example ## Use the Example
...@@ -200,6 +200,7 @@ This class has to implements several functions and works in a more detailed way: ...@@ -200,6 +200,7 @@ This class has to implements several functions and works in a more detailed way:
* The `canUpload()`and `upload()` methods work similar while the `upload()` method is called multiple times to create, append data and close the new file. * The `canUpload()`and `upload()` methods work similar while the `upload()` method is called multiple times to create, append data and close the new file.
## File upload ## File upload
By opening <http://webserver/$upload.htm> you can easily upload files by dragging them over the drop area. By opening <http://webserver/$upload.htm> you can easily upload files by dragging them over the drop area.
...@@ -238,6 +239,7 @@ You can see on the Serial output that one filesystem write error is reported. ...@@ -238,6 +239,7 @@ You can see on the Serial output that one filesystem write error is reported.
Please be patient and wait for the upload ending even when writing to the filesystem is disabled Please be patient and wait for the upload ending even when writing to the filesystem is disabled
it maybe take more than a minute. it maybe take more than a minute.
## Registering a special handler for "file not found" ## Registering a special handler for "file not found"
Any other incoming request that was not handled by the registered plug-ins above can be detected by registering Any other incoming request that was not handled by the registered plug-ins above can be detected by registering
...@@ -253,6 +255,7 @@ Any other incoming request that was not handled by the registered plug-ins above ...@@ -253,6 +255,7 @@ Any other incoming request that was not handled by the registered plug-ins above
This allows sending back an "friendly" result for the browser. Here a simple html page is created from a static string. This allows sending back an "friendly" result for the browser. Here a simple html page is created from a static string.
You can easily change the html code in the file `builtinfiles.h`. You can easily change the html code in the file `builtinfiles.h`.
## customizations ## customizations
You may like to change the hostname and the timezone in the lines: You may like to change the hostname and the timezone in the lines:
...@@ -262,10 +265,18 @@ You may like to change the hostname and the timezone in the lines: ...@@ -262,10 +265,18 @@ You may like to change the hostname and the timezone in the lines:
> #define TIMEZONE "CET-1CEST,M3.5.0,M10.5.0/3" > #define TIMEZONE "CET-1CEST,M3.5.0,M10.5.0/3"
> ``` > ```
## Troubleshooting ## Troubleshooting
Have a look in the Serial output for some additional runtime information. Have a look in the Serial output for some additional runtime information.
## Changes
* 2024-08-02 -- Fixing for board implementation 3.0.4 ff.
* 2024-08-02 -- Support for FAT
## Contribute ## Contribute
To know how to contribute to this project, see [How to contribute.](https://github.com/espressif/arduino-esp32/blob/master/CONTRIBUTING.rst) To know how to contribute to this project, see [How to contribute.](https://github.com/espressif/arduino-esp32/blob/master/CONTRIBUTING.rst)
...@@ -274,11 +285,13 @@ If you have any **feedback** or **issue** to report on this example/library, ple ...@@ -274,11 +285,13 @@ If you have any **feedback** or **issue** to report on this example/library, ple
Before creating a new issue, be sure to try Troubleshooting and check if the same issue was already created by someone else. Before creating a new issue, be sure to try Troubleshooting and check if the same issue was already created by someone else.
## Resources ## Resources
* Official ESP32 Forum: [Link](https://esp32.com) * Official ESP32 Forum: [Link](https://esp32.com)
* Arduino-ESP32 Official Repository: [espressif/arduino-esp32](https://github.com/espressif/arduino-esp32) * Arduino-ESP32 Official Repository: [espressif/arduino-esp32](https://github.com/espressif/arduino-esp32)
* ESP32 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32_datasheet_en.pdf) * ESP32 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32_datasheet_en.pdf)
* ESP32-S2 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-s2_datasheet_en.pdf) * ESP32-S2 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-s2_datasheet_en.pdf)
* ESP32-S3 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-s3_datasheet_en.pdf)
* ESP32-C3 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-c3_datasheet_en.pdf) * ESP32-C3 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-c3_datasheet_en.pdf)
* Official ESP-IDF documentation: [ESP-IDF](https://idf.espressif.com) * Official ESP-IDF documentation: [ESP-IDF](https://idf.espressif.com)
...@@ -18,14 +18,15 @@ ...@@ -18,14 +18,15 @@
// //
// Please use the following Arduino IDE configuration // Please use the following Arduino IDE configuration
// //
// * Board: ESP32 Dev Module // * Board: "ESP32 Dev Module" or other board with ESP32
// * Partition Scheme: Default 4MB with spiffs (1.2MB APP/1.5MB SPIFFS) // * Partition Scheme: "Default 4MB with spiffs" or any other scheme with spiffs or FAT
// but LittleFS will be used in the partition (not SPIFFS) // but LittleFS will be used in the partition (not SPIFFS)
// * other setting as applicable // * other setting as applicable
// //
// Changelog: // Changelog:
// 21.07.2021 creation, first version // 21.07.2021 creation, first version
// 08.01.2023 ESP32 version with ETag // 08.01.2023 ESP32 version with ETag
// 02.08.2024 support LitteFS and FAT file systems (on large Flash chips)
#include <Arduino.h> #include <Arduino.h>
#include <WebServer.h> #include <WebServer.h>
...@@ -33,8 +34,11 @@ ...@@ -33,8 +34,11 @@
#include "secrets.h" // add WLAN Credentials in here. #include "secrets.h" // add WLAN Credentials in here.
#include "esp_partition.h" // to check existing data partitions in Flash memory
#include <FS.h> // File System for Web Server Files #include <FS.h> // File System for Web Server Files
#include <LittleFS.h> // This file system is used. #include <LittleFS.h> // Use LittleFSThis file system is used.
#include <FFat.h> // or.. FAT
// mark parameters not used in example // mark parameters not used in example
#define UNUSED __attribute__((unused)) #define UNUSED __attribute__((unused))
...@@ -51,6 +55,9 @@ ...@@ -51,6 +55,9 @@
// need a WebServer for http access on port 80. // need a WebServer for http access on port 80.
WebServer server(80); WebServer server(80);
// The file system in use...
fs::FS *fsys = nullptr;
// The text of builtin files are in this header file // The text of builtin files are in this header file
#include "builtinfiles.h" #include "builtinfiles.h"
...@@ -65,7 +72,7 @@ void handleRedirect() { ...@@ -65,7 +72,7 @@ void handleRedirect() {
TRACE("Redirect...\n"); TRACE("Redirect...\n");
String url = "/index.htm"; String url = "/index.htm";
if (!LittleFS.exists(url)) { if (!fsys->exists(url)) {
url = "/$upload.htm"; url = "/$upload.htm";
} }
...@@ -76,7 +83,7 @@ void handleRedirect() { ...@@ -76,7 +83,7 @@ void handleRedirect() {
// This function is called when the WebServer was requested to list all existing files in the filesystem. // This function is called when the WebServer was requested to list all existing files in the filesystem.
// a JSON array with file information is returned. // a JSON array with file information is returned.
void handleListFiles() { void handleListFiles() {
File dir = LittleFS.open("/", "r"); File dir = fsys->open("/", "r");
String result; String result;
result += "[\n"; result += "[\n";
...@@ -107,8 +114,15 @@ void handleSysInfo() { ...@@ -107,8 +114,15 @@ void handleSysInfo() {
result += " \"Chip Revision\": " + String(ESP.getChipRevision()) + ",\n"; result += " \"Chip Revision\": " + String(ESP.getChipRevision()) + ",\n";
result += " \"flashSize\": " + String(ESP.getFlashChipSize()) + ",\n"; result += " \"flashSize\": " + String(ESP.getFlashChipSize()) + ",\n";
result += " \"freeHeap\": " + String(ESP.getFreeHeap()) + ",\n"; result += " \"freeHeap\": " + String(ESP.getFreeHeap()) + ",\n";
result += " \"fsTotalBytes\": " + String(LittleFS.totalBytes()) + ",\n";
result += " \"fsUsedBytes\": " + String(LittleFS.usedBytes()) + ",\n"; if (fsys == (fs::FS *)&FFat) {
result += " \"fsTotalBytes\": " + String(FFat.totalBytes()) + ",\n";
result += " \"fsUsedBytes\": " + String(FFat.usedBytes()) + ",\n";
} else {
result += " \"fsTotalBytes\": " + String(LittleFS.totalBytes()) + ",\n";
result += " \"fsUsedBytes\": " + String(LittleFS.usedBytes()) + ",\n";
}
result += "}"; result += "}";
server.sendHeader("Cache-Control", "no-cache"); server.sendHeader("Cache-Control", "no-cache");
...@@ -132,11 +146,11 @@ public: ...@@ -132,11 +146,11 @@ public:
// @param requestMethod method of the http request line. // @param requestMethod method of the http request line.
// @param requestUri request resource from the http request line. // @param requestUri request resource from the http request line.
// @return true when method can be handled. // @return true when method can be handled.
bool canHandle(HTTPMethod requestMethod, String UNUSED uri) override { bool canHandle(WebServer &server, HTTPMethod requestMethod, String uri) override {
return ((requestMethod == HTTP_POST) || (requestMethod == HTTP_DELETE)); return ((requestMethod == HTTP_POST) || (requestMethod == HTTP_DELETE));
} // canHandle() } // canHandle()
bool canUpload(String uri) override { bool canUpload(WebServer &server, String uri) override {
// only allow upload on root fs level. // only allow upload on root fs level.
return (uri == "/"); return (uri == "/");
} // canUpload() } // canUpload()
...@@ -148,15 +162,13 @@ public: ...@@ -148,15 +162,13 @@ public:
fName = "/" + fName; fName = "/" + fName;
} }
TRACE("handle %s\n", fName.c_str());
if (requestMethod == HTTP_POST) { if (requestMethod == HTTP_POST) {
// all done in upload. no other forms. // all done in upload. no other forms.
} else if (requestMethod == HTTP_DELETE) { } else if (requestMethod == HTTP_DELETE) {
if (LittleFS.exists(fName)) { if (fsys->exists(fName)) {
TRACE("DELETE %s\n", fName.c_str()); TRACE("DELETE %s\n", fName.c_str());
LittleFS.remove(fName); fsys->remove(fName);
} }
} // if } // if
...@@ -165,7 +177,7 @@ public: ...@@ -165,7 +177,7 @@ public:
} // handle() } // handle()
// uploading process // uploading process
void upload(WebServer UNUSED &server, String UNUSED _requestUri, HTTPUpload &upload) override { void upload(WebServer UNUSED &server, String requestUri, HTTPUpload &upload) override {
// ensure that filename starts with '/' // ensure that filename starts with '/'
static size_t uploadSize; static size_t uploadSize;
...@@ -178,10 +190,10 @@ public: ...@@ -178,10 +190,10 @@ public:
} }
TRACE("start uploading file %s...\n", fName.c_str()); TRACE("start uploading file %s...\n", fName.c_str());
if (LittleFS.exists(fName)) { if (fsys->exists(fName)) {
LittleFS.remove(fName); fsys->remove(fName);
} // if } // if
_fsUploadFile = LittleFS.open(fName, "w"); _fsUploadFile = fsys->open(fName, "w");
uploadSize = 0; uploadSize = 0;
} else if (upload.status == UPLOAD_FILE_WRITE) { } else if (upload.status == UPLOAD_FILE_WRITE) {
...@@ -198,7 +210,7 @@ public: ...@@ -198,7 +210,7 @@ public:
if (!fName.startsWith("/")) { if (!fName.startsWith("/")) {
fName = "/" + fName; fName = "/" + fName;
} }
LittleFS.remove(fName); fsys->remove(fName);
} }
uploadSize += upload.currentSize; uploadSize += upload.currentSize;
// TRACE("free:: %d of %d\n", LittleFS.usedBytes(), LittleFS.totalBytes()); // TRACE("free:: %d of %d\n", LittleFS.usedBytes(), LittleFS.totalBytes());
...@@ -207,7 +219,7 @@ public: ...@@ -207,7 +219,7 @@ public:
} // if } // if
} else if (upload.status == UPLOAD_FILE_END) { } else if (upload.status == UPLOAD_FILE_END) {
TRACE("finished.\n"); TRACE("upload done.\n");
// Close the file // Close the file
if (_fsUploadFile) { if (_fsUploadFile) {
_fsUploadFile.close(); _fsUploadFile.close();
...@@ -231,14 +243,49 @@ void setup(void) { ...@@ -231,14 +243,49 @@ void setup(void) {
TRACE("Starting WebServer example...\n"); TRACE("Starting WebServer example...\n");
// ----- check partitions for finding the fileystem type -----
esp_partition_iterator_t i;
i = esp_partition_find(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_FAT, nullptr);
if (i) {
TRACE("FAT partition found.");
fsys = &FFat;
} else {
i = esp_partition_find(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_SPIFFS, nullptr);
if (i) {
TRACE("SPIFFS partition found.");
fsys = &LittleFS;
} else {
TRACE("no partition found.");
}
}
esp_partition_iterator_release(i);
// mount and format as needed
TRACE("Mounting the filesystem...\n"); TRACE("Mounting the filesystem...\n");
if (!LittleFS.begin()) { if (!fsys) {
TRACE("need to change the board configuration to include a partition for files.\n");
delay(30000);
} else if ((fsys == (fs::FS *)&FFat) && (!FFat.begin())) {
TRACE("could not mount the filesystem...\n");
delay(2000);
TRACE("formatting FAT...\n");
FFat.format();
delay(2000);
TRACE("restarting...\n");
delay(2000);
ESP.restart();
} else if ((fsys == (fs::FS *)&LittleFS) && (!LittleFS.begin())) {
TRACE("could not mount the filesystem...\n"); TRACE("could not mount the filesystem...\n");
delay(2000); delay(2000);
TRACE("formatting...\n"); TRACE("formatting LittleFS...\n");
LittleFS.format(); LittleFS.format();
delay(2000); delay(2000);
TRACE("restart.\n"); TRACE("restarting...\n");
delay(2000); delay(2000);
ESP.restart(); ESP.restart();
} }
...@@ -286,7 +333,7 @@ void setup(void) { ...@@ -286,7 +333,7 @@ void setup(void) {
// UPLOAD and DELETE of files in the file system using a request handler. // UPLOAD and DELETE of files in the file system using a request handler.
server.addHandler(new FileServerHandler()); server.addHandler(new FileServerHandler());
// // enable CORS header in webserver results // enable CORS header in webserver results
server.enableCORS(true); server.enableCORS(true);
// enable ETAG header in webserver results (used by serveStatic handler) // enable ETAG header in webserver results (used by serveStatic handler)
...@@ -306,7 +353,7 @@ void setup(void) { ...@@ -306,7 +353,7 @@ void setup(void) {
#endif #endif
// serve all static files // serve all static files
server.serveStatic("/", LittleFS, "/"); server.serveStatic("/", *fsys, "/");
TRACE("Register default (not found) answer...\n"); TRACE("Register default (not found) answer...\n");
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment