From a1462f3bcdaab84ab71422f7b6d459dec1adb713 Mon Sep 17 00:00:00 2001 From: amkrk <52215223+amkrk@users.noreply.github.com> Date: Sun, 30 Jan 2022 12:43:58 +0100 Subject: [PATCH 1/3] Add files via upload --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index d6dd3206a..5d308b377 100644 --- a/README.md +++ b/README.md @@ -829,6 +829,12 @@ with "If-Modified-Since" header with the same value, instead of responding with // Update the date modified string every time files are updated server.serveStatic("/", SPIFFS, "/www/").setLastModified("Mon, 20 Jun 2016 14:00:00 GMT"); +or: + +AsyncStaticWebHandler& handler = server.serveStatic("/", LittleFS, "/", "public, max-age=604800"); +handler.setDefaultFile("index.html"); +handler.setLastModified((const char*)"Fri, 21 Jan 2022 14:00:00 GMT"); + //*** Chage last modified value at a later stage *** // During setup - read last modified value from config or EEPROM From 82e233fde6f876052367fa2ab49ce5d22cb6dbb4 Mon Sep 17 00:00:00 2001 From: amkrk <52215223+amkrk@users.noreply.github.com> Date: Sun, 30 Jan 2022 12:45:41 +0100 Subject: [PATCH 2/3] Add files via upload --- src/ESPAsyncWebServer.h | 2 ++ src/WebRequest.cpp | 3 +++ src/WebServer.cpp | 44 ++++++++++++++++++++++++++++++++++++----- 3 files changed, 44 insertions(+), 5 deletions(-) diff --git a/src/ESPAsyncWebServer.h b/src/ESPAsyncWebServer.h index 7cd21aa86..c58fb2335 100644 --- a/src/ESPAsyncWebServer.h +++ b/src/ESPAsyncWebServer.h @@ -408,6 +408,7 @@ class AsyncWebServer { void begin(); void end(); + int numOfRequests = 0; #if ASYNC_TCP_SSL_ENABLED void onSslFileRequest(AcSSlFileHandler cb, void* arg); void beginSecure(const char *cert, const char *private_key_file, const char *password); @@ -436,6 +437,7 @@ class AsyncWebServer { void _handleDisconnect(AsyncWebServerRequest *request); void _attachHandler(AsyncWebServerRequest *request); void _rewriteRequest(AsyncWebServerRequest *request); + void _freeClient(AsyncClient* c); }; class DefaultHeaders { diff --git a/src/WebRequest.cpp b/src/WebRequest.cpp index bbce5ca4c..b4e444baf 100644 --- a/src/WebRequest.cpp +++ b/src/WebRequest.cpp @@ -75,6 +75,7 @@ AsyncWebServerRequest::AsyncWebServerRequest(AsyncWebServer* s, AsyncClient* c) 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); + _server->numOfRequests++; } AsyncWebServerRequest::~AsyncWebServerRequest(){ @@ -96,6 +97,8 @@ AsyncWebServerRequest::~AsyncWebServerRequest(){ if(_tempFile){ _tempFile.close(); } + + if(_server->numOfRequests>0) _server->numOfRequests--; } void AsyncWebServerRequest::_onData(void *buf, size_t len){ diff --git a/src/WebServer.cpp b/src/WebServer.cpp index 95c2dd69f..f3d93ddfe 100644 --- a/src/WebServer.cpp +++ b/src/WebServer.cpp @@ -21,6 +21,10 @@ #include "ESPAsyncWebServer.h" #include "WebHandlerImpl.h" +#define SERVER_FREE_HEAP_LEVEL_CRITICAL (5*1024) +#define SERVER_FREE_HEAP_LEVEL_HIGH (7*1024) +#define MAX_NUM_OF_HTTP_REQUESTS 3 + bool ON_STA_FILTER(AsyncWebServerRequest *request) { return WiFi.localIP() == request->client()->localIP(); } @@ -29,7 +33,6 @@ bool ON_AP_FILTER(AsyncWebServerRequest *request) { return WiFi.localIP() != request->client()->localIP(); } - AsyncWebServer::AsyncWebServer(uint16_t port) : _server(port) , _rewrites(LinkedList([](AsyncWebRewrite* r){ delete r; })) @@ -41,13 +44,39 @@ AsyncWebServer::AsyncWebServer(uint16_t port) _server.onClient([](void *s, AsyncClient* c){ if(c == NULL) return; + + AsyncWebServer* svr = (AsyncWebServer*)s; + int freeHeap = ESP.getFreeHeap(); + + if ( freeHeap < SERVER_FREE_HEAP_LEVEL_CRITICAL ){ + svr->_freeClient(c); + return; + } + c->setRxTimeout(3); - AsyncWebServerRequest *r = new AsyncWebServerRequest((AsyncWebServer*)s, c); + + AsyncWebServerRequest *r = new AsyncWebServerRequest(svr, c); if(r == NULL){ - c->close(true); - c->free(); - delete c; + svr->_freeClient(c); + return; + } + + if ( freeHeap < SERVER_FREE_HEAP_LEVEL_HIGH ){ + r->send(500); + return; } + + if(svr->numOfRequests > MAX_NUM_OF_HTTP_REQUESTS){ + AsyncWebServerResponse *response = r->beginResponse(429); + + if(!response){ + svr->_freeClient(c); + return; + } + + response->addHeader("Retry-After", "1"); + r->send(response); + } }, this); } @@ -123,6 +152,11 @@ void AsyncWebServer::_attachHandler(AsyncWebServerRequest *request){ request->setHandler(_catchAllHandler); } +void AsyncWebServer::_freeClient(AsyncClient* c){ + c->close(true); + c->free(); + delete c; +} AsyncCallbackWebHandler& AsyncWebServer::on(const char* uri, WebRequestMethodComposite method, ArRequestHandlerFunction onRequest, ArUploadHandlerFunction onUpload, ArBodyHandlerFunction onBody){ AsyncCallbackWebHandler* handler = new AsyncCallbackWebHandler(); From 39e9b67651255c5365e03ba1eea0579f018dd013 Mon Sep 17 00:00:00 2001 From: amkrk <52215223+amkrk@users.noreply.github.com> Date: Wed, 5 Oct 2022 20:29:07 +0200 Subject: [PATCH 3/3] User can get a notification which AsyncWebServerRequest gets released When a data to be sent needs to be pulled from external MCU, a pointer into related AsyncWebServerRequest can be sent ESP->MCU, and then ESP<-MCU (response with the data). When the data arrives at ESP user application code running on it can cast a pointer into AsyncWebServerRequest and use it for building AsyncWebServerResponse. But the TCP connection and associated AsyncWebServerRequest can be released in a meantime (before ESP will get the data data from the MCU)... In order to secure the case the pointer needs to be validated before casting it to AsyncWebServerRequest. Application code shall then maintain a list of active AsyncWebServerRequest for this. The change to ESPAsyncWebServer helps to do it. When the connection is released it passes the pointer into user's callback as a parameter, so user can remove the invalid pointe from the list. Following can be example user's application code which makes it done: --------------------------- std::deque activeHttpRequests; bool isRequestValid(AsyncWebServerRequest *request) { for(int i=0; i::iterator it; it = activeHttpRequests.begin(); while (it != activeHttpRequests.end()) { if (*it == request) break; it++; } activeHttpRequests.erase(it); } void ApiOnBody(AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total) //this is called when POST request comes to ESP over WiFi { ... httpClientRegister(request); request->onDisconnect(httpClientDisconnectionHandler); ... } void sendApiResponseToHttpClient(const char* data) // the is called when ESP recives data from MCU { int32_t dataSeparatorOffset; AsyncWebServerRequest *request; ... get 'request' ptr value from msg incomming from MCU ... if(!isRequestValid(request)) return; // too late, disconnected already AsyncWebServerResponse *response = request->beginResponse(200, "text/xml", data); if(NULL!=response) request->send(response); } --- src/ESPAsyncWebServer.h | 2 +- src/WebRequest.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ESPAsyncWebServer.h b/src/ESPAsyncWebServer.h index c58fb2335..ab2d80ea2 100644 --- a/src/ESPAsyncWebServer.h +++ b/src/ESPAsyncWebServer.h @@ -74,7 +74,7 @@ typedef enum { #define RESPONSE_TRY_AGAIN 0xFFFFFFFF typedef uint8_t WebRequestMethodComposite; -typedef std::function ArDisconnectHandler; +typedef std::function ArDisconnectHandler; /* * PARAMETER :: Chainable object to hold GET/POST and FILE parameters diff --git a/src/WebRequest.cpp b/src/WebRequest.cpp index b4e444baf..f3f487186 100644 --- a/src/WebRequest.cpp +++ b/src/WebRequest.cpp @@ -227,7 +227,7 @@ void AsyncWebServerRequest::onDisconnect (ArDisconnectHandler fn){ void AsyncWebServerRequest::_onDisconnect(){ //os_printf("d\n"); if(_onDisconnectfn) { - _onDisconnectfn(); + _onDisconnectfn(this); } _server->_handleDisconnect(this); }