]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[#1764] More shared server
authorFrancis Dupont <fdupont@isc.org>
Sun, 4 Aug 2024 14:29:59 +0000 (16:29 +0200)
committerFrancis Dupont <fdupont@isc.org>
Thu, 22 Aug 2024 08:23:03 +0000 (10:23 +0200)
src/lib/http/tests/http_server_test.h
src/lib/http/tests/http_server_unittests.cc
src/lib/http/tests/tls_server_unittests.cc

index da0b3673f1f69d4c788bf8dc461ce32e6e793ca1..999869930cb2474e7b7922733bf487b99d2bd3fb 100644 (file)
@@ -374,6 +374,348 @@ public:
         EXPECT_EQ(httpOk(HttpVersion::HTTP_11()), client->getResponse());
     }
 
+    /// @brief Verify that HTTP connection can be established and used to
+    /// transmit HTTP request and receive a response.
+    void testListen() {
+        const std::string request = "POST /foo/bar HTTP/1.1\r\n"
+            "Content-Type: application/json\r\n"
+            "Content-Length: 3\r\n\r\n"
+            "{ }";
+
+        HttpListener listener(io_service_,
+                              IOAddress(SERVER_ADDRESS),
+                              SERVER_PORT,
+                              server_context_,
+                              factory_,
+                              HttpListener::RequestTimeout(REQUEST_TIMEOUT),
+                              HttpListener::IdleTimeout(IDLE_TIMEOUT));
+        ASSERT_NO_THROW(listener.start());
+        ASSERT_EQ(SERVER_ADDRESS, listener.getLocalAddress().toText());
+        ASSERT_EQ(SERVER_PORT, listener.getLocalPort());
+        ASSERT_NO_THROW(startRequest(request));
+        ASSERT_NO_THROW(runIOService());
+        ASSERT_EQ(1, clients_.size());
+        auto client = *clients_.begin();
+        ASSERT_TRUE(client);
+        EXPECT_EQ(httpOk(HttpVersion::HTTP_11()), client->getResponse());
+
+        listener.stop();
+        io_service_->poll();
+    }
+
+    /// @brief Verify that persistent HTTP connection can be established when
+    /// no "Connection: Keep-Alive" header value is specified.
+    void testKeepAlive() {
+        // The first request contains the keep-alive header which
+        // instructs the server to maintain the TCP connection after
+        // sending a response.
+        std::string request = "POST /foo/bar HTTP/1.0\r\n"
+            "Content-Type: application/json\r\n"
+            "Content-Length: 3\r\n"
+            "Connection: Keep-Alive\r\n\r\n"
+            "{ }";
+
+        HttpListener listener(io_service_,
+                              IOAddress(SERVER_ADDRESS),
+                              SERVER_PORT,
+                              server_context_,
+                              factory_,
+                              HttpListener::RequestTimeout(REQUEST_TIMEOUT),
+                              HttpListener::IdleTimeout(IDLE_TIMEOUT));
+
+        ASSERT_NO_THROW(listener.start());
+
+        // Send the request with the keep-alive header.
+        ASSERT_NO_THROW(startRequest(request));
+        ASSERT_NO_THROW(runIOService());
+        ASSERT_EQ(1, clients_.size());
+        auto client = *clients_.begin();
+        ASSERT_TRUE(client);
+        EXPECT_EQ(httpOk(HttpVersion::HTTP_10()), client->getResponse());
+
+        // We have sent keep-alive header so we expect that the connection with
+        // the server remains active.
+        ASSERT_TRUE(client->isConnectionAlive());
+
+        // Test that we can send another request via the same connection.
+        // This time it lacks the keep-alive header, so the server should
+        // close the connection after sending the response.
+        request = "POST /foo/bar HTTP/1.0\r\n"
+            "Content-Type: application/json\r\n"
+            "Content-Length: 3\r\n\r\n"
+            "{ }";
+
+        // Send request reusing the existing connection.
+        ASSERT_NO_THROW(client->sendRequest(request));
+        ASSERT_NO_THROW(runIOService());
+        EXPECT_EQ(httpOk(HttpVersion::HTTP_10()), client->getResponse());
+
+        // Connection should have been closed by the server.
+        EXPECT_TRUE(client->isConnectionClosed());
+
+        listener.stop();
+        io_service_->poll();
+    }
+
+    /// @brief Verify that persistent HTTP connection is established by default
+    /// when HTTP/1.1 is in use.
+    void testPersistentConnection() {
+        // The HTTP/1.1 requests are by default persistent.
+        std::string request = "POST /foo/bar HTTP/1.1\r\n"
+            "Content-Type: application/json\r\n"
+            "Content-Length: 3\r\n\r\n"
+            "{ }";
+
+        HttpListener listener(io_service_,
+                              IOAddress(SERVER_ADDRESS),
+                              SERVER_PORT,
+                              server_context_,
+                              factory_,
+                              HttpListener::RequestTimeout(REQUEST_TIMEOUT),
+                              HttpListener::IdleTimeout(IDLE_TIMEOUT));
+
+        ASSERT_NO_THROW(listener.start());
+
+        // Send the first request.
+        ASSERT_NO_THROW(startRequest(request));
+        ASSERT_NO_THROW(runIOService());
+        ASSERT_EQ(1, clients_.size());
+        auto client = *clients_.begin();
+        ASSERT_TRUE(client);
+        EXPECT_EQ(httpOk(HttpVersion::HTTP_11()), client->getResponse());
+
+        // HTTP/1.1 connection is persistent by default.
+        ASSERT_TRUE(client->isConnectionAlive());
+
+        // Test that we can send another request via the same connection.
+        // This time it includes the "Connection: close"  header which
+        // instructs the server to close the connection after responding.
+        request = "POST /foo/bar HTTP/1.1\r\n"
+            "Content-Type: application/json\r\n"
+            "Content-Length: 3\r\n"
+            "Connection: close\r\n\r\n"
+            "{ }";
+
+        // Send request reusing the existing connection.
+        ASSERT_NO_THROW(client->sendRequest(request));
+        ASSERT_NO_THROW(runIOService());
+        EXPECT_EQ(httpOk(HttpVersion::HTTP_11()), client->getResponse());
+
+        // Connection should have been closed by the server.
+        EXPECT_TRUE(client->isConnectionClosed());
+
+        listener.stop();
+        io_service_->poll();
+    }
+
+    /// @brief Verify that "keep-alive" connection is closed by the server
+    /// after an idle time.
+    void testKeepAliveTimeout() {
+
+        // The first request contains the keep-alive header which
+        // instructs the server to maintain the TCP connection after
+        // sending a response.
+        std::string request = "POST /foo/bar HTTP/1.0\r\n"
+            "Content-Type: application/json\r\n"
+            "Content-Length: 3\r\n"
+            "Connection: Keep-Alive\r\n\r\n"
+            "{ }";
+
+        // Specify the idle timeout of 500ms.
+        HttpListener listener(io_service_,
+                              IOAddress(SERVER_ADDRESS),
+                              SERVER_PORT,
+                              server_context_,
+                              factory_,
+                              HttpListener::RequestTimeout(REQUEST_TIMEOUT),
+                              HttpListener::IdleTimeout(500));
+
+        ASSERT_NO_THROW(listener.start());
+
+        // Send the request with the keep-alive header.
+        ASSERT_NO_THROW(startRequest(request));
+        ASSERT_NO_THROW(runIOService());
+        ASSERT_EQ(1, clients_.size());
+        auto client = *clients_.begin();
+        ASSERT_TRUE(client);
+        EXPECT_EQ(httpOk(HttpVersion::HTTP_10()), client->getResponse());
+
+        // We have sent keep-alive header so we expect that the connection with
+        // the server remains active.
+        ASSERT_TRUE(client->isConnectionAlive());
+
+        // Run IO service for 1000ms. The idle time is set to 500ms, so
+        // the connection should be closed by the server while we  wait here.
+        runIOService(1000);
+
+        // Make sure the connection has been closed.
+        EXPECT_TRUE(client->isConnectionClosed());
+
+        // Check if we can re-establish the connection and send another request.
+        clients_.clear();
+        request = "POST /foo/bar HTTP/1.0\r\n"
+            "Content-Type: application/json\r\n"
+            "Content-Length: 3\r\n\r\n"
+            "{ }";
+
+        ASSERT_NO_THROW(startRequest(request));
+        ASSERT_NO_THROW(runIOService());
+        ASSERT_EQ(1, clients_.size());
+        client = *clients_.begin();
+        ASSERT_TRUE(client);
+        EXPECT_EQ(httpOk(HttpVersion::HTTP_10()), client->getResponse());
+
+        EXPECT_TRUE(client->isConnectionClosed());
+
+        listener.stop();
+        io_service_->poll();
+    }
+
+    /// @brief Verify that persistent connection is closed by the server after
+    /// an idle time.
+    void testPersistentConnectionTimeout() {
+        // The HTTP/1.1 requests are by default persistent.
+        std::string request = "POST /foo/bar HTTP/1.1\r\n"
+            "Content-Type: application/json\r\n"
+            "Content-Length: 3\r\n\r\n"
+            "{ }";
+
+        // Specify the idle timeout of 500ms.
+        HttpListener listener(io_service_,
+                              IOAddress(SERVER_ADDRESS),
+                              SERVER_PORT,
+                              server_context_,
+                              factory_,
+                              HttpListener::RequestTimeout(REQUEST_TIMEOUT),
+                              HttpListener::IdleTimeout(500));
+
+        ASSERT_NO_THROW(listener.start());
+
+        // Send the request.
+        ASSERT_NO_THROW(startRequest(request));
+        ASSERT_NO_THROW(runIOService());
+        ASSERT_EQ(1, clients_.size());
+        auto client = *clients_.begin();
+        ASSERT_TRUE(client);
+        EXPECT_EQ(httpOk(HttpVersion::HTTP_11()), client->getResponse());
+
+        // The connection should remain active.
+        ASSERT_TRUE(client->isConnectionAlive());
+
+        // Run IO service for 1000ms. The idle time is set to 500ms, so
+        // the connection should be closed by the server while we wait here.
+        runIOService(1000);
+
+        // Make sure the connection has been closed.
+        EXPECT_TRUE(client->isConnectionClosed());
+
+        // Check if we can re-establish the connection and send another request.
+        clients_.clear();
+        request = "POST /foo/bar HTTP/1.1\r\n"
+            "Content-Type: application/json\r\n"
+            "Content-Length: 3\r\n"
+            "Connection: close\r\n\r\n"
+            "{ }";
+
+        ASSERT_NO_THROW(startRequest(request));
+        ASSERT_NO_THROW(runIOService());
+        ASSERT_EQ(1, clients_.size());
+        client = *clients_.begin();
+        ASSERT_TRUE(client);
+        EXPECT_EQ(httpOk(HttpVersion::HTTP_11()), client->getResponse());
+
+        EXPECT_TRUE(client->isConnectionClosed());
+
+        listener.stop();
+        io_service_->poll();
+    }
+
+    /// @brief Verify that HTTP/1.1 connection remains open even if there is an
+    /// error in the message body.
+    void testPersistentConnectionBadBody() {
+        // The HTTP/1.1 requests are by default persistent.
+        std::string request = "POST /foo/bar HTTP/1.1\r\n"
+            "Content-Type: application/json\r\n"
+            "Content-Length: 12\r\n\r\n"
+            "{ \"a\": abc }";
+
+        HttpListener listener(io_service_,
+                              IOAddress(SERVER_ADDRESS),
+                              SERVER_PORT,
+                              server_context_,
+                              factory_,
+                              HttpListener::RequestTimeout(REQUEST_TIMEOUT),
+                              HttpListener::IdleTimeout(IDLE_TIMEOUT));
+
+        ASSERT_NO_THROW(listener.start());
+
+        // Send the request.
+        ASSERT_NO_THROW(startRequest(request));
+        ASSERT_NO_THROW(runIOService());
+        ASSERT_EQ(1, clients_.size());
+        auto client = *clients_.begin();
+        ASSERT_TRUE(client);
+        EXPECT_EQ("HTTP/1.1 400 Bad Request\r\n"
+                  "Content-Length: 40\r\n"
+                  "Content-Type: application/json\r\n"
+                  "Date: Tue, 19 Dec 2016 18:53:35 GMT\r\n"
+                  "\r\n"
+                  "{ \"result\": 400, \"text\": \"Bad Request\" }",
+                  client->getResponse());
+
+        // The connection should remain active.
+        ASSERT_TRUE(client->isConnectionAlive());
+
+        // Make sure that we can send another request. This time we specify the
+        // "close" connection-token to force the connection to close.
+        request = "POST /foo/bar HTTP/1.1\r\n"
+            "Content-Type: application/json\r\n"
+            "Content-Length: 3\r\n"
+            "Connection: close\r\n\r\n"
+            "{ }";
+
+        // Send request reusing the existing connection.
+        ASSERT_NO_THROW(client->sendRequest(request));
+        ASSERT_NO_THROW(runIOService());
+        EXPECT_EQ(httpOk(HttpVersion::HTTP_11()), client->getResponse());
+
+        EXPECT_TRUE(client->isConnectionClosed());
+
+        listener.stop();
+        io_service_->poll();
+    }
+
+    /// @brief Verify that Bad Request status is returned when the request
+    /// is malformed.
+    void testBadRequest() {
+        // Content-Type is wrong. This should result in Bad Request status.
+        const std::string request = "POST /foo/bar HTTP/1.1\r\n"
+            "Content-Type: foo\r\n"
+            "Content-Length: 3\r\n\r\n"
+            "{ }";
+
+        HttpListener listener(io_service_,
+                              IOAddress(SERVER_ADDRESS),
+                              SERVER_PORT,
+                              server_context_,
+                              factory_,
+                              HttpListener::RequestTimeout(REQUEST_TIMEOUT),
+                              HttpListener::IdleTimeout(IDLE_TIMEOUT));
+        ASSERT_NO_THROW(listener.start());
+        ASSERT_NO_THROW(startRequest(request));
+        ASSERT_NO_THROW(runIOService());
+        ASSERT_EQ(1, clients_.size());
+        auto client = *clients_.begin();
+        ASSERT_TRUE(client);
+        EXPECT_EQ("HTTP/1.1 400 Bad Request\r\n"
+                  "Content-Length: 40\r\n"
+                  "Content-Type: application/json\r\n"
+                  "Date: Tue, 19 Dec 2016 18:53:35 GMT\r\n"
+                  "\r\n"
+                  "{ \"result\": 400, \"text\": \"Bad Request\" }",
+                  client->getResponse());
+    }
+
     /// @brief IO service used in the tests.
     IOServicePtr io_service_;
 
