]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[#1764] Shared server
authorFrancis Dupont <fdupont@isc.org>
Sun, 4 Aug 2024 13:39:03 +0000 (15:39 +0200)
committerFrancis Dupont <fdupont@isc.org>
Thu, 22 Aug 2024 08:23:03 +0000 (10:23 +0200)
src/lib/http/tests/Makefile.am
src/lib/http/tests/http_server_test.h [new file with mode: 0644]
src/lib/http/tests/http_server_unittests.cc
src/lib/http/tests/tls_server_unittests.cc

index 9b75632945d4d4a14a4da9418e9957adad856559..c77477c2f00268e94611923608dcd36e69d24a6a 100644 (file)
@@ -47,6 +47,7 @@ libhttp_unittests_SOURCES += http_tests.h
 libhttp_unittests_SOURCES += http_response_creator_test.h
 libhttp_unittests_SOURCES += http_client_test.h
 libhttp_unittests_SOURCES += http_client_unittests.cc
+libhttp_unittests_SOURCES += http_server_test.h
 libhttp_unittests_SOURCES += http_server_unittests.cc
 if HAVE_OPENSSL
 libhttp_unittests_SOURCES += tls_server_unittests.cc
diff --git a/src/lib/http/tests/http_server_test.h b/src/lib/http/tests/http_server_test.h
new file mode 100644 (file)
index 0000000..da0b367
--- /dev/null
@@ -0,0 +1,400 @@
+// Copyright (C) 2017-2024 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef HTTP_SERVER_TEST_H
+#define HTTP_SERVER_TEST_H
+
+namespace isc {
+namespace http {
+namespace test {
+
+/// @brief Implementation of the HTTP listener used in tests.
+///
+/// This implementation replaces the @c HttpConnection type with a custom
+/// implementation.
+///
+/// @tparam HttpConnectionType Type of the connection object to be used by
+/// the listener implementation.
+template<typename HttpConnectionType>
+class HttpListenerImplCustom : public HttpListenerImpl {
+public:
+
+    HttpListenerImplCustom(const IOServicePtr& io_service,
+                           const IOAddress& server_address,
+                           const unsigned short server_port,
+                           const TlsContextPtr& tls_context,
+                           const HttpResponseCreatorFactoryPtr& creator_factory,
+                           const long request_timeout,
+                           const long idle_timeout)
+        : HttpListenerImpl(io_service, server_address, server_port,
+                           tls_context, creator_factory, request_timeout,
+                           idle_timeout) {
+    }
+
+protected:
+
+    /// @brief Creates an instance of the @c HttpConnection.
+    ///
+    /// This method is virtual so as it can be overridden when customized
+    /// connections are to be used, e.g. in case of unit testing.
+    ///
+    /// @param response_creator Pointer to the response creator object used to
+    /// create HTTP response from the HTTP request received.
+    /// @param callback Callback invoked when new connection is accepted.
+    ///
+    /// @return Pointer to the created connection.
+    virtual HttpConnectionPtr createConnection(const HttpResponseCreatorPtr& response_creator,
+                                               const HttpAcceptorCallback& callback) {
+        HttpConnectionPtr
+            conn(new HttpConnectionType(io_service_, acceptor_,
+                                        tls_context_, connections_,
+                                        response_creator, callback,
+                                        request_timeout_, idle_timeout_));
+        return (conn);
+    }
+};
+
+/// @brief Derivation of the @c HttpListener used in tests.
+///
+/// This class replaces the default implementation instance with the
+/// @c HttpListenerImplCustom using the customized connection type.
+///
+/// @tparam HttpConnectionType Type of the connection object to be used by
+/// the listener implementation.
+template<typename HttpConnectionType>
+class HttpListenerCustom : public HttpListener {
+public:
+
+    /// @brief Constructor.
+    ///
+    /// @param io_service IO service to be used by the listener.
+    /// @param server_address Address on which the HTTP service should run.
+    /// @param server_port Port number on which the HTTP service should run.
+    /// @param tls_context TLS context.
+    /// @param creator_factory Pointer to the caller-defined
+    /// @ref HttpResponseCreatorFactory derivation which should be used to
+    /// create @ref HttpResponseCreator instances.
+    /// @param request_timeout Timeout after which the HTTP Request Timeout
+    /// is generated.
+    /// @param idle_timeout Timeout after which an idle persistent HTTP
+    /// connection is closed by the server.
+    ///
+    /// @throw HttpListenerError when any of the specified parameters is
+    /// invalid.
+    HttpListenerCustom(const IOServicePtr& io_service,
+                       const IOAddress& server_address,
+                       const unsigned short server_port,
+                       const TlsContextPtr& tls_context,
+                       const HttpResponseCreatorFactoryPtr& creator_factory,
+                       const HttpListener::RequestTimeout& request_timeout,
+                       const HttpListener::IdleTimeout& idle_timeout)
+        : HttpListener(io_service, server_address, server_port,
+                       tls_context, creator_factory,
+                       request_timeout, idle_timeout) {
+        // Replace the default implementation with the customized version
+        // using the custom derivation of the HttpConnection.
+        impl_.reset(new HttpListenerImplCustom<HttpConnectionType>
+                    (io_service, server_address, server_port,
+                     tls_context, creator_factory, request_timeout.value_,
+                     idle_timeout.value_));
+    }
+};
+
+/// @brief Implementation of the @c HttpConnection which injects greater
+/// length value than the buffer size into the write socket callback.
+class HttpConnectionLongWriteBuffer : public HttpConnection {
+public:
+
+    /// @brief Constructor.
+    ///
+    /// @param io_service IO service to be used by the connection.
+    /// @param acceptor Pointer to the TCP acceptor object used to listen for
+    /// new HTTP connections.
+    /// @param tls_context TLS context.
+    /// @param connection_pool Connection pool in which this connection is
+    /// stored.
+    /// @param response_creator Pointer to the response creator object used to
+    /// create HTTP response from the HTTP request received.
+    /// @param callback Callback invoked when new connection is accepted.
+    /// @param request_timeout Configured timeout for a HTTP request.
+    /// @param idle_timeout Timeout after which persistent HTTP connection is
+    /// closed by the server.
+    HttpConnectionLongWriteBuffer(const IOServicePtr& io_service,
+                                  const HttpAcceptorPtr& acceptor,
+                                  const TlsContextPtr& tls_context,
+                                  HttpConnectionPool& connection_pool,
+                                  const HttpResponseCreatorPtr& response_creator,
+                                  const HttpAcceptorCallback& callback,
+                                  const long request_timeout,
+                                  const long idle_timeout)
+        : HttpConnection(io_service, acceptor, tls_context, connection_pool,
+                         response_creator, callback, request_timeout,
+                         idle_timeout) {
+    }
+
+    /// @brief Callback invoked when data is sent over the socket.
+    ///
+    /// @param transaction Pointer to the transaction for which the callback
+    /// is invoked.
+    /// @param ec Error code.
+    /// @param length Length of the data sent.
+    virtual void socketWriteCallback(HttpConnection::TransactionPtr transaction,
+                                     boost::system::error_code ec,
+                                     size_t length) {
+        // Pass greater length of the data written. The callback should deal
+        // with this and adjust the data length.
+        HttpConnection::socketWriteCallback(transaction, ec, length + 1);
+    }
+};
+
+/// @brief Implementation of the @c HttpConnection which replaces
+/// transaction instance prior to calling write socket callback.
+class HttpConnectionTransactionChange : public HttpConnection {
+public:
+
+    /// @brief Constructor.
+    ///
+    /// @param io_service IO service to be used by the connection.
+    /// @param acceptor Pointer to the TCP acceptor object used to listen for
+    /// new HTTP connections.
+    /// @param context TLS tls_context.
+    /// @param connection_pool Connection pool in which this connection is
+    /// stored.
+    /// @param response_creator Pointer to the response creator object used to
+    /// create HTTP response from the HTTP request received.
+    /// @param callback Callback invoked when new connection is accepted.
+    /// @param request_timeout Configured timeout for a HTTP request.
+    /// @param idle_timeout Timeout after which persistent HTTP connection is
+    /// closed by the server.
+    HttpConnectionTransactionChange(const IOServicePtr& io_service,
+                                    const HttpAcceptorPtr& acceptor,
+                                    const TlsContextPtr& tls_context,
+                                    HttpConnectionPool& connection_pool,
+                                    const HttpResponseCreatorPtr& response_creator,
+                                    const HttpAcceptorCallback& callback,
+                                    const long request_timeout,
+                                    const long idle_timeout)
+        : HttpConnection(io_service, acceptor, tls_context, connection_pool,
+                         response_creator, callback, request_timeout,
+                         idle_timeout) {
+    }
+
+    /// @brief Callback invoked when data is sent over the socket.
+    ///
+    /// @param transaction Pointer to the transaction for which the callback
+    /// is invoked.
+    /// @param ec Error code.
+    /// @param length Length of the data sent.
+    virtual void socketWriteCallback(HttpConnection::TransactionPtr transaction,
+                                     boost::system::error_code ec,
+                                     size_t length) {
+        // Replace the transaction. The socket callback should deal with this
+        // gracefully. It should detect that the output buffer is empty. Then
+        // try to see if the connection is persistent. This check should fail,
+        // because the request hasn't been created/finalized. The exception
+        // thrown upon checking the persistence should be caught and the
+        // connection closed.
+        transaction = HttpConnection::Transaction::create(response_creator_);
+        HttpConnection::socketWriteCallback(transaction, ec, length);
+    }
+};
+
+/// @brief Pointer to the TestHttp[s]Client.
+typedef boost::shared_ptr<BaseTestHttpClient> TestClientPtr;
+
+/// @brief Test fixture class for @ref HttpListener.
+class BaseListenerTest : public ::testing::Test {
+public:
+
+    /// @brief Constructor.
+    ///
+    /// Starts test timer which detects timeouts.
+    BaseListenerTest()
+        : io_service_(new IOService()), factory_(new TestHttpResponseCreatorFactory()),
+          test_timer_(io_service_), run_io_service_timer_(io_service_),
+          clients_(), server_context_() {
+        test_timer_.setup(std::bind(&BaseListenerTest::timeoutHandler,
+                                    this, true),
+                          TEST_TIMEOUT, IntervalTimer::ONE_SHOT);
+    }
+
+    /// @brief Destructor.
+    ///
+    /// Removes active HTTP clients.
+    virtual ~BaseListenerTest() {
+        for (auto const& client : clients_) {
+            client->close();
+        }
+        test_timer_.cancel();
+        io_service_->stopAndPoll();
+    }
+
+    /// brief Create a HTTP test client.
+    virtual TestClientPtr createClient() = 0;
+
+    /// @brief Connect to the endpoint.
+    ///
+    /// This method creates TestHttpClient instance and retains it in the clients_
+    /// list.
+    ///
+    /// @param request String containing the HTTP request to be sent.
+    void startRequest(const std::string& request) {
+        auto client = createClient();
+        clients_.push_back(client);
+        clients_.back()->startRequest(request);
+    }
+
+    /// @brief Callback function invoke upon test timeout.
+    ///
+    /// It stops the IO service and reports test timeout.
+    ///
+    /// @param fail_on_timeout Specifies if test failure should be reported.
+    void timeoutHandler(const bool fail_on_timeout) {
+        if (fail_on_timeout) {
+            ADD_FAILURE() << "Timeout occurred while running the test!";
+        }
+        io_service_->stop();
+    }
+
+    /// @brief Runs IO service with optional timeout.
+    ///
+    /// @param timeout Optional value specifying for how long the io service
+    /// should be ran.
+    void runIOService(long timeout = 0) {
+        io_service_->stop();
+        io_service_->restart();
+
+        if (timeout > 0) {
+            run_io_service_timer_.setup(std::bind(&BaseListenerTest::timeoutHandler,
+                                                  this, false),
+                                        timeout, IntervalTimer::ONE_SHOT);
+        }
+        io_service_->run();
+        io_service_->stopAndPoll(false);
+    }
+
+    /// @brief Returns HTTP OK response expected by unit tests.
+    ///
+    /// @param http_version HTTP version.
+    ///
+    /// @return HTTP OK response expected by unit tests.
+    std::string httpOk(const HttpVersion& http_version) {
+        std::ostringstream s;
+        s << "HTTP/" << http_version.major_ << "." << http_version.minor_ << " 200 OK\r\n"
+            "Content-Length: 33\r\n"
+            "Content-Type: application/json\r\n"
+            "Date: Tue, 19 Dec 2016 18:53:35 GMT\r\n"
+            "\r\n"
+            "{ \"remote-address\": \"127.0.0.1\" }";
+        return (s.str());
+    }
+
+    /// @brief Tests that HTTP request timeout status is returned when the
+    /// server does not receive the entire request.
+    ///
+    /// @param request Partial request for which the parser will be waiting for
+    /// the next chunks of data.
+    /// @param expected_version HTTP version expected in the response.
+    void testRequestTimeout(const std::string& request,
+                            const HttpVersion& expected_version) {
+        // Open the listener with the Request Timeout of 1 sec and post the
+        // partial request.
+        HttpListener listener(io_service_, IOAddress(SERVER_ADDRESS),
+                              SERVER_PORT, server_context_,
+                              factory_, HttpListener::RequestTimeout(1000),
+                              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);
+
+        // Build the reference response.
+        std::ostringstream expected_response;
+        expected_response
+            << "HTTP/" << expected_version.major_ << "." << expected_version.minor_
+            << " 408 Request Timeout\r\n"
+            "Content-Length: 44\r\n"
+            "Content-Type: application/json\r\n"
+            "Date: Tue, 19 Dec 2016 18:53:35 GMT\r\n"
+            "\r\n"
+            "{ \"result\": 408, \"text\": \"Request Timeout\" }";
+
+        // The server should wait for the missing part of the request for 1 second.
+        // The missing part never arrives so the server should respond with the
+        // HTTP Request Timeout status.
+        EXPECT_EQ(expected_response.str(), client->getResponse());
+    }
+
+    /// @brief Tests various cases when unexpected data is passed to the
+    /// socket write handler.
+    ///
+    /// This test uses the custom listener and the test specific derivations of
+    /// the @c HttpConnection class to enforce injection of the unexpected
+    /// data to the socket write callback. The two example applications of
+    /// this test are:
+    /// - injecting greater length value than the output buffer size,
+    /// - replacing the transaction with another transaction.
+    ///
+    /// It is expected that the socket write callback deals gracefully with
+    /// those situations.
+    ///
+    /// @tparam HttpConnectionType Test specific derivation of the
+    /// @c HttpConnection class.
+    template<typename HttpConnectionType>
+    void testWriteBufferIssues() {
+        // 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"
+            "{ }";
+
+        // Use custom listener and the specialized connection object.
+        HttpListenerCustom<HttpConnectionType>
+            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));
+
+        // Injecting unexpected data should not result in an exception.
+        ASSERT_NO_THROW(runIOService());
+
+        ASSERT_EQ(1, clients_.size());
+        auto client = *clients_.begin();
+        ASSERT_TRUE(client);
+        EXPECT_EQ(httpOk(HttpVersion::HTTP_11()), client->getResponse());
+    }
+
+    /// @brief IO service used in the tests.
+    IOServicePtr io_service_;
+
+    /// @brief Pointer to the response creator factory.
+    HttpResponseCreatorFactoryPtr factory_;
+
+    /// @brief Asynchronous timer service to detect timeouts.
+    IntervalTimer test_timer_;
+
+    /// @brief Asynchronous timer for running IO service for a specified amount
+    /// of time.
+    IntervalTimer run_io_service_timer_;
+
+    /// @brief List of client connections.
+    std::list<TestClientPtr> clients_;
+
+    /// @brief Server TLS context.
+    TlsContextPtr server_context_;
+};
+
+}
+}
+}
+#endif // HTTP_SERVER_TEST_H
index 708eb50791572281edf528f045d1a230568cdd2d..3618fca2dbedb118a9352b6888d452171bfc6d28 100644 (file)
@@ -44,381 +44,18 @@ using namespace isc::http::test;
 using namespace isc::util;
 namespace ph = std::placeholders;
 
