refactor WebServer methods

and const specifiers for immutable returns
make &String arg overloads over const char*
+ some minor cleanups
This commit is contained in:
Emil Muratov
2024-06-28 00:45:05 +09:00
committed by Mathieu Carbou
parent 9e93f03525
commit c79f2d05f0
6 changed files with 176 additions and 100 deletions

View File

@ -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());
}

View File

@ -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){

View File

@ -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))){

View File

@ -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);

View File

@ -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);

View File

@ -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<PGM_P>(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<PGM_P>(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;