8000 WebServer: Solve HTTP request delay by dropping idle connections (#1537) · StarMiner99/arduino-pico@9b3032c · GitHub 8000
[go: up one dir, main page]

Skip to content

Commit 9b3032c

Browse files
authored
WebServer: Solve HTTP request delay by dropping idle connections (earlephilhower#1537)
Serve next wificlient (http_request) if current client does not have data
1 parent 50646b9 commit 9b3032c

File tree

3 files changed

+80
-73
lines changed

3 files changed

+80
-73
lines changed

libraries/WebServer/src/HTTPServer.cpp

Lines changed: 0 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -237,73 +237,6 @@ void HTTPServer::serveStatic(const char* uri, FS& fs, const char* path, const ch
237237
_addRequestHandler(new StaticRequestHandler(fs, path, uri, cache_header));
238238
}
239239

240-
void HTTPServer::httpHandleClient() {
241-
bool keepCurrentClient = false;
242-
bool callYield = false;
243-
244-
if (_currentClient->connected()) {
245-
switch (_currentStatus) {
246-
case HC_NONE:
247-
// No-op to avoid C++ compiler warning
248-
break;
249-
case HC_WAIT_READ:
250-
// Wait for data from client to become available
251-
if (_currentClient->available()) {
252-
switch (_parseRequest(_currentClient)) {
253-
case CLIENT_REQUEST_CAN_CONTINUE:
254-
// Because HTTP_MAX_SEND_WAIT is expressed in milliseconds, it must be divided by 1000
255-
_currentClient->setTimeout(HTTP_MAX_SEND_WAIT / 1000);
256-
_contentLength = CONTENT_LENGTH_NOT_SET;
257-
_handleRequest();
258-
/* fallthrough */
259-
case CLIENT_REQUEST_IS_HANDLED:
260-
if (_currentClient->connected() || _currentClient->available()) {
261-
_currentStatus = HC_WAIT_CLOSE;
262-
_statusChange = millis();
263-
keepCurrentClient = true;
264-
} else {
265-
log_v("webserver: peer has closed after served\n");
266-
}
267-
break;
268-
case CLIENT_MUST_STOP:
269-
log_v("Close client\n< 10000 span class="pl-pds">");
270-
_currentClient->stop();
271-
break;
272-
case CLIENT_IS_GIVEN:
273-
// client must not be stopped but must not be handled here anymore
274-
// (example: tcp connection given to websocket)
275-
log_v("Give client\n");
276-
break;
277-
} // switch _parseRequest()
278-
} else { // !_currentClient->available()
279-
if (millis() - _statusChange <= HTTP_MAX_DATA_WAIT) {
280-
keepCurrentClient = true;
281-
}
282-
callYield = true;
283-
}
284-
break;
285-
case HC_WAIT_CLOSE:
286-
// Wait for client to close the connection
287-
if (millis() - _statusChange <= HTTP_MAX_CLOSE_WAIT) {
288-
keepCurrentClient = true;
289-
callYield = true;
290-
}
291-
}
292-
}
293-
294-
if (!keepCurrentClient) {
295-
if (_currentClient) {
296-
delete _currentClient;
297-
_currentClient = nullptr;
298-
}
299-
_currentStatus = HC_NONE;
300-
_currentUpload.reset();
301-
}
302-
303-
if (callYield) {
304-
yield();
305-
}
306-
}
307240

308241
void HTTPServer::httpClose() {
309242
_currentStatus = HC_NONE;

libraries/WebServer/src/HTTPServer.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ enum HTTPAuthMethod { BASIC_AUTH, DIGEST_AUTH };
4141
#endif
4242

4343
#define HTTP_MAX_DATA_WAIT 5000 //ms to wait for the client to send the request
44+
#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
4445
#define HTTP_MAX_POST_WAIT 5000 //ms to wait for POST data to arrive
4546
#define HTTP_MAX_SEND_WAIT 5000 //ms to wait for data chunk to be ACKed
4647
#define HTTP_MAX_CLOSE_WAIT 2000 //ms to wait for the client to close the connection
@@ -74,7 +75,6 @@ class HTTPServer {
7475
virtual ~HTTPServer();
7576

7677
virtual void httpClose();
77-
virtual void httpHandleClient();
7878

7979
bool authenticate(const char * username, const char * password);
8080
void requestAuthentication(HTTPAuthMethod mode = BASIC_AUTH, const char* realm = nullptr, const String& authFailMsg = String(""));

libraries/WebServer/src/WebServerTemplate.h

Lines changed: 79 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -90,19 +90,93 @@ void WebServerTemplate<ServerType, DefaultPort>::handleClient() {
9090
_currentClient = nullptr;
9191
}
9292

93-
ClientType client = _server.available();
94-
if (!client) {
93+
_currentClient = new ClientType(_server.available());
94+
if (!_currentClient) {
9595
if (_nullDelay) {
9696
delay(1);
9797
}
9898
return;
9999
}
100-
101-
_currentClient = new ClientType(client);
102100
_currentStatus = HC_WAIT_READ;
103101
_statusChange = millis();
104102
}
105-
httpHandleClient();
103+
bool keepCurrentClient = false;
104+
bool callYield = false;
105+
106+
if (_currentClient->connected()) {
107+
switch (_currentStatus) {
108+
case HC_NONE:
109+
// No-op to avoid C++ compiler warning
110+
F438 break;
111+
case HC_WAIT_READ:
112+
// Wait for data from client to become available
113+
if (_currentClient->available()) {
114+
switch (_parseRequest(_currentClient)) {
115+
case CLIENT_REQUEST_CAN_CONTINUE:
116+
// Because HTTP_MAX_SEND_WAIT is expressed in milliseconds, it must be divided by 1000
117+
_currentClient->setTimeout(HTTP_MAX_SEND_WAIT / 1000);
118+
_contentLength = CONTENT_LENGTH_NOT_SET;
119+
_handleRequest();
120+
/* fallthrough */
121+
case CLIENT_REQUEST_IS_HANDLED:
122+
if (_currentClient->connected() || _currentClient->available()) {
123+
_currentStatus = HC_WAIT_CLOSE;
124+
_statusChange = millis();
125+
keepCurrentClient = true;
126+
} else {
127+
//log_v("webserver: peer has closed after served\n");
128+
}
129+
break;
130+
case CLIENT_MUST_STOP:
131+
//log_v("Close client\n");
132+
_currentClient->stop();
133+
break;
134+
case CLIENT_IS_GIVEN:
135+
// client must not be stopped but must not be handled here anymore
136+
// (example: tcp connection given to websocket)
137+
//log_v("Give client\n");
138+
break;
139+
} // switch _parseRequest()
140+
} else {
141+
// !_currentClient.available(): waiting for more data
142+
unsigned long timeSinceChange = millis() - _statusChange;
143+
// Use faster connection drop timeout if any other client has data
144+
// or the buffer of pending clients is full
145+
if ((_server.hasClientData() || _server.hasMaxPendingClients())
146+
&& timeSinceChange > HTTP_MAX_DATA_AVAILABLE_WAIT) {
147+
//log_v("webserver: closing since there's another connection to read from\r\n");
148+
} else {
149+
if (timeSinceChange > HTTP_MAX_DATA_WAIT) {
150+
//log_v("webserver: closing after read timeout\r\n");
151+
} else {
152+
keepCurrentClient = true;
153+
}
154+
}
155+
callYield = true;
156+
}
157+
break;
158+
case HC_WAIT_CLOSE:
159+
// Wait for client to close the connection
160+
if (millis() - _statusChange <= HTTP_MAX_CLOSE_WAIT) {
161+
keepCurrentClient = true;
162+
callYield = true;
163+
}
164+
}
165+
}
166+
167+
if (!keepCurrentClient) {
168+
if (_currentClient) {
169+
delete _currentClient;
170+
_currentClient = nullptr;
171+
}
172+
_currentStatus = HC_NONE;
173+
_currentUpload.reset();
174+
}
175+
176+
if (callYield) {
177+
yield();
178+
}
179+
106180
}
107181

108182
template <typename ServerType, int DefaultPort>

0 commit comments

Comments
 (0)
0