From 1f07cd0d0a4f598dd655f64fa9a1f4b617c31d95 Mon Sep 17 00:00:00 2001 From: Matthias Hertel Date: Tue, 20 Jul 2021 22:09:55 +0200 Subject: [PATCH 01/10] WebServer eTag implementation improvements --- .../src/ESP8266WebServer-impl.h | 16 ++++- .../ESP8266WebServer/src/ESP8266WebServer.h | 6 ++ .../src/detail/RequestHandlersImpl.h | 70 +++++++++++++++---- 3 files changed, 76 insertions(+), 16 deletions(-) diff --git a/libraries/ESP8266WebServer/src/ESP8266WebServer-impl.h b/libraries/ESP8266WebServer/src/ESP8266WebServer-impl.h index 8c5cdf401e..bf4b9e1ed0 100644 --- a/libraries/ESP8266WebServer/src/ESP8266WebServer-impl.h +++ b/libraries/ESP8266WebServer/src/ESP8266WebServer-impl.h @@ -68,6 +68,13 @@ template void ESP8266WebServerTemplate::enableCORS(bool enable) { _corsEnabled = enable; } + +template +void ESP8266WebServerTemplate::enableETag(bool enable, ETagFunction fn) { + _eTagEnabled = enable; + _eTagFunction = fn; +} + template void ESP8266WebServerTemplate::begin() { close(); @@ -264,10 +271,11 @@ void ESP8266WebServerTemplate::serveStatic(const char* uri, FS& fs, file.close(); } - if(is_file) + if(is_file) { _addRequestHandler(new StaticFileRequestHandler(fs, path, uri, cache_header)); - else + } else { _addRequestHandler(new StaticDirectoryRequestHandler(fs, path, uri, cache_header)); + } } template @@ -436,6 +444,10 @@ void ESP8266WebServerTemplate::_prepareHeader(String& response, int sendHeader(String(F("Keep-Alive")), String(F("timeout=")) + HTTP_MAX_CLOSE_WAIT); } + if (_eTagEnabled) { + // sendHeader(String(F("Access-Control-Allow-Origin")), String("*")); + } + response += _responseHeaders; response += "\r\n"; _responseHeaders = ""; diff --git a/libraries/ESP8266WebServer/src/ESP8266WebServer.h b/libraries/ESP8266WebServer/src/ESP8266WebServer.h index eeb98c15a7..334612d30a 100644 --- a/libraries/ESP8266WebServer/src/ESP8266WebServer.h +++ b/libraries/ESP8266WebServer/src/ESP8266WebServer.h @@ -114,6 +114,8 @@ class ESP8266WebServerTemplate void requestAuthentication(HTTPAuthMethod mode = BASIC_AUTH, const char* realm = NULL, const String& authFailMsg = String("") ); typedef std::function THandlerFunction; + typedef std::function ETagFunction; + void on(const Uri &uri, THandlerFunction handler); void on(const Uri &uri, HTTPMethod method, THandlerFunction fn); void on(const Uri &uri, HTTPMethod method, THandlerFunction fn, THandlerFunction ufn); @@ -122,6 +124,7 @@ class ESP8266WebServerTemplate void onNotFound(THandlerFunction fn); //called when handler is not assigned void onFileUpload(THandlerFunction fn); //handle file uploads void enableCORS(bool enable); + void enableETag(bool enable, ETagFunction fn = nullptr); const String& uri() const { return _currentUri; } HTTPMethod method() const { return _currentMethod; } @@ -271,6 +274,9 @@ class ESP8266WebServerTemplate } } + bool _eTagEnabled = false; + ETagFunction _eTagFunction = nullptr; + protected: void _addRequestHandler(RequestHandlerType* handler); void _handleRequest(); diff --git a/libraries/ESP8266WebServer/src/detail/RequestHandlersImpl.h b/libraries/ESP8266WebServer/src/detail/RequestHandlersImpl.h index c88c830320..dea6cfb76b 100644 --- a/libraries/ESP8266WebServer/src/detail/RequestHandlersImpl.h +++ b/libraries/ESP8266WebServer/src/detail/RequestHandlersImpl.h @@ -9,6 +9,25 @@ namespace esp8266webserver { +// calculate an eTag for a file in filesystem +static String calcETag(FS &fs, const String path) { + String result; + + // calculate eTag using md5 checksum + uint8_t md5_buf[16]; + File f = fs.open(path, "r"); + MD5Builder calcMD5; + calcMD5.begin(); + calcMD5.addStream(f, f.size()); + calcMD5.calculate(); + calcMD5.getBytes(md5_buf); + f.close(); + // create a minimal-length eTag using base64 byte[]->text encoding. + result = "\"" + base64::encode(md5_buf, 16, false) + "\""; + return(result); +} // calcETag + + template class FunctionRequestHandler : public RequestHandler { using WebServerType = ESP8266WebServerTemplate; @@ -92,6 +111,7 @@ class StaticRequestHandler : public RequestHandler { }; +// serve all files within a given directory template class StaticDirectoryRequestHandler : public StaticRequestHandler { @@ -117,6 +137,7 @@ class StaticDirectoryRequestHandler : public StaticRequestHandler { DEBUGV("DirectoryRequestHandler::handle: request=%s _uri=%s\r\n", requestUri.c_str(), SRH::_uri.c_str()); String path; + String eTagCode; path.reserve(SRH::_path.length() + requestUri.length() + 32); path = SRH::_path; @@ -156,10 +177,28 @@ class StaticDirectoryRequestHandler : public StaticRequestHandler { return false; } + if (server._eTagEnabled) { + if (server._eTagFunction) { + eTagCode = (server._eTagFunction)(SRH::_fs, path); + } else { + eTagCode = calcETag(SRH::_fs, path); + } + + if (server.header("If-None-Match") == eTagCode) { + server.send(304); + return true; + } + } + if (SRH::_cache_header.length() != 0) server.sendHeader("Cache-Control", SRH::_cache_header); + if ((server._eTagEnabled) && (eTagCode.length() > 0)) { + server.sendHeader("ETag", eTagCode); + } + server.streamFile(f, contentType, requestMethod); + return true; } @@ -167,6 +206,8 @@ class StaticDirectoryRequestHandler : public StaticRequestHandler { size_t _baseUriLength; }; + +// Serve a specific, single file template class StaticFileRequestHandler : @@ -180,13 +221,6 @@ public StaticRequestHandler { : StaticRequestHandler{fs, path, uri, cache_header} { - File f = SRH::_fs.open(path, "r"); - MD5Builder calcMD5; - calcMD5.begin(); - calcMD5.addStream(f, f.size()); - calcMD5.calculate(); - calcMD5.getBytes(_ETag_md5); - f.close(); } bool canHandle(HTTPMethod requestMethod, const String& requestUri) override { @@ -197,11 +231,17 @@ public StaticRequestHandler { if (!canHandle(requestMethod, requestUri)) return false; - const String etag = "\"" + base64::encode(_ETag_md5, 16, false) + "\""; - - if(server.header("If-None-Match") == etag){ - server.send(304); - return true; + if (server._eTagEnabled) { + if (server._eTagFunction) { + _eTagCode = (server._eTagFunction)(SRH::_fs, SRH::_path); + } else if (_eTagCode.isEmpty()) { + _eTagCode = calcETag(SRH::_fs, SRH::_path); + } + + if (server.header("If-None-Match") == _eTagCode) { + server.send(304); + return true; + } } File f = SRH::_fs.open(SRH::_path, "r"); @@ -217,14 +257,16 @@ public StaticRequestHandler { if (SRH::_cache_header.length() != 0) server.sendHeader("Cache-Control", SRH::_cache_header); - server.sendHeader("ETag", etag); + if ((server._eTagEnabled) && (_eTagCode.length() > 0)) { + server.sendHeader("ETag", _eTagCode); + } server.streamFile(f, mime::getContentType(SRH::_path), requestMethod); return true; } protected: - uint8_t _ETag_md5[16]; + String _eTagCode; // eTag as used in http header for this single file }; } // namespace From 4f1c5d502783242727b4f2c5451759f28e082630 Mon Sep 17 00:00:00 2001 From: Matthias Hertel Date: Tue, 20 Jul 2021 22:20:05 +0200 Subject: [PATCH 02/10] cleanup --- libraries/ESP8266WebServer/src/ESP8266WebServer-impl.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/libraries/ESP8266WebServer/src/ESP8266WebServer-impl.h b/libraries/ESP8266WebServer/src/ESP8266WebServer-impl.h index bf4b9e1ed0..42c8394e9d 100644 --- a/libraries/ESP8266WebServer/src/ESP8266WebServer-impl.h +++ b/libraries/ESP8266WebServer/src/ESP8266WebServer-impl.h @@ -444,10 +444,6 @@ void ESP8266WebServerTemplate::_prepareHeader(String& response, int sendHeader(String(F("Keep-Alive")), String(F("timeout=")) + HTTP_MAX_CLOSE_WAIT); } - if (_eTagEnabled) { - // sendHeader(String(F("Access-Control-Allow-Origin")), String("*")); - } - response += _responseHeaders; response += "\r\n"; _responseHeaders = ""; From b5e48de36e61f9366a4fd835e258d63ec4318d73 Mon Sep 17 00:00:00 2001 From: Matthias Hertel Date: Wed, 21 Jul 2021 08:19:15 +0200 Subject: [PATCH 03/10] fixing mac build --- libraries/ESP8266WebServer/src/ESP8266WebServer-impl.h | 3 ++- libraries/ESP8266WebServer/src/detail/RequestHandlersImpl.h | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/libraries/ESP8266WebServer/src/ESP8266WebServer-impl.h b/libraries/ESP8266WebServer/src/ESP8266WebServer-impl.h index 42c8394e9d..b9ca0fe535 100644 --- a/libraries/ESP8266WebServer/src/ESP8266WebServer-impl.h +++ b/libraries/ESP8266WebServer/src/ESP8266WebServer-impl.h @@ -72,7 +72,7 @@ void ESP8266WebServerTemplate::enableCORS(bool enable) { template void ESP8266WebServerTemplate::enableETag(bool enable, ETagFunction fn) { _eTagEnabled = enable; - _eTagFunction = fn; + _eTagFunction = fn; } template @@ -444,6 +444,7 @@ void ESP8266WebServerTemplate::_prepareHeader(String& response, int sendHeader(String(F("Keep-Alive")), String(F("timeout=")) + HTTP_MAX_CLOSE_WAIT); } + response += _responseHeaders; response += "\r\n"; _responseHeaders = ""; diff --git a/libraries/ESP8266WebServer/src/detail/RequestHandlersImpl.h b/libraries/ESP8266WebServer/src/detail/RequestHandlersImpl.h index dea6cfb76b..ea016328be 100644 --- a/libraries/ESP8266WebServer/src/detail/RequestHandlersImpl.h +++ b/libraries/ESP8266WebServer/src/detail/RequestHandlersImpl.h @@ -181,7 +181,7 @@ class StaticDirectoryRequestHandler : public StaticRequestHandler { if (server._eTagFunction) { eTagCode = (server._eTagFunction)(SRH::_fs, path); } else { - eTagCode = calcETag(SRH::_fs, path); + eTagCode = esp8266webserver::calcETag(SRH::_fs, path); } if (server.header("If-None-Match") == eTagCode) { @@ -235,7 +235,7 @@ public StaticRequestHandler { if (server._eTagFunction) { _eTagCode = (server._eTagFunction)(SRH::_fs, SRH::_path); } else if (_eTagCode.isEmpty()) { - _eTagCode = calcETag(SRH::_fs, SRH::_path); + _eTagCode = esp8266webserver::calcETag(SRH::_fs, SRH::_path); } if (server.header("If-None-Match") == _eTagCode) { From 5636d5faf6ed9c9e7f9e28736e19414df939fd6f Mon Sep 17 00:00:00 2001 From: Matthias Hertel Date: Wed, 21 Jul 2021 14:20:06 +0200 Subject: [PATCH 04/10] review fixes --- .../ESP8266WebServer/src/detail/RequestHandlersImpl.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/libraries/ESP8266WebServer/src/detail/RequestHandlersImpl.h b/libraries/ESP8266WebServer/src/detail/RequestHandlersImpl.h index ea016328be..bb06033dea 100644 --- a/libraries/ESP8266WebServer/src/detail/RequestHandlersImpl.h +++ b/libraries/ESP8266WebServer/src/detail/RequestHandlersImpl.h @@ -9,8 +9,9 @@ namespace esp8266webserver { -// calculate an eTag for a file in filesystem -static String calcETag(FS &fs, const String path) { +// calculate an ETag for a file in filesystem based on md5 checksum +// that can be used in the http headers - include quotes. +static String calcETag(FS &fs, const String &path) { String result; // calculate eTag using md5 checksum @@ -266,7 +267,7 @@ public StaticRequestHandler { } protected: - String _eTagCode; // eTag as used in http header for this single file + String _eTagCode; // ETag code calculated for this file as used in http header include quotes. }; } // namespace From fbd861ec80c1ace00b71ed0ba34bed09d675011e Mon Sep 17 00:00:00 2001 From: Matthias Hertel Date: Fri, 23 Jul 2021 00:31:19 +0200 Subject: [PATCH 05/10] WebServer example added --- .../examples/WebServer/README.md | 199 ++++++++++++ .../examples/WebServer/WebServer.ino | 284 ++++++++++++++++++ .../examples/WebServer/builtinfiles.h | 63 ++++ .../examples/WebServer/data/files.htm | 65 ++++ .../examples/WebServer/data/index.htm | 24 ++ .../examples/WebServer/data/style.css | 10 + .../examples/WebServer/secrets.h | 13 + 7 files changed, 658 insertions(+) create mode 100644 libraries/ESP8266WebServer/examples/WebServer/README.md create mode 100644 libraries/ESP8266WebServer/examples/WebServer/WebServer.ino create mode 100644 libraries/ESP8266WebServer/examples/WebServer/builtinfiles.h create mode 100644 libraries/ESP8266WebServer/examples/WebServer/data/files.htm create mode 100644 libraries/ESP8266WebServer/examples/WebServer/data/index.htm create mode 100644 libraries/ESP8266WebServer/examples/WebServer/data/style.css create mode 100644 libraries/ESP8266WebServer/examples/WebServer/secrets.h diff --git a/libraries/ESP8266WebServer/examples/WebServer/README.md b/libraries/ESP8266WebServer/examples/WebServer/README.md new file mode 100644 index 0000000000..d404a4a602 --- /dev/null +++ b/libraries/ESP8266WebServer/examples/WebServer/README.md @@ -0,0 +1,199 @@ +# WebServer example documentation and hints + +This example shows different techniques on how to use and extend the ESP8266WebServer for specific purposes + +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 requires some space for a filesystem and runs fine on ESP8266 NodeMCU board with 4 MByte flash using the following options: +* Flash Size Option 4MB (FS:2MB) +* Debug Port Serial +* MMU 32+32 balanced + +It features + +* http access to the web server +* deliver all files from the file system +* deliver special built-in files +* implement services (list files, sysinfo) +* uploading files using drag & drop +* listing and deleting files using a SPA application +* Example of SPA and Web Service application +* Only files in the root folder are supported for simplicity - no directories. + + + + +## Implementing a web server + +The ESP8266WebServer library offers a simple path to implement a web server on a ESP8266 board. + +The advantage on using the ESP8266WebServer instead of the plain simple WiFiServer is that the ESP8266WebServer +takes much care about the http protocol conventions and features and allows easily access to parameters. +It offers plug-in capabilities by registering specific functionalities that will be outlined below. + + +### Initialization + +In the setup() function in the webserver.ino sketch file the following steps are implemented to make the webserver available on the local network. + +* Create a webserver listening to port 80 for http requests. +* Initialize the access to the filesystem in the free flash memory (typically 2MByte). +* Connect to the local WiFi network. Here is only a straight-forward implementation hard-coding network name and passphrase. You may consider to use something like the WiFiManager library. +* Register the device in DNS using a known hostname. +* Registering several plug-ins (see below). +* Starting the web server. + + +### Running + +In the loop() function the web server will be given time to receive and send network packages by calling +`server.handleClient();`. + + + +## Registering simple functions to implement RESTful services + +Registering function is the simplest integration mechanism available to add functionality. The server offers the `on(path, function)` methods that take the URL and the function as parameters. + +There are 2 functions implemented that get registered to handle incoming GET requests for given URLs. + +The JSON data format is used often for such services as it is the "natural" data format of the browser using javascript. + +When the **handleSysInfo()** function is registered and a browser requests for the function will be called and can collect the requested information. + +> ```CPP +> server.on("/$sysinfo", handleSysInfo); +> ``` + +The result in this case is a JSON object that is assembled in the result String variable and the returned as a response to the client also giving the information about the data format. + +You can try this request in a browser by opening in the address bar. + +> ```CPP +> server.on("/$sysinfo", handleList); +> ``` + +The function **handleList()** is registered the same way to return the list of files in the file system also returning a JSON object including name, size and the last modification timestamp. + +You can try this request in a browser by opening in the address bar. + + +## Registering a function to send out some static content from a String + +This is an example of registering a inline function in the web server. +The 2. parameter of the on() method is a so called CPP lamda function (without a name) +that actually has only one line of functionality by sending a string as result to the client. + +> ```CPP +> server.on("/$upload.htm", []() { +> server.send(200, "text/html", FPSTR(uploadContent)); +> }); +> ``` + +Here the text from a static String with html code is returned instead of a file from the filesystem. +The content of this string can be found in the file `builtinfiles.h`. It contains a small html+javascript implementation +that allows uploading new files into the empty filesystem. + +Just open and drag some files from the data folder on the drop area. + + +## Registering a function to handle requests to the server without a path + +Often servers are addressed by using the base URL like where no further path details is given. +Of course we like the user to be redirected to something usable. Therefore the `handleRoot()` function is registered: + +> ```CPP +> server.on("/$upload.htm", handleRoot); +> ``` + +The `handleRoot()` function checks the filesystem for the file named **/index.htm** and creates a redirect to this file when the file exists. +Otherwise the redirection goes to the built-in **/$upload.htm** web page. + + + +## Using the serveStatic plug-in + +The **serveStatic** plug in is part of the library and handles delivering files from the filesystem to the client. It can be customized in some ways. + +> ```CPP +> server.enableCORS(true); +> server.enableETag(true); +> server.serveStatic("/", LittleFS, "/"); +> ``` + + +### Cross-Origin Ressource Sharing (CORS) + +The `enableCORS(true)` function adds a `Access-Control-Allow-Origin: *` http-header to all responses to the client +to inform that it is allowed to call URLs and services on this server from other web sites. + +The feature is disabled by default (in the current version) and when you like to disable this then you should call `enableCORS(false)` during setup. + +* Web sites providing high sensitive information like online banking this is disabled most of the times. +* Web sites providing advertising information or reusable scripts / images this is enabled. + + +### ETag support + +The `enableETag(true)` function adds a ETag http header to the responses to the client that come from files from the filesystem +to enable better use of the cache in the browser. + +When enabled by default the server reads the file content and creates a checksum using the md5 and base64 algorithm her called the ETag value +that changes whenever the file contains something different. + +Once a browser has got the content of a file from the server including the ETag information it will add that ETag value is added in the following requests for the same resource. +Now the server can answer with a 'use the version from the cache' when the new calculated ETag value is equal to the ETag value in the request. + +The calculation of the ETag value requires some time and processing but sending content is always slower. +So when you have the situation that a browser will use a web server multiple times this mechanism saves network and computing and makes web pages more responsive. + +In the source code you can find another version of an algorithm to calculate a ETag value that uses the date&time from the filesystem. +This is a simpler and faster way but with a low risk of dismissing a file update as the timestamp is based on seconds and local time. +This can be enabled on demand, see inline comments. + + +## Registering a full-featured handler as plug-in + +The example also implements the class `FileServerHandler` derived from the class `RequestHandler` to plug in functionality +that can handle more complex requests without giving a fixed URL. +It implements uploading and deleting files in the file system that is not implemented by the standard server.serveStatic functionality. + +This class has to implements several functions and works in a more detailed way: + +* The `canHandle()` method can inspect the given http method and url to decide weather the RequestFileHandler can handle the incoming request or not. + + In this case the RequestFileHandler will return true when the request method is an POST for upload or a DELETE for deleting files. + + The regular GET requests will be ignored and therefore handled by the also registered server.serveStatic handler. + +* The function `handle()` then implements the real deletion of the 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. + + +## 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 + +> ```CPP +> // handle cases when file is not found +> server.onNotFound([]() { +> // standard not found in browser. +> server.send(404, "text/html", FPSTR(notFoundContent)); +> }); +> ``` + +This allows sending back an "friendly" result for the browser. Here a sim ple html page is created from a static string. +You can easily change the html code in the file `builtinfiles.h`. + + +## customizations + +You may like to change the hostname and the timezone in the lines: + +> ```CPP +> #define HOSTNAME "webserver" +> #define TIMEZONE "CET-1CEST,M3.5.0,M10.5.0/3" +> ``` + + diff --git a/libraries/ESP8266WebServer/examples/WebServer/WebServer.ino b/libraries/ESP8266WebServer/examples/WebServer/WebServer.ino new file mode 100644 index 0000000000..f6446d5bce --- /dev/null +++ b/libraries/ESP8266WebServer/examples/WebServer/WebServer.ino @@ -0,0 +1,284 @@ +/** + * @file WebServer.ino + * @brief Example implementation using the ESP8266 WebServer. + * + * See also README.md for instructions and hints. + * + * Changelog: + * 21.07.2021 creation, first version + */ + +#include +#include + +#include "secrets.h" // add WLAN Credentials in here. + +#include // File System for Web Server Files +#include // This file system is used. + +#define TRACE(...) Serial.printf(__VA_ARGS__); + +// name of the server. You reach it using http://webserver +#define HOSTNAME "webserver" + +// local time zone definition (Berlin) +#define TIMEZONE "CET-1CEST,M3.5.0,M10.5.0/3" + +// need a WebServer for http access on port 80. +ESP8266WebServer server(80); + +// The text of builtin files are in this header file +#include "builtinfiles.h" + + +// ===== Simple functions used to answer simple GET requests ===== + +// This function is called when the WebServer was requested without giving a filename. +// This will redirect to the file index.htm when it is existing otherwise to the built-in $upload.htm page +void handleRedirect() +{ + TRACE("Redirect..."); + String url = "/index.htm"; + + if (!LittleFS.exists(url)) { + url = "/$update.htm"; + } + + server.sendHeader("Location", url, true); + server.send(302); + server.client().stop(); +} // handleRedirect() + + +// 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. +void handleListFiles() +{ + Dir dir = LittleFS.openDir("/"); + String result; + + result += "[\n"; + while (dir.next()) { + if (result.length() > 4) + result += ","; + result += " {"; + result += " \"name\": \"" + dir.fileName() + "\", "; + result += " \"size\": " + String(dir.fileSize()) + ", "; + result += " \"time\": " + String(dir.fileTime()); + result += " }\n"; + // jc.addProperty("size", dir.fileSize()); + } // while + result += "]"; + server.sendHeader("Cache-Control", "no-cache"); + server.send(200, "text/javascript; charset=utf-8", result); +} // handleListFiles() + + +// This function is called when the sysInfo service was requested. +void handleSysInfo() +{ + String result; + + FSInfo fs_info; + LittleFS.info(fs_info); + + result += "{\n"; + result += " \"flashSize\": " + String(ESP.getFlashChipSize()) + ",\n"; + result += " \"freeHeap\": " + String(ESP.getFreeHeap()) + ",\n"; + result += " \"fsTotalBytes\": " + String(fs_info.totalBytes) + ",\n"; + result += " \"fsUsedBytes\": " + String(fs_info.usedBytes) + ",\n"; + result += "}"; + + server.sendHeader("Cache-Control", "no-cache"); + server.send(200, "text/javascript; charset=utf-8", result); +} // handleSysInfo() + + +// ===== Request Handler class used to answer more complex requests ===== + +// The FileServerHandler is registered to the web server to support DELETE and UPLOAD of files into the filesystem. +class FileServerHandler : public RequestHandler +{ +public: + /** + * @brief Construct a new File Server Handler object + * @param fs The file system to be used. + * @param path Path to the root folder in the file system that is used for + * Serving static data down and upload. + * @param cache_header Cache Header to be used in replies. + */ + FileServerHandler() + { + TRACE("FileServerHandler is registered\n"); + } + + + /** + @brief check wether the request can be handled by this implementation. + @param requestMethod method of the http request line. + @param requestUri request ressource from the http request line. + @return true when method can be handled. + */ + bool canHandle(HTTPMethod requestMethod, const String &_uri) override + { + return ((requestMethod == HTTP_POST) || (requestMethod == HTTP_DELETE)); + } // canHandle() + + + bool canUpload(const String &uri) override + { + // only allow upload on root fs level. + return (uri == "/"); + } // canUpload() + + + bool handle(ESP8266WebServer &server, HTTPMethod requestMethod, const String &requestUri) override + { + // ensure that filename starts with '/' + String fName = requestUri; + if (!fName.startsWith("/")) { + fName = "/" + fName; + } + + // LOGGER_RAW("File:handle(%s)", requestUri.c_str()); + if (requestMethod == HTTP_POST) { + // all done in upload. no other forms. + + } else if (requestMethod == HTTP_DELETE) { + if (LittleFS.exists(fName)) { + LittleFS.remove(fName); + } + } // if + + server.send(200); // all done. + return (true); + } // handle() + + + void upload(ESP8266WebServer &_server, const String &_requestUri, HTTPUpload &upload) override + { + // ensure that filename starts with '/' + String fName = upload.filename; + if (!fName.startsWith("/")) { + fName = "/" + fName; + } + + // LOGGER_TRACE("upload...<%s>", fName.c_str()); + if (fName.indexOf('#') > 0) { + // LOGGER_TRACE("no #..."); + } else if (fName.indexOf('$') > 0) { + // LOGGER_TRACE("no $..."); + + } else if (upload.status == UPLOAD_FILE_START) { + if (LittleFS.exists(fName)) { + LittleFS.remove(fName); + } // if + _fsUploadFile = LittleFS.open(fName, "w"); + + } else if (upload.status == UPLOAD_FILE_WRITE) { + if (_fsUploadFile) + _fsUploadFile.write(upload.buf, upload.currentSize); + yield(); + + } else if (upload.status == UPLOAD_FILE_END) { + if (_fsUploadFile) { + _fsUploadFile.close(); + } + } // if + } // upload() + +protected: + File _fsUploadFile; +}; + + +/** + * Setup everything to make the webserver work. + */ +void setup(void) +{ + delay(3000); + + // Use Serial port for some trace information from the example + Serial.begin(115200); + Serial.setDebugOutput(false); + + TRACE("Starting WebServer example...\n"); + + TRACE("Mounting the filesystem...\n"); + if (!LittleFS.begin()) { + TRACE("could not mount the filesystem...\n"); + delay(2000); + ESP.restart(); + } + + // start WiFI + WiFi.mode(WIFI_STA); + if (strlen(ssid) == 0) { + WiFi.begin(); + } else { + WiFi.begin(ssid, passPhrase); + } + + // allow to address the device by the given name e.g. http://webserver + WiFi.setHostname(HOSTNAME); + + TRACE("Connect to WiFi...\n"); + while (WiFi.status() != WL_CONNECTED) { + delay(500); + TRACE("."); + } + TRACE("connected.\n"); + + // Ask for the current time using NTP request builtin into ESP firmware. + TRACE("Setup ntp...\n"); + configTime(TIMEZONE, "pool.ntp.org"); + + TRACE("Register service handlers...\n"); + + // serve a built-in htm page + server.on("/$upload.htm", []() { + server.send(200, "text/html", FPSTR(uploadContent)); + }); + + // register a redirect handler when only domain name is given. + server.on("/", HTTP_GET, handleRedirect); + + // register a REST service returning the list of files in the root folder + server.on("/$list", HTTP_GET, handleListFiles); + + // register a REST service returning some more system level information + server.on("/$sysinfo", HTTP_GET, handleSysInfo); + + // UPLOAD and DELETE of files in the file system using a request handler. + server.addHandler(new FileServerHandler()); + + // enable CORS header in webserver results + server.enableCORS(true); + + // enable ETAG header in webserver results from serveStatic handler + server.enableETag(true); + + // serve all static files + server.serveStatic("/", LittleFS, "/"); + + // handle cases when file is not found + server.onNotFound([]() { + // standard not found in browser. + server.send(404, "text/html", FPSTR(notFoundContent)); + }); + + server.begin(); + TRACE("setup done.\n"); + TRACE("hostname=%s\n", WiFi.getHostname()); +} // setup + + +// handle all give time to all Elements and active components. +void loop(void) +{ + server.handleClient(); + // MDNS.update(); +} // loop() + +// end. diff --git a/libraries/ESP8266WebServer/examples/WebServer/builtinfiles.h b/libraries/ESP8266WebServer/examples/WebServer/builtinfiles.h new file mode 100644 index 0000000000..4c13c1f2f3 --- /dev/null +++ b/libraries/ESP8266WebServer/examples/WebServer/builtinfiles.h @@ -0,0 +1,63 @@ +/** + * @file builtinfiles.h + * @brief This file is part of the WebServer example for the ESP8266WebServer. + * + * This file contains long, multiline text variables for all builtin resources. + */ + +// used for $upload.htm +static const char uploadContent[] PROGMEM = +R"==( + + + + + + + Upload + + + +

Upload

+ +
+
Drop files here...
+ + + +)=="; + +// used for $upload.htm +static const char notFoundContent[] PROGMEM = R"==( + + + Ressource not found + + +

The ressource was not found.

+

Start again

+ +)=="; diff --git a/libraries/ESP8266WebServer/examples/WebServer/data/files.htm b/libraries/ESP8266WebServer/examples/WebServer/data/files.htm new file mode 100644 index 0000000000..4eae798980 --- /dev/null +++ b/libraries/ESP8266WebServer/examples/WebServer/data/files.htm @@ -0,0 +1,65 @@ + + + + Files + + + + +

