From 29976ad85ab85d506beb4b3fc2a21ea5a267400b Mon Sep 17 00:00:00 2001 From: Mathieu Carbou Date: Thu, 27 Jun 2024 20:34:10 +0200 Subject: [PATCH] Code reformat according to clang file --- src/AsyncEventSource.cpp | 205 +++-- src/AsyncEventSource.h | 109 +-- src/AsyncJson.h | 8 +- src/AsyncWebSocket.cpp | 1604 +++++++++++++++++-------------------- src/AsyncWebSocket.h | 300 +++---- src/ESPAsyncWebServer.h | 373 +++++---- src/WebAuthentication.cpp | 127 ++- src/WebAuthentication.h | 12 +- src/WebHandlerImpl.h | 96 +-- src/WebHandlers.cpp | 130 +-- src/WebRequest.cpp | 793 +++++++++--------- src/WebResponseImpl.h | 88 +- src/WebResponses.cpp | 499 ++++++------ src/WebServer.cpp | 98 ++- 14 files changed, 2223 insertions(+), 2219 deletions(-) diff --git a/src/AsyncEventSource.cpp b/src/AsyncEventSource.cpp index 90faa3f..87d8293 100644 --- a/src/AsyncEventSource.cpp +++ b/src/AsyncEventSource.cpp @@ -23,38 +23,38 @@ #endif #include "AsyncEventSource.h" -static String generateEventMessage(const char *message, const char *event, uint32_t id, uint32_t reconnect){ +static String generateEventMessage(const char* message, const char* event, uint32_t id, uint32_t reconnect) { String ev; - if(reconnect){ + if (reconnect) { ev += F("retry: "); ev += reconnect; ev += F("\r\n"); } - if(id){ + if (id) { ev += F("id: "); ev += String(id); ev += F("\r\n"); } - if(event != NULL){ + if (event != NULL) { ev += F("event: "); ev += String(event); ev += F("\r\n"); } - if(message != NULL){ + if (message != NULL) { size_t messageLen = strlen(message); - char * lineStart = (char *)message; - char * lineEnd; + char* lineStart = (char*)message; + char* lineEnd; do { - char * nextN = strchr(lineStart, '\n'); - char * nextR = strchr(lineStart, '\r'); - if(nextN == NULL && nextR == NULL){ - size_t llen = ((char *)message + messageLen) - lineStart; - char * ldata = (char *)malloc(llen+1); - if(ldata != NULL){ + char* nextN = strchr(lineStart, '\n'); + char* nextR = strchr(lineStart, '\r'); + if (nextN == NULL && nextR == NULL) { + size_t llen = ((char*)message + messageLen) - lineStart; + char* ldata = (char*)malloc(llen + 1); + if (ldata != NULL) { memcpy(ldata, lineStart, llen); ldata[llen] = 0; ev += F("data: "); @@ -62,24 +62,24 @@ static String generateEventMessage(const char *message, const char *event, uint3 ev += F("\r\n\r\n"); free(ldata); } - lineStart = (char *)message + messageLen; + lineStart = (char*)message + messageLen; } else { - char * nextLine = NULL; - if(nextN != NULL && nextR != NULL){ - if(nextR < nextN){ + char* nextLine = NULL; + if (nextN != NULL && nextR != NULL) { + if (nextR < nextN) { lineEnd = nextR; - if(nextN == (nextR + 1)) + if (nextN == (nextR + 1)) nextLine = nextN + 1; else nextLine = nextR + 1; } else { lineEnd = nextN; - if(nextR == (nextN + 1)) + if (nextR == (nextN + 1)) nextLine = nextR + 1; else nextLine = nextN + 1; } - } else if(nextN != NULL){ + } else if (nextN != NULL) { lineEnd = nextN; nextLine = nextN + 1; } else { @@ -88,8 +88,8 @@ static String generateEventMessage(const char *message, const char *event, uint3 } size_t llen = lineEnd - lineStart; - char * ldata = (char *)malloc(llen+1); - if(ldata != NULL){ + char* ldata = (char*)malloc(llen + 1); + if (ldata != NULL) { memcpy(ldata, lineStart, llen); ldata[llen] = 0; ev += F("data: "); @@ -98,10 +98,10 @@ static String generateEventMessage(const char *message, const char *event, uint3 free(ldata); } lineStart = nextLine; - if(lineStart == ((char *)message + messageLen)) + if (lineStart == ((char*)message + messageLen)) ev += F("\r\n"); } - } while(lineStart < ((char *)message + messageLen)); + } while (lineStart < ((char*)message + messageLen)); } return ev; @@ -109,11 +109,10 @@ static String generateEventMessage(const char *message, const char *event, uint3 // Message -AsyncEventSourceMessage::AsyncEventSourceMessage(const char * data, size_t len) -: _data(nullptr), _len(len), _sent(0), _acked(0) -{ - _data = (uint8_t*)malloc(_len+1); - if(_data == nullptr){ +AsyncEventSourceMessage::AsyncEventSourceMessage(const char* data, size_t len) + : _data(nullptr), _len(len), _sent(0), _acked(0) { + _data = (uint8_t*)malloc(_len + 1); + if (_data == nullptr) { _len = 0; } else { memcpy(_data, data, len); @@ -122,18 +121,18 @@ AsyncEventSourceMessage::AsyncEventSourceMessage(const char * data, size_t len) } AsyncEventSourceMessage::~AsyncEventSourceMessage() { - if(_data != NULL) - free(_data); + if (_data != NULL) + free(_data); } size_t AsyncEventSourceMessage::ack(size_t len, uint32_t time) { (void)time; // If the whole message is now acked... - if(_acked + len > _len){ - // Return the number of extra bytes acked (they will be carried on to the next message) - const size_t extra = _acked + len - _len; - _acked = _len; - return extra; + if (_acked + len > _len) { + // Return the number of extra bytes acked (they will be carried on to the next message) + const size_t extra = _acked + len - _len; + _acked = _len; + return extra; } // Return that no extra bytes left. _acked += len; @@ -142,40 +141,39 @@ size_t AsyncEventSourceMessage::ack(size_t len, uint32_t time) { // This could also return void as the return value is not used. // Leaving as-is for compatibility... -size_t AsyncEventSourceMessage::send(AsyncClient *client) { - if (_sent >= _len) { - return 0; - } - const size_t len_to_send = _len - _sent; - auto position = reinterpret_cast(_data + _sent); - const size_t sent_now = client->write(position, len_to_send); - _sent += sent_now; - return sent_now; +size_t AsyncEventSourceMessage::send(AsyncClient* client) { + if (_sent >= _len) { + return 0; + } + const size_t len_to_send = _len - _sent; + auto position = reinterpret_cast(_data + _sent); + const size_t sent_now = client->write(position, len_to_send); + _sent += sent_now; + return sent_now; } // Client -AsyncEventSourceClient::AsyncEventSourceClient(AsyncWebServerRequest *request, AsyncEventSource *server) -{ +AsyncEventSourceClient::AsyncEventSourceClient(AsyncWebServerRequest* request, AsyncEventSource* server) { _client = request->client(); _server = server; _lastId = 0; - if(request->hasHeader(F("Last-Event-ID"))) + if (request->hasHeader(F("Last-Event-ID"))) _lastId = atoi(request->getHeader(F("Last-Event-ID"))->value().c_str()); _client->setRxTimeout(0); _client->onError(NULL, NULL); - _client->onAck([](void *r, AsyncClient* c, size_t len, uint32_t time){ (void)c; ((AsyncEventSourceClient*)(r))->_onAck(len, time); }, this); - _client->onPoll([](void *r, AsyncClient* c){ (void)c; ((AsyncEventSourceClient*)(r))->_onPoll(); }, this); + _client->onAck([](void* r, AsyncClient* c, size_t len, uint32_t time) { (void)c; ((AsyncEventSourceClient*)(r))->_onAck(len, time); }, this); + _client->onPoll([](void* r, AsyncClient* c) { (void)c; ((AsyncEventSourceClient*)(r))->_onPoll(); }, this); _client->onData(NULL, NULL); - _client->onTimeout([this](void *r, AsyncClient* c __attribute__((unused)), uint32_t time){ ((AsyncEventSourceClient*)(r))->_onTimeout(time); }, this); - _client->onDisconnect([this](void *r, AsyncClient* c){ ((AsyncEventSourceClient*)(r))->_onDisconnect(); delete c; }, this); + _client->onTimeout([this](void* r, AsyncClient* c __attribute__((unused)), uint32_t time) { ((AsyncEventSourceClient*)(r))->_onTimeout(time); }, this); + _client->onDisconnect([this](void* r, AsyncClient* c) { ((AsyncEventSourceClient*)(r))->_onDisconnect(); delete c; }, this); _server->_addClient(this); delete request; } -AsyncEventSourceClient::~AsyncEventSourceClient(){ +AsyncEventSourceClient::~AsyncEventSourceClient() { #ifdef ESP32 std::lock_guard lock(_lockmq); #endif @@ -183,132 +181,133 @@ AsyncEventSourceClient::~AsyncEventSourceClient(){ close(); } -void AsyncEventSourceClient::_queueMessage(const char * message, size_t len){ +void AsyncEventSourceClient::_queueMessage(const char* message, size_t len) { #ifdef ESP32 - //length() is not thread-safe, thus acquiring the lock before this call.. + // length() is not thread-safe, thus acquiring the lock before this call.. std::lock_guard lock(_lockmq); #endif - if(_messageQueue.size() >= SSE_MAX_QUEUED_MESSAGES){ + if (_messageQueue.size() >= SSE_MAX_QUEUED_MESSAGES) { #ifdef ESP8266 ets_printf(String(F("ERROR: Too many messages queued\n")).c_str()); #else log_e("Too many messages queued: deleting message"); #endif - return; + return; } _messageQueue.emplace_back(message, len); // runqueue trigger when new messages added - if(_client->canSend()) { + if (_client->canSend()) { _runQueue(); } } -void AsyncEventSourceClient::_onAck(size_t len, uint32_t time){ +void AsyncEventSourceClient::_onAck(size_t len, uint32_t time) { #ifdef ESP32 // Same here, acquiring the lock early std::lock_guard lock(_lockmq); #endif - while(len && _messageQueue.size()){ + while (len && _messageQueue.size()) { len = _messageQueue.front().ack(len, time); - if(_messageQueue.front().finished()) + if (_messageQueue.front().finished()) _messageQueue.pop_front(); } _runQueue(); } -void AsyncEventSourceClient::_onPoll(){ +void AsyncEventSourceClient::_onPoll() { #ifdef ESP32 // Same here, acquiring the lock early std::lock_guard lock(_lockmq); #endif - if(_messageQueue.size()){ + if (_messageQueue.size()) { _runQueue(); } } -void AsyncEventSourceClient::_onTimeout(uint32_t time __attribute__((unused))){ +void AsyncEventSourceClient::_onTimeout(uint32_t time __attribute__((unused))) { _client->close(true); } -void AsyncEventSourceClient::_onDisconnect(){ +void AsyncEventSourceClient::_onDisconnect() { _client = NULL; _server->_handleDisconnect(this); } -void AsyncEventSourceClient::close(){ - if(_client != NULL) +void AsyncEventSourceClient::close() { + if (_client != NULL) _client->close(); } -void AsyncEventSourceClient::write(const char * message, size_t len){ - if(!connected()) return; +void AsyncEventSourceClient::write(const char* message, size_t len) { + if (!connected()) + return; _queueMessage(message, len); } -void AsyncEventSourceClient::send(const char *message, const char *event, uint32_t id, uint32_t reconnect){ - if(!connected()) return; +void AsyncEventSourceClient::send(const char* message, const char* event, uint32_t id, uint32_t reconnect) { + if (!connected()) + return; String ev = generateEventMessage(message, event, id, reconnect); _queueMessage(ev.c_str(), ev.length()); } size_t AsyncEventSourceClient::packetsWaiting() const { #ifdef ESP32 - std::lock_guard lock(_lockmq); + std::lock_guard lock(_lockmq); #endif - return _messageQueue.size(); + return _messageQueue.size(); } void AsyncEventSourceClient::_runQueue() { // Calls to this private method now already protected by _lockmq acquisition // so no extra call of _lockmq.lock() here.. - for ( auto &i : _messageQueue){ + for (auto& i : _messageQueue) { if (!i.sent()) i.send(_client); } } - // Handler -void AsyncEventSource::onConnect(ArEventHandlerFunction cb){ +void AsyncEventSource::onConnect(ArEventHandlerFunction cb) { _connectcb = cb; } -void AsyncEventSource::authorizeConnect(ArAuthorizeConnectHandler cb){ +void AsyncEventSource::authorizeConnect(ArAuthorizeConnectHandler cb) { _authorizeConnectHandler = cb; } -void AsyncEventSource::_addClient(AsyncEventSourceClient * client){ +void AsyncEventSource::_addClient(AsyncEventSourceClient* client) { if (!client) return; #ifdef ESP32 std::lock_guard lock(_client_queue_lock); #endif _clients.emplace_back(client); - if(_connectcb) + if (_connectcb) _connectcb(client); } -void AsyncEventSource::_handleDisconnect(AsyncEventSourceClient * client){ +void AsyncEventSource::_handleDisconnect(AsyncEventSourceClient* client) { #ifdef ESP32 std::lock_guard lock(_client_queue_lock); #endif - for (auto i = _clients.begin(); i != _clients.end(); ++i){ + for (auto i = _clients.begin(); i != _clients.end(); ++i) { if (i->get() == client) _clients.erase(i); } } -void AsyncEventSource::close(){ +void AsyncEventSource::close() { // While the whole loop is not done, the linked list is locked and so the // iterator should remain valid even when AsyncEventSource::_handleDisconnect() // is called very early #ifdef ESP32 std::lock_guard lock(_client_queue_lock); #endif - for(const auto &c: _clients){ - if(c->connected()) + for (const auto& c : _clients) { + if (c->connected()) c->close(); } } @@ -320,25 +319,26 @@ size_t AsyncEventSource::avgPacketsWaiting() const { #ifdef ESP32 std::lock_guard lock(_client_queue_lock); #endif - if (!_clients.size()) return 0; + if (!_clients.size()) + return 0; - for(const auto &c: _clients){ - if(c->connected()) { + for (const auto& c : _clients) { + if (c->connected()) { aql += c->packetsWaiting(); ++nConnectedClients; } } - return ((aql) + (nConnectedClients/2)) / (nConnectedClients); // round up + return ((aql) + (nConnectedClients / 2)) / (nConnectedClients); // round up } void AsyncEventSource::send( - const char *message, const char *event, uint32_t id, uint32_t reconnect){ + const char* message, const char* event, uint32_t id, uint32_t reconnect) { String ev = generateEventMessage(message, event, id, reconnect); #ifdef ESP32 std::lock_guard lock(_client_queue_lock); #endif - for(const auto &c: _clients){ - if(c->connected()) { + for (const auto& c : _clients) { + if (c->connected()) { c->write(ev.c_str(), ev.length()); } } @@ -349,15 +349,15 @@ size_t AsyncEventSource::count() const { std::lock_guard lock(_client_queue_lock); #endif size_t n_clients{0}; - for (const auto &i : _clients) + for (const auto& i : _clients) if (i->connected()) ++n_clients; return n_clients; } -bool AsyncEventSource::canHandle(AsyncWebServerRequest *request){ - if(request->method() != HTTP_GET || !request->url().equals(_url)) { +bool AsyncEventSource::canHandle(AsyncWebServerRequest* request) { + if (request->method() != HTTP_GET || !request->url().equals(_url)) { return false; } request->addInterestingHeader(F("Last-Event-ID")); @@ -365,12 +365,12 @@ bool AsyncEventSource::canHandle(AsyncWebServerRequest *request){ return true; } -void AsyncEventSource::handleRequest(AsyncWebServerRequest *request){ - if((_username.length() && _password.length()) && !request->authenticate(_username.c_str(), _password.c_str())) { +void AsyncEventSource::handleRequest(AsyncWebServerRequest* request) { + if ((_username.length() && _password.length()) && !request->authenticate(_username.c_str(), _password.c_str())) { return request->requestAuthentication(); } - if(_authorizeConnectHandler != NULL){ - if(!_authorizeConnectHandler(request)){ + if (_authorizeConnectHandler != NULL) { + if (!_authorizeConnectHandler(request)) { return request->send(401); } } @@ -379,7 +379,7 @@ void AsyncEventSource::handleRequest(AsyncWebServerRequest *request){ // Response -AsyncEventSourceResponse::AsyncEventSourceResponse(AsyncEventSource *server){ +AsyncEventSourceResponse::AsyncEventSourceResponse(AsyncEventSource* server) { _server = server; _code = 200; _contentType = F("text/event-stream"); @@ -388,16 +388,15 @@ AsyncEventSourceResponse::AsyncEventSourceResponse(AsyncEventSource *server){ addHeader(F("Connection"), F("keep-alive")); } -void AsyncEventSourceResponse::_respond(AsyncWebServerRequest *request){ +void AsyncEventSourceResponse::_respond(AsyncWebServerRequest* request) { String out = _assembleHead(request->version()); request->client()->write(out.c_str(), _headLength); _state = RESPONSE_WAIT_ACK; } -size_t AsyncEventSourceResponse::_ack(AsyncWebServerRequest *request, size_t len, uint32_t time __attribute__((unused))){ - if(len){ +size_t AsyncEventSourceResponse::_ack(AsyncWebServerRequest* request, size_t len, uint32_t time __attribute__((unused))) { + if (len) { new AsyncEventSourceClient(request, _server); } return 0; } - diff --git a/src/AsyncEventSource.h b/src/AsyncEventSource.h index 6ce3e57..93a4176 100644 --- a/src/AsyncEventSource.h +++ b/src/AsyncEventSource.h @@ -23,130 +23,131 @@ #include #include #ifdef ESP32 -#include -#include -#ifndef SSE_MAX_QUEUED_MESSAGES -#define SSE_MAX_QUEUED_MESSAGES 32 -#endif + #include + #include + #ifndef SSE_MAX_QUEUED_MESSAGES + #define SSE_MAX_QUEUED_MESSAGES 32 + #endif #else // esp8266 -#include -#ifndef SSE_MAX_QUEUED_MESSAGES -#define SSE_MAX_QUEUED_MESSAGES 8 -#endif + #include + #ifndef SSE_MAX_QUEUED_MESSAGES + #define SSE_MAX_QUEUED_MESSAGES 8 + #endif #endif #include #ifdef ESP8266 -#include -#ifdef CRYPTO_HASH_h // include Hash.h from espressif framework if the first include was from the crypto library -#include <../src/Hash.h> -#endif + #include + #ifdef CRYPTO_HASH_h // include Hash.h from espressif framework if the first include was from the crypto library + #include <../src/Hash.h> + #endif #endif #ifndef DEFAULT_MAX_SSE_CLIENTS -#ifdef ESP32 -#define DEFAULT_MAX_SSE_CLIENTS 8 -#else -#define DEFAULT_MAX_SSE_CLIENTS 4 -#endif + #ifdef ESP32 + #define DEFAULT_MAX_SSE_CLIENTS 8 + #else + #define DEFAULT_MAX_SSE_CLIENTS 4 + #endif #endif class AsyncEventSource; class AsyncEventSourceResponse; class AsyncEventSourceClient; -using ArEventHandlerFunction = std::function; -using ArAuthorizeConnectHandler = std::function; +using ArEventHandlerFunction = std::function; +using ArAuthorizeConnectHandler = std::function; class AsyncEventSourceMessage { private: - uint8_t * _data; + uint8_t* _data; size_t _len; size_t _sent; - //size_t _ack; + // size_t _ack; size_t _acked; + public: - AsyncEventSourceMessage(const char * data, size_t len); + AsyncEventSourceMessage(const char* data, size_t len); ~AsyncEventSourceMessage(); size_t ack(size_t len, uint32_t time __attribute__((unused))); - size_t send(AsyncClient *client); - bool finished(){ return _acked == _len; } + size_t send(AsyncClient* client); + bool finished() { return _acked == _len; } bool sent() { return _sent == _len; } }; class AsyncEventSourceClient { private: - AsyncClient *_client; - AsyncEventSource *_server; + AsyncClient* _client; + AsyncEventSource* _server; uint32_t _lastId; - std::list< AsyncEventSourceMessage > _messageQueue; + std::list _messageQueue; #ifdef ESP32 mutable std::mutex _lockmq; #endif - void _queueMessage(const char * message, size_t len); + void _queueMessage(const char* message, size_t len); void _runQueue(); public: - - AsyncEventSourceClient(AsyncWebServerRequest *request, AsyncEventSource *server); + AsyncEventSourceClient(AsyncWebServerRequest* request, AsyncEventSource* server); ~AsyncEventSourceClient(); - AsyncClient* client(){ return _client; } + AsyncClient* client() { return _client; } void close(); - void write(const char * message, size_t len); - void send(const char *message, const char *event=NULL, uint32_t id=0, uint32_t reconnect=0); + void write(const char* message, size_t len); + void send(const char* message, const char* event = NULL, uint32_t id = 0, uint32_t reconnect = 0); bool connected() const { return (_client != NULL) && _client->connected(); } uint32_t lastId() const { return _lastId; } - size_t packetsWaiting() const; + size_t packetsWaiting() const; - //system callbacks (do not call) + // system callbacks (do not call) void _onAck(size_t len, uint32_t time); void _onPoll(); void _onTimeout(uint32_t time); void _onDisconnect(); }; -class AsyncEventSource: public AsyncWebHandler { +class AsyncEventSource : public AsyncWebHandler { private: String _url; - std::list< std::unique_ptr > _clients; + std::list> _clients; #ifdef ESP32 // Same as for individual messages, protect mutations of _clients list // since simultaneous access from different tasks is possible mutable std::mutex _client_queue_lock; #endif ArEventHandlerFunction _connectcb{nullptr}; - ArAuthorizeConnectHandler _authorizeConnectHandler; + ArAuthorizeConnectHandler _authorizeConnectHandler; + public: AsyncEventSource(const String& url) : _url(url){}; - ~AsyncEventSource(){ close(); }; + ~AsyncEventSource() { close(); }; - const char * url() const { return _url.c_str(); } + const char* url() const { return _url.c_str(); } void close(); void onConnect(ArEventHandlerFunction cb); void authorizeConnect(ArAuthorizeConnectHandler cb); - void send(const char *message, const char *event=NULL, uint32_t id=0, uint32_t reconnect=0); + void send(const char* message, const char* event = NULL, uint32_t id = 0, uint32_t reconnect = 0); // number of clients connected size_t count() const; - size_t avgPacketsWaiting() const; + size_t avgPacketsWaiting() const; - //system callbacks (do not call) - void _addClient(AsyncEventSourceClient * client); - void _handleDisconnect(AsyncEventSourceClient * client); - virtual bool canHandle(AsyncWebServerRequest *request) override final; - virtual void handleRequest(AsyncWebServerRequest *request) override final; + // system callbacks (do not call) + void _addClient(AsyncEventSourceClient* client); + void _handleDisconnect(AsyncEventSourceClient* client); + virtual bool canHandle(AsyncWebServerRequest* request) override final; + virtual void handleRequest(AsyncWebServerRequest* request) override final; }; -class AsyncEventSourceResponse: public AsyncWebServerResponse { +class AsyncEventSourceResponse : public AsyncWebServerResponse { private: String _content; - AsyncEventSource *_server; + AsyncEventSource* _server; + public: - AsyncEventSourceResponse(AsyncEventSource *server); - void _respond(AsyncWebServerRequest *request); - size_t _ack(AsyncWebServerRequest *request, size_t len, uint32_t time); + AsyncEventSourceResponse(AsyncEventSource* server); + void _respond(AsyncWebServerRequest* request); + size_t _ack(AsyncWebServerRequest* request, size_t len, uint32_t time); bool _sourceValid() const { return true; } }; - #endif /* ASYNCEVENTSOURCE_H_ */ diff --git a/src/AsyncJson.h b/src/AsyncJson.h index 6774454..ce89301 100644 --- a/src/AsyncJson.h +++ b/src/AsyncJson.h @@ -39,9 +39,9 @@ #include #if ARDUINOJSON_VERSION_MAJOR == 6 -#ifndef DYNAMIC_JSON_DOCUMENT_SIZE -#define DYNAMIC_JSON_DOCUMENT_SIZE 1024 -#endif + #ifndef DYNAMIC_JSON_DOCUMENT_SIZE + #define DYNAMIC_JSON_DOCUMENT_SIZE 1024 + #endif #endif constexpr const char* JSON_MIMETYPE = "application/json"; @@ -230,7 +230,7 @@ class AsyncCallbackJsonWebHandler : public AsyncWebHandler { } virtual void handleRequest(AsyncWebServerRequest* request) override final { - if((_username != "" && _password != "") && !request->authenticate(_username.c_str(), _password.c_str())) + if ((_username != "" && _password != "") && !request->authenticate(_username.c_str(), _password.c_str())) return request->requestAuthentication(); if (_onRequest) { if (request->method() == HTTP_GET) { diff --git a/src/AsyncWebSocket.cpp b/src/AsyncWebSocket.cpp index b59c392..8f1e6a8 100644 --- a/src/AsyncWebSocket.cpp +++ b/src/AsyncWebSocket.cpp @@ -18,144 +18,140 @@ License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "Arduino.h" #include "AsyncWebSocket.h" +#include "Arduino.h" #include #include #ifndef ESP8266 -#if ESP_IDF_VERSION_MAJOR < 5 -#include "./port/SHA1Builder.h" + #if ESP_IDF_VERSION_MAJOR < 5 + #include "./port/SHA1Builder.h" + #else + #include + #endif + #include #else -#include -#endif -#include -#else -#include + #include #endif #define MAX_PRINTF_LEN 64 -size_t webSocketSendFrameWindow(AsyncClient *client){ - if(!client->canSend()) +size_t webSocketSendFrameWindow(AsyncClient* client) { + if (!client->canSend()) return 0; size_t space = client->space(); - if(space < 9) + if (space < 9) return 0; return space - 8; } -size_t webSocketSendFrame(AsyncClient *client, bool final, uint8_t opcode, bool mask, uint8_t *data, size_t len){ - if(!client->canSend()) { +size_t webSocketSendFrame(AsyncClient* client, bool final, uint8_t opcode, bool mask, uint8_t* data, size_t len) { + if (!client->canSend()) { // Serial.println("SF 1"); return 0; } size_t space = client->space(); - if(space < 2) { + if (space < 2) { // Serial.println("SF 2"); return 0; } - uint8_t mbuf[4] = {0,0,0,0}; + uint8_t mbuf[4] = {0, 0, 0, 0}; uint8_t headLen = 2; - if(len && mask){ + if (len && mask) { headLen += 4; mbuf[0] = rand() % 0xFF; mbuf[1] = rand() % 0xFF; mbuf[2] = rand() % 0xFF; mbuf[3] = rand() % 0xFF; } - if(len > 125) + if (len > 125) headLen += 2; - if(space < headLen) { + if (space < headLen) { // Serial.println("SF 2"); return 0; } space -= headLen; - if(len > space) len = space; + if (len > space) + len = space; - uint8_t *buf = (uint8_t*)malloc(headLen); - if(buf == NULL){ - //os_printf("could not malloc %u bytes for frame header\n", headLen); - // Serial.println("SF 3"); + uint8_t* buf = (uint8_t*)malloc(headLen); + if (buf == NULL) { + // os_printf("could not malloc %u bytes for frame header\n", headLen); + // Serial.println("SF 3"); return 0; } buf[0] = opcode & 0x0F; - if(final) + if (final) buf[0] |= 0x80; - if(len < 126) + if (len < 126) buf[1] = len & 0x7F; else { buf[1] = 126; buf[2] = (uint8_t)((len >> 8) & 0xFF); buf[3] = (uint8_t)(len & 0xFF); } - if(len && mask){ + if (len && mask) { buf[1] |= 0x80; memcpy(buf + (headLen - 4), mbuf, 4); } - if(client->add((const char *)buf, headLen) != headLen){ - //os_printf("error adding %lu header bytes\n", headLen); + if (client->add((const char*)buf, headLen) != headLen) { + // os_printf("error adding %lu header bytes\n", headLen); free(buf); // Serial.println("SF 4"); return 0; } free(buf); - if(len){ - if(len && mask){ + if (len) { + if (len && mask) { size_t i; - for(i=0;iadd((const char *)data, len) != len){ - //os_printf("error adding %lu data bytes\n", len); - // Serial.println("SF 5"); + if (client->add((const char*)data, len) != len) { + // os_printf("error adding %lu data bytes\n", len); + // Serial.println("SF 5"); return 0; } } - if(!client->send()){ - //os_printf("error sending frame: %lu\n", headLen+len); - // Serial.println("SF 6"); + if (!client->send()) { + // os_printf("error sending frame: %lu\n", headLen+len); + // Serial.println("SF 6"); return 0; } // Serial.println("SF"); return len; } - - /* * AsyncWebSocketMessageBuffer */ AsyncWebSocketMessageBuffer::AsyncWebSocketMessageBuffer(const uint8_t* data, size_t size) - : _buffer(std::make_shared>(size)) -{ - if (_buffer->capacity() < size) { - _buffer->reserve(size); - } else { - std::memcpy(_buffer->data(), data, size); - } + : _buffer(std::make_shared>(size)) { + if (_buffer->capacity() < size) { + _buffer->reserve(size); + } else { + std::memcpy(_buffer->data(), data, size); + } } AsyncWebSocketMessageBuffer::AsyncWebSocketMessageBuffer(size_t size) - : _buffer(std::make_shared>(size)) -{ - if (_buffer->capacity() < size) { - _buffer->reserve(size); - } + : _buffer(std::make_shared>(size)) { + if (_buffer->capacity() < size) { + _buffer->reserve(size); + } } -bool AsyncWebSocketMessageBuffer::reserve(size_t size) -{ - if (_buffer->capacity() >= size) - return true; - _buffer->reserve(size); - return _buffer->capacity() >= size; +bool AsyncWebSocketMessageBuffer::reserve(size_t size) { + if (_buffer->capacity() >= size) + return true; + _buffer->reserve(size); + return _buffer->capacity() >= size; } /* @@ -163,381 +159,340 @@ bool AsyncWebSocketMessageBuffer::reserve(size_t size) */ class AsyncWebSocketControl { -private: + private: uint8_t _opcode; - uint8_t *_data; + uint8_t* _data; size_t _len; bool _mask; bool _finished; -public: - AsyncWebSocketControl(uint8_t opcode, const uint8_t *data=NULL, size_t len=0, bool mask=false) - :_opcode(opcode) - ,_len(len) - ,_mask(len && mask) - ,_finished(false) - { - if (data == NULL) - _len = 0; - if (_len) - { - if (_len > 125) - _len = 125; + public: + AsyncWebSocketControl(uint8_t opcode, const uint8_t* data = NULL, size_t len = 0, bool mask = false) + : _opcode(opcode), _len(len), _mask(len && mask), _finished(false) { + if (data == NULL) + _len = 0; + if (_len) { + if (_len > 125) + _len = 125; - _data = (uint8_t*)malloc(_len); + _data = (uint8_t*)malloc(_len); - if(_data == NULL) - _len = 0; - else - memcpy(_data, data, len); - } + if (_data == NULL) + _len = 0; else - _data = NULL; + memcpy(_data, data, len); + } else + _data = NULL; } - virtual ~AsyncWebSocketControl() - { - if (_data != NULL) - free(_data); + virtual ~AsyncWebSocketControl() { + if (_data != NULL) + free(_data); } virtual bool finished() const { return _finished; } - uint8_t opcode(){ return _opcode; } - uint8_t len(){ return _len + 2; } - size_t send(AsyncClient *client){ - _finished = true; - return webSocketSendFrame(client, true, _opcode & 0x0F, _mask, _data, _len); + uint8_t opcode() { return _opcode; } + uint8_t len() { return _len + 2; } + size_t send(AsyncClient* client) { + _finished = true; + return webSocketSendFrame(client, true, _opcode & 0x0F, _mask, _data, _len); } }; - /* * AsyncWebSocketMessage Message */ - -AsyncWebSocketMessage::AsyncWebSocketMessage(AsyncWebSocketSharedBuffer buffer, uint8_t opcode, bool mask) : - _WSbuffer{buffer}, - _opcode(opcode & 0x07), - _mask{mask}, - _status{_WSbuffer?WS_MSG_SENDING:WS_MSG_ERROR} -{ -} - -void AsyncWebSocketMessage::ack(size_t len, uint32_t time) -{ - (void)time; - _acked += len; - if (_sent >= _WSbuffer->size() && _acked >= _ack) - { - _status = WS_MSG_SENT; - } - //ets_printf("A: %u\n", len); +AsyncWebSocketMessage::AsyncWebSocketMessage(AsyncWebSocketSharedBuffer buffer, uint8_t opcode, bool mask) : _WSbuffer{buffer}, + _opcode(opcode & 0x07), + _mask{mask}, + _status{_WSbuffer ? WS_MSG_SENDING : WS_MSG_ERROR} { } -size_t AsyncWebSocketMessage::send(AsyncClient *client) -{ - if (_status != WS_MSG_SENDING) - return 0; - if (_acked < _ack){ - return 0; - } - if (_sent == _WSbuffer->size()) - { - if(_acked == _ack) - _status = WS_MSG_SENT; - return 0; - } - if (_sent > _WSbuffer->size()) - { - _status = WS_MSG_ERROR; - //ets_printf("E: %u > %u\n", _sent, _WSbuffer->length()); - return 0; - } - - size_t toSend = _WSbuffer->size() - _sent; - size_t window = webSocketSendFrameWindow(client); - - if (window < toSend) { - toSend = window; - } - - _sent += toSend; - _ack += toSend + ((toSend < 126)?2:4) + (_mask * 4); - - //ets_printf("W: %u %u\n", _sent - toSend, toSend); - - bool final = (_sent == _WSbuffer->size()); - uint8_t* dPtr = (uint8_t*)(_WSbuffer->data() + (_sent - toSend)); - uint8_t opCode = (toSend && _sent == toSend)?_opcode:(uint8_t)WS_CONTINUATION; - - size_t sent = webSocketSendFrame(client, final, opCode, _mask, dPtr, toSend); - _status = WS_MSG_SENDING; - if (toSend && sent != toSend){ - //ets_printf("E: %u != %u\n", toSend, sent); - _sent -= (toSend - sent); - _ack -= (toSend - sent); - } - //ets_printf("S: %u %u\n", _sent, sent); - return sent; +void AsyncWebSocketMessage::ack(size_t len, uint32_t time) { + (void)time; + _acked += len; + if (_sent >= _WSbuffer->size() && _acked >= _ack) { + _status = WS_MSG_SENT; + } + // ets_printf("A: %u\n", len); } +size_t AsyncWebSocketMessage::send(AsyncClient* client) { + if (_status != WS_MSG_SENDING) + return 0; + if (_acked < _ack) { + return 0; + } + if (_sent == _WSbuffer->size()) { + if (_acked == _ack) + _status = WS_MSG_SENT; + return 0; + } + if (_sent > _WSbuffer->size()) { + _status = WS_MSG_ERROR; + // ets_printf("E: %u > %u\n", _sent, _WSbuffer->length()); + return 0; + } + + size_t toSend = _WSbuffer->size() - _sent; + size_t window = webSocketSendFrameWindow(client); + + if (window < toSend) { + toSend = window; + } + + _sent += toSend; + _ack += toSend + ((toSend < 126) ? 2 : 4) + (_mask * 4); + + // ets_printf("W: %u %u\n", _sent - toSend, toSend); + + bool final = (_sent == _WSbuffer->size()); + uint8_t* dPtr = (uint8_t*)(_WSbuffer->data() + (_sent - toSend)); + uint8_t opCode = (toSend && _sent == toSend) ? _opcode : (uint8_t)WS_CONTINUATION; + + size_t sent = webSocketSendFrame(client, final, opCode, _mask, dPtr, toSend); + _status = WS_MSG_SENDING; + if (toSend && sent != toSend) { + // ets_printf("E: %u != %u\n", toSend, sent); + _sent -= (toSend - sent); + _ack -= (toSend - sent); + } + // ets_printf("S: %u %u\n", _sent, sent); + return sent; +} /* * Async WebSocket Client */ - const char * AWSC_PING_PAYLOAD = "ESPAsyncWebServer-PING"; - const size_t AWSC_PING_PAYLOAD_LEN = 22; +const char* AWSC_PING_PAYLOAD = "ESPAsyncWebServer-PING"; +const size_t AWSC_PING_PAYLOAD_LEN = 22; -AsyncWebSocketClient::AsyncWebSocketClient(AsyncWebServerRequest *request, AsyncWebSocket *server) - : _tempObject(NULL) -{ - _client = request->client(); - _server = server; - _clientId = _server->_getNextId(); - _status = WS_CONNECTED; - _pstate = 0; - _lastMessageTime = millis(); - _keepAlivePeriod = 0; - _client->setRxTimeout(0); - _client->onError([](void *r, AsyncClient* c, int8_t error){ (void)c; ((AsyncWebSocketClient*)(r))->_onError(error); }, this); - _client->onAck([](void *r, AsyncClient* c, size_t len, uint32_t time){ (void)c; ((AsyncWebSocketClient*)(r))->_onAck(len, time); }, this); - _client->onDisconnect([](void *r, AsyncClient* c){ ((AsyncWebSocketClient*)(r))->_onDisconnect(); delete c; }, this); - _client->onTimeout([](void *r, AsyncClient* c, uint32_t time){ (void)c; ((AsyncWebSocketClient*)(r))->_onTimeout(time); }, this); - _client->onData([](void *r, AsyncClient* c, void *buf, size_t len){ (void)c; ((AsyncWebSocketClient*)(r))->_onData(buf, len); }, this); - _client->onPoll([](void *r, AsyncClient* c){ (void)c; ((AsyncWebSocketClient*)(r))->_onPoll(); }, this); - _server->_handleEvent(this, WS_EVT_CONNECT, request, NULL, 0); - delete request; - memset(&_pinfo,0,sizeof(_pinfo)); +AsyncWebSocketClient::AsyncWebSocketClient(AsyncWebServerRequest* request, AsyncWebSocket* server) + : _tempObject(NULL) { + _client = request->client(); + _server = server; + _clientId = _server->_getNextId(); + _status = WS_CONNECTED; + _pstate = 0; + _lastMessageTime = millis(); + _keepAlivePeriod = 0; + _client->setRxTimeout(0); + _client->onError([](void* r, AsyncClient* c, int8_t error) { (void)c; ((AsyncWebSocketClient*)(r))->_onError(error); }, this); + _client->onAck([](void* r, AsyncClient* c, size_t len, uint32_t time) { (void)c; ((AsyncWebSocketClient*)(r))->_onAck(len, time); }, this); + _client->onDisconnect([](void* r, AsyncClient* c) { ((AsyncWebSocketClient*)(r))->_onDisconnect(); delete c; }, this); + _client->onTimeout([](void* r, AsyncClient* c, uint32_t time) { (void)c; ((AsyncWebSocketClient*)(r))->_onTimeout(time); }, this); + _client->onData([](void* r, AsyncClient* c, void* buf, size_t len) { (void)c; ((AsyncWebSocketClient*)(r))->_onData(buf, len); }, this); + _client->onPoll([](void* r, AsyncClient* c) { (void)c; ((AsyncWebSocketClient*)(r))->_onPoll(); }, this); + _server->_handleEvent(this, WS_EVT_CONNECT, request, NULL, 0); + delete request; + memset(&_pinfo, 0, sizeof(_pinfo)); } -AsyncWebSocketClient::~AsyncWebSocketClient() -{ - { - #ifdef ESP32 - std::lock_guard lock(_lock); - #endif - _messageQueue.clear(); - _controlQueue.clear(); - } - _server->_handleEvent(this, WS_EVT_DISCONNECT, NULL, NULL, 0); -} - -void AsyncWebSocketClient::_clearQueue() -{ - while (!_messageQueue.empty() && _messageQueue.front().finished()) - _messageQueue.pop_front(); -} - -void AsyncWebSocketClient::_onAck(size_t len, uint32_t time){ - _lastMessageTime = millis(); - - #ifdef ESP32 +AsyncWebSocketClient::~AsyncWebSocketClient() { + { +#ifdef ESP32 std::lock_guard lock(_lock); - #endif +#endif + _messageQueue.clear(); + _controlQueue.clear(); + } + _server->_handleEvent(this, WS_EVT_DISCONNECT, NULL, NULL, 0); +} - if (!_controlQueue.empty()) { - auto &head = _controlQueue.front(); - if (head.finished()){ - len -= head.len(); - if (_status == WS_DISCONNECTING && head.opcode() == WS_DISCONNECT){ - _controlQueue.pop_front(); - _status = WS_DISCONNECTED; - if (_client) _client->close(true); - return; - } - _controlQueue.pop_front(); - } +void AsyncWebSocketClient::_clearQueue() { + while (!_messageQueue.empty() && _messageQueue.front().finished()) + _messageQueue.pop_front(); +} + +void AsyncWebSocketClient::_onAck(size_t len, uint32_t time) { + _lastMessageTime = millis(); + +#ifdef ESP32 + std::lock_guard lock(_lock); +#endif + + if (!_controlQueue.empty()) { + auto& head = _controlQueue.front(); + if (head.finished()) { + len -= head.len(); + if (_status == WS_DISCONNECTING && head.opcode() == WS_DISCONNECT) { + _controlQueue.pop_front(); + _status = WS_DISCONNECTED; + if (_client) + _client->close(true); + return; + } + _controlQueue.pop_front(); } + } - if(len && !_messageQueue.empty()){ - _messageQueue.front().ack(len, time); - } + if (len && !_messageQueue.empty()) { + _messageQueue.front().ack(len, time); + } - _clearQueue(); + _clearQueue(); + _runQueue(); +} + +void AsyncWebSocketClient::_onPoll() { + if (!_client) + return; + +#ifdef ESP32 + std::unique_lock lock(_lock); +#endif + if (_client->canSend() && (!_controlQueue.empty() || !_messageQueue.empty())) { + _runQueue(); + } else if (_keepAlivePeriod > 0 && (millis() - _lastMessageTime) >= _keepAlivePeriod && (_controlQueue.empty() && _messageQueue.empty())) { +#ifdef ESP32 + lock.unlock(); +#endif + ping((uint8_t*)AWSC_PING_PAYLOAD, AWSC_PING_PAYLOAD_LEN); + } +} + +void AsyncWebSocketClient::_runQueue() { + // all calls to this method MUST be protected by a mutex lock! + if (!_client) + return; + + _clearQueue(); + + if (!_controlQueue.empty() && (_messageQueue.empty() || _messageQueue.front().betweenFrames()) && webSocketSendFrameWindow(_client) > (size_t)(_controlQueue.front().len() - 1)) { + _controlQueue.front().send(_client); + } else if (!_messageQueue.empty() && _messageQueue.front().betweenFrames() && webSocketSendFrameWindow(_client)) { + _messageQueue.front().send(_client); + } +} + +bool AsyncWebSocketClient::queueIsFull() const { +#ifdef ESP32 + std::lock_guard lock(_lock); +#endif + size_t size = _messageQueue.size(); + ; + return (size >= WS_MAX_QUEUED_MESSAGES) || (_status != WS_CONNECTED); +} + +size_t AsyncWebSocketClient::queueLen() const { +#ifdef ESP32 + std::lock_guard lock(_lock); +#endif + + return _messageQueue.size() + _controlQueue.size(); +} + +bool AsyncWebSocketClient::canSend() const { +#ifdef ESP32 + std::lock_guard lock(_lock); +#endif + return _messageQueue.size() < WS_MAX_QUEUED_MESSAGES; +} + +void AsyncWebSocketClient::_queueControl(uint8_t opcode, const uint8_t* data, size_t len, bool mask) { + if (!_client) + return; + + { +#ifdef ESP32 + std::lock_guard lock(_lock); +#endif + _controlQueue.emplace_back(opcode, data, len, mask); + } + + if (_client && _client->canSend()) _runQueue(); } -void AsyncWebSocketClient::_onPoll() -{ - if (!_client) - return; +void AsyncWebSocketClient::_queueMessage(AsyncWebSocketSharedBuffer buffer, uint8_t opcode, bool mask) { + if (!_client || buffer->size() == 0 || _status != WS_CONNECTED) + return; - #ifdef ESP32 - std::unique_lock lock(_lock); - #endif - if (_client->canSend() && (!_controlQueue.empty() || !_messageQueue.empty())) - { - _runQueue(); - } - else if (_keepAlivePeriod > 0 && (millis() - _lastMessageTime) >= _keepAlivePeriod && (_controlQueue.empty() && _messageQueue.empty())) - { #ifdef ESP32 - lock.unlock(); + std::lock_guard lock(_lock); #endif - ping((uint8_t *)AWSC_PING_PAYLOAD, AWSC_PING_PAYLOAD_LEN); - } -} - -void AsyncWebSocketClient::_runQueue() -{ - // all calls to this method MUST be protected by a mutex lock! - if (!_client) - return; - - _clearQueue(); - - if (!_controlQueue.empty() && (_messageQueue.empty() || _messageQueue.front().betweenFrames()) && webSocketSendFrameWindow(_client) > (size_t)(_controlQueue.front().len() - 1)) - { - _controlQueue.front().send(_client); - } - else if (!_messageQueue.empty() && _messageQueue.front().betweenFrames() && webSocketSendFrameWindow(_client)) - { - _messageQueue.front().send(_client); - } -} - -bool AsyncWebSocketClient::queueIsFull() const -{ - #ifdef ESP32 - std::lock_guard lock(_lock); - #endif - size_t size = _messageQueue.size();; - return (size >= WS_MAX_QUEUED_MESSAGES) || (_status != WS_CONNECTED); -} - -size_t AsyncWebSocketClient::queueLen() const -{ - #ifdef ESP32 - std::lock_guard lock(_lock); - #endif - - return _messageQueue.size() + _controlQueue.size(); -} - -bool AsyncWebSocketClient::canSend() const -{ - #ifdef ESP32 - std::lock_guard lock(_lock); - #endif - return _messageQueue.size() < WS_MAX_QUEUED_MESSAGES; -} - -void AsyncWebSocketClient::_queueControl(uint8_t opcode, const uint8_t *data, size_t len, bool mask) -{ - if (!_client) - return; - - { - #ifdef ESP32 - std::lock_guard lock(_lock); - #endif - _controlQueue.emplace_back(opcode, data, len, mask); - } - - if (_client && _client->canSend()) - _runQueue(); -} - -void AsyncWebSocketClient::_queueMessage(AsyncWebSocketSharedBuffer buffer, uint8_t opcode, bool mask) -{ - if(!_client || buffer->size() == 0 || _status != WS_CONNECTED) - return; - - #ifdef ESP32 - std::lock_guard lock(_lock); - #endif - if (_messageQueue.size() >= WS_MAX_QUEUED_MESSAGES) - { - if(closeWhenFull) - { + if (_messageQueue.size() >= WS_MAX_QUEUED_MESSAGES) { + if (closeWhenFull) { #ifdef ESP8266 - ets_printf("AsyncWebSocketClient::_queueMessage: Too many messages queued: closing connection\n"); + ets_printf("AsyncWebSocketClient::_queueMessage: Too many messages queued: closing connection\n"); #else - log_e("Too many messages queued: closing connection"); + log_e("Too many messages queued: closing connection"); #endif - _status = WS_DISCONNECTED; - if (_client) _client->close(true); - } else { + _status = WS_DISCONNECTED; + if (_client) + _client->close(true); + } else { #ifdef ESP8266 - ets_printf("AsyncWebSocketClient::_queueMessage: Too many messages queued: discarding new message\n"); + ets_printf("AsyncWebSocketClient::_queueMessage: Too many messages queued: discarding new message\n"); #else - log_e("Too many messages queued: discarding new message"); + log_e("Too many messages queued: discarding new message"); #endif - } - return; } - else { - _messageQueue.emplace_back(buffer, opcode, mask); + return; + } else { + _messageQueue.emplace_back(buffer, opcode, mask); + } + + if (_client && _client->canSend()) + _runQueue(); +} + +void AsyncWebSocketClient::close(uint16_t code, const char* message) { + if (_status != WS_CONNECTED) + return; + + if (code) { + uint8_t packetLen = 2; + if (message != NULL) { + size_t mlen = strlen(message); + if (mlen > 123) + mlen = 123; + packetLen += mlen; } - - if (_client && _client->canSend()) - _runQueue(); -} - -void AsyncWebSocketClient::close(uint16_t code, const char * message) -{ - if(_status != WS_CONNECTED) - return; - - if(code) - { - uint8_t packetLen = 2; - if (message != NULL) - { - size_t mlen = strlen(message); - if(mlen > 123) mlen = 123; - packetLen += mlen; - } - char * buf = (char*)malloc(packetLen); - if (buf != NULL) - { - buf[0] = (uint8_t)(code >> 8); - buf[1] = (uint8_t)(code & 0xFF); - if(message != NULL){ - memcpy(buf+2, message, packetLen -2); - } - _queueControl(WS_DISCONNECT, (uint8_t*)buf, packetLen); - free(buf); - return; - } + char* buf = (char*)malloc(packetLen); + if (buf != NULL) { + buf[0] = (uint8_t)(code >> 8); + buf[1] = (uint8_t)(code & 0xFF); + if (message != NULL) { + memcpy(buf + 2, message, packetLen - 2); + } + _queueControl(WS_DISCONNECT, (uint8_t*)buf, packetLen); + free(buf); + return; } - _queueControl(WS_DISCONNECT); + } + _queueControl(WS_DISCONNECT); } -void AsyncWebSocketClient::ping(const uint8_t *data, size_t len) -{ - if (_status == WS_CONNECTED) - _queueControl(WS_PING, data, len); +void AsyncWebSocketClient::ping(const uint8_t* data, size_t len) { + if (_status == WS_CONNECTED) + _queueControl(WS_PING, data, len); } -void AsyncWebSocketClient::_onError(int8_t) -{ - //Serial.println("onErr"); +void AsyncWebSocketClient::_onError(int8_t) { + // Serial.println("onErr"); } -void AsyncWebSocketClient::_onTimeout(uint32_t time) -{ - // Serial.println("onTime"); - (void)time; - _client->close(true); +void AsyncWebSocketClient::_onTimeout(uint32_t time) { + // Serial.println("onTime"); + (void)time; + _client->close(true); } -void AsyncWebSocketClient::_onDisconnect() -{ - // Serial.println("onDis"); - _client = NULL; +void AsyncWebSocketClient::_onDisconnect() { + // Serial.println("onDis"); + _client = NULL; } -void AsyncWebSocketClient::_onData(void *pbuf, size_t plen) -{ +void AsyncWebSocketClient::_onData(void* pbuf, size_t plen) { // Serial.println("onData"); _lastMessageTime = millis(); - uint8_t *data = (uint8_t*)pbuf; - while(plen > 0){ - if(!_pstate){ - const uint8_t *fdata = data; + uint8_t* data = (uint8_t*)pbuf; + while (plen > 0) { + if (!_pstate) { + const uint8_t* fdata = data; _pinfo.index = 0; _pinfo.final = (fdata[0] & 0x80) != 0; _pinfo.opcode = fdata[0] & 0x0F; @@ -545,17 +500,17 @@ void AsyncWebSocketClient::_onData(void *pbuf, size_t plen) _pinfo.len = fdata[1] & 0x7F; data += 2; plen -= 2; - if(_pinfo.len == 126){ + if (_pinfo.len == 126) { _pinfo.len = fdata[3] | (uint16_t)(fdata[2]) << 8; data += 2; plen -= 2; - } else if(_pinfo.len == 127){ + } else if (_pinfo.len == 127) { _pinfo.len = fdata[9] | (uint16_t)(fdata[8]) << 8 | (uint32_t)(fdata[7]) << 16 | (uint32_t)(fdata[6]) << 24 | (uint64_t)(fdata[5]) << 32 | (uint64_t)(fdata[4]) << 40 | (uint64_t)(fdata[3]) << 48 | (uint64_t)(fdata[2]) << 56; data += 8; plen -= 8; } - if(_pinfo.masked){ + if (_pinfo.masked) { memcpy(_pinfo.mask, data, 4); data += 4; plen -= 4; @@ -565,34 +520,35 @@ void AsyncWebSocketClient::_onData(void *pbuf, size_t plen) const size_t datalen = std::min((size_t)(_pinfo.len - _pinfo.index), plen); const auto datalast = data[datalen]; - if(_pinfo.masked){ - for(size_t i=0;i 0) _server->_handleEvent(this, WS_EVT_DATA, (void *)&_pinfo, (uint8_t*)data, datalen); + if (datalen > 0) + _server->_handleEvent(this, WS_EVT_DATA, (void*)&_pinfo, (uint8_t*)data, datalen); _pinfo.index += datalen; - } else if((datalen + _pinfo.index) == _pinfo.len){ + } else if ((datalen + _pinfo.index) == _pinfo.len) { _pstate = 0; - if(_pinfo.opcode == WS_DISCONNECT){ - if(datalen){ + if (_pinfo.opcode == WS_DISCONNECT) { + if (datalen) { uint16_t reasonCode = (uint16_t)(data[0] << 8) + data[1]; - char * reasonString = (char*)(data+2); - if(reasonCode > 1001){ - _server->_handleEvent(this, WS_EVT_ERROR, (void *)&reasonCode, (uint8_t*)reasonString, strlen(reasonString)); + char* reasonString = (char*)(data + 2); + if (reasonCode > 1001) { + _server->_handleEvent(this, WS_EVT_ERROR, (void*)&reasonCode, (uint8_t*)reasonString, strlen(reasonString)); } } - if(_status == WS_DISCONNECTING){ + if (_status == WS_DISCONNECTING) { _status = WS_DISCONNECTED; _client->close(true); } else { @@ -600,19 +556,21 @@ void AsyncWebSocketClient::_onData(void *pbuf, size_t plen) _client->ackLater(); _queueControl(WS_DISCONNECT, data, datalen); } - } else if(_pinfo.opcode == WS_PING){ + } else if (_pinfo.opcode == WS_PING) { _queueControl(WS_PONG, data, datalen); - } else if(_pinfo.opcode == WS_PONG){ - if(datalen != AWSC_PING_PAYLOAD_LEN || memcmp(AWSC_PING_PAYLOAD, data, AWSC_PING_PAYLOAD_LEN) != 0) + } else if (_pinfo.opcode == WS_PONG) { + if (datalen != AWSC_PING_PAYLOAD_LEN || memcmp(AWSC_PING_PAYLOAD, data, AWSC_PING_PAYLOAD_LEN) != 0) _server->_handleEvent(this, WS_EVT_PONG, NULL, data, datalen); - } else if(_pinfo.opcode < 8){//continuation or text/binary frame - _server->_handleEvent(this, WS_EVT_DATA, (void *)&_pinfo, data, datalen); - if (_pinfo.final) _pinfo.num = 0; - else _pinfo.num += 1; + } else if (_pinfo.opcode < 8) { // continuation or text/binary frame + _server->_handleEvent(this, WS_EVT_DATA, (void*)&_pinfo, data, datalen); + if (_pinfo.final) + _pinfo.num = 0; + else + _pinfo.num += 1; } } else { - //os_printf("frame error: len: %u, index: %llu, total: %llu\n", datalen, _pinfo.index, _pinfo.len); - //what should we do? + // os_printf("frame error: len: %u, index: %llu, total: %llu\n", datalen, _pinfo.index, _pinfo.len); + // what should we do? break; } @@ -625,12 +583,11 @@ void AsyncWebSocketClient::_onData(void *pbuf, size_t plen) } } -size_t AsyncWebSocketClient::printf(const char *format, ...) -{ +size_t AsyncWebSocketClient::printf(const char* format, ...) { va_list arg; va_start(arg, format); char* temp = new char[MAX_PRINTF_LEN]; - if(!temp){ + if (!temp) { va_end(arg); return 0; } @@ -641,7 +598,7 @@ size_t AsyncWebSocketClient::printf(const char *format, ...) if (len > (MAX_PRINTF_LEN - 1)) { buffer = new char[len + 1]; if (!buffer) { - delete[] temp; + delete[] temp; return 0; } va_start(arg, format); @@ -657,12 +614,11 @@ size_t AsyncWebSocketClient::printf(const char *format, ...) } #ifndef ESP32 -size_t AsyncWebSocketClient::printf_P(PGM_P formatP, ...) -{ +size_t AsyncWebSocketClient::printf_P(PGM_P formatP, ...) { va_list arg; va_start(arg, formatP); char* temp = new char[MAX_PRINTF_LEN]; - if(!temp){ + if (!temp) { va_end(arg); return 0; } @@ -673,7 +629,7 @@ size_t AsyncWebSocketClient::printf_P(PGM_P formatP, ...) if (len > (MAX_PRINTF_LEN - 1)) { buffer = new char[len + 1]; if (!buffer) { - delete[] temp; + delete[] temp; return 0; } va_start(arg, formatP); @@ -690,453 +646,381 @@ size_t AsyncWebSocketClient::printf_P(PGM_P formatP, ...) #endif namespace { -AsyncWebSocketSharedBuffer makeSharedBuffer(const uint8_t *message, size_t len) -{ + AsyncWebSocketSharedBuffer makeSharedBuffer(const uint8_t* message, size_t len) { auto buffer = std::make_shared>(len); std::memcpy(buffer->data(), message, len); return buffer; -} + } } -void AsyncWebSocketClient::text(AsyncWebSocketMessageBuffer * buffer) -{ - if (buffer) { - text(std::move(buffer->_buffer)); - delete buffer; - } +void AsyncWebSocketClient::text(AsyncWebSocketMessageBuffer* buffer) { + if (buffer) { + text(std::move(buffer->_buffer)); + delete buffer; + } } -void AsyncWebSocketClient::text(AsyncWebSocketSharedBuffer buffer) -{ - _queueMessage(buffer); +void AsyncWebSocketClient::text(AsyncWebSocketSharedBuffer buffer) { + _queueMessage(buffer); } -void AsyncWebSocketClient::text(const uint8_t *message, size_t len) -{ - text(makeSharedBuffer(message, len)); +void AsyncWebSocketClient::text(const uint8_t* message, size_t len) { + text(makeSharedBuffer(message, len)); } -void AsyncWebSocketClient::text(const char *message, size_t len) -{ - text((const uint8_t *)message, len); +void AsyncWebSocketClient::text(const char* message, size_t len) { + text((const uint8_t*)message, len); } -void AsyncWebSocketClient::text(const char *message) -{ - text(message, strlen(message)); +void AsyncWebSocketClient::text(const char* message) { + text(message, strlen(message)); } -void AsyncWebSocketClient::text(const String &message) -{ - text(message.c_str(), message.length()); +void AsyncWebSocketClient::text(const String& message) { + text(message.c_str(), message.length()); } #ifndef ESP32 -void AsyncWebSocketClient::text(const __FlashStringHelper *data) -{ - PGM_P p = reinterpret_cast(data); +void AsyncWebSocketClient::text(const __FlashStringHelper* data) { + PGM_P p = reinterpret_cast(data); - size_t n = 0; - while (1) - { - if (pgm_read_byte(p+n) == 0) break; - n += 1; - } + size_t n = 0; + while (1) { + if (pgm_read_byte(p + n) == 0) + break; + n += 1; + } - char * message = (char*) malloc(n+1); - if(message) - { - memcpy_P(message, p, n); - message[n] = 0; - text(message, n); - free(message); - } + char* message = (char*)malloc(n + 1); + if (message) { + memcpy_P(message, p, n); + message[n] = 0; + text(message, n); + free(message); + } } -#endif // ESP32 +#endif // ESP32 -void AsyncWebSocketClient::binary(AsyncWebSocketMessageBuffer * buffer) -{ - if (buffer) { - binary(std::move(buffer->_buffer)); - delete buffer; - } +void AsyncWebSocketClient::binary(AsyncWebSocketMessageBuffer* buffer) { + if (buffer) { + binary(std::move(buffer->_buffer)); + delete buffer; + } } -void AsyncWebSocketClient::binary(AsyncWebSocketSharedBuffer buffer) -{ - _queueMessage(buffer, WS_BINARY); +void AsyncWebSocketClient::binary(AsyncWebSocketSharedBuffer buffer) { + _queueMessage(buffer, WS_BINARY); } -void AsyncWebSocketClient::binary(const uint8_t *message, size_t len) -{ - binary(makeSharedBuffer(message, len)); +void AsyncWebSocketClient::binary(const uint8_t* message, size_t len) { + binary(makeSharedBuffer(message, len)); } -void AsyncWebSocketClient::binary(const char *message, size_t len) -{ - binary((const uint8_t *)message, len); +void AsyncWebSocketClient::binary(const char* message, size_t len) { + binary((const uint8_t*)message, len); } -void AsyncWebSocketClient::binary(const char *message) -{ - binary(message, strlen(message)); +void AsyncWebSocketClient::binary(const char* message) { + binary(message, strlen(message)); } -void AsyncWebSocketClient::binary(const String &message) -{ - binary(message.c_str(), message.length()); +void AsyncWebSocketClient::binary(const String& message) { + binary(message.c_str(), message.length()); } #ifndef ESP32 -void AsyncWebSocketClient::binary(const __FlashStringHelper *data, size_t len) -{ - PGM_P p = reinterpret_cast(data); - char *message = (char*) malloc(len); - if (message) { - memcpy_P(message, p, len); - binary(message, len); - free(message); - } +void AsyncWebSocketClient::binary(const __FlashStringHelper* data, size_t len) { + PGM_P p = reinterpret_cast(data); + char* message = (char*)malloc(len); + if (message) { + memcpy_P(message, p, len); + binary(message, len); + free(message); + } } #endif -IPAddress AsyncWebSocketClient::remoteIP() const -{ - if (!_client) - return IPAddress((uint32_t)0U); +IPAddress AsyncWebSocketClient::remoteIP() const { + if (!_client) + return IPAddress((uint32_t)0U); - return _client->remoteIP(); + return _client->remoteIP(); } -uint16_t AsyncWebSocketClient::remotePort() const -{ - if(!_client) - return 0; +uint16_t AsyncWebSocketClient::remotePort() const { + if (!_client) + return 0; - return _client->remotePort(); + return _client->remotePort(); } - - /* * Async Web Socket - Each separate socket location */ -void AsyncWebSocket::_handleEvent(AsyncWebSocketClient * client, AwsEventType type, void * arg, uint8_t *data, size_t len){ - if(_eventHandler != NULL){ +void AsyncWebSocket::_handleEvent(AsyncWebSocketClient* client, AwsEventType type, void* arg, uint8_t* data, size_t len) { + if (_eventHandler != NULL) { _eventHandler(this, client, type, arg, data, len); } } -AsyncWebSocketClient *AsyncWebSocket::_newClient(AsyncWebServerRequest *request) -{ - _clients.emplace_back(request, this); - return &_clients.back(); +AsyncWebSocketClient* AsyncWebSocket::_newClient(AsyncWebServerRequest* request) { + _clients.emplace_back(request, this); + return &_clients.back(); } -bool AsyncWebSocket::availableForWriteAll() -{ - return std::none_of(std::begin(_clients), std::end(_clients), - [](const AsyncWebSocketClient &c){ return c.queueIsFull(); }); +bool AsyncWebSocket::availableForWriteAll() { + return std::none_of(std::begin(_clients), std::end(_clients), [](const AsyncWebSocketClient& c) { return c.queueIsFull(); }); } -bool AsyncWebSocket::availableForWrite(uint32_t id) -{ - const auto iter = std::find_if(std::begin(_clients), std::end(_clients), - [id](const AsyncWebSocketClient &c){ return c.id() == id; }); - if (iter == std::end(_clients)) - return true; - return !iter->queueIsFull(); +bool AsyncWebSocket::availableForWrite(uint32_t id) { + const auto iter = std::find_if(std::begin(_clients), std::end(_clients), [id](const AsyncWebSocketClient& c) { return c.id() == id; }); + if (iter == std::end(_clients)) + return true; + return !iter->queueIsFull(); } -size_t AsyncWebSocket::count() const -{ - return std::count_if(std::begin(_clients), std::end(_clients), - [](const AsyncWebSocketClient &c){ return c.status() == WS_CONNECTED; }); +size_t AsyncWebSocket::count() const { + return std::count_if(std::begin(_clients), std::end(_clients), [](const AsyncWebSocketClient& c) { return c.status() == WS_CONNECTED; }); } -AsyncWebSocketClient * AsyncWebSocket::client(uint32_t id) -{ - const auto iter = std::find_if(_clients.begin(), _clients.end(), - [id](const AsyncWebSocketClient &c){ return c.id() == id && c.status() == WS_CONNECTED; }); - if (iter == std::end(_clients)) - return nullptr; +AsyncWebSocketClient* AsyncWebSocket::client(uint32_t id) { + const auto iter = std::find_if(_clients.begin(), _clients.end(), [id](const AsyncWebSocketClient& c) { return c.id() == id && c.status() == WS_CONNECTED; }); + if (iter == std::end(_clients)) + return nullptr; - return &(*iter); + return &(*iter); } - -void AsyncWebSocket::close(uint32_t id, uint16_t code, const char * message) -{ - if (AsyncWebSocketClient *c = client(id)) - c->close(code, message); +void AsyncWebSocket::close(uint32_t id, uint16_t code, const char* message) { + if (AsyncWebSocketClient* c = client(id)) + c->close(code, message); } -void AsyncWebSocket::closeAll(uint16_t code, const char * message) -{ - for (auto &c : _clients) - if (c.status() == WS_CONNECTED) - c.close(code, message); +void AsyncWebSocket::closeAll(uint16_t code, const char* message) { + for (auto& c : _clients) + if (c.status() == WS_CONNECTED) + c.close(code, message); } -void AsyncWebSocket::cleanupClients(uint16_t maxClients) -{ - if (count() > maxClients) - _clients.front().close(); +void AsyncWebSocket::cleanupClients(uint16_t maxClients) { + if (count() > maxClients) + _clients.front().close(); - for (auto iter = std::begin(_clients); iter != std::end(_clients);) - { - if (iter->shouldBeDeleted()) - iter = _clients.erase(iter); - else - iter++; - } + for (auto iter = std::begin(_clients); iter != std::end(_clients);) { + if (iter->shouldBeDeleted()) + iter = _clients.erase(iter); + else + iter++; + } } -void AsyncWebSocket::ping(uint32_t id, const uint8_t *data, size_t len) -{ - if (AsyncWebSocketClient * c = client(id)) - c->ping(data, len); +void AsyncWebSocket::ping(uint32_t id, const uint8_t* data, size_t len) { + if (AsyncWebSocketClient* c = client(id)) + c->ping(data, len); } -void AsyncWebSocket::pingAll(const uint8_t *data, size_t len) -{ - for (auto &c : _clients) - if (c.status() == WS_CONNECTED) - c.ping(data, len); +void AsyncWebSocket::pingAll(const uint8_t* data, size_t len) { + for (auto& c : _clients) + if (c.status() == WS_CONNECTED) + c.ping(data, len); } -void AsyncWebSocket::text(uint32_t id, const uint8_t *message, size_t len) -{ - if (AsyncWebSocketClient * c = client(id)) - c->text(makeSharedBuffer(message, len)); +void AsyncWebSocket::text(uint32_t id, const uint8_t* message, size_t len) { + if (AsyncWebSocketClient* c = client(id)) + c->text(makeSharedBuffer(message, len)); } -void AsyncWebSocket::text(uint32_t id, const char *message, size_t len) -{ - text(id, (const uint8_t *)message, len); +void AsyncWebSocket::text(uint32_t id, const char* message, size_t len) { + text(id, (const uint8_t*)message, len); } -void AsyncWebSocket::text(uint32_t id, const char * message) -{ - text(id, message, strlen(message)); +void AsyncWebSocket::text(uint32_t id, const char* message) { + text(id, message, strlen(message)); } -void AsyncWebSocket::text(uint32_t id, const String &message) -{ - text(id, message.c_str(), message.length()); +void AsyncWebSocket::text(uint32_t id, const String& message) { + text(id, message.c_str(), message.length()); } #ifndef ESP32 -void AsyncWebSocket::text(uint32_t id, const __FlashStringHelper *data) -{ - PGM_P p = reinterpret_cast(data); +void AsyncWebSocket::text(uint32_t id, const __FlashStringHelper* data) { + PGM_P p = reinterpret_cast(data); - size_t n = 0; - while (true) - { - if (pgm_read_byte(p+n) == 0) - break; - n += 1; - } + size_t n = 0; + while (true) { + if (pgm_read_byte(p + n) == 0) + break; + n += 1; + } - char * message = (char*) malloc(n+1); - if (message) - { - memcpy_P(message, p, n); - message[n] = 0; - text(id, message, n); - free(message); - } + char* message = (char*)malloc(n + 1); + if (message) { + memcpy_P(message, p, n); + message[n] = 0; + text(id, message, n); + free(message); + } } -#endif // ESP32 -void AsyncWebSocket::text(uint32_t id, AsyncWebSocketMessageBuffer *buffer) -{ - if (buffer) { - text(id, std::move(buffer->_buffer)); - delete buffer; - } +#endif // ESP32 +void AsyncWebSocket::text(uint32_t id, AsyncWebSocketMessageBuffer* buffer) { + if (buffer) { + text(id, std::move(buffer->_buffer)); + delete buffer; + } } -void AsyncWebSocket::text(uint32_t id, AsyncWebSocketSharedBuffer buffer) -{ - if (AsyncWebSocketClient *c = client(id)) - c->text(buffer); +void AsyncWebSocket::text(uint32_t id, AsyncWebSocketSharedBuffer buffer) { + if (AsyncWebSocketClient* c = client(id)) + c->text(buffer); } -void AsyncWebSocket::textAll(const uint8_t *message, size_t len) -{ - textAll(makeSharedBuffer(message, len)); +void AsyncWebSocket::textAll(const uint8_t* message, size_t len) { + textAll(makeSharedBuffer(message, len)); } -void AsyncWebSocket::textAll(const char * message, size_t len) -{ - textAll((const uint8_t *)message, len); +void AsyncWebSocket::textAll(const char* message, size_t len) { + textAll((const uint8_t*)message, len); } -void AsyncWebSocket::textAll(const char *message) -{ - textAll(message, strlen(message)); +void AsyncWebSocket::textAll(const char* message) { + textAll(message, strlen(message)); } -void AsyncWebSocket::textAll(const String &message) -{ - textAll(message.c_str(), message.length()); +void AsyncWebSocket::textAll(const String& message) { + textAll(message.c_str(), message.length()); } #ifndef ESP32 -void AsyncWebSocket::textAll(const __FlashStringHelper *data) -{ - PGM_P p = reinterpret_cast(data); +void AsyncWebSocket::textAll(const __FlashStringHelper* data) { + PGM_P p = reinterpret_cast(data); - size_t n = 0; - while (1) - { - if (pgm_read_byte(p+n) == 0) break; - n += 1; - } + size_t n = 0; + while (1) { + if (pgm_read_byte(p + n) == 0) + break; + n += 1; + } - char *message = (char*)malloc(n+1); - if(message) - { - memcpy_P(message, p, n); - message[n] = 0; - textAll(message, n); - free(message); - } + char* message = (char*)malloc(n + 1); + if (message) { + memcpy_P(message, p, n); + message[n] = 0; + textAll(message, n); + free(message); + } } -#endif // ESP32 -void AsyncWebSocket::textAll(AsyncWebSocketMessageBuffer * buffer) -{ - if (buffer) { - textAll(std::move(buffer->_buffer)); - delete buffer; - } +#endif // ESP32 +void AsyncWebSocket::textAll(AsyncWebSocketMessageBuffer* buffer) { + if (buffer) { + textAll(std::move(buffer->_buffer)); + delete buffer; + } } -void AsyncWebSocket::textAll(AsyncWebSocketSharedBuffer buffer) -{ - for (auto &c : _clients) - if (c.status() == WS_CONNECTED) - c.text(buffer); +void AsyncWebSocket::textAll(AsyncWebSocketSharedBuffer buffer) { + for (auto& c : _clients) + if (c.status() == WS_CONNECTED) + c.text(buffer); } -void AsyncWebSocket::binary(uint32_t id, const uint8_t *message, size_t len) -{ - if (AsyncWebSocketClient *c = client(id)) - c->binary(makeSharedBuffer(message, len)); +void AsyncWebSocket::binary(uint32_t id, const uint8_t* message, size_t len) { + if (AsyncWebSocketClient* c = client(id)) + c->binary(makeSharedBuffer(message, len)); } -void AsyncWebSocket::binary(uint32_t id, const char * message, size_t len) -{ - binary(id, (const uint8_t *)message, len); +void AsyncWebSocket::binary(uint32_t id, const char* message, size_t len) { + binary(id, (const uint8_t*)message, len); } -void AsyncWebSocket::binary(uint32_t id, const char * message) -{ - binary(id, message, strlen(message)); +void AsyncWebSocket::binary(uint32_t id, const char* message) { + binary(id, message, strlen(message)); } -void AsyncWebSocket::binary(uint32_t id, const String &message) -{ - binary(id, message.c_str(), message.length()); +void AsyncWebSocket::binary(uint32_t id, const String& message) { + binary(id, message.c_str(), message.length()); } #ifndef ESP32 -void AsyncWebSocket::binary(uint32_t id, const __FlashStringHelper *data, size_t len) -{ - PGM_P p = reinterpret_cast(data); - char *message = (char*) malloc(len); - if (message) - { - memcpy_P(message, p, len); - binary(id, message, len); - free(message); - } +void AsyncWebSocket::binary(uint32_t id, const __FlashStringHelper* data, size_t len) { + PGM_P p = reinterpret_cast(data); + char* message = (char*)malloc(len); + if (message) { + memcpy_P(message, p, len); + binary(id, message, len); + free(message); + } } -#endif // ESP32 -void AsyncWebSocket::binary(uint32_t id, AsyncWebSocketMessageBuffer *buffer) -{ - if (buffer) { - binary(id, std::move(buffer->_buffer)); - delete buffer; - } +#endif // ESP32 +void AsyncWebSocket::binary(uint32_t id, AsyncWebSocketMessageBuffer* buffer) { + if (buffer) { + binary(id, std::move(buffer->_buffer)); + delete buffer; + } } -void AsyncWebSocket::binary(uint32_t id, AsyncWebSocketSharedBuffer buffer) -{ - if (AsyncWebSocketClient *c = client(id)) - c->binary(buffer); +void AsyncWebSocket::binary(uint32_t id, AsyncWebSocketSharedBuffer buffer) { + if (AsyncWebSocketClient* c = client(id)) + c->binary(buffer); } - -void AsyncWebSocket::binaryAll(const uint8_t *message, size_t len) -{ - binaryAll(makeSharedBuffer(message, len)); +void AsyncWebSocket::binaryAll(const uint8_t* message, size_t len) { + binaryAll(makeSharedBuffer(message, len)); } -void AsyncWebSocket::binaryAll(const char *message, size_t len) -{ - binaryAll((const uint8_t *)message, len); +void AsyncWebSocket::binaryAll(const char* message, size_t len) { + binaryAll((const uint8_t*)message, len); } -void AsyncWebSocket::binaryAll(const char *message) -{ - binaryAll(message, strlen(message)); +void AsyncWebSocket::binaryAll(const char* message) { + binaryAll(message, strlen(message)); } -void AsyncWebSocket::binaryAll(const String &message) -{ - binaryAll(message.c_str(), message.length()); +void AsyncWebSocket::binaryAll(const String& message) { + binaryAll(message.c_str(), message.length()); } #ifndef ESP32 -void AsyncWebSocket::binaryAll(const __FlashStringHelper *data, size_t len) -{ - PGM_P p = reinterpret_cast(data); - char * message = (char*) malloc(len); - if(message) - { - memcpy_P(message, p, len); - binaryAll(message, len); - free(message); - } +void AsyncWebSocket::binaryAll(const __FlashStringHelper* data, size_t len) { + PGM_P p = reinterpret_cast(data); + char* message = (char*)malloc(len); + if (message) { + memcpy_P(message, p, len); + binaryAll(message, len); + free(message); + } } -#endif // ESP32 -void AsyncWebSocket::binaryAll(AsyncWebSocketMessageBuffer * buffer) -{ - if (buffer) { - binaryAll(std::move(buffer->_buffer)); - delete buffer; - } +#endif // ESP32 +void AsyncWebSocket::binaryAll(AsyncWebSocketMessageBuffer* buffer) { + if (buffer) { + binaryAll(std::move(buffer->_buffer)); + delete buffer; + } } -void AsyncWebSocket::binaryAll(AsyncWebSocketSharedBuffer buffer) -{ - for (auto &c : _clients) - if (c.status() == WS_CONNECTED) - c.binary(buffer); +void AsyncWebSocket::binaryAll(AsyncWebSocketSharedBuffer buffer) { + for (auto& c : _clients) + if (c.status() == WS_CONNECTED) + c.binary(buffer); } -size_t AsyncWebSocket::printf(uint32_t id, const char *format, ...){ - AsyncWebSocketClient * c = client(id); - if (c) - { - va_list arg; - va_start(arg, format); - size_t len = c->printf(format, arg); - va_end(arg); - return len; - } - return 0; -} - -size_t AsyncWebSocket::printfAll(const char *format, ...) -{ +size_t AsyncWebSocket::printf(uint32_t id, const char* format, ...) { + AsyncWebSocketClient* c = client(id); + if (c) { va_list arg; - char *temp = new char[MAX_PRINTF_LEN]; - if (!temp) - return 0; - va_start(arg, format); - size_t len = vsnprintf(temp, MAX_PRINTF_LEN, format, arg); + size_t len = c->printf(format, arg); va_end(arg); - delete[] temp; - - AsyncWebSocketSharedBuffer buffer = std::make_shared>(len); - - va_start(arg, format); - vsnprintf( (char *)buffer->data(), len + 1, format, arg); - va_end(arg); - - textAll(buffer); return len; + } + return 0; +} + +size_t AsyncWebSocket::printfAll(const char* format, ...) { + va_list arg; + char* temp = new char[MAX_PRINTF_LEN]; + if (!temp) + return 0; + + va_start(arg, format); + size_t len = vsnprintf(temp, MAX_PRINTF_LEN, format, arg); + va_end(arg); + delete[] temp; + + AsyncWebSocketSharedBuffer buffer = std::make_shared>(len); + + va_start(arg, format); + vsnprintf((char*)buffer->data(), len + 1, format, arg); + va_end(arg); + + textAll(buffer); + return len; } #ifndef ESP32 -size_t AsyncWebSocket::printf_P(uint32_t id, PGM_P formatP, ...){ - AsyncWebSocketClient * c = client(id); - if(c != NULL){ +size_t AsyncWebSocket::printf_P(uint32_t id, PGM_P formatP, ...) { + AsyncWebSocketClient* c = client(id); + if (c != NULL) { va_list arg; va_start(arg, formatP); size_t len = c->printf_P(formatP, arg); @@ -1146,126 +1030,116 @@ size_t AsyncWebSocket::printf_P(uint32_t id, PGM_P formatP, ...){ return 0; } -size_t AsyncWebSocket::printfAll_P(PGM_P formatP, ...) -{ - va_list arg; - char *temp = new char[MAX_PRINTF_LEN]; - if (!temp) - return 0; +size_t AsyncWebSocket::printfAll_P(PGM_P formatP, ...) { + va_list arg; + char* temp = new char[MAX_PRINTF_LEN]; + if (!temp) + return 0; - va_start(arg, formatP); - size_t len = vsnprintf_P(temp, MAX_PRINTF_LEN, formatP, arg); - va_end(arg); - delete[] temp; + va_start(arg, formatP); + size_t len = vsnprintf_P(temp, MAX_PRINTF_LEN, formatP, arg); + va_end(arg); + delete[] temp; - AsyncWebSocketSharedBuffer buffer = std::make_shared>(len + 1); + AsyncWebSocketSharedBuffer buffer = std::make_shared>(len + 1); - va_start(arg, formatP); - vsnprintf_P((char *)buffer->data(), len + 1, formatP, arg); - va_end(arg); + va_start(arg, formatP); + vsnprintf_P((char*)buffer->data(), len + 1, formatP, arg); + va_end(arg); - textAll(buffer); - return len; + textAll(buffer); + return len; } #endif -const char __WS_STR_CONNECTION[] PROGMEM = { "Connection" }; -const char __WS_STR_UPGRADE[] PROGMEM = { "Upgrade" }; -const char __WS_STR_ORIGIN[] PROGMEM = { "Origin" }; -const char __WS_STR_COOKIE[] PROGMEM = { "Cookie" }; -const char __WS_STR_VERSION[] PROGMEM = { "Sec-WebSocket-Version" }; -const char __WS_STR_KEY[] PROGMEM = { "Sec-WebSocket-Key" }; -const char __WS_STR_PROTOCOL[] PROGMEM = { "Sec-WebSocket-Protocol" }; -const char __WS_STR_ACCEPT[] PROGMEM = { "Sec-WebSocket-Accept" }; -const char __WS_STR_UUID[] PROGMEM = { "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" }; +const char __WS_STR_CONNECTION[] PROGMEM = {"Connection"}; +const char __WS_STR_UPGRADE[] PROGMEM = {"Upgrade"}; +const char __WS_STR_ORIGIN[] PROGMEM = {"Origin"}; +const char __WS_STR_COOKIE[] PROGMEM = {"Cookie"}; +const char __WS_STR_VERSION[] PROGMEM = {"Sec-WebSocket-Version"}; +const char __WS_STR_KEY[] PROGMEM = {"Sec-WebSocket-Key"}; +const char __WS_STR_PROTOCOL[] PROGMEM = {"Sec-WebSocket-Protocol"}; +const char __WS_STR_ACCEPT[] PROGMEM = {"Sec-WebSocket-Accept"}; +const char __WS_STR_UUID[] PROGMEM = {"258EAFA5-E914-47DA-95CA-C5AB0DC85B11"}; #define WS_STR_UUID_LEN 36 #define WS_STR_CONNECTION FPSTR(__WS_STR_CONNECTION) -#define WS_STR_UPGRADE FPSTR(__WS_STR_UPGRADE) -#define WS_STR_ORIGIN FPSTR(__WS_STR_ORIGIN) -#define WS_STR_COOKIE FPSTR(__WS_STR_COOKIE) -#define WS_STR_VERSION FPSTR(__WS_STR_VERSION) -#define WS_STR_KEY FPSTR(__WS_STR_KEY) -#define WS_STR_PROTOCOL FPSTR(__WS_STR_PROTOCOL) -#define WS_STR_ACCEPT FPSTR(__WS_STR_ACCEPT) -#define WS_STR_UUID FPSTR(__WS_STR_UUID) +#define WS_STR_UPGRADE FPSTR(__WS_STR_UPGRADE) +#define WS_STR_ORIGIN FPSTR(__WS_STR_ORIGIN) +#define WS_STR_COOKIE FPSTR(__WS_STR_COOKIE) +#define WS_STR_VERSION FPSTR(__WS_STR_VERSION) +#define WS_STR_KEY FPSTR(__WS_STR_KEY) +#define WS_STR_PROTOCOL FPSTR(__WS_STR_PROTOCOL) +#define WS_STR_ACCEPT FPSTR(__WS_STR_ACCEPT) +#define WS_STR_UUID FPSTR(__WS_STR_UUID) -bool AsyncWebSocket::canHandle(AsyncWebServerRequest *request){ - if(!_enabled) - return false; +bool AsyncWebSocket::canHandle(AsyncWebServerRequest* request) { + if (!_enabled) + return false; - if(request->method() != HTTP_GET || !request->url().equals(_url) || !request->isExpectedRequestedConnType(RCT_WS)) - return false; + if (request->method() != HTTP_GET || !request->url().equals(_url) || !request->isExpectedRequestedConnType(RCT_WS)) + return false; - request->addInterestingHeader(WS_STR_CONNECTION); - request->addInterestingHeader(WS_STR_UPGRADE); - request->addInterestingHeader(WS_STR_ORIGIN); - request->addInterestingHeader(WS_STR_COOKIE); - request->addInterestingHeader(WS_STR_VERSION); - request->addInterestingHeader(WS_STR_KEY); - request->addInterestingHeader(WS_STR_PROTOCOL); - return true; + request->addInterestingHeader(WS_STR_CONNECTION); + request->addInterestingHeader(WS_STR_UPGRADE); + request->addInterestingHeader(WS_STR_ORIGIN); + request->addInterestingHeader(WS_STR_COOKIE); + request->addInterestingHeader(WS_STR_VERSION); + request->addInterestingHeader(WS_STR_KEY); + request->addInterestingHeader(WS_STR_PROTOCOL); + return true; } -void AsyncWebSocket::handleRequest(AsyncWebServerRequest *request) -{ - if (!request->hasHeader(WS_STR_VERSION) || !request->hasHeader(WS_STR_KEY)) - { - request->send(400); - return; - } - if ((_username.length() && _password.length()) && !request->authenticate(_username.c_str(), _password.c_str())) - { - return request->requestAuthentication(); - } - if (_handshakeHandler != nullptr){ - if(!_handshakeHandler(request)){ - request->send(401); - return; - } - } - const AsyncWebHeader* version = request->getHeader(WS_STR_VERSION); - if (version->value().toInt() != 13) - { - AsyncWebServerResponse *response = request->beginResponse(400); - response->addHeader(WS_STR_VERSION, F("13")); - request->send(response); - return; - } - const AsyncWebHeader* key = request->getHeader(WS_STR_KEY); - AsyncWebServerResponse *response = new AsyncWebSocketResponse(key->value(), this); - if (request->hasHeader(WS_STR_PROTOCOL)) - { - const AsyncWebHeader* protocol = request->getHeader(WS_STR_PROTOCOL); - //ToDo: check protocol - response->addHeader(WS_STR_PROTOCOL, protocol->value()); +void AsyncWebSocket::handleRequest(AsyncWebServerRequest* request) { + if (!request->hasHeader(WS_STR_VERSION) || !request->hasHeader(WS_STR_KEY)) { + request->send(400); + return; + } + if ((_username.length() && _password.length()) && !request->authenticate(_username.c_str(), _password.c_str())) { + return request->requestAuthentication(); + } + if (_handshakeHandler != nullptr) { + if (!_handshakeHandler(request)) { + request->send(401); + return; } + } + const AsyncWebHeader* version = request->getHeader(WS_STR_VERSION); + if (version->value().toInt() != 13) { + AsyncWebServerResponse* response = request->beginResponse(400); + response->addHeader(WS_STR_VERSION, F("13")); request->send(response); + return; + } + const AsyncWebHeader* key = request->getHeader(WS_STR_KEY); + AsyncWebServerResponse* response = new AsyncWebSocketResponse(key->value(), this); + if (request->hasHeader(WS_STR_PROTOCOL)) { + const AsyncWebHeader* protocol = request->getHeader(WS_STR_PROTOCOL); + // ToDo: check protocol + response->addHeader(WS_STR_PROTOCOL, protocol->value()); + } + request->send(response); } -AsyncWebSocketMessageBuffer * AsyncWebSocket::makeBuffer(size_t size) -{ - AsyncWebSocketMessageBuffer * buffer = new AsyncWebSocketMessageBuffer(size); - if (buffer->length() != size) - { - delete buffer; - return nullptr; - } else { - return buffer; - } +AsyncWebSocketMessageBuffer* AsyncWebSocket::makeBuffer(size_t size) { + AsyncWebSocketMessageBuffer* buffer = new AsyncWebSocketMessageBuffer(size); + if (buffer->length() != size) { + delete buffer; + return nullptr; + } else { + return buffer; + } } -AsyncWebSocketMessageBuffer * AsyncWebSocket::makeBuffer(const uint8_t * data, size_t size) -{ - AsyncWebSocketMessageBuffer * buffer = new AsyncWebSocketMessageBuffer(data, size); - if (buffer->length() != size) - { - delete buffer; - return nullptr; - } else { - return buffer; - } +AsyncWebSocketMessageBuffer* AsyncWebSocket::makeBuffer(const uint8_t* data, size_t size) { + AsyncWebSocketMessageBuffer* buffer = new AsyncWebSocketMessageBuffer(data, size); + if (buffer->length() != size) { + delete buffer; + return nullptr; + } else { + return buffer; + } } /* @@ -1273,55 +1147,51 @@ AsyncWebSocketMessageBuffer * AsyncWebSocket::makeBuffer(const uint8_t * data, s * Authentication code from https://github.com/Links2004/arduinoWebSockets/blob/master/src/WebSockets.cpp#L480 */ -AsyncWebSocketResponse::AsyncWebSocketResponse(const String& key, AsyncWebSocket *server) -{ - _server = server; - _code = 101; - _sendContentLength = false; +AsyncWebSocketResponse::AsyncWebSocketResponse(const String& key, AsyncWebSocket* server) { + _server = server; + _code = 101; + _sendContentLength = false; - uint8_t hash[20]; - char buffer[33]; + uint8_t hash[20]; + char buffer[33]; #ifdef ESP8266 - sha1(key + WS_STR_UUID, hash); + sha1(key + WS_STR_UUID, hash); #else - String k; - k.reserve(key.length() + WS_STR_UUID_LEN); - k.concat(key); - k.concat(WS_STR_UUID); - SHA1Builder sha1; - sha1.begin(); - sha1.add((const uint8_t*)k.c_str(), k.length()); - sha1.calculate(); - sha1.getBytes(hash); + String k; + k.reserve(key.length() + WS_STR_UUID_LEN); + k.concat(key); + k.concat(WS_STR_UUID); + SHA1Builder sha1; + sha1.begin(); + sha1.add((const uint8_t*)k.c_str(), k.length()); + sha1.calculate(); + sha1.getBytes(hash); #endif - base64_encodestate _state; - base64_init_encodestate(&_state); - int len = base64_encode_block((const char *) hash, 20, buffer, &_state); - len = base64_encode_blockend((buffer + len), &_state); - addHeader(WS_STR_CONNECTION, WS_STR_UPGRADE); - addHeader(WS_STR_UPGRADE, F("websocket")); - addHeader(WS_STR_ACCEPT,buffer); + base64_encodestate _state; + base64_init_encodestate(&_state); + int len = base64_encode_block((const char*)hash, 20, buffer, &_state); + len = base64_encode_blockend((buffer + len), &_state); + addHeader(WS_STR_CONNECTION, WS_STR_UPGRADE); + addHeader(WS_STR_UPGRADE, F("websocket")); + addHeader(WS_STR_ACCEPT, buffer); } -void AsyncWebSocketResponse::_respond(AsyncWebServerRequest *request) -{ - if(_state == RESPONSE_FAILED) - { - request->client()->close(true); - return; - } - String out(_assembleHead(request->version())); - request->client()->write(out.c_str(), _headLength); - _state = RESPONSE_WAIT_ACK; +void AsyncWebSocketResponse::_respond(AsyncWebServerRequest* request) { + if (_state == RESPONSE_FAILED) { + request->client()->close(true); + return; + } + String out(_assembleHead(request->version())); + request->client()->write(out.c_str(), _headLength); + _state = RESPONSE_WAIT_ACK; } -size_t AsyncWebSocketResponse::_ack(AsyncWebServerRequest *request, size_t len, uint32_t time) -{ - (void)time; +size_t AsyncWebSocketResponse::_ack(AsyncWebServerRequest* request, size_t len, uint32_t time) { + (void)time; - if(len) - _server->_newClient(request); + if (len) + _server->_newClient(request); - return 0; + return 0; } diff --git a/src/AsyncWebSocket.h b/src/AsyncWebSocket.h index 8b7eca9..10e9537 100644 --- a/src/AsyncWebSocket.h +++ b/src/AsyncWebSocket.h @@ -23,37 +23,36 @@ #include #ifdef ESP32 -#include -#include -#ifndef WS_MAX_QUEUED_MESSAGES -#define WS_MAX_QUEUED_MESSAGES 32 -#endif + #include + #include + #ifndef WS_MAX_QUEUED_MESSAGES + #define WS_MAX_QUEUED_MESSAGES 32 + #endif #else -#include -#ifndef WS_MAX_QUEUED_MESSAGES -#define WS_MAX_QUEUED_MESSAGES 8 -#endif + #include + #ifndef WS_MAX_QUEUED_MESSAGES + #define WS_MAX_QUEUED_MESSAGES 8 + #endif #endif #include - -#include #include +#include #include #ifdef ESP8266 -#include -#ifdef CRYPTO_HASH_h // include Hash.h from espressif framework if the first include was from the crypto library -#include <../src/Hash.h> -#endif + #include + #ifdef CRYPTO_HASH_h // include Hash.h from espressif framework if the first include was from the crypto library + #include <../src/Hash.h> + #endif #endif #ifndef DEFAULT_MAX_WS_CLIENTS -#ifdef ESP32 -#define DEFAULT_MAX_WS_CLIENTS 8 -#else -#define DEFAULT_MAX_WS_CLIENTS 4 -#endif + #ifdef ESP32 + #define DEFAULT_MAX_WS_CLIENTS 8 + #else + #define DEFAULT_MAX_WS_CLIENTS 4 + #endif #endif using AsyncWebSocketSharedBuffer = std::shared_ptr>; @@ -87,20 +86,33 @@ typedef struct { uint64_t index; } AwsFrameInfo; -typedef enum { WS_DISCONNECTED, WS_CONNECTED, WS_DISCONNECTING } AwsClientStatus; -typedef enum { WS_CONTINUATION, WS_TEXT, WS_BINARY, WS_DISCONNECT = 0x08, WS_PING, WS_PONG } AwsFrameType; -typedef enum { WS_MSG_SENDING, WS_MSG_SENT, WS_MSG_ERROR } AwsMessageStatus; -typedef enum { WS_EVT_CONNECT, WS_EVT_DISCONNECT, WS_EVT_PONG, WS_EVT_ERROR, WS_EVT_DATA } AwsEventType; +typedef enum { WS_DISCONNECTED, + WS_CONNECTED, + WS_DISCONNECTING } AwsClientStatus; +typedef enum { WS_CONTINUATION, + WS_TEXT, + WS_BINARY, + WS_DISCONNECT = 0x08, + WS_PING, + WS_PONG } AwsFrameType; +typedef enum { WS_MSG_SENDING, + WS_MSG_SENT, + WS_MSG_ERROR } AwsMessageStatus; +typedef enum { WS_EVT_CONNECT, + WS_EVT_DISCONNECT, + WS_EVT_PONG, + WS_EVT_ERROR, + WS_EVT_DATA } AwsEventType; class AsyncWebSocketMessageBuffer { - friend AsyncWebSocket; - friend AsyncWebSocketClient; + friend AsyncWebSocket; + friend AsyncWebSocketClient; private: AsyncWebSocketSharedBuffer _buffer; public: - AsyncWebSocketMessageBuffer(){} + AsyncWebSocketMessageBuffer() {} explicit AsyncWebSocketMessageBuffer(size_t size); AsyncWebSocketMessageBuffer(const uint8_t* data, size_t size); //~AsyncWebSocketMessageBuffer(); @@ -109,9 +121,8 @@ class AsyncWebSocketMessageBuffer { size_t length() const { return _buffer->size(); } }; -class AsyncWebSocketMessage -{ -private: +class AsyncWebSocketMessage { + private: AsyncWebSocketSharedBuffer _WSbuffer; uint8_t _opcode{WS_TEXT}; bool _mask{false}; @@ -120,20 +131,20 @@ private: size_t _ack{}; size_t _acked{}; -public: - AsyncWebSocketMessage(AsyncWebSocketSharedBuffer buffer, uint8_t opcode=WS_TEXT, bool mask=false); + public: + AsyncWebSocketMessage(AsyncWebSocketSharedBuffer buffer, uint8_t opcode = WS_TEXT, bool mask = false); bool finished() const { return _status != WS_MSG_SENDING; } bool betweenFrames() const { return _acked == _ack; } void ack(size_t len, uint32_t time); - size_t send(AsyncClient *client); + size_t send(AsyncClient* client); }; class AsyncWebSocketClient { private: - AsyncClient *_client; - AsyncWebSocket *_server; + AsyncClient* _client; + AsyncWebSocket* _server; uint32_t _clientId; AwsClientStatus _status; #ifdef ESP32 @@ -149,226 +160,225 @@ class AsyncWebSocketClient { uint32_t _lastMessageTime; uint32_t _keepAlivePeriod; - void _queueControl(uint8_t opcode, const uint8_t *data=NULL, size_t len=0, bool mask=false); - void _queueMessage(AsyncWebSocketSharedBuffer buffer, uint8_t opcode=WS_TEXT, bool mask=false); + void _queueControl(uint8_t opcode, const uint8_t* data = NULL, size_t len = 0, bool mask = false); + void _queueMessage(AsyncWebSocketSharedBuffer buffer, uint8_t opcode = WS_TEXT, bool mask = false); void _runQueue(); void _clearQueue(); public: - void *_tempObject; + void* _tempObject; - AsyncWebSocketClient(AsyncWebServerRequest *request, AsyncWebSocket *server); + AsyncWebSocketClient(AsyncWebServerRequest* request, AsyncWebSocket* server); ~AsyncWebSocketClient(); - //client id increments for the given server + // client id increments for the given server uint32_t id() const { return _clientId; } AwsClientStatus status() const { return _status; } AsyncClient* client() { return _client; } const AsyncClient* client() const { return _client; } - AsyncWebSocket *server(){ return _server; } - const AsyncWebSocket *server() const { return _server; } - AwsFrameInfo const &pinfo() const { return _pinfo; } + AsyncWebSocket* server() { return _server; } + const AsyncWebSocket* server() const { return _server; } + AwsFrameInfo const& pinfo() const { return _pinfo; } // - If "true" (default), the connection will be closed if the message queue is full. // This is the default behavior in yubox-node-org, which is not silently discarding messages but instead closes the connection. - // The big issue with this behavior is that is can cause the UI to automatically re-create a new WS connection, which can be filled again, + // The big issue with this behavior is that is can cause the UI to automatically re-create a new WS connection, which can be filled again, // and so on, causing a resource exhaustion. - // + // // - If "false", the incoming message will be discarded if the queue is full. // This is the default behavior in the original ESPAsyncWebServer library from me-no-dev. // This behavior allows the best performance at the expense of unreliable message delivery in case the queue is full (some messages may be lost). - // + // // - In any case, when the queue is full, a message is logged. // - IT is recommended to use the methods queueIsFull(), availableForWriteAll(), availableForWrite(clientId) to check if the queue is full before sending a message. - // + // // Usage: // - can be set in the onEvent listener when connecting (event type is: WS_EVT_CONNECT) - // - // Use cases:, + // + // Use cases:, // - if using websocket to send logging messages, maybe some loss is acceptable. // - But if using websocket to send UI update messages, maybe the connection should be closed and the UI redrawn. void setCloseClientOnQueueFull(bool close) { closeWhenFull = close; } bool willCloseClientOnQueueFull() const { return closeWhenFull; } IPAddress remoteIP() const; - uint16_t remotePort() const; + uint16_t remotePort() const; bool shouldBeDeleted() const { return !_client; } - //control frames - void close(uint16_t code=0, const char * message=NULL); - void ping(const uint8_t *data=NULL, size_t len=0); + // control frames + void close(uint16_t code = 0, const char* message = NULL); + void ping(const uint8_t* data = NULL, size_t len = 0); - //set auto-ping period in seconds. disabled if zero (default) - void keepAlivePeriod(uint16_t seconds){ + // set auto-ping period in seconds. disabled if zero (default) + void keepAlivePeriod(uint16_t seconds) { _keepAlivePeriod = seconds * 1000; } - uint16_t keepAlivePeriod(){ + uint16_t keepAlivePeriod() { return (uint16_t)(_keepAlivePeriod / 1000); } - //data packets - void message(AsyncWebSocketSharedBuffer buffer, uint8_t opcode=WS_TEXT, bool mask=false) { _queueMessage(buffer, opcode, mask); } + // data packets + void message(AsyncWebSocketSharedBuffer buffer, uint8_t opcode = WS_TEXT, bool mask = false) { _queueMessage(buffer, opcode, mask); } bool queueIsFull() const; size_t queueLen() const; - size_t printf(const char *format, ...) __attribute__ ((format (printf, 2, 3))); + size_t printf(const char* format, ...) __attribute__((format(printf, 2, 3))); #ifndef ESP32 - size_t printf_P(PGM_P formatP, ...) __attribute__ ((format (printf, 2, 3))); + size_t printf_P(PGM_P formatP, ...) __attribute__((format(printf, 2, 3))); #endif void text(AsyncWebSocketSharedBuffer buffer); - void text(const uint8_t *message, size_t len); - void text(const char *message, size_t len); - void text(const char *message); - void text(const String &message); + void text(const uint8_t* message, size_t len); + void text(const char* message, size_t len); + void text(const char* message); + void text(const String& message); #ifndef ESP32 - void text(const __FlashStringHelper *message); -#endif // ESP32 - void text(AsyncWebSocketMessageBuffer *buffer); + void text(const __FlashStringHelper* message); +#endif // ESP32 + void text(AsyncWebSocketMessageBuffer* buffer); void binary(AsyncWebSocketSharedBuffer buffer); - void binary(const uint8_t *message, size_t len); - void binary(const char * message, size_t len); - void binary(const char * message); - void binary(const String &message); + void binary(const uint8_t* message, size_t len); + void binary(const char* message, size_t len); + void binary(const char* message); + void binary(const String& message); #ifndef ESP32 - void binary(const __FlashStringHelper *message, size_t len); -#endif // ESP32 - void binary(AsyncWebSocketMessageBuffer *buffer); + void binary(const __FlashStringHelper* message, size_t len); +#endif // ESP32 + void binary(AsyncWebSocketMessageBuffer* buffer); bool canSend() const; - //system callbacks (do not call) + // system callbacks (do not call) void _onAck(size_t len, uint32_t time); void _onError(int8_t); void _onPoll(); void _onTimeout(uint32_t time); void _onDisconnect(); - void _onData(void *pbuf, size_t plen); + void _onData(void* pbuf, size_t plen); }; -using AwsHandshakeHandler = std::function; -using AwsEventHandler = std::function; +using AwsHandshakeHandler = std::function; +using AwsEventHandler = std::function; -//WebServer Handler implementation that plays the role of a socket server -class AsyncWebSocket: public AsyncWebHandler { +// WebServer Handler implementation that plays the role of a socket server +class AsyncWebSocket : public AsyncWebHandler { private: String _url; std::list _clients; uint32_t _cNextId; AwsEventHandler _eventHandler{nullptr}; - AwsHandshakeHandler _handshakeHandler; + AwsHandshakeHandler _handshakeHandler; bool _enabled; #ifdef ESP32 mutable std::mutex _lock; #endif public: - explicit AsyncWebSocket(const char* url) : _url(url) ,_cNextId(1), _enabled(true) {} - AsyncWebSocket(const String& url) :_url(url) ,_cNextId(1),_enabled(true) {} + explicit AsyncWebSocket(const char* url) : _url(url), _cNextId(1), _enabled(true) {} + AsyncWebSocket(const String& url) : _url(url), _cNextId(1), _enabled(true) {} ~AsyncWebSocket(){}; - const char * url() const { return _url.c_str(); } - void enable(bool e){ _enabled = e; } + const char* url() const { return _url.c_str(); } + void enable(bool e) { _enabled = e; } bool enabled() const { return _enabled; } bool availableForWriteAll(); bool availableForWrite(uint32_t id); size_t count() const; - AsyncWebSocketClient * client(uint32_t id); - bool hasClient(uint32_t id){ return client(id) != nullptr; } + AsyncWebSocketClient* client(uint32_t id); + bool hasClient(uint32_t id) { return client(id) != nullptr; } - void close(uint32_t id, uint16_t code=0, const char * message=NULL); - void closeAll(uint16_t code=0, const char * message=NULL); + void close(uint32_t id, uint16_t code = 0, const char* message = NULL); + void closeAll(uint16_t code = 0, const char* message = NULL); void cleanupClients(uint16_t maxClients = DEFAULT_MAX_WS_CLIENTS); - void ping(uint32_t id, const uint8_t *data=NULL, size_t len=0); - void pingAll(const uint8_t *data=NULL, size_t len=0); // done + void ping(uint32_t id, const uint8_t* data = NULL, size_t len = 0); + void pingAll(const uint8_t* data = NULL, size_t len = 0); // done - void text(uint32_t id, const uint8_t * message, size_t len); - void text(uint32_t id, const char *message, size_t len); - void text(uint32_t id, const char *message); - void text(uint32_t id, const String &message); + void text(uint32_t id, const uint8_t* message, size_t len); + void text(uint32_t id, const char* message, size_t len); + void text(uint32_t id, const char* message); + void text(uint32_t id, const String& message); #ifndef ESP32 - void text(uint32_t id, const __FlashStringHelper *message); -#endif // ESP32 - void text(uint32_t id, AsyncWebSocketMessageBuffer *buffer); + void text(uint32_t id, const __FlashStringHelper* message); +#endif // ESP32 + void text(uint32_t id, AsyncWebSocketMessageBuffer* buffer); void text(uint32_t id, AsyncWebSocketSharedBuffer buffer); - void textAll(const uint8_t *message, size_t len); - void textAll(const char * message, size_t len); - void textAll(const char * message); - void textAll(const String &message); + void textAll(const uint8_t* message, size_t len); + void textAll(const char* message, size_t len); + void textAll(const char* message); + void textAll(const String& message); #ifndef ESP32 - void textAll(const __FlashStringHelper *message); -#endif // ESP32 - void textAll(AsyncWebSocketMessageBuffer *buffer); + void textAll(const __FlashStringHelper* message); +#endif // ESP32 + void textAll(AsyncWebSocketMessageBuffer* buffer); void textAll(AsyncWebSocketSharedBuffer buffer); - void binary(uint32_t id, const uint8_t *message, size_t len); - void binary(uint32_t id, const char *message, size_t len); - void binary(uint32_t id, const char *message); - void binary(uint32_t id, const String &message); + void binary(uint32_t id, const uint8_t* message, size_t len); + void binary(uint32_t id, const char* message, size_t len); + void binary(uint32_t id, const char* message); + void binary(uint32_t id, const String& message); #ifndef ESP32 - void binary(uint32_t id, const __FlashStringHelper *message, size_t len); -#endif // ESP32 - void binary(uint32_t id, AsyncWebSocketMessageBuffer *buffer); + void binary(uint32_t id, const __FlashStringHelper* message, size_t len); +#endif // ESP32 + void binary(uint32_t id, AsyncWebSocketMessageBuffer* buffer); void binary(uint32_t id, AsyncWebSocketSharedBuffer buffer); - void binaryAll(const uint8_t *message, size_t len); - void binaryAll(const char *message, size_t len); - void binaryAll(const char *message); - void binaryAll(const String &message); + void binaryAll(const uint8_t* message, size_t len); + void binaryAll(const char* message, size_t len); + void binaryAll(const char* message); + void binaryAll(const String& message); #ifndef ESP32 - void binaryAll(const __FlashStringHelper *message, size_t len); -#endif // ESP32 - void binaryAll(AsyncWebSocketMessageBuffer *buffer); + void binaryAll(const __FlashStringHelper* message, size_t len); +#endif // ESP32 + void binaryAll(AsyncWebSocketMessageBuffer* buffer); void binaryAll(AsyncWebSocketSharedBuffer buffer); - 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))); + 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))); - size_t printfAll_P(PGM_P formatP, ...) __attribute__ ((format (printf, 2, 3))); + size_t printf_P(uint32_t id, PGM_P formatP, ...) __attribute__((format(printf, 3, 4))); + size_t printfAll_P(PGM_P formatP, ...) __attribute__((format(printf, 2, 3))); #endif - //event listener - void onEvent(AwsEventHandler handler){ + // event listener + void onEvent(AwsEventHandler handler) { _eventHandler = handler; } // Handshake Handler - void handleHandshake(AwsHandshakeHandler handler){ - _handshakeHandler = handler; + void handleHandshake(AwsHandshakeHandler handler) { + _handshakeHandler = handler; } - - //system callbacks (do not call) - uint32_t _getNextId(){ return _cNextId++; } - AsyncWebSocketClient *_newClient(AsyncWebServerRequest *request); - void _handleEvent(AsyncWebSocketClient * client, AwsEventType type, void * arg, uint8_t *data, size_t len); - virtual bool canHandle(AsyncWebServerRequest *request) override final; - virtual void handleRequest(AsyncWebServerRequest *request) override final; + // system callbacks (do not call) + uint32_t _getNextId() { return _cNextId++; } + AsyncWebSocketClient* _newClient(AsyncWebServerRequest* request); + void _handleEvent(AsyncWebSocketClient* client, AwsEventType type, void* arg, uint8_t* data, size_t len); + virtual bool canHandle(AsyncWebServerRequest* request) override final; + virtual void handleRequest(AsyncWebServerRequest* request) override final; - // messagebuffer functions/objects. - AsyncWebSocketMessageBuffer * makeBuffer(size_t size = 0); - AsyncWebSocketMessageBuffer * makeBuffer(const uint8_t * data, size_t size); + // messagebuffer functions/objects. + AsyncWebSocketMessageBuffer* makeBuffer(size_t size = 0); + AsyncWebSocketMessageBuffer* makeBuffer(const uint8_t* data, size_t size); - const std::list &getClients() const { return _clients; } + const std::list& getClients() const { return _clients; } }; -//WebServer response to authenticate the socket and detach the tcp client from the web server request -class AsyncWebSocketResponse: public AsyncWebServerResponse { +// WebServer response to authenticate the socket and detach the tcp client from the web server request +class AsyncWebSocketResponse : public AsyncWebServerResponse { private: String _content; - AsyncWebSocket *_server; + AsyncWebSocket* _server; + public: - AsyncWebSocketResponse(const String& key, AsyncWebSocket *server); - void _respond(AsyncWebServerRequest *request); - size_t _ack(AsyncWebServerRequest *request, size_t len, uint32_t time); + AsyncWebSocketResponse(const String& key, AsyncWebSocket* server); + void _respond(AsyncWebServerRequest* request); + size_t _ack(AsyncWebServerRequest* request, size_t len, uint32_t time); bool _sourceValid() const { return true; } }; - #endif /* ASYNCWEBSOCKET_H_ */ diff --git a/src/ESPAsyncWebServer.h b/src/ESPAsyncWebServer.h index ec616d3..20360c6 100644 --- a/src/ESPAsyncWebServer.h +++ b/src/ESPAsyncWebServer.h @@ -23,31 +23,31 @@ #include "Arduino.h" +#include "FS.h" #include #include #include -#include "FS.h" #ifdef ESP32 -#include -#include + #include + #include #elif defined(ESP8266) -#include -#include + #include + #include #else -#error Platform not supported + #error Platform not supported #endif -#define ASYNCWEBSERVER_VERSION "2.10.8" -#define ASYNCWEBSERVER_VERSION_MAJOR 2 -#define ASYNCWEBSERVER_VERSION_MINOR 10 +#define ASYNCWEBSERVER_VERSION "2.10.8" +#define ASYNCWEBSERVER_VERSION_MAJOR 2 +#define ASYNCWEBSERVER_VERSION_MINOR 10 #define ASYNCWEBSERVER_VERSION_REVISION 8 #define ASYNCWEBSERVER_FORK_mathieucarbou #ifdef ASYNCWEBSERVER_REGEX -#define ASYNCWEBSERVER_REGEX_ATTRIBUTE + #define ASYNCWEBSERVER_REGEX_ATTRIBUTE #else -#define ASYNCWEBSERVER_REGEX_ATTRIBUTE __attribute__((warning("ASYNCWEBSERVER_REGEX not defined"))) + #define ASYNCWEBSERVER_REGEX_ATTRIBUTE __attribute__((warning("ASYNCWEBSERVER_REGEX not defined"))) #endif class AsyncWebServer; @@ -63,31 +63,31 @@ class AsyncResponseStream; #ifndef WEBSERVER_H typedef enum { - HTTP_GET = 0b00000001, - HTTP_POST = 0b00000010, - HTTP_DELETE = 0b00000100, - HTTP_PUT = 0b00001000, - HTTP_PATCH = 0b00010000, - HTTP_HEAD = 0b00100000, + HTTP_GET = 0b00000001, + HTTP_POST = 0b00000010, + HTTP_DELETE = 0b00000100, + HTTP_PUT = 0b00001000, + HTTP_PATCH = 0b00010000, + HTTP_HEAD = 0b00100000, HTTP_OPTIONS = 0b01000000, - HTTP_ANY = 0b01111111, + HTTP_ANY = 0b01111111, } WebRequestMethod; #endif #ifndef HAVE_FS_FILE_OPEN_MODE namespace fs { - class FileOpenMode { + class FileOpenMode { public: - static const char *read; - static const char *write; - static const char *append; - }; + static const char* read; + static const char* write; + static const char* append; + }; }; #else -#include "FileOpenMode.h" + #include "FileOpenMode.h" #endif -//if this value is returned when asked for data, packet will not be sent and you will be asked for data again +// if this value is returned when asked for data, packet will not be sent and you will be asked for data again #define RESPONSE_TRY_AGAIN 0xFFFFFFFF typedef uint8_t WebRequestMethodComposite; @@ -106,8 +106,7 @@ class AsyncWebParameter { bool _isFile; public: - - AsyncWebParameter(const String& name, const String& value, bool form=false, bool file=false, size_t size=0): _name(name), _value(value), _size(size), _isForm(form), _isFile(file){} + AsyncWebParameter(const String& name, const String& value, bool form = false, bool file = false, size_t size = 0) : _name(name), _value(value), _size(size), _isForm(form), _isFile(file) {} const String& name() const { return _name; } const String& value() const { return _value; } size_t size() const { return _size; } @@ -126,18 +125,20 @@ class AsyncWebHeader { public: AsyncWebHeader() = default; - AsyncWebHeader(const AsyncWebHeader &) = default; + AsyncWebHeader(const AsyncWebHeader&) = default; - AsyncWebHeader(const String& name, const String& value): _name(name), _value(value){} - AsyncWebHeader(const String& data){ - if(!data) return; + AsyncWebHeader(const String& name, const String& value) : _name(name), _value(value) {} + AsyncWebHeader(const String& data) { + if (!data) + return; int index = data.indexOf(':'); - if (index < 0) return; + if (index < 0) + return; _name = data.substring(0, index); _value = data.substring(index + 2); } - AsyncWebHeader &operator=(const AsyncWebHeader &) = default; + AsyncWebHeader& operator=(const AsyncWebHeader&) = default; const String& name() const { return _name; } const String& value() const { return _value; } @@ -148,16 +149,22 @@ class AsyncWebHeader { * REQUEST :: Each incoming Client is wrapped inside a Request and both live together until disconnect * */ -typedef enum { RCT_NOT_USED = -1, RCT_DEFAULT = 0, RCT_HTTP, RCT_WS, RCT_EVENT, RCT_MAX } RequestedConnectionType; +typedef enum { RCT_NOT_USED = -1, + RCT_DEFAULT = 0, + RCT_HTTP, + RCT_WS, + RCT_EVENT, + RCT_MAX } RequestedConnectionType; typedef std::function AwsResponseFiller; typedef std::function AwsTemplateProcessor; class AsyncWebServerRequest { - using File = fs::File; - using FS = fs::FS; - friend class AsyncWebServer; - friend class AsyncCallbackWebHandler; + using File = fs::File; + using FS = fs::FS; + friend class AsyncWebServer; + friend class AsyncCallbackWebHandler; + private: AsyncClient* _client; AsyncWebServer* _server; @@ -197,7 +204,7 @@ class AsyncWebServerRequest { String _itemFilename; String _itemType; String _itemValue; - uint8_t *_itemBuffer; + uint8_t* _itemBuffer; size_t _itemBufferIndex; bool _itemIsFile; @@ -206,9 +213,9 @@ class AsyncWebServerRequest { void _onError(int8_t error); void _onTimeout(uint32_t time); void _onDisconnect(); - void _onData(void *buf, size_t len); + void _onData(void* buf, size_t len); - void _addPathParam(const char *param); + void _addPathParam(const char* param); bool _parseReqHead(); bool _parseReqHeader(); @@ -223,12 +230,12 @@ class AsyncWebServerRequest { public: File _tempFile; - void *_tempObject; + void* _tempObject; AsyncWebServerRequest(AsyncWebServer*, AsyncClient*); ~AsyncWebServerRequest(); - AsyncClient* client(){ return _client; } + AsyncClient* client() { return _client; } uint8_t version() const { return _version; } WebRequestMethodComposite method() const { return _method; } const String& url() const { return _url; } @@ -241,120 +248,120 @@ class AsyncWebServerRequest { const char* methodToString() const; const char* requestedConnTypeToString() const; #else - const __FlashStringHelper *methodToString() const; - const __FlashStringHelper *requestedConnTypeToString() const; + 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); + void onDisconnect(ArDisconnectHandler fn); - //hash is the string representation of: - // base64(user:pass) for basic or - // user:realm:md5(user:realm:pass) for digest - bool authenticate(const char * hash); - bool authenticate(const char * username, const char * password, const char * realm = NULL, bool passwordIsHash = false); - void requestAuthentication(const char * realm = NULL, bool isDigest = true); + // hash is the string representation of: + // base64(user:pass) for basic or + // user:realm:md5(user:realm:pass) for digest + bool authenticate(const char* hash); + bool authenticate(const char* username, const char* password, const char* realm = NULL, bool passwordIsHash = false); + void requestAuthentication(const char* realm = NULL, bool isDigest = true); - void setHandler(AsyncWebHandler *handler){ _handler = handler; } + void setHandler(AsyncWebHandler* handler) { _handler = handler; } /** * @brief add header to collect from a response - * - * @param name + * + * @param name */ void addInterestingHeader(const char* name); - void addInterestingHeader(const String& name){ return addInterestingHeader(name.c_str()); }; + void addInterestingHeader(const String& name) { return addInterestingHeader(name.c_str()); }; /** * @brief issue 302 redirect response - * - * @param url + * + * @param url */ void redirect(const char* url); - void redirect(const String& url){ return redirect(url.c_str()); }; + 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()); - void send(FS &fs, const String& path, const String& contentType=String(), bool download=false, AwsTemplateProcessor callback=nullptr); - void send(File content, const String& path, const String& contentType=String(), bool download=false, AwsTemplateProcessor callback=nullptr); - 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); + void send(AsyncWebServerResponse* response); + void send(int code, const String& contentType = String(), const String& content = String()); + void send(FS& fs, const String& path, const String& contentType = String(), bool download = false, AwsTemplateProcessor callback = nullptr); + void send(File content, const String& path, const String& contentType = String(), bool download = false, AwsTemplateProcessor callback = nullptr); + 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); + 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); - AsyncWebServerResponse *beginResponse(File content, const String& path, const String& contentType=String(), bool download=false, AwsTemplateProcessor callback=nullptr); - AsyncWebServerResponse *beginResponse(Stream &stream, const String& contentType, size_t len, AwsTemplateProcessor callback=nullptr); - 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); + 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); + AsyncWebServerResponse* beginResponse(File content, const String& path, const String& contentType = String(), bool download = false, AwsTemplateProcessor callback = nullptr); + AsyncWebServerResponse* beginResponse(Stream& stream, const String& contentType, size_t len, AwsTemplateProcessor callback = nullptr); + 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); + 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 + size_t headers() const; // get header count // 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 + 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; + const AsyncWebHeader* getHeader(const __FlashStringHelper* data) const; #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; + 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; /** * @brief Get the Request parameter by name - * - * @param name - * @param post - * @param file - * @return const AsyncWebParameter* + * + * @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 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()); }; + 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; + 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* + * @param num + * @return const AsyncWebParameter* */ const AsyncWebParameter* getParam(size_t num) const; - size_t args() const { return params(); } // get arguments count + size_t args() const { return params(); } // get arguments count // 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) + 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 + 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 + bool hasArg(const __FlashStringHelper* data) const; // check if F(argument) exists #endif const String& ASYNCWEBSERVER_REGEX_ATTRIBUTE pathArg(size_t i) const; @@ -364,11 +371,11 @@ class AsyncWebServerRequest { 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) + 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 + 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; }; @@ -377,11 +384,11 @@ class AsyncWebServerRequest { * FILTER :: Callback to filter AsyncWebRewrite and AsyncWebHandler (done by the Server) * */ -using ArRequestFilterFunction = std::function; +using ArRequestFilterFunction = std::function; -bool ON_STA_FILTER(AsyncWebServerRequest *request); +bool ON_STA_FILTER(AsyncWebServerRequest* request); -bool ON_AP_FILTER(AsyncWebServerRequest *request); +bool ON_AP_FILTER(AsyncWebServerRequest* request); /* * REWRITE :: One instance can be handle any Request (done by the Server) @@ -393,21 +400,25 @@ class AsyncWebRewrite { String _toUrl; String _params; ArRequestFilterFunction _filter{nullptr}; + public: - AsyncWebRewrite(const char* from, const char* to) : _from(from), _toUrl(to){ + AsyncWebRewrite(const char* from, const char* to) : _from(from), _toUrl(to) { int index = _toUrl.indexOf('?'); if (index > 0) { - _params = _toUrl.substring(index +1); + _params = _toUrl.substring(index + 1); _toUrl = _toUrl.substring(0, index); } } - virtual ~AsyncWebRewrite(){} - AsyncWebRewrite& setFilter(ArRequestFilterFunction fn) { _filter = fn; return *this; } - bool filter(AsyncWebServerRequest *request) const { return _filter == NULL || _filter(request); } + virtual ~AsyncWebRewrite() {} + AsyncWebRewrite& setFilter(ArRequestFilterFunction fn) { + _filter = fn; + return *this; + } + bool filter(AsyncWebServerRequest* request) const { return _filter == NULL || _filter(request); } const String& from(void) const { return _from; } const String& toUrl(void) const { return _toUrl; } const String& params(void) const { return _params; } - virtual bool match(AsyncWebServerRequest *request) { return from() == request->url() && filter(request); } + virtual bool match(AsyncWebServerRequest* request) { return from() == request->url() && filter(request); } }; /* @@ -419,20 +430,32 @@ class AsyncWebHandler { ArRequestFilterFunction _filter{nullptr}; String _username; String _password; + public: - AsyncWebHandler(){} - AsyncWebHandler& setFilter(ArRequestFilterFunction fn) { _filter = fn; 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))){ + AsyncWebHandler() {} + AsyncWebHandler& setFilter(ArRequestFilterFunction fn) { + _filter = fn; + 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))) { return false; } - virtual void handleRequest(AsyncWebServerRequest *request __attribute__((unused))){} - virtual void handleUpload(AsyncWebServerRequest *request __attribute__((unused)), const String& filename __attribute__((unused)), size_t index __attribute__((unused)), uint8_t *data __attribute__((unused)), size_t len __attribute__((unused)), bool final __attribute__((unused))){} - virtual void handleBody(AsyncWebServerRequest *request __attribute__((unused)), uint8_t *data __attribute__((unused)), size_t len __attribute__((unused)), size_t index __attribute__((unused)), size_t total __attribute__((unused))){} - virtual bool isRequestHandlerTrivial(){return true;} + virtual void handleRequest(AsyncWebServerRequest* request __attribute__((unused))) {} + virtual void handleUpload(AsyncWebServerRequest* request __attribute__((unused)), const String& filename __attribute__((unused)), size_t index __attribute__((unused)), uint8_t* data __attribute__((unused)), size_t len __attribute__((unused)), bool final __attribute__((unused))) {} + virtual void handleBody(AsyncWebServerRequest* request __attribute__((unused)), uint8_t* data __attribute__((unused)), size_t len __attribute__((unused)), size_t index __attribute__((unused)), size_t total __attribute__((unused))) {} + virtual bool isRequestHandlerTrivial() { return true; } }; /* @@ -440,7 +463,12 @@ class AsyncWebHandler { * */ typedef enum { - RESPONSE_SETUP, RESPONSE_HEADERS, RESPONSE_CONTENT, RESPONSE_WAIT_ACK, RESPONSE_END, RESPONSE_FAILED + RESPONSE_SETUP, + RESPONSE_HEADERS, + RESPONSE_CONTENT, + RESPONSE_WAIT_ACK, + RESPONSE_END, + RESPONSE_FAILED } WebResponseState; class AsyncWebServerResponse { @@ -457,8 +485,9 @@ class AsyncWebServerResponse { size_t _writtenLength; WebResponseState _state; const char* _responseCodeToString(int code); -public: - static const __FlashStringHelper *responseCodeToString(int code); + + public: + static const __FlashStringHelper* responseCodeToString(int code); public: AsyncWebServerResponse(); @@ -472,23 +501,23 @@ public: virtual bool _finished() const; virtual bool _failed() const; virtual bool _sourceValid() const; - virtual void _respond(AsyncWebServerRequest *request); - virtual size_t _ack(AsyncWebServerRequest *request, size_t len, uint32_t time); + virtual void _respond(AsyncWebServerRequest* request); + virtual size_t _ack(AsyncWebServerRequest* request, size_t len, uint32_t time); }; /* * SERVER :: One instance * */ -typedef std::function ArRequestHandlerFunction; -typedef std::function ArUploadHandlerFunction; -typedef std::function ArBodyHandlerFunction; +typedef std::function ArRequestHandlerFunction; +typedef std::function ArUploadHandlerFunction; +typedef std::function ArBodyHandlerFunction; class AsyncWebServer { protected: AsyncServer _server; - std::list > _rewrites; - std::list > _handlers; + std::list> _rewrites; + std::list> _handlers; AsyncCallbackWebHandler* _catchAllHandler; public: @@ -500,7 +529,7 @@ class AsyncWebServer { #if ASYNC_TCP_SSL_ENABLED void onSslFileRequest(AcSSlFileHandler cb, void* arg); - void beginSecure(const char *cert, const char *private_key_file, const char *password); + void beginSecure(const char* cert, const char* private_key_file, const char* password); #endif AsyncWebRewrite& addRewrite(AsyncWebRewrite* rewrite); @@ -509,7 +538,7 @@ class AsyncWebServer { * @brief (compat) Add url rewrite rule by pointer * a deep copy of the pounter object will be created, * it is up to user to manage further lifetime of the object in argument - * + * * @param rewrite pointer to rewrite object to copy setting from * @return AsyncWebRewrite& reference to a newly created rewrite rule */ @@ -517,10 +546,10 @@ class AsyncWebServer { /** * @brief add url rewrite rule - * - * @param from - * @param to - * @return AsyncWebRewrite& + * + * @param from + * @param to + * @return AsyncWebRewrite& */ AsyncWebRewrite& rewrite(const char* from, const char* to); @@ -528,19 +557,19 @@ class AsyncWebServer { * @brief (compat) remove rewrite rule via referenced object * this will NOT deallocate pointed object itself, internal rule with same from/to urls will be removed if any * it's a compat method, better use `removeRewrite(const char* from, const char* to)` - * @param rewrite - * @return true - * @return false + * @param rewrite + * @return true + * @return false */ bool removeRewrite(AsyncWebRewrite* rewrite); /** * @brief remove rewrite rule - * - * @param from - * @param to - * @return true - * @return false + * + * @param from + * @param to + * @return true + * @return false */ bool removeRewrite(const char* from, const char* to); @@ -554,45 +583,45 @@ class AsyncWebServer { AsyncStaticWebHandler& serveStatic(const char* uri, fs::FS& fs, const char* path, const char* cache_control = NULL); - void onNotFound(ArRequestHandlerFunction fn); //called when handler is not assigned - void onFileUpload(ArUploadHandlerFunction fn); //handle file uploads - void onRequestBody(ArBodyHandlerFunction fn); //handle posts with plain body content (JSON often transmitted this way as a request) + void onNotFound(ArRequestHandlerFunction fn); // called when handler is not assigned + void onFileUpload(ArUploadHandlerFunction fn); // handle file uploads + void onRequestBody(ArBodyHandlerFunction fn); // handle posts with plain body content (JSON often transmitted this way as a request) - void reset(); //remove all writers and handlers, with onNotFound/onFileUpload/onRequestBody + void reset(); // remove all writers and handlers, with onNotFound/onFileUpload/onRequestBody - void _handleDisconnect(AsyncWebServerRequest *request); - void _attachHandler(AsyncWebServerRequest *request); - void _rewriteRequest(AsyncWebServerRequest *request); + void _handleDisconnect(AsyncWebServerRequest* request); + void _attachHandler(AsyncWebServerRequest* request); + void _rewriteRequest(AsyncWebServerRequest* request); }; class DefaultHeaders { - using headers_t = std::list; - headers_t _headers; + using headers_t = std::list; + headers_t _headers; -public: - DefaultHeaders() = default; + public: + DefaultHeaders() = default; - using ConstIterator = headers_t::const_iterator; + using ConstIterator = headers_t::const_iterator; - void addHeader(const String& name, const String& value){ - _headers.emplace_back(name, value); - } + void addHeader(const String& name, const String& value) { + _headers.emplace_back(name, value); + } - ConstIterator begin() const { return _headers.begin(); } - ConstIterator end() const { return _headers.end(); } + ConstIterator begin() const { return _headers.begin(); } + ConstIterator end() const { return _headers.end(); } - DefaultHeaders(DefaultHeaders const &) = delete; - DefaultHeaders &operator=(DefaultHeaders const &) = delete; + DefaultHeaders(DefaultHeaders const&) = delete; + DefaultHeaders& operator=(DefaultHeaders const&) = delete; - static DefaultHeaders &Instance() { - static DefaultHeaders instance; - return instance; - } + static DefaultHeaders& Instance() { + static DefaultHeaders instance; + return instance; + } }; -#include "WebResponseImpl.h" -#include "WebHandlerImpl.h" -#include "AsyncWebSocket.h" #include "AsyncEventSource.h" +#include "AsyncWebSocket.h" +#include "WebHandlerImpl.h" +#include "WebResponseImpl.h" #endif /* _AsyncWebServer_H_ */ diff --git a/src/WebAuthentication.cpp b/src/WebAuthentication.cpp index 78c8e43..5761616 100644 --- a/src/WebAuthentication.cpp +++ b/src/WebAuthentication.cpp @@ -21,40 +21,39 @@ #include "WebAuthentication.h" #include #ifdef ESP32 -#include + #include #else -#include "md5.h" + #include "md5.h" #endif - // Basic Auth hash = base64("username:password") -bool checkBasicAuthentication(const char * hash, const char * username, const char * password){ - if(username == NULL || password == NULL || hash == NULL) +bool checkBasicAuthentication(const char* hash, const char* username, const char* password) { + if (username == NULL || password == NULL || hash == NULL) return false; - size_t toencodeLen = strlen(username)+strlen(password)+1; + size_t toencodeLen = strlen(username) + strlen(password) + 1; size_t encodedLen = base64_encode_expected_len(toencodeLen); - if(strlen(hash) != encodedLen) + if (strlen(hash) != encodedLen) // Fix from https://github.com/me-no-dev/ESPAsyncWebServer/issues/667 #ifdef ARDUINO_ARCH_ESP32 - if(strlen(hash) != encodedLen) + if (strlen(hash) != encodedLen) #else if (strlen(hash) != encodedLen - 1) #endif - return false; + return false; - char *toencode = new char[toencodeLen+1]; - if(toencode == NULL){ + char* toencode = new char[toencodeLen + 1]; + if (toencode == NULL) { return false; } - char *encoded = new char[base64_encode_expected_len(toencodeLen)+1]; - if(encoded == NULL){ + char* encoded = new char[base64_encode_expected_len(toencodeLen) + 1]; + if (encoded == NULL) { delete[] toencode; return false; } sprintf_P(toencode, PSTR("%s:%s"), username, password); - if(base64_encode_chars(toencode, toencodeLen, encoded) > 0 && memcmp(hash, encoded, encodedLen) == 0){ + if (base64_encode_chars(toencode, toencodeLen, encoded) > 0 && memcmp(hash, encoded, encodedLen) == 0) { delete[] toencode; delete[] encoded; return true; @@ -64,7 +63,7 @@ bool checkBasicAuthentication(const char * hash, const char * username, const ch return false; } -static bool getMD5(uint8_t * data, uint16_t len, char * output){//33 bytes or more +static bool getMD5(uint8_t* data, uint16_t len, char* output) { // 33 bytes or more #ifdef ESP32 MD5Builder md5; md5.begin(); @@ -73,9 +72,9 @@ static bool getMD5(uint8_t * data, uint16_t len, char * output){//33 bytes or mo md5.getChars(output); #else md5_context_t _ctx; - - uint8_t * _buf = (uint8_t*)malloc(16); - if(_buf == NULL) + + uint8_t* _buf = (uint8_t*)malloc(16); + if (_buf == NULL) return false; memset(_buf, 0x00, 16); @@ -83,7 +82,7 @@ static bool getMD5(uint8_t * data, uint16_t len, char * output){//33 bytes or mo MD5Update(&_ctx, data, len); MD5Final(_buf, &_ctx); - for(uint8_t i = 0; i < 16; i++) { + for (uint8_t i = 0; i < 16; i++) { sprintf_P(output + (i * 2), PSTR("%02x"), _buf[i]); } @@ -92,50 +91,50 @@ static bool getMD5(uint8_t * data, uint16_t len, char * output){//33 bytes or mo return true; } -static String genRandomMD5(){ +static String genRandomMD5() { #ifdef ESP8266 uint32_t r = RANDOM_REG32; #else uint32_t r = rand(); #endif - char * out = (char*)malloc(33); - if(out == NULL || !getMD5((uint8_t*)(&r), 4, out)) + char* out = (char*)malloc(33); + if (out == NULL || !getMD5((uint8_t*)(&r), 4, out)) return emptyString; String res = String(out); free(out); return res; } -static String stringMD5(const String& in){ - char * out = (char*)malloc(33); - if(out == NULL || !getMD5((uint8_t*)(in.c_str()), in.length(), out)) +static String stringMD5(const String& in) { + char* out = (char*)malloc(33); + if (out == NULL || !getMD5((uint8_t*)(in.c_str()), in.length(), out)) return emptyString; String res = String(out); free(out); return res; } -String generateDigestHash(const char * username, const char * password, const char * realm){ - if(username == NULL || password == NULL || realm == NULL){ +String generateDigestHash(const char* username, const char* password, const char* realm) { + if (username == NULL || password == NULL || realm == NULL) { return emptyString; } - char * out = (char*)malloc(33); + char* out = (char*)malloc(33); String res = String(username); res += ':'; res.concat(realm); res += ':'; String in = res; in.concat(password); - if(out == NULL || !getMD5((uint8_t*)(in.c_str()), in.length(), out)) + if (out == NULL || !getMD5((uint8_t*)(in.c_str()), in.length(), out)) return emptyString; res.concat(out); free(out); return res; } -String requestDigestAuthentication(const char * realm){ +String requestDigestAuthentication(const char* realm) { String header = F("realm=\""); - if(realm == NULL) + if (realm == NULL) header.concat(F("asyncesp")); else header.concat(realm); @@ -148,20 +147,20 @@ String requestDigestAuthentication(const char * realm){ } #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) +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) +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"); + if (username == NULL || password == NULL || header == NULL || method == NULL) { + // os_printf("AUTH FAIL: missing requred fields\n"); return false; } String myHeader(header); int nextBreak = myHeader.indexOf(','); - if(nextBreak < 0){ - //os_printf("AUTH FAIL: no variables\n"); + if (nextBreak < 0) { + // os_printf("AUTH FAIL: no variables\n"); return false; } @@ -178,69 +177,69 @@ bool checkDigestAuthentication(const char * header, const __FlashStringHelper *m do { String avLine(myHeader.substring(0, nextBreak)); avLine.trim(); - myHeader = myHeader.substring(nextBreak+1); + myHeader = myHeader.substring(nextBreak + 1); nextBreak = myHeader.indexOf(','); int eqSign = avLine.indexOf('='); - if(eqSign < 0){ - //os_printf("AUTH FAIL: no = sign\n"); + if (eqSign < 0) { + // os_printf("AUTH FAIL: no = sign\n"); return false; } String varName(avLine.substring(0, eqSign)); avLine = avLine.substring(eqSign + 1); - if(avLine.startsWith(String('"'))){ + if (avLine.startsWith(String('"'))) { avLine = avLine.substring(1, avLine.length() - 1); } - if(varName.equals(F("username"))){ - if(!avLine.equals(username)){ - //os_printf("AUTH FAIL: username\n"); + if (varName.equals(F("username"))) { + if (!avLine.equals(username)) { + // os_printf("AUTH FAIL: username\n"); return false; } myUsername = avLine; - } else if(varName.equals(F("realm"))){ - if(realm != NULL && !avLine.equals(realm)){ - //os_printf("AUTH FAIL: realm\n"); + } else if (varName.equals(F("realm"))) { + if (realm != NULL && !avLine.equals(realm)) { + // os_printf("AUTH FAIL: realm\n"); return false; } myRealm = avLine; - } else if(varName.equals(F("nonce"))){ - if(nonce != NULL && !avLine.equals(nonce)){ - //os_printf("AUTH FAIL: nonce\n"); + } else if (varName.equals(F("nonce"))) { + if (nonce != NULL && !avLine.equals(nonce)) { + // os_printf("AUTH FAIL: nonce\n"); return false; } myNonce = avLine; - } else if(varName.equals(F("opaque"))){ - if(opaque != NULL && !avLine.equals(opaque)){ - //os_printf("AUTH FAIL: opaque\n"); + } else if (varName.equals(F("opaque"))) { + if (opaque != NULL && !avLine.equals(opaque)) { + // os_printf("AUTH FAIL: opaque\n"); return false; } - } else if(varName.equals(F("uri"))){ - if(uri != NULL && !avLine.equals(uri)){ - //os_printf("AUTH FAIL: uri\n"); + } else if (varName.equals(F("uri"))) { + if (uri != NULL && !avLine.equals(uri)) { + // os_printf("AUTH FAIL: uri\n"); return false; } myUri = avLine; - } else if(varName.equals(F("response"))){ + } else if (varName.equals(F("response"))) { myResponse = avLine; - } else if(varName.equals(F("qop"))){ + } else if (varName.equals(F("qop"))) { myQop = avLine; - } else if(varName.equals(F("nc"))){ + } else if (varName.equals(F("nc"))) { myNc = avLine; - } else if(varName.equals(F("cnonce"))){ + } else if (varName.equals(F("cnonce"))) { myCnonce = avLine; } - } while(nextBreak > 0); + } while (nextBreak > 0); String ha1 = (passwordIsHash) ? String(password) : stringMD5(myUsername + ':' + myRealm + ':' + password); String ha2 = String(method) + ':' + myUri; String response = ha1 + ':' + myNonce + ':' + myNc + ':' + myCnonce + ':' + myQop + ':' + stringMD5(ha2); - if(myResponse.equals(stringMD5(response))){ - //os_printf("AUTH SUCCESS\n"); + if (myResponse.equals(stringMD5(response))) { + // os_printf("AUTH SUCCESS\n"); return true; } - //os_printf("AUTH FAIL: password\n"); + // os_printf("AUTH FAIL: password\n"); return false; } diff --git a/src/WebAuthentication.h b/src/WebAuthentication.h index 8bc5f05..d519777 100644 --- a/src/WebAuthentication.h +++ b/src/WebAuthentication.h @@ -24,16 +24,16 @@ #include "Arduino.h" -bool checkBasicAuthentication(const char * header, const char * username, const char * password); -String requestDigestAuthentication(const char * realm); +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); +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); +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); +// for storing hashed versions on the device that can be authenticated against +String generateDigestHash(const char* username, const char* password, const char* realm); #endif diff --git a/src/WebHandlerImpl.h b/src/WebHandlerImpl.h index 9b7ba1b..22757d7 100644 --- a/src/WebHandlerImpl.h +++ b/src/WebHandlerImpl.h @@ -23,19 +23,21 @@ #include #ifdef ASYNCWEBSERVER_REGEX -#include + #include #endif #include "stddef.h" #include -class AsyncStaticWebHandler: public AsyncWebHandler { - using File = fs::File; - using FS = fs::FS; +class AsyncStaticWebHandler : public AsyncWebHandler { + using File = fs::File; + using FS = fs::FS; + private: - bool _getFile(AsyncWebServerRequest *request); - bool _fileExists(AsyncWebServerRequest *request, const String& path); + bool _getFile(AsyncWebServerRequest* request); + bool _fileExists(AsyncWebServerRequest* request, const String& path); uint8_t _countBits(const uint8_t value) const; + protected: FS _fs; String _uri; @@ -47,23 +49,27 @@ class AsyncStaticWebHandler: public AsyncWebHandler { bool _isDir; bool _gzipFirst; uint8_t _gzipStats; + public: AsyncStaticWebHandler(const char* uri, FS& fs, const char* path, const char* cache_control); - virtual bool canHandle(AsyncWebServerRequest *request) override final; - virtual void handleRequest(AsyncWebServerRequest *request) override final; + virtual bool canHandle(AsyncWebServerRequest* request) override final; + virtual void handleRequest(AsyncWebServerRequest* request) override final; AsyncStaticWebHandler& setIsDir(bool isDir); AsyncStaticWebHandler& setDefaultFile(const char* filename); AsyncStaticWebHandler& setCacheControl(const char* cache_control); AsyncStaticWebHandler& setLastModified(const char* last_modified); AsyncStaticWebHandler& setLastModified(struct tm* last_modified); - #ifdef ESP8266 +#ifdef ESP8266 AsyncStaticWebHandler& setLastModified(time_t last_modified); - AsyncStaticWebHandler& setLastModified(); //sets to current time. Make sure sntp is runing and time is updated - #endif - AsyncStaticWebHandler& setTemplateProcessor(AwsTemplateProcessor newCallback) {_callback = newCallback; return *this;} + AsyncStaticWebHandler& setLastModified(); // sets to current time. Make sure sntp is runing and time is updated +#endif + AsyncStaticWebHandler& setTemplateProcessor(AwsTemplateProcessor newCallback) { + _callback = newCallback; + return *this; + } }; -class AsyncCallbackWebHandler: public AsyncWebHandler { +class AsyncCallbackWebHandler : public AsyncWebHandler { private: protected: String _uri; @@ -72,23 +78,24 @@ class AsyncCallbackWebHandler: public AsyncWebHandler { ArUploadHandlerFunction _onUpload; ArBodyHandlerFunction _onBody; bool _isRegex; + public: AsyncCallbackWebHandler() : _uri(), _method(HTTP_ANY), _onRequest(NULL), _onUpload(NULL), _onBody(NULL), _isRegex(false) {} - void setUri(const String& uri){ - _uri = uri; + void setUri(const String& uri) { + _uri = uri; _isRegex = uri.startsWith("^") && uri.endsWith("$"); } - void setMethod(WebRequestMethodComposite method){ _method = method; } - void onRequest(ArRequestHandlerFunction fn){ _onRequest = fn; } - void onUpload(ArUploadHandlerFunction fn){ _onUpload = fn; } - void onBody(ArBodyHandlerFunction fn){ _onBody = fn; } + void setMethod(WebRequestMethodComposite method) { _method = method; } + void onRequest(ArRequestHandlerFunction fn) { _onRequest = fn; } + void onUpload(ArUploadHandlerFunction fn) { _onUpload = fn; } + void onBody(ArBodyHandlerFunction fn) { _onBody = fn; } - virtual bool canHandle(AsyncWebServerRequest *request) override final{ + virtual bool canHandle(AsyncWebServerRequest* request) override final { - if(!_onRequest) + if (!_onRequest) return false; - if(!(_method & request->method())) + if (!(_method & request->method())) return false; #ifdef ASYNCWEBSERVER_REGEX @@ -96,56 +103,53 @@ class AsyncCallbackWebHandler: public AsyncWebHandler { std::regex pattern(_uri.c_str()); std::smatch matches; std::string s(request->url().c_str()); - if(std::regex_search(s, matches, pattern)) { + if (std::regex_search(s, matches, pattern)) { for (size_t i = 1; i < matches.size(); ++i) { // start from 1 request->_addPathParam(matches[i].str().c_str()); } } else { return false; } - } else + } else #endif - if (_uri.length() && _uri.startsWith("/*.")) { - String uriTemplate = String (_uri); - uriTemplate = uriTemplate.substring(uriTemplate.lastIndexOf(".")); - if (!request->url().endsWith(uriTemplate)) - return false; - } - else - if (_uri.length() && _uri.endsWith("*")) { + if (_uri.length() && _uri.startsWith("/*.")) { String uriTemplate = String(_uri); - uriTemplate = uriTemplate.substring(0, uriTemplate.length() - 1); + uriTemplate = uriTemplate.substring(uriTemplate.lastIndexOf(".")); + if (!request->url().endsWith(uriTemplate)) + return false; + } else if (_uri.length() && _uri.endsWith("*")) { + String uriTemplate = String(_uri); + uriTemplate = uriTemplate.substring(0, uriTemplate.length() - 1); if (!request->url().startsWith(uriTemplate)) return false; - } - else if(_uri.length() && (_uri != request->url() && !request->url().startsWith(_uri+"/"))) + } else if (_uri.length() && (_uri != request->url() && !request->url().startsWith(_uri + "/"))) return false; request->addInterestingHeader("ANY"); return true; } - - virtual void handleRequest(AsyncWebServerRequest *request) override final { - if((_username != "" && _password != "") && !request->authenticate(_username.c_str(), _password.c_str())) + + virtual void handleRequest(AsyncWebServerRequest* request) override final { + if ((_username != "" && _password != "") && !request->authenticate(_username.c_str(), _password.c_str())) return request->requestAuthentication(); - if(_onRequest) + if (_onRequest) _onRequest(request); else request->send(500); } - virtual void handleUpload(AsyncWebServerRequest *request, const String& filename, size_t index, uint8_t *data, size_t len, bool final) override final { - if((_username != "" && _password != "") && !request->authenticate(_username.c_str(), _password.c_str())) + virtual void handleUpload(AsyncWebServerRequest* request, const String& filename, size_t index, uint8_t* data, size_t len, bool final) override final { + if ((_username != "" && _password != "") && !request->authenticate(_username.c_str(), _password.c_str())) return request->requestAuthentication(); - if(_onUpload) + if (_onUpload) _onUpload(request, filename, index, data, len, final); } - virtual void handleBody(AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total) override final { - if((_username != "" && _password != "") && !request->authenticate(_username.c_str(), _password.c_str())) + virtual void handleBody(AsyncWebServerRequest* request, uint8_t* data, size_t len, size_t index, size_t total) override final { + if ((_username != "" && _password != "") && !request->authenticate(_username.c_str(), _password.c_str())) return request->requestAuthentication(); - if(_onBody) + if (_onBody) _onBody(request, data, len, index, total); } - virtual bool isRequestHandlerTrivial() override final {return _onRequest ? false : true;} + virtual bool isRequestHandlerTrivial() override final { return _onRequest ? false : true; } }; #endif /* ASYNCWEBSERVERHANDLERIMPL_H_ */ diff --git a/src/WebHandlers.cpp b/src/WebHandlers.cpp index d3d82cd..40232df 100644 --- a/src/WebHandlers.cpp +++ b/src/WebHandlers.cpp @@ -22,73 +22,73 @@ #include "WebHandlerImpl.h" AsyncStaticWebHandler::AsyncStaticWebHandler(const char* uri, FS& fs, const char* path, const char* cache_control) - : _fs(fs), _uri(uri), _path(path), _default_file(F("index.htm")), _cache_control(cache_control), _last_modified(), _callback(nullptr) -{ + : _fs(fs), _uri(uri), _path(path), _default_file(F("index.htm")), _cache_control(cache_control), _last_modified(), _callback(nullptr) { // Ensure leading '/' - if (_uri.length() == 0 || _uri[0] != '/') _uri = String('/') + _uri; - if (_path.length() == 0 || _path[0] != '/') _path = String('/') + _path; + if (_uri.length() == 0 || _uri[0] != '/') + _uri = String('/') + _uri; + if (_path.length() == 0 || _path[0] != '/') + _path = String('/') + _path; // If path ends with '/' we assume a hint that this is a directory to improve performance. // However - if it does not end with '/' we, can't assume a file, path can still be a directory. - _isDir = _path[_path.length()-1] == '/'; + _isDir = _path[_path.length() - 1] == '/'; // Remove the trailing '/' so we can handle default file // Notice that root will be "" not "/" - if (_uri[_uri.length()-1] == '/') _uri = _uri.substring(0, _uri.length()-1); - if (_path[_path.length()-1] == '/') _path = _path.substring(0, _path.length()-1); + if (_uri[_uri.length() - 1] == '/') + _uri = _uri.substring(0, _uri.length() - 1); + if (_path[_path.length() - 1] == '/') + _path = _path.substring(0, _path.length() - 1); // Reset stats _gzipFirst = false; _gzipStats = 0xF8; } -AsyncStaticWebHandler& AsyncStaticWebHandler::setIsDir(bool isDir){ +AsyncStaticWebHandler& AsyncStaticWebHandler::setIsDir(bool isDir) { _isDir = isDir; return *this; } -AsyncStaticWebHandler& AsyncStaticWebHandler::setDefaultFile(const char* filename){ +AsyncStaticWebHandler& AsyncStaticWebHandler::setDefaultFile(const char* filename) { _default_file = String(filename); return *this; } -AsyncStaticWebHandler& AsyncStaticWebHandler::setCacheControl(const char* cache_control){ +AsyncStaticWebHandler& AsyncStaticWebHandler::setCacheControl(const char* cache_control) { _cache_control = String(cache_control); return *this; } -AsyncStaticWebHandler& AsyncStaticWebHandler::setLastModified(const char* last_modified){ +AsyncStaticWebHandler& AsyncStaticWebHandler::setLastModified(const char* last_modified) { _last_modified = last_modified; return *this; } -AsyncStaticWebHandler& AsyncStaticWebHandler::setLastModified(struct tm* last_modified){ +AsyncStaticWebHandler& AsyncStaticWebHandler::setLastModified(struct tm* last_modified) { auto formatP = PSTR("%a, %d %b %Y %H:%M:%S %Z"); char format[strlen_P(formatP) + 1]; strcpy_P(format, formatP); char result[30]; strftime(result, sizeof(result), format, last_modified); - return setLastModified((const char *)result); + return setLastModified((const char*)result); } #ifdef ESP8266 -AsyncStaticWebHandler& AsyncStaticWebHandler::setLastModified(time_t last_modified){ - return setLastModified((struct tm *)gmtime(&last_modified)); +AsyncStaticWebHandler& AsyncStaticWebHandler::setLastModified(time_t last_modified) { + return setLastModified((struct tm*)gmtime(&last_modified)); } -AsyncStaticWebHandler& AsyncStaticWebHandler::setLastModified(){ +AsyncStaticWebHandler& AsyncStaticWebHandler::setLastModified() { time_t last_modified; - if(time(&last_modified) == 0) //time is not yet set + if (time(&last_modified) == 0) // time is not yet set return *this; return setLastModified(last_modified); } #endif -bool AsyncStaticWebHandler::canHandle(AsyncWebServerRequest *request){ - if(request->method() != HTTP_GET - || !request->url().startsWith(_uri) - || !request->isExpectedRequestedConnType(RCT_DEFAULT, RCT_HTTP) - ){ +bool AsyncStaticWebHandler::canHandle(AsyncWebServerRequest* request) { + if (request->method() != HTTP_GET || !request->url().startsWith(_uri) || !request->isExpectedRequestedConnType(RCT_DEFAULT, RCT_HTTP)) { return false; } if (_getFile(request)) { @@ -96,7 +96,7 @@ bool AsyncStaticWebHandler::canHandle(AsyncWebServerRequest *request){ if (_last_modified.length()) request->addInterestingHeader(F("If-Modified-Since")); - if(_cache_control.length()) + if (_cache_control.length()) request->addInterestingHeader(F("If-None-Match")); return true; @@ -105,13 +105,12 @@ bool AsyncStaticWebHandler::canHandle(AsyncWebServerRequest *request){ return false; } -bool AsyncStaticWebHandler::_getFile(AsyncWebServerRequest *request) -{ +bool AsyncStaticWebHandler::_getFile(AsyncWebServerRequest* request) { // Remove the found uri String path = request->url().substring(_uri.length()); // We can skip the file check and look for default if request is to the root of a directory or that request path ends with '/' - bool canSkipFileCheck = (_isDir && path.length() == 0) || (path.length() && path[path.length()-1] == '/'); + bool canSkipFileCheck = (_isDir && path.length() == 0) || (path.length() && path[path.length() - 1] == '/'); path = _path + path; @@ -124,7 +123,7 @@ bool AsyncStaticWebHandler::_getFile(AsyncWebServerRequest *request) return false; // Try to add default file, ensure there is a trailing '/' ot the path. - if (path.length() == 0 || path[path.length()-1] != '/') + if (path.length() == 0 || path[path.length() - 1] != '/') path += String('/'); path += _default_file; @@ -132,39 +131,38 @@ bool AsyncStaticWebHandler::_getFile(AsyncWebServerRequest *request) } #ifdef ESP32 -#define FILE_IS_REAL(f) (f == true && !f.isDirectory()) + #define FILE_IS_REAL(f) (f == true && !f.isDirectory()) #else -#define FILE_IS_REAL(f) (f == true) + #define FILE_IS_REAL(f) (f == true) #endif -bool AsyncStaticWebHandler::_fileExists(AsyncWebServerRequest *request, const String& path) -{ +bool AsyncStaticWebHandler::_fileExists(AsyncWebServerRequest* request, const String& path) { bool fileFound = false; bool gzipFound = false; String gzip = path + F(".gz"); if (_gzipFirst) { - if (_fs.exists(gzip)) { - request->_tempFile = _fs.open(gzip, fs::FileOpenMode::read); - gzipFound = FILE_IS_REAL(request->_tempFile); - } - if (!gzipFound){ - if (_fs.exists(path)) { - request->_tempFile = _fs.open(path, fs::FileOpenMode::read); - fileFound = FILE_IS_REAL(request->_tempFile); - } - } - } else { - if (_fs.exists(path)) { - request->_tempFile = _fs.open(path, fs::FileOpenMode::read); - fileFound = FILE_IS_REAL(request->_tempFile); - } - if (!fileFound){ - if (_fs.exists(gzip)) { + if (_fs.exists(gzip)) { request->_tempFile = _fs.open(gzip, fs::FileOpenMode::read); gzipFound = FILE_IS_REAL(request->_tempFile); - } + } + if (!gzipFound) { + if (_fs.exists(path)) { + request->_tempFile = _fs.open(path, fs::FileOpenMode::read); + fileFound = FILE_IS_REAL(request->_tempFile); + } + } + } else { + if (_fs.exists(path)) { + request->_tempFile = _fs.open(path, fs::FileOpenMode::read); + fileFound = FILE_IS_REAL(request->_tempFile); + } + if (!fileFound) { + if (_fs.exists(gzip)) { + request->_tempFile = _fs.open(gzip, fs::FileOpenMode::read); + gzipFound = FILE_IS_REAL(request->_tempFile); + } } } @@ -173,39 +171,41 @@ bool AsyncStaticWebHandler::_fileExists(AsyncWebServerRequest *request, const St if (found) { // Extract the file name from the path and keep it in _tempObject size_t pathLen = path.length(); - char * _tempPath = (char*)malloc(pathLen+1); - snprintf_P(_tempPath, pathLen+1, PSTR("%s"), path.c_str()); + char* _tempPath = (char*)malloc(pathLen + 1); + snprintf_P(_tempPath, pathLen + 1, PSTR("%s"), path.c_str()); request->_tempObject = (void*)_tempPath; // Calculate gzip statistic _gzipStats = (_gzipStats << 1) + (gzipFound ? 1 : 0); - if (_gzipStats == 0x00) _gzipFirst = false; // All files are not gzip - else if (_gzipStats == 0xFF) _gzipFirst = true; // All files are gzip - else _gzipFirst = _countBits(_gzipStats) > 4; // IF we have more gzip files - try gzip first + if (_gzipStats == 0x00) + _gzipFirst = false; // All files are not gzip + else if (_gzipStats == 0xFF) + _gzipFirst = true; // All files are gzip + else + _gzipFirst = _countBits(_gzipStats) > 4; // IF we have more gzip files - try gzip first } return found; } -uint8_t AsyncStaticWebHandler::_countBits(const uint8_t value) const -{ +uint8_t AsyncStaticWebHandler::_countBits(const uint8_t value) const { uint8_t w = value; uint8_t n; - for (n=0; w!=0; n++) w&=w-1; + for (n = 0; w != 0; n++) + w &= w - 1; return n; } -void AsyncStaticWebHandler::handleRequest(AsyncWebServerRequest *request) -{ +void AsyncStaticWebHandler::handleRequest(AsyncWebServerRequest* request) { // Get the filename from request->_tempObject and free it String filename = String((char*)request->_tempObject); free(request->_tempObject); request->_tempObject = NULL; - if((_username.length() && _password.length()) && !request->authenticate(_username.c_str(), _password.c_str())) - return request->requestAuthentication(); + if ((_username.length() && _password.length()) && !request->authenticate(_username.c_str(), _password.c_str())) + return request->requestAuthentication(); if (request->_tempFile == true) { - time_t lw = request->_tempFile.getLastWrite(); // get last file mod time (if supported by FS) + time_t lw = request->_tempFile.getLastWrite(); // get last file mod time (if supported by FS) // set etag to lastmod timestamp if available, otherwise to size String etag; if (lw) { @@ -219,15 +219,15 @@ void AsyncStaticWebHandler::handleRequest(AsyncWebServerRequest *request) request->send(304); // Not modified } else if (_cache_control.length() && request->hasHeader(F("If-None-Match")) && request->header(F("If-None-Match")).equals(etag)) { request->_tempFile.close(); - AsyncWebServerResponse * response = new AsyncBasicResponse(304); // Not modified + AsyncWebServerResponse* response = new AsyncBasicResponse(304); // Not modified response->addHeader(F("Cache-Control"), _cache_control); response->addHeader(F("ETag"), etag); request->send(response); } else { - AsyncWebServerResponse * response = new AsyncFileResponse(request->_tempFile, filename, String(), false, _callback); + AsyncWebServerResponse* response = new AsyncFileResponse(request->_tempFile, filename, String(), false, _callback); if (_last_modified.length()) response->addHeader(F("Last-Modified"), _last_modified); - if (_cache_control.length()){ + if (_cache_control.length()) { response->addHeader(F("Cache-Control"), _cache_control); response->addHeader(F("ETag"), etag); } diff --git a/src/WebRequest.cpp b/src/WebRequest.cpp index bb5d142..c31b9ef 100644 --- a/src/WebRequest.cpp +++ b/src/WebRequest.cpp @@ -19,185 +19,157 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "ESPAsyncWebServer.h" -#include "WebResponseImpl.h" #include "WebAuthentication.h" +#include "WebResponseImpl.h" #ifndef ESP8266 -#define os_strlen strlen + #define os_strlen strlen #endif #define __is_param_char(c) ((c) && ((c) != '{') && ((c) != '[') && ((c) != '&') && ((c) != '=')) -enum { PARSE_REQ_START, PARSE_REQ_HEADERS, PARSE_REQ_BODY, PARSE_REQ_END, PARSE_REQ_FAIL }; +enum { PARSE_REQ_START, + PARSE_REQ_HEADERS, + PARSE_REQ_BODY, + PARSE_REQ_END, + PARSE_REQ_FAIL }; AsyncWebServerRequest::AsyncWebServerRequest(AsyncWebServer* s, AsyncClient* c) - : _client(c) - , _server(s) - , _handler(NULL) - , _response(NULL) - , _temp() - , _parseState(0) - , _version(0) - , _method(HTTP_ANY) - , _url() - , _host() - , _contentType() - , _boundary() - , _authorization() - , _reqconntype(RCT_HTTP) - , _isDigest(false) - , _isMultipart(false) - , _isPlainPost(false) - , _expectingContinue(false) - , _contentLength(0) - , _parsedLength(0) - , _multiParseState(0) - , _boundaryPosition(0) - , _itemStartIndex(0) - , _itemSize(0) - , _itemName() - , _itemFilename() - , _itemType() - , _itemValue() - , _itemBuffer(0) - , _itemBufferIndex(0) - , _itemIsFile(false) - , _tempObject(NULL) -{ - c->onError([](void *r, AsyncClient* c, int8_t error){ (void)c; AsyncWebServerRequest *req = (AsyncWebServerRequest*)r; req->_onError(error); }, this); - c->onAck([](void *r, AsyncClient* c, size_t len, uint32_t time){ (void)c; AsyncWebServerRequest *req = (AsyncWebServerRequest*)r; req->_onAck(len, time); }, this); - c->onDisconnect([](void *r, AsyncClient* c){ AsyncWebServerRequest *req = (AsyncWebServerRequest*)r; req->_onDisconnect(); delete c; }, this); - c->onTimeout([](void *r, AsyncClient* c, uint32_t time){ (void)c; AsyncWebServerRequest *req = (AsyncWebServerRequest*)r; req->_onTimeout(time); }, this); - c->onData([](void *r, AsyncClient* c, void *buf, size_t len){ (void)c; AsyncWebServerRequest *req = (AsyncWebServerRequest*)r; req->_onData(buf, len); }, this); - c->onPoll([](void *r, AsyncClient* c){ (void)c; AsyncWebServerRequest *req = ( AsyncWebServerRequest*)r; req->_onPoll(); }, this); + : _client(c), _server(s), _handler(NULL), _response(NULL), _temp(), _parseState(0), _version(0), _method(HTTP_ANY), _url(), _host(), _contentType(), _boundary(), _authorization(), _reqconntype(RCT_HTTP), _isDigest(false), _isMultipart(false), _isPlainPost(false), _expectingContinue(false), _contentLength(0), _parsedLength(0), _multiParseState(0), _boundaryPosition(0), _itemStartIndex(0), _itemSize(0), _itemName(), _itemFilename(), _itemType(), _itemValue(), _itemBuffer(0), _itemBufferIndex(0), _itemIsFile(false), _tempObject(NULL) { + c->onError([](void* r, AsyncClient* c, int8_t error) { (void)c; AsyncWebServerRequest *req = (AsyncWebServerRequest*)r; req->_onError(error); }, this); + c->onAck([](void* r, AsyncClient* c, size_t len, uint32_t time) { (void)c; AsyncWebServerRequest *req = (AsyncWebServerRequest*)r; req->_onAck(len, time); }, this); + c->onDisconnect([](void* r, AsyncClient* c) { AsyncWebServerRequest *req = (AsyncWebServerRequest*)r; req->_onDisconnect(); delete c; }, this); + c->onTimeout([](void* r, AsyncClient* c, uint32_t time) { (void)c; AsyncWebServerRequest *req = (AsyncWebServerRequest*)r; req->_onTimeout(time); }, this); + c->onData([](void* r, AsyncClient* c, void* buf, size_t len) { (void)c; AsyncWebServerRequest *req = (AsyncWebServerRequest*)r; req->_onData(buf, len); }, this); + c->onPoll([](void* r, AsyncClient* c) { (void)c; AsyncWebServerRequest *req = ( AsyncWebServerRequest*)r; req->_onPoll(); }, this); } -AsyncWebServerRequest::~AsyncWebServerRequest(){ +AsyncWebServerRequest::~AsyncWebServerRequest() { _headers.clear(); _pathParams.clear(); _interestingHeaders.clear(); - if(_response != NULL){ + if (_response != NULL) { delete _response; } - if(_tempObject != NULL){ + if (_tempObject != NULL) { free(_tempObject); } - if(_tempFile){ + if (_tempFile) { _tempFile.close(); } - - if(_itemBuffer){ + + if (_itemBuffer) { free(_itemBuffer); } - } -void AsyncWebServerRequest::_onData(void *buf, size_t len){ +void AsyncWebServerRequest::_onData(void* buf, size_t len) { size_t i = 0; while (true) { - if(_parseState < PARSE_REQ_BODY){ - // Find new line in buf - char *str = (char*)buf; - for (i = 0; i < len; i++) { - if (str[i] == '\n') { - break; - } - } - if (i == len) { // No new line, just add the buffer in _temp - char ch = str[len-1]; - str[len-1] = 0; - _temp.reserve(_temp.length()+len); - _temp.concat(str); - _temp.concat(ch); - } else { // Found new line - extract it and parse - str[i] = 0; // Terminate the string at the end of the line. - _temp.concat(str); - _temp.trim(); - _parseLine(); - if (++i < len) { - // Still have more buffer to process - buf = str+i; - len-= i; - continue; - } - } - } else if(_parseState == PARSE_REQ_BODY){ - // A handler should be already attached at this point in _parseLine function. - // If handler does nothing (_onRequest is NULL), we don't need to really parse the body. - const bool needParse = _handler && !_handler->isRequestHandlerTrivial(); - if(_isMultipart){ - if(needParse){ - size_t i; - for(i=0; iisRequestHandlerTrivial(); + if (_isMultipart) { + if (needParse) { + size_t i; + for (i = 0; i < len; i++) { + _parseMultipartPostByte(((uint8_t*)buf)[i], i == len - 1); + _parsedLength++; + } + } else _parsedLength += len; - } else { - if(_parsedLength == 0){ - if(_contentType.startsWith(F("application/x-www-form-urlencoded"))){ - _isPlainPost = true; - } else if(_contentType == F("text/plain") && __is_param_char(((char*)buf)[0])){ - size_t i = 0; - while (ihandleBody(this, (uint8_t*)buf, len, _parsedLength, _contentLength); - _parsedLength += len; - } else if(needParse) { - size_t i; - for(i=0; ihandleBody(this, (uint8_t*)buf, len, _parsedLength, _contentLength); + _parsedLength += len; + } else if (needParse) { + size_t i; + for (i = 0; i < len; i++) { + _parsedLength++; + _parsePlainPostChar(((uint8_t*)buf)[i]); + } + } else { + _parsedLength += len; } - } else { - _parsedLength += len; + } + if (_parsedLength == _contentLength) { + _parseState = PARSE_REQ_END; + // check if authenticated before calling handleRequest and request auth instead + if (_handler) + _handler->handleRequest(this); + else + send(501); } } - if(_parsedLength == _contentLength){ - _parseState = PARSE_REQ_END; - //check if authenticated before calling handleRequest and request auth instead - if(_handler) _handler->handleRequest(this); - else send(501); - } - } - break; + break; } } -void AsyncWebServerRequest::_removeNotInterestingHeaders(){ - if (std::any_of(std::begin(_interestingHeaders), std::end(_interestingHeaders), - [](const String &str){ return str.equalsIgnoreCase(F("ANY")); })) - return; // nothing to do +void AsyncWebServerRequest::_removeNotInterestingHeaders() { + if (std::any_of(std::begin(_interestingHeaders), std::end(_interestingHeaders), [](const String& str) { return str.equalsIgnoreCase(F("ANY")); })) + return; // nothing to do - for(auto iter = std::begin(_headers); iter != std::end(_headers); ) - { - const auto name = iter->name(); + for (auto iter = std::begin(_headers); iter != std::end(_headers);) { + const auto name = iter->name(); - if (std::none_of(std::begin(_interestingHeaders), std::end(_interestingHeaders), - [&name](const String &str){ return str.equalsIgnoreCase(name); })) - iter = _headers.erase(iter); - else - iter++; + if (std::none_of(std::begin(_interestingHeaders), std::end(_interestingHeaders), [&name](const String& str) { return str.equalsIgnoreCase(name); })) + iter = _headers.erase(iter); + else + iter++; } } -void AsyncWebServerRequest::_onPoll(){ - //os_printf("p\n"); - if(_response != NULL && _client != NULL && _client->canSend()){ - if(!_response->_finished()){ +void AsyncWebServerRequest::_onPoll() { + // os_printf("p\n"); + if (_response != NULL && _client != NULL && _client->canSend()) { + if (!_response->_finished()) { _response->_ack(this, 0, 0); } else { AsyncWebServerResponse* r = _response; @@ -209,12 +181,12 @@ void AsyncWebServerRequest::_onPoll(){ } } -void AsyncWebServerRequest::_onAck(size_t len, uint32_t time){ - //os_printf("a:%u:%u\n", len, time); - if(_response != NULL){ - if(!_response->_finished()){ +void AsyncWebServerRequest::_onAck(size_t len, uint32_t time) { + // os_printf("a:%u:%u\n", len, time); + if (_response != NULL) { + if (!_response->_finished()) { _response->_ack(this, len, time); - } else if(_response->_finished()){ + } else if (_response->_finished()) { AsyncWebServerResponse* r = _response; _response = NULL; delete r; @@ -224,138 +196,142 @@ void AsyncWebServerRequest::_onAck(size_t len, uint32_t time){ } } -void AsyncWebServerRequest::_onError(int8_t error){ +void AsyncWebServerRequest::_onError(int8_t error) { (void)error; } -void AsyncWebServerRequest::_onTimeout(uint32_t time){ +void AsyncWebServerRequest::_onTimeout(uint32_t time) { (void)time; - //os_printf("TIMEOUT: %u, state: %s\n", time, _client->stateToString()); + // os_printf("TIMEOUT: %u, state: %s\n", time, _client->stateToString()); _client->close(); } -void AsyncWebServerRequest::onDisconnect (ArDisconnectHandler fn){ - _onDisconnectfn=fn; +void AsyncWebServerRequest::onDisconnect(ArDisconnectHandler fn) { + _onDisconnectfn = fn; } -void AsyncWebServerRequest::_onDisconnect(){ - //os_printf("d\n"); - if(_onDisconnectfn) { - _onDisconnectfn(); - } +void AsyncWebServerRequest::_onDisconnect() { + // os_printf("d\n"); + if (_onDisconnectfn) { + _onDisconnectfn(); + } _server->_handleDisconnect(this); } -void AsyncWebServerRequest::_addPathParam(const char *p){ +void AsyncWebServerRequest::_addPathParam(const char* p) { _pathParams.emplace_back(p); } -void AsyncWebServerRequest::_addGetParams(const String& params){ +void AsyncWebServerRequest::_addGetParams(const String& params) { size_t start = 0; - while (start < params.length()){ + while (start < params.length()) { int end = params.indexOf('&', start); - if (end < 0) end = params.length(); + if (end < 0) + end = params.length(); int equal = params.indexOf('=', start); - if (equal < 0 || equal > end) equal = end; - String name( params.substring(start, equal) ); - String value( equal + 1 < end ? params.substring(equal + 1, end) : String() ); + if (equal < 0 || equal > end) + equal = end; + String name(params.substring(start, equal)); + String value(equal + 1 < end ? params.substring(equal + 1, end) : String()); _params.emplace_back(urlDecode(name), urlDecode(value)); start = end + 1; } } -bool AsyncWebServerRequest::_parseReqHead(){ +bool AsyncWebServerRequest::_parseReqHead() { // Split the head into method, url and version int index = _temp.indexOf(' '); String m = _temp.substring(0, index); - index = _temp.indexOf(' ', index+1); - String u = _temp.substring(m.length()+1, index); - _temp = _temp.substring(index+1); + index = _temp.indexOf(' ', index + 1); + String u = _temp.substring(m.length() + 1, index); + _temp = _temp.substring(index + 1); - if(m == F("GET")){ + if (m == F("GET")) { _method = HTTP_GET; - } else if(m == F("POST")){ + } else if (m == F("POST")) { _method = HTTP_POST; - } else if(m == F("DELETE")){ + } else if (m == F("DELETE")) { _method = HTTP_DELETE; - } else if(m == F("PUT")){ + } else if (m == F("PUT")) { _method = HTTP_PUT; - } else if(m == F("PATCH")){ + } else if (m == F("PATCH")) { _method = HTTP_PATCH; - } else if(m == F("HEAD")){ + } else if (m == F("HEAD")) { _method = HTTP_HEAD; - } else if(m == F("OPTIONS")){ + } else if (m == F("OPTIONS")) { _method = HTTP_OPTIONS; } String g; index = u.indexOf('?'); - if(index > 0){ - g = u.substring(index +1); + if (index > 0) { + g = u.substring(index + 1); u = u.substring(0, index); } _url = urlDecode(u); _addGetParams(g); - if(!_temp.startsWith(F("HTTP/1.0"))) + if (!_temp.startsWith(F("HTTP/1.0"))) _version = 1; _temp = String(); return true; } -bool strContains(const String &src, const String &find, bool mindcase = true) { - int pos=0, i=0; +bool strContains(const String& src, const String& find, bool mindcase = true) { + int pos = 0, i = 0; const int slen = src.length(); const int flen = find.length(); - if (slen < flen) return false; + if (slen < flen) + return false; while (pos <= (slen - flen)) { - for (i=0; i < flen; i++) { + for (i = 0; i < flen; i++) { if (mindcase) { - if (src[pos+i] != find[i]) i = flen + 1; // no match - } - else if (tolower(src[pos+i]) != tolower(find[i])) { + if (src[pos + i] != find[i]) + i = flen + 1; // no match + } else if (tolower(src[pos + i]) != tolower(find[i])) { i = flen + 1; // no match } } - if (i == flen) return true; + if (i == flen) + return true; pos++; } return false; } -bool AsyncWebServerRequest::_parseReqHeader(){ +bool AsyncWebServerRequest::_parseReqHeader() { int index = _temp.indexOf(':'); - if(index){ + if (index) { String name = _temp.substring(0, index); String value = _temp.substring(index + 2); - if(name.equalsIgnoreCase("Host")){ + if (name.equalsIgnoreCase("Host")) { _host = value; - } else if(name.equalsIgnoreCase(F("Content-Type"))){ - _contentType = value.substring(0, value.indexOf(';')); - if (value.startsWith(F("multipart/"))){ - _boundary = value.substring(value.indexOf('=')+1); + } else if (name.equalsIgnoreCase(F("Content-Type"))) { + _contentType = value.substring(0, value.indexOf(';')); + if (value.startsWith(F("multipart/"))) { + _boundary = value.substring(value.indexOf('=') + 1); _boundary.replace(String('"'), String()); _isMultipart = true; } - } else if(name.equalsIgnoreCase(F("Content-Length"))){ + } else if (name.equalsIgnoreCase(F("Content-Length"))) { _contentLength = atoi(value.c_str()); - } else if(name.equalsIgnoreCase(F("Expect")) && value == F("100-continue")){ + } else if (name.equalsIgnoreCase(F("Expect")) && value == F("100-continue")) { _expectingContinue = true; - } else if(name.equalsIgnoreCase(F("Authorization"))){ - if(value.length() > 5 && value.substring(0,5).equalsIgnoreCase(F("Basic"))){ + } else if (name.equalsIgnoreCase(F("Authorization"))) { + if (value.length() > 5 && value.substring(0, 5).equalsIgnoreCase(F("Basic"))) { _authorization = value.substring(6); - } else if(value.length() > 6 && value.substring(0,6).equalsIgnoreCase(F("Digest"))){ + } else if (value.length() > 6 && value.substring(0, 6).equalsIgnoreCase(F("Digest"))) { _isDigest = true; _authorization = value.substring(7); } } else { - if(name.equalsIgnoreCase(F("Upgrade")) && value.equalsIgnoreCase(F("websocket"))){ + if (name.equalsIgnoreCase(F("Upgrade")) && value.equalsIgnoreCase(F("websocket"))) { // WebSocket request can be uniquely identified by header: [Upgrade: websocket] _reqconntype = RCT_WS; } else { - if(name.equalsIgnoreCase(F("Accept")) && strContains(value, F("text/event-stream"), false)){ + if (name.equalsIgnoreCase(F("Accept")) && strContains(value, F("text/event-stream"), false)) { // WebEvent request can be uniquely identified by header: [Accept: text/event-stream] _reqconntype = RCT_EVENT; } @@ -367,13 +343,13 @@ bool AsyncWebServerRequest::_parseReqHeader(){ return true; } -void AsyncWebServerRequest::_parsePlainPostChar(uint8_t data){ - if(data && (char)data != '&') +void AsyncWebServerRequest::_parsePlainPostChar(uint8_t data) { + if (data && (char)data != '&') _temp += (char)data; - if(!data || (char)data == '&' || _parsedLength == _contentLength){ + if (!data || (char)data == '&' || _parsedLength == _contentLength) { String name = F("body"); String value = _temp; - if(!_temp.startsWith(String('{')) && !_temp.startsWith(String('[')) && _temp.indexOf('=') > 0){ + if (!_temp.startsWith(String('{')) && !_temp.startsWith(String('[')) && _temp.indexOf('=') > 0) { name = _temp.substring(0, _temp.indexOf('=')); value = _temp.substring(_temp.indexOf('=') + 1); } @@ -382,12 +358,12 @@ void AsyncWebServerRequest::_parsePlainPostChar(uint8_t data){ } } -void AsyncWebServerRequest::_handleUploadByte(uint8_t data, bool last){ +void AsyncWebServerRequest::_handleUploadByte(uint8_t data, bool last) { _itemBuffer[_itemBufferIndex++] = data; - if(last || _itemBufferIndex == 1460){ - //check if authenticated before calling the upload - if(_handler) + if (last || _itemBufferIndex == 1460) { + // check if authenticated before calling the upload + if (_handler) _handler->handleUpload(this, _itemFilename, _itemSize - _itemBufferIndex, _itemBuffer, _itemBufferIndex, false); _itemBufferIndex = 0; } @@ -407,10 +383,17 @@ enum { PARSE_ERROR }; -void AsyncWebServerRequest::_parseMultipartPostByte(uint8_t data, bool last){ -#define itemWriteByte(b) do { _itemSize++; if(_itemIsFile) _handleUploadByte(b, last); else _itemValue+=(char)(b); } while(0) +void AsyncWebServerRequest::_parseMultipartPostByte(uint8_t data, bool last) { +#define itemWriteByte(b) \ + do { \ + _itemSize++; \ + if (_itemIsFile) \ + _handleUploadByte(b, last); \ + else \ + _itemValue += (char)(b); \ + } while (0) - if(!_parsedLength){ + if (!_parsedLength) { _multiParseState = EXPECT_BOUNDARY; _temp = String(); _itemName = String(); @@ -418,46 +401,46 @@ void AsyncWebServerRequest::_parseMultipartPostByte(uint8_t data, bool last){ _itemType = String(); } - if(_multiParseState == WAIT_FOR_RETURN1){ - if(data != '\r'){ + if (_multiParseState == WAIT_FOR_RETURN1) { + if (data != '\r') { itemWriteByte(data); } else { _multiParseState = EXPECT_FEED1; } - } else if(_multiParseState == EXPECT_BOUNDARY){ - if(_parsedLength < 2 && data != '-'){ + } else if (_multiParseState == EXPECT_BOUNDARY) { + if (_parsedLength < 2 && data != '-') { _multiParseState = PARSE_ERROR; return; - } else if(_parsedLength - 2 < _boundary.length() && _boundary.c_str()[_parsedLength - 2] != data){ + } else if (_parsedLength - 2 < _boundary.length() && _boundary.c_str()[_parsedLength - 2] != data) { _multiParseState = PARSE_ERROR; return; - } else if(_parsedLength - 2 == _boundary.length() && data != '\r'){ + } else if (_parsedLength - 2 == _boundary.length() && data != '\r') { _multiParseState = PARSE_ERROR; return; - } else if(_parsedLength - 3 == _boundary.length()){ - if(data != '\n'){ + } else if (_parsedLength - 3 == _boundary.length()) { + if (data != '\n') { _multiParseState = PARSE_ERROR; return; } _multiParseState = PARSE_HEADERS; _itemIsFile = false; } - } else if(_multiParseState == PARSE_HEADERS){ - if((char)data != '\r' && (char)data != '\n') - _temp += (char)data; - if((char)data == '\n'){ - if(_temp.length()){ - if(_temp.length() > 12 && _temp.substring(0, 12).equalsIgnoreCase(F("Content-Type"))){ + } else if (_multiParseState == PARSE_HEADERS) { + if ((char)data != '\r' && (char)data != '\n') + _temp += (char)data; + if ((char)data == '\n') { + if (_temp.length()) { + if (_temp.length() > 12 && _temp.substring(0, 12).equalsIgnoreCase(F("Content-Type"))) { _itemType = _temp.substring(14); _itemIsFile = true; - } else if(_temp.length() > 19 && _temp.substring(0, 19).equalsIgnoreCase(F("Content-Disposition"))){ + } else if (_temp.length() > 19 && _temp.substring(0, 19).equalsIgnoreCase(F("Content-Disposition"))) { _temp = _temp.substring(_temp.indexOf(';') + 2); - while(_temp.indexOf(';') > 0){ + while (_temp.indexOf(';') > 0) { String name = _temp.substring(0, _temp.indexOf('=')); String nameVal = _temp.substring(_temp.indexOf('=') + 2, _temp.indexOf(';') - 1); - if(name == F("name")){ + if (name == F("name")) { _itemName = nameVal; - } else if(name == F("filename")){ + } else if (name == F("filename")) { _itemFilename = nameVal; _itemIsFile = true; } @@ -465,9 +448,9 @@ void AsyncWebServerRequest::_parseMultipartPostByte(uint8_t data, bool last){ } String name = _temp.substring(0, _temp.indexOf('=')); String nameVal = _temp.substring(_temp.indexOf('=') + 2, _temp.length() - 1); - if(name == F("name")){ + if (name == F("name")) { _itemName = nameVal; - } else if(name == F("filename")){ + } else if (name == F("filename")) { _itemFilename = nameVal; _itemIsFile = true; } @@ -475,15 +458,15 @@ void AsyncWebServerRequest::_parseMultipartPostByte(uint8_t data, bool last){ _temp = String(); } else { _multiParseState = WAIT_FOR_RETURN1; - //value starts from here + // value starts from here _itemSize = 0; _itemStartIndex = _parsedLength; _itemValue = String(); - if(_itemIsFile){ - if(_itemBuffer) + if (_itemIsFile) { + if (_itemBuffer) free(_itemBuffer); _itemBuffer = (uint8_t*)malloc(1460); - if(_itemBuffer == NULL){ + if (_itemBuffer == NULL) { _multiParseState = PARSE_ERROR; return; } @@ -491,44 +474,54 @@ void AsyncWebServerRequest::_parseMultipartPostByte(uint8_t data, bool last){ } } } - } else if(_multiParseState == EXPECT_FEED1){ - if(data != '\n'){ + } else if (_multiParseState == EXPECT_FEED1) { + if (data != '\n') { _multiParseState = WAIT_FOR_RETURN1; - itemWriteByte('\r'); _parseMultipartPostByte(data, last); + itemWriteByte('\r'); + _parseMultipartPostByte(data, last); } else { _multiParseState = EXPECT_DASH1; } - } else if(_multiParseState == EXPECT_DASH1){ - if(data != '-'){ + } else if (_multiParseState == EXPECT_DASH1) { + if (data != '-') { _multiParseState = WAIT_FOR_RETURN1; - itemWriteByte('\r'); itemWriteByte('\n'); _parseMultipartPostByte(data, last); + itemWriteByte('\r'); + itemWriteByte('\n'); + _parseMultipartPostByte(data, last); } else { _multiParseState = EXPECT_DASH2; } - } else if(_multiParseState == EXPECT_DASH2){ - if(data != '-'){ + } else if (_multiParseState == EXPECT_DASH2) { + if (data != '-') { _multiParseState = WAIT_FOR_RETURN1; - itemWriteByte('\r'); itemWriteByte('\n'); itemWriteByte('-'); _parseMultipartPostByte(data, last); + itemWriteByte('\r'); + itemWriteByte('\n'); + itemWriteByte('-'); + _parseMultipartPostByte(data, last); } else { _multiParseState = BOUNDARY_OR_DATA; _boundaryPosition = 0; } - } else if(_multiParseState == BOUNDARY_OR_DATA){ - if(_boundaryPosition < _boundary.length() && _boundary.c_str()[_boundaryPosition] != data){ + } else if (_multiParseState == BOUNDARY_OR_DATA) { + if (_boundaryPosition < _boundary.length() && _boundary.c_str()[_boundaryPosition] != data) { _multiParseState = WAIT_FOR_RETURN1; - itemWriteByte('\r'); itemWriteByte('\n'); itemWriteByte('-'); itemWriteByte('-'); + itemWriteByte('\r'); + itemWriteByte('\n'); + itemWriteByte('-'); + itemWriteByte('-'); uint8_t i; - for(i=0; i<_boundaryPosition; i++) + for (i = 0; i < _boundaryPosition; i++) itemWriteByte(_boundary.c_str()[i]); _parseMultipartPostByte(data, last); - } else if(_boundaryPosition == _boundary.length() - 1){ + } else if (_boundaryPosition == _boundary.length() - 1) { _multiParseState = DASH3_OR_RETURN2; - if(!_itemIsFile){ + if (!_itemIsFile) { _params.emplace_back(_itemName, _itemValue, true); } else { - if(_itemSize){ - //check if authenticated before calling the upload - if(_handler) _handler->handleUpload(this, _itemFilename, _itemSize - _itemBufferIndex, _itemBuffer, _itemBufferIndex, true); + if (_itemSize) { + // check if authenticated before calling the upload + if (_handler) + _handler->handleUpload(this, _itemFilename, _itemSize - _itemBufferIndex, _itemBuffer, _itemBufferIndex, true); _itemBufferIndex = 0; _params.emplace_back(_itemName, _itemFilename, true, true, _itemSize); } @@ -539,37 +532,48 @@ void AsyncWebServerRequest::_parseMultipartPostByte(uint8_t data, bool last){ } else { _boundaryPosition++; } - } else if(_multiParseState == DASH3_OR_RETURN2){ - if(data == '-' && (_contentLength - _parsedLength - 4) != 0){ - //os_printf("ERROR: The parser got to the end of the POST but is expecting %u bytes more!\nDrop an issue so we can have more info on the matter!\n", _contentLength - _parsedLength - 4); - _contentLength = _parsedLength + 4;//lets close the request gracefully + } else if (_multiParseState == DASH3_OR_RETURN2) { + if (data == '-' && (_contentLength - _parsedLength - 4) != 0) { + // os_printf("ERROR: The parser got to the end of the POST but is expecting %u bytes more!\nDrop an issue so we can have more info on the matter!\n", _contentLength - _parsedLength - 4); + _contentLength = _parsedLength + 4; // lets close the request gracefully } - if(data == '\r'){ + if (data == '\r') { _multiParseState = EXPECT_FEED2; - } else if(data == '-' && _contentLength == (_parsedLength + 4)){ + } else if (data == '-' && _contentLength == (_parsedLength + 4)) { _multiParseState = PARSING_FINISHED; } else { _multiParseState = WAIT_FOR_RETURN1; - itemWriteByte('\r'); itemWriteByte('\n'); itemWriteByte('-'); itemWriteByte('-'); - uint8_t i; for(i=0; i<_boundary.length(); i++) itemWriteByte(_boundary.c_str()[i]); + itemWriteByte('\r'); + itemWriteByte('\n'); + itemWriteByte('-'); + itemWriteByte('-'); + uint8_t i; + for (i = 0; i < _boundary.length(); i++) + itemWriteByte(_boundary.c_str()[i]); _parseMultipartPostByte(data, last); } - } else if(_multiParseState == EXPECT_FEED2){ - if(data == '\n'){ + } else if (_multiParseState == EXPECT_FEED2) { + if (data == '\n') { _multiParseState = PARSE_HEADERS; _itemIsFile = false; } else { _multiParseState = WAIT_FOR_RETURN1; - itemWriteByte('\r'); itemWriteByte('\n'); itemWriteByte('-'); itemWriteByte('-'); - uint8_t i; for(i=0; i<_boundary.length(); i++) itemWriteByte(_boundary.c_str()[i]); - itemWriteByte('\r'); _parseMultipartPostByte(data, last); + itemWriteByte('\r'); + itemWriteByte('\n'); + itemWriteByte('-'); + itemWriteByte('-'); + uint8_t i; + for (i = 0; i < _boundary.length(); i++) + itemWriteByte(_boundary.c_str()[i]); + itemWriteByte('\r'); + _parseMultipartPostByte(data, last); } } } -void AsyncWebServerRequest::_parseLine(){ - if(_parseState == PARSE_REQ_START){ - if(!_temp.length()){ +void AsyncWebServerRequest::_parseLine() { + if (_parseState == PARSE_REQ_START) { + if (!_temp.length()) { _parseState = PARSE_REQ_FAIL; _client->close(); } else { @@ -579,35 +583,38 @@ void AsyncWebServerRequest::_parseLine(){ return; } - if(_parseState == PARSE_REQ_HEADERS){ - if(!_temp.length()){ - //end of headers + if (_parseState == PARSE_REQ_HEADERS) { + if (!_temp.length()) { + // end of headers _server->_rewriteRequest(this); _server->_attachHandler(this); _removeNotInterestingHeaders(); - if(_expectingContinue){ + if (_expectingContinue) { String response = F("HTTP/1.1 100 Continue\r\n\r\n"); _client->write(response.c_str(), response.length()); } - //check handler for authentication - if(_contentLength){ + // check handler for authentication + if (_contentLength) { _parseState = PARSE_REQ_BODY; } else { _parseState = PARSE_REQ_END; - if(_handler) _handler->handleRequest(this); - else send(501); + if (_handler) + _handler->handleRequest(this); + else + send(501); } - } else _parseReqHeader(); + } else + _parseReqHeader(); } } -size_t AsyncWebServerRequest::headers() const{ +size_t AsyncWebServerRequest::headers() const { return _headers.size(); } bool AsyncWebServerRequest::hasHeader(const char* name) const { - for(const auto& h: _headers){ - if(h.name().equalsIgnoreCase(name)){ + for (const auto& h : _headers) { + if (h.name().equalsIgnoreCase(name)) { return true; } } @@ -615,26 +622,25 @@ bool AsyncWebServerRequest::hasHeader(const char* name) const { } #ifdef ESP8266 -bool AsyncWebServerRequest::hasHeader(const __FlashStringHelper * data) const { +bool AsyncWebServerRequest::hasHeader(const __FlashStringHelper* data) const { return hasHeader(String(data)); } #endif 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); }); + auto iter = std::find_if(std::begin(_headers), std::end(_headers), [&name](const AsyncWebHeader& header) { return header.name().equalsIgnoreCase(name); }); return (iter == std::end(_headers)) ? nullptr : &(*iter); } #ifdef ESP8266 -const AsyncWebHeader* AsyncWebServerRequest::getHeader(const __FlashStringHelper * data) const { +const AsyncWebHeader* AsyncWebServerRequest::getHeader(const __FlashStringHelper* data) const { PGM_P p = reinterpret_cast(data); size_t n = strlen_P(p); - char * name = (char*) malloc(n+1); + char* name = (char*)malloc(n + 1); if (name) { strcpy_P(name, p); - const AsyncWebHeader* result = getHeader( String(name)); + const AsyncWebHeader* result = getHeader(String(name)); free(name); return result; } else { @@ -645,7 +651,7 @@ const AsyncWebHeader* AsyncWebServerRequest::getHeader(const __FlashStringHelper const AsyncWebHeader* AsyncWebServerRequest::getHeader(size_t num) const { if (num >= _headers.size()) - return nullptr; + return nullptr; return &(*std::next(_headers.cbegin(), num)); } @@ -654,21 +660,21 @@ size_t AsyncWebServerRequest::params() const { } bool AsyncWebServerRequest::hasParam(const String& name, bool post, bool file) const { - for(const auto& p: _params){ - if(p.name() == name && p.isPost() == post && p.isFile() == file){ + for (const auto& p : _params) { + if (p.name() == name && p.isPost() == post && p.isFile() == file) { return true; } } return false; } -bool AsyncWebServerRequest::hasParam(const __FlashStringHelper * data, bool post, bool file) const { +bool AsyncWebServerRequest::hasParam(const __FlashStringHelper* data, bool post, bool file) const { return hasParam(String(data).c_str(), post, file); } 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){ + for (const auto& p : _params) { + if (p.name() == name && p.isPost() == post && p.isFile() == file) { return &p; } } @@ -676,134 +682,134 @@ const AsyncWebParameter* AsyncWebServerRequest::getParam(const char* name, bool } #ifdef ESP8266 -const AsyncWebParameter* AsyncWebServerRequest::getParam(const __FlashStringHelper * data, bool post, bool file) const { +const AsyncWebParameter* AsyncWebServerRequest::getParam(const __FlashStringHelper* data, bool post, bool file) const { return getParam(String(data), post, file); } #endif const AsyncWebParameter* AsyncWebServerRequest::getParam(size_t num) const { if (num >= _params.size()) - return nullptr; + return nullptr; return &(*std::next(_params.cbegin(), num)); } -void AsyncWebServerRequest::addInterestingHeader(const char* name){ - if(std::none_of(std::begin(_interestingHeaders), std::end(_interestingHeaders), - [&name](const String &str){ return str.equalsIgnoreCase(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.emplace_back(name); } -AsyncWebServerResponse * AsyncWebServerRequest::beginResponse(int code, const String& contentType, const String& content){ +AsyncWebServerResponse* AsyncWebServerRequest::beginResponse(int code, const String& contentType, const String& content) { return new AsyncBasicResponse(code, contentType, content); } -AsyncWebServerResponse * AsyncWebServerRequest::beginResponse(FS &fs, const String& path, const String& contentType, bool download, AwsTemplateProcessor callback){ - if(fs.exists(path) || (!download && fs.exists(path+F(".gz")))) +AsyncWebServerResponse* AsyncWebServerRequest::beginResponse(FS& fs, const String& path, const String& contentType, bool download, AwsTemplateProcessor callback) { + if (fs.exists(path) || (!download && fs.exists(path + F(".gz")))) return new AsyncFileResponse(fs, path, contentType, download, callback); return NULL; } -AsyncWebServerResponse * AsyncWebServerRequest::beginResponse(File content, const String& path, const String& contentType, bool download, AwsTemplateProcessor callback){ - if(content == true) +AsyncWebServerResponse* AsyncWebServerRequest::beginResponse(File content, const String& path, const String& contentType, bool download, AwsTemplateProcessor callback) { + if (content == true) return new AsyncFileResponse(content, path, contentType, download, callback); return NULL; } -AsyncWebServerResponse * AsyncWebServerRequest::beginResponse(Stream &stream, const String& contentType, size_t len, AwsTemplateProcessor callback){ +AsyncWebServerResponse* AsyncWebServerRequest::beginResponse(Stream& stream, const String& contentType, size_t len, AwsTemplateProcessor callback) { return new AsyncStreamResponse(stream, contentType, len, callback); } -AsyncWebServerResponse * AsyncWebServerRequest::beginResponse(const String& contentType, size_t len, AwsResponseFiller callback, AwsTemplateProcessor templateCallback){ +AsyncWebServerResponse* AsyncWebServerRequest::beginResponse(const String& contentType, size_t len, AwsResponseFiller callback, AwsTemplateProcessor templateCallback) { return new AsyncCallbackResponse(contentType, len, callback, templateCallback); } -AsyncWebServerResponse * AsyncWebServerRequest::beginChunkedResponse(const String& contentType, AwsResponseFiller callback, AwsTemplateProcessor templateCallback){ - if(_version) +AsyncWebServerResponse* AsyncWebServerRequest::beginChunkedResponse(const String& contentType, AwsResponseFiller callback, AwsTemplateProcessor templateCallback) { + if (_version) return new AsyncChunkedResponse(contentType, callback, templateCallback); return new AsyncCallbackResponse(contentType, 0, callback, templateCallback); } -AsyncResponseStream * AsyncWebServerRequest::beginResponseStream(const String& contentType, size_t bufferSize){ +AsyncResponseStream* AsyncWebServerRequest::beginResponseStream(const String& contentType, size_t bufferSize) { 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){ +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); } -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); +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){ +void AsyncWebServerRequest::send(AsyncWebServerResponse* response) { _response = response; - if(_response == NULL){ + if (_response == NULL) { _client->close(true); _onDisconnect(); return; } - if(!_response->_sourceValid()){ + if (!_response->_sourceValid()) { delete response; _response = NULL; send(500); - } - else { + } else { _client->setRxTimeout(0); _response->_respond(this); } } -void AsyncWebServerRequest::send(int code, const String& contentType, const String& content){ +void AsyncWebServerRequest::send(int code, const String& contentType, const String& content) { send(beginResponse(code, contentType, content)); } -void AsyncWebServerRequest::send(FS &fs, const String& path, const String& contentType, bool download, AwsTemplateProcessor callback){ - if(fs.exists(path) || (!download && fs.exists(path+F(".gz")))){ +void AsyncWebServerRequest::send(FS& fs, const String& path, const String& contentType, bool download, AwsTemplateProcessor callback) { + if (fs.exists(path) || (!download && fs.exists(path + F(".gz")))) { send(beginResponse(fs, path, contentType, download, callback)); - } else send(404); + } else + send(404); } -void AsyncWebServerRequest::send(File content, const String& path, const String& contentType, bool download, AwsTemplateProcessor callback){ - if(content == true){ +void AsyncWebServerRequest::send(File content, const String& path, const String& contentType, bool download, AwsTemplateProcessor callback) { + if (content == true) { send(beginResponse(content, path, contentType, download, callback)); - } else send(404); + } else + send(404); } -void AsyncWebServerRequest::send(Stream &stream, const String& contentType, size_t len, AwsTemplateProcessor callback){ +void AsyncWebServerRequest::send(Stream& stream, const String& contentType, size_t len, AwsTemplateProcessor callback) { send(beginResponse(stream, contentType, len, callback)); } -void AsyncWebServerRequest::send(const String& contentType, size_t len, AwsResponseFiller callback, AwsTemplateProcessor templateCallback){ +void AsyncWebServerRequest::send(const String& contentType, size_t len, AwsResponseFiller callback, AwsTemplateProcessor templateCallback) { send(beginResponse(contentType, len, callback, templateCallback)); } -void AsyncWebServerRequest::sendChunked(const String& contentType, AwsResponseFiller callback, AwsTemplateProcessor templateCallback){ +void AsyncWebServerRequest::sendChunked(const String& contentType, AwsResponseFiller callback, AwsTemplateProcessor templateCallback) { 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){ +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)); } -void AsyncWebServerRequest::send_P(int code, const String& contentType, PGM_P content, AwsTemplateProcessor callback){ +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 char* url){ - AsyncWebServerResponse * response = beginResponse(302); +void AsyncWebServerRequest::redirect(const char* url) { + AsyncWebServerResponse* response = beginResponse(302); response->addHeader(F("Location"), url); send(response); } -bool AsyncWebServerRequest::authenticate(const char * username, const char * password, const char * realm, bool passwordIsHash){ - if(_authorization.length()){ - if(_isDigest) +bool AsyncWebServerRequest::authenticate(const char* username, const char* password, const char* realm, bool passwordIsHash) { + if (_authorization.length()) { + if (_isDigest) return checkDigestAuthentication(_authorization.c_str(), methodToString(), username, password, realm, passwordIsHash, NULL, NULL, NULL); - else if(!passwordIsHash) + else if (!passwordIsHash) return checkBasicAuthentication(_authorization.c_str(), username, password); else return _authorization.equals(password); @@ -811,19 +817,19 @@ bool AsyncWebServerRequest::authenticate(const char * username, const char * pas return false; } -bool AsyncWebServerRequest::authenticate(const char * hash){ - if(!_authorization.length() || hash == NULL) +bool AsyncWebServerRequest::authenticate(const char* hash) { + if (!_authorization.length() || hash == NULL) return false; - if(_isDigest){ + if (_isDigest) { String hStr = String(hash); int separator = hStr.indexOf(':'); - if(separator <= 0) + if (separator <= 0) return false; String username = hStr.substring(0, separator); hStr = hStr.substring(separator + 1); separator = hStr.indexOf(':'); - if(separator <= 0) + if (separator <= 0) return false; String realm = hStr.substring(0, separator); hStr = hStr.substring(separator + 1); @@ -833,11 +839,11 @@ bool AsyncWebServerRequest::authenticate(const char * hash){ return (_authorization.equals(hash)); } -void AsyncWebServerRequest::requestAuthentication(const char * realm, bool isDigest){ - AsyncWebServerResponse * r = beginResponse(401); - if(!isDigest && realm == NULL){ +void AsyncWebServerRequest::requestAuthentication(const char* realm, bool isDigest) { + AsyncWebServerResponse* r = beginResponse(401); + if (!isDigest && realm == NULL) { r->addHeader(F("WWW-Authenticate"), F("Basic realm=\"Login Required\"")); - } else if(!isDigest){ + } else if (!isDigest) { String header = F("Basic realm=\""); header.concat(realm); header += '"'; @@ -851,8 +857,8 @@ void AsyncWebServerRequest::requestAuthentication(const char * realm, bool isDig } bool AsyncWebServerRequest::hasArg(const char* name) const { - for(const auto& arg: _params){ - if(arg.name() == name){ + for (const auto& arg : _params) { + if (arg.name() == name) { return true; } } @@ -860,14 +866,14 @@ bool AsyncWebServerRequest::hasArg(const char* name) const { } #ifdef ESP8266 -bool AsyncWebServerRequest::hasArg(const __FlashStringHelper * data) const { +bool AsyncWebServerRequest::hasArg(const __FlashStringHelper* data) const { return hasArg(String(data).c_str()); } #endif const String& AsyncWebServerRequest::arg(const char* name) const { - for(const auto& arg: _params){ - if(arg.name() == name){ + for (const auto& arg : _params) { + if (arg.name() == name) { return arg.value(); } } @@ -875,7 +881,7 @@ const String& AsyncWebServerRequest::arg(const char* name) const { } #ifdef ESP8266 -const String& AsyncWebServerRequest::arg(const __FlashStringHelper * data) const { +const String& AsyncWebServerRequest::arg(const __FlashStringHelper* data) const { return arg(String(data).c_str()); } #endif @@ -898,14 +904,14 @@ const String& AsyncWebServerRequest::header(const char* name) const { } #ifdef ESP8266 -const String& AsyncWebServerRequest::header(const __FlashStringHelper * data) const { +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); - return h ? h->value() : emptyString; + return h ? h->value() : emptyString; } const String& AsyncWebServerRequest::headerName(size_t i) const { @@ -919,17 +925,17 @@ String AsyncWebServerRequest::urlDecode(const String& text) const { unsigned int i = 0; String decoded; decoded.reserve(len); // Allocate the string internal buffer - never longer from source text - while (i < len){ + while (i < len) { char decodedChar; char encodedChar = text.charAt(i++); - if ((encodedChar == '%') && (i + 1 < len)){ + if ((encodedChar == '%') && (i + 1 < len)) { temp[2] = text.charAt(i++); temp[3] = text.charAt(i++); decodedChar = strtol(temp, NULL, 16); } else if (encodedChar == '+') { decodedChar = ' '; } else { - decodedChar = encodedChar; // normal ascii char + decodedChar = encodedChar; // normal ascii char } decoded.concat(decodedChar); } @@ -938,58 +944,89 @@ String AsyncWebServerRequest::urlDecode(const String& text) const { #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"; + 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"; + 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"); - else if(_method & HTTP_POST) return F("POST"); - else if(_method & HTTP_DELETE) return F("DELETE"); - else if(_method & HTTP_PUT) return F("PUT"); - else if(_method & HTTP_PATCH) return F("PATCH"); - else if(_method & HTTP_HEAD) return F("HEAD"); - else if(_method & HTTP_OPTIONS) return F("OPTIONS"); +const __FlashStringHelper* AsyncWebServerRequest::methodToString() const { + if (_method == HTTP_ANY) + return F("ANY"); + else if (_method & HTTP_GET) + return F("GET"); + else if (_method & HTTP_POST) + return F("POST"); + else if (_method & HTTP_DELETE) + return F("DELETE"); + else if (_method & HTTP_PUT) + return F("PUT"); + else if (_method & HTTP_PATCH) + return F("PATCH"); + else if (_method & HTTP_HEAD) + return F("HEAD"); + else if (_method & HTTP_OPTIONS) + return F("OPTIONS"); return F("UNKNOWN"); } -const __FlashStringHelper *AsyncWebServerRequest::requestedConnTypeToString() const { +const __FlashStringHelper* AsyncWebServerRequest::requestedConnTypeToString() const { switch (_reqconntype) { - case RCT_NOT_USED: return F("RCT_NOT_USED"); - case RCT_DEFAULT: return F("RCT_DEFAULT"); - case RCT_HTTP: return F("RCT_HTTP"); - case RCT_WS: return F("RCT_WS"); - case RCT_EVENT: return F("RCT_EVENT"); - default: return F("ERROR"); + case RCT_NOT_USED: + return F("RCT_NOT_USED"); + case RCT_DEFAULT: + return F("RCT_DEFAULT"); + case RCT_HTTP: + return F("RCT_HTTP"); + case RCT_WS: + return F("RCT_WS"); + case RCT_EVENT: + return F("RCT_EVENT"); + default: + return F("ERROR"); } } #endif bool AsyncWebServerRequest::isExpectedRequestedConnType(RequestedConnectionType erct1, RequestedConnectionType erct2, RequestedConnectionType erct3) { - bool res = false; - if ((erct1 != RCT_NOT_USED) && (erct1 == _reqconntype)) res = true; - if ((erct2 != RCT_NOT_USED) && (erct2 == _reqconntype)) res = true; - if ((erct3 != RCT_NOT_USED) && (erct3 == _reqconntype)) res = true; - return res; + bool res = false; + if ((erct1 != RCT_NOT_USED) && (erct1 == _reqconntype)) + res = true; + if ((erct2 != RCT_NOT_USED) && (erct2 == _reqconntype)) + res = true; + if ((erct3 != RCT_NOT_USED) && (erct3 == _reqconntype)) + res = true; + return res; } diff --git a/src/WebResponseImpl.h b/src/WebResponseImpl.h index 4a47225..26ec223 100644 --- a/src/WebResponseImpl.h +++ b/src/WebResponseImpl.h @@ -22,115 +22,125 @@ #define ASYNCWEBSERVERRESPONSEIMPL_H_ #ifdef Arduino_h -// arduino is not compatible with std::vector -#undef min -#undef max + // arduino is not compatible with std::vector + #undef min + #undef max #endif -#include #include +#include // It is possible to restore these defines, but one can use _min and _max instead. Or std::min, std::max. -class AsyncBasicResponse: public AsyncWebServerResponse { +class AsyncBasicResponse : public AsyncWebServerResponse { private: String _content; + public: - AsyncBasicResponse(int code, const String& contentType=String(), const String& content=String()); - void _respond(AsyncWebServerRequest *request); - size_t _ack(AsyncWebServerRequest *request, size_t len, uint32_t time); + AsyncBasicResponse(int code, const String& contentType = String(), const String& content = String()); + void _respond(AsyncWebServerRequest* request); + size_t _ack(AsyncWebServerRequest* request, size_t len, uint32_t time); bool _sourceValid() const { return true; } }; -class AsyncAbstractResponse: public AsyncWebServerResponse { +class AsyncAbstractResponse : public AsyncWebServerResponse { private: String _head; - // Data is inserted into cache at begin(). - // This is inefficient with vector, but if we use some other container, + // Data is inserted into cache at begin(). + // This is inefficient with vector, but if we use some other container, // we won't be able to access it as contiguous array of bytes when reading from it, // so by gaining performance in one place, we'll lose it in another. std::vector _cache; size_t _readDataFromCacheOrContent(uint8_t* data, const size_t len); size_t _fillBufferAndProcessTemplates(uint8_t* buf, size_t maxLen); + protected: AwsTemplateProcessor _callback; + public: - AsyncAbstractResponse(AwsTemplateProcessor callback=nullptr); - void _respond(AsyncWebServerRequest *request); - size_t _ack(AsyncWebServerRequest *request, size_t len, uint32_t time); + AsyncAbstractResponse(AwsTemplateProcessor callback = nullptr); + void _respond(AsyncWebServerRequest* request); + size_t _ack(AsyncWebServerRequest* request, size_t len, uint32_t time); bool _sourceValid() const { return false; } - virtual size_t _fillBuffer(uint8_t *buf __attribute__((unused)), size_t maxLen __attribute__((unused))) { return 0; } + virtual size_t _fillBuffer(uint8_t* buf __attribute__((unused)), size_t maxLen __attribute__((unused))) { return 0; } }; #ifndef TEMPLATE_PLACEHOLDER -#define TEMPLATE_PLACEHOLDER '%' + #define TEMPLATE_PLACEHOLDER '%' #endif #define TEMPLATE_PARAM_NAME_LENGTH 32 -class AsyncFileResponse: public AsyncAbstractResponse { - using File = fs::File; - using FS = fs::FS; +class AsyncFileResponse : public AsyncAbstractResponse { + using File = fs::File; + using FS = fs::FS; + private: File _content; String _path; void _setContentType(const String& path); + public: - AsyncFileResponse(FS &fs, const String& path, const String& contentType=String(), bool download=false, AwsTemplateProcessor callback=nullptr); - AsyncFileResponse(File content, const String& path, const String& contentType=String(), bool download=false, AwsTemplateProcessor callback=nullptr); + AsyncFileResponse(FS& fs, const String& path, const String& contentType = String(), bool download = false, AwsTemplateProcessor callback = nullptr); + AsyncFileResponse(File content, const String& path, const String& contentType = String(), bool download = false, AwsTemplateProcessor callback = nullptr); ~AsyncFileResponse(); bool _sourceValid() const { return !!(_content); } - virtual size_t _fillBuffer(uint8_t *buf, size_t maxLen) override; + virtual size_t _fillBuffer(uint8_t* buf, size_t maxLen) override; }; -class AsyncStreamResponse: public AsyncAbstractResponse { +class AsyncStreamResponse : public AsyncAbstractResponse { private: - Stream *_content; + Stream* _content; + public: - AsyncStreamResponse(Stream &stream, const String& contentType, size_t len, AwsTemplateProcessor callback=nullptr); + AsyncStreamResponse(Stream& stream, const String& contentType, size_t len, AwsTemplateProcessor callback = nullptr); bool _sourceValid() const { return !!(_content); } - virtual size_t _fillBuffer(uint8_t *buf, size_t maxLen) override; + virtual size_t _fillBuffer(uint8_t* buf, size_t maxLen) override; }; -class AsyncCallbackResponse: public AsyncAbstractResponse { +class AsyncCallbackResponse : public AsyncAbstractResponse { private: AwsResponseFiller _content; size_t _filledLength; + public: - AsyncCallbackResponse(const String& contentType, size_t len, AwsResponseFiller callback, AwsTemplateProcessor templateCallback=nullptr); + AsyncCallbackResponse(const String& contentType, size_t len, AwsResponseFiller callback, AwsTemplateProcessor templateCallback = nullptr); bool _sourceValid() const { return !!(_content); } - virtual size_t _fillBuffer(uint8_t *buf, size_t maxLen) override; + virtual size_t _fillBuffer(uint8_t* buf, size_t maxLen) override; }; -class AsyncChunkedResponse: public AsyncAbstractResponse { +class AsyncChunkedResponse : public AsyncAbstractResponse { private: AwsResponseFiller _content; size_t _filledLength; + public: - AsyncChunkedResponse(const String& contentType, AwsResponseFiller callback, AwsTemplateProcessor templateCallback=nullptr); + AsyncChunkedResponse(const String& contentType, AwsResponseFiller callback, AwsTemplateProcessor templateCallback = nullptr); bool _sourceValid() const { return !!(_content); } - virtual size_t _fillBuffer(uint8_t *buf, size_t maxLen) override; + virtual size_t _fillBuffer(uint8_t* buf, size_t maxLen) override; }; -class AsyncProgmemResponse: public AsyncAbstractResponse { +class AsyncProgmemResponse : public AsyncAbstractResponse { private: - const uint8_t * _content; + const uint8_t* _content; size_t _readLength; + public: - AsyncProgmemResponse(int code, const String& contentType, const uint8_t * content, size_t len, AwsTemplateProcessor callback=nullptr); + AsyncProgmemResponse(int code, const String& contentType, const uint8_t* content, size_t len, AwsTemplateProcessor callback = nullptr); bool _sourceValid() const { return true; } - virtual size_t _fillBuffer(uint8_t *buf, size_t maxLen) override; + virtual size_t _fillBuffer(uint8_t* buf, size_t maxLen) override; }; class cbuf; -class AsyncResponseStream: public AsyncAbstractResponse, public Print { +class AsyncResponseStream : public AsyncAbstractResponse, public Print { private: std::unique_ptr _content; + public: AsyncResponseStream(const String& contentType, size_t bufferSize); ~AsyncResponseStream(); bool _sourceValid() const { return (_state < RESPONSE_END); } - virtual size_t _fillBuffer(uint8_t *buf, size_t maxLen) override; - size_t write(const uint8_t *data, size_t len); + virtual size_t _fillBuffer(uint8_t* buf, size_t maxLen) override; + size_t write(const uint8_t* data, size_t len); size_t write(uint8_t data); using Print::write; }; diff --git a/src/WebResponses.cpp b/src/WebResponses.cpp index a783de0..1fd41fa 100644 --- a/src/WebResponses.cpp +++ b/src/WebResponses.cpp @@ -23,111 +23,140 @@ #include "cbuf.h" // Since ESP8266 does not link memchr by default, here's its implementation. -void* memchr(void* ptr, int ch, size_t count) -{ +void* memchr(void* ptr, int ch, size_t count) { unsigned char* p = static_cast(ptr); - while(count--) - if(*p++ == static_cast(ch)) + while (count--) + if (*p++ == static_cast(ch)) return --p; return nullptr; } - /* * Abstract Response * */ const char* AsyncWebServerResponse::_responseCodeToString(int code) { - return reinterpret_cast(responseCodeToString(code)); + return reinterpret_cast(responseCodeToString(code)); } -const __FlashStringHelper *AsyncWebServerResponse::responseCodeToString(int code) { +const __FlashStringHelper* AsyncWebServerResponse::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 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(""); } } AsyncWebServerResponse::AsyncWebServerResponse() - : _code(0) - , _contentType() - , _contentLength(0) - , _sendContentLength(true) - , _chunked(false) - , _headLength(0) - , _sentLength(0) - , _ackedLength(0) - , _writtenLength(0) - , _state(RESPONSE_SETUP) -{ - for(const auto &header: DefaultHeaders::Instance()) { + : _code(0), _contentType(), _contentLength(0), _sendContentLength(true), _chunked(false), _headLength(0), _sentLength(0), _ackedLength(0), _writtenLength(0), _state(RESPONSE_SETUP) { + for (const auto& header : DefaultHeaders::Instance()) { _headers.emplace_back(header); } } AsyncWebServerResponse::~AsyncWebServerResponse() = default; -void AsyncWebServerResponse::setCode(int code){ - if(_state == RESPONSE_SETUP) +void AsyncWebServerResponse::setCode(int code) { + if (_state == RESPONSE_SETUP) _code = code; } -void AsyncWebServerResponse::setContentLength(size_t len){ - if(_state == RESPONSE_SETUP) +void AsyncWebServerResponse::setContentLength(size_t len) { + if (_state == RESPONSE_SETUP) _contentLength = len; } -void AsyncWebServerResponse::setContentType(const String& type){ - if(_state == RESPONSE_SETUP) +void AsyncWebServerResponse::setContentType(const String& type) { + if (_state == RESPONSE_SETUP) _contentType = type; } -void AsyncWebServerResponse::addHeader(const String& name, const String& value){ +void AsyncWebServerResponse::addHeader(const String& name, const String& value) { _headers.emplace_back(name, value); } -String AsyncWebServerResponse::_assembleHead(uint8_t version){ - if(version){ +String AsyncWebServerResponse::_assembleHead(uint8_t version) { + if (version) { addHeader(F("Accept-Ranges"), F("none")); - if(_chunked) + if (_chunked) addHeader(F("Transfer-Encoding"), F("chunked")); } String out = String(); @@ -137,16 +166,16 @@ String AsyncWebServerResponse::_assembleHead(uint8_t version){ snprintf_P(buf, bufSize, PSTR("HTTP/1.%d %d %s\r\n"), version, _code, _responseCodeToString(_code)); out.concat(buf); - if(_sendContentLength) { + if (_sendContentLength) { snprintf_P(buf, bufSize, PSTR("Content-Length: %d\r\n"), _contentLength); out.concat(buf); } - if(_contentType.length()) { + if (_contentType.length()) { snprintf_P(buf, bufSize, PSTR("Content-Type: %s\r\n"), _contentType.c_str()); out.concat(buf); } - for(const auto& header: _headers){ + for (const auto& header : _headers) { snprintf_P(buf, bufSize, PSTR("%s: %s\r\n"), header.name().c_str(), header.value().c_str()); out.concat(buf); } @@ -161,44 +190,52 @@ bool AsyncWebServerResponse::_started() const { return _state > RESPONSE_SETUP; bool AsyncWebServerResponse::_finished() const { return _state > RESPONSE_WAIT_ACK; } bool AsyncWebServerResponse::_failed() const { return _state == RESPONSE_FAILED; } bool AsyncWebServerResponse::_sourceValid() const { return false; } -void AsyncWebServerResponse::_respond(AsyncWebServerRequest *request){ _state = RESPONSE_END; request->client()->close(); } -size_t AsyncWebServerResponse::_ack(AsyncWebServerRequest *request, size_t len, uint32_t time){ (void)request; (void)len; (void)time; return 0; } +void AsyncWebServerResponse::_respond(AsyncWebServerRequest* request) { + _state = RESPONSE_END; + request->client()->close(); +} +size_t AsyncWebServerResponse::_ack(AsyncWebServerRequest* request, size_t len, uint32_t time) { + (void)request; + (void)len; + (void)time; + return 0; +} /* * String/Code Response * */ -AsyncBasicResponse::AsyncBasicResponse(int code, const String& contentType, const String& content){ +AsyncBasicResponse::AsyncBasicResponse(int code, const String& contentType, const String& content) { _code = code; _content = content; _contentType = contentType; - if(_content.length()){ + if (_content.length()) { _contentLength = _content.length(); - if(!_contentType.length()) + if (!_contentType.length()) _contentType = F("text/plain"); } addHeader(F("Connection"), F("close")); } -void AsyncBasicResponse::_respond(AsyncWebServerRequest *request){ +void AsyncBasicResponse::_respond(AsyncWebServerRequest* request) { _state = RESPONSE_HEADERS; String out = _assembleHead(request->version()); size_t outLen = out.length(); size_t space = request->client()->space(); - if(!_contentLength && space >= outLen){ + if (!_contentLength && space >= outLen) { _writtenLength += request->client()->write(out.c_str(), outLen); _state = RESPONSE_WAIT_ACK; - } else if(_contentLength && space >= outLen + _contentLength){ + } else if (_contentLength && space >= outLen + _contentLength) { out += _content; outLen += _contentLength; _writtenLength += request->client()->write(out.c_str(), outLen); _state = RESPONSE_WAIT_ACK; - } else if(space && space < outLen){ + } else if (space && space < outLen) { String partial = out.substring(0, space); _content = out.substring(space) + _content; _contentLength += outLen - space; _writtenLength += request->client()->write(partial.c_str(), partial.length()); _state = RESPONSE_CONTENT; - } else if(space > outLen && space < (outLen + _contentLength)){ + } else if (space > outLen && space < (outLen + _contentLength)) { size_t shift = space - outLen; outLen += shift; _sentLength += shift; @@ -213,58 +250,56 @@ void AsyncBasicResponse::_respond(AsyncWebServerRequest *request){ } } -size_t AsyncBasicResponse::_ack(AsyncWebServerRequest *request, size_t len, uint32_t time){ +size_t AsyncBasicResponse::_ack(AsyncWebServerRequest* request, size_t len, uint32_t time) { (void)time; _ackedLength += len; - if(_state == RESPONSE_CONTENT){ + if (_state == RESPONSE_CONTENT) { size_t available = _contentLength - _sentLength; size_t space = request->client()->space(); - //we can fit in this packet - if(space > available){ + // we can fit in this packet + if (space > available) { _writtenLength += request->client()->write(_content.c_str(), available); _content = String(); _state = RESPONSE_WAIT_ACK; return available; } - //send some data, the rest on ack + // send some data, the rest on ack String out = _content.substring(0, space); _content = _content.substring(space); _sentLength += space; _writtenLength += request->client()->write(out.c_str(), space); return space; - } else if(_state == RESPONSE_WAIT_ACK){ - if(_ackedLength >= _writtenLength){ + } else if (_state == RESPONSE_WAIT_ACK) { + if (_ackedLength >= _writtenLength) { _state = RESPONSE_END; } } return 0; } - /* * Abstract Response * */ -AsyncAbstractResponse::AsyncAbstractResponse(AwsTemplateProcessor callback): _callback(callback) -{ +AsyncAbstractResponse::AsyncAbstractResponse(AwsTemplateProcessor callback) : _callback(callback) { // In case of template processing, we're unable to determine real response size - if(callback) { + if (callback) { _contentLength = 0; _sendContentLength = false; _chunked = true; } } -void AsyncAbstractResponse::_respond(AsyncWebServerRequest *request){ +void AsyncAbstractResponse::_respond(AsyncWebServerRequest* request) { addHeader(F("Connection"), F("close")); _head = _assembleHead(request->version()); _state = RESPONSE_HEADERS; _ack(request, 0, 0); } -size_t AsyncAbstractResponse::_ack(AsyncWebServerRequest *request, size_t len, uint32_t time){ +size_t AsyncAbstractResponse::_ack(AsyncWebServerRequest* request, size_t len, uint32_t time) { (void)time; - if(!_sourceValid()){ + if (!_sourceValid()) { _state = RESPONSE_FAILED; request->client()->close(); return 0; @@ -273,8 +308,8 @@ size_t AsyncAbstractResponse::_ack(AsyncWebServerRequest *request, size_t len, u size_t space = request->client()->space(); size_t headLen = _head.length(); - if(_state == RESPONSE_HEADERS){ - if(space >= headLen){ + if (_state == RESPONSE_HEADERS) { + if (space >= headLen) { _state = RESPONSE_CONTENT; space -= headLen; } else { @@ -285,103 +320,102 @@ size_t AsyncAbstractResponse::_ack(AsyncWebServerRequest *request, size_t len, u } } - if(_state == RESPONSE_CONTENT){ + if (_state == RESPONSE_CONTENT) { size_t outLen; - if(_chunked){ - if(space <= 8){ + if (_chunked) { + if (space <= 8) { return 0; } outLen = space; - } else if(!_sendContentLength){ + } else if (!_sendContentLength) { outLen = space; } else { - outLen = ((_contentLength - _sentLength) > space)?space:(_contentLength - _sentLength); + outLen = ((_contentLength - _sentLength) > space) ? space : (_contentLength - _sentLength); } - uint8_t *buf = (uint8_t *)malloc(outLen+headLen); + uint8_t* buf = (uint8_t*)malloc(outLen + headLen); if (!buf) { // os_printf("_ack malloc %d failed\n", outLen+headLen); return 0; } - if(headLen){ + if (headLen) { memcpy(buf, _head.c_str(), _head.length()); } size_t readLen = 0; - if(_chunked){ + if (_chunked) { // HTTP 1.1 allows leading zeros in chunk length. Or spaces may be added. // See RFC2616 sections 2, 3.6.1. - readLen = _fillBufferAndProcessTemplates(buf+headLen+6, outLen - 8); - if(readLen == RESPONSE_TRY_AGAIN){ - free(buf); - return 0; + readLen = _fillBufferAndProcessTemplates(buf + headLen + 6, outLen - 8); + if (readLen == RESPONSE_TRY_AGAIN) { + free(buf); + return 0; } - outLen = sprintf_P((char*)buf+headLen, PSTR("%x"), readLen) + headLen; - while(outLen < headLen + 4) buf[outLen++] = ' '; + outLen = sprintf_P((char*)buf + headLen, PSTR("%x"), readLen) + headLen; + while (outLen < headLen + 4) + buf[outLen++] = ' '; buf[outLen++] = '\r'; buf[outLen++] = '\n'; outLen += readLen; buf[outLen++] = '\r'; buf[outLen++] = '\n'; } else { - readLen = _fillBufferAndProcessTemplates(buf+headLen, outLen); - if(readLen == RESPONSE_TRY_AGAIN){ - free(buf); - return 0; + readLen = _fillBufferAndProcessTemplates(buf + headLen, outLen); + if (readLen == RESPONSE_TRY_AGAIN) { + free(buf); + return 0; } outLen = readLen + headLen; } - if(headLen){ - _head = String(); + if (headLen) { + _head = String(); } - if(outLen){ - _writtenLength += request->client()->write((const char*)buf, outLen); + if (outLen) { + _writtenLength += request->client()->write((const char*)buf, outLen); } - if(_chunked){ - _sentLength += readLen; + if (_chunked) { + _sentLength += readLen; } else { - _sentLength += outLen - headLen; + _sentLength += outLen - headLen; } free(buf); - if((_chunked && readLen == 0) || (!_sendContentLength && outLen == 0) || (!_chunked && _sentLength == _contentLength)){ + if ((_chunked && readLen == 0) || (!_sendContentLength && outLen == 0) || (!_chunked && _sentLength == _contentLength)) { _state = RESPONSE_WAIT_ACK; } return outLen; - } else if(_state == RESPONSE_WAIT_ACK){ - if(!_sendContentLength || _ackedLength >= _writtenLength){ + } else if (_state == RESPONSE_WAIT_ACK) { + if (!_sendContentLength || _ackedLength >= _writtenLength) { _state = RESPONSE_END; - if(!_chunked && !_sendContentLength) + if (!_chunked && !_sendContentLength) request->client()->close(true); } } return 0; } -size_t AsyncAbstractResponse::_readDataFromCacheOrContent(uint8_t* data, const size_t len) -{ - // If we have something in cache, copy it to buffer - const size_t readFromCache = std::min(len, _cache.size()); - if(readFromCache) { - memcpy(data, _cache.data(), readFromCache); - _cache.erase(_cache.begin(), _cache.begin() + readFromCache); - } - // If we need to read more... - const size_t needFromFile = len - readFromCache; - const size_t readFromContent = _fillBuffer(data + readFromCache, needFromFile); - return readFromCache + readFromContent; +size_t AsyncAbstractResponse::_readDataFromCacheOrContent(uint8_t* data, const size_t len) { + // If we have something in cache, copy it to buffer + const size_t readFromCache = std::min(len, _cache.size()); + if (readFromCache) { + memcpy(data, _cache.data(), readFromCache); + _cache.erase(_cache.begin(), _cache.begin() + readFromCache); + } + // If we need to read more... + const size_t needFromFile = len - readFromCache; + const size_t readFromContent = _fillBuffer(data + readFromCache, needFromFile); + return readFromCache + readFromContent; } -size_t AsyncAbstractResponse::_fillBufferAndProcessTemplates(uint8_t* data, size_t len) -{ - if(!_callback) +size_t AsyncAbstractResponse::_fillBufferAndProcessTemplates(uint8_t* data, size_t len) { + if (!_callback) return _fillBuffer(data, len); const size_t originalLen = len; @@ -389,16 +423,16 @@ size_t AsyncAbstractResponse::_fillBufferAndProcessTemplates(uint8_t* data, size // Now we've read 'len' bytes, either from cache or from file // Search for template placeholders uint8_t* pTemplateStart = data; - while((pTemplateStart < &data[len]) && (pTemplateStart = (uint8_t*)memchr(pTemplateStart, TEMPLATE_PLACEHOLDER, &data[len - 1] - pTemplateStart + 1))) { // data[0] ... data[len - 1] + while ((pTemplateStart < &data[len]) && (pTemplateStart = (uint8_t*)memchr(pTemplateStart, TEMPLATE_PLACEHOLDER, &data[len - 1] - pTemplateStart + 1))) { // data[0] ... data[len - 1] uint8_t* pTemplateEnd = (pTemplateStart < &data[len - 1]) ? (uint8_t*)memchr(pTemplateStart + 1, TEMPLATE_PLACEHOLDER, &data[len - 1] - pTemplateStart) : nullptr; // temporary buffer to hold parameter name uint8_t buf[TEMPLATE_PARAM_NAME_LENGTH + 1]; String paramName; // If closing placeholder is found: - if(pTemplateEnd) { + if (pTemplateEnd) { // prepare argument to callback const size_t paramNameLength = std::min((size_t)sizeof(buf) - 1, (size_t)(pTemplateEnd - pTemplateStart - 1)); - if(paramNameLength) { + if (paramNameLength) { memcpy(buf, pTemplateStart + 1, paramNameLength); buf[paramNameLength] = 0; paramName = String(reinterpret_cast(buf)); @@ -408,32 +442,29 @@ size_t AsyncAbstractResponse::_fillBufferAndProcessTemplates(uint8_t* data, size len += _readDataFromCacheOrContent(&data[len - 1], 1) - 1; ++pTemplateStart; } - } else if(&data[len - 1] - pTemplateStart + 1 < TEMPLATE_PARAM_NAME_LENGTH + 2) { // closing placeholder not found, check if it's in the remaining file data + } else if (&data[len - 1] - pTemplateStart + 1 < TEMPLATE_PARAM_NAME_LENGTH + 2) { // closing placeholder not found, check if it's in the remaining file data memcpy(buf, pTemplateStart + 1, &data[len - 1] - pTemplateStart); const size_t readFromCacheOrContent = _readDataFromCacheOrContent(buf + (&data[len - 1] - pTemplateStart), TEMPLATE_PARAM_NAME_LENGTH + 2 - (&data[len - 1] - pTemplateStart + 1)); - if(readFromCacheOrContent) { + if (readFromCacheOrContent) { pTemplateEnd = (uint8_t*)memchr(buf + (&data[len - 1] - pTemplateStart), TEMPLATE_PLACEHOLDER, readFromCacheOrContent); - if(pTemplateEnd) { + if (pTemplateEnd) { // prepare argument to callback *pTemplateEnd = 0; paramName = String(reinterpret_cast(buf)); // Copy remaining read-ahead data into cache _cache.insert(_cache.begin(), pTemplateEnd + 1, buf + (&data[len - 1] - pTemplateStart) + readFromCacheOrContent); pTemplateEnd = &data[len - 1]; - } - else // closing placeholder not found in file data, store found percent symbol as is and advance to the next position + } else // closing placeholder not found in file data, store found percent symbol as is and advance to the next position { // but first, store read file data in cache _cache.insert(_cache.begin(), buf + (&data[len - 1] - pTemplateStart), buf + (&data[len - 1] - pTemplateStart) + readFromCacheOrContent); ++pTemplateStart; } - } - else // closing placeholder not found in content data, store found percent symbol as is and advance to the next position + } else // closing placeholder not found in content data, store found percent symbol as is and advance to the next position ++pTemplateStart; - } - else // closing placeholder not found in content data, store found percent symbol as is and advance to the next position + } else // closing placeholder not found in content data, store found percent symbol as is and advance to the next position ++pTemplateStart; - if(paramName.length()) { + if (paramName.length()) { // call callback and replace with result. // Everything in range [pTemplateStart, pTemplateEnd] can be safely replaced with parameter value. // Data after pTemplateEnd may need to be moved. @@ -445,21 +476,21 @@ size_t AsyncAbstractResponse::_fillBufferAndProcessTemplates(uint8_t* data, size const size_t numBytesCopied = std::min(pvlen, static_cast(&data[originalLen - 1] - pTemplateStart + 1)); // make room for param value // 1. move extra data to cache if parameter value is longer than placeholder AND if there is no room to store - if((pTemplateEnd + 1 < pTemplateStart + numBytesCopied) && (originalLen - (pTemplateStart + numBytesCopied - pTemplateEnd - 1) < len)) { + if ((pTemplateEnd + 1 < pTemplateStart + numBytesCopied) && (originalLen - (pTemplateStart + numBytesCopied - pTemplateEnd - 1) < len)) { _cache.insert(_cache.begin(), &data[originalLen - (pTemplateStart + numBytesCopied - pTemplateEnd - 1)], &data[len]); - //2. parameter value is longer than placeholder text, push the data after placeholder which not saved into cache further to the end + // 2. parameter value is longer than placeholder text, push the data after placeholder which not saved into cache further to the end memmove(pTemplateStart + numBytesCopied, pTemplateEnd + 1, &data[originalLen] - pTemplateStart - numBytesCopied); len = originalLen; // fix issue with truncated data, not sure if it has any side effects - } else if(pTemplateEnd + 1 != pTemplateStart + numBytesCopied) - //2. Either parameter value is shorter than placeholder text OR there is enough free space in buffer to fit. - // Move the entire data after the placeholder + } else if (pTemplateEnd + 1 != pTemplateStart + numBytesCopied) + // 2. Either parameter value is shorter than placeholder text OR there is enough free space in buffer to fit. + // Move the entire data after the placeholder memmove(pTemplateStart + numBytesCopied, pTemplateEnd + 1, &data[len] - pTemplateEnd - 1); // 3. replace placeholder with actual value memcpy(pTemplateStart, pvstr, numBytesCopied); // If result is longer than buffer, copy the remainder into cache (this could happen only if placeholder text itself did not fit entirely in buffer) - if(numBytesCopied < pvlen) { + if (numBytesCopied < pvlen) { _cache.insert(_cache.begin(), pvstr + numBytesCopied, pvstr + pvlen); - } else if(pTemplateStart + numBytesCopied < pTemplateEnd + 1) { // result is copied fully; if result is shorter than placeholder text... + } else if (pTemplateStart + numBytesCopied < pTemplateEnd + 1) { // result is copied fully; if result is shorter than placeholder text... // there is some free room, fill it from cache const size_t roomFreed = pTemplateEnd + 1 - pTemplateStart - numBytesCopied; const size_t totalFreeRoom = originalLen - len + roomFreed; @@ -473,48 +504,66 @@ size_t AsyncAbstractResponse::_fillBufferAndProcessTemplates(uint8_t* data, size return len; } - /* * File Response * */ -AsyncFileResponse::~AsyncFileResponse(){ - if(_content) +AsyncFileResponse::~AsyncFileResponse() { + if (_content) _content.close(); } -void AsyncFileResponse::_setContentType(const String& path){ +void AsyncFileResponse::_setContentType(const String& path) { #if HAVE_EXTERN_GET_CONTENT_TYPE_FUNCTION - extern const __FlashStringHelper *getContentType(const String &path); + extern const __FlashStringHelper* getContentType(const String& path); _contentType = getContentType(path); #else - if (path.endsWith(F(".html"))) _contentType = F("text/html"); - else if (path.endsWith(F(".htm"))) _contentType = F("text/html"); - else if (path.endsWith(F(".css"))) _contentType = F("text/css"); - else if (path.endsWith(F(".json"))) _contentType = F("application/json"); - else if (path.endsWith(F(".js"))) _contentType = F("application/javascript"); - else if (path.endsWith(F(".png"))) _contentType = F("image/png"); - else if (path.endsWith(F(".gif"))) _contentType = F("image/gif"); - else if (path.endsWith(F(".jpg"))) _contentType = F("image/jpeg"); - else if (path.endsWith(F(".ico"))) _contentType = F("image/x-icon"); - else if (path.endsWith(F(".svg"))) _contentType = F("image/svg+xml"); - else if (path.endsWith(F(".eot"))) _contentType = F("font/eot"); - else if (path.endsWith(F(".woff"))) _contentType = F("font/woff"); - else if (path.endsWith(F(".woff2"))) _contentType = F("font/woff2"); - else if (path.endsWith(F(".ttf"))) _contentType = F("font/ttf"); - else if (path.endsWith(F(".xml"))) _contentType = F("text/xml"); - else if (path.endsWith(F(".pdf"))) _contentType = F("application/pdf"); - else if (path.endsWith(F(".zip"))) _contentType = F("application/zip"); - else if(path.endsWith(F(".gz"))) _contentType = F("application/x-gzip"); - else _contentType = F("text/plain"); + if (path.endsWith(F(".html"))) + _contentType = F("text/html"); + else if (path.endsWith(F(".htm"))) + _contentType = F("text/html"); + else if (path.endsWith(F(".css"))) + _contentType = F("text/css"); + else if (path.endsWith(F(".json"))) + _contentType = F("application/json"); + else if (path.endsWith(F(".js"))) + _contentType = F("application/javascript"); + else if (path.endsWith(F(".png"))) + _contentType = F("image/png"); + else if (path.endsWith(F(".gif"))) + _contentType = F("image/gif"); + else if (path.endsWith(F(".jpg"))) + _contentType = F("image/jpeg"); + else if (path.endsWith(F(".ico"))) + _contentType = F("image/x-icon"); + else if (path.endsWith(F(".svg"))) + _contentType = F("image/svg+xml"); + else if (path.endsWith(F(".eot"))) + _contentType = F("font/eot"); + else if (path.endsWith(F(".woff"))) + _contentType = F("font/woff"); + else if (path.endsWith(F(".woff2"))) + _contentType = F("font/woff2"); + else if (path.endsWith(F(".ttf"))) + _contentType = F("font/ttf"); + else if (path.endsWith(F(".xml"))) + _contentType = F("text/xml"); + else if (path.endsWith(F(".pdf"))) + _contentType = F("application/pdf"); + else if (path.endsWith(F(".zip"))) + _contentType = F("application/zip"); + else if (path.endsWith(F(".gz"))) + _contentType = F("application/x-gzip"); + else + _contentType = F("text/plain"); #endif } -AsyncFileResponse::AsyncFileResponse(FS &fs, const String& path, const String& contentType, bool download, AwsTemplateProcessor callback): AsyncAbstractResponse(callback){ +AsyncFileResponse::AsyncFileResponse(FS& fs, const String& path, const String& contentType, bool download, AwsTemplateProcessor callback) : AsyncAbstractResponse(callback) { _code = 200; _path = path; - if(!download && !fs.exists(_path) && fs.exists(_path + F(".gz"))){ + if (!download && !fs.exists(_path) && fs.exists(_path + F(".gz"))) { _path = _path + F(".gz"); addHeader(F("Content-Encoding"), F("gzip")); _callback = nullptr; // Unable to process zipped templates @@ -525,30 +574,30 @@ AsyncFileResponse::AsyncFileResponse(FS &fs, const String& path, const String& c _content = fs.open(_path, fs::FileOpenMode::read); _contentLength = _content.size(); - if(contentType.length() == 0) + if (contentType.length() == 0) _setContentType(path); else _contentType = contentType; int filenameStart = path.lastIndexOf('/') + 1; - char buf[26+path.length()-filenameStart]; + char buf[26 + path.length() - filenameStart]; char* filename = (char*)path.c_str() + filenameStart; - if(download) { + if (download) { // set filename and force download - snprintf_P(buf, sizeof (buf), PSTR("attachment; filename=\"%s\""), filename); + snprintf_P(buf, sizeof(buf), PSTR("attachment; filename=\"%s\""), filename); } else { // set filename and force rendering - snprintf_P(buf, sizeof (buf), PSTR("inline")); + snprintf_P(buf, sizeof(buf), PSTR("inline")); } addHeader(F("Content-Disposition"), buf); } -AsyncFileResponse::AsyncFileResponse(File content, const String& path, const String& contentType, bool download, AwsTemplateProcessor callback): AsyncAbstractResponse(callback){ +AsyncFileResponse::AsyncFileResponse(File content, const String& path, const String& contentType, bool download, AwsTemplateProcessor callback) : AsyncAbstractResponse(callback) { _code = 200; _path = path; - if(!download && String(content.name()).endsWith(F(".gz")) && !path.endsWith(F(".gz"))){ + if (!download && String(content.name()).endsWith(F(".gz")) && !path.endsWith(F(".gz"))) { addHeader(F("Content-Encoding"), F("gzip")); _callback = nullptr; // Unable to process gzipped templates _sendContentLength = true; @@ -558,24 +607,24 @@ AsyncFileResponse::AsyncFileResponse(File content, const String& path, const Str _content = content; _contentLength = _content.size(); - if(contentType.length() == 0) + if (contentType.length() == 0) _setContentType(path); else _contentType = contentType; int filenameStart = path.lastIndexOf('/') + 1; - char buf[26+path.length()-filenameStart]; + char buf[26 + path.length() - filenameStart]; char* filename = (char*)path.c_str() + filenameStart; - if(download) { - snprintf_P(buf, sizeof (buf), PSTR("attachment; filename=\"%s\""), filename); + if (download) { + snprintf_P(buf, sizeof(buf), PSTR("attachment; filename=\"%s\""), filename); } else { - snprintf_P(buf, sizeof (buf), PSTR("inline")); + snprintf_P(buf, sizeof(buf), PSTR("inline")); } addHeader(F("Content-Disposition"), buf); } -size_t AsyncFileResponse::_fillBuffer(uint8_t *data, size_t len){ +size_t AsyncFileResponse::_fillBuffer(uint8_t* data, size_t len) { return _content.read(data, len); } @@ -583,18 +632,18 @@ size_t AsyncFileResponse::_fillBuffer(uint8_t *data, size_t len){ * Stream Response * */ -AsyncStreamResponse::AsyncStreamResponse(Stream &stream, const String& contentType, size_t len, AwsTemplateProcessor callback): AsyncAbstractResponse(callback) { +AsyncStreamResponse::AsyncStreamResponse(Stream& stream, const String& contentType, size_t len, AwsTemplateProcessor callback) : AsyncAbstractResponse(callback) { _code = 200; _content = &stream; _contentLength = len; _contentType = contentType; } -size_t AsyncStreamResponse::_fillBuffer(uint8_t *data, size_t len){ +size_t AsyncStreamResponse::_fillBuffer(uint8_t* data, size_t len) { size_t available = _content->available(); - size_t outLen = (available > len)?len:available; + size_t outLen = (available > len) ? len : available; size_t i; - for(i=0;iread(); return outLen; } @@ -603,20 +652,20 @@ size_t AsyncStreamResponse::_fillBuffer(uint8_t *data, size_t len){ * Callback Response * */ -AsyncCallbackResponse::AsyncCallbackResponse(const String& contentType, size_t len, AwsResponseFiller callback, AwsTemplateProcessor templateCallback): AsyncAbstractResponse(templateCallback) { +AsyncCallbackResponse::AsyncCallbackResponse(const String& contentType, size_t len, AwsResponseFiller callback, AwsTemplateProcessor templateCallback) : AsyncAbstractResponse(templateCallback) { _code = 200; _content = callback; _contentLength = len; - if(!len) + if (!len) _sendContentLength = false; _contentType = contentType; _filledLength = 0; } -size_t AsyncCallbackResponse::_fillBuffer(uint8_t *data, size_t len){ +size_t AsyncCallbackResponse::_fillBuffer(uint8_t* data, size_t len) { size_t ret = _content(data, len, _filledLength); - if(ret != RESPONSE_TRY_AGAIN){ - _filledLength += ret; + if (ret != RESPONSE_TRY_AGAIN) { + _filledLength += ret; } return ret; } @@ -625,7 +674,7 @@ size_t AsyncCallbackResponse::_fillBuffer(uint8_t *data, size_t len){ * Chunked Response * */ -AsyncChunkedResponse::AsyncChunkedResponse(const String& contentType, AwsResponseFiller callback, AwsTemplateProcessor processorCallback): AsyncAbstractResponse(processorCallback) { +AsyncChunkedResponse::AsyncChunkedResponse(const String& contentType, AwsResponseFiller callback, AwsTemplateProcessor processorCallback) : AsyncAbstractResponse(processorCallback) { _code = 200; _content = callback; _contentLength = 0; @@ -635,10 +684,10 @@ AsyncChunkedResponse::AsyncChunkedResponse(const String& contentType, AwsRespons _filledLength = 0; } -size_t AsyncChunkedResponse::_fillBuffer(uint8_t *data, size_t len){ +size_t AsyncChunkedResponse::_fillBuffer(uint8_t* data, size_t len) { size_t ret = _content(data, len, _filledLength); - if(ret != RESPONSE_TRY_AGAIN){ - _filledLength += ret; + if (ret != RESPONSE_TRY_AGAIN) { + _filledLength += ret; } return ret; } @@ -647,7 +696,7 @@ size_t AsyncChunkedResponse::_fillBuffer(uint8_t *data, size_t len){ * Progmem Response * */ -AsyncProgmemResponse::AsyncProgmemResponse(int code, const String& contentType, const uint8_t * content, size_t len, AwsTemplateProcessor callback): AsyncAbstractResponse(callback) { +AsyncProgmemResponse::AsyncProgmemResponse(int code, const String& contentType, const uint8_t* content, size_t len, AwsTemplateProcessor callback) : AsyncAbstractResponse(callback) { _code = code; _content = content; _contentType = contentType; @@ -655,7 +704,7 @@ AsyncProgmemResponse::AsyncProgmemResponse(int code, const String& contentType, _readLength = 0; } -size_t AsyncProgmemResponse::_fillBuffer(uint8_t *data, size_t len){ +size_t AsyncProgmemResponse::_fillBuffer(uint8_t* data, size_t len) { size_t left = _contentLength - _readLength; if (left > len) { memcpy_P(data, _content + _readLength, len); @@ -667,30 +716,28 @@ size_t AsyncProgmemResponse::_fillBuffer(uint8_t *data, size_t len){ return left; } - /* * Response Stream (You can print/write/printf to it, up to the contentLen bytes) * */ -AsyncResponseStream::AsyncResponseStream(const String& contentType, size_t bufferSize) -{ +AsyncResponseStream::AsyncResponseStream(const String& contentType, size_t bufferSize) { _code = 200; _contentLength = 0; _contentType = contentType; - _content = std::unique_ptr(new cbuf(bufferSize)); //std::make_unique(bufferSize); + _content = std::unique_ptr(new cbuf(bufferSize)); // std::make_unique(bufferSize); } AsyncResponseStream::~AsyncResponseStream() = default; -size_t AsyncResponseStream::_fillBuffer(uint8_t *buf, size_t maxLen){ +size_t AsyncResponseStream::_fillBuffer(uint8_t* buf, size_t maxLen) { return _content->read((char*)buf, maxLen); } -size_t AsyncResponseStream::write(const uint8_t *data, size_t len){ - if(_started()) +size_t AsyncResponseStream::write(const uint8_t* data, size_t len) { + if (_started()) return 0; - if(len > _content->room()){ + if (len > _content->room()) { size_t needed = len - _content->room(); _content->resizeAdd(needed); } @@ -699,6 +746,6 @@ size_t AsyncResponseStream::write(const uint8_t *data, size_t len){ return written; } -size_t AsyncResponseStream::write(uint8_t data){ +size_t AsyncResponseStream::write(uint8_t data) { return write(&data, 1); } diff --git a/src/WebServer.cpp b/src/WebServer.cpp index ebd464a..9d78e02 100644 --- a/src/WebServer.cpp +++ b/src/WebServer.cpp @@ -21,63 +21,63 @@ #include "ESPAsyncWebServer.h" #include "WebHandlerImpl.h" -bool ON_STA_FILTER(AsyncWebServerRequest *request) { +bool ON_STA_FILTER(AsyncWebServerRequest* request) { return WiFi.localIP() == request->client()->localIP(); } -bool ON_AP_FILTER(AsyncWebServerRequest *request) { +bool ON_AP_FILTER(AsyncWebServerRequest* request) { return WiFi.localIP() != request->client()->localIP(); } #ifndef HAVE_FS_FILE_OPEN_MODE -const char *fs::FileOpenMode::read = "r"; -const char *fs::FileOpenMode::write = "w"; -const char *fs::FileOpenMode::append = "a"; +const char* fs::FileOpenMode::read = "r"; +const char* fs::FileOpenMode::write = "w"; +const char* fs::FileOpenMode::append = "a"; #endif AsyncWebServer::AsyncWebServer(uint16_t port) - : _server(port) -{ + : _server(port) { _catchAllHandler = new AsyncCallbackWebHandler(); - if(_catchAllHandler == NULL) + if (_catchAllHandler == NULL) return; - _server.onClient([](void *s, AsyncClient* c){ - if(c == NULL) + _server.onClient([](void* s, AsyncClient* c) { + if (c == NULL) return; c->setRxTimeout(3); - AsyncWebServerRequest *r = new AsyncWebServerRequest((AsyncWebServer*)s, c); - if(r == NULL){ + AsyncWebServerRequest* r = new AsyncWebServerRequest((AsyncWebServer*)s, c); + if (r == NULL) { c->close(true); c->free(); delete c; } - }, this); + }, + this); } -AsyncWebServer::~AsyncWebServer(){ +AsyncWebServer::~AsyncWebServer() { reset(); end(); - if(_catchAllHandler) delete _catchAllHandler; + if (_catchAllHandler) + delete _catchAllHandler; } -AsyncWebRewrite& AsyncWebServer::addRewrite(std::shared_ptr rewrite){ +AsyncWebRewrite& AsyncWebServer::addRewrite(std::shared_ptr rewrite) { _rewrites.emplace_back(rewrite); return *_rewrites.back().get(); } - -AsyncWebRewrite& AsyncWebServer::addRewrite(AsyncWebRewrite* rewrite){ +AsyncWebRewrite& AsyncWebServer::addRewrite(AsyncWebRewrite* rewrite) { _rewrites.emplace_back(rewrite); return *_rewrites.back().get(); } -bool AsyncWebServer::removeRewrite(AsyncWebRewrite *rewrite){ +bool AsyncWebServer::removeRewrite(AsyncWebRewrite* rewrite) { return removeRewrite(rewrite->from().c_str(), rewrite->toUrl().c_str()); } -bool AsyncWebServer::removeRewrite(const char* from, const char* to){ - for(auto r = _rewrites.begin(); r != _rewrites.end(); ++r ){ - if (r->get()->from() == from && r->get()->toUrl() == to){ +bool AsyncWebServer::removeRewrite(const char* from, const char* to) { + for (auto r = _rewrites.begin(); r != _rewrites.end(); ++r) { + if (r->get()->from() == from && r->get()->toUrl() == to) { _rewrites.erase(r); return true; } @@ -85,19 +85,19 @@ bool AsyncWebServer::removeRewrite(const char* from, const char* to){ return false; } -AsyncWebRewrite& AsyncWebServer::rewrite(const char* from, const char* to){ +AsyncWebRewrite& AsyncWebServer::rewrite(const char* from, const char* to) { _rewrites.emplace_back(std::make_shared(from, to)); return *_rewrites.back().get(); } -AsyncWebHandler& AsyncWebServer::addHandler(AsyncWebHandler* handler){ +AsyncWebHandler& AsyncWebServer::addHandler(AsyncWebHandler* handler) { _handlers.emplace_back(handler); return *(_handlers.back().get()); } -bool AsyncWebServer::removeHandler(AsyncWebHandler *handler){ - for (auto i = _handlers.begin(); i != _handlers.end(); ++i){ - if (i->get() == handler ){ +bool AsyncWebServer::removeHandler(AsyncWebHandler* handler) { + for (auto i = _handlers.begin(); i != _handlers.end(); ++i) { + if (i->get() == handler) { _handlers.erase(i); return true; } @@ -105,41 +105,41 @@ bool AsyncWebServer::removeHandler(AsyncWebHandler *handler){ return false; } -void AsyncWebServer::begin(){ +void AsyncWebServer::begin() { _server.setNoDelay(true); _server.begin(); } -void AsyncWebServer::end(){ +void AsyncWebServer::end() { _server.end(); } #if ASYNC_TCP_SSL_ENABLED -void AsyncWebServer::onSslFileRequest(AcSSlFileHandler cb, void* arg){ +void AsyncWebServer::onSslFileRequest(AcSSlFileHandler cb, void* arg) { _server.onSslFileRequest(cb, arg); } -void AsyncWebServer::beginSecure(const char *cert, const char *key, const char *password){ +void AsyncWebServer::beginSecure(const char* cert, const char* key, const char* password) { _server.beginSecure(cert, key, password); } #endif -void AsyncWebServer::_handleDisconnect(AsyncWebServerRequest *request){ +void AsyncWebServer::_handleDisconnect(AsyncWebServerRequest* request) { delete request; } -void AsyncWebServer::_rewriteRequest(AsyncWebServerRequest *request){ - for(const auto& r: _rewrites){ - if (r->match(request)){ +void AsyncWebServer::_rewriteRequest(AsyncWebServerRequest* request) { + for (const auto& r : _rewrites) { + if (r->match(request)) { request->_url = r->toUrl(); request->_addGetParams(r->params()); } } } -void AsyncWebServer::_attachHandler(AsyncWebServerRequest *request){ - for(auto& h: _handlers){ - if (h->filter(request) && h->canHandle(request)){ +void AsyncWebServer::_attachHandler(AsyncWebServerRequest* request) { + for (auto& h : _handlers) { + if (h->filter(request) && h->canHandle(request)) { request->setHandler(h.get()); return; } @@ -149,8 +149,7 @@ void AsyncWebServer::_attachHandler(AsyncWebServerRequest *request){ request->setHandler(_catchAllHandler); } - -AsyncCallbackWebHandler& AsyncWebServer::on(const char* uri, WebRequestMethodComposite method, ArRequestHandlerFunction onRequest, ArUploadHandlerFunction onUpload, ArBodyHandlerFunction onBody){ +AsyncCallbackWebHandler& AsyncWebServer::on(const char* uri, WebRequestMethodComposite method, ArRequestHandlerFunction onRequest, ArUploadHandlerFunction onUpload, ArBodyHandlerFunction onBody) { AsyncCallbackWebHandler* handler = new AsyncCallbackWebHandler(); handler->setUri(uri); handler->setMethod(method); @@ -161,7 +160,7 @@ AsyncCallbackWebHandler& AsyncWebServer::on(const char* uri, WebRequestMethodCom return *handler; } -AsyncCallbackWebHandler& AsyncWebServer::on(const char* uri, WebRequestMethodComposite method, ArRequestHandlerFunction onRequest, ArUploadHandlerFunction onUpload){ +AsyncCallbackWebHandler& AsyncWebServer::on(const char* uri, WebRequestMethodComposite method, ArRequestHandlerFunction onRequest, ArUploadHandlerFunction onUpload) { AsyncCallbackWebHandler* handler = new AsyncCallbackWebHandler(); handler->setUri(uri); handler->setMethod(method); @@ -171,7 +170,7 @@ AsyncCallbackWebHandler& AsyncWebServer::on(const char* uri, WebRequestMethodCom return *handler; } -AsyncCallbackWebHandler& AsyncWebServer::on(const char* uri, WebRequestMethodComposite method, ArRequestHandlerFunction onRequest){ +AsyncCallbackWebHandler& AsyncWebServer::on(const char* uri, WebRequestMethodComposite method, ArRequestHandlerFunction onRequest) { AsyncCallbackWebHandler* handler = new AsyncCallbackWebHandler(); handler->setUri(uri); handler->setMethod(method); @@ -180,7 +179,7 @@ AsyncCallbackWebHandler& AsyncWebServer::on(const char* uri, WebRequestMethodCom return *handler; } -AsyncCallbackWebHandler& AsyncWebServer::on(const char* uri, ArRequestHandlerFunction onRequest){ +AsyncCallbackWebHandler& AsyncWebServer::on(const char* uri, ArRequestHandlerFunction onRequest) { AsyncCallbackWebHandler* handler = new AsyncCallbackWebHandler(); handler->setUri(uri); handler->onRequest(onRequest); @@ -188,32 +187,31 @@ AsyncCallbackWebHandler& AsyncWebServer::on(const char* uri, ArRequestHandlerFun return *handler; } -AsyncStaticWebHandler& AsyncWebServer::serveStatic(const char* uri, fs::FS& fs, const char* path, const char* cache_control){ +AsyncStaticWebHandler& AsyncWebServer::serveStatic(const char* uri, fs::FS& fs, const char* path, const char* cache_control) { AsyncStaticWebHandler* handler = new AsyncStaticWebHandler(uri, fs, path, cache_control); addHandler(handler); return *handler; } -void AsyncWebServer::onNotFound(ArRequestHandlerFunction fn){ +void AsyncWebServer::onNotFound(ArRequestHandlerFunction fn) { _catchAllHandler->onRequest(fn); } -void AsyncWebServer::onFileUpload(ArUploadHandlerFunction fn){ +void AsyncWebServer::onFileUpload(ArUploadHandlerFunction fn) { _catchAllHandler->onUpload(fn); } -void AsyncWebServer::onRequestBody(ArBodyHandlerFunction fn){ +void AsyncWebServer::onRequestBody(ArBodyHandlerFunction fn) { _catchAllHandler->onBody(fn); } -void AsyncWebServer::reset(){ +void AsyncWebServer::reset() { _rewrites.clear(); _handlers.clear(); - if (_catchAllHandler != NULL){ + if (_catchAllHandler != NULL) { _catchAllHandler->onRequest(NULL); _catchAllHandler->onUpload(NULL); _catchAllHandler->onBody(NULL); } } -