Skip to content

Commit 8f32271

Browse files
authored
Support LOCAL_ADDR and LOCAL_PORT header in client Request (#1450)
Having the local address/port is useful if the server is bound to all interfaces, e.g. to serve different content for developers on localhost only.
1 parent c8c1c3d commit 8f32271

File tree

3 files changed

+63
-8
lines changed

3 files changed

+63
-8
lines changed

httplib.h

Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,8 @@ struct Request {
413413

414414
std::string remote_addr;
415415
int remote_port = -1;
416+
std::string local_addr;
417+
int local_port = -1;
416418

417419
// for server
418420
std::string version;
@@ -514,6 +516,7 @@ class Stream {
514516
virtual ssize_t read(char *ptr, size_t size) = 0;
515517
virtual ssize_t write(const char *ptr, size_t size) = 0;
516518
virtual void get_remote_ip_and_port(std::string &ip, int &port) const = 0;
519+
virtual void get_local_ip_and_port(std::string &ip, int &port) const = 0;
517520
virtual socket_t socket() const = 0;
518521

519522
template <typename... Args>
@@ -1778,6 +1781,7 @@ class BufferStream : public Stream {
17781781
ssize_t read(char *ptr, size_t size) override;
17791782
ssize_t write(const char *ptr, size_t size) override;
17801783
void get_remote_ip_and_port(std::string &ip, int &port) const override;
1784+
void get_local_ip_and_port(std::string &ip, int &port) const override;
17811785
socket_t socket() const override;
17821786

17831787
const std::string &get_buffer() const;
@@ -2446,6 +2450,7 @@ class SocketStream : public Stream {
24462450
ssize_t read(char *ptr, size_t size) override;
24472451
ssize_t write(const char *ptr, size_t size) override;
24482452
void get_remote_ip_and_port(std::string &ip, int &port) const override;
2453+
void get_local_ip_and_port(std::string &ip, int &port) const override;
24492454
socket_t socket() const override;
24502455

24512456
private:
@@ -2475,6 +2480,7 @@ class SSLSocketStream : public Stream {
24752480
ssize_t read(char *ptr, size_t size) override;
24762481
ssize_t write(const char *ptr, size_t size) override;
24772482
void get_remote_ip_and_port(std::string &ip, int &port) const override;
2483+
void get_local_ip_and_port(std::string &ip, int &port) const override;
24782484
socket_t socket() const override;
24792485

24802486
private:
@@ -2843,9 +2849,9 @@ inline socket_t create_client_socket(
28432849
return sock;
28442850
}
28452851

2846-
inline bool get_remote_ip_and_port(const struct sockaddr_storage &addr,
2847-
socklen_t addr_len, std::string &ip,
2848-
int &port) {
2852+
inline bool get_ip_and_port(const struct sockaddr_storage &addr,
2853+
socklen_t addr_len, std::string &ip,
2854+
int &port) {
28492855
if (addr.ss_family == AF_INET) {
28502856
port = ntohs(reinterpret_cast<const struct sockaddr_in *>(&addr)->sin_port);
28512857
} else if (addr.ss_family == AF_INET6) {
@@ -2866,6 +2872,15 @@ inline bool get_remote_ip_and_port(const struct sockaddr_storage &addr,
28662872
return true;
28672873
}
28682874

2875+
inline void get_local_ip_and_port(socket_t sock, std::string &ip, int &port) {
2876+
struct sockaddr_storage addr;
2877+
socklen_t addr_len = sizeof(addr);
2878+
if (!getsockname(sock, reinterpret_cast<struct sockaddr *>(&addr),
2879+
&addr_len)) {
2880+
get_ip_and_port(addr, addr_len, ip, port);
2881+
}
2882+
}
2883+
28692884
inline void get_remote_ip_and_port(socket_t sock, std::string &ip, int &port) {
28702885
struct sockaddr_storage addr;
28712886
socklen_t addr_len = sizeof(addr);
@@ -2890,7 +2905,7 @@ inline void get_remote_ip_and_port(socket_t sock, std::string &ip, int &port) {
28902905
return;
28912906
}
28922907
#endif
2893-
get_remote_ip_and_port(addr, addr_len, ip, port);
2908+
get_ip_and_port(addr, addr_len, ip, port);
28942909
}
28952910
}
28962911

@@ -4517,8 +4532,8 @@ inline void hosted_at(const std::string &hostname,
45174532
*reinterpret_cast<struct sockaddr_storage *>(rp->ai_addr);
45184533
std::string ip;
45194534
int dummy = -1;
4520-
if (detail::get_remote_ip_and_port(addr, sizeof(struct sockaddr_storage),
4521-
ip, dummy)) {
4535+
if (detail::get_ip_and_port(addr, sizeof(struct sockaddr_storage),
4536+
ip, dummy)) {
45224537
addrs.push_back(ip);
45234538
}
45244539
}
@@ -4808,6 +4823,11 @@ inline void SocketStream::get_remote_ip_and_port(std::string &ip,
48084823
return detail::get_remote_ip_and_port(sock_, ip, port);
48094824
}
48104825

4826+
inline void SocketStream::get_local_ip_and_port(std::string &ip,
4827+
int &port) const {
4828+
return detail::get_local_ip_and_port(sock_, ip, port);
4829+
}
4830+
48114831
inline socket_t SocketStream::socket() const { return sock_; }
48124832

48134833
// Buffer stream implementation
@@ -4833,6 +4853,9 @@ inline ssize_t BufferStream::write(const char *ptr, size_t size) {
48334853
inline void BufferStream::get_remote_ip_and_port(std::string & /*ip*/,
48344854
int & /*port*/) const {}
48354855

4856+
inline void BufferStream::get_local_ip_and_port(std::string & /*ip*/,
4857+
int & /*port*/) const {}
4858+
48364859
inline socket_t BufferStream::socket() const { return 0; }
48374860

48384861
inline const std::string &BufferStream::get_buffer() const { return buffer; }
@@ -5812,6 +5835,10 @@ Server::process_request(Stream &strm, bool close_connection,
58125835
req.set_header("REMOTE_ADDR", req.remote_addr);
58135836
req.set_header("REMOTE_PORT", std::to_string(req.remote_port));
58145837

5838+
strm.get_local_ip_and_port(req.local_addr, req.local_port);
5839+
req.set_header("LOCAL_ADDR", req.local_addr);
5840+
req.set_header("LOCAL_PORT", std::to_string(req.local_port));
5841+
58155842
if (req.has_header("Range")) {
58165843
const auto &range_header_value = req.get_header_value("Range");
58175844
if (!detail::parse_range_header(range_header_value, req.ranges)) {
@@ -7409,6 +7436,11 @@ inline void SSLSocketStream::get_remote_ip_and_port(std::string &ip,
74097436
detail::get_remote_ip_and_port(sock_, ip, port);
74107437
}
74117438

7439+
inline void SSLSocketStream::get_local_ip_and_port(std::string &ip,
7440+
int &port) const {
7441+
detail::get_local_ip_and_port(sock_, ip, port);
7442+
}
7443+
74127444
inline socket_t SSLSocketStream::socket() const { return sock_; }
74137445

74147446
static SSLInit sslinit_;

test/fuzzing/server_fuzzer.cc

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,6 @@ class FuzzedStream : public httplib::Stream {
2222

2323
ssize_t write(const std::string &s) { return write(s.data(), s.size()); }
2424

25-
std::string get_remote_addr() const { return ""; }
26-
2725
bool is_readable() const override { return true; }
2826

2927
bool is_writable() const override { return true; }
@@ -33,6 +31,11 @@ class FuzzedStream : public httplib::Stream {
3331
port = 8080;
3432
}
3533

34+
void get_local_ip_and_port(std::string &ip, int &port) const override {
35+
ip = "127.0.0.1";
36+
port = 8080;
37+
}
38+
3639
socket_t socket() const override { return 0; }
3740

3841
private:

test/test.cc

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1521,6 +1521,17 @@ class ServerTest : public ::testing::Test {
15211521
std::stoi(req.get_header_value("REMOTE_PORT")));
15221522
res.set_content(remote_addr.c_str(), "text/plain");
15231523
})
1524+
.Get("/local_addr",
1525+
[&](const Request &req, Response &res) {
1526+
EXPECT_TRUE(req.has_header("LOCAL_PORT"));
1527+
EXPECT_TRUE(req.has_header("LOCAL_ADDR"));
1528+
auto local_addr = req.get_header_value("LOCAL_ADDR");
1529+
auto local_port = req.get_header_value("LOCAL_PORT");
1530+
EXPECT_EQ(req.local_addr, local_addr);
1531+
EXPECT_EQ(req.local_port, std::stoi(local_port));
1532+
res.set_content(local_addr.append(":").append(local_port),
1533+
"text/plain");
1534+
})
15241535
.Get("/endwith%",
15251536
[&](const Request & /*req*/, Response &res) {
15261537
res.set_content("Hello World!", "text/plain");
@@ -2810,6 +2821,15 @@ TEST_F(ServerTest, GetMethodRemoteAddr) {
28102821
EXPECT_TRUE(res->body == "::1" || res->body == "127.0.0.1");
28112822
}
28122823

2824+
TEST_F(ServerTest, GetMethodLocalAddr) {
2825+
auto res = cli_.Get("/local_addr");
2826+
ASSERT_TRUE(res);
2827+
EXPECT_EQ(200, res->status);
2828+
EXPECT_EQ("text/plain", res->get_header_value("Content-Type"));
2829+
EXPECT_TRUE(res->body == std::string("::1:").append(to_string(PORT)) ||
2830+
res->body == std::string("127.0.0.1:").append(to_string(PORT)));
2831+
}
2832+
28132833
TEST_F(ServerTest, HTTPResponseSplitting) {
28142834
auto res = cli_.Get("/http_response_splitting");
28152835
ASSERT_TRUE(res);

0 commit comments

Comments
 (0)