Issue with IPAddress not working in HttpClient

I have an ENC28J60 board connected to a UNO and can connect to my webserver happily when I hard-code the IP address into the HttpClient call. When I change to using an IPAddress structure instead the GET request returns a 400 error.

Here's the code:

#include <UIPEthernet.h>
#include <ArduinoHttpClient.h>

EthernetClient client;
IPAddress ipServer;
uint8_t macAddress[6] = { 0xBE, 0xEF, 0xFA, 0xCE, 0xCA, 0xFE };

void setup() {
  Serial.begin(9600);
  Serial.println("Start");
  Ethernet.begin(macAddress);
  Serial.print("localIP: ");
  Serial.println(Ethernet.localIP());
  ipServer = IPAddress(192, 168, 20, 107); // this is my local web server
  Serial.print("ipServer: ");
  Serial.println(ipServer);
}

void loop() {
  Serial.println("Connecting to ipServer");
  HttpClient httpClient = HttpClient(client, ipServer, 80);  // IP as an IPAddress
  httpClient.get("/request.php?echorequest=1");
  Serial.print(httpClient.responseStatusCode());    // 400
  Serial.print(": ");
  Serial.println(httpClient.responseBody());   // 400 error page

  delay(5000);

  Serial.println("Connecting to 192.168.20.107");
  httpClient = HttpClient(client, "192.168.20.107", 80);  // IP as a string
  httpClient.get("/request.php?echorequest=1");
  Serial.print(httpClient.responseStatusCode());   // 200
  Serial.print(": ");
  Serial.println(httpClient.responseBody());   // server just returns "1"

  while (true) {} // stop here, comment this out to have it loop
  delay(5000);
}

Here's the serial comms:

17:56:20.876 -> Start
17:56:25.747 -> localIP: 192.168.20.115
17:56:25.747 -> ipServer: 192.168.20.107
17:56:25.799 -> Connecting to ipServer
17:56:27.455 -> 400: <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
17:56:27.586 -> <html><head>
17:56:27.618 -> <title>400 Bad Request</title>
17:56:27.618 -> </head><body>
17:56:27.650 -> <h1>Bad Request</h1>
17:56:27.682 -> <p>Your browser sent a request that this server could not understand.<br />
17:56:27.748 -> </p>
17:56:27.748 -> </body></html>
17:56:27.781 -> 
17:56:32.716 -> Connecting to 192.168.20.107
17:56:33.538 -> 200: 1

Digging into the HttpClient I can see that it takes const IPAddress& aServerAddress as a 2nd parameter and CMD+clicking IPAddress takes me to the same definition as the one in my source code so I believe it's the same structure type?

I tried casting ipAddress to a String and char*, the other 2 types that HttpClient supports but it didn't help - responseStatusCode -2. I might be casting incorrectly though...

Does anyone have any advice on how to debug this further or if there's a trick to using IPAddress here like this.

thanks,
Kris

First, this is the ArduinoHttpClient library, not one of the others. All of their examples, even ones using an IP address, use it as a string, not an IPAddress object. Here's SimpleGet

char serverAddress[] = "192.168.0.3";  // server address
int port = 8080;

WiFiClient wifi;
HttpClient client = HttpClient(wifi, serverAddress, port);

Of the three constructors

    HttpClient(Client& aClient, const char* aServerName, uint16_t aServerPort = kHttpPort);
    HttpClient(Client& aClient, const String& aServerName, uint16_t aServerPort = kHttpPort);
    HttpClient(Client& aClient, const IPAddress& aServerAddress, uint16_t aServerPort = kHttpPort);
  • two take aServerName
    • the String one just calls aServerName.c_str(), which calls the const char * one
      HttpClient::HttpClient(Client& aClient, const String& aServerName, uint16_t aServerPort)
       : HttpClient(aClient, aServerName.c_str(), aServerPort)
      
    • the const char * one sets the iServerName field
      HttpClient::HttpClient(Client& aClient, const char* aServerName, uint16_t aServerPort)
       : iClient(&aClient), iServerName(aServerName), iServerAddress(), iServerPort(aServerPort),
         iConnectionClose(true), iSendDefaultRequestHeaders(true)
      
  • one only takes aServerAddress

During sendInitialHeaders, the client will send the Host header, but only for aServerName; it doesn't have it with aServerAddress

    if (iSendDefaultRequestHeaders)
    {
        // The host header, if required
        if (iServerName)
        {
            iClient->print("Host: ");
            iClient->print(iServerName);

With HTTP 1.1, the Host header is required. If it is missing, you get 400.

If you want to use IPAddress, you have to send the Host header manually, That requires calling beginRequest and endRequest, along with sendHeader; as in the CustomHeader example

  client.beginRequest();
  client.get("/");
  client.sendHeader("X-CUSTOM-HEADER", "custom_value");
  client.endRequest();

but with sendHeader("Host", "whatever.name.here")

1 Like

gah! I didn't notice the constructors were name, name and address.

Using the name is working great.

thanks for that!

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.