index 3618fca2dbedb118a9352b6888d452171bfc6d28..a05e5fbc8f87c3369e22630f42b84dda5a01ff2a 100644 (file)
@@ -61,297 +61,37 @@ public:
 // This test verifies that HTTP connection can be established and used to
 // transmit HTTP request and receive a response.
 TEST_F(HttpListenerTest, listen) {
-    const std::string request = "POST /foo/bar HTTP/1.1\r\n"
-        "Content-Type: application/json\r\n"
-        "Content-Length: 3\r\n\r\n"
-        "{ }";
-
-    HttpListener listener(io_service_, IOAddress(SERVER_ADDRESS), SERVER_PORT,
-                          TlsContextPtr(), factory_,
-                          HttpListener::RequestTimeout(REQUEST_TIMEOUT),
-                          HttpListener::IdleTimeout(IDLE_TIMEOUT));
-    ASSERT_NO_THROW(listener.start());
-    ASSERT_EQ(SERVER_ADDRESS, listener.getLocalAddress().toText());
-    ASSERT_EQ(SERVER_PORT, listener.getLocalPort());
-    ASSERT_NO_THROW(startRequest(request));
-    ASSERT_NO_THROW(runIOService());
-    ASSERT_EQ(1, clients_.size());
-    auto client = *clients_.begin();
-    ASSERT_TRUE(client);
-    EXPECT_EQ(httpOk(HttpVersion::HTTP_11()), client->getResponse());
-
-    listener.stop();
-    io_service_->poll();
+    testListen();
 }
 