-namespace {
-
-/// @brief Implementation of the HTTP listener used in tests.
-///
-/// This implementation replaces the @c HttpConnection type with a custom
-/// implementation.
-///
-/// @tparam HttpConnectionType Type of the connection object to be used by
-/// the listener implementation.
-template<typename HttpConnectionType>
-class HttpListenerImplCustom : public HttpListenerImpl {
-public:
-
-    HttpListenerImplCustom(const IOServicePtr& io_service,
-                           const IOAddress& server_address,
-                           const unsigned short server_port,
-                           const TlsContextPtr& tls_context,
-                           const HttpResponseCreatorFactoryPtr& creator_factory,
-                           const long request_timeout,
-                           const long idle_timeout)
-        : HttpListenerImpl(io_service, server_address, server_port,
-                           tls_context, creator_factory, request_timeout,
-                           idle_timeout) {
-    }
-
-protected:
-
-    /// @brief Creates an instance of the @c HttpConnection.
-    ///
-    /// This method is virtual so as it can be overridden when customized
-    /// connections are to be used, e.g. in case of unit testing.
-    ///
-    /// @param response_creator Pointer to the response creator object used to
-    /// create HTTP response from the HTTP request received.
-    /// @param callback Callback invoked when new connection is accepted.
-    ///
-    /// @return Pointer to the created connection.
-    virtual HttpConnectionPtr createConnection(const HttpResponseCreatorPtr& response_creator,
-                                               const HttpAcceptorCallback& callback) {
-        HttpConnectionPtr
-            conn(new HttpConnectionType(io_service_, acceptor_,
-                                        tls_context_, connections_,
-                                        response_creator, callback,
-                                        request_timeout_, idle_timeout_));
-        return (conn);
-    }
-};
-
-/// @brief Derivation of the @c HttpListener used in tests.
-///
-/// This class replaces the default implementation instance with the
-/// @c HttpListenerImplCustom using the customized connection type.
-///
-/// @tparam HttpConnectionType Type of the connection object to be used by
-/// the listener implementation.
-template<typename HttpConnectionType>
-class HttpListenerCustom : public HttpListener {
-public:
-
-    /// @brief Constructor.
-    ///
-    /// @param io_service IO service to be used by the listener.
-    /// @param server_address Address on which the HTTP service should run.
-    /// @param server_port Port number on which the HTTP service should run.
-    /// @param tls_context TLS context.
-    /// @param creator_factory Pointer to the caller-defined
-    /// @ref HttpResponseCreatorFactory derivation which should be used to
-    /// create @ref HttpResponseCreator instances.
-    /// @param request_timeout Timeout after which the HTTP Request Timeout
-    /// is generated.
-    /// @param idle_timeout Timeout after which an idle persistent HTTP
-    /// connection is closed by the server.
-    ///
-    /// @throw HttpListenerError when any of the specified parameters is
-    /// invalid.
-    HttpListenerCustom(const IOServicePtr& io_service,
-                       const IOAddress& server_address,
-                       const unsigned short server_port,
-                       const TlsContextPtr& tls_context,
-                       const HttpResponseCreatorFactoryPtr& creator_factory,
-                       const HttpListener::RequestTimeout& request_timeout,
-                       const HttpListener::IdleTimeout& idle_timeout)
-        : HttpListener(io_service, server_address, server_port,
-                       tls_context, creator_factory,
-                       request_timeout, idle_timeout) {
-        // Replace the default implementation with the customized version
-        // using the custom derivation of the HttpConnection.
-        impl_.reset(new HttpListenerImplCustom<HttpConnectionType>
-                    (io_service, server_address, server_port,
-                     tls_context, creator_factory, request_timeout.value_,
-                     idle_timeout.value_));
-    }
-};
-
-/// @brief Implementation of the @c HttpConnection which injects greater
-/// length value than the buffer size into the write socket callback.
-class HttpConnectionLongWriteBuffer : public HttpConnection {
-public:
-
-    /// @brief Constructor.
-    ///
-    /// @param io_service IO service to be used by the connection.
-    /// @param acceptor Pointer to the TCP acceptor object used to listen for
-    /// new HTTP connections.
-    /// @param tls_context TLS context.
-    /// @param connection_pool Connection pool in which this connection is
-    /// stored.
-    /// @param response_creator Pointer to the response creator object used to
-    /// create HTTP response from the HTTP request received.
-    /// @param callback Callback invoked when new connection is accepted.
-    /// @param request_timeout Configured timeout for a HTTP request.
-    /// @param idle_timeout Timeout after which persistent HTTP connection is
-    /// closed by the server.
-    HttpConnectionLongWriteBuffer(const IOServicePtr& io_service,
-                                  const HttpAcceptorPtr& acceptor,
-                                  const TlsContextPtr& tls_context,
-                                  HttpConnectionPool& connection_pool,
-                                  const HttpResponseCreatorPtr& response_creator,
-                                  const HttpAcceptorCallback& callback,
-                                  const long request_timeout,
-                                  const long idle_timeout)
-        : HttpConnection(io_service, acceptor, tls_context, connection_pool,
-                         response_creator, callback, request_timeout,
-                         idle_timeout) {
-    }
-
-    /// @brief Callback invoked when data is sent over the socket.
-    ///
-    /// @param transaction Pointer to the transaction for which the callback
-    /// is invoked.
-    /// @param ec Error code.
-    /// @param length Length of the data sent.
-    virtual void socketWriteCallback(HttpConnection::TransactionPtr transaction,
-                                     boost::system::error_code ec,
-                                     size_t length) {
-        // Pass greater length of the data written. The callback should deal
-        // with this and adjust the data length.
-        HttpConnection::socketWriteCallback(transaction, ec, length + 1);
-    }
-};
-
-/// @brief Implementation of the @c HttpConnection which replaces
-/// transaction instance prior to calling write socket callback.
-class HttpConnectionTransactionChange : public HttpConnection {
-public:
-
-    /// @brief Constructor.
-    ///
-    /// @param io_service IO service to be used by the connection.
-    /// @param acceptor Pointer to the TCP acceptor object used to listen for
-    /// new HTTP connections.
-    /// @param context TLS tls_context.
-    /// @param connection_pool Connection pool in which this connection is
-    /// stored.
-    /// @param response_creator Pointer to the response creator object used to
-    /// create HTTP response from the HTTP request received.
-    /// @param callback Callback invoked when new connection is accepted.
-    /// @param request_timeout Configured timeout for a HTTP request.
-    /// @param idle_timeout Timeout after which persistent HTTP connection is
-    /// closed by the server.
-    HttpConnectionTransactionChange(const IOServicePtr& io_service,
-                                    const HttpAcceptorPtr& acceptor,
-                                    const TlsContextPtr& tls_context,
-                                    HttpConnectionPool& connection_pool,
-                                    const HttpResponseCreatorPtr& response_creator,
-                                    const HttpAcceptorCallback& callback,
-                                    const long request_timeout,
-                                    const long idle_timeout)
-        : HttpConnection(io_service, acceptor, tls_context, connection_pool,
-                         response_creator, callback, request_timeout,
-                         idle_timeout) {
-    }
+#include <http/tests/http_server_test.h>
 
-    /// @brief Callback invoked when data is sent over the socket.
-    ///
-    /// @param transaction Pointer to the transaction for which the callback
-    /// is invoked.
-    /// @param ec Error code.
-    /// @param length Length of the data sent.
-    virtual void socketWriteCallback(HttpConnection::TransactionPtr transaction,
-                                     boost::system::error_code ec,
-                                     size_t length) {
-        // Replace the transaction. The socket callback should deal with this
-        // gracefully. It should detect that the output buffer is empty. Then
-        // try to see if the connection is persistent. This check should fail,
-        // because the request hasn't been created/finalized. The exception
-        // thrown upon checking the persistence should be caught and the
-        // connection closed.
-        transaction = HttpConnection::Transaction::create(response_creator_);
-        HttpConnection::socketWriteCallback(transaction, ec, length);
-    }
-};
-
-/// @brief Pointer to the TestHttpClient.
-typedef boost::shared_ptr<TestHttpClient> TestHttpClientPtr;
+namespace {
 
 /// @brief Test fixture class for @ref HttpListener.
-class HttpListenerTest : public ::testing::Test {
+class HttpListenerTest : public BaseListenerTest {
 public:
 
-    /// @brief Constructor.
-    ///
-    /// Starts test timer which detects timeouts.
-    HttpListenerTest()
-        : io_service_(new IOService()), factory_(new TestHttpResponseCreatorFactory()),
-          test_timer_(io_service_), run_io_service_timer_(io_service_), clients_() {
-        test_timer_.setup(std::bind(&HttpListenerTest::timeoutHandler, this, true),
-                          TEST_TIMEOUT, IntervalTimer::ONE_SHOT);
-    }
-
-    /// @brief Destructor.
-    ///
-    /// Removes active HTTP clients.
-    virtual ~HttpListenerTest() {
-        for (auto const& client : clients_) {
-            client->close();
-        }
-        test_timer_.cancel();
-        io_service_->stopAndPoll();
-    }
-
-    /// @brief Connect to the endpoint.
-    ///
-    /// This method creates TestHttpClient instance and retains it in the clients_
-    /// list.
-    ///
-    /// @param request String containing the HTTP request to be sent.
-    void startRequest(const std::string& request) {
-        TestHttpClientPtr client(new TestHttpClient(io_service_));
-        clients_.push_back(client);
-        clients_.back()->startRequest(request);
-    }
-
-    /// @brief Callback function invoke upon test timeout.
-    ///
-    /// It stops the IO service and reports test timeout.
-    ///
-    /// @param fail_on_timeout Specifies if test failure should be reported.
-    void timeoutHandler(const bool fail_on_timeout) {
-        if (fail_on_timeout) {
-            ADD_FAILURE() << "Timeout occurred while running the test!";
-        }
-        io_service_->stop();
-    }
-
-    /// @brief Runs IO service with optional timeout.
-    ///
-    /// @param timeout Optional value specifying for how long the io service
-    /// should be ran.
-    void runIOService(long timeout = 0) {
-        io_service_->stop();
-        io_service_->restart();
-
-        if (timeout > 0) {
-            run_io_service_timer_.setup(std::bind(&HttpListenerTest::timeoutHandler,
-                                                  this, false),
-                                        timeout, IntervalTimer::ONE_SHOT);
-        }
-        io_service_->run();
-        io_service_->stopAndPoll(false);
+    /// brief Create a HTTP test client.
+    virtual TestClientPtr createClient() override {
+        return (TestHttpClientPtr(new TestHttpClient(io_service_)));
     }
-
-    /// @brief Returns HTTP OK response expected by unit tests.
-    ///
-    /// @param http_version HTTP version.
-    ///
-    /// @return HTTP OK response expected by unit tests.
-    std::string httpOk(const HttpVersion& http_version) {
-        std::ostringstream s;
-        s << "HTTP/" << http_version.major_ << "." << http_version.minor_ << " 200 OK\r\n"
-            "Content-Length: 33\r\n"
-            "Content-Type: application/json\r\n"
-            "Date: Tue, 19 Dec 2016 18:53:35 GMT\r\n"
-            "\r\n"
-            "{ \"remote-address\": \"127.0.0.1\" }";
-        return (s.str());
-    }
-
-    /// @brief Tests that HTTP request timeout status is returned when the
-    /// server does not receive the entire request.
-    ///
-    /// @param request Partial request for which the parser will be waiting for
-    /// the next chunks of data.
-    /// @param expected_version HTTP version expected in the response.
-    void testRequestTimeout(const std::string& request,
-                            const HttpVersion& expected_version) {
-        // Open the listener with the Request Timeout of 1 sec and post the
-        // partial request.
-        HttpListener listener(io_service_, IOAddress(SERVER_ADDRESS),
-                              SERVER_PORT, TlsContextPtr(),
-                              factory_, HttpListener::RequestTimeout(1000),
-                              HttpListener::IdleTimeout(IDLE_TIMEOUT));
-        ASSERT_NO_THROW(listener.start());
-        ASSERT_NO_THROW(startRequest(request));
-        ASSERT_NO_THROW(runIOService());
-        ASSERT_EQ(1, clients_.size());
-        TestHttpClientPtr client = *clients_.begin();
-        ASSERT_TRUE(client);
-
-        // Build the reference response.
-        std::ostringstream expected_response;
-        expected_response
-            << "HTTP/" << expected_version.major_ << "." << expected_version.minor_
-            << " 408 Request Timeout\r\n"
-            "Content-Length: 44\r\n"
-            "Content-Type: application/json\r\n"
-            "Date: Tue, 19 Dec 2016 18:53:35 GMT\r\n"
-            "\r\n"
-            "{ \"result\": 408, \"text\": \"Request Timeout\" }";
-
-        // The server should wait for the missing part of the request for 1 second.
-        // The missing part never arrives so the server should respond with the
-        // HTTP Request Timeout status.
-        EXPECT_EQ(expected_response.str(), client->getResponse());
-    }
-
-    /// @brief Tests various cases when unexpected data is passed to the
-    /// socket write handler.
-    ///
-    /// This test uses the custom listener and the test specific derivations of
-    /// the @c HttpConnection class to enforce injection of the unexpected
-    /// data to the socket write callback. The two example applications of
-    /// this test are:
-    /// - injecting greater length value than the output buffer size,
-    /// - replacing the transaction with another transaction.
-    ///
-    /// It is expected that the socket write callback deals gracefully with
-    /// those situations.
-    ///
-    /// @tparam HttpConnectionType Test specific derivation of the
-    /// @c HttpConnection class.
-    template<typename HttpConnectionType>
-    void testWriteBufferIssues() {
-        // 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"
-            "{ }";
-
-        // Use custom listener and the specialized connection object.
-        HttpListenerCustom<HttpConnectionType>
-            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));
-
-        // Injecting unexpected data should not result in an exception.
-        ASSERT_NO_THROW(runIOService());
-
-        ASSERT_EQ(1, clients_.size());
-        TestHttpClientPtr client = *clients_.begin();
-        ASSERT_TRUE(client);
-        EXPECT_EQ(httpOk(HttpVersion::HTTP_11()), client->getResponse());
-    }
-
-    /// @brief IO service used in the tests.
-    IOServicePtr io_service_;
-
-    /// @brief Pointer to the response creator factory.
-    HttpResponseCreatorFactoryPtr factory_;
-
-    /// @brief Asynchronous timer service to detect timeouts.
-    IntervalTimer test_timer_;
-
-    /// @brief Asynchronous timer for running IO service for a specified amount
-    /// of time.
-    IntervalTimer run_io_service_timer_;
-
-    /// @brief List of client connections.
-    std::list<TestHttpClientPtr> clients_;
 };
 
 // This test verifies that HTTP connection can be established and used to
@@ -439,7 +76,7 @@ TEST_F(HttpListenerTest, listen) {
     ASSERT_NO_THROW(startRequest(request));
     ASSERT_NO_THROW(runIOService());
     ASSERT_EQ(1, clients_.size());
-    TestHttpClientPtr client = *clients_.begin();
+    auto client = *clients_.begin();
     ASSERT_TRUE(client);
     EXPECT_EQ(httpOk(HttpVersion::HTTP_11()), client->getResponse());
 
@@ -471,7 +108,7 @@ TEST_F(HttpListenerTest, keepAlive) {
     ASSERT_NO_THROW(startRequest(request));
     ASSERT_NO_THROW(runIOService());
     ASSERT_EQ(1, clients_.size());
-    TestHttpClientPtr client = *clients_.begin();
+    auto client = *clients_.begin();
     ASSERT_TRUE(client);
     EXPECT_EQ(httpOk(HttpVersion::HTTP_10()), client->getResponse());
 
@@ -520,7 +157,7 @@ TEST_F(HttpListenerTest, persistentConnection) {
     ASSERT_NO_THROW(startRequest(request));
     ASSERT_NO_THROW(runIOService());
     ASSERT_EQ(1, clients_.size());
-    TestHttpClientPtr client = *clients_.begin();
+    auto client = *clients_.begin();
     ASSERT_TRUE(client);
     EXPECT_EQ(httpOk(HttpVersion::HTTP_11()), client->getResponse());
 
@@ -572,7 +209,7 @@ TEST_F(HttpListenerTest, keepAliveTimeout) {
     ASSERT_NO_THROW(startRequest(request));
     ASSERT_NO_THROW(runIOService());
     ASSERT_EQ(1, clients_.size());
-    TestHttpClientPtr client = *clients_.begin();
+    auto client = *clients_.begin();
     ASSERT_TRUE(client);
     EXPECT_EQ(httpOk(HttpVersion::HTTP_10()), client->getResponse());
 
@@ -629,7 +266,7 @@ TEST_F(HttpListenerTest, persistentConnectionTimeout) {
     ASSERT_NO_THROW(startRequest(request));
     ASSERT_NO_THROW(runIOService());
     ASSERT_EQ(1, clients_.size());
-    TestHttpClientPtr client = *clients_.begin();
+    auto client = *clients_.begin();
     ASSERT_TRUE(client);
     EXPECT_EQ(httpOk(HttpVersion::HTTP_11()), client->getResponse());
 
@@ -685,7 +322,7 @@ TEST_F(HttpListenerTest, persistentConnectionBadBody) {
     ASSERT_NO_THROW(startRequest(request));
     ASSERT_NO_THROW(runIOService());
     ASSERT_EQ(1, clients_.size());
-    TestHttpClientPtr client = *clients_.begin();
+    auto client = *clients_.begin();
     ASSERT_TRUE(client);
     EXPECT_EQ("HTTP/1.1 400 Bad Request\r\n"
               "Content-Length: 40\r\n"
@@ -744,7 +381,7 @@ TEST_F(HttpListenerTest, badRequest) {
     ASSERT_NO_THROW(startRequest(request));
     ASSERT_NO_THROW(runIOService());
     ASSERT_EQ(1, clients_.size());
-    TestHttpClientPtr client = *clients_.begin();
+    auto client = *clients_.begin();
     ASSERT_TRUE(client);
     EXPECT_EQ("HTTP/1.1 400 Bad Request\r\n"
               "Content-Length: 40\r\n"
index b11e0d9f7150cd0cf30c5ca3fcaa95a215a019c1..f281d83c8c759e76b6be104115c7f628d1e04429 100644 (file)
@@ -46,388 +46,28 @@ using namespace isc::http;
 using namespace isc::http::test;
 using namespace isc::util;
 
-namespace {
-
-/// @brief Implementation of the HTTP listener used in tests.
-///
-/// This implementation replaces the @c HttpConnection type with a custom
-/// implementation.
-///
-/// @tparam HttpConnectionType Type of the connection object to be used by
-/// the listener implementation.
-template<typename HttpConnectionType>
-class HttpListenerImplCustom : public HttpListenerImpl {
-public:
-
-    HttpListenerImplCustom(const IOServicePtr& io_service,
-                           const IOAddress& server_address,
-                           const unsigned short server_port,
-                           const TlsContextPtr& tls_context,
-                           const HttpResponseCreatorFactoryPtr& creator_factory,
-                           const long request_timeout,
-                           const long idle_timeout)
-        : HttpListenerImpl(io_service, server_address, server_port,
-                           tls_context, creator_factory, request_timeout,
-                           idle_timeout) {
-    }
-
-protected:
-
-    /// @brief Creates an instance of the @c HttpConnection.
-    ///
-    /// This method is virtual so as it can be overridden when customized
-    /// connections are to be used, e.g. in case of unit testing.
-    ///
-    /// @param response_creator Pointer to the response creator object used to
-    /// create HTTP response from the HTTP request received.
-    /// @param callback Callback invoked when new connection is accepted.
-    ///
-    /// @return Pointer to the created connection.
-    virtual HttpConnectionPtr createConnection(const HttpResponseCreatorPtr& response_creator,
-                                               const HttpAcceptorCallback& callback) {
-        TlsContextPtr tls_context;
-        configClient(tls_context);
-        HttpConnectionPtr
-            conn(new HttpConnectionType(io_service_, acceptor_,
-                                        tls_context_, connections_,
-                                        response_creator, callback,
-                                        request_timeout_, idle_timeout_));
-        return (conn);
-    }
-};
-
-/// @brief Derivation of the @c HttpListener used in tests.
-///
-/// This class replaces the default implementation instance with the
-/// @c HttpListenerImplCustom using the customized connection type.
-///
-/// @tparam HttpConnectionType Type of the connection object to be used by
-/// the listener implementation.
-template<typename HttpConnectionType>
-class HttpListenerCustom : public HttpListener {
-public:
-
-    /// @brief Constructor.
-    ///
-    /// @param io_service IO service to be used by the listener.
-    /// @param server_address Address on which the HTTP service should run.
-    /// @param server_port Port number on which the HTTP service should run.
-    /// @param tls_context TLS context.
-    /// @param creator_factory Pointer to the caller-defined
-    /// @ref HttpResponseCreatorFactory derivation which should be used to
-    /// create @ref HttpResponseCreator instances.
-    /// @param request_timeout Timeout after which the HTTP Request Timeout
-    /// is generated.
-    /// @param idle_timeout Timeout after which an idle persistent HTTP
-    /// connection is closed by the server.
-    ///
-    /// @throw HttpListenerError when any of the specified parameters is
-    /// invalid.
-    HttpListenerCustom(const IOServicePtr& io_service,
-                       const IOAddress& server_address,
-                       const unsigned short server_port,
-                       const TlsContextPtr& tls_context,
-                       const HttpResponseCreatorFactoryPtr& creator_factory,
-                       const HttpListener::RequestTimeout& request_timeout,
-                       const HttpListener::IdleTimeout& idle_timeout)
-        : HttpListener(io_service, server_address, server_port,
-                       tls_context, creator_factory,
-                       request_timeout, idle_timeout) {
-        // Replace the default implementation with the customized version
-        // using the custom derivation of the HttpConnection.
-        impl_.reset(new HttpListenerImplCustom<HttpConnectionType>
-                    (io_service, server_address, server_port,
-                     tls_context, creator_factory, request_timeout.value_,
-                     idle_timeout.value_));
-    }
-};
-
-/// @brief Implementation of the @c HttpConnection which injects greater
-/// length value than the buffer size into the write socket callback.
-class HttpConnectionLongWriteBuffer : public HttpConnection {
-public:
-
-    /// @brief Constructor.
-    ///
-    /// @param io_service IO service to be used by the connection.
-    /// @param acceptor Pointer to the TCP acceptor object used to listen for
-    /// new HTTP connections.
-    /// @param tls_context TLS context.
-    /// @param connection_pool Connection pool in which this connection is
-    /// stored.
-    /// @param response_creator Pointer to the response creator object used to
-    /// create HTTP response from the HTTP request received.
-    /// @param callback Callback invoked when new connection is accepted.
-    /// @param request_timeout Configured timeout for a HTTP request.
-    /// @param idle_timeout Timeout after which persistent HTTP connection is
-    /// closed by the server.
-    HttpConnectionLongWriteBuffer(const IOServicePtr& io_service,
-                                  const HttpAcceptorPtr& acceptor,
-                                  const TlsContextPtr& tls_context,
-                                  HttpConnectionPool& connection_pool,
-                                  const HttpResponseCreatorPtr& response_creator,
-                                  const HttpAcceptorCallback& callback,
-                                  const long request_timeout,
-                                  const long idle_timeout)
-        : HttpConnection(io_service, acceptor, tls_context, connection_pool,
-                         response_creator, callback, request_timeout,
-                         idle_timeout) {
-    }
-
-    /// @brief Callback invoked when data is sent over the socket.
-    ///
-    /// @param transaction Pointer to the transaction for which the callback
-    /// is invoked.
-    /// @param ec Error code.
-    /// @param length Length of the data sent.
-    virtual void socketWriteCallback(HttpConnection::TransactionPtr transaction,
-                                     boost::system::error_code ec,
-                                     size_t length) {
-        // Pass greater length of the data written. The callback should deal
-        // with this and adjust the data length.
-        HttpConnection::socketWriteCallback(transaction, ec, length + 1);
-    }
-};
-
-/// @brief Implementation of the @c HttpConnection which replaces
-/// transaction instance prior to calling write socket callback.
-class HttpConnectionTransactionChange : public HttpConnection {
-public:
-
-    /// @brief Constructor.
-    ///
-    /// @param io_service IO service to be used by the connection.
-    /// @param acceptor Pointer to the TCP acceptor object used to listen for
-    /// new HTTP connections.
-    /// @param tls_context TLS context.
-    /// @param connection_pool Connection pool in which this connection is
-    /// stored.
-    /// @param response_creator Pointer to the response creator object used to
-    /// create HTTP response from the HTTP request received.
-    /// @param callback Callback invoked when new connection is accepted.
-    /// @param request_timeout Configured timeout for a HTTP request.
-    /// @param idle_timeout Timeout after which persistent HTTP connection is
-    /// closed by the server.
-    HttpConnectionTransactionChange(const IOServicePtr& io_service,
-                                    const HttpAcceptorPtr& acceptor,
-                                    const TlsContextPtr& tls_context,
-                                    HttpConnectionPool& connection_pool,
-                                    const HttpResponseCreatorPtr& response_creator,
-                                    const HttpAcceptorCallback& callback,
-                                    const long request_timeout,
-                                    const long idle_timeout)
-        : HttpConnection(io_service, acceptor, tls_context, connection_pool,
-                         response_creator, callback, request_timeout,
-                         idle_timeout) {
-    }
+#include <http/tests/http_server_test.h>
 
-    /// @brief Callback invoked when data is sent over the socket.
-    ///
-    /// @param transaction Pointer to the transaction for which the callback
-    /// is invoked.
-    /// @param ec Error code.
-    /// @param length Length of the data sent.
-    virtual void socketWriteCallback(HttpConnection::TransactionPtr transaction,
-                                     boost::system::error_code ec,
-                                     size_t length) {
-        // Replace the transaction. The socket callback should deal with this
-        // gracefully. It should detect that the output buffer is empty. Then
-        // try to see if the connection is persistent. This check should fail,
-        // because the request hasn't been created/finalized. The exception
-        // thrown upon checking the persistence should be caught and the
-        // connection closed.
-        transaction = HttpConnection::Transaction::create(response_creator_);
-        HttpConnection::socketWriteCallback(transaction, ec, length);
-    }
-};
+namespace {
 
 /// @brief Test fixture class for @ref HttpListener.
-class HttpsListenerTest : public ::testing::Test {
+class HttpsListenerTest : public BaseListenerTest {
 public:
 
     /// @brief Constructor.
     ///
     /// Starts test timer which detects timeouts.
-    HttpsListenerTest()
-        : io_service_(new IOService()), factory_(new TestHttpResponseCreatorFactory()),
-          test_timer_(io_service_), run_io_service_timer_(io_service_),
-          clients_(), server_context_(), client_context_() {
+    HttpsListenerTest() : client_context_() {
         configServer(server_context_);
         configClient(client_context_);
-        test_timer_.setup(std::bind(&HttpsListenerTest::timeoutHandler, this, true),
-                          TEST_TIMEOUT, IntervalTimer::ONE_SHOT);
-    }
-
-    /// @brief Destructor.
-    ///
-    /// Removes active HTTP clients.
-    virtual ~HttpsListenerTest() {
-        for (auto const& client : clients_) {
-            client->close();
-        }
-        test_timer_.cancel();
-        io_service_->stopAndPoll();
-    }
-
-    /// @brief Connect to the endpoint.
-    ///
-    /// This method creates TestHttpsClient instance and retains it in the clients_
-    /// list.
-    ///
-    /// @param request String containing the HTTP request to be sent.
-    void startRequest(const std::string& request) {
-        TestHttpsClientPtr client(new TestHttpsClient(io_service_,
-                                                      client_context_));
-        clients_.push_back(client);
-        clients_.back()->startRequest(request);
     }
 
-    /// @brief Callback function invoke upon test timeout.
-    ///
-    /// It stops the IO service and reports test timeout.
-    ///
-    /// @param fail_on_timeout Specifies if test failure should be reported.
-    void timeoutHandler(const bool fail_on_timeout) {
-        if (fail_on_timeout) {
-            ADD_FAILURE() << "Timeout occurred while running the test!";
-        }
-        io_service_->stop();
+    /// brief Create a HTTPS test client.
+    virtual TestClientPtr createClient() override {
+        return (TestHttpsClientPtr(new TestHttpsClient(io_service_,
+                                                       client_context_)));
     }
 
-    /// @brief Runs IO service with optional timeout.
-    ///
-    /// @param timeout Optional value specifying for how long the io service
-    /// should be ran.
-    void runIOService(long timeout = 0) {
-        io_service_->stop();
-        io_service_->restart();
-
-        if (timeout > 0) {
-            run_io_service_timer_.setup(std::bind(&HttpsListenerTest::timeoutHandler,
-                                                  this, false),
-                                        timeout, IntervalTimer::ONE_SHOT);
-        }
-        io_service_->run();
-        io_service_->stopAndPoll(false);
-    }
-
-    /// @brief Returns HTTP OK response expected by unit tests.
-    ///
-    /// @param http_version HTTP version.
-    ///
-    /// @return HTTP OK response expected by unit tests.
-    std::string httpOk(const HttpVersion& http_version) {
-        std::ostringstream s;
-        s << "HTTP/" << http_version.major_ << "." << http_version.minor_ << " 200 OK\r\n"
-            "Content-Length: 33\r\n"
-            "Content-Type: application/json\r\n"
-            "Date: Tue, 19 Dec 2016 18:53:35 GMT\r\n"
-            "\r\n"
-            "{ \"remote-address\": \"127.0.0.1\" }";
-        return (s.str());
-    }
-
-    /// @brief Tests that HTTP request timeout status is returned when the
-    /// server does not receive the entire request.
-    ///
-    /// @param request Partial request for which the parser will be waiting for
-    /// the next chunks of data.
-    /// @param expected_version HTTP version expected in the response.
-    void testRequestTimeout(const std::string& request,
-                            const HttpVersion& expected_version) {
-        // Open the listener with the Request Timeout of 1 sec and post the
-        // partial request.
-        HttpListener listener(io_service_, IOAddress(SERVER_ADDRESS),
-                              SERVER_PORT, server_context_,
-                              factory_, HttpListener::RequestTimeout(1000),
-                              HttpListener::IdleTimeout(IDLE_TIMEOUT));
-        ASSERT_NO_THROW(listener.start());
-        ASSERT_NO_THROW(startRequest(request));
-        ASSERT_NO_THROW(runIOService());
-        ASSERT_EQ(1, clients_.size());
-        TestHttpsClientPtr client = *clients_.begin();
-        ASSERT_TRUE(client);
-
-        // Build the reference response.
-        std::ostringstream expected_response;
-        expected_response
-            << "HTTP/" << expected_version.major_ << "." << expected_version.minor_
-            << " 408 Request Timeout\r\n"
-            "Content-Length: 44\r\n"
-            "Content-Type: application/json\r\n"
-            "Date: Tue, 19 Dec 2016 18:53:35 GMT\r\n"
-            "\r\n"
-            "{ \"result\": 408, \"text\": \"Request Timeout\" }";
-
-        // The server should wait for the missing part of the request for 1 second.
-        // The missing part never arrives so the server should respond with the
-        // HTTP Request Timeout status.
-        EXPECT_EQ(expected_response.str(), client->getResponse());
-    }
-
-    /// @brief Tests various cases when unexpected data is passed to the
-    /// socket write handler.
-    ///
-    /// This test uses the custom listener and the test specific derivations of
-    /// the @c HttpConnection class to enforce injection of the unexpected
-    /// data to the socket write callback. The two example applications of
-    /// this test are:
-    /// - injecting greater length value than the output buffer size,
-    /// - replacing the transaction with another transaction.
-    ///
-    /// It is expected that the socket write callback deals gracefully with
-    /// those situations.
-    ///
-    /// @tparam HttpConnectionType Test specific derivation of the
-    /// @c HttpConnection class.
-    template<typename HttpConnectionType>
-    void testWriteBufferIssues() {
-        // 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"
-            "{ }";
-
-        // Use custom listener and the specialized connection object.
-        HttpListenerCustom<HttpConnectionType>
-            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));
-
-        // Injecting unexpected data should not result in an exception.
-        ASSERT_NO_THROW(runIOService());
-
-        ASSERT_EQ(1, clients_.size());
-        TestHttpsClientPtr client = *clients_.begin();
-        ASSERT_TRUE(client);
-        EXPECT_EQ(httpOk(HttpVersion::HTTP_11()), client->getResponse());
-    }
-
-    /// @brief IO service used in the tests.
-    IOServicePtr io_service_;
-
-    /// @brief Pointer to the response creator factory.
-    HttpResponseCreatorFactoryPtr factory_;
-
-    /// @brief Asynchronous timer service to detect timeouts.
-    IntervalTimer test_timer_;
-
-    /// @brief Asynchronous timer for running IO service for a specified amount
-    /// of time.
-    IntervalTimer run_io_service_timer_;
-
-    /// @brief List of client connections.
-    std::list<TestHttpsClientPtr> clients_;
-
-    /// @brief Server TLS context.
-    TlsContextPtr server_context_;
-
     /// @brief Client TLS context.
     TlsContextPtr client_context_;
 };
@@ -450,7 +90,7 @@ TEST_F(HttpsListenerTest, listen) {
     ASSERT_NO_THROW(startRequest(request));
     ASSERT_NO_THROW(runIOService());
     ASSERT_EQ(1, clients_.size());
-    TestHttpsClientPtr client = *clients_.begin();
+    auto client = *clients_.begin();
     ASSERT_TRUE(client);
     EXPECT_EQ(httpOk(HttpVersion::HTTP_11()), client->getResponse());
 
@@ -482,7 +122,7 @@ TEST_F(HttpsListenerTest, keepAlive) {
     ASSERT_NO_THROW(startRequest(request));
     ASSERT_NO_THROW(runIOService());
     ASSERT_EQ(1, clients_.size());
-    TestHttpsClientPtr client = *clients_.begin();
+    auto client = *clients_.begin();
     ASSERT_TRUE(client);
     EXPECT_EQ(httpOk(HttpVersion::HTTP_10()), client->getResponse());
 
@@ -531,7 +171,7 @@ TEST_F(HttpsListenerTest, persistentConnection) {
     ASSERT_NO_THROW(startRequest(request));
     ASSERT_NO_THROW(runIOService());
     ASSERT_EQ(1, clients_.size());
-    TestHttpsClientPtr client = *clients_.begin();
+    auto client = *clients_.begin();
     ASSERT_TRUE(client);
     EXPECT_EQ(httpOk(HttpVersion::HTTP_11()), client->getResponse());
 
@@ -583,7 +223,7 @@ TEST_F(HttpsListenerTest, keepAliveTimeout) {
     ASSERT_NO_THROW(startRequest(request));
     ASSERT_NO_THROW(runIOService());
     ASSERT_EQ(1, clients_.size());
-    TestHttpsClientPtr client = *clients_.begin();
+    auto client = *clients_.begin();
     ASSERT_TRUE(client);
     EXPECT_EQ(httpOk(HttpVersion::HTTP_10()), client->getResponse());
 
@@ -640,7 +280,7 @@ TEST_F(HttpsListenerTest, persistentConnectionTimeout) {
     ASSERT_NO_THROW(startRequest(request));
     ASSERT_NO_THROW(runIOService());
     ASSERT_EQ(1, clients_.size());
-    TestHttpsClientPtr client = *clients_.begin();
+    auto client = *clients_.begin();
     ASSERT_TRUE(client);
     EXPECT_EQ(httpOk(HttpVersion::HTTP_11()), client->getResponse());
 
@@ -696,7 +336,7 @@ TEST_F(HttpsListenerTest, persistentConnectionBadBody) {
     ASSERT_NO_THROW(startRequest(request));
     ASSERT_NO_THROW(runIOService());
     ASSERT_EQ(1, clients_.size());
-    TestHttpsClientPtr client = *clients_.begin();
+    auto client = *clients_.begin();
     ASSERT_TRUE(client);
     EXPECT_EQ("HTTP/1.1 400 Bad Request\r\n"
               "Content-Length: 40\r\n"
@@ -755,7 +395,7 @@ TEST_F(HttpsListenerTest, badRequest) {
     ASSERT_NO_THROW(startRequest(request));
     ASSERT_NO_THROW(runIOService());
     ASSERT_EQ(1, clients_.size());
-    TestHttpsClientPtr client = *clients_.begin();
+    auto client = *clients_.begin();
     ASSERT_TRUE(client);
     EXPECT_EQ("HTTP/1.1 400 Bad Request\r\n"
               "Content-Length: 40\r\n"