From 3e21c74abcb3ee1742bdad8b8ad6163a98459766 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?T=C3=B3th=20G=C3=A1bor?= Date: Wed, 8 Dec 2021 20:03:43 +0100 Subject: [PATCH] Fix base64 encoding of websocket client key and progmem support for webserver --- src/AsyncWebRequest_STM32.cpp | 38 +++--- src/AsyncWebResponseImpl_STM32.h | 84 ++++++------ src/AsyncWebResponses_STM32.cpp | 72 ++++++---- src/AsyncWebServer_STM32.cpp | 49 ++++--- src/AsyncWebServer_STM32.h | 222 ++++++++++++++++--------------- src/AsyncWebSocket_STM32.cpp | 100 ++++++++++++-- src/AsyncWebSocket_STM32.h | 160 +++++++++++----------- 7 files changed, 421 insertions(+), 304 deletions(-) diff --git a/src/AsyncWebRequest_STM32.cpp b/src/AsyncWebRequest_STM32.cpp index f431e52..1b4ef7b 100644 --- a/src/AsyncWebRequest_STM32.cpp +++ b/src/AsyncWebRequest_STM32.cpp @@ -1,16 +1,16 @@ /**************************************************************************************************************************** AsyncWebRequest_STM32.cpp - Dead simple AsyncWebServer for STM32 LAN8720 or built-in LAN8742A Ethernet - + For STM32 with LAN8720 (STM32F4/F7) or built-in LAN8742A Ethernet (Nucleo-144, DISCOVERY, etc) - + AsyncWebServer_STM32 is a library for the STM32 with LAN8720 or built-in LAN8742A Ethernet WebServer - + Based on and modified from ESPAsyncWebServer (https://github.com/me-no-dev/ESPAsyncWebServer) Built by Khoi Hoang https://github.com/khoih-prog/AsyncWebServer_STM32 Licensed under MIT license - + Version: 1.3.0 - + Version Modified By Date Comments ------- ----------- ---------- ----------- 1.2.3 K Hoang 02/09/2020 Initial coding for STM32 for built-in Ethernet (Nucleo-144, DISCOVERY, etc). @@ -1007,6 +1007,14 @@ void AsyncWebServerRequest::send(AsyncWebServerResponse *response) } } +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(int code, const String& contentType, const String& content) { return new AsyncBasicResponse(code, contentType, content); @@ -1063,31 +1071,31 @@ void AsyncWebServerRequest::redirect(const String& url) } bool AsyncWebServerRequest::authenticate(const char * username, const char * password, const char * realm, bool passwordIsHash) -{ +{ LOGDEBUG1("AsyncWebServerRequest::authenticate: auth-len =", _authorization.length()); - + if (_authorization.length()) - { + { if (_isDigest) { LOGDEBUG("AsyncWebServerRequest::authenticate: _isDigest"); - + return checkDigestAuthentication(_authorization.c_str(), methodToString(), username, password, realm, passwordIsHash, NULL, NULL, NULL); } else if (!passwordIsHash) { LOGDEBUG("AsyncWebServerRequest::authenticate: !passwordIsHash"); - + return checkBasicAuthentication(_authorization.c_str(), username, password); } else { LOGDEBUG("AsyncWebServerRequest::authenticate: Using password _authorization.equals"); - + return _authorization.equals(password); } } - + LOGDEBUG("AsyncWebServerRequest::authenticate: failed, len = 0"); return false; @@ -1293,12 +1301,12 @@ bool AsyncWebServerRequest::isExpectedRequestedConnType(RequestedConnectionType 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/AsyncWebResponseImpl_STM32.h b/src/AsyncWebResponseImpl_STM32.h index fc17984..4b44b3c 100644 --- a/src/AsyncWebResponseImpl_STM32.h +++ b/src/AsyncWebResponseImpl_STM32.h @@ -1,16 +1,16 @@ /**************************************************************************************************************************** AsyncWebResponseImpl_STM32.h - Dead simple AsyncWebServer for STM32 LAN8720 or built-in LAN8742A Ethernet - + For STM32 with LAN8720 (STM32F4/F7) or built-in LAN8742A Ethernet (Nucleo-144, DISCOVERY, etc) - + AsyncWebServer_STM32 is a library for the STM32 with LAN8720 or built-in LAN8742A Ethernet WebServer - + Based on and modified from ESPAsyncWebServer (https://github.com/me-no-dev/ESPAsyncWebServer) Built by Khoi Hoang https://github.com/khoih-prog/AsyncWebServer_STM32 Licensed under MIT license - + Version: 1.3.0 - + Version Modified By Date Comments ------- ----------- ---------- ----------- 1.2.3 K Hoang 02/09/2020 Initial coding for STM32 for built-in Ethernet (Nucleo-144, DISCOVERY, etc). @@ -35,24 +35,25 @@ #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); - - bool _sourceValid() const + + bool _sourceValid() const { return true; } }; -class AsyncAbstractResponse: public AsyncWebServerResponse +class AsyncAbstractResponse: public AsyncWebServerResponse { private: String _head; @@ -63,21 +64,21 @@ class AsyncAbstractResponse: public AsyncWebServerResponse 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); - - bool _sourceValid() const + + bool _sourceValid() const { return false; } - - virtual size_t _fillBuffer(uint8_t *buf __attribute__((unused)), size_t maxLen __attribute__((unused))) + + virtual size_t _fillBuffer(uint8_t *buf __attribute__((unused)), size_t maxLen __attribute__((unused))) { return 0; } @@ -89,72 +90,81 @@ class AsyncAbstractResponse: public AsyncWebServerResponse #define TEMPLATE_PARAM_NAME_LENGTH 32 -class AsyncStreamResponse: public AsyncAbstractResponse +class AsyncStreamResponse: public AsyncAbstractResponse { private: Stream *_content; - + public: AsyncStreamResponse(Stream &stream, const String& contentType, size_t len, AwsTemplateProcessor callback = nullptr); - - bool _sourceValid() const + + bool _sourceValid() const { return !!(_content); } - + 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); - - bool _sourceValid() const + + bool _sourceValid() const { return !!(_content); } - + 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); - - bool _sourceValid() const + + bool _sourceValid() const { return !!(_content); } - + virtual size_t _fillBuffer(uint8_t *buf, size_t maxLen) override; }; class cbuf; +class AsyncProgmemResponse: public AsyncAbstractResponse { + private: + const uint8_t * _content; + size_t _readLength; + public: + 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; +}; -class AsyncResponseStream: public AsyncAbstractResponse, public Print +class AsyncResponseStream: public AsyncAbstractResponse, public Print { private: cbuf *_content; - + public: AsyncResponseStream(const String& contentType, size_t bufferSize); ~AsyncResponseStream(); - - bool _sourceValid() const + + 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); size_t write(uint8_t data); diff --git a/src/AsyncWebResponses_STM32.cpp b/src/AsyncWebResponses_STM32.cpp index 58389b9..8ab9d00 100644 --- a/src/AsyncWebResponses_STM32.cpp +++ b/src/AsyncWebResponses_STM32.cpp @@ -1,16 +1,16 @@ /**************************************************************************************************************************** AsyncWebResponses_STM32.cpp - Dead simple AsyncWebServer for STM32 LAN8720 or built-in LAN8742A Ethernet - + For STM32 with LAN8720 (STM32F4/F7) or built-in LAN8742A Ethernet (Nucleo-144, DISCOVERY, etc) - + AsyncWebServer_STM32 is a library for the STM32 with LAN8720 or built-in LAN8742A Ethernet WebServer - + Based on and modified from ESPAsyncWebServer (https://github.com/me-no-dev/ESPAsyncWebServer) Built by Khoi Hoang https://github.com/khoih-prog/AsyncWebServer_STM32 Licensed under MIT license - + Version: 1.3.0 - + Version Modified By Date Comments ------- ----------- ---------- ----------- 1.2.3 K Hoang 02/09/2020 Initial coding for STM32 for built-in Ethernet (Nucleo-144, DISCOVERY, etc). @@ -310,6 +310,7 @@ size_t AsyncBasicResponse::_ack(AsyncWebServerRequest *request, size_t len, uint if (_ackedLength >= _writtenLength) { _state = RESPONSE_END; + request->client()->close(true); /* Might it be required? */ } } @@ -673,23 +674,23 @@ AsyncCallbackResponse::AsyncCallbackResponse(const String& contentType, size_t l _code = 200; _content = callback; _contentLength = 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) + + if (ret != RESPONSE_TRY_AGAIN) { _filledLength += ret; } - + return ret; } @@ -697,7 +698,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; @@ -708,23 +709,46 @@ 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) + + if (ret != RESPONSE_TRY_AGAIN) { _filledLength += ret; } - + return ret; } +/* + * Progmem Response + * */ +AsyncProgmemResponse::AsyncProgmemResponse(int code, const String& contentType, const uint8_t * content, size_t len, AwsTemplateProcessor callback): AsyncAbstractResponse(callback) { + _code = code; + _content = content; + _contentType = contentType; + _contentLength = len; + _readLength = 0; +} + +size_t AsyncProgmemResponse::_fillBuffer(uint8_t *data, size_t len){ + size_t left = _contentLength - _readLength; + if (left > len) { + memcpy_P(data, _content + _readLength, len); + _readLength += len; + return len; + } + memcpy_P(data, _content + _readLength, left); + _readLength += left; + 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; @@ -732,34 +756,34 @@ AsyncResponseStream::AsyncResponseStream(const String& contentType, size_t buffe _content = new cbuf(bufferSize); } -AsyncResponseStream::~AsyncResponseStream() +AsyncResponseStream::~AsyncResponseStream() { delete _content; } -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) +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); } - + size_t written = _content->write((const char*)data, len); _contentLength += written; - + return written; } -size_t AsyncResponseStream::write(uint8_t data) +size_t AsyncResponseStream::write(uint8_t data) { return write(&data, 1); } diff --git a/src/AsyncWebServer_STM32.cpp b/src/AsyncWebServer_STM32.cpp index 101a9b1..b965b13 100644 --- a/src/AsyncWebServer_STM32.cpp +++ b/src/AsyncWebServer_STM32.cpp @@ -1,16 +1,16 @@ /**************************************************************************************************************************** AsyncWebServer_STM32.cpp - Dead simple AsyncWebServer for STM32 LAN8720 or built-in LAN8742A Ethernet - + For STM32 with LAN8720 (STM32F4/F7) or built-in LAN8742A Ethernet (Nucleo-144, DISCOVERY, etc) - + AsyncWebServer_STM32 is a library for the STM32 with LAN8720 or built-in LAN8742A Ethernet WebServer - + Based on and modified from ESPAsyncWebServer (https://github.com/me-no-dev/ESPAsyncWebServer) Built by Khoi Hoang https://github.com/khoih-prog/AsyncWebServer_STM32 Licensed under MIT license - + Version: 1.3.0 - + Version Modified By Date Comments ------- ----------- ---------- ----------- 1.2.3 K Hoang 02/09/2020 Initial coding for STM32 for built-in Ethernet (Nucleo-144, DISCOVERY, etc). @@ -127,9 +127,9 @@ void AsyncWebServer::_handleDisconnect(AsyncWebServerRequest *request) void AsyncWebServer::_rewriteRequest(AsyncWebServerRequest *request) { - for (const auto& r : _rewrites) + for (const auto& r : _rewrites) { - if (r->match(request)) + if (r->match(request)) { request->_url = r->toUrl(); request->_addGetParams(r->params()); @@ -137,11 +137,11 @@ void AsyncWebServer::_rewriteRequest(AsyncWebServerRequest *request) } } -void AsyncWebServer::_attachHandler(AsyncWebServerRequest *request) +void AsyncWebServer::_attachHandler(AsyncWebServerRequest *request) { - for (const auto& h : _handlers) + for (const auto& h : _handlers) { - if (h->filter(request) && h->canHandle(request)) + if (h->filter(request) && h->canHandle(request)) { request->setHandler(h); return; @@ -153,22 +153,22 @@ void AsyncWebServer::_attachHandler(AsyncWebServerRequest *request) } -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); handler->onRequest(onRequest); handler->onUpload(onUpload); handler->onBody(onBody); addHandler(handler); - + 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); @@ -176,51 +176,50 @@ AsyncCallbackWebHandler& AsyncWebServer::on(const char* uri, WebRequestMethodCom handler->onRequest(onRequest); handler->onUpload(onUpload); addHandler(handler); - + 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); handler->onRequest(onRequest); addHandler(handler); - + 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); addHandler(handler); - + return *handler; } -void AsyncWebServer::onNotFound(ArRequestHandlerFunction fn) +void AsyncWebServer::onNotFound(ArRequestHandlerFunction fn) { _catchAllHandler->onRequest(fn); } -void AsyncWebServer::onRequestBody(ArBodyHandlerFunction fn) +void AsyncWebServer::onRequestBody(ArBodyHandlerFunction fn) { _catchAllHandler->onBody(fn); } -void AsyncWebServer::reset() +void AsyncWebServer::reset() { _rewrites.free(); _handlers.free(); - if (_catchAllHandler != NULL) + if (_catchAllHandler != NULL) { _catchAllHandler->onRequest(NULL); _catchAllHandler->onUpload(NULL); _catchAllHandler->onBody(NULL); } } - diff --git a/src/AsyncWebServer_STM32.h b/src/AsyncWebServer_STM32.h index 371c0bb..e498592 100644 --- a/src/AsyncWebServer_STM32.h +++ b/src/AsyncWebServer_STM32.h @@ -1,16 +1,16 @@ /**************************************************************************************************************************** AsyncWebServer_STM32.h - Dead simple AsyncWebServer for STM32 LAN8720 or built-in LAN8742A Ethernet - + For STM32 with LAN8720 (STM32F4/F7) or built-in LAN8742A Ethernet (Nucleo-144, DISCOVERY, etc) - + AsyncWebServer_STM32 is a library for the STM32 with LAN8720 or built-in LAN8742A Ethernet WebServer - + Based on and modified from ESPAsyncWebServer (https://github.com/me-no-dev/ESPAsyncWebServer) Built by Khoi Hoang https://github.com/khoih-prog/AsyncWebServer_STM32 Licensed under MIT license - + Version: 1.3.0 - + Version Modified By Date Comments ------- ----------- ---------- ----------- 1.2.3 K Hoang 02/09/2020 Initial coding for STM32 for built-in Ethernet (Nucleo-144, DISCOVERY, etc). @@ -20,7 +20,7 @@ 1.2.6 K Hoang 22/03/2021 Fix dependency on STM32AsyncTCP Library 1.3.0 K Hoang 14/04/2021 Add support to LAN8720 using STM32F4 or STM32F7 *****************************************************************************************************************************/ - + #ifndef _AsyncWebServer_STM32_H_ #define _AsyncWebServer_STM32_H_ @@ -45,7 +45,7 @@ #define ASYNCWEBSERVER_REGEX_ATTRIBUTE __attribute__((warning("ASYNCWEBSERVER_REGEX not defined"))) #endif -#define DEBUGF(...) //Serial.printf(__VA_ARGS__) +#define DEBUGF(...) Serial.printf(__VA_ARGS__) static const String SharedEmptyString = String(); @@ -61,7 +61,7 @@ class AsyncCallbackWebHandler; class AsyncResponseStream; #ifndef WEBSERVER_H - typedef enum + typedef enum { HTTP_GET = 0b00000001, HTTP_POST = 0b00000010, @@ -84,7 +84,7 @@ typedef std::function ArDisconnectHandler; PARAMETER :: Chainable object to hold GET/POST and FILE parameters * */ -class AsyncWebParameter +class AsyncWebParameter { private: String _name; @@ -96,28 +96,28 @@ class AsyncWebParameter 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) {} - - const String& name() const + + const String& name() const { return _name; } - - const String& value() const + + const String& value() const { return _value; } - - size_t size() const + + size_t size() const { return _size; } - - bool isPost() const + + bool isPost() const { return _isForm; } - - bool isFile() const + + bool isFile() const { return _isFile; } @@ -127,7 +127,7 @@ class AsyncWebParameter HEADER :: Chainable object to hold the headers * */ -class AsyncWebHeader +class AsyncWebHeader { private: String _name; @@ -135,34 +135,34 @@ class AsyncWebHeader public: AsyncWebHeader(const String& name, const String& value): _name(name), _value(value) {} - - AsyncWebHeader(const String& data): _name(), _value() + + AsyncWebHeader(const String& data): _name(), _value() { - if (!data) + if (!data) return; - + int index = data.indexOf(':'); - - if (index < 0) + + if (index < 0) return; - + _name = data.substring(0, index); _value = data.substring(index + 2); } - + ~AsyncWebHeader() {} - - const String& name() const + + const String& name() const { return _name; } - - const String& value() const + + const String& value() const { return _value; } - - String toString() const + + String toString() const { return String(_name + ": " + _value + "\r\n"); } @@ -177,11 +177,11 @@ typedef enum { RCT_NOT_USED = -1, RCT_DEFAULT = 0, RCT_HTTP, RCT_WS, RCT_EVENT, typedef std::function AwsResponseFiller; typedef std::function AwsTemplateProcessor; -class AsyncWebServerRequest +class AsyncWebServerRequest { friend class AsyncWebServer; friend class AsyncCallbackWebHandler; - + private: AsyncClient* _client; AsyncWebServer* _server; @@ -193,19 +193,19 @@ class AsyncWebServerRequest String _temp; uint8_t _parseState; uint8_t _version; - + WebRequestMethodComposite _method; - + String _url; String _host; String _contentType; String _boundary; String _authorization; - + RequestedConnectionType _reqconntype; - + void _removeNotInterestingHeaders(); - + bool _isDigest; bool _isMultipart; bool _isPlainPost; @@ -256,54 +256,54 @@ class AsyncWebServerRequest AsyncWebServerRequest(AsyncWebServer*, AsyncClient*); ~AsyncWebServerRequest(); - AsyncClient* client() + AsyncClient* client() { return _client; } - - uint8_t version() const + + uint8_t version() const { return _version; } - - WebRequestMethodComposite method() const + + WebRequestMethodComposite method() const { return _method; } - - const String& url() const + + const String& url() const { return _url; } - - const String& host() const + + const String& host() const { return _host; } - - const String& contentType() const + + const String& contentType() const { return _contentType; } - - size_t contentLength() const + + size_t contentLength() const { return _contentLength; } - - bool multipart() const + + bool multipart() const { return _isMultipart; } - + const char * methodToString() const; const char * requestedConnTypeToString() const; - - RequestedConnectionType requestedConnType() const + + RequestedConnectionType requestedConnType() const { return _reqconntype; } - + bool isExpectedRequestedConnType(RequestedConnectionType erct1, RequestedConnectionType erct2 = RCT_NOT_USED, RequestedConnectionType erct3 = RCT_NOT_USED); void onDisconnect (ArDisconnectHandler fn); @@ -314,11 +314,11 @@ class AsyncWebServerRequest 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) + void setHandler(AsyncWebHandler *handler) { _handler = handler; } - + void addInterestingHeader(const String& name); void redirect(const String& url); @@ -331,15 +331,17 @@ class AsyncWebServerRequest void sendChunked(const String& contentType, AwsResponseFiller callback, AwsTemplateProcessor templateCallback = nullptr); AsyncWebServerResponse *beginResponse(int code, const String& contentType = String(), const String& content = String()); - 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 *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 *beginChunkedResponse(const String& contentType, AwsResponseFiller callback, AwsTemplateProcessor templateCallback = nullptr); AsyncResponseStream *beginResponseStream(const String& contentType, size_t bufferSize = 1460); size_t headers() const; // get header count bool hasHeader(const String& name) const; // check if header exists - + AsyncWebHeader* getHeader(const String& name) const; AsyncWebHeader* getHeader(size_t num) const; @@ -349,11 +351,11 @@ class AsyncWebServerRequest AsyncWebParameter* getParam(const String& name, bool post = false, bool file = false) const; AsyncWebParameter* getParam(size_t num) const; - size_t args() const + size_t args() const { return params(); // get arguments count } - + const String& arg(const String& name) const; // get request argument value by name 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 @@ -381,55 +383,55 @@ bool ON_AP_FILTER(AsyncWebServerRequest *request); REWRITE :: One instance can be handle any Request (done by the Server) * */ -class AsyncWebRewrite +class AsyncWebRewrite { protected: String _from; String _toUrl; String _params; ArRequestFilterFunction _filter; - + public: - AsyncWebRewrite(const char* from, const char* to): _from(from), _toUrl(to), _params(String()), _filter(NULL) + AsyncWebRewrite(const char* from, const char* to): _from(from), _toUrl(to), _params(String()), _filter(NULL) { int index = _toUrl.indexOf('?'); - - if (index > 0) + + if (index > 0) { _params = _toUrl.substring(index + 1); _toUrl = _toUrl.substring(0, index); } } - + virtual ~AsyncWebRewrite() {} - - AsyncWebRewrite& setFilter(ArRequestFilterFunction fn) + + AsyncWebRewrite& setFilter(ArRequestFilterFunction fn) { _filter = fn; return *this; } - - bool filter(AsyncWebServerRequest *request) const + + bool filter(AsyncWebServerRequest *request) const { return _filter == NULL || _filter(request); } - - const String& from(void) const + + const String& from(void) const { return _from; } - - const String& toUrl(void) const + + const String& toUrl(void) const { return _toUrl; } - - const String& params(void) const + + const String& params(void) const { return _params; } - - virtual bool match(AsyncWebServerRequest *request) + + virtual bool match(AsyncWebServerRequest *request) { return from() == request->url() && filter(request); } @@ -439,46 +441,46 @@ class AsyncWebRewrite HANDLER :: One instance can be attached to any Request (done by the Server) * */ -class AsyncWebHandler +class AsyncWebHandler { protected: ArRequestFilterFunction _filter; String _username; String _password; - + public: AsyncWebHandler(): _username(""), _password("") {} - - AsyncWebHandler& setFilter(ArRequestFilterFunction fn) + + AsyncWebHandler& setFilter(ArRequestFilterFunction fn) { _filter = fn; return *this; } - - AsyncWebHandler& setAuthentication(const char *username, const char *password) + + AsyncWebHandler& setAuthentication(const char *username, const char *password) { _username = String(username); _password = String(password); return *this; }; - - bool filter(AsyncWebServerRequest *request) + + bool filter(AsyncWebServerRequest *request) { return _filter == NULL || _filter(request); } - + virtual ~AsyncWebHandler() {} - - virtual bool canHandle(AsyncWebServerRequest *request __attribute__((unused))) + + 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() + + virtual bool isRequestHandlerTrivial() { return true; } @@ -488,12 +490,12 @@ class AsyncWebHandler RESPONSE :: One instance is created for each Request (attached by the Handler) * */ -typedef enum +typedef enum { RESPONSE_SETUP, RESPONSE_HEADERS, RESPONSE_CONTENT, RESPONSE_WAIT_ACK, RESPONSE_END, RESPONSE_FAILED } WebResponseState; -class AsyncWebServerResponse +class AsyncWebServerResponse { protected: int _code; @@ -533,7 +535,7 @@ typedef std::function ArRequestHandlerFunc typedef std::function ArUploadHandlerFunction; typedef std::function ArBodyHandlerFunction; -class AsyncWebServer +class AsyncWebServer { protected: AsyncServer _server; @@ -575,40 +577,40 @@ class AsyncWebServer void _rewriteRequest(AsyncWebServerRequest *request); }; -class DefaultHeaders +class DefaultHeaders { using headers_t = LinkedList; headers_t _headers; DefaultHeaders() - : _headers(headers_t([](AsyncWebHeader * h) + : _headers(headers_t([](AsyncWebHeader * h) { delete h; })) {} - + public: using ConstIterator = headers_t::ConstIterator; - void addHeader(const String& name, const String& value) + void addHeader(const String& name, const String& value) { _headers.add(new AsyncWebHeader(name, value)); } - ConstIterator begin() const + ConstIterator begin() const { return _headers.begin(); } - - ConstIterator end() const + + ConstIterator end() const { return _headers.end(); } DefaultHeaders(DefaultHeaders const &) = delete; DefaultHeaders &operator=(DefaultHeaders const &) = delete; - - static DefaultHeaders &Instance() + + static DefaultHeaders &Instance() { static DefaultHeaders instance; return instance; diff --git a/src/AsyncWebSocket_STM32.cpp b/src/AsyncWebSocket_STM32.cpp index 229bf9d..f6f0570 100644 --- a/src/AsyncWebSocket_STM32.cpp +++ b/src/AsyncWebSocket_STM32.cpp @@ -1,16 +1,16 @@ /**************************************************************************************************************************** AsyncWebSocket_STM32.cpp - Dead simple AsyncWebServer for STM32 LAN8720 or built-in LAN8742A Ethernet - + For STM32 with LAN8720 (STM32F4/F7) or built-in LAN8742A Ethernet (Nucleo-144, DISCOVERY, etc) - + AsyncWebServer_STM32 is a library for the STM32 with LAN8720 or built-in LAN8742A Ethernet WebServer - + Based on and modified from ESPAsyncWebServer (https://github.com/me-no-dev/ESPAsyncWebServer) Built by Khoi Hoang https://github.com/khoih-prog/AsyncWebServer_STM32 Licensed under MIT license - + Version: 1.3.0 - + Version Modified By Date Comments ------- ----------- ---------- ----------- 1.2.3 K Hoang 02/09/2020 Initial coding for STM32 for built-in Ethernet (Nucleo-144, DISCOVERY, etc). @@ -37,6 +37,67 @@ #define MAX_PRINTF_LEN 64 +char *ltrim(char *s) { + while(isspace(*s)) s++; + return s; +} + +char *rtrim(char *s) { + char* back = s + strlen(s); + while(isspace(*--back)); + *(back+1) = '\0'; + return s; +} + +char *trim(char *s) { + return rtrim(ltrim(s)); +} + +size_t b64_encoded_size(size_t inlen){ + size_t ret; + ret = inlen; + if (inlen % 3 != 0) + ret += 3 - (inlen % 3); + ret /= 3; + ret *= 4; + + return ret; +} + +char * b64_encode(const unsigned char *in, size_t len, char * out){ + //char *out; + const char b64chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + size_t elen; size_t i; size_t j; size_t v; + + if (in == NULL || len == 0) + return NULL; + + elen = b64_encoded_size(len); + //out = malloc(elen+1); + out[elen] = '\0'; + + for (i=0, j=0; i> 18) & 0x3F]; + out[j+1] = b64chars[(v >> 12) & 0x3F]; + if (i+1 < len) { + out[j+2] = b64chars[(v >> 6) & 0x3F]; + } else { + out[j+2] = '='; + } + if (i+2 < len) { + out[j+3] = b64chars[v & 0x3F]; + } else { + out[j+3] = '='; + } + } + + return out; +} + size_t webSocketSendFrameWindow(AsyncClient *client) { if (!client->canSend()) @@ -1488,7 +1549,19 @@ AsyncWebSocket::AsyncWebSocketClientLinkedList AsyncWebSocket::getClients() cons Response to Web Socket request - sends the authorization and detaches the TCP Client from the web server Authentication code from https://github.com/Links2004/arduinoWebSockets/blob/master/src/WebSockets.cpp#L480 */ - +/*static */ +/*void acceptKey(char * skey, char * ckey) { + char sha1HashBin[22] = { 0 }; + //String key = base64_encode(sha1HashBin, 20); + __disable_irq(); + char buf[256]; + sprintf(buf, "%s258EAFA5-E914-47DA-95CA-C5AB0DC85B11", skey); + SHA1(sha1HashBin, (const char *)buf, strlen(buf)); + b64_encode((const unsigned char *)sha1HashBin, 20, buf); + sprintf(ckey, "%s", trim(buf)); + __enable_irq(); +} +*/ AsyncWebSocketResponse::AsyncWebSocketResponse(const String & key, AsyncWebSocket * server) { _server = server; @@ -1512,24 +1585,23 @@ AsyncWebSocketResponse::AsyncWebSocketResponse(const String & key, AsyncWebSocke return; } + Serial.printf("key: %s", key.c_str()); // KH, for STM32 sha1_context _ctx; - + (String&) key += WS_STR_UUID; sha1_starts(&_ctx); sha1_update(&_ctx, (const unsigned char*) key.c_str(), key.length()); sha1_finish(&_ctx, hash); - ////// - - base64_encodestate _state; - base64_init_encodestate(&_state); - int len = base64_encode_block((const char *) hash, HASH_BUFFER_SIZE, buffer, &_state); - len = base64_encode_blockend((buffer + len), &_state); + ////// Mod by: TothTechnika! + char buf[256]; + b64_encode((const unsigned char *)hash, 20, buffer); + sprintf(buffer, "%s", trim(buffer)); addHeader(WS_STR_CONNECTION, WS_STR_UPGRADE); addHeader(WS_STR_UPGRADE, "websocket"); - addHeader(WS_STR_ACCEPT, buffer); + addHeader(WS_STR_ACCEPT, (String)buffer); free(buffer); free(hash); diff --git a/src/AsyncWebSocket_STM32.h b/src/AsyncWebSocket_STM32.h index 3ba8b72..2fa894e 100644 --- a/src/AsyncWebSocket_STM32.h +++ b/src/AsyncWebSocket_STM32.h @@ -1,16 +1,16 @@ /**************************************************************************************************************************** AsyncWebSocket_STM32.h - Dead simple AsyncWebServer for STM32 LAN8720 or built-in LAN8742A Ethernet - + For STM32 with LAN8720 (STM32F4/F7) or built-in LAN8742A Ethernet (Nucleo-144, DISCOVERY, etc) - + AsyncWebServer_STM32 is a library for the STM32 with LAN8720 or built-in LAN8742A Ethernet WebServer - + Based on and modified from ESPAsyncWebServer (https://github.com/me-no-dev/ESPAsyncWebServer) Built by Khoi Hoang https://github.com/khoih-prog/AsyncWebServer_STM32 Licensed under MIT license - + Version: 1.3.0 - + Version Modified By Date Comments ------- ----------- ---------- ----------- 1.2.3 K Hoang 02/09/2020 Initial coding for STM32 for built-in Ethernet (Nucleo-144, DISCOVERY, etc). @@ -22,7 +22,7 @@ *****************************************************************************************************************************/ #pragma once - + #ifndef ASYNCWEBSOCKET_STM32_H_ #define ASYNCWEBSOCKET_STM32_H_ @@ -43,6 +43,8 @@ class AsyncWebSocketResponse; class AsyncWebSocketClient; class AsyncWebSocketControl; + + typedef struct { /** Message type as defined by enum AwsFrameType. @@ -101,7 +103,7 @@ typedef enum WS_EVT_DATA } AwsEventType; -class AsyncWebSocketMessageBuffer +class AsyncWebSocketMessageBuffer { private: uint8_t * _data; @@ -116,51 +118,51 @@ class AsyncWebSocketMessageBuffer AsyncWebSocketMessageBuffer(const AsyncWebSocketMessageBuffer &); AsyncWebSocketMessageBuffer(AsyncWebSocketMessageBuffer &&); ~AsyncWebSocketMessageBuffer(); - - void operator ++(int i) + + void operator ++(int i) { (void)i; _count++; } - - void operator --(int i) + + void operator --(int i) { (void)i; - - if (_count > 0) + + if (_count > 0) { _count--; } ; } - + bool reserve(size_t size); - - void lock() + + void lock() { _lock = true; } - - void unlock() + + void unlock() { _lock = false; } - - uint8_t * get() + + uint8_t * get() { return _data; } - - size_t length() + + size_t length() { return _len; } - - uint32_t count() + + uint32_t count() { return _count; } - - bool canDelete() + + bool canDelete() { return (!_count && !_lock); } @@ -169,35 +171,35 @@ class AsyncWebSocketMessageBuffer }; -class AsyncWebSocketMessage +class AsyncWebSocketMessage { protected: uint8_t _opcode; bool _mask; AwsMessageStatus _status; - + public: AsyncWebSocketMessage(): _opcode(WS_TEXT), _mask(false), _status(WS_MSG_ERROR) {} virtual ~AsyncWebSocketMessage() {} virtual void ack(size_t len __attribute__((unused)), uint32_t time __attribute__((unused))) {} - - virtual size_t send(AsyncClient *client __attribute__((unused))) + + virtual size_t send(AsyncClient *client __attribute__((unused))) { return 0; } - - virtual bool finished() + + virtual bool finished() { return _status != WS_MSG_SENDING; } - - virtual bool betweenFrames() const + + virtual bool betweenFrames() const { return false; } }; -class AsyncWebSocketBasicMessage: public AsyncWebSocketMessage +class AsyncWebSocketBasicMessage: public AsyncWebSocketMessage { private: size_t _len; @@ -205,24 +207,24 @@ class AsyncWebSocketBasicMessage: public AsyncWebSocketMessage size_t _ack; size_t _acked; uint8_t * _data; - + public: AsyncWebSocketBasicMessage(const char * data, size_t len, uint8_t opcode = WS_TEXT, bool mask = false); AsyncWebSocketBasicMessage(uint8_t opcode = WS_TEXT, bool mask = false); virtual ~AsyncWebSocketBasicMessage() override; - - virtual bool betweenFrames() const override + + virtual bool betweenFrames() const override { return _acked == _ack; } - + virtual void ack(size_t len, uint32_t time) override; virtual size_t send(AsyncClient *client) override; - + virtual bool reserve(size_t size); }; -class AsyncWebSocketMultiMessage: public AsyncWebSocketMessage +class AsyncWebSocketMultiMessage: public AsyncWebSocketMessage { private: uint8_t * _data; @@ -231,21 +233,21 @@ class AsyncWebSocketMultiMessage: public AsyncWebSocketMessage size_t _ack; size_t _acked; AsyncWebSocketMessageBuffer * _WSbuffer; - + public: AsyncWebSocketMultiMessage(AsyncWebSocketMessageBuffer * buffer, uint8_t opcode = WS_TEXT, bool mask = false); virtual ~AsyncWebSocketMultiMessage() override; - - virtual bool betweenFrames() const override + + virtual bool betweenFrames() const override { return _acked == _ack; } - + virtual void ack(size_t len, uint32_t time) override ; virtual size_t send(AsyncClient *client) override ; }; -class AsyncWebSocketClient +class AsyncWebSocketClient { private: AsyncClient *_client; @@ -273,27 +275,27 @@ class AsyncWebSocketClient ~AsyncWebSocketClient(); //client id increments for the given server - uint32_t id() + uint32_t id() { return _clientId; } - - AwsClientStatus status() + + AwsClientStatus status() { return _status; } - - AsyncClient* client() + + AsyncClient* client() { return _client; } - - AsyncWebSocket *server() + + AsyncWebSocket *server() { return _server; } - - AwsFrameInfo const &pinfo() const + + AwsFrameInfo const &pinfo() const { return _pinfo; } @@ -306,22 +308,22 @@ class AsyncWebSocketClient void ping(uint8_t *data = NULL, size_t len = 0); //set auto-ping period in seconds. disabled if zero (default) - void keepAlivePeriod(uint16_t seconds) + void keepAlivePeriod(uint16_t seconds) { _keepAlivePeriod = seconds * 1000; } - - uint16_t keepAlivePeriod() + + uint16_t keepAlivePeriod() { return (uint16_t)(_keepAlivePeriod / 1000); } //data packets - void message(AsyncWebSocketMessage *message) + void message(AsyncWebSocketMessage *message) { _queueMessage(message); } - + bool queueIsFull(); size_t printf(const char *format, ...) __attribute__ ((format (printf, 2, 3))); @@ -340,7 +342,7 @@ class AsyncWebSocketClient void binary(const String &message); void binary(AsyncWebSocketMessageBuffer *buffer); - bool canSend() + bool canSend() { return _messageQueue.length() < WS_MAX_QUEUED_MESSAGES; } @@ -357,11 +359,11 @@ class AsyncWebSocketClient typedef std::function AwsEventHandler; //WebServer Handler implementation that plays the role of a socket server -class AsyncWebSocket: public AsyncWebHandler +class AsyncWebSocket: public AsyncWebHandler { public: typedef LinkedList AsyncWebSocketClientLinkedList; - + private: String _url; AsyncWebSocketClientLinkedList _clients; @@ -373,29 +375,29 @@ class AsyncWebSocket: public AsyncWebHandler public: AsyncWebSocket(const String& url); ~AsyncWebSocket(); - - const char * url() const + + const char * url() const { return _url.c_str(); } - - void enable(bool e) + + void enable(bool e) { _enabled = e; } - - bool enabled() const + + 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) + + bool hasClient(uint32_t id) { return client(id) != NULL; } @@ -440,17 +442,17 @@ class AsyncWebSocket: public AsyncWebHandler size_t printfAll(const char *format, ...) __attribute__ ((format (printf, 2, 3))); //event listener - void onEvent(AwsEventHandler handler) + void onEvent(AwsEventHandler handler) { _eventHandler = handler; } //system callbacks (do not call) - uint32_t _getNextId() + uint32_t _getNextId() { return _cNextId++; } - + void _addClient(AsyncWebSocketClient * client); void _handleDisconnect(AsyncWebSocketClient * client); void _handleEvent(AsyncWebSocketClient * client, AwsEventType type, void * arg, uint8_t *data, size_t len); @@ -468,18 +470,18 @@ class AsyncWebSocket: public AsyncWebHandler }; //WebServer response to authenticate the socket and detach the tcp client from the web server request -class AsyncWebSocketResponse: public AsyncWebServerResponse +class AsyncWebSocketResponse: public AsyncWebServerResponse { private: String _content; AsyncWebSocket *_server; - + public: AsyncWebSocketResponse(const String& key, AsyncWebSocket *server); void _respond(AsyncWebServerRequest *request); size_t _ack(AsyncWebServerRequest *request, size_t len, uint32_t time); - - bool _sourceValid() const + + bool _sourceValid() const { return true; }