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

ESP8266WebServer - Drop inactive connection when another is waiting to improve page load time #8216

Merged
merged 3 commits into from
Oct 27, 2021
Merged
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
2 changes: 2 additions & 0 deletions doc/esp8266wifi/server-class.rst
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ Other Function Calls
.. code:: cpp

bool hasClient ()
size_t hasClientData ()
bool hasMaxPendingClients ()
bool getNoDelay ()
virtual size_t write (const uint8_t *buf, size_t size)
uint8_t status ()
Expand Down
15 changes: 11 additions & 4 deletions libraries/ESP8266WebServer/src/ESP8266WebServer-impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -343,11 +343,18 @@ void ESP8266WebServerTemplate<ServerType>::handleClient() {
} // switch _parseRequest()
} else {
// !_currentClient.available(): waiting for more data
if (millis() - _statusChange <= HTTP_MAX_DATA_WAIT) {
keepCurrentClient = true;
unsigned long timeSinceChange = millis() - _statusChange;
// Use faster connection drop timeout if any other client has data
// or the buffer of pending clients is full
if ((_server.hasClientData() || _server.hasMaxPendingClients())
&& timeSinceChange > HTTP_MAX_DATA_AVAILABLE_WAIT)
DBGWS("webserver: closing since there's another connection to read from\n");
else {
if (timeSinceChange > HTTP_MAX_DATA_WAIT)
DBGWS("webserver: closing after read timeout\n");
else
keepCurrentClient = true;
}
else
DBGWS("webserver: closing after read timeout\n");
callYield = true;
}
break;
Expand Down
1 change: 1 addition & 0 deletions libraries/ESP8266WebServer/src/ESP8266WebServer.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ enum HTTPAuthMethod { BASIC_AUTH, DIGEST_AUTH };
#endif

#define HTTP_MAX_DATA_WAIT 5000 //ms to wait for the client to send the request
#define HTTP_MAX_DATA_AVAILABLE_WAIT 30 //ms to wait for the client to send the request when there is another client with data available
#define HTTP_MAX_POST_WAIT 5000 //ms to wait for POST data to arrive
#define HTTP_MAX_SEND_WAIT 5000 //ms to wait for data chunk to be ACKed
#define HTTP_MAX_CLOSE_WAIT 2000 //ms to wait for the client to close the connection
Expand Down
19 changes: 19 additions & 0 deletions libraries/ESP8266WiFi/src/WiFiServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,25 @@ bool WiFiServer::hasClient() {
return false;
}

size_t WiFiServer::hasClientData() {
ClientContext *next = _unclaimed;
while (next) {
size_t s = next->getSize();
// return the amount of data available from the first connection that has any
if (s) return s;
next = next->next();
}
return 0;
}

bool WiFiServer::hasMaxPendingClients() {
#if TCP_LISTEN_BACKLOG
return ((struct tcp_pcb_listen *)_listen_pcb)->accepts_pending >= MAX_PENDING_CLIENTS_PER_PORT;
#else
return false;
#endif
}

WiFiClient WiFiServer::available(byte* status) {
(void) status;
if (_unclaimed) {
Expand Down
7 changes: 7 additions & 0 deletions libraries/ESP8266WiFi/src/WiFiServer.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,13 @@ class WiFiServer : public Server {
virtual ~WiFiServer() {}
WiFiClient available(uint8_t* status = NULL);
bool hasClient();
// hasClientData():
// returns the amount of data available from the first client
// or 0 if there is none
size_t hasClientData();
// hasMaxPendingClients():
// returns true if the queue of pending clients is full
bool hasMaxPendingClients();
void begin();
void begin(uint16_t port);
void begin(uint16_t port, uint8_t backlog);
Expand Down
22 changes: 21 additions & 1 deletion tests/host/common/MockWiFiServerSocket.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ void WiFiServer::begin ()
exit(EXIT_FAILURE);
}

server.sin_family = AF_INET;
server.sin_family = AF_INET;
server.sin_port = htons(mockport);
server.sin_addr.s_addr = htonl(global_source_address);
if (bind(sock, (struct sockaddr*)&server, sizeof(server)) == -1)
Expand Down Expand Up @@ -150,3 +150,23 @@ void WiFiServer::stop ()
{
close();
}

size_t WiFiServer::hasClientData ()
{
// Trivial Mocking:
// There is no waiting list of clients in this trivial mocking code,
// so the code has to act as if the tcp backlog list is full,
// and nothing is known about potential further clients.
// It could be implemented by accepting new clients and store their data until the current one is closed.
return 0;
}

bool WiFiServer::hasMaxPendingClients ()
{
// Mocking code does not consider the waiting client list,
// so it will return ::hasClient() here meaning:
// - our waiting client list does not exist
// - we consider pending number is max if a new client is waiting
// or not max if there's no new client.
return hasClient();
}