yhirose 7 years ago
parent
commit
5536d4c1ff
2 changed files with 79 additions and 15 deletions
  1. 23 13
      httplib.h
  2. 56 2
      test/test.cc

+ 23 - 13
httplib.h

@@ -437,25 +437,32 @@ inline int select_read(socket_t sock, size_t sec, size_t usec)
     return select(sock + 1, &fds, NULL, NULL, &tv);
     return select(sock + 1, &fds, NULL, NULL, &tv);
 }
 }
 
 
-inline bool is_socket_writable(socket_t sock, size_t sec, size_t usec)
+inline bool wait_until_socket_is_ready(socket_t sock, size_t sec, size_t usec)
 {
 {
-    fd_set fdsw;
-    FD_ZERO(&fdsw);
-    FD_SET(sock, &fdsw);
+    fd_set fdsr;
+    FD_ZERO(&fdsr);
+    FD_SET(sock, &fdsr);
 
 
-    fd_set fdse;
-    FD_ZERO(&fdse);
-    FD_SET(sock, &fdse);
+    auto fdsw = fdsr;
+    auto fdse = fdsr;
 
 
     timeval tv;
     timeval tv;
     tv.tv_sec = sec;
     tv.tv_sec = sec;
     tv.tv_usec = usec;
     tv.tv_usec = usec;
 
 
-    if (select(sock + 1, NULL, &fdsw, &fdse, &tv) <= 0) {
+    if (select(sock + 1, &fdsr, &fdsw, &fdse, &tv) < 0) {
+        return false;
+    } else if (FD_ISSET(sock, &fdsr) || FD_ISSET(sock, &fdsw)) {
+        int error = 0;
+        socklen_t len = sizeof(error);
+        if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (char*)&error, &len) < 0 || error) {
+            return false;
+        }
+    } else {
         return false;
         return false;
     }
     }
 
 
-    return FD_ISSET(sock, &fdsw) != 0;
+    return true;
 }
 }
 
 
 template <typename T>
 template <typename T>
@@ -1690,13 +1697,16 @@ inline socket_t Client::create_client_socket() const
             detail::set_nonblocking(sock, true);
             detail::set_nonblocking(sock, true);
 
 
             auto ret = connect(sock, ai.ai_addr, ai.ai_addrlen);
             auto ret = connect(sock, ai.ai_addr, ai.ai_addrlen);
-            if (ret == -1 && detail::is_connection_error()) {
-                return false;
+            if (ret < 0) {
+                if (detail::is_connection_error() ||
+                    !detail::wait_until_socket_is_ready(sock, timeout_sec_, 0)) {
+                    detail::close_socket(sock);
+                    return false;
+                }
             }
             }
 
 
             detail::set_nonblocking(sock, false);
             detail::set_nonblocking(sock, false);
-
-            return detail::is_socket_writable(sock, timeout_sec_, 0);
+            return true;
         });
         });
 }
 }
 
 

+ 56 - 2
test/test.cc

@@ -121,7 +121,7 @@ TEST(GetHeaderValueTest, Range)
 void testChunkedEncoding(httplib::HttpVersion ver)
 void testChunkedEncoding(httplib::HttpVersion ver)
 {
 {
     auto host = "www.httpwatch.com";
     auto host = "www.httpwatch.com";
-    auto sec = 5;
+    auto sec = 2;
 
 
 #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
 #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
     auto port = 443;
     auto port = 443;
@@ -186,6 +186,60 @@ TEST(RangeTest, FromHTTPBin)
     }
     }
 }
 }
 
 
+TEST(ConnectionErrorTest, InvalidHost)
+{
+    auto host = "abcde.com";
+    auto sec = 2;
+    auto ver = httplib::HttpVersion::v1_1;
+
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+    auto port = 443;
+    httplib::SSLClient cli(host, port, sec, ver);
+#else
+    auto port = 80;
+    httplib::Client cli(host, port, sec, ver);
+#endif
+
+    auto res = cli.get("/");
+    ASSERT_TRUE(res == nullptr);
+}
+
+TEST(ConnectionErrorTest, InvalidPort)
+{
+    auto host = "localhost";
+    auto sec = 2;
+    auto ver = httplib::HttpVersion::v1_1;
+
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+    auto port = 44380;
+    httplib::SSLClient cli(host, port, sec, ver);
+#else
+    auto port = 8080;
+    httplib::Client cli(host, port, sec, ver);
+#endif
+
+    auto res = cli.get("/");
+    ASSERT_TRUE(res == nullptr);
+}
+
+TEST(ConnectionErrorTest, Timeout)
+{
+    auto host = "google.com";
+    auto sec = 2;
+    auto ver = httplib::HttpVersion::v1_1;
+
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+    auto port = 44380;
+    httplib::SSLClient cli(host, port, sec, ver);
+#else
+    auto port = 8080;
+    httplib::Client cli(host, port, sec, ver);
+#endif
+
+    auto res = cli.get("/");
+    ASSERT_TRUE(res == nullptr);
+}
+
 class ServerTest : public ::testing::Test {
 class ServerTest : public ::testing::Test {
 protected:
 protected:
     ServerTest()
     ServerTest()
@@ -584,7 +638,7 @@ TEST_F(ServerTest, GetMethodRemoteAddr)
     ASSERT_TRUE(res != nullptr);
     ASSERT_TRUE(res != nullptr);
     EXPECT_EQ(200, res->status);
     EXPECT_EQ(200, res->status);
     EXPECT_EQ("text/plain", res->get_header_value("Content-Type"));
     EXPECT_EQ("text/plain", res->get_header_value("Content-Type"));
-    EXPECT_EQ("::1", res->body);  // NOTE: depends on user's environment...
+    EXPECT_TRUE(res->body == "::1" || res->body == "127.0.0.1");
 }
 }
 
 
 #ifdef CPPHTTPLIB_ZLIB_SUPPORT
 #ifdef CPPHTTPLIB_ZLIB_SUPPORT