Closed hreintke closed 1 year ago
@d-a-v was not involved here, sadly. I'm not sure he'd be able to help w/the PicoW side of things.
My guess would be that if you're using Chrome it's trying to send a bunch of connections in parallel, and since the processing is very much serial in nature on the Pico, things get stuck waiting. FWIW under Firefox I haven't noticed any issue like this on the AdvancedWebServer.
We are using the unpatched LWIP, straight from the Pico-SDK, but I think there are a couple things low-effort to try.
First, you can grab/dumb all received Ethernet level packets by hacking in to https://github.com/earlephilhower/arduino-pico/blob/cc800713bd7b30b19ca4b5f02e88f3e915802527/cores/rp2040/cyw43_wrappers.cpp#L48. You can get all Ethernet sent packets here: https://github.com/earlephilhower/arduino-pico/blob/cc800713bd7b30b19ca4b5f02e88f3e915802527/libraries/lwIP_CYW43/src/utility/CYW43shim.cpp#L108
It is also possible to enable very verbose LWIP debugging by editing https://github.com/earlephilhower/arduino-pico/blob/master/tools/libpico/lwipopts.h (and enabling Tools->Debug Port->Serial to get ::printf output to USB).
Another possibility could be a bug in the webserver code, which just happens to have been noted a couple days ago in the upstream sources... https://github.com/esp8266/Arduino/issues/8941
I have not looked at the code, yet, so can't really comment if it's a real issue or not, but if it is then it's one heck of a coincidence. :four_leaf_clover:
Checked into it.
You are using another webserver implementation (webserver vs esp8266webserver) so the issue cannot come from there. But it is definitely possible the the issue is caused by the webserver/webclient code.
Did a quick try to use the esp8266webserver for the pico but got into trouble because esp8266 has a custom implementation of String and you are using the Arduino api one. Not sure if is possible to solve that with namespaces.
Edit : Found a similar construct in your webserver implementation. Will look into that.
Edit 2 : In WebserverTemplate.h
change code to :
template <typename ServerType, int DefaultPort>
void WebServerTemplate<ServerType, DefaultPort>::handleClient() {
if (_currentStatus == HC_NONE) {
if (_currentClient) {
delete _currentClient;
_currentClient = nullptr;
}
// ClientType client = _server.available();
_currentClient = new ClientType(_server.available());
if (!_currentClient) {
if (_nullDelay) {
delay(1);
}
return;
}
// _currentClient = new ClientType(client);
_currentStatus = HC_WAIT_READ;
_statusChange = millis();
}
httpHandleClient();
}
That had no effect on the issue.
Edit 3 : I think it is related to the fact that the browser already opens a new TCP connection when the first one is finished, without immediately sending data over the connection. Just to be prepared for the next request.
Edit 3 : I think it is related to the fact that the browser already opens a new TCP connection when the first one is finished, without immediately sending data over the connection. Just to be prepared for the next request.
That's a tough nut to crack here. The TCP connections are processed by LWIP in order of reception and we need to finish the lifecycle for the current one before starting processing on the next one. You'd need to use the AsyncWebServer to handle something like that.
(The ESP8266 WebServer evolved to fit its niche so well that it's nigh on unusable elsewhere. In addition to the String
there are Stream
changes as well. Bringing those in requires bringing in lots of other 8266-specific oddities, as far as I could tell when I tried it before going to the ESP32 one. It's really well tuned for low memory usage, but not really portable anymore.)
it before going to the ESP32 one
Tried the same on esp32, that suffers the same issue.
Running it on esp8266, it runs OK As far my testing goes.
Do you want to close this as a "known limitation" ?
I think that's the best we can do for now. I wonder if me-no-dev's async web server can work here...
I have seen this https://github.com/khoih-prog/AsyncWebServer_RP2040W but did not do any tests with it.
I see my issue is linked and read your story. Maybe a longshot but sharing my experiences. When using chrome on my ESP devices chrome asks for the page and the favicon.ico. It the latter request was first (since the default webserver does requests one by one) delays of a few seconds occurred (you have to wait for a timeout on the icon). Usually the first time, than a lot of requests ok, and than chrome "rechecked" the icon. And that's why it's ok with curl or in my case openHAB calls, they don't care about the favicon.
I solved this issue by adding an empty icon in the arduino code.
(somewhere in the setup method)
server.on("/favicon.ico", handleIcon);
//send no favicon (else blocks webserver for 3-5 seconds)
void handleIcon() {
sendResponse(404,F("NA"));
}
Maybe it helps, you can give it a try.
@supersjellie No, it is not the favicon.ico request. I've seen that before and this different. See also the remark below.
@earlephilhower : Was wondering why esp8266 does not suffer from issue so took a dive into the code. It is in the 'httpHandleClient()' part where there is always a wait when no data is (yet) available.
httpServer.cpp line 282
} else { // !_currentClient->available()
if (millis() - _statusChange <= HTTP_MAX_DATA_WAIT) {
keepCurrentClient = true;
}
esp8266webserver-impl.h line 367
} else {
// !_currentClient.available(): waiting for more data
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;
}
callYield = true;
}
When I found the differences, I also found the issue/PR on which it was solved. https://github.com/esp8266/Arduino/pull/8216
It is not a one to one port to pico, as it depends on other changes in their code But I can give it a try if you want.
That would be great if you could, since you seem to also have a good test case w/your web browser setup. I'm kind of surprised the same change wasn't already done to the ESP32 webserver (where this one was taken from)...
From @d-a-v in the issue
edit: esp32/arduino uses lwIP's socket API while here the raw API is used. Changes will not be the same there.
Hi,
Running non FreeRTOS, basic webserver example I see some late responses (5 seconds delay, but not always) on HTTP requests. This only happens when I use a webbroswer, using curl all works as expected (keep tcp connection open ?)
Would like to do some IP traffic analyses for that, using the Netdump library I made for esp8266.
I am not sure, but think there needs to be a patch/addition in lwip netif (phy_capture) for that. Was not (yet?) be able to track that down in pico-w and/or esp8266.
Do you know where/how to add that ? If not, was @d-a-v involved in the wifi/lwip implementation of pico-w ? I can ask him for some help too.