diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index abdea4627..231dc5292 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -21,14 +21,14 @@ jobs: - name: Build Tests run: bash ./.github/scripts/on-push.sh ${{ matrix.board }} 0 1 - build-pio: - name: PlatformIO for ${{ matrix.board }} on ${{ matrix.os }} - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [ubuntu-latest, windows-latest, macOS-latest] - board: [esp32, esp8266] - steps: - - uses: actions/checkout@v1 - - name: Build Tests - run: bash ./.github/scripts/on-push.sh ${{ matrix.board }} 1 1 +# build-pio: +# name: PlatformIO for ${{ matrix.board }} on ${{ matrix.os }} +# runs-on: ${{ matrix.os }} +# strategy: +# matrix: +# os: [ubuntu-latest, windows-latest, macOS-latest] +# board: [esp32, esp8266] +# steps: +# - uses: actions/checkout@v1 +# - name: Build Tests +# run: bash ./.github/scripts/on-push.sh ${{ matrix.board }} 1 1 diff --git a/library.json b/library.json index acacb416e..64b1e7f4b 100644 --- a/library.json +++ b/library.json @@ -25,11 +25,15 @@ "platforms": ["espressif8266", "espressif32"], "dependencies": [ { + "owner": "me-no-dev", "name": "ESPAsyncTCP", + "version": "^1.2.2", "platforms": "espressif8266" }, { + "owner": "me-no-dev", "name": "AsyncTCP", + "version": "^1.1.1", "platforms": "espressif32" }, { diff --git a/src/AsyncJson.h b/src/AsyncJson.h index 27b4a26f6..8ed4373bd 100644 --- a/src/AsyncJson.h +++ b/src/AsyncJson.h @@ -41,7 +41,9 @@ #if ARDUINOJSON_VERSION_MAJOR == 5 #define ARDUINOJSON_5_COMPATIBILITY #else - #define DYNAMIC_JSON_DOCUMENT_SIZE 1024 + #ifndef DYNAMIC_JSON_DOCUMENT_SIZE + #define DYNAMIC_JSON_DOCUMENT_SIZE 1024 + #endif #endif constexpr const char* JSON_MIMETYPE = "application/json"; @@ -199,9 +201,15 @@ class AsyncCallbackJsonWebHandler: public AsyncWebHandler { if(!(_method & request->method())) return false; - - if(_uri.length() && (_uri != request->url() && !request->url().startsWith(_uri+"/"))) - return false; + + 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+"/"))) + return false; if ( !request->contentType().equalsIgnoreCase(JSON_MIMETYPE) ) return false; diff --git a/src/AsyncWebSocket.cpp b/src/AsyncWebSocket.cpp index 9ebab12cd..a801bb0d8 100644 --- a/src/AsyncWebSocket.cpp +++ b/src/AsyncWebSocket.cpp @@ -24,18 +24,7 @@ #include #ifndef ESP8266 -extern "C" { -typedef struct { - uint32_t state[5]; - uint32_t count[2]; - unsigned char buffer[64]; -} SHA1_CTX; - -void SHA1Transform(uint32_t state[5], const unsigned char buffer[64]); -void SHA1Init(SHA1_CTX* context); -void SHA1Update(SHA1_CTX* context, const unsigned char* data, uint32_t len); -void SHA1Final(unsigned char digest[20], SHA1_CTX* context); -} +#include "mbedtls/sha1.h" #else #include #endif @@ -911,7 +900,7 @@ void AsyncWebSocketClient::binary(AsyncWebSocketMessageBuffer * buffer) IPAddress AsyncWebSocketClient::remoteIP() { if(!_client) { - return IPAddress(0U); + return IPAddress((uint32_t)0); } return _client->remoteIP(); } @@ -1361,10 +1350,12 @@ AsyncWebSocketResponse::AsyncWebSocketResponse(const String& key, AsyncWebSocket sha1(key + WS_STR_UUID, hash); #else (String&)key += WS_STR_UUID; - SHA1_CTX ctx; - SHA1Init(&ctx); - SHA1Update(&ctx, (const unsigned char*)key.c_str(), key.length()); - SHA1Final(hash, &ctx); + mbedtls_sha1_context ctx; + mbedtls_sha1_init(&ctx); + mbedtls_sha1_starts_ret(&ctx); + mbedtls_sha1_update_ret(&ctx, (const unsigned char*)key.c_str(), key.length()); + mbedtls_sha1_finish_ret(&ctx, hash); + mbedtls_sha1_free(&ctx); #endif base64_encodestate _state; base64_init_encodestate(&_state); diff --git a/src/ESPAsyncWebServer.h b/src/ESPAsyncWebServer.h index 3aff61b59..f021e4f34 100644 --- a/src/ESPAsyncWebServer.h +++ b/src/ESPAsyncWebServer.h @@ -409,18 +409,22 @@ typedef std::function ArRequestHandlerFunc typedef std::function ArUploadHandlerFunction; typedef std::function ArBodyHandlerFunction; +typedef std::function ASDisconnectHandler; + class AsyncWebServer { protected: AsyncServer _server; LinkedList _rewrites; LinkedList _handlers; AsyncCallbackWebHandler* _catchAllHandler; + ASDisconnectHandler _onDisconnectfn; + ArRequestFilterFunction _filter; public: AsyncWebServer(uint16_t port); ~AsyncWebServer(); - void begin(); + int8_t begin(); void end(); #if ASYNC_TCP_SSL_ENABLED @@ -435,16 +439,21 @@ class AsyncWebServer { AsyncWebHandler& addHandler(AsyncWebHandler* handler); bool removeHandler(AsyncWebHandler* handler); - AsyncCallbackWebHandler& on(const char* uri, ArRequestHandlerFunction onRequest); - AsyncCallbackWebHandler& on(const char* uri, WebRequestMethodComposite method, ArRequestHandlerFunction onRequest); - AsyncCallbackWebHandler& on(const char* uri, WebRequestMethodComposite method, ArRequestHandlerFunction onRequest, ArUploadHandlerFunction onUpload); - AsyncCallbackWebHandler& on(const char* uri, WebRequestMethodComposite method, ArRequestHandlerFunction onRequest, ArUploadHandlerFunction onUpload, ArBodyHandlerFunction onBody); + // Filter returns true of request should be processed. + // In case of false is returned, filter must set own handler + AsyncWebServer& setFilter(ArRequestFilterFunction fn); + + AsyncCallbackWebHandler& on(const String &uri, ArRequestHandlerFunction onRequest); + AsyncCallbackWebHandler& on(const String &uri, WebRequestMethodComposite method, ArRequestHandlerFunction onRequest); + AsyncCallbackWebHandler& on(const String &uri, WebRequestMethodComposite method, ArRequestHandlerFunction onRequest, ArUploadHandlerFunction onUpload); + AsyncCallbackWebHandler& on(const String &uri, WebRequestMethodComposite method, ArRequestHandlerFunction onRequest, ArUploadHandlerFunction onUpload, ArBodyHandlerFunction onBody); 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 onDisconnect (ASDisconnectHandler fn); // handle disconnect globally void reset(); //remove all writers and handlers, with onNotFound/onFileUpload/onRequestBody diff --git a/src/SPIFFSEditor.cpp b/src/SPIFFSEditor.cpp index 343ed79e0..548776354 100644 --- a/src/SPIFFSEditor.cpp +++ b/src/SPIFFSEditor.cpp @@ -7,7 +7,7 @@ #include "edit.htm.gz.h" #endif -#ifdef ESP32 +#ifdef ESP32 #define fullName(x) name(x) #endif @@ -33,13 +33,13 @@ static bool matchWild(const char *pattern, const char *testee) { nxPat=pattern++; nxTst=testee; continue; } - if (nxPat){ + if (nxPat){ pattern = nxPat+1; testee=++nxTst; continue; } return false; } - while (*pattern=='*'){pattern++;} + while (*pattern=='*'){pattern++;} return (*pattern == 0); } @@ -200,7 +200,7 @@ void SPIFFSEditor::handleRequest(AsyncWebServerRequest *request){ #endif String fname = entry.fullName(); if (fname.charAt(0) != '/') fname = "/" + fname; - + if (isExcluded(_fs, fname.c_str())) { #ifdef ESP32 entry = dir.openNextFile(); @@ -236,14 +236,16 @@ void SPIFFSEditor::handleRequest(AsyncWebServerRequest *request){ if (request->header(F("If-Modified-Since")).equals(buildTime)) { request->send(304); } else { -#ifdef EDFS - AsyncWebServerResponse *response = request->beginResponse(_fs, F("/edit_gz"), F("text/html"), false); +#ifdef EDFS + AsyncWebServerResponse *response = request->beginResponse(_fs, F("/edit.htm.gz"), F("text/html"), false); #else AsyncWebServerResponse *response = request->beginResponse_P(200, F("text/html"), edit_htm_gz, edit_htm_gz_len); #endif - response->addHeader(F("Content-Encoding"), F("gzip")); - response->addHeader(F("Last-Modified"), buildTime); - request->send(response); + if (response) { + response->addHeader(F("Content-Encoding"), F("gzip")); + response->addHeader(F("Last-Modified"), buildTime); + request->send(response); + } } } } else if(request->method() == HTTP_DELETE){ @@ -252,45 +254,45 @@ void SPIFFSEditor::handleRequest(AsyncWebServerRequest *request){ #ifdef ESP32 _fs.rmdir(request->getParam(F("path"), true)->value()); // try rmdir for littlefs #endif - } - + } + request->send(200, "", String(F("DELETE: "))+request->getParam(F("path"), true)->value()); } else request->send(404); } else if(request->method() == HTTP_POST){ if(request->hasParam(F("data"), true, true) && _fs.exists(request->getParam(F("data"), true, true)->value())) request->send(200, "", String(F("UPLOADED: "))+request->getParam(F("data"), true, true)->value()); - + else if(request->hasParam(F("rawname"), true) && request->hasParam(F("raw0"), true)){ String rawnam = request->getParam(F("rawname"), true)->value(); - + if (_fs.exists(rawnam)) _fs.remove(rawnam); // delete it to allow a mode - + int k = 0; uint16_t i = 0; fs::File f = _fs.open(rawnam, "a"); - + while (request->hasParam(String(F("raw")) + String(k), true)) { //raw0 .. raw1 if(f){ - i += f.print(request->getParam(String(F("raw")) + String(k), true)->value()); + i += f.print(request->getParam(String(F("raw")) + String(k), true)->value()); } k++; } f.close(); request->send(200, "", String(F("IPADWRITE: ")) + rawnam + ":" + String(i)); - + } else { request->send(500); - } - + } + } else if(request->method() == HTTP_PUT){ if(request->hasParam(F("path"), true)){ String filename = request->getParam(F("path"), true)->value(); if(_fs.exists(filename)){ request->send(200); - } else { + } else { /*******************************************************/ -#ifdef ESP32 +#ifdef ESP32 if (strchr(filename.c_str(), '/')) { // For file creation, silently make subdirs as needed. If any fail, // it will be caught by the real file open later on @@ -306,9 +308,9 @@ void SPIFFSEditor::handleRequest(AsyncWebServerRequest *request){ } } free(pathStr); - } -#endif -/*******************************************************/ + } +#endif +/*******************************************************/ fs::File f = _fs.open(filename, "w"); if(f){ f.write((uint8_t)0x00); diff --git a/src/WebAuthentication.cpp b/src/WebAuthentication.cpp index 2d72de9d4..1a22afdfc 100644 --- a/src/WebAuthentication.cpp +++ b/src/WebAuthentication.cpp @@ -77,9 +77,9 @@ static bool getMD5(uint8_t * data, uint16_t len, char * output){//33 bytes or mo memset(_buf, 0x00, 16); #ifdef ESP32 mbedtls_md5_init(&_ctx); - mbedtls_md5_starts(&_ctx); - mbedtls_md5_update(&_ctx, data, len); - mbedtls_md5_finish(&_ctx, _buf); + mbedtls_md5_starts_ret(&_ctx); + mbedtls_md5_update_ret(&_ctx, data, len); + mbedtls_md5_finish_ret(&_ctx, _buf); #else MD5Init(&_ctx); MD5Update(&_ctx, data, len); diff --git a/src/WebServer.cpp b/src/WebServer.cpp index 62e85b23a..a17f7dc57 100644 --- a/src/WebServer.cpp +++ b/src/WebServer.cpp @@ -39,6 +39,8 @@ AsyncWebServer::AsyncWebServer(uint16_t port) : _server(port) , _rewrites(LinkedList([](AsyncWebRewrite* r){ delete r; })) , _handlers(LinkedList([](AsyncWebHandler* h){ delete h; })) + , _onDisconnectfn(nullptr) + ,_filter (nullptr) { _catchAllHandler = new AsyncCallbackWebHandler(); if(_catchAllHandler == NULL) @@ -84,9 +86,14 @@ bool AsyncWebServer::removeHandler(AsyncWebHandler *handler){ return _handlers.remove(handler); } -void AsyncWebServer::begin(){ +AsyncWebServer& AsyncWebServer::setFilter(ArRequestFilterFunction fn) { + _filter = fn; + return *this; +} + +int8_t AsyncWebServer::begin(){ _server.setNoDelay(true); - _server.begin(); + return _server.begin(); } void AsyncWebServer::end(){ @@ -103,7 +110,14 @@ void AsyncWebServer::beginSecure(const char *cert, const char *key, const char * } #endif +void AsyncWebServer::onDisconnect (ASDisconnectHandler fn){ + _onDisconnectfn=fn; +} + void AsyncWebServer::_handleDisconnect(AsyncWebServerRequest *request){ + if(_onDisconnectfn) { + _onDisconnectfn(request); + } delete request; } @@ -117,19 +131,20 @@ void AsyncWebServer::_rewriteRequest(AsyncWebServerRequest *request){ } void AsyncWebServer::_attachHandler(AsyncWebServerRequest *request){ - for(const auto& h: _handlers){ - if (h->filter(request) && h->canHandle(request)){ - request->setHandler(h); - return; + if(!_filter || _filter(request)) { + for(const auto& h: _handlers){ + if (h->filter(request) && h->canHandle(request)){ + request->setHandler(h); + return; + } } + request->addInterestingHeader(F("ANY")); + request->setHandler(_catchAllHandler); } - - request->addInterestingHeader(F("ANY")); - request->setHandler(_catchAllHandler); } -AsyncCallbackWebHandler& AsyncWebServer::on(const char* uri, WebRequestMethodComposite method, ArRequestHandlerFunction onRequest, ArUploadHandlerFunction onUpload, ArBodyHandlerFunction onBody){ +AsyncCallbackWebHandler& AsyncWebServer::on(const String &uri, WebRequestMethodComposite method, ArRequestHandlerFunction onRequest, ArUploadHandlerFunction onUpload, ArBodyHandlerFunction onBody){ AsyncCallbackWebHandler* handler = new AsyncCallbackWebHandler(); handler->setUri(uri); handler->setMethod(method); @@ -140,7 +155,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 String &uri, WebRequestMethodComposite method, ArRequestHandlerFunction onRequest, ArUploadHandlerFunction onUpload){ AsyncCallbackWebHandler* handler = new AsyncCallbackWebHandler(); handler->setUri(uri); handler->setMethod(method); @@ -150,7 +165,7 @@ AsyncCallbackWebHandler& AsyncWebServer::on(const char* uri, WebRequestMethodCom return *handler; } -AsyncCallbackWebHandler& AsyncWebServer::on(const char* uri, WebRequestMethodComposite method, ArRequestHandlerFunction onRequest){ +AsyncCallbackWebHandler& AsyncWebServer::on(const String &uri, WebRequestMethodComposite method, ArRequestHandlerFunction onRequest){ AsyncCallbackWebHandler* handler = new AsyncCallbackWebHandler(); handler->setUri(uri); handler->setMethod(method); @@ -159,7 +174,7 @@ AsyncCallbackWebHandler& AsyncWebServer::on(const char* uri, WebRequestMethodCom return *handler; } -AsyncCallbackWebHandler& AsyncWebServer::on(const char* uri, ArRequestHandlerFunction onRequest){ +AsyncCallbackWebHandler& AsyncWebServer::on(const String &uri, ArRequestHandlerFunction onRequest){ AsyncCallbackWebHandler* handler = new AsyncCallbackWebHandler(); handler->setUri(uri); handler->onRequest(onRequest);