Files on Server

+ +

These files are available on the server to be opened or delete:

+
+
+ + + + + \ No newline at end of file diff --git a/libraries/ESP8266WebServer/examples/WebServer/data/index.htm b/libraries/ESP8266WebServer/examples/WebServer/data/index.htm new file mode 100644 index 0000000000..434f2c1d64 --- /dev/null +++ b/libraries/ESP8266WebServer/examples/WebServer/data/index.htm @@ -0,0 +1,24 @@ + + + + HomePage + + + + +

Homepage of the WebServer Example

+ +

The following pages are available:

+ + +

The following REST services are available:

+
    +
  • /$sysinfo - Some system level information
  • +
  • /$list - Array of all files
  • +
+ + \ No newline at end of file diff --git a/libraries/ESP8266WebServer/examples/WebServer/data/style.css b/libraries/ESP8266WebServer/examples/WebServer/data/style.css new file mode 100644 index 0000000000..4730fef58a --- /dev/null +++ b/libraries/ESP8266WebServer/examples/WebServer/data/style.css @@ -0,0 +1,10 @@ +html, body { + color: #111111; font-family: Arial, ui-sans-serif, sans-serif; font-size: 1em; background-color: #f0f0f0; +} + +#list > div { + margin: 0 0 0.5rem 0; +} + +a { color: inherit; cursor: pointer; } + diff --git a/libraries/ESP8266WebServer/examples/WebServer/secrets.h b/libraries/ESP8266WebServer/examples/WebServer/secrets.h new file mode 100644 index 0000000000..62c3093278 --- /dev/null +++ b/libraries/ESP8266WebServer/examples/WebServer/secrets.h @@ -0,0 +1,13 @@ +// Secrets for your local home network + +// This is a "hard way" to configure your local WiFi network name and passphrase +// into the source code and the uploaded sketch. +// +// Using the WiFi Manager is preferred and avoids reprogramming when your network changes. +// See https://homeding.github.io/#page=/wifimanager.md + +// ssid and passPhrase can be used when compiling for a specific environment as a 2. option. + +// add you wifi network name and PassPhrase or use WiFi Manager +const char *ssid = ""; +const char *passPhrase = ""; From b36a7c32f922c76ddd35fb37f1ab48fdd440d069 Mon Sep 17 00:00:00 2001 From: Matthias Hertel Date: Fri, 23 Jul 2021 08:21:03 +0200 Subject: [PATCH 06/10] fixing unused parameters and cleanup --- .../examples/WebServer/WebServer.ino | 36 +++++++++---------- 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/libraries/ESP8266WebServer/examples/WebServer/WebServer.ino b/libraries/ESP8266WebServer/examples/WebServer/WebServer.ino index f6446d5bce..b4121fe17e 100644 --- a/libraries/ESP8266WebServer/examples/WebServer/WebServer.ino +++ b/libraries/ESP8266WebServer/examples/WebServer/WebServer.ino @@ -16,7 +16,11 @@ #include // File System for Web Server Files #include // This file system is used. -#define TRACE(...) Serial.printf(__VA_ARGS__); +// mark parameters not used in example +#define UNUSED __attribute__((unused)) + +// TRACE output simplified, can be deactivated here +#define TRACE(...) Serial.printf(__VA_ARGS__) // name of the server. You reach it using http://webserver #define HOSTNAME "webserver" @@ -46,7 +50,6 @@ void handleRedirect() server.sendHeader("Location", url, true); server.send(302); - server.client().stop(); } // handleRedirect() @@ -119,8 +122,9 @@ public: @param requestUri request ressource from the http request line. @return true when method can be handled. */ - bool canHandle(HTTPMethod requestMethod, const String &_uri) override + bool canHandle(HTTPMethod requestMethod, const String UNUSED &_uri) override { + // can handle POST for uploads and DELETE. return ((requestMethod == HTTP_POST) || (requestMethod == HTTP_DELETE)); } // canHandle() @@ -140,7 +144,6 @@ public: fName = "/" + fName; } - // LOGGER_RAW("File:handle(%s)", requestUri.c_str()); if (requestMethod == HTTP_POST) { // all done in upload. no other forms. @@ -155,7 +158,8 @@ public: } // handle() - void upload(ESP8266WebServer &_server, const String &_requestUri, HTTPUpload &upload) override + // uploading process + void upload(ESP8266WebServer UNUSED &server, const String UNUSED &_requestUri, HTTPUpload &upload) override { // ensure that filename starts with '/' String fName = upload.filename; @@ -163,24 +167,20 @@ public: fName = "/" + fName; } - // LOGGER_TRACE("upload...<%s>", fName.c_str()); - if (fName.indexOf('#') > 0) { - // LOGGER_TRACE("no #..."); - } else if (fName.indexOf('$') > 0) { - // LOGGER_TRACE("no $..."); - - } else if (upload.status == UPLOAD_FILE_START) { + if (upload.status == UPLOAD_FILE_START) { + // Open the file if (LittleFS.exists(fName)) { LittleFS.remove(fName); } // if _fsUploadFile = LittleFS.open(fName, "w"); } else if (upload.status == UPLOAD_FILE_WRITE) { + // Write received bytes if (_fsUploadFile) _fsUploadFile.write(upload.buf, upload.currentSize); - yield(); } else if (upload.status == UPLOAD_FILE_END) { + // Close the file if (_fsUploadFile) { _fsUploadFile.close(); } @@ -197,7 +197,7 @@ protected: */ void setup(void) { - delay(3000); + delay(3000); // wait for serial monitor to start completely. // Use Serial port for some trace information from the example Serial.begin(115200); @@ -244,10 +244,8 @@ void setup(void) // register a redirect handler when only domain name is given. server.on("/", HTTP_GET, handleRedirect); - // register a REST service returning the list of files in the root folder + // register some REST services server.on("/$list", HTTP_GET, handleListFiles); - - // register a REST service returning some more system level information server.on("/$sysinfo", HTTP_GET, handleSysInfo); // UPLOAD and DELETE of files in the file system using a request handler. @@ -269,16 +267,14 @@ void setup(void) }); server.begin(); - TRACE("setup done.\n"); TRACE("hostname=%s\n", WiFi.getHostname()); } // setup -// handle all give time to all Elements and active components. +// run the server... void loop(void) { server.handleClient(); - // MDNS.update(); } // loop() // end. From f727bb3664f203b2f8bbc1fbe56fed6e889c6853 Mon Sep 17 00:00:00 2001 From: Matthias Hertel Date: Fri, 23 Jul 2021 08:42:59 +0200 Subject: [PATCH 07/10] CRLF into LF --- .../examples/WebServer/README.md | 398 ++++++------- .../examples/WebServer/WebServer.ino | 560 +++++++++--------- .../examples/WebServer/builtinfiles.h | 126 ++-- .../examples/WebServer/data/files.htm | 128 ++-- .../examples/WebServer/data/index.htm | 46 +- .../examples/WebServer/data/style.css | 20 +- .../examples/WebServer/secrets.h | 26 +- 7 files changed, 652 insertions(+), 652 deletions(-) diff --git a/libraries/ESP8266WebServer/examples/WebServer/README.md b/libraries/ESP8266WebServer/examples/WebServer/README.md index d404a4a602..68999100ab 100644 --- a/libraries/ESP8266WebServer/examples/WebServer/README.md +++ b/libraries/ESP8266WebServer/examples/WebServer/README.md @@ -1,199 +1,199 @@ -# WebServer example documentation and hints - -This example shows different techniques on how to use and extend the ESP8266WebServer for specific purposes - -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 requires some space for a filesystem and runs fine on ESP8266 NodeMCU board with 4 MByte flash using the following options: -* Flash Size Option 4MB (FS:2MB) -* Debug Port Serial -* MMU 32+32 balanced - -It features - -* http access to the web server -* deliver all files from the file system -* deliver special built-in files -* implement services (list files, sysinfo) -* uploading files using drag & drop -* listing and deleting files using a SPA application -* Example of SPA and Web Service application -* Only files in the root folder are supported for simplicity - no directories. - - - - -## Implementing a web server - -The ESP8266WebServer library offers a simple path to implement a web server on a ESP8266 board. - -The advantage on using the ESP8266WebServer instead of the plain simple WiFiServer is that the ESP8266WebServer -takes much care about the http protocol conventions and features and allows easily access to parameters. -It offers plug-in capabilities by registering specific functionalities that will be outlined below. - - -### Initialization - -In the setup() function in the webserver.ino sketch file the following steps are implemented to make the webserver available on the local network. - -* Create a webserver listening to port 80 for http requests. -* Initialize the access to the filesystem in the free flash memory (typically 2MByte). -* Connect to the local WiFi network. Here is only a straight-forward implementation hard-coding network name and passphrase. You may consider to use something like the WiFiManager library. -* Register the device in DNS using a known hostname. -* Registering several plug-ins (see below). -* Starting the web server. - - -### Running - -In the loop() function the web server will be given time to receive and send network packages by calling -`server.handleClient();`. - - - -## Registering simple functions to implement RESTful services - -Registering function is the simplest integration mechanism available to add functionality. The server offers the `on(path, function)` methods that take the URL and the function as parameters. - -There are 2 functions implemented that get registered to handle incoming GET requests for given URLs. - -The JSON data format is used often for such services as it is the "natural" data format of the browser using javascript. - -When the **handleSysInfo()** function is registered and a browser requests for the function will be called and can collect the requested information. - -> ```CPP -> server.on("/$sysinfo", handleSysInfo); -> ``` - -The result in this case is a JSON object that is assembled in the result String variable and the returned as a response to the client also giving the information about the data format. - -You can try this request in a browser by opening in the address bar. - -> ```CPP -> server.on("/$sysinfo", handleList); -> ``` - -The function **handleList()** is registered the same way to return the list of files in the file system also returning a JSON object including name, size and the last modification timestamp. - -You can try this request in a browser by opening in the address bar. - - -## Registering a function to send out some static content from a String - -This is an example of registering a inline function in the web server. -The 2. parameter of the on() method is a so called CPP lamda function (without a name) -that actually has only one line of functionality by sending a string as result to the client. - -> ```CPP -> server.on("/$upload.htm", []() { -> server.send(200, "text/html", FPSTR(uploadContent)); -> }); -> ``` - -Here the text from a static String with html code is returned instead of a file from the filesystem. -The content of this string can be found in the file `builtinfiles.h`. It contains a small html+javascript implementation -that allows uploading new files into the empty filesystem. - -Just open and drag some files from the data folder on the drop area. - - -## Registering a function to handle requests to the server without a path - -Often servers are addressed by using the base URL like where no further path details is given. -Of course we like the user to be redirected to something usable. Therefore the `handleRoot()` function is registered: - -> ```CPP -> server.on("/$upload.htm", handleRoot); -> ``` - -The `handleRoot()` function checks the filesystem for the file named **/index.htm** and creates a redirect to this file when the file exists. -Otherwise the redirection goes to the built-in **/$upload.htm** web page. - - - -## Using the serveStatic plug-in - -The **serveStatic** plug in is part of the library and handles delivering files from the filesystem to the client. It can be customized in some ways. - -> ```CPP -> server.enableCORS(true); -> server.enableETag(true); -> server.serveStatic("/", LittleFS, "/"); -> ``` - - -### Cross-Origin Ressource Sharing (CORS) - -The `enableCORS(true)` function adds a `Access-Control-Allow-Origin: *` http-header to all responses to the client -to inform that it is allowed to call URLs and services on this server from other web sites. - -The feature is disabled by default (in the current version) and when you like to disable this then you should call `enableCORS(false)` during setup. - -* Web sites providing high sensitive information like online banking this is disabled most of the times. -* Web sites providing advertising information or reusable scripts / images this is enabled. - - -### ETag support - -The `enableETag(true)` function adds a ETag http header to the responses to the client that come from files from the filesystem -to enable better use of the cache in the browser. - -When enabled by default the server reads the file content and creates a checksum using the md5 and base64 algorithm her called the ETag value -that changes whenever the file contains something different. - -Once a browser has got the content of a file from the server including the ETag information it will add that ETag value is added in the following requests for the same resource. -Now the server can answer with a 'use the version from the cache' when the new calculated ETag value is equal to the ETag value in the request. - -The calculation of the ETag value requires some time and processing but sending content is always slower. -So when you have the situation that a browser will use a web server multiple times this mechanism saves network and computing and makes web pages more responsive. - -In the source code you can find another version of an algorithm to calculate a ETag value that uses the date&time from the filesystem. -This is a simpler and faster way but with a low risk of dismissing a file update as the timestamp is based on seconds and local time. -This can be enabled on demand, see inline comments. - - -## Registering a full-featured handler as plug-in - -The example also implements the class `FileServerHandler` derived from the class `RequestHandler` to plug in functionality -that can handle more complex requests without giving a fixed URL. -It implements uploading and deleting files in the file system that is not implemented by the standard server.serveStatic functionality. - -This class has to implements several functions and works in a more detailed way: - -* The `canHandle()` method can inspect the given http method and url to decide weather the RequestFileHandler can handle the incoming request or not. - - In this case the RequestFileHandler will return true when the request method is an POST for upload or a DELETE for deleting files. - - The regular GET requests will be ignored and therefore handled by the also registered server.serveStatic handler. - -* The function `handle()` then implements the real deletion of the 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. - - -## 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 - -> ```CPP -> // handle cases when file is not found -> server.onNotFound([]() { -> // standard not found in browser. -> server.send(404, "text/html", FPSTR(notFoundContent)); -> }); -> ``` - -This allows sending back an "friendly" result for the browser. Here a sim ple html page is created from a static string. -You can easily change the html code in the file `builtinfiles.h`. - - -## customizations - -You may like to change the hostname and the timezone in the lines: - -> ```CPP -> #define HOSTNAME "webserver" -> #define TIMEZONE "CET-1CEST,M3.5.0,M10.5.0/3" -> ``` - - +# WebServer example documentation and hints + +This example shows different techniques on how to use and extend the ESP8266WebServer for specific purposes + +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 requires some space for a filesystem and runs fine on ESP8266 NodeMCU board with 4 MByte flash using the following options: +* Flash Size Option 4MB (FS:2MB) +* Debug Port Serial +* MMU 32+32 balanced + +It features + +* http access to the web server +* deliver all files from the file system +* deliver special built-in files +* implement services (list files, sysinfo) +* uploading files using drag & drop +* listing and deleting files using a SPA application +* Example of SPA and Web Service application +* Only files in the root folder are supported for simplicity - no directories. + + + + +## Implementing a web server + +The ESP8266WebServer library offers a simple path to implement a web server on a ESP8266 board. + +The advantage on using the ESP8266WebServer instead of the plain simple WiFiServer is that the ESP8266WebServer +takes much care about the http protocol conventions and features and allows easily access to parameters. +It offers plug-in capabilities by registering specific functionalities that will be outlined below. + + +### Initialization + +In the setup() function in the webserver.ino sketch file the following steps are implemented to make the webserver available on the local network. + +* Create a webserver listening to port 80 for http requests. +* Initialize the access to the filesystem in the free flash memory (typically 2MByte). +* Connect to the local WiFi network. Here is only a straight-forward implementation hard-coding network name and passphrase. You may consider to use something like the WiFiManager library. +* Register the device in DNS using a known hostname. +* Registering several plug-ins (see below). +* Starting the web server. + + +### Running + +In the loop() function the web server will be given time to receive and send network packages by calling +`server.handleClient();`. + + + +## Registering simple functions to implement RESTful services + +Registering function is the simplest integration mechanism available to add functionality. The server offers the `on(path, function)` methods that take the URL and the function as parameters. + +There are 2 functions implemented that get registered to handle incoming GET requests for given URLs. + +The JSON data format is used often for such services as it is the "natural" data format of the browser using javascript. + +When the **handleSysInfo()** function is registered and a browser requests for the function will be called and can collect the requested information. + +> ```CPP +> server.on("/$sysinfo", handleSysInfo); +> ``` + +The result in this case is a JSON object that is assembled in the result String variable and the returned as a response to the client also giving the information about the data format. + +You can try this request in a browser by opening in the address bar. + +> ```CPP +> server.on("/$sysinfo", handleList); +> ``` + +The function **handleList()** is registered the same way to return the list of files in the file system also returning a JSON object including name, size and the last modification timestamp. + +You can try this request in a browser by opening in the address bar. + + +## Registering a function to send out some static content from a String + +This is an example of registering a inline function in the web server. +The 2. parameter of the on() method is a so called CPP lamda function (without a name) +that actually has only one line of functionality by sending a string as result to the client. + +> ```CPP +> server.on("/$upload.htm", []() { +> server.send(200, "text/html", FPSTR(uploadContent)); +> }); +> ``` + +Here the text from a static String with html code is returned instead of a file from the filesystem. +The content of this string can be found in the file `builtinfiles.h`. It contains a small html+javascript implementation +that allows uploading new files into the empty filesystem. + +Just open and drag some files from the data folder on the drop area. + + +## Registering a function to handle requests to the server without a path + +Often servers are addressed by using the base URL like where no further path details is given. +Of course we like the user to be redirected to something usable. Therefore the `handleRoot()` function is registered: + +> ```CPP +> server.on("/$upload.htm", handleRoot); +> ``` + +The `handleRoot()` function checks the filesystem for the file named **/index.htm** and creates a redirect to this file when the file exists. +Otherwise the redirection goes to the built-in **/$upload.htm** web page. + + + +## Using the serveStatic plug-in + +The **serveStatic** plug in is part of the library and handles delivering files from the filesystem to the client. It can be customized in some ways. + +> ```CPP +> server.enableCORS(true); +> server.enableETag(true); +> server.serveStatic("/", LittleFS, "/"); +> ``` + + +### Cross-Origin Ressource Sharing (CORS) + +The `enableCORS(true)` function adds a `Access-Control-Allow-Origin: *` http-header to all responses to the client +to inform that it is allowed to call URLs and services on this server from other web sites. + +The feature is disabled by default (in the current version) and when you like to disable this then you should call `enableCORS(false)` during setup. + +* Web sites providing high sensitive information like online banking this is disabled most of the times. +* Web sites providing advertising information or reusable scripts / images this is enabled. + + +### ETag support + +The `enableETag(true)` function adds a ETag http header to the responses to the client that come from files from the filesystem +to enable better use of the cache in the browser. + +When enabled by default the server reads the file content and creates a checksum using the md5 and base64 algorithm her called the ETag value +that changes whenever the file contains something different. + +Once a browser has got the content of a file from the server including the ETag information it will add that ETag value is added in the following requests for the same resource. +Now the server can answer with a 'use the version from the cache' when the new calculated ETag value is equal to the ETag value in the request. + +The calculation of the ETag value requires some time and processing but sending content is always slower. +So when you have the situation that a browser will use a web server multiple times this mechanism saves network and computing and makes web pages more responsive. + +In the source code you can find another version of an algorithm to calculate a ETag value that uses the date&time from the filesystem. +This is a simpler and faster way but with a low risk of dismissing a file update as the timestamp is based on seconds and local time. +This can be enabled on demand, see inline comments. + + +## Registering a full-featured handler as plug-in + +The example also implements the class `FileServerHandler` derived from the class `RequestHandler` to plug in functionality +that can handle more complex requests without giving a fixed URL. +It implements uploading and deleting files in the file system that is not implemented by the standard server.serveStatic functionality. + +This class has to implements several functions and works in a more detailed way: + +* The `canHandle()` method can inspect the given http method and url to decide weather the RequestFileHandler can handle the incoming request or not. + + In this case the RequestFileHandler will return true when the request method is an POST for upload or a DELETE for deleting files. + + The regular GET requests will be ignored and therefore handled by the also registered server.serveStatic handler. + +* The function `handle()` then implements the real deletion of the 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. + + +## 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 + +> ```CPP +> // handle cases when file is not found +> server.onNotFound([]() { +> // standard not found in browser. +> server.send(404, "text/html", FPSTR(notFoundContent)); +> }); +> ``` + +This allows sending back an "friendly" result for the browser. Here a sim ple html page is created from a static string. +You can easily change the html code in the file `builtinfiles.h`. + + +## customizations + +You may like to change the hostname and the timezone in the lines: + +> ```CPP +> #define HOSTNAME "webserver" +> #define TIMEZONE "CET-1CEST,M3.5.0,M10.5.0/3" +> ``` + + diff --git a/libraries/ESP8266WebServer/examples/WebServer/WebServer.ino b/libraries/ESP8266WebServer/examples/WebServer/WebServer.ino index b4121fe17e..0bb0575208 100644 --- a/libraries/ESP8266WebServer/examples/WebServer/WebServer.ino +++ b/libraries/ESP8266WebServer/examples/WebServer/WebServer.ino @@ -1,280 +1,280 @@ -/** - * @file WebServer.ino - * @brief Example implementation using the ESP8266 WebServer. - * - * See also README.md for instructions and hints. - * - * Changelog: - * 21.07.2021 creation, first version - */ - -#include -#include - -#include "secrets.h" // add WLAN Credentials in here. - -#include // File System for Web Server Files -#include // This file system is used. - -// mark parameters not used in example -#define UNUSED __attribute__((unused)) - -// TRACE output simplified, can be deactivated here -#define TRACE(...) Serial.printf(__VA_ARGS__) - -// name of the server. You reach it using http://webserver -#define HOSTNAME "webserver" - -// local time zone definition (Berlin) -#define TIMEZONE "CET-1CEST,M3.5.0,M10.5.0/3" - -// need a WebServer for http access on port 80. -ESP8266WebServer server(80); - -// The text of builtin files are in this header file -#include "builtinfiles.h" - - -// ===== Simple functions used to answer simple GET requests ===== - -// This function is called when the WebServer was requested without giving a filename. -// This will redirect to the file index.htm when it is existing otherwise to the built-in $upload.htm page -void handleRedirect() -{ - TRACE("Redirect..."); - String url = "/index.htm"; - - if (!LittleFS.exists(url)) { - url = "/$update.htm"; - } - - server.sendHeader("Location", url, true); - server.send(302); -} // handleRedirect() - - -// 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. -void handleListFiles() -{ - Dir dir = LittleFS.openDir("/"); - String result; - - result += "[\n"; - while (dir.next()) { - if (result.length() > 4) - result += ","; - result += " {"; - result += " \"name\": \"" + dir.fileName() + "\", "; - result += " \"size\": " + String(dir.fileSize()) + ", "; - result += " \"time\": " + String(dir.fileTime()); - result += " }\n"; - // jc.addProperty("size", dir.fileSize()); - } // while - result += "]"; - server.sendHeader("Cache-Control", "no-cache"); - server.send(200, "text/javascript; charset=utf-8", result); -} // handleListFiles() - - -// This function is called when the sysInfo service was requested. -void handleSysInfo() -{ - String result; - - FSInfo fs_info; - LittleFS.info(fs_info); - - result += "{\n"; - result += " \"flashSize\": " + String(ESP.getFlashChipSize()) + ",\n"; - result += " \"freeHeap\": " + String(ESP.getFreeHeap()) + ",\n"; - result += " \"fsTotalBytes\": " + String(fs_info.totalBytes) + ",\n"; - result += " \"fsUsedBytes\": " + String(fs_info.usedBytes) + ",\n"; - result += "}"; - - server.sendHeader("Cache-Control", "no-cache"); - server.send(200, "text/javascript; charset=utf-8", result); -} // handleSysInfo() - - -// ===== Request Handler class used to answer more complex requests ===== - -// The FileServerHandler is registered to the web server to support DELETE and UPLOAD of files into the filesystem. -class FileServerHandler : public RequestHandler -{ -public: - /** - * @brief Construct a new File Server Handler object - * @param fs The file system to be used. - * @param path Path to the root folder in the file system that is used for - * Serving static data down and upload. - * @param cache_header Cache Header to be used in replies. - */ - FileServerHandler() - { - TRACE("FileServerHandler is registered\n"); - } - - - /** - @brief check wether the request can be handled by this implementation. - @param requestMethod method of the http request line. - @param requestUri request ressource from the http request line. - @return true when method can be handled. - */ - bool canHandle(HTTPMethod requestMethod, const String UNUSED &_uri) override - { - // can handle POST for uploads and DELETE. - return ((requestMethod == HTTP_POST) || (requestMethod == HTTP_DELETE)); - } // canHandle() - - - bool canUpload(const String &uri) override - { - // only allow upload on root fs level. - return (uri == "/"); - } // canUpload() - - - bool handle(ESP8266WebServer &server, HTTPMethod requestMethod, const String &requestUri) override - { - // ensure that filename starts with '/' - String fName = requestUri; - if (!fName.startsWith("/")) { - fName = "/" + fName; - } - - if (requestMethod == HTTP_POST) { - // all done in upload. no other forms. - - } else if (requestMethod == HTTP_DELETE) { - if (LittleFS.exists(fName)) { - LittleFS.remove(fName); - } - } // if - - server.send(200); // all done. - return (true); - } // handle() - - - // uploading process - void upload(ESP8266WebServer UNUSED &server, const String UNUSED &_requestUri, HTTPUpload &upload) override - { - // ensure that filename starts with '/' - String fName = upload.filename; - if (!fName.startsWith("/")) { - fName = "/" + fName; - } - - if (upload.status == UPLOAD_FILE_START) { - // Open the file - if (LittleFS.exists(fName)) { - LittleFS.remove(fName); - } // if - _fsUploadFile = LittleFS.open(fName, "w"); - - } else if (upload.status == UPLOAD_FILE_WRITE) { - // Write received bytes - if (_fsUploadFile) - _fsUploadFile.write(upload.buf, upload.currentSize); - - } else if (upload.status == UPLOAD_FILE_END) { - // Close the file - if (_fsUploadFile) { - _fsUploadFile.close(); - } - } // if - } // upload() - -protected: - File _fsUploadFile; -}; - - -/** - * Setup everything to make the webserver work. - */ -void setup(void) -{ - delay(3000); // wait for serial monitor to start completely. - - // Use Serial port for some trace information from the example - Serial.begin(115200); - Serial.setDebugOutput(false); - - TRACE("Starting WebServer example...\n"); - - TRACE("Mounting the filesystem...\n"); - if (!LittleFS.begin()) { - TRACE("could not mount the filesystem...\n"); - delay(2000); - ESP.restart(); - } - - // start WiFI - WiFi.mode(WIFI_STA); - if (strlen(ssid) == 0) { - WiFi.begin(); - } else { - WiFi.begin(ssid, passPhrase); - } - - // allow to address the device by the given name e.g. http://webserver - WiFi.setHostname(HOSTNAME); - - TRACE("Connect to WiFi...\n"); - while (WiFi.status() != WL_CONNECTED) { - delay(500); - TRACE("."); - } - TRACE("connected.\n"); - - // Ask for the current time using NTP request builtin into ESP firmware. - TRACE("Setup ntp...\n"); - configTime(TIMEZONE, "pool.ntp.org"); - - TRACE("Register service handlers...\n"); - - // serve a built-in htm page - server.on("/$upload.htm", []() { - server.send(200, "text/html", FPSTR(uploadContent)); - }); - - // register a redirect handler when only domain name is given. - server.on("/", HTTP_GET, handleRedirect); - - // register some REST services - server.on("/$list", HTTP_GET, handleListFiles); - server.on("/$sysinfo", HTTP_GET, handleSysInfo); - - // UPLOAD and DELETE of files in the file system using a request handler. - server.addHandler(new FileServerHandler()); - - // enable CORS header in webserver results - server.enableCORS(true); - - // enable ETAG header in webserver results from serveStatic handler - server.enableETag(true); - - // serve all static files - server.serveStatic("/", LittleFS, "/"); - - // handle cases when file is not found - server.onNotFound([]() { - // standard not found in browser. - server.send(404, "text/html", FPSTR(notFoundContent)); - }); - - server.begin(); - TRACE("hostname=%s\n", WiFi.getHostname()); -} // setup - - -// run the server... -void loop(void) -{ - server.handleClient(); -} // loop() - -// end. +/** + * @file WebServer.ino + * @brief Example implementation using the ESP8266 WebServer. + * + * See also README.md for instructions and hints. + * + * Changelog: + * 21.07.2021 creation, first version + */ + +#include +#include + +#include "secrets.h" // add WLAN Credentials in here. + +#include // File System for Web Server Files +#include // This file system is used. + +// mark parameters not used in example +#define UNUSED __attribute__((unused)) + +// TRACE output simplified, can be deactivated here +#define TRACE(...) Serial.printf(__VA_ARGS__) + +// name of the server. You reach it using http://webserver +#define HOSTNAME "webserver" + +// local time zone definition (Berlin) +#define TIMEZONE "CET-1CEST,M3.5.0,M10.5.0/3" + +// need a WebServer for http access on port 80. +ESP8266WebServer server(80); + +// The text of builtin files are in this header file +#include "builtinfiles.h" + + +// ===== Simple functions used to answer simple GET requests ===== + +// This function is called when the WebServer was requested without giving a filename. +// This will redirect to the file index.htm when it is existing otherwise to the built-in $upload.htm page +void handleRedirect() +{ + TRACE("Redirect..."); + String url = "/index.htm"; + + if (!LittleFS.exists(url)) { + url = "/$update.htm"; + } + + server.sendHeader("Location", url, true); + server.send(302); +} // handleRedirect() + + +// 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. +void handleListFiles() +{ + Dir dir = LittleFS.openDir("/"); + String result; + + result += "[\n"; + while (dir.next()) { + if (result.length() > 4) + result += ","; + result += " {"; + result += " \"name\": \"" + dir.fileName() + "\", "; + result += " \"size\": " + String(dir.fileSize()) + ", "; + result += " \"time\": " + String(dir.fileTime()); + result += " }\n"; + // jc.addProperty("size", dir.fileSize()); + } // while + result += "]"; + server.sendHeader("Cache-Control", "no-cache"); + server.send(200, "text/javascript; charset=utf-8", result); +} // handleListFiles() + + +// This function is called when the sysInfo service was requested. +void handleSysInfo() +{ + String result; + + FSInfo fs_info; + LittleFS.info(fs_info); + + result += "{\n"; + result += " \"flashSize\": " + String(ESP.getFlashChipSize()) + ",\n"; + result += " \"freeHeap\": " + String(ESP.getFreeHeap()) + ",\n"; + result += " \"fsTotalBytes\": " + String(fs_info.totalBytes) + ",\n"; + result += " \"fsUsedBytes\": " + String(fs_info.usedBytes) + ",\n"; + result += "}"; + + server.sendHeader("Cache-Control", "no-cache"); + server.send(200, "text/javascript; charset=utf-8", result); +} // handleSysInfo() + + +// ===== Request Handler class used to answer more complex requests ===== + +// The FileServerHandler is registered to the web server to support DELETE and UPLOAD of files into the filesystem. +class FileServerHandler : public RequestHandler +{ +public: + /** + * @brief Construct a new File Server Handler object + * @param fs The file system to be used. + * @param path Path to the root folder in the file system that is used for + * Serving static data down and upload. + * @param cache_header Cache Header to be used in replies. + */ + FileServerHandler() + { + TRACE("FileServerHandler is registered\n"); + } + + + /** + @brief check wether the request can be handled by this implementation. + @param requestMethod method of the http request line. + @param requestUri request ressource from the http request line. + @return true when method can be handled. + */ + bool canHandle(HTTPMethod requestMethod, const String UNUSED &_uri) override + { + // can handle POST for uploads and DELETE. + return ((requestMethod == HTTP_POST) || (requestMethod == HTTP_DELETE)); + } // canHandle() + + + bool canUpload(const String &uri) override + { + // only allow upload on root fs level. + return (uri == "/"); + } // canUpload() + + + bool handle(ESP8266WebServer &server, HTTPMethod requestMethod, const String &requestUri) override + { + // ensure that filename starts with '/' + String fName = requestUri; + if (!fName.startsWith("/")) { + fName = "/" + fName; + } + + if (requestMethod == HTTP_POST) { + // all done in upload. no other forms. + + } else if (requestMethod == HTTP_DELETE) { + if (LittleFS.exists(fName)) { + LittleFS.remove(fName); + } + } // if + + server.send(200); // all done. + return (true); + } // handle() + + + // uploading process + void upload(ESP8266WebServer UNUSED &server, const String UNUSED &_requestUri, HTTPUpload &upload) override + { + // ensure that filename starts with '/' + String fName = upload.filename; + if (!fName.startsWith("/")) { + fName = "/" + fName; + } + + if (upload.status == UPLOAD_FILE_START) { + // Open the file + if (LittleFS.exists(fName)) { + LittleFS.remove(fName); + } // if + _fsUploadFile = LittleFS.open(fName, "w"); + + } else if (upload.status == UPLOAD_FILE_WRITE) { + // Write received bytes + if (_fsUploadFile) + _fsUploadFile.write(upload.buf, upload.currentSize); + + } else if (upload.status == UPLOAD_FILE_END) { + // Close the file + if (_fsUploadFile) { + _fsUploadFile.close(); + } + } // if + } // upload() + +protected: + File _fsUploadFile; +}; + + +/** + * Setup everything to make the webserver work. + */ +void setup(void) +{ + delay(3000); // wait for serial monitor to start completely. + + // Use Serial port for some trace information from the example + Serial.begin(115200); + Serial.setDebugOutput(false); + + TRACE("Starting WebServer example...\n"); + + TRACE("Mounting the filesystem...\n"); + if (!LittleFS.begin()) { + TRACE("could not mount the filesystem...\n"); + delay(2000); + ESP.restart(); + } + + // start WiFI + WiFi.mode(WIFI_STA); + if (strlen(ssid) == 0) { + WiFi.begin(); + } else { + WiFi.begin(ssid, passPhrase); + } + + // allow to address the device by the given name e.g. http://webserver + WiFi.setHostname(HOSTNAME); + + TRACE("Connect to WiFi...\n"); + while (WiFi.status() != WL_CONNECTED) { + delay(500); + TRACE("."); + } + TRACE("connected.\n"); + + // Ask for the current time using NTP request builtin into ESP firmware. + TRACE("Setup ntp...\n"); + configTime(TIMEZONE, "pool.ntp.org"); + + TRACE("Register service handlers...\n"); + + // serve a built-in htm page + server.on("/$upload.htm", []() { + server.send(200, "text/html", FPSTR(uploadContent)); + }); + + // register a redirect handler when only domain name is given. + server.on("/", HTTP_GET, handleRedirect); + + // register some REST services + server.on("/$list", HTTP_GET, handleListFiles); + server.on("/$sysinfo", HTTP_GET, handleSysInfo); + + // UPLOAD and DELETE of files in the file system using a request handler. + server.addHandler(new FileServerHandler()); + + // enable CORS header in webserver results + server.enableCORS(true); + + // enable ETAG header in webserver results from serveStatic handler + server.enableETag(true); + + // serve all static files + server.serveStatic("/", LittleFS, "/"); + + // handle cases when file is not found + server.onNotFound([]() { + // standard not found in browser. + server.send(404, "text/html", FPSTR(notFoundContent)); + }); + + server.begin(); + TRACE("hostname=%s\n", WiFi.getHostname()); +} // setup + + +// run the server... +void loop(void) +{ + server.handleClient(); +} // loop() + +// end. diff --git a/libraries/ESP8266WebServer/examples/WebServer/builtinfiles.h b/libraries/ESP8266WebServer/examples/WebServer/builtinfiles.h index 4c13c1f2f3..210b18c1a5 100644 --- a/libraries/ESP8266WebServer/examples/WebServer/builtinfiles.h +++ b/libraries/ESP8266WebServer/examples/WebServer/builtinfiles.h @@ -1,63 +1,63 @@ -/** - * @file builtinfiles.h - * @brief This file is part of the WebServer example for the ESP8266WebServer. - * - * This file contains long, multiline text variables for all builtin resources. - */ - -// used for $upload.htm -static const char uploadContent[] PROGMEM = -R"==( - - - - - - - Upload - - - -

Upload

- -
-
Drop files here...
- - - -)=="; - -// used for $upload.htm -static const char notFoundContent[] PROGMEM = R"==( - - - Ressource not found - - -

The ressource was not found.

-

Start again

- -)=="; +/** + * @file builtinfiles.h + * @brief This file is part of the WebServer example for the ESP8266WebServer. + * + * This file contains long, multiline text variables for all builtin resources. + */ + +// used for $upload.htm +static const char uploadContent[] PROGMEM = +R"==( + + + + + + + Upload + + + +

Upload

+ +
+
Drop files here...
+ + + +)=="; + +// used for $upload.htm +static const char notFoundContent[] PROGMEM = R"==( + + + Ressource not found + + +

The ressource was not found.

+

Start again

+ +)=="; diff --git a/libraries/ESP8266WebServer/examples/WebServer/data/files.htm b/libraries/ESP8266WebServer/examples/WebServer/data/files.htm index 4eae798980..c05c22fc78 100644 --- a/libraries/ESP8266WebServer/examples/WebServer/data/files.htm +++ b/libraries/ESP8266WebServer/examples/WebServer/data/files.htm @@ -1,65 +1,65 @@ - - - - Files - - - - -

