Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Overload handling: low heap and high number of open connections #1116

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 3 additions & 1 deletion src/ESPAsyncWebServer.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ typedef enum {
#define RESPONSE_TRY_AGAIN 0xFFFFFFFF

typedef uint8_t WebRequestMethodComposite;
typedef std::function<void(void)> ArDisconnectHandler;
typedef std::function<void(AsyncWebServerRequest*)> ArDisconnectHandler;

/*
* PARAMETER :: Chainable object to hold GET/POST and FILE parameters
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -436,6 +437,7 @@ class AsyncWebServer {
void _handleDisconnect(AsyncWebServerRequest *request);
void _attachHandler(AsyncWebServerRequest *request);
void _rewriteRequest(AsyncWebServerRequest *request);
void _freeClient(AsyncClient* c);
};

class DefaultHeaders {
Expand Down
5 changes: 4 additions & 1 deletion src/WebRequest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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(){
Expand All @@ -96,6 +97,8 @@ AsyncWebServerRequest::~AsyncWebServerRequest(){
if(_tempFile){
_tempFile.close();
}

if(_server->numOfRequests>0) _server->numOfRequests--;
}

void AsyncWebServerRequest::_onData(void *buf, size_t len){
Expand Down Expand Up @@ -224,7 +227,7 @@ void AsyncWebServerRequest::onDisconnect (ArDisconnectHandler fn){
void AsyncWebServerRequest::_onDisconnect(){
//os_printf("d\n");
if(_onDisconnectfn) {
_onDisconnectfn();
_onDisconnectfn(this);
}
_server->_handleDisconnect(this);
}
Expand Down
44 changes: 39 additions & 5 deletions src/WebServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
Expand All @@ -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*>([](AsyncWebRewrite* r){ delete r; }))
Expand All @@ -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);
}

Expand Down Expand Up @@ -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();
Expand Down