| // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| #ifndef NET_TEST_EMBEDDED_TEST_SERVER_EMBEDDED_TEST_SERVER_H_ | |
| #define NET_TEST_EMBEDDED_TEST_SERVER_EMBEDDED_TEST_SERVER_H_ | |
| #include <map> | |
| #include <memory> | |
| #include <string> | |
| #include <vector> | |
| #include "base/callback.h" | |
| #include "base/compiler_specific.h" | |
| #include "base/files/file_path.h" | |
| #include "base/macros.h" | |
| #include "base/memory/ref_counted.h" | |
| #include "base/memory/weak_ptr.h" | |
| #include "base/threading/thread.h" | |
| #include "base/threading/thread_checker.h" | |
| #include "net/base/address_list.h" | |
| #include "net/base/host_port_pair.h" | |
| #include "net/base/ip_endpoint.h" | |
| #include "net/cert/x509_certificate.h" | |
| #include "net/socket/ssl_server_socket.h" | |
| #include "net/socket/stream_socket.h" | |
| #include "net/socket/tcp_server_socket.h" | |
| #include "net/ssl/ssl_server_config.h" | |
| #include "starboard/types.h" | |
| #include "url/gurl.h" | |
| namespace net { | |
| class StreamSocket; | |
| class TCPServerSocket; | |
| namespace test_server { | |
| class EmbeddedTestServerConnectionListener; | |
| class HttpConnection; | |
| class HttpResponse; | |
| struct HttpRequest; | |
| // Class providing an HTTP server for testing purpose. This is a basic server | |
| // providing only an essential subset of HTTP/1.1 protocol. Especially, | |
| // it assumes that the request syntax is correct. It *does not* support | |
| // a Chunked Transfer Encoding. | |
| // | |
| // The common use case for unit tests is below: | |
| // | |
| // void SetUp() { | |
| // test_server_.reset(new EmbeddedTestServer()); | |
| // test_server_->RegisterRequestHandler( | |
| // base::Bind(&FooTest::HandleRequest, base::Unretained(this))); | |
| // ASSERT_TRUE(test_server_.Start()); | |
| // } | |
| // | |
| // std::unique_ptr<HttpResponse> HandleRequest(const HttpRequest& request) { | |
| // GURL absolute_url = test_server_->GetURL(request.relative_url); | |
| // if (absolute_url.path() != "/test") | |
| // return std::unique_ptr<HttpResponse>(); | |
| // | |
| // std::unique_ptr<BasicHttpResponse> http_response(new BasicHttpResponse()); | |
| // http_response->set_code(net::HTTP_OK); | |
| // http_response->set_content("hello"); | |
| // http_response->set_content_type("text/plain"); | |
| // return http_response; | |
| // } | |
| // | |
| // For a test that spawns another process such as browser_tests, it is | |
| // suggested to call Start in SetUpOnMainThread after the process is spawned. | |
| // If you have to do it before the process spawns, you need to first setup the | |
| // listen socket so that there is no no other threads running while spawning | |
| // the process. To do so, please follow the following example: | |
| // | |
| // void SetUp() { | |
| // ASSERT_TRUE(embedded_test_server()->InitializeAndListen()); | |
| // ... | |
| // InProcessBrowserTest::SetUp(); | |
| // } | |
| // | |
| // void SetUpOnMainThread() { | |
| // // Starts the accept IO thread. | |
| // embedded_test_server()->StartAcceptingConnections(); | |
| // } | |
| // | |
| class EmbeddedTestServer { | |
| public: | |
| enum Type { | |
| TYPE_HTTP, | |
| TYPE_HTTPS, | |
| }; | |
| // A Java counterpart will be generated for this enum. | |
| // GENERATED_JAVA_ENUM_PACKAGE: org.chromium.net.test | |
| enum ServerCertificate { | |
| CERT_OK, | |
| CERT_MISMATCHED_NAME, | |
| CERT_EXPIRED, | |
| // Causes the testserver to use a hostname that is a domain | |
| // instead of an IP. | |
| CERT_COMMON_NAME_IS_DOMAIN, | |
| // A certificate that only contains a commonName, rather than also | |
| // including a subjectAltName extension. | |
| CERT_COMMON_NAME_ONLY, | |
| // A certificate that is a leaf certificate signed with SHA-1. | |
| CERT_SHA1_LEAF, | |
| }; | |
| typedef base::RepeatingCallback<std::unique_ptr<HttpResponse>( | |
| const HttpRequest& request)> | |
| HandleRequestCallback; | |
| typedef base::RepeatingCallback<void(const HttpRequest& request)> | |
| MonitorRequestCallback; | |
| // Creates a http test server. Start() must be called to start the server. | |
| // |type| indicates the protocol type of the server (HTTP/HTTPS). | |
| // | |
| // When a TYPE_HTTPS server is created, EmbeddedTestServer will call | |
| // EmbeddedTestServer::RegisterTestCerts(), so that when the default | |
| // CertVerifiers are run in-process, they will recognize the test server's | |
| // certs. However, if the test server is running in a different process from | |
| // the CertVerifiers, EmbeddedTestServer::RegisterTestCerts() must be called | |
| // in any process where CertVerifiers are expected to accept the | |
| // EmbeddedTestServer's certs. | |
| EmbeddedTestServer(); | |
| explicit EmbeddedTestServer(Type type); | |
| ~EmbeddedTestServer(); | |
| // Registers the EmbeddedTestServer's certs for the current process. See | |
| // constructor documentation for more information. | |
| static void RegisterTestCerts(); | |
| // Sets a connection listener, that would be notified when various connection | |
| // events happen. May only be called before the server is started. Caller | |
| // maintains ownership of the listener. | |
| void SetConnectionListener(EmbeddedTestServerConnectionListener* listener); | |
| // Initializes and waits until the server is ready to accept requests. | |
| // This is the equivalent of calling InitializeAndListen() followed by | |
| // StartAcceptingConnections(). | |
| // Returns whether a listening socket has been successfully created. | |
| bool Start(int port = 0) WARN_UNUSED_RESULT; | |
| // Starts listening for incoming connections but will not yet accept them. | |
| // Returns whether a listening socket has been succesfully created. | |
| bool InitializeAndListen(int port = 0) WARN_UNUSED_RESULT; | |
| // Starts the Accept IO Thread and begins accepting connections. | |
| void StartAcceptingConnections(); | |
| // Shuts down the http server and waits until the shutdown is complete. | |
| bool ShutdownAndWaitUntilComplete() WARN_UNUSED_RESULT; | |
| // Checks if the server has started listening for incoming connections. | |
| bool Started() const { | |
| return listen_socket_.get() != NULL; | |
| } | |
| static base::FilePath GetRootCertPemPath(); | |
| HostPortPair host_port_pair() const { | |
| return HostPortPair::FromURL(base_url_); | |
| } | |
| // Returns the base URL to the server, which looks like | |
| // http://127.0.0.1:<port>/, where <port> is the actual port number used by | |
| // the server. | |
| const GURL& base_url() const { return base_url_; } | |
| // Returns a URL to the server based on the given relative URL, which | |
| // should start with '/'. For example: GetURL("/path?query=foo") => | |
| // http://127.0.0.1:<port>/path?query=foo. | |
| GURL GetURL(const std::string& relative_url) const; | |
| // Similar to the above method with the difference that it uses the supplied | |
| // |hostname| for the URL instead of 127.0.0.1. The hostname should be | |
| // resolved to 127.0.0.1. | |
| GURL GetURL(const std::string& hostname, | |
| const std::string& relative_url) const; | |
| // Returns the address list needed to connect to the server. | |
| bool GetAddressList(AddressList* address_list) const WARN_UNUSED_RESULT; | |
| // Returns the port number used by the server. | |
| uint16_t port() const { return port_; } | |
| void SetSSLConfig(ServerCertificate cert, const SSLServerConfig& ssl_config); | |
| void SetSSLConfig(ServerCertificate cert); | |
| bool ResetSSLConfig(ServerCertificate cert, | |
| const SSLServerConfig& ssl_config); | |
| // Returns the file name of the certificate the server is using. The test | |
| // certificates can be found in net/data/ssl/certificates/. | |
| std::string GetCertificateName() const; | |
| // Returns the certificate that the server is using. | |
| scoped_refptr<X509Certificate> GetCertificate() const; | |
| // Registers request handler which serves files from |directory|. | |
| // For instance, a request to "/foo.html" is served by "foo.html" under | |
| // |directory|. Files under sub directories are also handled in the same way | |
| // (i.e. "/foo/bar.html" is served by "foo/bar.html" under |directory|). | |
| // TODO(svaldez): Merge ServeFilesFromDirectory and | |
| // ServeFilesFromSourceDirectory. | |
| void ServeFilesFromDirectory(const base::FilePath& directory); | |
| // Serves files relative to DIR_SOURCE_ROOT_FOR_TESTING. | |
| void ServeFilesFromSourceDirectory(const std::string& relative); | |
| void ServeFilesFromSourceDirectory(const base::FilePath& relative); | |
| // Registers the default handlers and serve additional files from the | |
| // |directory| directory, relative to DIR_SOURCE_ROOT_FOR_TESTING. | |
| void AddDefaultHandlers(const base::FilePath& directory); | |
| // The most general purpose method. Any request processing can be added using | |
| // this method. Takes ownership of the object. The |callback| is called | |
| // on the server's IO thread so all handlers must be registered before the | |
| // server is started. | |
| void RegisterRequestHandler(const HandleRequestCallback& callback); | |
| // Adds request monitors. The |callback| is called before any handlers are | |
| // called, but can not respond it. This is useful to monitor requests that | |
| // will be handled by other request handlers. The |callback| is called | |
| // on the server's IO thread so all monitors must be registered before the | |
| // server is started. | |
| void RegisterRequestMonitor(const MonitorRequestCallback& callback); | |
| // Adds default handlers, including those added by AddDefaultHandlers, to be | |
| // tried after all other user-specified handlers have been tried. The | |
| // |callback| is called on the server's IO thread so all handlers must be | |
| // registered before the server is started. | |
| void RegisterDefaultHandler(const HandleRequestCallback& callback); | |
| bool FlushAllSocketsAndConnectionsOnUIThread(); | |
| void FlushAllSocketsAndConnections(); | |
| private: | |
| // Shuts down the server. | |
| void ShutdownOnIOThread(); | |
| // Resets the SSLServerConfig on the IO thread. | |
| void ResetSSLConfigOnIOThread(ServerCertificate cert, | |
| const SSLServerConfig& ssl_config); | |
| // Upgrade the TCP connection to one over SSL. | |
| std::unique_ptr<StreamSocket> DoSSLUpgrade( | |
| std::unique_ptr<StreamSocket> connection); | |
| // Handles async callback when the SSL handshake has been completed. | |
| void OnHandshakeDone(HttpConnection* connection, int rv); | |
| // Begins accepting new client connections. | |
| void DoAcceptLoop(); | |
| // Handles async callback when there is a new client socket. |rv| is the | |
| // return value of the socket Accept. | |
| void OnAcceptCompleted(int rv); | |
| // Adds the new |socket| to the list of clients and begins the reading | |
| // data. | |
| void HandleAcceptResult(std::unique_ptr<StreamSocket> socket); | |
| // Attempts to read data from the |connection|'s socket. | |
| void ReadData(HttpConnection* connection); | |
| // Handles async callback when new data has been read from the |connection|. | |
| void OnReadCompleted(HttpConnection* connection, int rv); | |
| // Parses the data read from the |connection| and returns true if the entire | |
| // request has been received. | |
| bool HandleReadResult(HttpConnection* connection, int rv); | |
| // Closes and removes the connection upon error or completion. | |
| void DidClose(HttpConnection* connection); | |
| // Handles a request when it is parsed. It passes the request to registered | |
| // request handlers and sends a http response. | |
| void HandleRequest(HttpConnection* connection, | |
| std::unique_ptr<HttpRequest> request); | |
| // Initializes the SSLServerContext so that SSLServerSocket connections may | |
| // share the same cache | |
| void InitializeSSLServerContext(); | |
| HttpConnection* FindConnection(StreamSocket* socket); | |
| // Posts a task to the |io_thread_| and waits for a reply. | |
| bool PostTaskToIOThreadAndWait( | |
| const base::Closure& closure) WARN_UNUSED_RESULT; | |
| const bool is_using_ssl_; | |
| std::unique_ptr<base::Thread> io_thread_; | |
| std::unique_ptr<TCPServerSocket> listen_socket_; | |
| std::unique_ptr<StreamSocket> accepted_socket_; | |
| EmbeddedTestServerConnectionListener* connection_listener_; | |
| uint16_t port_; | |
| GURL base_url_; | |
| IPEndPoint local_endpoint_; | |
| std::map<StreamSocket*, std::unique_ptr<HttpConnection>> connections_; | |
| // Vector of registered and default request handlers and monitors. | |
| std::vector<HandleRequestCallback> request_handlers_; | |
| std::vector<MonitorRequestCallback> request_monitors_; | |
| std::vector<HandleRequestCallback> default_request_handlers_; | |
| base::ThreadChecker thread_checker_; | |
| net::SSLServerConfig ssl_config_; | |
| ServerCertificate cert_; | |
| std::unique_ptr<SSLServerContext> context_; | |
| base::WeakPtrFactory<EmbeddedTestServer> weak_factory_; | |
| DISALLOW_COPY_AND_ASSIGN(EmbeddedTestServer); | |
| }; | |
| } // namespace test_server | |
| // TODO(svaldez): Refactor EmbeddedTestServer to be in the net namespace. | |
| using test_server::EmbeddedTestServer; | |
| } // namespace net | |
| #endif // NET_TEST_EMBEDDED_TEST_SERVER_EMBEDDED_TEST_SERVER_H_ |