Przeglądaj źródła

Keep a Client usable when its URL cannot be used

An unsupported scheme without exceptions, or a port out of range, left
Client with no implementation, so the first request after it went
through a null pointer. Put a client in its place that reports itself
invalid and fails every request with Error::Connection.
yhirose 2 dni temu
rodzic
commit
b270564c18
2 zmienionych plików z 27 dodań i 1 usunięć
  1. 23 1
      httplib.h
  2. 4 0
      test/test.cc

+ 23 - 1
httplib.h

@@ -3103,6 +3103,24 @@ protected:
 #endif
 };
 
+namespace detail {
+
+// Stands in for a client that Client could not make from its arguments, so a
+// request fails rather than going through a null pointer.
+class InvalidClientImpl final : public ClientImpl {
+public:
+  InvalidClientImpl() : ClientImpl(std::string(), 0) {}
+  bool is_valid() const override { return false; }
+
+private:
+  bool create_and_connect_socket(Socket &, Error &error) override {
+    error = Error::Connection;
+    return false;
+  }
+};
+
+} // namespace detail
+
 class Client {
 public:
   // Universal interface
@@ -17697,6 +17715,7 @@ inline Client::Client(const std::string &scheme_host_port,
       std::string msg = "'" + scheme + "' scheme is not supported.";
       throw std::invalid_argument(msg);
 #endif
+      cli_ = detail::make_unique<detail::InvalidClientImpl>();
       return;
     }
 
@@ -17705,7 +17724,10 @@ inline Client::Client(const std::string &scheme_host_port,
     auto host = std::move(uc.host);
 
     auto port = is_ssl ? 443 : 80;
-    if (!uc.port.empty() && !detail::parse_port(uc.port, port)) { return; }
+    if (!uc.port.empty() && !detail::parse_port(uc.port, port)) {
+      cli_ = detail::make_unique<detail::InvalidClientImpl>();
+      return;
+    }
 
     if (is_ssl) {
 #ifdef CPPHTTPLIB_SSL_ENABLED

+ 4 - 0
test/test.cc

@@ -14627,6 +14627,10 @@ TEST(HostAndPortPropertiesTest, PortOutOfRange) {
   // Port 99999 exceeds valid range (1-65535) — should not crash
   httplib::Client cli("http://www.google.com:99999");
   ASSERT_FALSE(cli.is_valid());
+
+  auto res = cli.Get("/");
+  EXPECT_FALSE(res);
+  EXPECT_EQ(Error::Connection, res.error());
 }
 
 TEST(HostAndPortPropertiesTest, TrailingCharactersInPort) {