-
 // This test verifies that persistent HTTP connection can be established when
-// "Connection: Keep-Alive" header value is specified.
+// no "Connection: Keep-Alive" header value is specified.
 TEST_F(HttpListenerTest, keepAlive) {
-
-    // The first request contains the keep-alive header which instructs the server
-    // to maintain the TCP connection after sending a response.
-    std::string request = "POST /foo/bar HTTP/1.0\r\n"
-        "Content-Type: application/json\r\n"
-        "Content-Length: 3\r\n"
-        "Connection: Keep-Alive\r\n\r\n"
-        "{ }";
-
-    HttpListener listener(io_service_, IOAddress(SERVER_ADDRESS), SERVER_PORT,
-                          TlsContextPtr(), factory_,
-                          HttpListener::RequestTimeout(REQUEST_TIMEOUT),
-                          HttpListener::IdleTimeout(IDLE_TIMEOUT));
-
-    ASSERT_NO_THROW(listener.start());
-
-    // Send the request with the keep-alive header.
-    ASSERT_NO_THROW(startRequest(request));
-    ASSERT_NO_THROW(runIOService());
-    ASSERT_EQ(1, clients_.size());
-    auto client = *clients_.begin();
-    ASSERT_TRUE(client);
-    EXPECT_EQ(httpOk(HttpVersion::HTTP_10()), client->getResponse());
-
-    // We have sent keep-alive header so we expect that the connection with
-    // the server remains active.
-    ASSERT_TRUE(client->isConnectionAlive());
-
-    // Test that we can send another request via the same connection. This time
-    // it lacks the keep-alive header, so the server should close the connection
-    // after sending the response.
-    request = "POST /foo/bar HTTP/1.0\r\n"
-        "Content-Type: application/json\r\n"
-        "Content-Length: 3\r\n\r\n"
-        "{ }";
-
-    // Send request reusing the existing connection.
-    ASSERT_NO_THROW(client->sendRequest(request));
-    ASSERT_NO_THROW(runIOService());
-    EXPECT_EQ(httpOk(HttpVersion::HTTP_10()), client->getResponse());
-
-    // Connection should have been closed by the server.
-    EXPECT_TRUE(client->isConnectionClosed());
-
-    listener.stop();
-    io_service_->poll();
+    testKeepAlive();
 }
 
 // This test verifies that persistent HTTP connection is established by default
 // when HTTP/1.1 is in use.
 TEST_F(HttpListenerTest, persistentConnection) {
-
-    // The HTTP/1.1 requests are by default persistent.
-    std::string request = "POST /foo/bar HTTP/1.1\r\n"
-        "Content-Type: application/json\r\n"
-        "Content-Length: 3\r\n\r\n"
-        "{ }";
-
-    HttpListener listener(io_service_, IOAddress(SERVER_ADDRESS), SERVER_PORT,
-                          TlsContextPtr(), factory_,
-                          HttpListener::RequestTimeout(REQUEST_TIMEOUT),
-                          HttpListener::IdleTimeout(IDLE_TIMEOUT));
-
-    ASSERT_NO_THROW(listener.start());
-
-    // Send the first request.
-    ASSERT_NO_THROW(startRequest(request));
-    ASSERT_NO_THROW(runIOService());
-    ASSERT_EQ(1, clients_.size());
-    auto client = *clients_.begin();
-    ASSERT_TRUE(client);
-    EXPECT_EQ(httpOk(HttpVersion::HTTP_11()), client->getResponse());
-
-    // HTTP/1.1 connection is persistent by default.
-    ASSERT_TRUE(client->isConnectionAlive());
-
-    // Test that we can send another request via the same connection. This time
-    // it includes the "Connection: close" header which instructs the server to
-    // close the connection after responding.
-    request = "POST /foo/bar HTTP/1.1\r\n"
-        "Content-Type: application/json\r\n"
-        "Content-Length: 3\r\n"
-        "Connection: close\r\n\r\n"
-        "{ }";
-
-    // Send request reusing the existing connection.
-    ASSERT_NO_THROW(client->sendRequest(request));
-    ASSERT_NO_THROW(runIOService());
-    EXPECT_EQ(httpOk(HttpVersion::HTTP_11()), client->getResponse());
-
-    // Connection should have been closed by the server.
-    EXPECT_TRUE(client->isConnectionClosed());
-
-    listener.stop();
-    io_service_->poll();
+    testPersistentConnection();
 }
 
 // This test verifies that "keep-alive" connection is closed by the server after
 // an idle time.
 TEST_F(HttpListenerTest, keepAliveTimeout) {
-
-    // The first request contains the keep-alive header which instructs the server
-    // to maintain the TCP connection after sending a response.
-    std::string request = "POST /foo/bar HTTP/1.0\r\n"
-        "Content-Type: application/json\r\n"
-        "Content-Length: 3\r\n"
-        "Connection: Keep-Alive\r\n\r\n"
-        "{ }";
-
-    // Specify the idle timeout of 500ms.
-    HttpListener listener(io_service_, IOAddress(SERVER_ADDRESS), SERVER_PORT,
-                          TlsContextPtr(), factory_,
-                          HttpListener::RequestTimeout(REQUEST_TIMEOUT),
-                          HttpListener::IdleTimeout(500));
-
-    ASSERT_NO_THROW(listener.start());
-
-    // Send the request with the keep-alive header.
-    ASSERT_NO_THROW(startRequest(request));
-    ASSERT_NO_THROW(runIOService());
-    ASSERT_EQ(1, clients_.size());
-    auto client = *clients_.begin();
-    ASSERT_TRUE(client);
-    EXPECT_EQ(httpOk(HttpVersion::HTTP_10()), client->getResponse());
-
-    // We have sent keep-alive header so we expect that the connection with
-    // the server remains active.
-    ASSERT_TRUE(client->isConnectionAlive());
-
-    // Run IO service for 1000ms. The idle time is set to 500ms, so the connection
-    // should be closed by the server while we wait here.
-    runIOService(1000);
-
-    // Make sure the connection has been closed.
-    EXPECT_TRUE(client->isConnectionClosed());
-
-    // Check if we can re-establish the connection and send another request.
-    clients_.clear();
-    request = "POST /foo/bar HTTP/1.0\r\n"
-        "Content-Type: application/json\r\n"
-        "Content-Length: 3\r\n\r\n"
-        "{ }";
-
-    ASSERT_NO_THROW(startRequest(request));
-    ASSERT_NO_THROW(runIOService());
-    ASSERT_EQ(1, clients_.size());
-    client = *clients_.begin();
-    ASSERT_TRUE(client);
-    EXPECT_EQ(httpOk(HttpVersion::HTTP_10()), client->getResponse());
-
-    EXPECT_TRUE(client->isConnectionClosed());
-
-    listener.stop();
-    io_service_->poll();
+    testKeepAliveTimeout();
 }
 
 // This test verifies that persistent connection is closed by the server after
 // an idle time.
 TEST_F(HttpListenerTest, persistentConnectionTimeout) {
-
-    // The HTTP/1.1 requests are by default persistent.
-    std::string request = "POST /foo/bar HTTP/1.1\r\n"
-        "Content-Type: application/json\r\n"
-        "Content-Length: 3\r\n\r\n"
-        "{ }";
-
-    // Specify the idle timeout of 500ms.
-    HttpListener listener(io_service_, IOAddress(SERVER_ADDRESS), SERVER_PORT,
-                          TlsContextPtr(), factory_,
-                          HttpListener::RequestTimeout(REQUEST_TIMEOUT),
-                          HttpListener::IdleTimeout(500));
-
-    ASSERT_NO_THROW(listener.start());
-
-    // Send the request.
-    ASSERT_NO_THROW(startRequest(request));
-    ASSERT_NO_THROW(runIOService());
-    ASSERT_EQ(1, clients_.size());
-    auto client = *clients_.begin();
-    ASSERT_TRUE(client);
-    EXPECT_EQ(httpOk(HttpVersion::HTTP_11()), client->getResponse());
-
-    // The connection should remain active.
-    ASSERT_TRUE(client->isConnectionAlive());
-
-    // Run IO service for 1000ms. The idle time is set to 500ms, so the connection
-    // should be closed by the server while we wait here.
-    runIOService(1000);
-
-    // Make sure the connection has been closed.
-    EXPECT_TRUE(client->isConnectionClosed());
-
-    // Check if we can re-establish the connection and send another request.
-    clients_.clear();
-    request = "POST /foo/bar HTTP/1.1\r\n"
-        "Content-Type: application/json\r\n"
-        "Content-Length: 3\r\n"
-        "Connection: close\r\n\r\n"
-        "{ }";
-
-    ASSERT_NO_THROW(startRequest(request));
-    ASSERT_NO_THROW(runIOService());
-    ASSERT_EQ(1, clients_.size());
-    client = *clients_.begin();
-    ASSERT_TRUE(client);
-    EXPECT_EQ(httpOk(HttpVersion::HTTP_11()), client->getResponse());
-
-    EXPECT_TRUE(client->isConnectionClosed());
-
-    listener.stop();
-    io_service_->poll();
+    testPersistentConnectionTimeout();
 }
 
 // This test verifies that HTTP/1.1 connection remains open even if there is an
 // error in the message body.
 TEST_F(HttpListenerTest, persistentConnectionBadBody) {
-
-    // The HTTP/1.1 requests are by default persistent.
-    std::string request = "POST /foo/bar HTTP/1.1\r\n"
-        "Content-Type: application/json\r\n"
-        "Content-Length: 12\r\n\r\n"
-        "{ \"a\": abc }";
-
-    HttpListener listener(io_service_, IOAddress(SERVER_ADDRESS), SERVER_PORT,
-                          TlsContextPtr(), factory_,
-                          HttpListener::RequestTimeout(REQUEST_TIMEOUT),
-                          HttpListener::IdleTimeout(IDLE_TIMEOUT));
-
-    ASSERT_NO_THROW(listener.start());
-
-    // Send the request.
-    ASSERT_NO_THROW(startRequest(request));
-    ASSERT_NO_THROW(runIOService());
-    ASSERT_EQ(1, clients_.size());
-    auto client = *clients_.begin();
-    ASSERT_TRUE(client);
-    EXPECT_EQ("HTTP/1.1 400 Bad Request\r\n"
-              "Content-Length: 40\r\n"
-              "Content-Type: application/json\r\n"
-              "Date: Tue, 19 Dec 2016 18:53:35 GMT\r\n"
-              "\r\n"
-              "{ \"result\": 400, \"text\": \"Bad Request\" }",
-              client->getResponse());
-
-    // The connection should remain active.
-    ASSERT_TRUE(client->isConnectionAlive());
-
-    // Make sure that we can send another request. This time we specify the
-    // "close" connection-token to force the connection to close.
-    request = "POST /foo/bar HTTP/1.1\r\n"
-        "Content-Type: application/json\r\n"
-        "Content-Length: 3\r\n"
-        "Connection: close\r\n\r\n"
-        "{ }";
-
-    // Send request reusing the existing connection.
-    ASSERT_NO_THROW(client->sendRequest(request));
-    ASSERT_NO_THROW(runIOService());
-    EXPECT_EQ(httpOk(HttpVersion::HTTP_11()), client->getResponse());
-
-    EXPECT_TRUE(client->isConnectionClosed());
-
-    listener.stop();
-    io_service_->poll();
+    testPersistentConnectionBadBody();
 }
 
 // This test verifies that the HTTP listener can't be started twice.
