From b84b7de6be235bff4e9e23d6c12fe56f0c04559e Mon Sep 17 00:00:00 2001 From: AntonioBerna Date: Thu, 8 Jan 2026 15:24:31 +0100 Subject: [PATCH] fix: host header wrong :rocket: --- README.md | 7 ++ .../ConnectByIPWithHostHeader.ino | 70 +++++++++++++++++++ .../arduino_secrets.h | 2 + src/HttpClient.cpp | 24 ++++++- src/HttpClient.h | 18 +++++ 5 files changed, 119 insertions(+), 2 deletions(-) create mode 100644 examples/ConnectByIPWithHostHeader/ConnectByIPWithHostHeader.ino create mode 100644 examples/ConnectByIPWithHostHeader/arduino_secrets.h diff --git a/README.md b/README.md index e9c163b..fc21934 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,13 @@ Derived from [Adrian McEwen's HttpClient library](https://github.com/amcewen/Htt In normal usage, handles the outgoing request and Host header. The returned status code is parsed for you, as is the Content-Length header (if present). +If you need to connect to a server by IP address (or IP string) but still send a specific virtual-host name in the `Host` header (common on shared hosting), you can override the Host header: + +```cpp +HttpClient http(client, "93.184.216.34", 80); // connect by IP +http.setHostHeader("mypageservices.com"); // send desired Host header +``` + Because it expects an object of type Client, you can use it with any of the networking classes that derive from that. Which means it will work with WiFiClient, EthernetClient and GSMClient. See the examples for more detail on how the library is used. diff --git a/examples/ConnectByIPWithHostHeader/ConnectByIPWithHostHeader.ino b/examples/ConnectByIPWithHostHeader/ConnectByIPWithHostHeader.ino new file mode 100644 index 0000000..26f38e0 --- /dev/null +++ b/examples/ConnectByIPWithHostHeader/ConnectByIPWithHostHeader.ino @@ -0,0 +1,70 @@ +/* + Connect By IP, Override Host Header + for ArduinoHttpClient library + + Some hosting providers serve multiple sites from the same IP. + In that case you may need to connect to an IP address but still send the + correct HTTP Host header (virtual host), e.g. "mypageservices.com". + + created 8 Jan 2026 + + this example is in the public domain +*/ + +#include +#include + +#include "arduino_secrets.h" + +///////please enter your sensitive data in the Secret tab/arduino_secrets.h +/////// WiFi Settings /////// +char ssid[] = SECRET_SSID; +char pass[] = SECRET_PASS; + +// Connect by IP address (string form) +char serverAddress[] = "93.184.216.34"; // example.com +int port = 80; + +// But send this virtual-host name in the Host header +char hostName[] = "example.com"; + +WiFiClient wifi; +HttpClient client = HttpClient(wifi, serverAddress, port); +int status = WL_IDLE_STATUS; + +void setup() { + Serial.begin(9600); + + while (status != WL_CONNECTED) { + Serial.print("Attempting to connect to Network named: "); + Serial.println(ssid); + + status = WiFi.begin(ssid, pass); + } + + Serial.print("SSID: "); + Serial.println(WiFi.SSID()); + + IPAddress ip = WiFi.localIP(); + Serial.print("IP Address: "); + Serial.println(ip); + + // IMPORTANT: override Host header to target the right site on shared hosting + client.setHostHeader(hostName); +} + +void loop() { + Serial.println("making GET request"); + client.get("/"); + + int statusCode = client.responseStatusCode(); + String response = client.responseBody(); + + Serial.print("Status code: "); + Serial.println(statusCode); + Serial.print("Response: "); + Serial.println(response); + + Serial.println("Wait five seconds"); + delay(5000); +} diff --git a/examples/ConnectByIPWithHostHeader/arduino_secrets.h b/examples/ConnectByIPWithHostHeader/arduino_secrets.h new file mode 100644 index 0000000..0c9fdd5 --- /dev/null +++ b/examples/ConnectByIPWithHostHeader/arduino_secrets.h @@ -0,0 +1,2 @@ +#define SECRET_SSID "" +#define SECRET_PASS "" diff --git a/src/HttpClient.cpp b/src/HttpClient.cpp index 31909d9..9423220 100644 --- a/src/HttpClient.cpp +++ b/src/HttpClient.cpp @@ -29,6 +29,16 @@ HttpClient::HttpClient(Client& aClient, const IPAddress& aServerAddress, uint16_ resetState(); } +void HttpClient::setHostHeader(const char* aHostHeader) +{ + iHostHeader = aHostHeader ? aHostHeader : ""; +} + +void HttpClient::clearHostHeader() +{ + iHostHeader = ""; +} + void HttpClient::resetState() { iState = eIdle; @@ -158,10 +168,20 @@ int HttpClient::sendInitialHeaders(const char* aURLPath, const char* aHttpMethod if (iSendDefaultRequestHeaders) { // The host header, if required - if (iServerName) + const bool hasCustomHostHeader = (iHostHeader.length() > 0); + const bool shouldSendHostHeader = hasCustomHostHeader || (iServerName != NULL); + + if (shouldSendHostHeader) { iClient->print("Host: "); - iClient->print(iServerName); + if (hasCustomHostHeader) + { + iClient->print(iHostHeader); + } + else + { + iClient->print(iServerName); + } if (iServerPort != kHttpPort && iServerPort != kHttpsPort) { iClient->print(":"); diff --git a/src/HttpClient.h b/src/HttpClient.h index 3d404af..090313b 100644 --- a/src/HttpClient.h +++ b/src/HttpClient.h @@ -295,6 +295,23 @@ class HttpClient : public Client */ void noDefaultRequestHeaders(); + /** Override the value used for the HTTP Host header. + Useful when connecting to an IP address (or an IP string) but needing + a specific virtual-host name in the Host header. + + If not set (default), the Host header is generated from the server name + passed to the constructor. If the IPAddress constructor is used and no + override is set, no Host header is sent. + */ + void setHostHeader(const char* aHostHeader); + + void setHostHeader(const String& aHostHeader) + { setHostHeader(aHostHeader.c_str()); } + + /** Clear a previously overridden Host header value. + */ + void clearHostHeader(); + // Inherited from Print // Note: 1st call to these indicates the user is sending the body, so if need // Note: be we should finish the header first @@ -390,6 +407,7 @@ class HttpClient : public Client uint32_t iHttpWaitForDataDelay; bool iConnectionClose; bool iSendDefaultRequestHeaders; + String iHostHeader; String iHeaderLine; };