Przeglądaj źródła

add set_hostname_addr_map to WebSocketClient (#2463)

* add set_hostname_addr_map to WebSocketClient

* add WebSocketTest unit test cases
* SpecifyServerIPAddress_AnotherHostname
* SpecifyServerIPAddress_RealHostname

* Change wrong_ip from 0.0.0.0 to 192.0.2.1

Use 192.0.2.1 (RFC 5737 documentation address) to ensure it acts
as a non-routable address and does not alias to loopback.

* Fix style check

* set short timeout in WebSocketTest.SpecifyServerIPAddress_RealHostname

cannot reach wrong_ip
Kim, Hyuk 2 miesięcy temu
rodzic
commit
907257f51d
2 zmienionych plików z 66 dodań i 1 usunięć
  1. 15 1
      httplib.h
  2. 51 0
      test/test.cc

+ 15 - 1
httplib.h

@@ -3848,6 +3848,7 @@ public:
   void set_socket_options(SocketOptions socket_options);
   void set_connection_timeout(time_t sec, time_t usec = 0);
   void set_interface(const std::string &intf);
+  void set_hostname_addr_map(std::map<std::string, std::string> addr_map);
 
 #ifdef CPPHTTPLIB_SSL_ENABLED
   void set_ca_cert_path(const std::string &path);
@@ -3882,6 +3883,9 @@ private:
   time_t connection_timeout_usec_ = CPPHTTPLIB_CONNECTION_TIMEOUT_USECOND;
   std::string interface_;
 
+  // Hostname-IP map
+  std::map<std::string, std::string> addr_map_;
+
 #ifdef CPPHTTPLIB_SSL_ENABLED
   bool is_ssl_ = false;
   tls::ctx_t tls_ctx_ = nullptr;
@@ -20326,9 +20330,14 @@ inline bool WebSocketClient::connect() {
   if (!is_valid_) { return false; }
   shutdown_and_close();
 
+  // Check is custom IP specified for host_
+  std::string ip;
+  auto it = addr_map_.find(host_);
+  if (it != addr_map_.end()) { ip = it->second; }
+
   Error error;
   sock_ = detail::create_client_socket(
-      host_, std::string(), port_, address_family_, tcp_nodelay_, ipv6_v6only_,
+      host_, ip, port_, address_family_, tcp_nodelay_, ipv6_v6only_,
       socket_options_, connection_timeout_sec_, connection_timeout_usec_,
       read_timeout_sec_, read_timeout_usec_, write_timeout_sec_,
       write_timeout_usec_, interface_, error);
@@ -20423,6 +20432,11 @@ inline void WebSocketClient::set_interface(const std::string &intf) {
   interface_ = intf;
 }
 
+inline void WebSocketClient::set_hostname_addr_map(
+    std::map<std::string, std::string> addr_map) {
+  addr_map_ = std::move(addr_map);
+}
+
 #ifdef CPPHTTPLIB_SSL_ENABLED
 
 inline void WebSocketClient::set_ca_cert_path(const std::string &path) {

+ 51 - 0
test/test.cc

@@ -17706,6 +17706,57 @@ TEST(WebSocketTest, ComplexPath) {
   EXPECT_TRUE(ws2.is_valid());
 }
 
+TEST(WebSocketTest, SpecifyServerIPAddress_AnotherHostname) {
+  Server svr;
+  svr.WebSocket("/ws", [](const Request &, ws::WebSocket &ws) {
+    std::string msg;
+    while (ws.read(msg)) {}
+  });
+
+  auto port = svr.bind_to_any_port(HOST);
+  std::thread t([&]() { svr.listen_after_bind(); });
+  svr.wait_until_ready();
+
+  auto another_host = "example.com";
+  auto wrong_ip = "192.0.2.1";
+
+  ws::WebSocketClient client("ws://localhost:" + std::to_string(port) + "/ws");
+  client.set_hostname_addr_map({{another_host, wrong_ip}});
+
+  ASSERT_TRUE(client.connect());
+  EXPECT_TRUE(client.is_open());
+  client.close();
+
+  svr.stop();
+  t.join();
+}
+
+TEST(WebSocketTest, SpecifyServerIPAddress_RealHostname) {
+  Server svr;
+  svr.WebSocket("/ws", [](const Request &, ws::WebSocket &ws) {
+    std::string msg;
+    while (ws.read(msg)) {}
+  });
+
+  auto port = svr.bind_to_any_port(HOST);
+  std::thread t([&]() { svr.listen_after_bind(); });
+  svr.wait_until_ready();
+
+  auto wrong_ip = "192.0.2.1";
+
+  ws::WebSocketClient client("ws://localhost:" + std::to_string(port) + "/ws");
+  client.set_hostname_addr_map({{"localhost", wrong_ip}});
+  client.set_connection_timeout(1);
+  client.set_read_timeout(1);
+  client.set_write_timeout(1);
+
+  EXPECT_FALSE(client.connect());
+  EXPECT_FALSE(client.is_open());
+
+  svr.stop();
+  t.join();
+}
+
 class WebSocketIntegrationTest : public ::testing::Test {
 protected:
   void SetUp() override {