diff --git a/cores/esp8266/pgmspace.h b/cores/esp8266/pgmspace.h index d793324dda..b725d36dce 100644 --- a/cores/esp8266/pgmspace.h +++ b/cores/esp8266/pgmspace.h @@ -10,10 +10,35 @@ #include "ets_sys.h" #include "osapi.h" -#define PROGMEM ICACHE_RODATA_ATTR -#define PGM_P const char * -#define PGM_VOID_P const void * -#define PSTR(s) (__extension__({static const char __c[] PROGMEM = (s); &__c[0];})) + +#ifndef ICACHE_RODATA_ATTR + #define ICACHE_RODATA_ATTR __attribute__((section(".irom.text"))) +#endif +#ifndef PROGMEM + // The following two macros cause a parameter to be enclosed in quotes + // by the preopressor (i.e. for concatenating ints to strings) + #define __STRINGIZE_NX(A) #A + #define __STRINGIZE(A) __STRINGIZE_NX(A) + // Since __section__ is supposed to be only use for global variables, + // there could be conflicts when a static/inlined function has them in the + // same file as a non-static PROGMEM object. + // Ref: https://gcc.gnu.org/onlinedocs/gcc-3.2/gcc/Variable-Attributes.html + // Place each progmem object into its own named section, avoiding conflicts + #define PROGMEM __attribute__((section( "\".irom.text." __FILE__ "." __STRINGIZE(__LINE__) "." __STRINGIZE(__COUNTER__) "\""))) +#endif +#ifndef PGM_P + #define PGM_P const char * +#endif +#ifndef PGM_VOID_P + #define PGM_VOID_P const void * +#endif + +// PSTR() macro modified to start on a 32-bit boundary. This adds on average +// 1.5 bytes/string, but in return memcpy_P and strcpy_P will work 4~8x faster +#ifndef PSTR + #define PSTR(s) (__extension__({static const char __c[] __attribute__((__aligned__(4))) PROGMEM = (s); &__c[0];})) +#endif + #else //__ets__ #define PROGMEM #define PGM_P const char * diff --git a/libraries/ESP8266HTTPUpdateServer/examples/SecureBearSSLUpdater/SecureBearSSLUpdater.ino b/libraries/ESP8266HTTPUpdateServer/examples/SecureBearSSLUpdater/SecureBearSSLUpdater.ino index 1a230fca57..cbb9e95cdf 100644 --- a/libraries/ESP8266HTTPUpdateServer/examples/SecureBearSSLUpdater/SecureBearSSLUpdater.ino +++ b/libraries/ESP8266HTTPUpdateServer/examples/SecureBearSSLUpdater/SecureBearSSLUpdater.ino @@ -27,7 +27,7 @@ const char* ssid = "........"; const char* password = "........"; BearSSL::ESP8266WebServerSecure httpServer(443); -ESP8266HTTPUpdateServer httpUpdater; +ESP8266HTTPUpdateServerTemplate httpUpdater; static const char serverCert[] PROGMEM = R"EOF( -----BEGIN CERTIFICATE----- diff --git a/libraries/ESP8266HTTPUpdateServer/examples/SecureHTTPSUpdater/SecureHTTPSUpdater.ino b/libraries/ESP8266HTTPUpdateServer/examples/SecureHTTPSUpdater/SecureHTTPSUpdater.ino index 815e9ca965..71cba54dba 100644 --- a/libraries/ESP8266HTTPUpdateServer/examples/SecureHTTPSUpdater/SecureHTTPSUpdater.ino +++ b/libraries/ESP8266HTTPUpdateServer/examples/SecureHTTPSUpdater/SecureHTTPSUpdater.ino @@ -56,7 +56,7 @@ const char* ssid = "........"; const char* password = "........"; ESP8266WebServerSecure httpServer(443); -ESP8266HTTPUpdateServer httpUpdater; +ESP8266HTTPUpdateServerTemplate httpUpdater; // The certificate is stored in PMEM static const uint8_t x509[] PROGMEM = { diff --git a/libraries/ESP8266HTTPUpdateServer/src/ESP8266HTTPUpdateServer.cpp b/libraries/ESP8266HTTPUpdateServer/src/ESP8266HTTPUpdateServer-impl.h similarity index 79% rename from libraries/ESP8266HTTPUpdateServer/src/ESP8266HTTPUpdateServer.cpp rename to libraries/ESP8266HTTPUpdateServer/src/ESP8266HTTPUpdateServer-impl.h index 25236294e2..a0362d2102 100644 --- a/libraries/ESP8266HTTPUpdateServer/src/ESP8266HTTPUpdateServer.cpp +++ b/libraries/ESP8266HTTPUpdateServer/src/ESP8266HTTPUpdateServer-impl.h @@ -6,17 +6,17 @@ #include "StreamString.h" #include "ESP8266HTTPUpdateServer.h" - -static const char serverIndex[] PROGMEM = +static const char serverIndex[] = R"(
)"; -static const char successResponse[] PROGMEM = +static const char successResponse[] = "Update Success! Rebooting...\n"; -ESP8266HTTPUpdateServer::ESP8266HTTPUpdateServer(bool serial_debug) +template +ESP8266HTTPUpdateServerTemplate::ESP8266HTTPUpdateServerTemplate(bool serial_debug) { _serial_output = serial_debug; _server = NULL; @@ -25,7 +25,8 @@ ESP8266HTTPUpdateServer::ESP8266HTTPUpdateServer(bool serial_debug) _authenticated = false; } -void ESP8266HTTPUpdateServer::setup(ESP8266WebServer *server, const char * path, const char * username, const char * password) +template +void ESP8266HTTPUpdateServerTemplate::setup(ESP8266WebServerTemplate *server, const char * path, const char * username, const char * password) { _server = server; _username = (char *)username; @@ -35,7 +36,7 @@ void ESP8266HTTPUpdateServer::setup(ESP8266WebServer *server, const char * path, _server->on(path, HTTP_GET, [&](){ if(_username != NULL && _password != NULL && !_server->authenticate(_username, _password)) return _server->requestAuthentication(); - _server->send_P(200, PSTR("text/html"), serverIndex); + _server->send_P(200, ("text/html"), serverIndex); }); // handler for the /update form POST (once file upload finishes) @@ -43,10 +44,10 @@ void ESP8266HTTPUpdateServer::setup(ESP8266WebServer *server, const char * path, if(!_authenticated) return _server->requestAuthentication(); if (Update.hasError()) { - _server->send(200, F("text/html"), String(F("Update error: ")) + _updaterError); + _server->send(200, ("text/html"), String(("Update error: ")) + _updaterError); } else { _server->client().setNoDelay(true); - _server->send_P(200, PSTR("text/html"), successResponse); + _server->send_P(200, ("text/html"), successResponse); delay(100); _server->client().stop(); ESP.restart(); @@ -95,7 +96,8 @@ void ESP8266HTTPUpdateServer::setup(ESP8266WebServer *server, const char * path, }); } -void ESP8266HTTPUpdateServer::_setUpdaterError() +template +void ESP8266HTTPUpdateServerTemplate::_setUpdaterError() { if (_serial_output) Update.printError(Serial); StreamString str; diff --git a/libraries/ESP8266HTTPUpdateServer/src/ESP8266HTTPUpdateServer.h b/libraries/ESP8266HTTPUpdateServer/src/ESP8266HTTPUpdateServer.h index d537e55665..c4f471e96b 100644 --- a/libraries/ESP8266HTTPUpdateServer/src/ESP8266HTTPUpdateServer.h +++ b/libraries/ESP8266HTTPUpdateServer/src/ESP8266HTTPUpdateServer.h @@ -1,29 +1,30 @@ #ifndef __HTTP_UPDATE_SERVER_H #define __HTTP_UPDATE_SERVER_H -class ESP8266WebServer; +#include -class ESP8266HTTPUpdateServer +template +class ESP8266HTTPUpdateServerTemplate { public: - ESP8266HTTPUpdateServer(bool serial_debug=false); + ESP8266HTTPUpdateServerTemplate(bool serial_debug=false); - void setup(ESP8266WebServer *server) + void setup(ESP8266WebServerTemplate *server) { setup(server, NULL, NULL); } - void setup(ESP8266WebServer *server, const char * path) + void setup(ESP8266WebServerTemplate *server, const char * path) { setup(server, path, NULL, NULL); } - void setup(ESP8266WebServer *server, const char * username, const char * password) + void setup(ESP8266WebServerTemplate *server, const char * username, const char * password) { setup(server, "/update", username, password); } - void setup(ESP8266WebServer *server, const char * path, const char * username, const char * password); + void setup(ESP8266WebServerTemplate *server, const char * path, const char * username, const char * password); void updateCredentials(const char * username, const char * password) { @@ -36,12 +37,15 @@ class ESP8266HTTPUpdateServer private: bool _serial_output; - ESP8266WebServer *_server; + ESP8266WebServerTemplate *_server; char * _username; char * _password; bool _authenticated; String _updaterError; }; +#include "ESP8266HTTPUpdateServer-impl.h" + +typedef ESP8266HTTPUpdateServerTemplate ESP8266HTTPUpdateServer; #endif diff --git a/libraries/ESP8266WebServer/src/ESP8266WebServer.cpp b/libraries/ESP8266WebServer/src/ESP8266WebServer-impl.h similarity index 52% rename from libraries/ESP8266WebServer/src/ESP8266WebServer.cpp rename to libraries/ESP8266WebServer/src/ESP8266WebServer-impl.h index 7f0657629f..5b2a942b25 100644 --- a/libraries/ESP8266WebServer/src/ESP8266WebServer.cpp +++ b/libraries/ESP8266WebServer/src/ESP8266WebServer-impl.h @@ -42,7 +42,8 @@ static const char WWW_Authenticate[] PROGMEM = "WWW-Authenticate"; static const char Content_Length[] PROGMEM = "Content-Length"; -ESP8266WebServer::ESP8266WebServer(IPAddress addr, int port) +template +ESP8266WebServerTemplate::ESP8266WebServerTemplate(IPAddress addr, int port) : _server(addr, port) , _currentMethod(HTTP_ANY) , _currentVersion(0) @@ -60,7 +61,8 @@ ESP8266WebServer::ESP8266WebServer(IPAddress addr, int port) { } -ESP8266WebServer::ESP8266WebServer(int port) +template +ESP8266WebServerTemplate::ESP8266WebServerTemplate(int port) : _server(port) , _currentMethod(HTTP_ANY) , _currentVersion(0) @@ -78,39 +80,44 @@ ESP8266WebServer::ESP8266WebServer(int port) { } -ESP8266WebServer::~ESP8266WebServer() { +template +ESP8266WebServerTemplate::~ESP8266WebServerTemplate() { _server.close(); if (_currentHeaders) delete[]_currentHeaders; - RequestHandler* handler = _firstHandler; + RequestHandler* handler = _firstHandler; while (handler) { - RequestHandler* next = handler->next(); + RequestHandler* next = handler->next(); delete handler; handler = next; } } -void ESP8266WebServer::begin() { +template +void ESP8266WebServerTemplate::begin() { close(); _server.begin(); } -void ESP8266WebServer::begin(uint16_t port) { +template +void ESP8266WebServerTemplate::begin(uint16_t port) { close(); _server.begin(port); } -String ESP8266WebServer::_extractParam(String& authReq,const String& param,const char delimit){ +template +String ESP8266WebServerTemplate::_extractParam(String& authReq,const String& param,const char delimit){ int _begin = authReq.indexOf(param); if (_begin == -1) return ""; return authReq.substring(_begin+param.length(),authReq.indexOf(delimit,_begin+param.length())); } -bool ESP8266WebServer::authenticate(const char * username, const char * password){ +template +bool ESP8266WebServerTemplate::authenticate(const char * username, const char * password){ if(hasHeader(FPSTR(AUTHORIZATION_HEADER))) { String authReq = header(FPSTR(AUTHORIZATION_HEADER)); - if(authReq.startsWith(F("Basic"))){ + if(authReq.startsWith(("Basic"))){ authReq = authReq.substring(6); authReq.trim(); char toencodeLen = strlen(username)+strlen(password)+1; @@ -134,22 +141,22 @@ bool ESP8266WebServer::authenticate(const char * username, const char * password } delete[] toencode; delete[] encoded; - } else if(authReq.startsWith(F("Digest"))) { + } else if(authReq.startsWith(("Digest"))) { authReq = authReq.substring(7); #ifdef DEBUG_ESP_HTTP_SERVER DEBUG_OUTPUT.println(authReq); #endif - String _username = _extractParam(authReq,F("username=\"")); + String _username = _extractParam(authReq,("username=\"")); if(!_username.length() || _username != String(username)) { authReq = ""; return false; } // extracting required parameters for RFC 2069 simpler Digest - String _realm = _extractParam(authReq, F("realm=\"")); - String _nonce = _extractParam(authReq, F("nonce=\"")); - String _uri = _extractParam(authReq, F("uri=\"")); - String _response = _extractParam(authReq, F("response=\"")); - String _opaque = _extractParam(authReq, F("opaque=\"")); + String _realm = _extractParam(authReq, ("realm=\"")); + String _nonce = _extractParam(authReq, ("nonce=\"")); + String _uri = _extractParam(authReq, ("uri=\"")); + String _response = _extractParam(authReq, ("response=\"")); + String _opaque = _extractParam(authReq, ("opaque=\"")); if((!_realm.length()) || (!_nonce.length()) || (!_uri.length()) || (!_response.length()) || (!_opaque.length())) { authReq = ""; @@ -162,8 +169,8 @@ bool ESP8266WebServer::authenticate(const char * username, const char * password // parameters for the RFC 2617 newer Digest String _nc,_cnonce; if(authReq.indexOf(FPSTR(qop_auth)) != -1) { - _nc = _extractParam(authReq, F("nc="), ','); - _cnonce = _extractParam(authReq, F("cnonce=\"")); + _nc = _extractParam(authReq, ("nc="), ','); + _cnonce = _extractParam(authReq, ("cnonce=\"")); } MD5Builder md5; md5.begin(); @@ -175,15 +182,15 @@ bool ESP8266WebServer::authenticate(const char * username, const char * password #endif md5.begin(); if(_currentMethod == HTTP_GET){ - md5.add(String(F("GET:")) + _uri); + md5.add(String(("GET:")) + _uri); }else if(_currentMethod == HTTP_POST){ - md5.add(String(F("POST:")) + _uri); + md5.add(String(("POST:")) + _uri); }else if(_currentMethod == HTTP_PUT){ - md5.add(String(F("PUT:")) + _uri); + md5.add(String(("PUT:")) + _uri); }else if(_currentMethod == HTTP_DELETE){ - md5.add(String(F("DELETE:")) + _uri); + md5.add(String(("DELETE:")) + _uri); }else{ - md5.add(String(F("GET:")) + _uri); + md5.add(String(("GET:")) + _uri); } md5.calculate(); String _H2 = md5.toString(); @@ -192,7 +199,7 @@ bool ESP8266WebServer::authenticate(const char * username, const char * password #endif md5.begin(); if(authReq.indexOf(FPSTR(qop_auth)) != -1) { - md5.add(_H1 + ':' + _nonce + ':' + _nc + ':' + _cnonce + F(":auth:") + _H2); + md5.add(_H1 + ':' + _nonce + ':' + _nc + ':' + _cnonce + (":auth:") + _H2); } else { md5.add(_H1 + ':' + _nonce + ':' + _H2); } @@ -211,7 +218,8 @@ bool ESP8266WebServer::authenticate(const char * username, const char * password return false; } -String ESP8266WebServer::_getRandomHexString() { +template +String ESP8266WebServerTemplate::_getRandomHexString() { char buffer[33]; // buffer to hold 32 Hex Digit + /0 int i; for(i = 0; i < 4; i++) { @@ -220,40 +228,46 @@ String ESP8266WebServer::_getRandomHexString() { return String(buffer); } -void ESP8266WebServer::requestAuthentication(HTTPAuthMethod mode, const char* realm, const String& authFailMsg) { +template +void ESP8266WebServerTemplate::requestAuthentication(HTTPAuthMethod mode, const char* realm, const String& authFailMsg) { if(realm == NULL) { - _srealm = String(F("Login Required")); + _srealm = String(("Login Required")); } else { _srealm = String(realm); } if(mode == BASIC_AUTH) { - sendHeader(String(FPSTR(WWW_Authenticate)), String(F("Basic realm=\"")) + _srealm + String(F("\""))); + sendHeader(String(FPSTR(WWW_Authenticate)), String(("Basic realm=\"")) + _srealm + String(("\""))); } else { _snonce=_getRandomHexString(); _sopaque=_getRandomHexString(); - sendHeader(String(FPSTR(WWW_Authenticate)), String(F("Digest realm=\"")) +_srealm + String(F("\", qop=\"auth\", nonce=\"")) + _snonce + String(F("\", opaque=\"")) + _sopaque + String(F("\""))); + sendHeader(String(FPSTR(WWW_Authenticate)), String(("Digest realm=\"")) +_srealm + String(("\", qop=\"auth\", nonce=\"")) + _snonce + String(("\", opaque=\"")) + _sopaque + String(("\""))); } using namespace mime; send(401, String(FPSTR(mimeTable[html].mimeType)), authFailMsg); } -void ESP8266WebServer::on(const String &uri, ESP8266WebServer::THandlerFunction handler) { +template +void ESP8266WebServerTemplate::on(const String &uri, ESP8266WebServerTemplate::THandlerFunction handler) { on(uri, HTTP_ANY, handler); } -void ESP8266WebServer::on(const String &uri, HTTPMethod method, ESP8266WebServer::THandlerFunction fn) { +template +void ESP8266WebServerTemplate::on(const String &uri, HTTPMethod method, ESP8266WebServerTemplate::THandlerFunction fn) { on(uri, method, fn, _fileUploadHandler); } -void ESP8266WebServer::on(const String &uri, HTTPMethod method, ESP8266WebServer::THandlerFunction fn, ESP8266WebServer::THandlerFunction ufn) { - _addRequestHandler(new FunctionRequestHandler(fn, ufn, uri, method)); +template +void ESP8266WebServerTemplate::on(const String &uri, HTTPMethod method, ESP8266WebServerTemplate::THandlerFunction fn, ESP8266WebServerTemplate::THandlerFunction ufn) { + _addRequestHandler(new FunctionRequestHandler(fn, ufn, uri, method)); } -void ESP8266WebServer::addHandler(RequestHandler* handler) { +template +void ESP8266WebServerTemplate::addHandler(RequestHandler* handler) { _addRequestHandler(handler); } -void ESP8266WebServer::_addRequestHandler(RequestHandler* handler) { +template +void ESP8266WebServerTemplate::_addRequestHandler(RequestHandler* handler) { if (!_lastHandler) { _firstHandler = handler; _lastHandler = handler; @@ -264,13 +278,15 @@ void ESP8266WebServer::_addRequestHandler(RequestHandler* handler) { } } -void ESP8266WebServer::serveStatic(const char* uri, FS& fs, const char* path, const char* cache_header) { - _addRequestHandler(new StaticRequestHandler(fs, path, uri, cache_header)); +template +void ESP8266WebServerTemplate::serveStatic(const char* uri, FS& fs, const char* path, const char* cache_header) { + _addRequestHandler(new StaticRequestHandler(fs, path, uri, cache_header)); } -void ESP8266WebServer::handleClient() { +template +void ESP8266WebServerTemplate::handleClient() { if (_currentStatus == HC_NONE) { - WiFiClient client = _server.available(); + ClientType client = _server.available(); if (!client) { return; } @@ -323,7 +339,7 @@ void ESP8266WebServer::handleClient() { } if (!keepCurrentClient) { - _currentClient = WiFiClient(); + _currentClient = ClientType(); _currentStatus = HC_NONE; _currentUpload.reset(); } @@ -333,20 +349,23 @@ void ESP8266WebServer::handleClient() { } } -void ESP8266WebServer::close() { +template +void ESP8266WebServerTemplate::close() { _server.close(); _currentStatus = HC_NONE; if(!_headerKeysCount) collectHeaders(0, 0); } -void ESP8266WebServer::stop() { +template +void ESP8266WebServerTemplate::stop() { close(); } -void ESP8266WebServer::sendHeader(const String& name, const String& value, bool first) { +template +void ESP8266WebServerTemplate::sendHeader(const String& name, const String& value, bool first) { String headerLine = name; - headerLine += F(": "); + headerLine += (": "); headerLine += value; headerLine += "\r\n"; @@ -358,12 +377,14 @@ void ESP8266WebServer::sendHeader(const String& name, const String& value, bool } } -void ESP8266WebServer::setContentLength(const size_t contentLength) { +template +void ESP8266WebServerTemplate::setContentLength(const size_t contentLength) { _contentLength = contentLength; } -void ESP8266WebServer::_prepareHeader(String& response, int code, const char* content_type, size_t contentLength) { - response = String(F("HTTP/1.")) + String(_currentVersion) + ' '; +template +void ESP8266WebServerTemplate::_prepareHeader(String& response, int code, const char* content_type, size_t contentLength) { + response = String(("HTTP/1.")) + String(_currentVersion) + ' '; response += String(code); response += ' '; response += _responseCodeToString(code); @@ -373,7 +394,7 @@ void ESP8266WebServer::_prepareHeader(String& response, int code, const char* co if (!content_type) content_type = mimeTable[html].mimeType; - sendHeader(String(F("Content-Type")), String(FPSTR(content_type)), true); + sendHeader(String(("Content-Type")), String(FPSTR(content_type)), true); if (_contentLength == CONTENT_LENGTH_NOT_SET) { sendHeader(String(FPSTR(Content_Length)), String(contentLength)); } else if (_contentLength != CONTENT_LENGTH_UNKNOWN) { @@ -381,28 +402,30 @@ void ESP8266WebServer::_prepareHeader(String& response, int code, const char* co } else if(_contentLength == CONTENT_LENGTH_UNKNOWN && _currentVersion){ //HTTP/1.1 or above client //let's do chunked _chunked = true; - sendHeader(String(F("Accept-Ranges")),String(F("none"))); - sendHeader(String(F("Transfer-Encoding")),String(F("chunked"))); + sendHeader(String(("Accept-Ranges")),String(("none"))); + sendHeader(String(("Transfer-Encoding")),String(("chunked"))); } - sendHeader(String(F("Connection")), String(F("close"))); + sendHeader(String(("Connection")), String(("close"))); response += _responseHeaders; response += "\r\n"; _responseHeaders = ""; } -void ESP8266WebServer::send(int code, const char* content_type, const String& content) { +template +void ESP8266WebServerTemplate::send(int code, const char* content_type, const String& content) { String header; // Can we asume the following? //if(code == 200 && content.length() == 0 && _contentLength == CONTENT_LENGTH_NOT_SET) // _contentLength = CONTENT_LENGTH_UNKNOWN; _prepareHeader(header, code, content_type, content.length()); - _currentClientWrite(header.c_str(), header.length()); + _currentClient.write((const uint8_t *)header.c_str(), header.length()); if(content.length()) sendContent(content); } -void ESP8266WebServer::send_P(int code, PGM_P content_type, PGM_P content) { +template +void ESP8266WebServerTemplate::send_P(int code, PGM_P content_type, PGM_P content) { size_t contentLength = 0; if (content != NULL) { @@ -413,11 +436,12 @@ void ESP8266WebServer::send_P(int code, PGM_P content_type, PGM_P content) { char type[64]; memccpy_P((void*)type, (PGM_VOID_P)content_type, 0, sizeof(type)); _prepareHeader(header, code, (const char* )type, contentLength); - _currentClientWrite(header.c_str(), header.length()); + _currentClient.write((const uint8_t *)header.c_str(), header.length()); sendContent_P(content); } -void ESP8266WebServer::send_P(int code, PGM_P content_type, PGM_P content, size_t contentLength) { +template +void ESP8266WebServerTemplate::send_P(int code, PGM_P content_type, PGM_P content, size_t contentLength) { String header; char type[64]; memccpy_P((void*)type, (PGM_VOID_P)content_type, 0, sizeof(type)); @@ -426,51 +450,56 @@ void ESP8266WebServer::send_P(int code, PGM_P content_type, PGM_P content, size_ sendContent_P(content, contentLength); } -void ESP8266WebServer::send(int code, char* content_type, const String& content) { +template +void ESP8266WebServerTemplate::send(int code, char* content_type, const String& content) { send(code, (const char*)content_type, content); } -void ESP8266WebServer::send(int code, const String& content_type, const String& content) { +template +void ESP8266WebServerTemplate::send(int code, const String& content_type, const String& content) { send(code, (const char*)content_type.c_str(), content); } -void ESP8266WebServer::sendContent(const String& content) { +template +void ESP8266WebServerTemplate::sendContent(const String& content) { const char * footer = "\r\n"; size_t len = content.length(); if(_chunked) { char * chunkSize = (char *)malloc(11); if(chunkSize){ sprintf(chunkSize, "%x%s", len, footer); - _currentClientWrite(chunkSize, strlen(chunkSize)); + _currentClient.write((const uint8_t *)chunkSize, strlen(chunkSize)); free(chunkSize); } } - _currentClientWrite(content.c_str(), len); + _currentClient.write((const uint8_t *)content.c_str(), len); if(_chunked){ - _currentClient.write(footer, 2); + _currentClient.write((const uint8_t *)footer, 2); if (len == 0) { _chunked = false; } } } -void ESP8266WebServer::sendContent_P(PGM_P content) { +template +void ESP8266WebServerTemplate::sendContent_P(PGM_P content) { sendContent_P(content, strlen_P(content)); } -void ESP8266WebServer::sendContent_P(PGM_P content, size_t size) { +template +void ESP8266WebServerTemplate::sendContent_P(PGM_P content, size_t size) { const char * footer = "\r\n"; if(_chunked) { char * chunkSize = (char *)malloc(11); if(chunkSize){ sprintf(chunkSize, "%x%s", size, footer); - _currentClientWrite(chunkSize, strlen(chunkSize)); + _currentClient.write((const uint8_t *)chunkSize, strlen(chunkSize)); free(chunkSize); } } - _currentClientWrite_P(content, size); + _currentClient.write_P(content, size); if(_chunked){ - _currentClient.write(footer, 2); + _currentClient.write((const uint8_t *)footer, 2); if (size == 0) { _chunked = false; } @@ -478,20 +507,22 @@ void ESP8266WebServer::sendContent_P(PGM_P content, size_t size) { } -void ESP8266WebServer::_streamFileCore(const size_t fileSize, const String & fileName, const String & contentType) +template +void ESP8266WebServerTemplate::_streamFileCore(const size_t fileSize, const String & fileName, const String & contentType) { using namespace mime; setContentLength(fileSize); if (fileName.endsWith(String(FPSTR(mimeTable[gz].endsWith))) && contentType != String(FPSTR(mimeTable[gz].mimeType)) && contentType != String(FPSTR(mimeTable[none].mimeType))) { - sendHeader(F("Content-Encoding"), F("gzip")); + sendHeader(("Content-Encoding"), ("gzip")); } send(200, contentType, ""); } -String ESP8266WebServer::arg(String name) { +template +String ESP8266WebServerTemplate::arg(String name) { for (int i = 0; i < _currentArgCount; ++i) { if ( _currentArgs[i].key == name ) return _currentArgs[i].value; @@ -499,23 +530,27 @@ String ESP8266WebServer::arg(String name) { return ""; } -String ESP8266WebServer::arg(int i) { +template +String ESP8266WebServerTemplate::arg(int i) { if (i < _currentArgCount) return _currentArgs[i].value; return ""; } -String ESP8266WebServer::argName(int i) { +template +String ESP8266WebServerTemplate::argName(int i) { if (i < _currentArgCount) return _currentArgs[i].key; return ""; } -int ESP8266WebServer::args() { +template +int ESP8266WebServerTemplate::args() { return _currentArgCount; } -bool ESP8266WebServer::hasArg(String name) { +template +bool ESP8266WebServerTemplate::hasArg(String name) { for (int i = 0; i < _currentArgCount; ++i) { if (_currentArgs[i].key == name) return true; @@ -524,7 +559,8 @@ bool ESP8266WebServer::hasArg(String name) { } -String ESP8266WebServer::header(String name) { +template +String ESP8266WebServerTemplate::header(String name) { for (int i = 0; i < _headerKeysCount; ++i) { if (_currentHeaders[i].key.equalsIgnoreCase(name)) return _currentHeaders[i].value; @@ -532,7 +568,8 @@ String ESP8266WebServer::header(String name) { return ""; } -void ESP8266WebServer::collectHeaders(const char* headerKeys[], const size_t headerKeysCount) { +template +void ESP8266WebServerTemplate::collectHeaders(const char* headerKeys[], const size_t headerKeysCount) { _headerKeysCount = headerKeysCount + 1; if (_currentHeaders) delete[]_currentHeaders; @@ -543,23 +580,27 @@ void ESP8266WebServer::collectHeaders(const char* headerKeys[], const size_t hea } } -String ESP8266WebServer::header(int i) { +template +String ESP8266WebServerTemplate::header(int i) { if (i < _headerKeysCount) return _currentHeaders[i].value; return ""; } -String ESP8266WebServer::headerName(int i) { +template +String ESP8266WebServerTemplate::headerName(int i) { if (i < _headerKeysCount) return _currentHeaders[i].key; return ""; } -int ESP8266WebServer::headers() { +template +int ESP8266WebServerTemplate::headers() { return _headerKeysCount; } -bool ESP8266WebServer::hasHeader(String name) { +template +bool ESP8266WebServerTemplate::hasHeader(String name) { for (int i = 0; i < _headerKeysCount; ++i) { if ((_currentHeaders[i].key.equalsIgnoreCase(name)) && (_currentHeaders[i].value.length() > 0)) return true; @@ -567,19 +608,23 @@ bool ESP8266WebServer::hasHeader(String name) { return false; } -String ESP8266WebServer::hostHeader() { +template +String ESP8266WebServerTemplate::hostHeader() { return _hostHeader; } -void ESP8266WebServer::onFileUpload(THandlerFunction fn) { +template +void ESP8266WebServerTemplate::onFileUpload(THandlerFunction fn) { _fileUploadHandler = fn; } -void ESP8266WebServer::onNotFound(THandlerFunction fn) { +template +void ESP8266WebServerTemplate::onNotFound(THandlerFunction fn) { _notFoundHandler = fn; } -void ESP8266WebServer::_handleRequest() { +template +void ESP8266WebServerTemplate::_handleRequest() { bool handled = false; if (!_currentHandler){ #ifdef DEBUG_ESP_HTTP_SERVER @@ -600,7 +645,7 @@ void ESP8266WebServer::_handleRequest() { } if (!handled) { using namespace mime; - send(404, String(FPSTR(mimeTable[html].mimeType)), String(F("Not found: ")) + _currentUri); + send(404, String(FPSTR(mimeTable[html].mimeType)), String(("Not found: ")) + _currentUri); handled = true; } if (handled) { @@ -610,54 +655,56 @@ void ESP8266WebServer::_handleRequest() { } -void ESP8266WebServer::_finalizeResponse() { +template +void ESP8266WebServerTemplate::_finalizeResponse() { if (_chunked) { sendContent(""); } } -String ESP8266WebServer::_responseCodeToString(int code) { +template +String ESP8266WebServerTemplate::_responseCodeToString(int code) { switch (code) { - case 100: return F("Continue"); - case 101: return F("Switching Protocols"); - case 200: return F("OK"); - case 201: return F("Created"); - case 202: return F("Accepted"); - case 203: return F("Non-Authoritative Information"); - case 204: return F("No Content"); - case 205: return F("Reset Content"); - case 206: return F("Partial Content"); - case 300: return F("Multiple Choices"); - case 301: return F("Moved Permanently"); - case 302: return F("Found"); - case 303: return F("See Other"); - case 304: return F("Not Modified"); - case 305: return F("Use Proxy"); - case 307: return F("Temporary Redirect"); - case 400: return F("Bad Request"); - case 401: return F("Unauthorized"); - case 402: return F("Payment Required"); - case 403: return F("Forbidden"); - case 404: return F("Not Found"); - case 405: return F("Method Not Allowed"); - case 406: return F("Not Acceptable"); - case 407: return F("Proxy Authentication Required"); - case 408: return F("Request Time-out"); - case 409: return F("Conflict"); - case 410: return F("Gone"); - case 411: return F("Length Required"); - case 412: return F("Precondition Failed"); - case 413: return F("Request Entity Too Large"); - case 414: return F("Request-URI Too Large"); - case 415: return F("Unsupported Media Type"); - case 416: return F("Requested range not satisfiable"); - case 417: return F("Expectation Failed"); - case 500: return F("Internal Server Error"); - case 501: return F("Not Implemented"); - case 502: return F("Bad Gateway"); - case 503: return F("Service Unavailable"); - case 504: return F("Gateway Time-out"); - case 505: return F("HTTP Version not supported"); - default: return F(""); + case 100: return ("Continue"); + case 101: return ("Switching Protocols"); + case 200: return ("OK"); + case 201: return ("Created"); + case 202: return ("Accepted"); + case 203: return ("Non-Authoritative Information"); + case 204: return ("No Content"); + case 205: return ("Reset Content"); + case 206: return ("Partial Content"); + case 300: return ("Multiple Choices"); + case 301: return ("Moved Permanently"); + case 302: return ("Found"); + case 303: return ("See Other"); + case 304: return ("Not Modified"); + case 305: return ("Use Proxy"); + case 307: return ("Temporary Redirect"); + case 400: return ("Bad Request"); + case 401: return ("Unauthorized"); + case 402: return ("Payment Required"); + case 403: return ("Forbidden"); + case 404: return ("Not Found"); + case 405: return ("Method Not Allowed"); + case 406: return ("Not Acceptable"); + case 407: return ("Proxy Authentication Required"); + case 408: return ("Request Time-out"); + case 409: return ("Conflict"); + case 410: return ("Gone"); + case 411: return ("Length Required"); + case 412: return ("Precondition Failed"); + case 413: return ("Request Entity Too Large"); + case 414: return ("Request-URI Too Large"); + case 415: return ("Unsupported Media Type"); + case 416: return ("Requested range not satisfiable"); + case 417: return ("Expectation Failed"); + case 500: return ("Internal Server Error"); + case 501: return ("Not Implemented"); + case 502: return ("Bad Gateway"); + case 503: return ("Service Unavailable"); + case 504: return ("Gateway Time-out"); + case 505: return ("HTTP Version not supported"); + default: return (""); } } diff --git a/libraries/ESP8266WebServer/src/ESP8266WebServer.h b/libraries/ESP8266WebServer/src/ESP8266WebServer.h index 0bfa302a4c..d15438838f 100644 --- a/libraries/ESP8266WebServer/src/ESP8266WebServer.h +++ b/libraries/ESP8266WebServer/src/ESP8266WebServer.h @@ -48,7 +48,8 @@ enum HTTPAuthMethod { BASIC_AUTH, DIGEST_AUTH }; #define CONTENT_LENGTH_UNKNOWN ((size_t) -1) #define CONTENT_LENGTH_NOT_SET ((size_t) -2) -class ESP8266WebServer; +template +class ESP8266WebServerTemplate; typedef struct { HTTPUploadStatus status; @@ -66,18 +67,21 @@ namespace fs { class FS; } -class ESP8266WebServer +template +class ESP8266WebServerTemplate { public: - ESP8266WebServer(IPAddress addr, int port = 80); - ESP8266WebServer(int port = 80); - virtual ~ESP8266WebServer(); + ESP8266WebServerTemplate(IPAddress addr, int port = 80); + ESP8266WebServerTemplate(int port = 80); + ~ESP8266WebServerTemplate(); - virtual void begin(); - virtual void begin(uint16_t port); - virtual void handleClient(); + using RequestHandlerType = RequestHandler; - virtual void close(); + void begin(); + void begin(uint16_t port); + void handleClient(); + + void close(); void stop(); bool authenticate(const char * username, const char * password); @@ -87,14 +91,14 @@ class ESP8266WebServer void on(const String &uri, THandlerFunction handler); void on(const String &uri, HTTPMethod method, THandlerFunction fn); void on(const String &uri, HTTPMethod method, THandlerFunction fn, THandlerFunction ufn); - void addHandler(RequestHandler* handler); + void addHandler(RequestHandlerType* handler); void serveStatic(const char* uri, fs::FS& fs, const char* path, const char* cache_header = NULL ); void onNotFound(THandlerFunction fn); //called when handler is not assigned void onFileUpload(THandlerFunction fn); //handle file uploads String uri() { return _currentUri; } HTTPMethod method() { return _currentMethod; } - virtual WiFiClient client() { return _currentClient; } + ClientType client() { return _currentClient; } HTTPUpload& upload() { return *_currentUpload; } String arg(String name); // get request argument value by name @@ -134,20 +138,21 @@ class ESP8266WebServer _streamFileCore(file.size(), file.name(), contentType); return _currentClient.write(file); } - + + // Allows setting server options (i.e. SSL keys) by the instantiator + ServerType &getServer() { return _server; } + protected: - virtual size_t _currentClientWrite(const char* b, size_t l) { return _currentClient.write( b, l ); } - virtual size_t _currentClientWrite_P(PGM_P b, size_t l) { return _currentClient.write_P( b, l ); } - void _addRequestHandler(RequestHandler* handler); + void _addRequestHandler(RequestHandlerType* handler); void _handleRequest(); void _finalizeResponse(); - bool _parseRequest(WiFiClient& client); + bool _parseRequest(ClientType& client); void _parseArguments(String data); static String _responseCodeToString(int code); - bool _parseForm(WiFiClient& client, String boundary, uint32_t len); + bool _parseForm(ClientType& client, String boundary, uint32_t len); bool _parseFormUploadAborted(); void _uploadWriteByte(uint8_t b); - uint8_t _uploadReadByte(WiFiClient& client); + uint8_t _uploadReadByte(ClientType& client); void _prepareHeader(String& response, int code, const char* content_type, size_t contentLength); bool _collectHeader(const char* headerName, const char* headerValue); @@ -162,18 +167,18 @@ class ESP8266WebServer String value; }; - WiFiServer _server; + ServerType _server; - WiFiClient _currentClient; + ClientType _currentClient; HTTPMethod _currentMethod; String _currentUri; uint8_t _currentVersion; HTTPClientStatus _currentStatus; unsigned long _statusChange; - RequestHandler* _currentHandler; - RequestHandler* _firstHandler; - RequestHandler* _lastHandler; + RequestHandlerType* _currentHandler; + RequestHandlerType* _firstHandler; + RequestHandlerType* _lastHandler; THandlerFunction _notFoundHandler; THandlerFunction _fileUploadHandler; @@ -195,5 +200,9 @@ class ESP8266WebServer }; +#include "ESP8266WebServer-impl.h" +#include "Parsing-impl.h" + +using ESP8266WebServer = ESP8266WebServerTemplate; #endif //ESP8266WEBSERVER_H diff --git a/libraries/ESP8266WebServer/src/ESP8266WebServerSecure.h b/libraries/ESP8266WebServer/src/ESP8266WebServerSecure.h index fa248c1f1f..f969da1e3f 100644 --- a/libraries/ESP8266WebServer/src/ESP8266WebServerSecure.h +++ b/libraries/ESP8266WebServer/src/ESP8266WebServerSecure.h @@ -19,5 +19,17 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "ESP8266WebServerSecureAxTLS.h" -#include "ESP8266WebServerSecureBearSSL.h" +#include "ESP8266WebServer.h" + +#ifndef ESP8266SECUREWEBSERVER_H +#define ESP8266SECUREWEBSERVER_H + +namespace axTLS { + typedef ESP8266WebServerTemplate ESP8266WebServerSecure; +}; + +namespace BearSSL { + typedef ESP8266WebServerTemplate ESP8266WebServerSecure; +}; + +#endif diff --git a/libraries/ESP8266WebServer/src/ESP8266WebServerSecureAxTLS.cpp b/libraries/ESP8266WebServer/src/ESP8266WebServerSecureAxTLS.cpp deleted file mode 100644 index fb62b75ef7..0000000000 --- a/libraries/ESP8266WebServer/src/ESP8266WebServerSecureAxTLS.cpp +++ /dev/null @@ -1,149 +0,0 @@ -/* - ESP8266WebServerSecure.cpp - Dead simple HTTPS web-server. - Supports only one simultaneous client, knows how to handle GET and POST. - - Copyright (c) 2017 Earle F. Philhower, III. All rights reserved. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - Modified 8 May 2015 by Hristo Gochkov (proper post and file upload handling) -*/ - - -#include -#include -#include "WiFiServer.h" -#include "WiFiClient.h" -#include "ESP8266WebServerSecure.h" - -//#define DEBUG_ESP_HTTP_SERVER -#ifdef DEBUG_ESP_PORT -#define DEBUG_OUTPUT DEBUG_ESP_PORT -#else -#define DEBUG_OUTPUT Serial -#endif - -namespace axTLS { - -ESP8266WebServerSecure::ESP8266WebServerSecure(IPAddress addr, int port) -: _serverSecure(addr, port) -{ -} - -ESP8266WebServerSecure::ESP8266WebServerSecure(int port) -: _serverSecure(port) -{ -} - -void ESP8266WebServerSecure::setServerKeyAndCert_P(const uint8_t *key, int keyLen, const uint8_t *cert, int certLen) -{ - _serverSecure.setServerKeyAndCert_P(key, keyLen, cert, certLen); -} - -void ESP8266WebServerSecure::setServerKeyAndCert(const uint8_t *key, int keyLen, const uint8_t *cert, int certLen) -{ - _serverSecure.setServerKeyAndCert(key, keyLen, cert, certLen); -} - -ESP8266WebServerSecure::~ESP8266WebServerSecure() { - // Nothing to do here. - // Base class's destructor will be called to clean up itself -} - -// We need to basically cut-n-paste these from WebServer because of the problem -// of object slicing. The class uses assignment operators like "WiFiClient x=y;" -// When this happens, even if "y" is a WiFiClientSecure, the main class is -// already compiled down into code which will only copy the WiFiClient superclass -// and not the extra bits for our own class (since when it was compiled it needed -// to know the size of memory to allocate on the stack for this local variable -// there's not realy anything else it could do). - -void ESP8266WebServerSecure::begin() { - _currentStatus = HC_NONE; - _serverSecure.begin(); - if(!_headerKeysCount) - collectHeaders(0, 0); -} - -void ESP8266WebServerSecure::handleClient() { - if (_currentStatus == HC_NONE) { - WiFiClientSecure client = _serverSecure.available(); - if (!client) { - return; - } - -#ifdef DEBUG_ESP_HTTP_SERVER - DEBUG_OUTPUT.println("New secure client"); -#endif - - _currentClientSecure = client; - _currentStatus = HC_WAIT_READ; - _statusChange = millis(); - } - - bool keepCurrentClient = false; - bool callYield = false; - - if (_currentClientSecure.connected()) { - switch (_currentStatus) { - case HC_NONE: - // No-op to avoid C++ compiler warning - break; - case HC_WAIT_READ: - // Wait for data from client to become available - if (_currentClientSecure.available()) { - if (_parseRequest(_currentClientSecure)) { - _currentClientSecure.setTimeout(HTTP_MAX_SEND_WAIT); - _contentLength = CONTENT_LENGTH_NOT_SET; - _handleRequest(); - - if (_currentClientSecure.connected()) { - _currentStatus = HC_WAIT_CLOSE; - _statusChange = millis(); - keepCurrentClient = true; - } - } - } else { // !_currentClient.available() - if (millis() - _statusChange <= HTTP_MAX_DATA_WAIT) { - keepCurrentClient = true; - } - callYield = true; - } - break; - case HC_WAIT_CLOSE: - // Wait for client to close the connection - if (millis() - _statusChange <= HTTP_MAX_CLOSE_WAIT) { - keepCurrentClient = true; - callYield = true; - } - } - } - - if (!keepCurrentClient) { - _currentClientSecure = WiFiClientSecure(); - _currentStatus = HC_NONE; - _currentUpload.reset(); - } - - if (callYield) { - yield(); - } -} - -void ESP8266WebServerSecure::close() { - _currentClientSecure.stop(); - _serverSecure.close(); -} - -}; diff --git a/libraries/ESP8266WebServer/src/ESP8266WebServerSecureAxTLS.h b/libraries/ESP8266WebServer/src/ESP8266WebServerSecureAxTLS.h deleted file mode 100644 index abc351ea43..0000000000 --- a/libraries/ESP8266WebServer/src/ESP8266WebServerSecureAxTLS.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - ESP8266WebServerSecure.h - Dead simple HTTPS web-server. - Supports only one simultaneous client, knows how to handle GET and POST. - - Copyright (c) 2017 Earle F. Philhower, III. All rights reserved. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - - -#ifndef ESP8266WEBSERVERSECURE_H -#define ESP8266WEBSERVERSECURE_H - -#include -#include - -namespace axTLS { - -class ESP8266WebServerSecure : public ESP8266WebServer -{ -public: - ESP8266WebServerSecure(IPAddress addr, int port = 443); - ESP8266WebServerSecure(int port = 443); - virtual ~ESP8266WebServerSecure(); - - void setServerKeyAndCert_P(const uint8_t *key, int keyLen, const uint8_t *cert, int certLen); - void setServerKeyAndCert(const uint8_t *key, int keyLen, const uint8_t *cert, int certLen); - - WiFiClient client() override { return _currentClientSecure; } - - void begin() override; - void handleClient() override; - void close() override; - - template - size_t streamFile(T &file, const String& contentType) { - _streamFileCore(file.size(), file.name(), contentType); - return _currentClientSecure.write(file); - } - -private: - size_t _currentClientWrite (const char *bytes, size_t len) override { return _currentClientSecure.write((const uint8_t *)bytes, len); } - size_t _currentClientWrite_P (PGM_P bytes, size_t len) override { return _currentClientSecure.write_P(bytes, len); } - -protected: - WiFiServerSecure _serverSecure; - WiFiClientSecure _currentClientSecure; -}; - -}; - -#endif //ESP8266WEBSERVERSECURE_H diff --git a/libraries/ESP8266WebServer/src/ESP8266WebServerSecureBearSSL.cpp b/libraries/ESP8266WebServer/src/ESP8266WebServerSecureBearSSL.cpp deleted file mode 100644 index 63ab49ceb6..0000000000 --- a/libraries/ESP8266WebServer/src/ESP8266WebServerSecureBearSSL.cpp +++ /dev/null @@ -1,165 +0,0 @@ -/* - ESP8266WebServerSecure.cpp - Dead simple HTTPS web-server. - Supports only one simultaneous client, knows how to handle GET and POST. - - Copyright (c) 2017 Earle F. Philhower, III. All rights reserved. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - Modified 8 May 2015 by Hristo Gochkov (proper post and file upload handling) -*/ - - -#include -#include -#include "WiFiServer.h" -#include "WiFiClient.h" -#include "ESP8266WebServerSecureBearSSL.h" - -//#define DEBUG_ESP_HTTP_SERVER -#ifdef DEBUG_ESP_PORT -#define DEBUG_OUTPUT DEBUG_ESP_PORT -#else -#define DEBUG_OUTPUT Serial -#endif - -namespace BearSSL { - -ESP8266WebServerSecure::ESP8266WebServerSecure(IPAddress addr, int port) -: _serverSecure(addr, port) -{ -} - -ESP8266WebServerSecure::ESP8266WebServerSecure(int port) -: _serverSecure(port) -{ -} - -void ESP8266WebServerSecure::setRSACert(const BearSSLX509List *chain, const BearSSLPrivateKey *sk) -{ - _serverSecure.setRSACert(chain, sk); -} - -void ESP8266WebServerSecure::setECCert(const BearSSLX509List *chain, unsigned cert_issuer_key_type, const BearSSLPrivateKey *sk) -{ - _serverSecure.setECCert(chain, cert_issuer_key_type, sk); -} - -void ESP8266WebServerSecure::setBufferSizes(int recv, int xmit) -{ - _serverSecure.setBufferSizes(recv, xmit); -} - -ESP8266WebServerSecure::~ESP8266WebServerSecure() { - // Nothing to do here. - // Base class's destructor will be called to clean up itself -} - -// We need to basically cut-n-paste these from WebServer because of the problem -// of object slicing. The class uses assignment operators like "WiFiClient x=y;" -// When this happens, even if "y" is a WiFiClientSecure, the main class is -// already compiled down into code which will only copy the WiFiClient superclass -// and not the extra bits for our own class (since when it was compiled it needed -// to know the size of memory to allocate on the stack for this local variable -// there's not realy anything else it could do). - -void ESP8266WebServerSecure::begin() { - _currentStatus = HC_NONE; - _serverSecure.begin(); - if(!_headerKeysCount) - collectHeaders(0, 0); -} - -void ESP8266WebServerSecure::handleClient() { - if (_currentStatus == HC_NONE) { - BearSSL::WiFiClientSecure client = _serverSecure.available(); - if (!client) { - return; - } - -#ifdef DEBUG_ESP_HTTP_SERVER - DEBUG_OUTPUT.println("New secure client"); -#endif - - _currentClientSecure = client; - _currentStatus = HC_WAIT_READ; - _statusChange = millis(); - } - - bool keepCurrentClient = false; - bool callYield = false; - - if (_currentClientSecure.connected()) { - switch (_currentStatus) { - case HC_NONE: - // No-op to avoid C++ compiler warning - break; - case HC_WAIT_READ: - // Wait for data from client to become available - if (_currentClientSecure.available()) { - if (_parseRequest(_currentClientSecure)) { - _currentClientSecure.setTimeout(HTTP_MAX_SEND_WAIT); - _contentLength = CONTENT_LENGTH_NOT_SET; - _handleRequest(); - - if (_currentClientSecure.connected()) { - _currentStatus = HC_WAIT_CLOSE; - _statusChange = millis(); - keepCurrentClient = true; - } - } - } else { // !_currentClient.available() - if (millis() - _statusChange <= HTTP_MAX_DATA_WAIT) { - keepCurrentClient = true; - } - callYield = true; - } - break; - case HC_WAIT_CLOSE: - // Wait for client to close the connection - if (millis() - _statusChange <= HTTP_MAX_CLOSE_WAIT) { - keepCurrentClient = true; - callYield = true; - } - } - } - - if (!keepCurrentClient) { - _currentClientSecure = BearSSL::WiFiClientSecure(); - _currentStatus = HC_NONE; - _currentUpload.reset(); - } - - if (callYield) { - yield(); - } -} - -void ESP8266WebServerSecure::close() { - _currentClientSecure.flush(); - _currentClientSecure.stop(); - _serverSecure.close(); -} - - -void ESP8266WebServerSecure::setServerKeyAndCert_P(const uint8_t *key, int keyLen, const uint8_t *cert, int certLen) { - _serverSecure.setServerKeyAndCert_P(key, keyLen, cert, certLen); -} - -void ESP8266WebServerSecure::setServerKeyAndCert(const uint8_t *key, int keyLen, const uint8_t *cert, int certLen) -{ - _serverSecure.setServerKeyAndCert(key, keyLen, cert, certLen); -} - -}; diff --git a/libraries/ESP8266WebServer/src/ESP8266WebServerSecureBearSSL.h b/libraries/ESP8266WebServer/src/ESP8266WebServerSecureBearSSL.h deleted file mode 100644 index 86785f81b0..0000000000 --- a/libraries/ESP8266WebServer/src/ESP8266WebServerSecureBearSSL.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - ESP8266WebServerSecure.h - Dead simple HTTPS web-server. - Supports only one simultaneous client, knows how to handle GET and POST. - - Copyright (c) 2017 Earle F. Philhower, III. All rights reserved. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - - -#ifndef ESP8266WEBSERVERBEARSSL_H -#define ESP8266WEBSERVERBEARSSL_H - -#include -#include -#include - -namespace BearSSL { - -class ESP8266WebServerSecure : public ESP8266WebServer -{ -public: - ESP8266WebServerSecure(IPAddress addr, int port = 443); - ESP8266WebServerSecure(int port = 443); - virtual ~ESP8266WebServerSecure(); - - void setBufferSizes(int recv, int xmit); - void setRSACert(const BearSSLX509List *chain, const BearSSLPrivateKey *sk); - void setECCert(const BearSSLX509List *chain, unsigned cert_issuer_key_type, const BearSSLPrivateKey *sk); - - WiFiClient client() override { return _currentClientSecure; } - - void begin() override; - void handleClient() override; - void close() override; - - template - size_t streamFile(T &file, const String& contentType) { - _streamFileCore(file.size(), file.name(), contentType); - return _currentClientSecure.write(file); - } - - // AXTLS Compatibility - void setServerKeyAndCert_P(const uint8_t *key, int keyLen, const uint8_t *cert, int certLen); - void setServerKeyAndCert(const uint8_t *key, int keyLen, const uint8_t *cert, int certLen); - -private: - size_t _currentClientWrite (const char *bytes, size_t len) override { return _currentClientSecure.write((const uint8_t *)bytes, len); } - size_t _currentClientWrite_P (PGM_P bytes, size_t len) override { return _currentClientSecure.write_P(bytes, len); } - -protected: - BearSSL::WiFiServerSecure _serverSecure; - BearSSL::WiFiClientSecure _currentClientSecure; -}; - -}; -#endif //ESP8266WEBSERVERSECURE_H diff --git a/libraries/ESP8266WebServer/src/Parsing.cpp b/libraries/ESP8266WebServer/src/Parsing-impl.h similarity index 90% rename from libraries/ESP8266WebServer/src/Parsing.cpp rename to libraries/ESP8266WebServer/src/Parsing-impl.h index 25bf6acec0..afdb153a84 100644 --- a/libraries/ESP8266WebServer/src/Parsing.cpp +++ b/libraries/ESP8266WebServer/src/Parsing-impl.h @@ -35,7 +35,8 @@ static const char Content_Type[] PROGMEM = "Content-Type"; static const char filename[] PROGMEM = "filename"; -static char* readBytesWithTimeout(WiFiClient& client, size_t maxLength, size_t& dataLength, int timeout_ms) +template +static char* readBytesWithTimeout(ClientType& client, size_t maxLength, size_t& dataLength, int timeout_ms) { char *buf = nullptr; dataLength = 0; @@ -67,7 +68,8 @@ static char* readBytesWithTimeout(WiFiClient& client, size_t maxLength, size_t& return buf; } -bool ESP8266WebServer::_parseRequest(WiFiClient& client) { +template +bool ESP8266WebServerTemplate::_parseRequest(ClientType& client) { // Read the first line of HTTP request String req = client.readStringUntil('\r'); client.readStringUntil('\n'); @@ -125,7 +127,7 @@ bool ESP8266WebServer::_parseRequest(WiFiClient& client) { #endif //attach handler - RequestHandler* handler; + RequestHandlerType* handler; for (handler = _firstHandler; handler; handler = handler->next()) { if (handler->canHandle(_currentMethod, _currentUri)) break; @@ -166,24 +168,24 @@ bool ESP8266WebServer::_parseRequest(WiFiClient& client) { using namespace mime; if (headerValue.startsWith(FPSTR(mimeTable[txt].mimeType))){ isForm = false; - } else if (headerValue.startsWith(F("application/x-www-form-urlencoded"))){ + } else if (headerValue.startsWith(("application/x-www-form-urlencoded"))){ isForm = false; isEncoded = true; - } else if (headerValue.startsWith(F("multipart/"))){ + } else if (headerValue.startsWith(("multipart/"))){ boundaryStr = headerValue.substring(headerValue.indexOf('=') + 1); boundaryStr.replace("\"",""); isForm = true; } - } else if (headerName.equalsIgnoreCase(F("Content-Length"))){ + } else if (headerName.equalsIgnoreCase(("Content-Length"))){ contentLength = headerValue.toInt(); - } else if (headerName.equalsIgnoreCase(F("Host"))){ + } else if (headerName.equalsIgnoreCase(("Host"))){ _hostHeader = headerValue; } } if (!isForm){ size_t plainLength; - char* plainBuf = readBytesWithTimeout(client, contentLength, plainLength, HTTP_MAX_POST_WAIT); + char* plainBuf = readBytesWithTimeout(client, contentLength, plainLength, HTTP_MAX_POST_WAIT); if (plainLength < contentLength) { free(plainBuf); return false; @@ -198,7 +200,7 @@ bool ESP8266WebServer::_parseRequest(WiFiClient& client) { if(!isEncoded){ //plain post json or other data RequestArgument& arg = _currentArgs[_currentArgCount++]; - arg.key = F("plain"); + arg.key = ("plain"); arg.value = String(plainBuf); } @@ -260,7 +262,8 @@ bool ESP8266WebServer::_parseRequest(WiFiClient& client) { return true; } -bool ESP8266WebServer::_collectHeader(const char* headerName, const char* headerValue) { +template +bool ESP8266WebServerTemplate::_collectHeader(const char* headerName, const char* headerValue) { for (int i = 0; i < _headerKeysCount; i++) { if (_currentHeaders[i].key.equalsIgnoreCase(headerName)) { _currentHeaders[i].value=headerValue; @@ -270,7 +273,8 @@ bool ESP8266WebServer::_collectHeader(const char* headerName, const char* header return false; } -void ESP8266WebServer::_parseArguments(String data) { +template +void ESP8266WebServerTemplate::_parseArguments(String data) { #ifdef DEBUG_ESP_HTTP_SERVER DEBUG_OUTPUT.print("args: "); DEBUG_OUTPUT.println(data); @@ -345,7 +349,8 @@ void ESP8266WebServer::_parseArguments(String data) { } -void ESP8266WebServer::_uploadWriteByte(uint8_t b){ +template +void ESP8266WebServerTemplate::_uploadWriteByte(uint8_t b){ if (_currentUpload->currentSize == HTTP_UPLOAD_BUFLEN){ if(_currentHandler && _currentHandler->canUpload(_currentUri)) _currentHandler->upload(*this, _currentUri, *_currentUpload); @@ -355,7 +360,8 @@ void ESP8266WebServer::_uploadWriteByte(uint8_t b){ _currentUpload->buf[_currentUpload->currentSize++] = b; } -uint8_t ESP8266WebServer::_uploadReadByte(WiFiClient& client){ +template +uint8_t ESP8266WebServerTemplate::_uploadReadByte(ClientType& client){ int res = client.read(); if(res == -1){ while(!client.available() && client.connected()) @@ -365,7 +371,8 @@ uint8_t ESP8266WebServer::_uploadReadByte(WiFiClient& client){ return (uint8_t)res; } -bool ESP8266WebServer::_parseForm(WiFiClient& client, String boundary, uint32_t len){ +template +bool ESP8266WebServerTemplate::_parseForm(ClientType& client, String boundary, uint32_t len){ (void) len; #ifdef DEBUG_ESP_HTTP_SERVER DEBUG_OUTPUT.print("Parse Form: Boundary: "); @@ -394,7 +401,7 @@ bool ESP8266WebServer::_parseForm(WiFiClient& client, String boundary, uint32_t line = client.readStringUntil('\r'); client.readStringUntil('\n'); - if (line.length() > 19 && line.substring(0, 19).equalsIgnoreCase(F("Content-Disposition"))){ + if (line.length() > 19 && line.substring(0, 19).equalsIgnoreCase(("Content-Disposition"))){ int nameStart = line.indexOf('='); if (nameStart != -1){ argName = line.substring(nameStart+2); @@ -410,7 +417,7 @@ bool ESP8266WebServer::_parseForm(WiFiClient& client, String boundary, uint32_t DEBUG_OUTPUT.println(argFilename); #endif //use GET to set the filename if uploading using blob - if (argFilename == F("blob") && hasArg(FPSTR(filename))) + if (argFilename == ("blob") && hasArg(FPSTR(filename))) argFilename = arg(FPSTR(filename)); } #ifdef DEBUG_ESP_HTTP_SERVER @@ -577,7 +584,8 @@ bool ESP8266WebServer::_parseForm(WiFiClient& client, String boundary, uint32_t return false; } -String ESP8266WebServer::urlDecode(const String& text) +template +String ESP8266WebServerTemplate::urlDecode(const String& text) { String decoded = ""; char temp[] = "0x00"; @@ -608,7 +616,8 @@ String ESP8266WebServer::urlDecode(const String& text) return decoded; } -bool ESP8266WebServer::_parseFormUploadAborted(){ +template +bool ESP8266WebServerTemplate::_parseFormUploadAborted(){ _currentUpload->status = UPLOAD_FILE_ABORTED; if(_currentHandler && _currentHandler->canUpload(_currentUri)) _currentHandler->upload(*this, _currentUri, *_currentUpload); diff --git a/libraries/ESP8266WebServer/src/detail/RequestHandler.h b/libraries/ESP8266WebServer/src/detail/RequestHandler.h index fc5d0371d2..9b37667a8c 100644 --- a/libraries/ESP8266WebServer/src/detail/RequestHandler.h +++ b/libraries/ESP8266WebServer/src/detail/RequestHandler.h @@ -1,13 +1,14 @@ #ifndef REQUESTHANDLER_H #define REQUESTHANDLER_H +template class RequestHandler { public: virtual ~RequestHandler() { } virtual bool canHandle(HTTPMethod method, String uri) { (void) method; (void) uri; return false; } virtual bool canUpload(String uri) { (void) uri; return false; } - virtual bool handle(ESP8266WebServer& server, HTTPMethod requestMethod, String requestUri) { (void) server; (void) requestMethod; (void) requestUri; return false; } - virtual void upload(ESP8266WebServer& server, String requestUri, HTTPUpload& upload) { (void) server; (void) requestUri; (void) upload; } + virtual bool handle(ESP8266WebServerTemplate& server, HTTPMethod requestMethod, String requestUri) { (void) server; (void) requestMethod; (void) requestUri; return false; } + virtual void upload(ESP8266WebServerTemplate& server, String requestUri, HTTPUpload& upload) { (void) server; (void) requestUri; (void) upload; } RequestHandler* next() { return _next; } void next(RequestHandler* r) { _next = r; } diff --git a/libraries/ESP8266WebServer/src/detail/RequestHandlersImpl.h b/libraries/ESP8266WebServer/src/detail/RequestHandlersImpl.h index feada8c13b..0d7aa860d0 100644 --- a/libraries/ESP8266WebServer/src/detail/RequestHandlersImpl.h +++ b/libraries/ESP8266WebServer/src/detail/RequestHandlersImpl.h @@ -7,9 +7,10 @@ using namespace mime; -class FunctionRequestHandler : public RequestHandler { +template +class FunctionRequestHandler : public RequestHandler { public: - FunctionRequestHandler(ESP8266WebServer::THandlerFunction fn, ESP8266WebServer::THandlerFunction ufn, const String &uri, HTTPMethod method) + FunctionRequestHandler(typename ESP8266WebServerTemplate::THandlerFunction fn, typename ESP8266WebServerTemplate::THandlerFunction ufn, const String &uri, HTTPMethod method) : _fn(fn) , _ufn(ufn) , _uri(uri) @@ -34,7 +35,7 @@ class FunctionRequestHandler : public RequestHandler { return true; } - bool handle(ESP8266WebServer& server, HTTPMethod requestMethod, String requestUri) override { + bool handle(ESP8266WebServerTemplate& server, HTTPMethod requestMethod, String requestUri) override { (void) server; if (!canHandle(requestMethod, requestUri)) return false; @@ -43,7 +44,7 @@ class FunctionRequestHandler : public RequestHandler { return true; } - void upload(ESP8266WebServer& server, String requestUri, HTTPUpload& upload) override { + void upload(ESP8266WebServerTemplate& server, String requestUri, HTTPUpload& upload) override { (void) server; (void) upload; if (canUpload(requestUri)) @@ -51,13 +52,14 @@ class FunctionRequestHandler : public RequestHandler { } protected: - ESP8266WebServer::THandlerFunction _fn; - ESP8266WebServer::THandlerFunction _ufn; + typename ESP8266WebServerTemplate::THandlerFunction _fn; + typename ESP8266WebServerTemplate::THandlerFunction _ufn; String _uri; HTTPMethod _method; }; -class StaticRequestHandler : public RequestHandler { +template +class StaticRequestHandler : public RequestHandler { public: StaticRequestHandler(FS& fs, const char* path, const char* uri, const char* cache_header) : _fs(fs) @@ -80,7 +82,7 @@ class StaticRequestHandler : public RequestHandler { return true; } - bool handle(ESP8266WebServer& server, HTTPMethod requestMethod, String requestUri) override { + bool handle(ESP8266WebServerTemplate& server, HTTPMethod requestMethod, String requestUri) override { if (!canHandle(requestMethod, requestUri)) return false;