@@ -367,29 +107,7 @@ TEST_F(HttpListenerTest, startTwice) {
 // This test verifies that Bad Request status is returned when the request
 // is malformed.
 TEST_F(HttpListenerTest, badRequest) {
-    // Content-Type is wrong. This should result in Bad Request status.
-    const std::string request = "POST /foo/bar HTTP/1.1\r\n"
-        "Content-Type: foo\r\n"
-        "Content-Length: 3\r\n\r\n"
-        "{ }";
-
-    HttpListener listener(io_service_, IOAddress(SERVER_ADDRESS), SERVER_PORT,
-                          TlsContextPtr(), factory_,
-                          HttpListener::RequestTimeout(REQUEST_TIMEOUT),
-                          HttpListener::IdleTimeout(IDLE_TIMEOUT));
-    ASSERT_NO_THROW(listener.start());
-    ASSERT_NO_THROW(startRequest(request));
-    ASSERT_NO_THROW(runIOService());
-    ASSERT_EQ(1, clients_.size());
-    auto client = *clients_.begin();
-    ASSERT_TRUE(client);
-    EXPECT_EQ("HTTP/1.1 400 Bad Request\r\n"
-              "Content-Length: 40\r\n"
-              "Content-Type: application/json\r\n"
-              "Date: Tue, 19 Dec 2016 18:53:35 GMT\r\n"
-              "\r\n"
-              "{ \"result\": 400, \"text\": \"Bad Request\" }",
-              client->getResponse());
+    testBadRequest();
 }
 
 // This test verifies that NULL pointer can't be specified for the
index f281d83c8c759e76b6be104115c7f628d1e04429..be2592aac340ceb518d0d5aed025d9ebfd84effd 100644 (file)
@@ -75,297 +75,38 @@ public:
 // This test verifies that HTTP connection can be established and used to
 // transmit HTTP request and receive a response.
 TEST_F(HttpsListenerTest, listen) {
-    const std::string request = "POST /foo/bar HTTP/1.1\r\n"
-        "Content-Type: application/json\r\n"
-        "Content-Length: 3\r\n\r\n"
-        "{ }";
-
-    HttpListener listener(io_service_, IOAddress(SERVER_ADDRESS), SERVER_PORT,
-                          server_context_, factory_,
-                          HttpListener::RequestTimeout(REQUEST_TIMEOUT),
-                          HttpListener::IdleTimeout(IDLE_TIMEOUT));
-    ASSERT_NO_THROW(listener.start());
-    ASSERT_EQ(SERVER_ADDRESS, listener.getLocalAddress().toText());
-    ASSERT_EQ(SERVER_PORT, listener.getLocalPort());
-    ASSERT_NO_THROW(startRequest(request));
-    ASSERT_NO_THROW(runIOService());
-    ASSERT_EQ(1, clients_.size());
-    auto client = *clients_.begin();
-    ASSERT_TRUE(client);
-    EXPECT_EQ(httpOk(HttpVersion::HTTP_11()), client->getResponse());
-
-    listener.stop();
-    io_service_->poll();
+    testListen();
 }
 
 
 // This test verifies that persistent HTTP connection can be established when
 // "Connection: Keep-Alive" header value is specified.
 TEST_F(HttpsListenerTest, keepAlive) {
-
-    // The first request contains the keep-alive header which instructs the server
-    // to maintain the TCP connection after sending a response.
-    std::string request = "POST /foo/bar HTTP/1.0\r\n"
-        "Content-Type: application/json\r\n"
-        "Content-Length: 3\r\n"
-        "Connection: Keep-Alive\r\n\r\n"
-        "{ }";
-
-    HttpListener listener(io_service_, IOAddress(SERVER_ADDRESS), SERVER_PORT,
-                          server_context_, factory_,
-                          HttpListener::RequestTimeout(REQUEST_TIMEOUT),
-                          HttpListener::IdleTimeout(IDLE_TIMEOUT));
-
-    ASSERT_NO_THROW(listener.start());
-
-    // Send the request with the keep-alive header.
-    ASSERT_NO_THROW(startRequest(request));
-    ASSERT_NO_THROW(runIOService());
-    ASSERT_EQ(1, clients_.size());
-    auto client = *clients_.begin();
-    ASSERT_TRUE(client);
-    EXPECT_EQ(httpOk(HttpVersion::HTTP_10()), client->getResponse());
-
-    // We have sent keep-alive header so we expect that the connection with
-    // the server remains active.
-    ASSERT_TRUE(client->isConnectionAlive());
-
-    // Test that we can send another request via the same connection. This time
-    // it lacks the keep-alive header, so the server should close the connection
-    // after sending the response.
-    request = "POST /foo/bar HTTP/1.0\r\n"
-        "Content-Type: application/json\r\n"
-        "Content-Length: 3\r\n\r\n"
-        "{ }";
-
-    // Send request reusing the existing connection.
-    ASSERT_NO_THROW(client->sendRequest(request));
-    ASSERT_NO_THROW(runIOService());
-    EXPECT_EQ(httpOk(HttpVersion::HTTP_10()), client->getResponse());
-
-    // Connection should have been closed by the server.
-    EXPECT_TRUE(client->isConnectionClosed());
-
-    listener.stop();
-    io_service_->poll();
+    testKeepAlive();
 }
 
 // This test verifies that persistent HTTP connection is established by default
 // when HTTP/1.1 is in use.
 TEST_F(HttpsListenerTest, persistentConnection) {
-
-    // The HTTP/1.1 requests are by default persistent.
-    std::string request = "POST /foo/bar HTTP/1.1\r\n"
-        "Content-Type: application/json\r\n"
-        "Content-Length: 3\r\n\r\n"
-        "{ }";
-
-    HttpListener listener(io_service_, IOAddress(SERVER_ADDRESS), SERVER_PORT,
-                          server_context_, factory_,
-                          HttpListener::RequestTimeout(REQUEST_TIMEOUT),
-                          HttpListener::IdleTimeout(IDLE_TIMEOUT));
-
-    ASSERT_NO_THROW(listener.start());
-
-    // Send the first request.
-    ASSERT_NO_THROW(startRequest(request));
-    ASSERT_NO_THROW(runIOService());
-    ASSERT_EQ(1, clients_.size());
-    auto client = *clients_.begin();
-    ASSERT_TRUE(client);
-    EXPECT_EQ(httpOk(HttpVersion::HTTP_11()), client->getResponse());
-
-    // HTTP/1.1 connection is persistent by default.
-    ASSERT_TRUE(client->isConnectionAlive());
-
-    // Test that we can send another request via the same connection. This time
-    // it includes the "Connection: close" header which instructs the server to
-    // close the connection after responding.
-    request = "POST /foo/bar HTTP/1.1\r\n"
-        "Content-Type: application/json\r\n"
-        "Content-Length: 3\r\n"
-        "Connection: close\r\n\r\n"
-        "{ }";
-
-    // Send request reusing the existing connection.
-    ASSERT_NO_THROW(client->sendRequest(request));
-    ASSERT_NO_THROW(runIOService());
-    EXPECT_EQ(httpOk(HttpVersion::HTTP_11()), client->getResponse());
-
-    // Connection should have been closed by the server.
-    EXPECT_TRUE(client->isConnectionClosed());
-
-    listener.stop();
-    io_service_->poll();
+    testPersistentConnection();
 }
 
 // This test verifies that "keep-alive" connection is closed by the server after
 // an idle time.
 TEST_F(HttpsListenerTest, keepAliveTimeout) {
-
-    // The first request contains the keep-alive header which instructs the server
-    // to maintain the TCP connection after sending a response.
-    std::string request = "POST /foo/bar HTTP/1.0\r\n"
-        "Content-Type: application/json\r\n"
-        "Content-Length: 3\r\n"
-        "Connection: Keep-Alive\r\n\r\n"
-        "{ }";
-
-    // Specify the idle timeout of 500ms.
-    HttpListener listener(io_service_, IOAddress(SERVER_ADDRESS), SERVER_PORT,
-                          server_context_, factory_,
-                          HttpListener::RequestTimeout(REQUEST_TIMEOUT),
-                          HttpListener::IdleTimeout(500));
-
-    ASSERT_NO_THROW(listener.start());
-
-    // Send the request with the keep-alive header.
-    ASSERT_NO_THROW(startRequest(request));
-    ASSERT_NO_THROW(runIOService());
-    ASSERT_EQ(1, clients_.size());
-    auto client = *clients_.begin();
-    ASSERT_TRUE(client);
-    EXPECT_EQ(httpOk(HttpVersion::HTTP_10()), client->getResponse());
-
-    // We have sent keep-alive header so we expect that the connection with
-    // the server remains active.
-    ASSERT_TRUE(client->isConnectionAlive());
-
-    // Run IO service for 1000ms. The idle time is set to 500ms, so the connection
-    // should be closed by the server while we wait here.
-    runIOService(1000);
-
-    // Make sure the connection has been closed.
-    EXPECT_TRUE(client->isConnectionClosed());
-
-    // Check if we can re-establish the connection and send another request.
-    clients_.clear();
-    request = "POST /foo/bar HTTP/1.0\r\n"
-        "Content-Type: application/json\r\n"
-        "Content-Length: 3\r\n\r\n"
-        "{ }";
-
-    ASSERT_NO_THROW(startRequest(request));
-    ASSERT_NO_THROW(runIOService());
-    ASSERT_EQ(1, clients_.size());
-    client = *clients_.begin();
-    ASSERT_TRUE(client);
-    EXPECT_EQ(httpOk(HttpVersion::HTTP_10()), client->getResponse());
-
-    EXPECT_TRUE(client->isConnectionClosed());
-
-    listener.stop();
-    io_service_->poll();
+    testKeepAliveTimeout();
 }
 
 // This test verifies that persistent connection is closed by the server after
 // an idle time.
 TEST_F(HttpsListenerTest, persistentConnectionTimeout) {
-
-    // The HTTP/1.1 requests are by default persistent.
-    std::string request = "POST /foo/bar HTTP/1.1\r\n"
-        "Content-Type: application/json\r\n"
-        "Content-Length: 3\r\n\r\n"
-        "{ }";
-
-    // Specify the idle timeout of 500ms.
-    HttpListener listener(io_service_, IOAddress(SERVER_ADDRESS), SERVER_PORT,
-                          server_context_, factory_,
-                          HttpListener::RequestTimeout(REQUEST_TIMEOUT),
-                          HttpListener::IdleTimeout(500));
-
-    ASSERT_NO_THROW(listener.start());
-
-    // Send the request.
-    ASSERT_NO_THROW(startRequest(request));
-    ASSERT_NO_THROW(runIOService());
-    ASSERT_EQ(1, clients_.size());
-    auto client = *clients_.begin();
-    ASSERT_TRUE(client);
-    EXPECT_EQ(httpOk(HttpVersion::HTTP_11()), client->getResponse());
-
-    // The connection should remain active.
-    ASSERT_TRUE(client->isConnectionAlive());
-
-    // Run IO service for 1000ms. The idle time is set to 500ms, so the connection
-    // should be closed by the server while we wait here.
-    runIOService(1000);
-
-    // Make sure the connection has been closed.
-    EXPECT_TRUE(client->isConnectionClosed());
-
-    // Check if we can re-establish the connection and send another request.
-    clients_.clear();
-    request = "POST /foo/bar HTTP/1.1\r\n"
-        "Content-Type: application/json\r\n"
-        "Content-Length: 3\r\n"
-        "Connection: close\r\n\r\n"
-        "{ }";
-
-    ASSERT_NO_THROW(startRequest(request));
-    ASSERT_NO_THROW(runIOService());
-    ASSERT_EQ(1, clients_.size());
-    client = *clients_.begin();
-    ASSERT_TRUE(client);
-    EXPECT_EQ(httpOk(HttpVersion::HTTP_11()), client->getResponse());
-
-    EXPECT_TRUE(client->isConnectionClosed());
-
-    listener.stop();
-    io_service_->poll();
+    testPersistentConnectionTimeout();
 }
 
 // This test verifies that HTTP/1.1 connection remains open even if there is an
 // error in the message body.
 TEST_F(HttpsListenerTest, persistentConnectionBadBody) {
-
-    // The HTTP/1.1 requests are by default persistent.
-    std::string request = "POST /foo/bar HTTP/1.1\r\n"
-        "Content-Type: application/json\r\n"
-        "Content-Length: 12\r\n\r\n"
-        "{ \"a\": abc }";
-
-    HttpListener listener(io_service_, IOAddress(SERVER_ADDRESS), SERVER_PORT,
-                          server_context_, factory_,
-                          HttpListener::RequestTimeout(REQUEST_TIMEOUT),
-                          HttpListener::IdleTimeout(IDLE_TIMEOUT));
-
-    ASSERT_NO_THROW(listener.start());
-
-    // Send the request.
-    ASSERT_NO_THROW(startRequest(request));
-    ASSERT_NO_THROW(runIOService());
-    ASSERT_EQ(1, clients_.size());
-    auto client = *clients_.begin();
-    ASSERT_TRUE(client);
-    EXPECT_EQ("HTTP/1.1 400 Bad Request\r\n"
-              "Content-Length: 40\r\n"
-              "Content-Type: application/json\r\n"
-              "Date: Tue, 19 Dec 2016 18:53:35 GMT\r\n"
-              "\r\n"
-              "{ \"result\": 400, \"text\": \"Bad Request\" }",
-              client->getResponse());
-
-    // The connection should remain active.
-    ASSERT_TRUE(client->isConnectionAlive());
-
-    // Make sure that we can send another request. This time we specify the
-    // "close" connection-token to force the connection to close.
-    request = "POST /foo/bar HTTP/1.1\r\n"
-        "Content-Type: application/json\r\n"
-        "Content-Length: 3\r\n"
-        "Connection: close\r\n\r\n"
-        "{ }";
-
-    // Send request reusing the existing connection.
-    ASSERT_NO_THROW(client->sendRequest(request));
-    ASSERT_NO_THROW(runIOService());
-    EXPECT_EQ(httpOk(HttpVersion::HTTP_11()), client->getResponse());
-
-    EXPECT_TRUE(client->isConnectionClosed());
-
-    listener.stop();
-    io_service_->poll();
+    testPersistentConnectionBadBody();
 }
 
 // This test verifies that the HTTP listener can't be started twice.
@@ -381,29 +122,7 @@ TEST_F(HttpsListenerTest, startTwice) {
 // This test verifies that Bad Request status is returned when the request
 // is malformed.
 TEST_F(HttpsListenerTest, badRequest) {
-    // Content-Type is wrong. This should result in Bad Request status.
-    const std::string request = "POST /foo/bar HTTP/1.1\r\n"
-        "Content-Type: foo\r\n"
-        "Content-Length: 3\r\n\r\n"
-        "{ }";
-
-    HttpListener listener(io_service_, IOAddress(SERVER_ADDRESS), SERVER_PORT,
-                          server_context_, factory_,
-                          HttpListener::RequestTimeout(REQUEST_TIMEOUT),
-                          HttpListener::IdleTimeout(IDLE_TIMEOUT));
-    ASSERT_NO_THROW(listener.start());
-    ASSERT_NO_THROW(startRequest(request));
-    ASSERT_NO_THROW(runIOService());
-    ASSERT_EQ(1, clients_.size());
-    auto client = *clients_.begin();
-    ASSERT_TRUE(client);
-    EXPECT_EQ("HTTP/1.1 400 Bad Request\r\n"
-              "Content-Length: 40\r\n"
-              "Content-Type: application/json\r\n"
-              "Date: Tue, 19 Dec 2016 18:53:35 GMT\r\n"
-              "\r\n"
-              "{ \"result\": 400, \"text\": \"Bad Request\" }",
-              client->getResponse());
+    testBadRequest();
 }
 
 // This test verifies that NULL pointer can't be specified for the