From 7b6867bcdf727f0a12b5e85a91007e8011eb41e5 Mon Sep 17 00:00:00 2001 From: yhirose Date: Thu, 10 Jul 2025 22:01:41 -0400 Subject: [PATCH] Fix #2021 (#2180) --- README.md | 2 ++ httplib.h | 6 +++++- test/test.cc | 42 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 49 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 75330a7..b607c20 100644 --- a/README.md +++ b/README.md @@ -1084,6 +1084,8 @@ cli.set_address_family(AF_UNIX); "my-socket.sock" can be a relative path or an absolute path. Your application must have the appropriate permissions for the path. You can also use an abstract socket address on Linux. To use an abstract socket address, prepend a null byte ('\x00') to the path. +This library automatically sets the Host header to "localhost" for Unix socket connections, similar to curl's behavior: + URI Encoding/Decoding Utilities ------------------------------- diff --git a/httplib.h b/httplib.h index 830c81e..b1c778a 100644 --- a/httplib.h +++ b/httplib.h @@ -8844,7 +8844,11 @@ inline bool ClientImpl::write_request(Stream &strm, Request &req, } if (!req.has_header("Host")) { - if (is_ssl()) { + // For Unix socket connections, use "localhost" as Host header (similar to + // curl behavior) + if (address_family_ == AF_UNIX) { + req.set_header("Host", "localhost"); + } else if (is_ssl()) { if (port_ == 443) { req.set_header("Host", host_); } else { diff --git a/test/test.cc b/test/test.cc index 7e397de..f7624bf 100644 --- a/test/test.cc +++ b/test/test.cc @@ -173,6 +173,48 @@ TEST_F(UnixSocketTest, abstract) { } #endif +TEST_F(UnixSocketTest, HostHeaderAutoSet) { + httplib::Server svr; + std::string received_host_header; + + svr.Get(pattern_, [&](const httplib::Request &req, httplib::Response &res) { + // Capture the Host header sent by the client + auto host_iter = req.headers.find("Host"); + if (host_iter != req.headers.end()) { + received_host_header = host_iter->second; + } + res.set_content(content_, "text/plain"); + }); + + std::thread t{[&] { + ASSERT_TRUE(svr.set_address_family(AF_UNIX).listen(pathname_, 80)); + }}; + auto se = detail::scope_exit([&] { + svr.stop(); + t.join(); + ASSERT_FALSE(svr.is_running()); + }); + + svr.wait_until_ready(); + ASSERT_TRUE(svr.is_running()); + + // Test that Host header is automatically set to "localhost" for Unix socket + // connections + httplib::Client cli{pathname_}; + cli.set_address_family(AF_UNIX); + ASSERT_TRUE(cli.is_valid()); + + const auto &result = cli.Get(pattern_); + ASSERT_TRUE(result) << "error: " << result.error(); + + const auto &resp = result.value(); + EXPECT_EQ(resp.status, StatusCode::OK_200); + EXPECT_EQ(resp.body, content_); + + // Verify that Host header was automatically set to "localhost" + EXPECT_EQ(received_host_header, "localhost"); +} + #ifndef _WIN32 TEST(SocketStream, wait_writable_UNIX) { int fds[2];