-2

I'm running a server on a Raspberry Pi Pico W that serves a webpage and some data. I'd like the http response to be consumable by a variety of clients (wget, curl, python requests, browsers) but I'm having trouble getting my HTTP response understood. Browsers handle it ok (Chrome parses the response headers, Firefox does not), curl and python requests think there are no HTTP headers and close the connection immediately, and wget receives the data but thinks the headers are part of the response body.

This snippet writes the HTTP response

WiFiServer server(80); // server on port 80
void loop(){
  WiFiClient wificlient = server.available();   // Listen for incoming clients

  // If a new client connects,
  if (wificlient) {
    HttpClient client(wificlient, WiFi.localIP());
    net_time = millis();
    net_prev_time = net_time;

    while ((client.connected() || client.available()) && (!client.endOfBodyReached()) &&
           (net_time - net_prev_time <= net_timeout))
    {
      net_time = millis();
      if (client.available()) {
        char c = client.read(); // read a byte
        Serial.write(c);
        httpbody += c;

        if (!client.available()) { // client is done, respond
          if (httpbody.indexOf("GET /api/last") == 0){
            Serial.println("Serving api request...");
            client.println("HTTP/1.1 200 OK");
            client.println("Content-type: text/plain; charset=utf-8");
            client.println("Content-length: " + String(last_str.length()));
            client.println("Content-Disposition: inline");
            client.println("Connection: close");
            client.println("");
            client.println(last_str);
            client.println("");
            break;
         }
       }
    }
...
}

In the above client is an instance of HttpClient from the ArduinoHttpClient library (via the arduino-pico core)

And when requesting with wget it says "No headers, assuming HTTP/0.9".

$ wget -O - http://10.0.0.27/api/last
--2023-02-24 22:09:34--  http://10.0.0.27/api/last
Connecting to 10.0.0.27:80... connected.
HTTP request sent, awaiting response... 200 No headers, assuming HTTP/0.9
Length: unspecified
Saving to: ‘STDOUT’

-
HTTP/1.1 200 OK
Content-type:text/plain; charset=utf-8
Content-length:136
Content-Disposition: inline
Connection: close

3006, MHZTemp (C): 17, Temp (C): 22.40, Humidity (%): 30.00, Feels like (C): 21.48, CO2 (ppm): 653, Dust (pcs/283ml): 599.09, GPS Fix: 0
-

Using curl, it seems like a similar assumption is made, since I get "Received HTTP/0.9 when not allowed".

How should I format the HTTP response so that it is correctly parsed by these clients?

Update:

Substituting WifiClient instead of HttpClient solves the issue, and both wget and curl no longer complain of missing headers or HTTP/0.9. Looking at the traffic in wireshark, it appears that when WifiClient is responding it sends a TCP [PSH, ACK] packet with the HTTP status code whereas and then after wget or curl respond with a TCP [ACK] WifiClient responds with the rest of the data. HttpClient was not sending [PSH, ACK] (probably because it isn't meant to) and curl closes the connection in response to more data.

In the following is the wireshark traffic with different configurations. 10.0.0.27 is my Pico server and 10.0.0.193 is my desktop machine (the requestor).

Requesting with curl and responding with WifiClient (expected behaviour): enter image description here

Requesting with curl and responding with HttpClient (connection gets closed):

enter image description here

So I think the PSH packet is the answer. WifiClient knows to send it while HttpClient isn't meant for this use and doesn't send it.

zeitoon
  • 330
  • 1
  • 2
  • 10
  • 1
    I guess `println` ends the line using a `\n`. HTTP requires `\r\n` line termination. – tkausl Feb 25 '23 at 03:37
  • wireshark shows `\r\n` line termination in the packet between the headers. – zeitoon Feb 25 '23 at 03:40
  • Try with spaces after the colons. Not sure whether they are _required_ though. – tkausl Feb 25 '23 at 03:45
  • this is not how you use ArduinoHttpClient. see the examples. but how do you make a web server with a client? – Juraj Feb 25 '23 at 07:15
  • I've updated the question with more code. The client comes from server.available(), and I couldn't find an example in ArduinoHttpClient that included responding to a client, but the interface seems to be the same as WifiClient and other Client classes. Adding a space after the colon didn't change anything – zeitoon Feb 26 '23 at 04:44
  • 1
    the HTTPClient library can't be used this way. it is only intended to make a HTTP request and process a HTTP response. it is very different from WiFiClient in function. – Juraj Feb 26 '23 at 11:27
  • @zeitoon are you limited to server software which are you using now or are you allowed to use another software to get desired result? – Daweo Feb 26 '23 at 19:57
  • I'm using the Arduino-Pico core and `WiFi.h` which is generally compatible with the arduino wifi library – zeitoon Feb 26 '23 at 20:09
  • Please post the full packet dump from wireshark. Also the output when you run the same wget command with the --debug option. I'm guessing @tkausl is correct and your response is not well formatted. – darnir Mar 09 '23 at 09:07
  • I've updated the post with wireshark traffic @darnir – zeitoon Mar 09 '23 at 18:49
  • I think @Juraj was correct and I was misusing HttpClient, as removing it fixed the issue with wget and curl, as described above. – zeitoon Mar 09 '23 at 18:51

1 Answers1

-1

As mentioned in the update to the question, use WifiClient or a library that properly handles TCP traffic

zeitoon
  • 330
  • 1
  • 2
  • 10