diff --git a/src/AsyncWebSocket.cpp b/src/AsyncWebSocket.cpp index 926d6a4..b59c392 100644 --- a/src/AsyncWebSocket.cpp +++ b/src/AsyncWebSocket.cpp @@ -1145,7 +1145,6 @@ size_t AsyncWebSocket::printf_P(uint32_t id, PGM_P formatP, ...){ } return 0; } -#endif size_t AsyncWebSocket::printfAll_P(PGM_P formatP, ...) { @@ -1168,6 +1167,7 @@ size_t AsyncWebSocket::printfAll_P(PGM_P formatP, ...) textAll(buffer); return len; } +#endif const char __WS_STR_CONNECTION[] PROGMEM = { "Connection" }; const char __WS_STR_UPGRADE[] PROGMEM = { "Upgrade" }; @@ -1225,7 +1225,7 @@ void AsyncWebSocket::handleRequest(AsyncWebServerRequest *request) return; } } - AsyncWebHeader* version = request->getHeader(WS_STR_VERSION); + const AsyncWebHeader* version = request->getHeader(WS_STR_VERSION); if (version->value().toInt() != 13) { AsyncWebServerResponse *response = request->beginResponse(400); @@ -1233,11 +1233,11 @@ void AsyncWebSocket::handleRequest(AsyncWebServerRequest *request) request->send(response); return; } - AsyncWebHeader* key = request->getHeader(WS_STR_KEY); + const AsyncWebHeader* key = request->getHeader(WS_STR_KEY); AsyncWebServerResponse *response = new AsyncWebSocketResponse(key->value(), this); if (request->hasHeader(WS_STR_PROTOCOL)) { - AsyncWebHeader* protocol = request->getHeader(WS_STR_PROTOCOL); + const AsyncWebHeader* protocol = request->getHeader(WS_STR_PROTOCOL); //ToDo: check protocol response->addHeader(WS_STR_PROTOCOL, protocol->value()); } diff --git a/src/AsyncWebSocket.h b/src/AsyncWebSocket.h index a40fc85..8b7eca9 100644 --- a/src/AsyncWebSocket.h +++ b/src/AsyncWebSocket.h @@ -327,10 +327,11 @@ class AsyncWebSocket: public AsyncWebHandler { size_t printf(uint32_t id, const char *format, ...) __attribute__ ((format (printf, 3, 4))); size_t printfAll(const char *format, ...) __attribute__ ((format (printf, 2, 3))); + #ifndef ESP32 size_t printf_P(uint32_t id, PGM_P formatP, ...) __attribute__ ((format (printf, 3, 4))); -#endif size_t printfAll_P(PGM_P formatP, ...) __attribute__ ((format (printf, 2, 3))); +#endif //event listener void onEvent(AwsEventHandler handler){ diff --git a/src/ESPAsyncWebServer.h b/src/ESPAsyncWebServer.h index 2b11be5..4508521 100644 --- a/src/ESPAsyncWebServer.h +++ b/src/ESPAsyncWebServer.h @@ -129,7 +129,7 @@ class AsyncWebHeader { AsyncWebHeader(const AsyncWebHeader &) = default; AsyncWebHeader(const String& name, const String& value): _name(name), _value(value){} - AsyncWebHeader(const String& data): _name(), _value(){ + AsyncWebHeader(const String& data){ if(!data) return; int index = data.indexOf(':'); if (index < 0) return; @@ -237,8 +237,15 @@ class AsyncWebServerRequest { const String& contentType() const { return _contentType; } size_t contentLength() const { return _contentLength; } bool multipart() const { return _isMultipart; } + +#ifndef ESP8266 + const char* methodToString() const; + const char* requestedConnTypeToString() const; +#else const __FlashStringHelper *methodToString() const; const __FlashStringHelper *requestedConnTypeToString() const; +#endif + RequestedConnectionType requestedConnType() const { return _reqconntype; } bool isExpectedRequestedConnType(RequestedConnectionType erct1, RequestedConnectionType erct2 = RCT_NOT_USED, RequestedConnectionType erct3 = RCT_NOT_USED); void onDisconnect (ArDisconnectHandler fn); @@ -251,9 +258,22 @@ class AsyncWebServerRequest { void requestAuthentication(const char * realm = NULL, bool isDigest = true); void setHandler(AsyncWebHandler *handler){ _handler = handler; } - void addInterestingHeader(const String& name); - void redirect(const String& url); + /** + * @brief add header to collect from a response + * + * @param name + */ + void addInterestingHeader(const char* name); + void addInterestingHeader(const String& name){ return addInterestingHeader(name.c_str()); }; + + /** + * @brief issue 302 redirect responce + * + * @param url + */ + void redirect(const char* url); + void redirect(const String& url){ return redirect(url.c_str()); }; void send(AsyncWebServerResponse *response); void send(int code, const String& contentType=String(), const String& content=String()); @@ -262,8 +282,10 @@ class AsyncWebServerRequest { void send(Stream &stream, const String& contentType, size_t len, AwsTemplateProcessor callback=nullptr); void send(const String& contentType, size_t len, AwsResponseFiller callback, AwsTemplateProcessor templateCallback=nullptr); void sendChunked(const String& contentType, AwsResponseFiller callback, AwsTemplateProcessor templateCallback=nullptr); +#ifdef ESP8266 void send_P(int code, const String& contentType, const uint8_t * content, size_t len, AwsTemplateProcessor callback=nullptr); void send_P(int code, const String& contentType, PGM_P content, AwsTemplateProcessor callback=nullptr); +#endif AsyncWebServerResponse *beginResponse(int code, const String& contentType=String(), const String& content=String()); AsyncWebServerResponse *beginResponse(FS &fs, const String& path, const String& contentType=String(), bool download=false, AwsTemplateProcessor callback=nullptr); @@ -272,44 +294,83 @@ class AsyncWebServerRequest { AsyncWebServerResponse *beginResponse(const String& contentType, size_t len, AwsResponseFiller callback, AwsTemplateProcessor templateCallback=nullptr); AsyncWebServerResponse *beginChunkedResponse(const String& contentType, AwsResponseFiller callback, AwsTemplateProcessor templateCallback=nullptr); AsyncResponseStream *beginResponseStream(const String& contentType, size_t bufferSize=1460); +#ifdef ESP8266 AsyncWebServerResponse *beginResponse_P(int code, const String& contentType, const uint8_t * content, size_t len, AwsTemplateProcessor callback=nullptr); AsyncWebServerResponse *beginResponse_P(int code, const String& contentType, PGM_P content, AwsTemplateProcessor callback=nullptr); +#endif size_t headers() const; // get header count - bool hasHeader(const String& name) const; // check if header exists - bool hasHeader(const __FlashStringHelper * data) const; // check if header exists - AsyncWebHeader* getHeader(const String& name); - const AsyncWebHeader* getHeader(const String& name) const; - AsyncWebHeader* getHeader(const __FlashStringHelper * data); + // check if header exists + bool hasHeader(const char* name) const; + bool hasHeader(const String& name) const { return hasHeader(name.c_str()); }; +#ifdef ESP8266 + bool hasHeader(const __FlashStringHelper * data) const; // check if header exists +#endif + + const AsyncWebHeader* getHeader(const char* name) const; + const AsyncWebHeader* getHeader(const String& name) const { return getHeader(name.c_str()); }; +#ifdef ESP8266 const AsyncWebHeader* getHeader(const __FlashStringHelper * data) const; - AsyncWebHeader* getHeader(size_t num); +#endif const AsyncWebHeader* getHeader(size_t num) const; size_t params() const; // get arguments count bool hasParam(const String& name, bool post=false, bool file=false) const; bool hasParam(const __FlashStringHelper * data, bool post=false, bool file=false) const; - const AsyncWebParameter* getParam(const String& name, bool post=false, bool file=false) const; + /** + * @brief Get the Request parameter by name + * + * @param name + * @param post + * @param file + * @return const AsyncWebParameter* + */ + const AsyncWebParameter* getParam(const char* name, bool post=false, bool file=false) const; + + const AsyncWebParameter* getParam(const String& name, bool post=false, bool file=false) const { return getParam(name.c_str()); }; #ifdef ESP8266 const AsyncWebParameter* getParam(const __FlashStringHelper * data, bool post, bool file) const; #endif + + /** + * @brief Get request parameter by number + * i.e., n-th parameter + * @param num + * @return const AsyncWebParameter* + */ const AsyncWebParameter* getParam(size_t num) const; size_t args() const { return params(); } // get arguments count - const String& arg(const String& name) const; // get request argument value by name + + // get request argument value by name + const String& arg(const char* name) const; + // get request argument value by name + const String& arg(const String& name) const { return arg(name.c_str()); }; +#ifdef ESP8266 const String& arg(const __FlashStringHelper * data) const; // get request argument value by F(name) +#endif const String& arg(size_t i) const; // get request argument value by number const String& argName(size_t i) const; // get request argument name by number bool hasArg(const char* name) const; // check if argument exists +#ifdef ESP8266 bool hasArg(const __FlashStringHelper * data) const; // check if F(argument) exists +#endif const String& ASYNCWEBSERVER_REGEX_ATTRIBUTE pathArg(size_t i) const; - const String& header(const char* name) const;// get request header value by name + // get request header value by name + const String& header(const char* name) const; + const String& header(const String& name) const { return header(name.c_str()); }; + +#ifdef ESP8266 const String& header(const __FlashStringHelper * data) const;// get request header value by F(name) +#endif + const String& header(size_t i) const; // get request header value by number const String& headerName(size_t i) const; // get request header name by number + String urlDecode(const String& text) const; }; @@ -362,8 +423,8 @@ class AsyncWebHandler { public: AsyncWebHandler(){} AsyncWebHandler& setFilter(ArRequestFilterFunction fn) { _filter = fn; return *this; } - AsyncWebHandler& setAuthentication(const char *username, const char *password){ _username = String(username);_password = String(password); return *this; }; - AsyncWebHandler& setAuthentication(const String& username, const String& password){ _username = username;_password = password; return *this; }; + AsyncWebHandler& setAuthentication(const char *username, const char *password){ _username = username; _password = password; return *this; }; + AsyncWebHandler& setAuthentication(const String& username, const String& password){ _username = username; _password = password; return *this; }; bool filter(AsyncWebServerRequest *request){ return _filter == NULL || _filter(request); } virtual ~AsyncWebHandler(){} virtual bool canHandle(AsyncWebServerRequest *request __attribute__((unused))){ diff --git a/src/WebAuthentication.cpp b/src/WebAuthentication.cpp index 8396795..78c8e43 100644 --- a/src/WebAuthentication.cpp +++ b/src/WebAuthentication.cpp @@ -147,31 +147,36 @@ String requestDigestAuthentication(const char * realm){ return header; } -bool checkDigestAuthentication(const char * header, const __FlashStringHelper *method, const char * username, const char * password, const char * realm, bool passwordIsHash, const char * nonce, const char * opaque, const char * uri){ +#ifndef ESP8266 +bool checkDigestAuthentication(const char * header, const char* method, const char * username, const char * password, const char * realm, bool passwordIsHash, const char * nonce, const char * opaque, const char * uri) +#else +bool checkDigestAuthentication(const char * header, const __FlashStringHelper *method, const char * username, const char * password, const char * realm, bool passwordIsHash, const char * nonce, const char * opaque, const char * uri) +#endif +{ if(username == NULL || password == NULL || header == NULL || method == NULL){ //os_printf("AUTH FAIL: missing requred fields\n"); return false; } - String myHeader = String(header); + String myHeader(header); int nextBreak = myHeader.indexOf(','); if(nextBreak < 0){ //os_printf("AUTH FAIL: no variables\n"); return false; } - String myUsername = String(); - String myRealm = String(); - String myNonce = String(); - String myUri = String(); - String myResponse = String(); - String myQop = String(); - String myNc = String(); - String myCnonce = String(); + String myUsername; + String myRealm; + String myNonce; + String myUri; + String myResponse; + String myQop; + String myNc; + String myCnonce; myHeader += F(", "); do { - String avLine = myHeader.substring(0, nextBreak); + String avLine(myHeader.substring(0, nextBreak)); avLine.trim(); myHeader = myHeader.substring(nextBreak+1); nextBreak = myHeader.indexOf(','); @@ -181,7 +186,7 @@ bool checkDigestAuthentication(const char * header, const __FlashStringHelper *m //os_printf("AUTH FAIL: no = sign\n"); return false; } - String varName = avLine.substring(0, eqSign); + String varName(avLine.substring(0, eqSign)); avLine = avLine.substring(eqSign + 1); if(avLine.startsWith(String('"'))){ avLine = avLine.substring(1, avLine.length() - 1); @@ -227,7 +232,7 @@ bool checkDigestAuthentication(const char * header, const __FlashStringHelper *m } } while(nextBreak > 0); - String ha1 = (passwordIsHash) ? String(password) : stringMD5(myUsername + ':' + myRealm + ':' + String(password)); + String ha1 = (passwordIsHash) ? String(password) : stringMD5(myUsername + ':' + myRealm + ':' + password); String ha2 = String(method) + ':' + myUri; String response = ha1 + ':' + myNonce + ':' + myNc + ':' + myCnonce + ':' + myQop + ':' + stringMD5(ha2); diff --git a/src/WebAuthentication.h b/src/WebAuthentication.h index a6f1966..8bc5f05 100644 --- a/src/WebAuthentication.h +++ b/src/WebAuthentication.h @@ -26,7 +26,12 @@ bool checkBasicAuthentication(const char * header, const char * username, const char * password); String requestDigestAuthentication(const char * realm); + +bool checkDigestAuthentication(const char * header, const char* method, const char * username, const char * password, const char * realm, bool passwordIsHash, const char * nonce, const char * opaque, const char * uri); + +#ifdef ESP8266 bool checkDigestAuthentication(const char * header, const __FlashStringHelper *method, const char * username, const char * password, const char * realm, bool passwordIsHash, const char * nonce, const char * opaque, const char * uri); +#endif //for storing hashed versions on the device that can be authenticated against String generateDigestHash(const char * username, const char * password, const char * realm); diff --git a/src/WebRequest.cpp b/src/WebRequest.cpp index 39d0f95..bb5d142 100644 --- a/src/WebRequest.cpp +++ b/src/WebRequest.cpp @@ -605,7 +605,7 @@ size_t AsyncWebServerRequest::headers() const{ return _headers.size(); } -bool AsyncWebServerRequest::hasHeader(const String& name) const { +bool AsyncWebServerRequest::hasHeader(const char* name) const { for(const auto& h: _headers){ if(h.name().equalsIgnoreCase(name)){ return true; @@ -614,44 +614,20 @@ bool AsyncWebServerRequest::hasHeader(const String& name) const { return false; } +#ifdef ESP8266 bool AsyncWebServerRequest::hasHeader(const __FlashStringHelper * data) const { return hasHeader(String(data)); } +#endif -AsyncWebHeader* AsyncWebServerRequest::getHeader(const String& name) { +const AsyncWebHeader* AsyncWebServerRequest::getHeader(const char* name) const { auto iter = std::find_if(std::begin(_headers), std::end(_headers), [&name](const AsyncWebHeader &header){ return header.name().equalsIgnoreCase(name); }); - if (iter == std::end(_headers)) - return nullptr; - - return &(*iter); -} - -const AsyncWebHeader* AsyncWebServerRequest::getHeader(const String& name) const { - auto iter = std::find_if(std::begin(_headers), std::end(_headers), - [&name](const AsyncWebHeader &header){ return header.name().equalsIgnoreCase(name); }); - - if (iter == std::end(_headers)) - return nullptr; - - return &(*iter); -} - -AsyncWebHeader* AsyncWebServerRequest::getHeader(const __FlashStringHelper * data) { - PGM_P p = reinterpret_cast(data); - size_t n = strlen_P(p); - char * name = (char*) malloc(n+1); - if (name) { - strcpy_P(name, p); - AsyncWebHeader* result = getHeader( String(name)); - free(name); - return result; - } else { - return nullptr; - } + return (iter == std::end(_headers)) ? nullptr : &(*iter); } +#ifdef ESP8266 const AsyncWebHeader* AsyncWebServerRequest::getHeader(const __FlashStringHelper * data) const { PGM_P p = reinterpret_cast(data); size_t n = strlen_P(p); @@ -665,17 +641,12 @@ const AsyncWebHeader* AsyncWebServerRequest::getHeader(const __FlashStringHelper return nullptr; } } - -AsyncWebHeader* AsyncWebServerRequest::getHeader(size_t num) { - if (num >= _headers.size()) - return nullptr; - return &(*std::next(std::begin(_headers), num)); -} +#endif const AsyncWebHeader* AsyncWebServerRequest::getHeader(size_t num) const { if (num >= _headers.size()) return nullptr; - return &(*std::next(std::begin(_headers), num)); + return &(*std::next(_headers.cbegin(), num)); } size_t AsyncWebServerRequest::params() const { @@ -695,7 +666,7 @@ bool AsyncWebServerRequest::hasParam(const __FlashStringHelper * data, bool post return hasParam(String(data).c_str(), post, file); } -const AsyncWebParameter* AsyncWebServerRequest::getParam(const String& name, bool post, bool file) const { +const AsyncWebParameter* AsyncWebServerRequest::getParam(const char* name, bool post, bool file) const { for(const auto &p: _params){ if(p.name() == name && p.isPost() == post && p.isFile() == file){ return &p; @@ -711,34 +682,15 @@ const AsyncWebParameter* AsyncWebServerRequest::getParam(const __FlashStringHelp #endif const AsyncWebParameter* AsyncWebServerRequest::getParam(size_t num) const { - if (num >= _params.size()) return nullptr; - auto iter = _params.cbegin(); - std::advance(iter, num); - return &(*iter); + if (num >= _params.size()) + return nullptr; + return &(*std::next(_params.cbegin(), num)); } -void AsyncWebServerRequest::addInterestingHeader(const String& name){ +void AsyncWebServerRequest::addInterestingHeader(const char* name){ if(std::none_of(std::begin(_interestingHeaders), std::end(_interestingHeaders), [&name](const String &str){ return str.equalsIgnoreCase(name); })) - _interestingHeaders.push_back(name); -} - -void AsyncWebServerRequest::send(AsyncWebServerResponse *response){ - _response = response; - if(_response == NULL){ - _client->close(true); - _onDisconnect(); - return; - } - if(!_response->_sourceValid()){ - delete response; - _response = NULL; - send(500); - } - else { - _client->setRxTimeout(0); - _response->_respond(this); - } + _interestingHeaders.emplace_back(name); } AsyncWebServerResponse * AsyncWebServerRequest::beginResponse(int code, const String& contentType, const String& content){ @@ -775,6 +727,7 @@ AsyncResponseStream * AsyncWebServerRequest::beginResponseStream(const String& c return new AsyncResponseStream(contentType, bufferSize); } +#ifdef ESP8266 AsyncWebServerResponse * AsyncWebServerRequest::beginResponse_P(int code, const String& contentType, const uint8_t * content, size_t len, AwsTemplateProcessor callback){ return new AsyncProgmemResponse(code, contentType, content, len, callback); } @@ -782,6 +735,25 @@ AsyncWebServerResponse * AsyncWebServerRequest::beginResponse_P(int code, const AsyncWebServerResponse * AsyncWebServerRequest::beginResponse_P(int code, const String& contentType, PGM_P content, AwsTemplateProcessor callback){ return beginResponse_P(code, contentType, (const uint8_t *)content, strlen_P(content), callback); } +#endif + +void AsyncWebServerRequest::send(AsyncWebServerResponse *response){ + _response = response; + if(_response == NULL){ + _client->close(true); + _onDisconnect(); + return; + } + if(!_response->_sourceValid()){ + delete response; + _response = NULL; + send(500); + } + else { + _client->setRxTimeout(0); + _response->_respond(this); + } +} void AsyncWebServerRequest::send(int code, const String& contentType, const String& content){ send(beginResponse(code, contentType, content)); @@ -811,6 +783,7 @@ void AsyncWebServerRequest::sendChunked(const String& contentType, AwsResponseFi send(beginChunkedResponse(contentType, callback, templateCallback)); } +#ifdef ESP8266 void AsyncWebServerRequest::send_P(int code, const String& contentType, const uint8_t * content, size_t len, AwsTemplateProcessor callback){ send(beginResponse_P(code, contentType, content, len, callback)); } @@ -818,8 +791,9 @@ void AsyncWebServerRequest::send_P(int code, const String& contentType, const ui void AsyncWebServerRequest::send_P(int code, const String& contentType, PGM_P content, AwsTemplateProcessor callback){ send(beginResponse_P(code, contentType, content, callback)); } +#endif -void AsyncWebServerRequest::redirect(const String& url){ +void AsyncWebServerRequest::redirect(const char* url){ AsyncWebServerResponse * response = beginResponse(302); response->addHeader(F("Location"), url); send(response); @@ -885,12 +859,13 @@ bool AsyncWebServerRequest::hasArg(const char* name) const { return false; } +#ifdef ESP8266 bool AsyncWebServerRequest::hasArg(const __FlashStringHelper * data) const { return hasArg(String(data).c_str()); } +#endif - -const String& AsyncWebServerRequest::arg(const String& name) const { +const String& AsyncWebServerRequest::arg(const char* name) const { for(const auto& arg: _params){ if(arg.name() == name){ return arg.value(); @@ -899,9 +874,11 @@ const String& AsyncWebServerRequest::arg(const String& name) const { return emptyString; } +#ifdef ESP8266 const String& AsyncWebServerRequest::arg(const __FlashStringHelper * data) const { return arg(String(data).c_str()); } +#endif const String& AsyncWebServerRequest::arg(size_t i) const { return getParam(i)->value(); @@ -916,14 +893,15 @@ const String& AsyncWebServerRequest::pathArg(size_t i) const { } const String& AsyncWebServerRequest::header(const char* name) const { - const AsyncWebHeader* h = getHeader(String(name)); + const AsyncWebHeader* h = getHeader(name); return h ? h->value() : emptyString; } +#ifdef ESP8266 const String& AsyncWebServerRequest::header(const __FlashStringHelper * data) const { return header(String(data).c_str()); }; - +#endif const String& AsyncWebServerRequest::header(size_t i) const { const AsyncWebHeader* h = getHeader(i); @@ -939,7 +917,7 @@ String AsyncWebServerRequest::urlDecode(const String& text) const { char temp[] = "0x00"; unsigned int len = text.length(); unsigned int i = 0; - String decoded = String(); + String decoded; decoded.reserve(len); // Allocate the string internal buffer - never longer from source text while (i < len){ char decodedChar; @@ -958,7 +936,32 @@ String AsyncWebServerRequest::urlDecode(const String& text) const { return decoded; } +#ifndef ESP8266 +const char* AsyncWebServerRequest::methodToString() const { + if(_method == HTTP_ANY) return "ANY"; + if(_method & HTTP_GET) return "GET"; + if(_method & HTTP_POST) return "POST"; + if(_method & HTTP_DELETE) return "DELETE"; + if(_method & HTTP_PUT) return "PUT"; + if(_method & HTTP_PATCH) return "PATCH"; + if(_method & HTTP_HEAD) return "HEAD"; + if(_method & HTTP_OPTIONS) return "OPTIONS"; + return "UNKNOWN"; +} +const char* AsyncWebServerRequest::requestedConnTypeToString() const { + switch (_reqconntype) { + case RCT_NOT_USED: return "RCT_NOT_USED"; + case RCT_DEFAULT: return "RCT_DEFAULT"; + case RCT_HTTP: return "RCT_HTTP"; + case RCT_WS: return "RCT_WS"; + case RCT_EVENT: return "RCT_EVENT"; + default: return "ERROR"; + } +} +#endif + +#ifdef ESP8266 const __FlashStringHelper *AsyncWebServerRequest::methodToString() const { if(_method == HTTP_ANY) return F("ANY"); else if(_method & HTTP_GET) return F("GET"); @@ -981,6 +984,7 @@ const __FlashStringHelper *AsyncWebServerRequest::requestedConnTypeToString() co default: return F("ERROR"); } } +#endif bool AsyncWebServerRequest::isExpectedRequestedConnType(RequestedConnectionType erct1, RequestedConnectionType erct2, RequestedConnectionType erct3) { bool res = false;