Files on Server

- -

These files are available on the server to be opened or delete:

-
-
- - - - + + + + Files + + + + +

Files on Server

+ +

These files are available on the server to be opened or delete:

+
+
+ + + + \ No newline at end of file diff --git a/libraries/ESP8266WebServer/examples/WebServer/data/index.htm b/libraries/ESP8266WebServer/examples/WebServer/data/index.htm index 434f2c1d64..89188f5203 100644 --- a/libraries/ESP8266WebServer/examples/WebServer/data/index.htm +++ b/libraries/ESP8266WebServer/examples/WebServer/data/index.htm @@ -1,24 +1,24 @@ - - - - HomePage - - - - -

Homepage of the WebServer Example

- -

The following pages are available:

- - -

The following REST services are available:

-
    -
  • /$sysinfo - Some system level information
  • -
  • /$list - Array of all files
  • -
- + + + + HomePage + + + + +

Homepage of the WebServer Example

+ +

The following pages are available:

+ + +

The following REST services are available:

+
    +
  • /$sysinfo - Some system level information
  • +
  • /$list - Array of all files
  • +
+ \ No newline at end of file diff --git a/libraries/ESP8266WebServer/examples/WebServer/data/style.css b/libraries/ESP8266WebServer/examples/WebServer/data/style.css index 4730fef58a..95ac48e727 100644 --- a/libraries/ESP8266WebServer/examples/WebServer/data/style.css +++ b/libraries/ESP8266WebServer/examples/WebServer/data/style.css @@ -1,10 +1,10 @@ -html, body { - color: #111111; font-family: Arial, ui-sans-serif, sans-serif; font-size: 1em; background-color: #f0f0f0; -} - -#list > div { - margin: 0 0 0.5rem 0; -} - -a { color: inherit; cursor: pointer; } - +html, body { + color: #111111; font-family: Arial, ui-sans-serif, sans-serif; font-size: 1em; background-color: #f0f0f0; +} + +#list > div { + margin: 0 0 0.5rem 0; +} + +a { color: inherit; cursor: pointer; } + diff --git a/libraries/ESP8266WebServer/examples/WebServer/secrets.h b/libraries/ESP8266WebServer/examples/WebServer/secrets.h index 62c3093278..094e0dfa7d 100644 --- a/libraries/ESP8266WebServer/examples/WebServer/secrets.h +++ b/libraries/ESP8266WebServer/examples/WebServer/secrets.h @@ -1,13 +1,13 @@ -// Secrets for your local home network - -// This is a "hard way" to configure your local WiFi network name and passphrase -// into the source code and the uploaded sketch. -// -// Using the WiFi Manager is preferred and avoids reprogramming when your network changes. -// See https://homeding.github.io/#page=/wifimanager.md - -// ssid and passPhrase can be used when compiling for a specific environment as a 2. option. - -// add you wifi network name and PassPhrase or use WiFi Manager -const char *ssid = ""; -const char *passPhrase = ""; +// Secrets for your local home network + +// This is a "hard way" to configure your local WiFi network name and passphrase +// into the source code and the uploaded sketch. +// +// Using the WiFi Manager is preferred and avoids reprogramming when your network changes. +// See https://homeding.github.io/#page=/wifimanager.md + +// ssid and passPhrase can be used when compiling for a specific environment as a 2. option. + +// add you wifi network name and PassPhrase or use WiFi Manager +const char *ssid = "KHMH"; +const char *passPhrase = "hk-2012FD2926"; From eb04578f0a69745b83cc32daac2579baac93d635 Mon Sep 17 00:00:00 2001 From: Matthias Hertel Date: Fri, 23 Jul 2021 09:04:54 +0200 Subject: [PATCH 08/10] fixing style --- .../examples/WebServer/WebServer.ino | 45 +++++++------------ 1 file changed, 17 insertions(+), 28 deletions(-) diff --git a/libraries/ESP8266WebServer/examples/WebServer/WebServer.ino b/libraries/ESP8266WebServer/examples/WebServer/WebServer.ino index 0bb0575208..f81e72d244 100644 --- a/libraries/ESP8266WebServer/examples/WebServer/WebServer.ino +++ b/libraries/ESP8266WebServer/examples/WebServer/WebServer.ino @@ -39,8 +39,7 @@ ESP8266WebServer server(80); // This function is called when the WebServer was requested without giving a filename. // This will redirect to the file index.htm when it is existing otherwise to the built-in $upload.htm page -void handleRedirect() -{ +void handleRedirect() { TRACE("Redirect..."); String url = "/index.htm"; @@ -55,15 +54,15 @@ void handleRedirect() // 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. -void handleListFiles() -{ +void handleListFiles() { Dir dir = LittleFS.openDir("/"); String result; result += "[\n"; while (dir.next()) { - if (result.length() > 4) + if (result.length() > 4) { result += ","; + } result += " {"; result += " \"name\": \"" + dir.fileName() + "\", "; result += " \"size\": " + String(dir.fileSize()) + ", "; @@ -78,8 +77,7 @@ void handleListFiles() // This function is called when the sysInfo service was requested. -void handleSysInfo() -{ +void handleSysInfo() { String result; FSInfo fs_info; @@ -100,18 +98,15 @@ void handleSysInfo() // ===== Request Handler class used to answer more complex requests ===== // The FileServerHandler is registered to the web server to support DELETE and UPLOAD of files into the filesystem. -class FileServerHandler : public RequestHandler -{ +class FileServerHandler : public RequestHandler { public: /** - * @brief Construct a new File Server Handler object - * @param fs The file system to be used. - * @param path Path to the root folder in the file system that is used for - * Serving static data down and upload. - * @param cache_header Cache Header to be used in replies. + @brief Construct a new File Server Handler object + @param fs The file system to be used. + @param path Path to the root folder in the file system that is used for serving static data down and upload. + @param cache_header Cache Header to be used in replies. */ - FileServerHandler() - { + FileServerHandler() { TRACE("FileServerHandler is registered\n"); } @@ -122,22 +117,19 @@ public: @param requestUri request ressource from the http request line. @return true when method can be handled. */ - bool canHandle(HTTPMethod requestMethod, const String UNUSED &_uri) override - { + bool canHandle(HTTPMethod requestMethod, const String UNUSED &_uri) override { // can handle POST for uploads and DELETE. return ((requestMethod == HTTP_POST) || (requestMethod == HTTP_DELETE)); } // canHandle() - bool canUpload(const String &uri) override - { + bool canUpload(const String &uri) override { // only allow upload on root fs level. return (uri == "/"); } // canUpload() - bool handle(ESP8266WebServer &server, HTTPMethod requestMethod, const String &requestUri) override - { + bool handle(ESP8266WebServer &server, HTTPMethod requestMethod, const String &requestUri) override { // ensure that filename starts with '/' String fName = requestUri; if (!fName.startsWith("/")) { @@ -159,8 +151,7 @@ public: // uploading process - void upload(ESP8266WebServer UNUSED &server, const String UNUSED &_requestUri, HTTPUpload &upload) override - { + void upload(ESP8266WebServer UNUSED &server, const String UNUSED &_requestUri, HTTPUpload &upload) override { // ensure that filename starts with '/' String fName = upload.filename; if (!fName.startsWith("/")) { @@ -195,8 +186,7 @@ protected: /** * Setup everything to make the webserver work. */ -void setup(void) -{ +void setup(void) { delay(3000); // wait for serial monitor to start completely. // Use Serial port for some trace information from the example @@ -272,8 +262,7 @@ void setup(void) // run the server... -void loop(void) -{ +void loop(void) { server.handleClient(); } // loop() From 4b9a0da7429bf7f9fbd576d54be052df87b917ac Mon Sep 17 00:00:00 2001 From: Matthias Hertel Date: Fri, 23 Jul 2021 09:16:39 +0200 Subject: [PATCH 09/10] fixing style --- .../examples/WebServer/WebServer.ino | 149 ++++++++---------- 1 file changed, 70 insertions(+), 79 deletions(-) diff --git a/libraries/ESP8266WebServer/examples/WebServer/WebServer.ino b/libraries/ESP8266WebServer/examples/WebServer/WebServer.ino index f81e72d244..49d78a68f3 100644 --- a/libraries/ESP8266WebServer/examples/WebServer/WebServer.ino +++ b/libraries/ESP8266WebServer/examples/WebServer/WebServer.ino @@ -1,12 +1,10 @@ -/** - * @file WebServer.ino - * @brief Example implementation using the ESP8266 WebServer. - * - * See also README.md for instructions and hints. - * - * Changelog: - * 21.07.2021 creation, first version - */ +// @file WebServer.ino +// @brief Example implementation using the ESP8266 WebServer. +// +// See also README.md for instructions and hints. +// +// Changelog: +// 21.07.2021 creation, first version #include #include @@ -99,93 +97,86 @@ void handleSysInfo() { // The FileServerHandler is registered to the web server to support DELETE and UPLOAD of files into the filesystem. class FileServerHandler : public RequestHandler { -public: - /** - @brief Construct a new File Server Handler object - @param fs The file system to be used. - @param path Path to the root folder in the file system that is used for serving static data down and upload. - @param cache_header Cache Header to be used in replies. - */ - FileServerHandler() { - TRACE("FileServerHandler is registered\n"); - } - - - /** - @brief check wether the request can be handled by this implementation. - @param requestMethod method of the http request line. - @param requestUri request ressource from the http request line. - @return true when method can be handled. - */ - bool canHandle(HTTPMethod requestMethod, const String UNUSED &_uri) override { - // can handle POST for uploads and DELETE. - return ((requestMethod == HTTP_POST) || (requestMethod == HTTP_DELETE)); - } // canHandle() + public: + // @brief Construct a new File Server Handler object + // @param fs The file system to be used. + // @param path Path to the root folder in the file system that is used for serving static data down and upload. + // @param cache_header Cache Header to be used in replies. + FileServerHandler() { + TRACE("FileServerHandler is registered\n"); + } - bool canUpload(const String &uri) override { - // only allow upload on root fs level. - return (uri == "/"); - } // canUpload() + // @brief check incoming request. Can handle POST for uploads and DELETE. + // @param requestMethod method of the http request line. + // @param requestUri request ressource from the http request line. + // @return true when method can be handled. + bool canHandle(HTTPMethod requestMethod, const String UNUSED &_uri) override { + return ((requestMethod == HTTP_POST) || (requestMethod == HTTP_DELETE)); + } // canHandle() - bool handle(ESP8266WebServer &server, HTTPMethod requestMethod, const String &requestUri) override { - // ensure that filename starts with '/' - String fName = requestUri; - if (!fName.startsWith("/")) { - fName = "/" + fName; - } + bool canUpload(const String &uri) override { + // only allow upload on root fs level. + return (uri == "/"); + } // canUpload() - if (requestMethod == HTTP_POST) { - // all done in upload. no other forms. - } else if (requestMethod == HTTP_DELETE) { - if (LittleFS.exists(fName)) { - LittleFS.remove(fName); + bool handle(ESP8266WebServer &server, HTTPMethod requestMethod, const String &requestUri) override { + // ensure that filename starts with '/' + String fName = requestUri; + if (!fName.startsWith("/")) { + fName = "/" + fName; } - } // if - - server.send(200); // all done. - return (true); - } // handle() + if (requestMethod == HTTP_POST) { + // all done in upload. no other forms. - // uploading process - void upload(ESP8266WebServer UNUSED &server, const String UNUSED &_requestUri, HTTPUpload &upload) override { - // ensure that filename starts with '/' - String fName = upload.filename; - if (!fName.startsWith("/")) { - fName = "/" + fName; - } - - if (upload.status == UPLOAD_FILE_START) { - // Open the file - if (LittleFS.exists(fName)) { - LittleFS.remove(fName); + } else if (requestMethod == HTTP_DELETE) { + if (LittleFS.exists(fName)) { + LittleFS.remove(fName); + } } // if - _fsUploadFile = LittleFS.open(fName, "w"); - } else if (upload.status == UPLOAD_FILE_WRITE) { - // Write received bytes - if (_fsUploadFile) - _fsUploadFile.write(upload.buf, upload.currentSize); + server.send(200); // all done. + return (true); + } // handle() + - } else if (upload.status == UPLOAD_FILE_END) { - // Close the file - if (_fsUploadFile) { - _fsUploadFile.close(); + // uploading process + void upload(ESP8266WebServer UNUSED &server, const String UNUSED &_requestUri, HTTPUpload &upload) override { + // ensure that filename starts with '/' + String fName = upload.filename; + if (!fName.startsWith("/")) { + fName = "/" + fName; } - } // if - } // upload() -protected: - File _fsUploadFile; + if (upload.status == UPLOAD_FILE_START) { + // Open the file + if (LittleFS.exists(fName)) { + LittleFS.remove(fName); + } // if + _fsUploadFile = LittleFS.open(fName, "w"); + + } else if (upload.status == UPLOAD_FILE_WRITE) { + // Write received bytes + if (_fsUploadFile) + _fsUploadFile.write(upload.buf, upload.currentSize); + + } else if (upload.status == UPLOAD_FILE_END) { + // Close the file + if (_fsUploadFile) { + _fsUploadFile.close(); + } + } // if + } // upload() + + protected: + File _fsUploadFile; }; -/** - * Setup everything to make the webserver work. - */ +// Setup everything to make the webserver work. void setup(void) { delay(3000); // wait for serial monitor to start completely. From e2ad93972bed2dce557388ef62d6cf685da4c5ca Mon Sep 17 00:00:00 2001 From: Matthias Hertel Date: Fri, 23 Jul 2021 09:22:53 +0200 Subject: [PATCH 10/10] fixing style --- .../ESP8266WebServer/examples/WebServer/WebServer.ino | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/libraries/ESP8266WebServer/examples/WebServer/WebServer.ino b/libraries/ESP8266WebServer/examples/WebServer/WebServer.ino index 49d78a68f3..08107586fd 100644 --- a/libraries/ESP8266WebServer/examples/WebServer/WebServer.ino +++ b/libraries/ESP8266WebServer/examples/WebServer/WebServer.ino @@ -1,8 +1,8 @@ // @file WebServer.ino // @brief Example implementation using the ESP8266 WebServer. -// +// // See also README.md for instructions and hints. -// +// // Changelog: // 21.07.2021 creation, first version @@ -160,8 +160,9 @@ class FileServerHandler : public RequestHandler { } else if (upload.status == UPLOAD_FILE_WRITE) { // Write received bytes - if (_fsUploadFile) + if (_fsUploadFile) { _fsUploadFile.write(upload.buf, upload.currentSize); + } } else if (upload.status == UPLOAD_FILE_END) { // Close the file pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy