From 136a11192faa1f2643c3423d94602b903310fbe9 Mon Sep 17 00:00:00 2001 From: imwhocodes Date: Mon, 16 Nov 2020 23:18:24 +0100 Subject: [PATCH 1/4] testing locals variables --- .../src/ESP8266WebServer-impl.h | 38 ++++++++++++++----- .../ESP8266WebServer/src/ESP8266WebServer.h | 6 ++- 2 files changed, 33 insertions(+), 11 deletions(-) diff --git a/libraries/ESP8266WebServer/src/ESP8266WebServer-impl.h b/libraries/ESP8266WebServer/src/ESP8266WebServer-impl.h index 0fcb3c3970..44c5b533e2 100644 --- a/libraries/ESP8266WebServer/src/ESP8266WebServer-impl.h +++ b/libraries/ESP8266WebServer/src/ESP8266WebServer-impl.h @@ -619,17 +619,31 @@ void ESP8266WebServerTemplate::collectHeaders(const char* headerKeys } } +// template +// void ESP8266WebServerETagTemplate::collectHeaders(const char* headerKeys[], const size_t headerKeysCount) { +// WST::_headerKeysCount = headerKeysCount + 2; +// if (WST::_currentHeaders){ +// delete[] WST::_currentHeaders; +// } +// WST::_currentHeaders = new typename WST::RequestArgument[WST::_headerKeysCount]; +// WST::_currentHeaders[0].key = FPSTR(AUTHORIZATION_HEADER); +// WST::_currentHeaders[1].key = FPSTR(ETAG_HEADER); +// for (int i = 2; i < WST::_headerKeysCount; i++){ +// WST::_currentHeaders[i].key = headerKeys[i-2]; +// } +// } + template void ESP8266WebServerETagTemplate::collectHeaders(const char* headerKeys[], const size_t headerKeysCount) { - WST::_headerKeysCount = headerKeysCount + 2; - if (WST::_currentHeaders){ - delete[] WST::_currentHeaders; + _headerKeysCount = headerKeysCount + 2; + if (_currentHeaders){ + delete[] _currentHeaders; } - WST::_currentHeaders = new typename WST::RequestArgument[WST::_headerKeysCount]; - WST::_currentHeaders[0].key = FPSTR(AUTHORIZATION_HEADER); - WST::_currentHeaders[1].key = FPSTR(ETAG_HEADER); - for (int i = 2; i < WST::_headerKeysCount; i++){ - WST::_currentHeaders[i].key = headerKeys[i-2]; + _currentHeaders = new typename RequestArgument[_headerKeysCount]; + _currentHeaders[0].key = FPSTR(AUTHORIZATION_HEADER); + _currentHeaders[1].key = FPSTR(ETAG_HEADER); + for (int i = 2; i < _headerKeysCount; i++){ + _currentHeaders[i].key = headerKeys[i-2]; } } @@ -846,11 +860,17 @@ String ESP8266WebServerTemplate::responseCodeToString(const int code return String(r); } +// template +// void ESP8266WebServerETagTemplate::serveStaticETag(const char* uri, FS& fs, const char* path, const char* cache_header){ +// WST::_addRequestHandler(new StaticRequestETagHandler(fs, path, uri, cache_header)); +// } + template void ESP8266WebServerETagTemplate::serveStaticETag(const char* uri, FS& fs, const char* path, const char* cache_header){ - WST::_addRequestHandler(new StaticRequestETagHandler(fs, path, uri, cache_header)); + _addRequestHandler(new StaticRequestETagHandler(fs, path, uri, cache_header)); } + template void ESP8266WebServerETagTemplate::serveStaticETag(const char* uri, FS& fs, const char * path) { diff --git a/libraries/ESP8266WebServer/src/ESP8266WebServer.h b/libraries/ESP8266WebServer/src/ESP8266WebServer.h index 28036ed8d5..a19d2b4e1c 100644 --- a/libraries/ESP8266WebServer/src/ESP8266WebServer.h +++ b/libraries/ESP8266WebServer/src/ESP8266WebServer.h @@ -304,10 +304,12 @@ class ESP8266WebServerTemplate template class ESP8266WebServerETagTemplate : public ESP8266WebServerTemplate { - using WST = ESP8266WebServerTemplate; + // using WST = ESP8266WebServerTemplate; - using WST::WST; + // using WST::WST; + using ESP8266WebServerTemplate::ESP8266WebServerTemplate; + public: void collectHeaders(const char* headerKeys[], const size_t headerKeysCount); void serveStaticETag(const char* uri, FS& fs, const char* path, const char* cache_header); From 44030606a7f1c7ba503181bb68bac6cc5726b007 Mon Sep 17 00:00:00 2001 From: imwhocodes Date: Tue, 17 Nov 2020 02:34:10 +0100 Subject: [PATCH 2/4] less memory used, partil refactoring --- .vscode/settings.json | 7 ++ .../src/ESP8266WebServer-impl.h | 69 ++++------------ .../ESP8266WebServer/src/ESP8266WebServer.h | 7 +- .../src/detail/RequestHandlersImpl.h | 82 ++++++++++++++++--- 4 files changed, 96 insertions(+), 69 deletions(-) create mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000000..1a5467e1a2 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,7 @@ +{ + "files.associations": { + "__config": "cpp", + "fstream": "cpp", + "locale": "cpp" + } +} \ No newline at end of file diff --git a/libraries/ESP8266WebServer/src/ESP8266WebServer-impl.h b/libraries/ESP8266WebServer/src/ESP8266WebServer-impl.h index 44c5b533e2..7eacc5bfdc 100644 --- a/libraries/ESP8266WebServer/src/ESP8266WebServer-impl.h +++ b/libraries/ESP8266WebServer/src/ESP8266WebServer-impl.h @@ -619,31 +619,17 @@ void ESP8266WebServerTemplate::collectHeaders(const char* headerKeys } } -// template -// void ESP8266WebServerETagTemplate::collectHeaders(const char* headerKeys[], const size_t headerKeysCount) { -// WST::_headerKeysCount = headerKeysCount + 2; -// if (WST::_currentHeaders){ -// delete[] WST::_currentHeaders; -// } -// WST::_currentHeaders = new typename WST::RequestArgument[WST::_headerKeysCount]; -// WST::_currentHeaders[0].key = FPSTR(AUTHORIZATION_HEADER); -// WST::_currentHeaders[1].key = FPSTR(ETAG_HEADER); -// for (int i = 2; i < WST::_headerKeysCount; i++){ -// WST::_currentHeaders[i].key = headerKeys[i-2]; -// } -// } - template void ESP8266WebServerETagTemplate::collectHeaders(const char* headerKeys[], const size_t headerKeysCount) { - _headerKeysCount = headerKeysCount + 2; - if (_currentHeaders){ - delete[] _currentHeaders; + WST::_headerKeysCount = headerKeysCount + 2; + if (WST::_currentHeaders){ + delete[] WST::_currentHeaders; } - _currentHeaders = new typename RequestArgument[_headerKeysCount]; - _currentHeaders[0].key = FPSTR(AUTHORIZATION_HEADER); - _currentHeaders[1].key = FPSTR(ETAG_HEADER); - for (int i = 2; i < _headerKeysCount; i++){ - _currentHeaders[i].key = headerKeys[i-2]; + WST::_currentHeaders = new typename WST::RequestArgument[WST::_headerKeysCount]; + WST::_currentHeaders[0].key = FPSTR(AUTHORIZATION_HEADER); + WST::_currentHeaders[1].key = FPSTR(ETAG_HEADER); + for (int i = 2; i < WST::_headerKeysCount; i++){ + WST::_currentHeaders[i].key = headerKeys[i-2]; } } @@ -860,43 +846,16 @@ String ESP8266WebServerTemplate::responseCodeToString(const int code return String(r); } -// template -// void ESP8266WebServerETagTemplate::serveStaticETag(const char* uri, FS& fs, const char* path, const char* cache_header){ -// WST::_addRequestHandler(new StaticRequestETagHandler(fs, path, uri, cache_header)); -// } - template -void ESP8266WebServerETagTemplate::serveStaticETag(const char* uri, FS& fs, const char* path, const char* cache_header){ - _addRequestHandler(new StaticRequestETagHandler(fs, path, uri, cache_header)); +void ESP8266WebServerETagTemplate::serveStatic(const char* uri, FS& fs, const char* path, const char* cache_header){ + WST::_addRequestHandler(new StaticRequestETagHandler(fs, path, uri, cache_header)); } -template -void ESP8266WebServerETagTemplate::serveStaticETag(const char* uri, FS& fs, const char * path) { - - File toHash = fs.open(path, "r"); - - if(toHash){ - - MD5Builder calcMD5; - calcMD5.begin(); - - calcMD5.addStream(toHash, toHash.size()); - - toHash.close(); - - calcMD5.calculate(); - - uint8_t buff[16]; - - calcMD5.getBytes(buff); - - const String etag = "\"" + base64::encode(buff, 16, false) + "\""; - - serveStaticETag(uri, fs, path, etag.c_str()); - - } +// template +// void ESP8266WebServerETagTemplate::serveStatic(const char* uri, FS& fs, const char * path) { +// serveStatic(uri, fs, path, ""); -} +// } } // namespace diff --git a/libraries/ESP8266WebServer/src/ESP8266WebServer.h b/libraries/ESP8266WebServer/src/ESP8266WebServer.h index a19d2b4e1c..7e1a3e4172 100644 --- a/libraries/ESP8266WebServer/src/ESP8266WebServer.h +++ b/libraries/ESP8266WebServer/src/ESP8266WebServer.h @@ -304,16 +304,15 @@ class ESP8266WebServerTemplate template class ESP8266WebServerETagTemplate : public ESP8266WebServerTemplate { - // using WST = ESP8266WebServerTemplate; + using WST = ESP8266WebServerTemplate; // using WST::WST; using ESP8266WebServerTemplate::ESP8266WebServerTemplate; - + public: void collectHeaders(const char* headerKeys[], const size_t headerKeysCount); - void serveStaticETag(const char* uri, FS& fs, const char* path, const char* cache_header); - void serveStaticETag(const char* uri, FS& fs, const char* path); + void serveStatic(const char* uri, fs::FS& fs, const char* path, const char* cache_header = NULL ); }; } // namespace diff --git a/libraries/ESP8266WebServer/src/detail/RequestHandlersImpl.h b/libraries/ESP8266WebServer/src/detail/RequestHandlersImpl.h index 1ea64c0c11..4f5556a16c 100644 --- a/libraries/ESP8266WebServer/src/detail/RequestHandlersImpl.h +++ b/libraries/ESP8266WebServer/src/detail/RequestHandlersImpl.h @@ -172,41 +172,103 @@ public StaticRequestHandler { using SRH = StaticRequestHandler; - using SRH::SRH; - using WebServerType = ESP8266WebServerTemplate; + protected: + uint8_t _ETag_md5[16]; + + void computeMD5(File toHash){ + MD5Builder calcMD5; + calcMD5.begin(); + calcMD5.addStream(toHash, toHash.size()); + calcMD5.calculate(); + calcMD5.getBytes(_ETag_md5); + } + + public: + StaticRequestETagHandler(FS& fs, const char* path, const char* uri, const char* cache_header) + : + StaticRequestHandler{fs, path, uri, cache_header} + { + File f = fs.open(path, "r"); + if(f){ + if(f.isFile()) + computeMD5(f); + f.close(); + } + + } + bool handle(WebServerType& server, HTTPMethod requestMethod, const String & requestUri) override { if (!SRH::canHandle(requestMethod, requestUri)){ return false; } - if(server.header("If-None-Match") == SRH::_cache_header){ - // Serial.println("Sending 304!!!"); + const String etag = "\"" + base64::encode(_ETag_md5, 16, false) + "\""; + + if(server.header("If-None-Match") == etag){ server.send(304); return true; } - File f = SRH::_fs.open(SRH::_path, "r"); - if (!f){ + if (!f) return false; - } if (!f.isFile()) { f.close(); return false; } - if (SRH::_cache_header.length() != 0){ - server.sendHeader("ETag", SRH::_cache_header); - } + if (SRH::_cache_header.length() != 0) + server.sendHeader("Cache-Control", SRH::_cache_header); + + server.sendHeader("ETag", etag); + server.streamFile(f, SRH::getContentType(SRH::_path), requestMethod); return true; + } + + // bool handle(WebServerType& server, HTTPMethod requestMethod, const String & requestUri) override { + // if (!SRH::canHandle(requestMethod, requestUri)){ + // return false; + // } + + // File f = SRH::_fs.open(SRH::_path, "r"); + + // if (!f) + // return false; + + // if (!f.isFile()) { + // f.close(); + // return false; + // } + + // if(last_edit == f.getLastWrite()){ + // //update chache + // } + + // const String etag = "\"" + base64::encode(buff, 16, false) + "\""; + + // if(server.header("If-None-Match") == etag){ + // server.send(304); + // return true; + // } + + // if (_cache_header.length() != 0) + // server.sendHeader("Cache-Control", SRH::_cache_header); + + // server.sendHeader("ETag", etag); + + + // server.streamFile(f, SRH::getContentType(SRH::_path), requestMethod); + // return true; + + // } }; From c428958a1e8b3523ad1a9ffc7fc9e06facdf3575 Mon Sep 17 00:00:00 2001 From: imwhocodes Date: Thu, 19 Nov 2020 00:44:07 +0100 Subject: [PATCH 3/4] reworked serveStatic logic, different handler for File and Directory --- .../src/ESP8266WebServer-impl.h | 19 +- .../src/detail/RequestHandlersImpl.h | 175 +++++++----------- 2 files changed, 77 insertions(+), 117 deletions(-) diff --git a/libraries/ESP8266WebServer/src/ESP8266WebServer-impl.h b/libraries/ESP8266WebServer/src/ESP8266WebServer-impl.h index 7eacc5bfdc..320c03f452 100644 --- a/libraries/ESP8266WebServer/src/ESP8266WebServer-impl.h +++ b/libraries/ESP8266WebServer/src/ESP8266WebServer-impl.h @@ -848,14 +848,19 @@ String ESP8266WebServerTemplate::responseCodeToString(const int code template void ESP8266WebServerETagTemplate::serveStatic(const char* uri, FS& fs, const char* path, const char* cache_header){ - WST::_addRequestHandler(new StaticRequestETagHandler(fs, path, uri, cache_header)); -} + bool is_file = false; + + if (fs.exists(path)) { + File file = fs.open(path, "r"); + is_file = file && file.isFile(); + file.close(); + } -// template -// void ESP8266WebServerETagTemplate::serveStatic(const char* uri, FS& fs, const char * path) { -// serveStatic(uri, fs, path, ""); - -// } + if(is_file) + WST::_addRequestHandler(new StaticFileRequestHandler(fs, path, uri, cache_header)); + else + WST::_addRequestHandler(new StaticDirectoryRequestHandler(fs, path, uri, cache_header)); +} } // namespace diff --git a/libraries/ESP8266WebServer/src/detail/RequestHandlersImpl.h b/libraries/ESP8266WebServer/src/detail/RequestHandlersImpl.h index 4f5556a16c..b15b54a000 100644 --- a/libraries/ESP8266WebServer/src/detail/RequestHandlersImpl.h +++ b/libraries/ESP8266WebServer/src/detail/RequestHandlersImpl.h @@ -72,27 +72,41 @@ class StaticRequestHandler : public RequestHandler { , _path(path) , _cache_header(cache_header) { - if (fs.exists(path)) { - File file = fs.open(path, "r"); - _isFile = file && file.isFile(); - file.close(); - } - else { - _isFile = false; - } - DEBUGV("StaticRequestHandler: path=%s uri=%s isFile=%d, cache_header=%s\r\n", path, uri, _isFile, cache_header == __null ? "" : cache_header); - _baseUriLength = _uri.length(); } - bool canHandle(HTTPMethod requestMethod, const String& requestUri) override { - if ((requestMethod != HTTP_GET) && (requestMethod != HTTP_HEAD)) - return false; + bool validMethod(HTTPMethod requestMethod){ + return (requestMethod == HTTP_GET) || (requestMethod == HTTP_HEAD); + } - if ((_isFile && requestUri != _uri) || !requestUri.startsWith(_uri)) - return false; + /* Deprecated version. Please use mime::getContentType instead */ + static String getContentType(const String& path) __attribute__((deprecated)) { + return mime::getContentType(path); + } - return true; +protected: + FS _fs; + String _uri; + String _path; + String _cache_header; +}; + + +template +class StaticDirectoryRequestHandler : public StaticRequestHandler { + + using SRH = StaticRequestHandler; + using WebServerType = ESP8266WebServerTemplate; + +public: + StaticDirectoryRequestHandler(FS& fs, const char* path, const char* uri, const char* cache_header) + : + SRH(fs, path, uri, cache_header), + _baseUriLength{SRH::_uri.length()} + {} + + bool canHandle(HTTPMethod requestMethod, const String& requestUri) override { + return SRH::validMethod(requestMethod) && requestUri.startsWith(SRH::_uri); } bool handle(WebServerType& server, HTTPMethod requestMethod, const String& requestUri) override { @@ -100,42 +114,40 @@ class StaticRequestHandler : public RequestHandler { if (!canHandle(requestMethod, requestUri)) return false; - DEBUGV("StaticRequestHandler::handle: request=%s _uri=%s\r\n", requestUri.c_str(), _uri.c_str()); + DEBUGV("DirectoryRequestHandler::handle: request=%s _uri=%s\r\n", requestUri.c_str(), SRH::_uri.c_str()); String path; - path.reserve(_path.length() + requestUri.length() + 32); - path = _path; - - if (!_isFile) { + path.reserve(SRH::_path.length() + requestUri.length() + 32); + path = SRH::_path; - // Append whatever follows this URI in request to get the file path. - path += requestUri.substring(_baseUriLength); + // Append whatever follows this URI in request to get the file path. + path += requestUri.substring(_baseUriLength); - // Base URI doesn't point to a file. - // If a directory is requested, look for index file. - if (path.endsWith("/")) - path += F("index.htm"); + // Base URI doesn't point to a file. + // If a directory is requested, look for index file. + if (path.endsWith("/")) + path += F("index.htm"); - // If neither nor .gz exist, and is a file.htm, try it with file.html instead - // For the normal case this will give a search order of index.htm, index.htm.gz, index.html, index.html.gz - if (!_fs.exists(path) && !_fs.exists(path + ".gz") && path.endsWith(".htm")) { - path += 'l'; - } + // If neither nor .gz exist, and is a file.htm, try it with file.html instead + // For the normal case this will give a search order of index.htm, index.htm.gz, index.html, index.html.gz + if (!SRH::_fs.exists(path) && !SRH::_fs.exists(path + ".gz") && path.endsWith(".htm")) { + path += 'l'; } - DEBUGV("StaticRequestHandler::handle: path=%s, isFile=%d\r\n", path.c_str(), _isFile); + + DEBUGV("DirectoryRequestHandler::handle: path=%s\r\n", path.c_str()); String contentType = mime::getContentType(path); using namespace mime; // look for gz file, only if the original specified path is not a gz. So part only works to send gzip via content encoding when a non compressed is asked for // if you point the the path to gzip you will serve the gzip as content type "application/x-gzip", not text or javascript etc... - if (!path.endsWith(FPSTR(mimeTable[gz].endsWith)) && !_fs.exists(path)) { + if (!path.endsWith(FPSTR(mimeTable[gz].endsWith)) && !SRH::_fs.exists(path)) { String pathWithGz = path + FPSTR(mimeTable[gz].endsWith); - if(_fs.exists(pathWithGz)) + if(SRH::_fs.exists(pathWithGz)) path += FPSTR(mimeTable[gz].endsWith); } - File f = _fs.open(path, "r"); + File f = SRH::_fs.open(path, "r"); if (!f) return false; @@ -144,66 +156,46 @@ class StaticRequestHandler : public RequestHandler { return false; } - if (_cache_header.length() != 0) - server.sendHeader("Cache-Control", _cache_header); + if (SRH::_cache_header.length() != 0) + server.sendHeader("Cache-Control", SRH::_cache_header); server.streamFile(f, contentType, requestMethod); return true; } - /* Deprecated version. Please use mime::getContentType instead */ - static String getContentType(const String& path) __attribute__((deprecated)) { - return mime::getContentType(path); - } - protected: - FS _fs; - String _uri; - String _path; - String _cache_header; - bool _isFile; size_t _baseUriLength; }; template -class StaticRequestETagHandler +class StaticFileRequestHandler : public StaticRequestHandler { using SRH = StaticRequestHandler; - using WebServerType = ESP8266WebServerTemplate; - protected: - uint8_t _ETag_md5[16]; - - void computeMD5(File toHash){ +public: + StaticFileRequestHandler(FS& fs, const char* path, const char* uri, const char* cache_header) + : + StaticRequestHandler{fs, path, uri, cache_header} + { + File f = SRH::_fs.open(path, "r"); MD5Builder calcMD5; calcMD5.begin(); - calcMD5.addStream(toHash, toHash.size()); + calcMD5.addStream(f, f.size()); calcMD5.calculate(); calcMD5.getBytes(_ETag_md5); + f.close(); } - - public: - StaticRequestETagHandler(FS& fs, const char* path, const char* uri, const char* cache_header) - : - StaticRequestHandler{fs, path, uri, cache_header} - { - File f = fs.open(path, "r"); - if(f){ - if(f.isFile()) - computeMD5(f); - f.close(); - } - + bool canHandle(HTTPMethod requestMethod, const String& requestUri) override { + return SRH::validMethod(requestMethod) && requestUri == SRH::_uri; } bool handle(WebServerType& server, HTTPMethod requestMethod, const String & requestUri) override { - if (!SRH::canHandle(requestMethod, requestUri)){ + if (!canHandle(requestMethod, requestUri)) return false; - } const String etag = "\"" + base64::encode(_ETag_md5, 16, false) + "\""; @@ -227,49 +219,12 @@ public StaticRequestHandler { server.sendHeader("ETag", etag); - - server.streamFile(f, SRH::getContentType(SRH::_path), requestMethod); + server.streamFile(f, mime::getContentType(SRH::_path), requestMethod); return true; - } - // bool handle(WebServerType& server, HTTPMethod requestMethod, const String & requestUri) override { - // if (!SRH::canHandle(requestMethod, requestUri)){ - // return false; - // } - - // File f = SRH::_fs.open(SRH::_path, "r"); - - // if (!f) - // return false; - - // if (!f.isFile()) { - // f.close(); - // return false; - // } - - // if(last_edit == f.getLastWrite()){ - // //update chache - // } - - // const String etag = "\"" + base64::encode(buff, 16, false) + "\""; - - // if(server.header("If-None-Match") == etag){ - // server.send(304); - // return true; - // } - - // if (_cache_header.length() != 0) - // server.sendHeader("Cache-Control", SRH::_cache_header); - - // server.sendHeader("ETag", etag); - - - // server.streamFile(f, SRH::getContentType(SRH::_path), requestMethod); - // return true; - - // } - +protected: + uint8_t _ETag_md5[16]; }; } // namespace From 865054c0dbc7513be8643b4cbd0dfa5d50d3277a Mon Sep 17 00:00:00 2001 From: imwhocodes Date: Thu, 19 Nov 2020 00:44:07 +0100 Subject: [PATCH 4/4] reworked serveStatic logic, different handler for File and Directory --- .../src/ESP8266WebServer-impl.h | 54 +++--- .../ESP8266WebServer/src/ESP8266WebServer.h | 17 -- .../src/detail/RequestHandlersImpl.h | 175 +++++++----------- 3 files changed, 86 insertions(+), 160 deletions(-) diff --git a/libraries/ESP8266WebServer/src/ESP8266WebServer-impl.h b/libraries/ESP8266WebServer/src/ESP8266WebServer-impl.h index 7eacc5bfdc..9ea77718f8 100644 --- a/libraries/ESP8266WebServer/src/ESP8266WebServer-impl.h +++ b/libraries/ESP8266WebServer/src/ESP8266WebServer-impl.h @@ -255,7 +255,18 @@ void ESP8266WebServerTemplate::_addRequestHandler(RequestHandlerType template void ESP8266WebServerTemplate::serveStatic(const char* uri, FS& fs, const char* path, const char* cache_header) { - _addRequestHandler(new StaticRequestHandler(fs, path, uri, cache_header)); + bool is_file = false; + + if (fs.exists(path)) { + File file = fs.open(path, "r"); + is_file = file && file.isFile(); + file.close(); + } + + if(is_file) + _addRequestHandler(new StaticFileRequestHandler(fs, path, uri, cache_header)); + else + _addRequestHandler(new StaticDirectoryRequestHandler(fs, path, uri, cache_header)); } template @@ -607,29 +618,18 @@ const String& ESP8266WebServerTemplate::header(const String& name) c return emptyString; } -template -void ESP8266WebServerTemplate::collectHeaders(const char* headerKeys[], const size_t headerKeysCount) { - _headerKeysCount = headerKeysCount + 1; - if (_currentHeaders) - delete[]_currentHeaders; - _currentHeaders = new RequestArgument[_headerKeysCount]; - _currentHeaders[0].key = FPSTR(AUTHORIZATION_HEADER); - for (int i = 1; i < _headerKeysCount; i++){ - _currentHeaders[i].key = headerKeys[i-1]; - } -} template -void ESP8266WebServerETagTemplate::collectHeaders(const char* headerKeys[], const size_t headerKeysCount) { - WST::_headerKeysCount = headerKeysCount + 2; - if (WST::_currentHeaders){ - delete[] WST::_currentHeaders; +void ESP8266WebServerTemplate::collectHeaders(const char* headerKeys[], const size_t headerKeysCount) { + _headerKeysCount = headerKeysCount + 2; + if (_currentHeaders){ + delete[] _currentHeaders; } - WST::_currentHeaders = new typename WST::RequestArgument[WST::_headerKeysCount]; - WST::_currentHeaders[0].key = FPSTR(AUTHORIZATION_HEADER); - WST::_currentHeaders[1].key = FPSTR(ETAG_HEADER); - for (int i = 2; i < WST::_headerKeysCount; i++){ - WST::_currentHeaders[i].key = headerKeys[i-2]; + _currentHeaders = new RequestArgument[_headerKeysCount]; + _currentHeaders[0].key = FPSTR(AUTHORIZATION_HEADER); + _currentHeaders[1].key = FPSTR(ETAG_HEADER); + for (int i = 2; i < _headerKeysCount; i++){ + _currentHeaders[i].key = headerKeys[i-2]; } } @@ -846,16 +846,4 @@ String ESP8266WebServerTemplate::responseCodeToString(const int code return String(r); } -template -void ESP8266WebServerETagTemplate::serveStatic(const char* uri, FS& fs, const char* path, const char* cache_header){ - WST::_addRequestHandler(new StaticRequestETagHandler(fs, path, uri, cache_header)); -} - - -// template -// void ESP8266WebServerETagTemplate::serveStatic(const char* uri, FS& fs, const char * path) { -// serveStatic(uri, fs, path, ""); - -// } - } // namespace diff --git a/libraries/ESP8266WebServer/src/ESP8266WebServer.h b/libraries/ESP8266WebServer/src/ESP8266WebServer.h index 7e1a3e4172..d7199c4a9a 100644 --- a/libraries/ESP8266WebServer/src/ESP8266WebServer.h +++ b/libraries/ESP8266WebServer/src/ESP8266WebServer.h @@ -300,21 +300,6 @@ class ESP8266WebServerTemplate HookFunction _hook; }; - -template -class ESP8266WebServerETagTemplate : public ESP8266WebServerTemplate -{ - using WST = ESP8266WebServerTemplate; - - // using WST::WST; - - using ESP8266WebServerTemplate::ESP8266WebServerTemplate; - - public: - void collectHeaders(const char* headerKeys[], const size_t headerKeysCount); - void serveStatic(const char* uri, fs::FS& fs, const char* path, const char* cache_header = NULL ); -}; - } // namespace #include "ESP8266WebServer-impl.h" @@ -323,6 +308,4 @@ class ESP8266WebServerETagTemplate : public ESP8266WebServerTemplate using ESP8266WebServer = esp8266webserver::ESP8266WebServerTemplate; using RequestHandler = esp8266webserver::RequestHandler; -using ESP8266WebServerETag = esp8266webserver::ESP8266WebServerETagTemplate; - #endif //ESP8266WEBSERVER_H \ No newline at end of file diff --git a/libraries/ESP8266WebServer/src/detail/RequestHandlersImpl.h b/libraries/ESP8266WebServer/src/detail/RequestHandlersImpl.h index 4f5556a16c..b15b54a000 100644 --- a/libraries/ESP8266WebServer/src/detail/RequestHandlersImpl.h +++ b/libraries/ESP8266WebServer/src/detail/RequestHandlersImpl.h @@ -72,27 +72,41 @@ class StaticRequestHandler : public RequestHandler { , _path(path) , _cache_header(cache_header) { - if (fs.exists(path)) { - File file = fs.open(path, "r"); - _isFile = file && file.isFile(); - file.close(); - } - else { - _isFile = false; - } - DEBUGV("StaticRequestHandler: path=%s uri=%s isFile=%d, cache_header=%s\r\n", path, uri, _isFile, cache_header == __null ? "" : cache_header); - _baseUriLength = _uri.length(); } - bool canHandle(HTTPMethod requestMethod, const String& requestUri) override { - if ((requestMethod != HTTP_GET) && (requestMethod != HTTP_HEAD)) - return false; + bool validMethod(HTTPMethod requestMethod){ + return (requestMethod == HTTP_GET) || (requestMethod == HTTP_HEAD); + } - if ((_isFile && requestUri != _uri) || !requestUri.startsWith(_uri)) - return false; + /* Deprecated version. Please use mime::getContentType instead */ + static String getContentType(const String& path) __attribute__((deprecated)) { + return mime::getContentType(path); + } - return true; +protected: + FS _fs; + String _uri; + String _path; + String _cache_header; +}; + + +template +class StaticDirectoryRequestHandler : public StaticRequestHandler { + + using SRH = StaticRequestHandler; + using WebServerType = ESP8266WebServerTemplate; + +public: + StaticDirectoryRequestHandler(FS& fs, const char* path, const char* uri, const char* cache_header) + : + SRH(fs, path, uri, cache_header), + _baseUriLength{SRH::_uri.length()} + {} + + bool canHandle(HTTPMethod requestMethod, const String& requestUri) override { + return SRH::validMethod(requestMethod) && requestUri.startsWith(SRH::_uri); } bool handle(WebServerType& server, HTTPMethod requestMethod, const String& requestUri) override { @@ -100,42 +114,40 @@ class StaticRequestHandler : public RequestHandler { if (!canHandle(requestMethod, requestUri)) return false; - DEBUGV("StaticRequestHandler::handle: request=%s _uri=%s\r\n", requestUri.c_str(), _uri.c_str()); + DEBUGV("DirectoryRequestHandler::handle: request=%s _uri=%s\r\n", requestUri.c_str(), SRH::_uri.c_str()); String path; - path.reserve(_path.length() + requestUri.length() + 32); - path = _path; - - if (!_isFile) { + path.reserve(SRH::_path.length() + requestUri.length() + 32); + path = SRH::_path; - // Append whatever follows this URI in request to get the file path. - path += requestUri.substring(_baseUriLength); + // Append whatever follows this URI in request to get the file path. + path += requestUri.substring(_baseUriLength); - // Base URI doesn't point to a file. - // If a directory is requested, look for index file. - if (path.endsWith("/")) - path += F("index.htm"); + // Base URI doesn't point to a file. + // If a directory is requested, look for index file. + if (path.endsWith("/")) + path += F("index.htm"); - // If neither nor .gz exist, and is a file.htm, try it with file.html instead - // For the normal case this will give a search order of index.htm, index.htm.gz, index.html, index.html.gz - if (!_fs.exists(path) && !_fs.exists(path + ".gz") && path.endsWith(".htm")) { - path += 'l'; - } + // If neither nor .gz exist, and is a file.htm, try it with file.html instead + // For the normal case this will give a search order of index.htm, index.htm.gz, index.html, index.html.gz + if (!SRH::_fs.exists(path) && !SRH::_fs.exists(path + ".gz") && path.endsWith(".htm")) { + path += 'l'; } - DEBUGV("StaticRequestHandler::handle: path=%s, isFile=%d\r\n", path.c_str(), _isFile); + + DEBUGV("DirectoryRequestHandler::handle: path=%s\r\n", path.c_str()); String contentType = mime::getContentType(path); using namespace mime; // look for gz file, only if the original specified path is not a gz. So part only works to send gzip via content encoding when a non compressed is asked for // if you point the the path to gzip you will serve the gzip as content type "application/x-gzip", not text or javascript etc... - if (!path.endsWith(FPSTR(mimeTable[gz].endsWith)) && !_fs.exists(path)) { + if (!path.endsWith(FPSTR(mimeTable[gz].endsWith)) && !SRH::_fs.exists(path)) { String pathWithGz = path + FPSTR(mimeTable[gz].endsWith); - if(_fs.exists(pathWithGz)) + if(SRH::_fs.exists(pathWithGz)) path += FPSTR(mimeTable[gz].endsWith); } - File f = _fs.open(path, "r"); + File f = SRH::_fs.open(path, "r"); if (!f) return false; @@ -144,66 +156,46 @@ class StaticRequestHandler : public RequestHandler { return false; } - if (_cache_header.length() != 0) - server.sendHeader("Cache-Control", _cache_header); + if (SRH::_cache_header.length() != 0) + server.sendHeader("Cache-Control", SRH::_cache_header); server.streamFile(f, contentType, requestMethod); return true; } - /* Deprecated version. Please use mime::getContentType instead */ - static String getContentType(const String& path) __attribute__((deprecated)) { - return mime::getContentType(path); - } - protected: - FS _fs; - String _uri; - String _path; - String _cache_header; - bool _isFile; size_t _baseUriLength; }; template -class StaticRequestETagHandler +class StaticFileRequestHandler : public StaticRequestHandler { using SRH = StaticRequestHandler; - using WebServerType = ESP8266WebServerTemplate; - protected: - uint8_t _ETag_md5[16]; - - void computeMD5(File toHash){ +public: + StaticFileRequestHandler(FS& fs, const char* path, const char* uri, const char* cache_header) + : + StaticRequestHandler{fs, path, uri, cache_header} + { + File f = SRH::_fs.open(path, "r"); MD5Builder calcMD5; calcMD5.begin(); - calcMD5.addStream(toHash, toHash.size()); + calcMD5.addStream(f, f.size()); calcMD5.calculate(); calcMD5.getBytes(_ETag_md5); + f.close(); } - - public: - StaticRequestETagHandler(FS& fs, const char* path, const char* uri, const char* cache_header) - : - StaticRequestHandler{fs, path, uri, cache_header} - { - File f = fs.open(path, "r"); - if(f){ - if(f.isFile()) - computeMD5(f); - f.close(); - } - + bool canHandle(HTTPMethod requestMethod, const String& requestUri) override { + return SRH::validMethod(requestMethod) && requestUri == SRH::_uri; } bool handle(WebServerType& server, HTTPMethod requestMethod, const String & requestUri) override { - if (!SRH::canHandle(requestMethod, requestUri)){ + if (!canHandle(requestMethod, requestUri)) return false; - } const String etag = "\"" + base64::encode(_ETag_md5, 16, false) + "\""; @@ -227,49 +219,12 @@ public StaticRequestHandler { server.sendHeader("ETag", etag); - - server.streamFile(f, SRH::getContentType(SRH::_path), requestMethod); + server.streamFile(f, mime::getContentType(SRH::_path), requestMethod); return true; - } - // bool handle(WebServerType& server, HTTPMethod requestMethod, const String & requestUri) override { - // if (!SRH::canHandle(requestMethod, requestUri)){ - // return false; - // } - - // File f = SRH::_fs.open(SRH::_path, "r"); - - // if (!f) - // return false; - - // if (!f.isFile()) { - // f.close(); - // return false; - // } - - // if(last_edit == f.getLastWrite()){ - // //update chache - // } - - // const String etag = "\"" + base64::encode(buff, 16, false) + "\""; - - // if(server.header("If-None-Match") == etag){ - // server.send(304); - // return true; - // } - - // if (_cache_header.length() != 0) - // server.sendHeader("Cache-Control", SRH::_cache_header); - - // server.sendHeader("ETag", etag); - - - // server.streamFile(f, SRH::getContentType(SRH::_path), requestMethod); - // return true; - - // } - +protected: + uint8_t _ETag_md5[16]; }; } // namespace