diff --git a/libraries/ESP8266WebServer/src/ESP8266WebServer.cpp b/libraries/ESP8266WebServer/src/ESP8266WebServer.cpp index 4eef8725a6..6950012217 100644 --- a/libraries/ESP8266WebServer/src/ESP8266WebServer.cpp +++ b/libraries/ESP8266WebServer/src/ESP8266WebServer.cpp @@ -36,13 +36,7 @@ #define DEBUG_OUTPUT Serial #endif -//const char * AUTHORIZATION_HEADER = "Authorization"; -static const char AUTHORIZATION_HEADER[] PROGMEM = "Authorization"; -static const char qop_auth[] PROGMEM = "qop=auth"; -static const char WWW_Authenticate[] PROGMEM = "WWW-Authenticate"; -static const char colon[] PROGMEM = ":"; -static const char Content_Length[] PROGMEM = "Content-Length"; - +const char * AUTHORIZATION_HEADER = "Authorization"; ESP8266WebServer::ESP8266WebServer(IPAddress addr, int port) : _server(addr, port) @@ -50,13 +44,13 @@ ESP8266WebServer::ESP8266WebServer(IPAddress addr, int port) , _currentVersion(0) , _currentStatus(HC_NONE) , _statusChange(0) -, _currentHandler(nullptr) -, _firstHandler(nullptr) -, _lastHandler(nullptr) +, _currentHandler(0) +, _firstHandler(0) +, _lastHandler(0) , _currentArgCount(0) -, _currentArgs(nullptr) +, _currentArgs(0) , _headerKeysCount(0) -, _currentHeaders(nullptr) +, _currentHeaders(0) , _contentLength(0) , _chunked(false) { @@ -68,13 +62,13 @@ ESP8266WebServer::ESP8266WebServer(int port) , _currentVersion(0) , _currentStatus(HC_NONE) , _statusChange(0) -, _currentHandler(nullptr) -, _firstHandler(nullptr) -, _lastHandler(nullptr) +, _currentHandler(0) +, _firstHandler(0) +, _lastHandler(0) , _currentArgCount(0) -, _currentArgs(nullptr) +, _currentArgs(0) , _headerKeysCount(0) -, _currentHeaders(nullptr) +, _currentHeaders(0) , _contentLength(0) , _chunked(false) { @@ -94,83 +88,79 @@ ESP8266WebServer::~ESP8266WebServer() { } void ESP8266WebServer::begin() { - close(); + _currentStatus = HC_NONE; _server.begin(); + if(!_headerKeysCount) + collectHeaders(0, 0); } -void ESP8266WebServer::begin(uint16_t port) { - close(); - _server.begin(port); -} - -String ESP8266WebServer::_extractParam(String& authReq,const String& param,const char delimit){ +String ESP8266WebServer::_exractParam(String& authReq,const String& param,const char delimit){ int _begin = authReq.indexOf(param); - if (_begin==-1) - return ""; + 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){ - if(hasHeader(FPSTR(AUTHORIZATION_HEADER))) { - String authReq = header(FPSTR(AUTHORIZATION_HEADER)); - if(authReq.startsWith(F("Basic"))){ + if(hasHeader(AUTHORIZATION_HEADER)){ + String authReq = header(AUTHORIZATION_HEADER); + if(authReq.startsWith("Basic")){ authReq = authReq.substring(6); authReq.trim(); char toencodeLen = strlen(username)+strlen(password)+1; char *toencode = new char[toencodeLen + 1]; if(toencode == NULL){ - authReq = ""; + authReq = String(); return false; } char *encoded = new char[base64_encode_expected_len(toencodeLen)+1]; if(encoded == NULL){ - authReq = ""; + authReq = String(); delete[] toencode; return false; } sprintf(toencode, "%s:%s", username, password); if(base64_encode_chars(toencode, toencodeLen, encoded) > 0 && authReq.equalsConstantTime(encoded)) { - authReq = ""; + authReq = String(); delete[] toencode; delete[] encoded; return true; } 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=\"")); - if(!_username.length() || _username != String(username)) { - authReq = ""; + String _username = _exractParam(authReq,"username=\""); + if((!_username.length())||_username!=String(username)){ + authReq = String(); 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=\"")); - - if((!_realm.length()) || (!_nonce.length()) || (!_uri.length()) || (!_response.length()) || (!_opaque.length())) { - authReq = ""; + String _realm = _exractParam(authReq,"realm=\""); + String _nonce = _exractParam(authReq,"nonce=\""); + String _uri = _exractParam(authReq,"uri=\""); + String _response = _exractParam(authReq,"response=\""); + String _opaque = _exractParam(authReq,"opaque=\""); + + if((!_realm.length())||(!_nonce.length())||(!_uri.length())||(!_response.length())||(!_opaque.length())){ + authReq = String(); return false; } - if((_opaque != _sopaque) || (_nonce != _snonce) || (_realm != _srealm)) { - authReq = ""; + if((_opaque!=_sopaque)||(_nonce!=_snonce)||(_realm!=_srealm)){ + authReq = String(); return false; } // 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=\"")); + if(authReq.indexOf("qop=auth") != -1){ + _nc = _exractParam(authReq,"nc=",','); + _cnonce = _exractParam(authReq,"cnonce=\""); } MD5Builder md5; md5.begin(); - md5.add(String(username) + ':' + _realm + ':' + String(password)); // md5 of the user:realm:user + md5.add(String(username)+":"+_realm+":"+String(password)); // md5 of the user:realm:user md5.calculate(); String _H1 = md5.toString(); #ifdef DEBUG_ESP_HTTP_SERVER @@ -178,15 +168,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("GET:"+_uri); }else if(_currentMethod == HTTP_POST){ - md5.add(String(F("POST:")) + _uri); + md5.add("POST:"+_uri); }else if(_currentMethod == HTTP_PUT){ - md5.add(String(F("PUT:")) + _uri); + md5.add("PUT:"+_uri); }else if(_currentMethod == HTTP_DELETE){ - md5.add(String(F("DELETE:")) + _uri); + md5.add("DELETE:"+_uri); }else{ - md5.add(String(F("GET:")) + _uri); + md5.add("GET:"+_uri); } md5.calculate(); String _H2 = md5.toString(); @@ -194,50 +184,49 @@ bool ESP8266WebServer::authenticate(const char * username, const char * password DEBUG_OUTPUT.println("Hash of GET:uri=" + _H2); #endif md5.begin(); - if(authReq.indexOf(FPSTR(qop_auth)) != -1) { - md5.add(_H1 + FPSTR(colon) + _nonce + FPSTR(colon) + _nc + FPSTR(colon) + _cnonce + ':auth:' + _H2); + if(authReq.indexOf("qop=auth") != -1){ + md5.add(_H1+":"+_nonce+":"+_nc+":"+_cnonce+":auth:"+_H2); }else{ - md5.add(_H1 + FPSTR(colon) + _nonce + FPSTR(colon) + _H2); + md5.add(_H1+":"+_nonce+":"+_H2); } md5.calculate(); String _responsecheck = md5.toString(); #ifdef DEBUG_ESP_HTTP_SERVER DEBUG_OUTPUT.println("The Proper response=" +_responsecheck); #endif - if(_response == _responsecheck){ - authReq = ""; + if(_response==_responsecheck){ + authReq = String(); return true; } } - authReq = ""; + authReq = String(); } return false; } -String ESP8266WebServer::_getRandomHexString() { +String ESP8266WebServer::_getRandomHexString(){ char buffer[33]; // buffer to hold 32 Hex Digit + /0 int i; - for(i = 0; i < 4; i++) { - sprintf (buffer + (i*8), "%08x", RANDOM_REG32); + for(i=0;i<4;i++){ + sprintf (buffer+(i*8), "%08x", RANDOM_REG32); } return String(buffer); } -void ESP8266WebServer::requestAuthentication(HTTPAuthMethod mode, const char* realm, const String& authFailMsg) { - if(realm == NULL) { - _srealm = String(F("Login Required")); - } else { +void ESP8266WebServer::requestAuthentication(HTTPAuthMethod mode, const char* realm, const String& authFailMsg){ + if(realm==NULL){ + _srealm = "Login Required"; + }else{ _srealm = String(realm); } - if(mode == BASIC_AUTH) { - sendHeader(String(FPSTR(WWW_Authenticate)), String(F("Basic realm=\"")) + _srealm + String(F("\""))); - } else { + if(mode==BASIC_AUTH){ + sendHeader("WWW-Authenticate", "Basic realm=\"" + _srealm + "\""); + }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("WWW-Authenticate", "Digest realm=\"" +_srealm + "\", qop=\"auth\", nonce=\""+_snonce+"\", opaque=\""+_sopaque+"\""); } - using namespace mime; - send(401, mimeTable[html].mimeType, authFailMsg); + send(401,"text/html",authFailMsg); } void ESP8266WebServer::on(const String &uri, ESP8266WebServer::THandlerFunction handler) { @@ -338,9 +327,6 @@ void ESP8266WebServer::handleClient() { void ESP8266WebServer::close() { _server.close(); - _currentStatus = HC_NONE; - if(!_headerKeysCount) - collectHeaders(0, 0); } void ESP8266WebServer::stop() { @@ -349,7 +335,7 @@ void ESP8266WebServer::stop() { void ESP8266WebServer::sendHeader(const String& name, const String& value, bool first) { String headerLine = name; - headerLine += F(": "); + headerLine += ": "; headerLine += value; headerLine += "\r\n"; @@ -361,37 +347,36 @@ void ESP8266WebServer::sendHeader(const String& name, const String& value, bool } } -void ESP8266WebServer::setContentLength(const size_t contentLength) { +void ESP8266WebServer::setContentLength(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) + ' '; + response = "HTTP/1."+String(_currentVersion)+" "; response += String(code); - response += ' '; + response += " "; response += _responseCodeToString(code); response += "\r\n"; - using namespace mime; if (!content_type) - content_type = mimeTable[html].mimeType; + content_type = "text/html"; - sendHeader(String(F("Content-Type")), content_type, true); + sendHeader("Content-Type", content_type, true); if (_contentLength == CONTENT_LENGTH_NOT_SET) { - sendHeader(String(FPSTR(Content_Length)), String(contentLength)); + sendHeader("Content-Length", String(contentLength)); } else if (_contentLength != CONTENT_LENGTH_UNKNOWN) { - sendHeader(String(FPSTR(Content_Length)), String(_contentLength)); + sendHeader("Content-Length", String(_contentLength)); } 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("Accept-Ranges","none"); + sendHeader("Transfer-Encoding","chunked"); } - sendHeader(String(F("Connection")), String(F("close"))); + sendHeader("Connection", "close"); response += _responseHeaders; response += "\r\n"; - _responseHeaders = ""; + _responseHeaders = String(); } void ESP8266WebServer::send(int code, const char* content_type, const String& content) { @@ -481,37 +466,24 @@ void ESP8266WebServer::sendContent_P(PGM_P content, size_t size) { } -void ESP8266WebServer::_streamFileCore(const size_t fileSize, const String & fileName, const String & contentType) -{ - using namespace mime; - setContentLength(fileSize); - if (fileName.endsWith(mimeTable[gz].endsWith) && - contentType != mimeTable[gz].mimeType && - contentType != mimeTable[none].mimeType) { - sendHeader(F("Content-Encoding"), F("gzip")); - } - send(200, contentType, ""); -} - - String ESP8266WebServer::arg(String name) { for (int i = 0; i < _currentArgCount; ++i) { if ( _currentArgs[i].key == name ) return _currentArgs[i].value; } - return ""; + return String(); } String ESP8266WebServer::arg(int i) { if (i < _currentArgCount) return _currentArgs[i].value; - return ""; + return String(); } String ESP8266WebServer::argName(int i) { if (i < _currentArgCount) return _currentArgs[i].key; - return ""; + return String(); } int ESP8266WebServer::args() { @@ -532,7 +504,7 @@ String ESP8266WebServer::header(String name) { if (_currentHeaders[i].key.equalsIgnoreCase(name)) return _currentHeaders[i].value; } - return ""; + return String(); } void ESP8266WebServer::collectHeaders(const char* headerKeys[], const size_t headerKeysCount) { @@ -540,7 +512,7 @@ void ESP8266WebServer::collectHeaders(const char* headerKeys[], const size_t hea if (_currentHeaders) delete[]_currentHeaders; _currentHeaders = new RequestArgument[_headerKeysCount]; - _currentHeaders[0].key = FPSTR(AUTHORIZATION_HEADER); + _currentHeaders[0].key = AUTHORIZATION_HEADER; for (int i = 1; i < _headerKeysCount; i++){ _currentHeaders[i].key = headerKeys[i-1]; } @@ -549,13 +521,13 @@ void ESP8266WebServer::collectHeaders(const char* headerKeys[], const size_t hea String ESP8266WebServer::header(int i) { if (i < _headerKeysCount) return _currentHeaders[i].value; - return ""; + return String(); } String ESP8266WebServer::headerName(int i) { if (i < _headerKeysCount) return _currentHeaders[i].key; - return ""; + return String(); } int ESP8266WebServer::headers() { @@ -602,14 +574,13 @@ void ESP8266WebServer::_handleRequest() { handled = true; } if (!handled) { - using namespace mime; - send(404, mimeTable[html].mimeType, String(F("Not found: ")) + _currentUri); + send(404, "text/plain", String("Not found: ") + _currentUri); handled = true; } if (handled) { _finalizeResponse(); } - _currentUri = ""; + _currentUri = String(); } @@ -661,6 +632,6 @@ String ESP8266WebServer::_responseCodeToString(int code) { case 503: return F("Service Unavailable"); case 504: return F("Gateway Time-out"); case 505: return F("HTTP Version not supported"); - default: return F(""); + default: return ""; } } diff --git a/libraries/ESP8266WebServer/src/ESP8266WebServer.h b/libraries/ESP8266WebServer/src/ESP8266WebServer.h index 0bfa302a4c..6de40e07b7 100644 --- a/libraries/ESP8266WebServer/src/ESP8266WebServer.h +++ b/libraries/ESP8266WebServer/src/ESP8266WebServer.h @@ -74,7 +74,6 @@ class ESP8266WebServer virtual ~ESP8266WebServer(); virtual void begin(); - virtual void begin(uint16_t port); virtual void handleClient(); virtual void close(); @@ -121,7 +120,7 @@ class ESP8266WebServer void send_P(int code, PGM_P content_type, PGM_P content); void send_P(int code, PGM_P content_type, PGM_P content, size_t contentLength); - void setContentLength(const size_t contentLength); + void setContentLength(size_t contentLength); void sendHeader(const String& name, const String& value, bool first = false); void sendContent(const String& content); void sendContent_P(PGM_P content); @@ -129,12 +128,17 @@ class ESP8266WebServer static String urlDecode(const String& text); - template - size_t streamFile(T &file, const String& contentType) { - _streamFileCore(file.size(), file.name(), contentType); - return _currentClient.write(file); +template size_t streamFile(T &file, const String& contentType){ + setContentLength(file.size()); + if (String(file.name()).endsWith(".gz") && + contentType != "application/x-gzip" && + contentType != "application/octet-stream"){ + sendHeader("Content-Encoding", "gzip"); } - + send(200, contentType, ""); + return _currentClient.write(file); +} + 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 ); } @@ -150,12 +154,10 @@ class ESP8266WebServer uint8_t _uploadReadByte(WiFiClient& client); void _prepareHeader(String& response, int code, const char* content_type, size_t contentLength); bool _collectHeader(const char* headerName, const char* headerValue); - - void _streamFileCore(const size_t fileSize, const String & fileName, const String & contentType); - + String _getRandomHexString(); // for extracting Auth parameters - String _extractParam(String& authReq,const String& param,const char delimit = '"'); + String _exractParam(String& authReq,const String& param,const char delimit = '"'); struct RequestArgument { String key; diff --git a/libraries/ESP8266WebServer/src/detail/RequestHandlersImpl.h b/libraries/ESP8266WebServer/src/detail/RequestHandlersImpl.h index b1de4a6005..692052359d 100644 --- a/libraries/ESP8266WebServer/src/detail/RequestHandlersImpl.h +++ b/libraries/ESP8266WebServer/src/detail/RequestHandlersImpl.h @@ -2,9 +2,32 @@ #define REQUESTHANDLERSIMPL_H #include "RequestHandler.h" -#include "mimetable.h" -using namespace mime; +// Table of extension->MIME strings stored in PROGMEM, needs to be global due to GCC section typing rules +static const struct {const char endsWith[16]; const char mimeType[32];} mimeTable[] ICACHE_RODATA_ATTR = { + { ".html", "text/html" }, + { ".htm", "text/html" }, + { ".css", "text/css" }, + { ".txt", "text/plain" }, + { ".js", "application/javascript" }, + { ".json", "application/json" }, + { ".png", "image/png" }, + { ".gif", "image/gif" }, + { ".jpg", "image/jpeg" }, + { ".ico", "image/x-icon" }, + { ".svg", "image/svg+xml" }, + { ".ttf", "application/x-font-ttf" }, + { ".otf", "application/x-font-opentype" }, + { ".woff", "application/font-woff" }, + { ".woff2", "application/font-woff2" }, + { ".eot", "application/vnd.ms-fontobject" }, + { ".sfnt", "application/font-sfnt" }, + { ".xml", "text/xml" }, + { ".pdf", "application/pdf" }, + { ".zip", "application/zip" }, + { ".gz", "application/x-gzip" }, + { ".appcache", "text/cache-manifest" }, + { "", "application/octet-stream" } }; class FunctionRequestHandler : public RequestHandler { public: @@ -101,10 +124,10 @@ class StaticRequestHandler : public RequestHandler { // 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(mimeTable[gz].endsWith) && !_fs.exists(path)) { - String pathWithGz = path + mimeTable[gz].endsWith; + if (!path.endsWith(".gz") && !_fs.exists(path)) { + String pathWithGz = path + ".gz"; if(_fs.exists(pathWithGz)) - path += mimeTable[gz].endsWith; + path += ".gz"; } File f = _fs.open(path, "r"); diff --git a/libraries/ESP8266WebServer/src/detail/mimetable.cpp b/libraries/ESP8266WebServer/src/detail/mimetable.cpp deleted file mode 100644 index 51a1f60bc7..0000000000 --- a/libraries/ESP8266WebServer/src/detail/mimetable.cpp +++ /dev/null @@ -1,35 +0,0 @@ -#include "mimetable.h" -#include "pgmspace.h" - -namespace mime -{ - -// Table of extension->MIME strings stored in PROGMEM, needs to be global due to GCC section typing rules -const Entry mimeTable[maxType] ICACHE_RODATA_ATTR = -{ - { ".html", "text/html" }, - { ".htm", "text/html" }, - { ".css", "text/css" }, - { ".txt", "text/plain" }, - { ".js", "application/javascript" }, - { ".json", "application/json" }, - { ".png", "image/png" }, - { ".gif", "image/gif" }, - { ".jpg", "image/jpeg" }, - { ".ico", "image/x-icon" }, - { ".svg", "image/svg+xml" }, - { ".ttf", "application/x-font-ttf" }, - { ".otf", "application/x-font-opentype" }, - { ".woff", "application/font-woff" }, - { ".woff2", "application/font-woff2" }, - { ".eot", "application/vnd.ms-fontobject" }, - { ".sfnt", "application/font-sfnt" }, - { ".xml", "text/xml" }, - { ".pdf", "application/pdf" }, - { ".zip", "application/zip" }, - { ".gz", "application/x-gzip" }, - { ".appcache", "text/cache-manifest" }, - { "", "application/octet-stream" } -}; - -} diff --git a/libraries/ESP8266WebServer/src/detail/mimetable.h b/libraries/ESP8266WebServer/src/detail/mimetable.h deleted file mode 100644 index 191356c489..0000000000 --- a/libraries/ESP8266WebServer/src/detail/mimetable.h +++ /dev/null @@ -1,47 +0,0 @@ -#ifndef __MIMETABLE_H__ -#define __MIMETABLE_H__ - - -namespace mime -{ - -enum type -{ - html, - htm, - css, - txt, - js, - json, - png, - gif, - jpg, - ico, - svg, - ttf, - otf, - woff, - woff2, - eot, - sfnt, - xml, - pdf, - zip, - gz, - appcache, - none, - maxType -}; - -struct Entry -{ - const char endsWith[16]; - const char mimeType[32]; -}; - - -extern const Entry mimeTable[maxType]; -} - - -#endif diff --git a/tools/sdk/lwip2/builder b/tools/sdk/lwip2/builder index bdd68addcf..1b8826735c 160000 --- a/tools/sdk/lwip2/builder +++ b/tools/sdk/lwip2/builder @@ -1 +1 @@ -Subproject commit bdd68addcfed8f2e3b484b465369dac0407d3f5e +Subproject commit 1b8826735cffa57d71ff6ce1fd79ec9d44a5215f