blob: 428c13063f88a0aef11b97e2ff124f1e6ffdc74d [file] [log] [blame]
// 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 <stdint.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/ocsp_revocation_status.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 "url/gurl.h"
namespace net {
class StreamSocket;
class TCPServerSocket;
namespace test_server {
class EmbeddedTestServerConnectionListener;
class HttpConnection;
class HttpResponse;
struct HttpRequest;
class EmbeddedTestServer;
// Returned by the Start[AcceptingConnections]WithHandle() APIs, to simplify
// correct shutdown ordering of the EmbeddedTestServer. Shutdown() is invoked
// on the associated test server when the handle goes out of scope. The handle
// must therefore be destroyed before the test server.
class EmbeddedTestServerHandle {
public:
EmbeddedTestServerHandle() = default;
EmbeddedTestServerHandle(EmbeddedTestServerHandle&& other);
EmbeddedTestServerHandle& operator=(EmbeddedTestServerHandle&& other);
~EmbeddedTestServerHandle();
bool is_valid() const { return test_server_; }
explicit operator bool() const { return test_server_; }
private:
friend class EmbeddedTestServer;
explicit EmbeddedTestServerHandle(EmbeddedTestServer* test_server);
EmbeddedTestServer* test_server_ = nullptr;
};
// 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_ = std::make_unique<EmbeddedTestServer>();
// test_server_->RegisterRequestHandler(
// base::BindRepeating(&FooTest::HandleRequest, base::Unretained(this)));
// ASSERT_TRUE((test_server_handle_ = test_server_.StartAndReturnHandle()));
// }
//
// std::unique_ptr<HttpResponse> HandleRequest(const HttpRequest& request) {
// GURL absolute_url = test_server_->GetURL(request.relative_url);
// if (absolute_url.path() != "/test")
// return nullptr;
//
// auto http_response = std::make_unique<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,
// Cross-signed certificate to test PKIX path building. Contains an
// intermediate cross-signed by an unknown root, while the client (via
// TestRootStore) is expected to have a self-signed version of the
// intermediate.
CERT_CHAIN_WRONG_ROOT,
// 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,
// A certificate that is signed by an intermediate certificate.
CERT_OK_BY_INTERMEDIATE,
// A certificate with invalid notBefore and notAfter times. Windows'
// certificate library will not parse this certificate.
CERT_BAD_VALIDITY,
// A certificate that covers a number of test names. See [test_names] in
// net/data/ssl/scripts/ee.cnf. More may be added by editing this list and
// and rerunning net/data/ssl/scripts/generate-test-certs.sh.
CERT_TEST_NAMES,
// An RSA certificate with the keyUsage extension specifying that the key
// is only for encipherment.
CERT_KEY_USAGE_RSA_ENCIPHERMENT,
// An RSA certificate with the keyUsage extension specifying that the key
// is only for digital signatures.
CERT_KEY_USAGE_RSA_DIGITAL_SIGNATURE,
// A certificate will be generated at runtime. A ServerCertificateConfig
// passed to SetSSLConfig may be used to configure the details of the
// generated certificate.
CERT_AUTO,
};
enum class IntermediateType {
// Generated cert is issued directly by the CA.
kNone,
// Generated cert is issued by a generated intermediate cert, which is
// included in the TLS handshake.
kInHandshake,
// Generated cert is issued by a generated intermediate, which is NOT
// included in the TLS handshake, but is available through the leaf's
// AIA caIssuers URL.
kByAIA,
};
struct OCSPConfig {
// Enumerates the types of OCSP response that the testserver can produce.
enum class ResponseType {
// OCSP will not be enabled for the corresponding config.
kOff,
// These correspond to the OCSPResponseStatus enumeration in RFC
// 6960.
kSuccessful,
kMalformedRequest,
kInternalError,
kTryLater,
kSigRequired,
kUnauthorized,
// The response will not be valid OCSPResponse DER.
kInvalidResponse,
// OCSPResponse will be valid DER but the contained ResponseData will not.
kInvalidResponseData,
};
// OCSPProduced describes the time of the producedAt field in the
// OCSP response relative to the certificate the response is for.
enum class Produced {
// producedAt is between certificate's notBefore and notAfter dates.
kValid,
// producedAt is before certificate's notBefore date.
kBeforeCert,
// producedAt is after certificate's notAfter date.
kAfterCert,
};
struct SingleResponse {
// Date describes the thisUpdate..nextUpdate ranges for OCSP
// singleResponses, relative to the current time.
enum class Date {
// The singleResponse is valid for 7 days, and includes the current
// time.
kValid,
// The singleResponse is valid for 7 days, but nextUpdate is before the
// current time.
kOld,
// The singleResponse is valid for 7 days, but thisUpdate is after the
// current time.
kEarly,
// The singleResponse is valid for 366 days, and includes the current
// time.
kLong,
// The singleResponse is valid for 368 days, and includes the current
// time.
kLonger,
};
// Configures whether a generated OCSP singleResponse's serial field
// matches the serial number of the target certificate.
enum class Serial {
kMatch,
kMismatch,
};
OCSPRevocationStatus cert_status = OCSPRevocationStatus::GOOD;
Date ocsp_date = Date::kValid;
Serial serial = Serial::kMatch;
};
OCSPConfig();
// Configure OCSP response with |response_type|.
explicit OCSPConfig(ResponseType response_type);
// Configure a successful OCSP response with |single_responses|. |produced|
// specifies the response's producedAt value, relative to the validity
// period of the certificate the OCSPConfig is for.
explicit OCSPConfig(std::vector<SingleResponse> single_responses,
Produced produced = Produced::kValid);
OCSPConfig(const OCSPConfig&);
OCSPConfig(OCSPConfig&&);
~OCSPConfig();
OCSPConfig& operator=(const OCSPConfig&);
OCSPConfig& operator=(OCSPConfig&&);
ResponseType response_type = ResponseType::kOff;
Produced produced = Produced::kValid;
std::vector<SingleResponse> single_responses;
};
// Configuration for generated server certificate.
struct ServerCertificateConfig {
ServerCertificateConfig();
ServerCertificateConfig(const ServerCertificateConfig&);
ServerCertificateConfig(ServerCertificateConfig&&);
~ServerCertificateConfig();
ServerCertificateConfig& operator=(const ServerCertificateConfig&);
ServerCertificateConfig& operator=(ServerCertificateConfig&&);
// Configure whether the generated certificate chain should include an
// intermediate, and if so, how it is delivered to the client.
IntermediateType intermediate = IntermediateType::kNone;
// Configure OCSP handling.
// Note: In the current implementation the AIA request handler does not
// actually parse the OCSP request (a different OCSP URL is used for each
// cert). So this is useful for testing the client's handling of the OCSP
// response, but not for testing that the client is sending a proper OCSP
// request.
//
// AIA OCSP for the leaf cert. If |kOff|, no AIA OCSP URL will be included
// in the leaf cert.
OCSPConfig ocsp_config;
// Stapled OCSP for the leaf cert. If |kOff|, OCSP Stapling will not be
// used.
OCSPConfig stapled_ocsp_config;
// AIA OCSP for the intermediate cert. If |kOff|, no AIA OCSP URL will be
// included in the intermediate cert. It is invalid to supply a
// configuration other than |kOff| if |intermediate| is |kNone|.
OCSPConfig intermediate_ocsp_config;
// Certificate policy OIDs, in text notation (e.g. "1.2.3.4"). If
// non-empty, the policies will be added to the leaf cert and the
// intermediate cert (if an intermediate is configured).
std::vector<std::string> policy_oids;
};
typedef base::RepeatingCallback<std::unique_ptr<HttpResponse>(
const HttpRequest& request)>
HandleRequestCallback;
typedef base::RepeatingCallback<void(const HttpRequest& request)>
MonitorRequestCallback;
// Creates a http test server. StartAndReturnHandle() 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
// StartAcceptingConnectionsAndReturnHandle().
// Returns a "handle" which will ShutdownAndWaitUntilComplete() when
// destroyed, or null if the listening socket could not be created.
EmbeddedTestServerHandle StartAndReturnHandle(int port = 0)
WARN_UNUSED_RESULT;
// Equivalent of StartAndReturnHandle(), but requires manual Shutdown() by
// the caller.
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.
EmbeddedTestServerHandle StartAcceptingConnectionsAndReturnHandle()
WARN_UNUSED_RESULT;
// Equivalent of StartAcceptingConnectionsAndReturnHandle(), but requires
// manual Shutdown() by the caller.
void StartAcceptingConnections();
// Shuts down the http server and waits until the shutdown is complete.
// Prefer to use the Start*AndReturnHandle() APIs to manage shutdown, if
// possible.
bool ShutdownAndWaitUntilComplete() WARN_UNUSED_RESULT;
// Checks if the server has started listening for incoming connections.
bool Started() const { return listen_socket_.get() != nullptr; }
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 IP Address to connect to the server as a string.
std::string GetIPLiteralString() const;
// Returns the port number used by the server.
uint16_t port() const { return port_; }
// SetSSLConfig sets the SSL configuration for the server. It is invalid to
// call after the server is started. If called multiple times, the last call
// will have effect.
void SetSSLConfig(ServerCertificate cert, const SSLServerConfig& ssl_config);
void SetSSLConfig(ServerCertificate cert);
void SetSSLConfig(const ServerCertificateConfig& cert_config,
const SSLServerConfig& ssl_config);
void SetSSLConfig(const ServerCertificateConfig& cert_config);
// TODO(mattm): make this WARN_UNUSED_RESULT
bool ResetSSLConfig(ServerCertificate cert,
const SSLServerConfig& ssl_config);
// Returns the certificate that the server is using.
// If using a generated ServerCertificate type, this must not be called before
// InitializeAndListen() has been called.
scoped_refptr<X509Certificate> GetCertificate();
// 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.
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.
void AddDefaultHandlers(const base::FilePath& directory);
// Adds a request handler that can perform any general-purpose processing.
// |callback| will be invoked on the server's IO thread. Note that:
// 1. All handlers must be registered before the server is Start()ed.
// 2. The server should be Shutdown() before any variables referred to by
// |callback| (e.g. via base::Unretained(&local)) are deleted. Using the
// Start*WithHandle() API variants is recommended for this reason.
void RegisterRequestHandler(const HandleRequestCallback& callback);
// Adds a request monitor that will be called before any handlers. Monitors
// can be used to observe requests, but not to respond to them.
// See RegisterRequestHandler() for notes on usage.
void RegisterRequestMonitor(const MonitorRequestCallback& callback);
// Adds a default request handler, to be called if no user-specified handler
// handles the request.
// See RegisterRequestHandler() for notes on usage.
void RegisterDefaultHandler(const HandleRequestCallback& callback);
bool FlushAllSocketsAndConnectionsOnUIThread();
void FlushAllSocketsAndConnections();
private:
// 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;
// Shuts down the server.
void ShutdownOnIOThread();
// Sets the SSL configuration for the server. It is invalid for |cert_config|
// to be non-null if |cert| is not CERT_AUTO.
void SetSSLConfigInternal(ServerCertificate cert,
const ServerCertificateConfig* cert_config,
const SSLServerConfig& ssl_config);
// Resets the SSLServerConfig on the IO thread.
bool 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);
// Called when |connection| is finished writing the response and the socket
// can be closed, allowing for |connnection_listener_| to take it if the
// socket is still open.
void OnResponseCompleted(HttpConnection* connection);
// 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);
// Returns true if the current |cert_| configuration uses a static
// pre-generated cert loaded from the filesystem.
bool UsingStaticCert() const;
// Reads server certificate and private key from file. May only be called if
// |cert_| refers to a file-based cert & key.
bool InitializeCertAndKeyFromFile() WARN_UNUSED_RESULT;
// Generate server certificate and private key. May only be called if |cert_|
// refers to a generated cert & key.
bool GenerateCertAndKey() WARN_UNUSED_RESULT;
// Initializes the SSLServerContext so that SSLServerSocket connections may
// share the same cache
bool InitializeSSLServerContext() WARN_UNUSED_RESULT;
HttpConnection* FindConnection(StreamSocket* socket);
// Posts a task to the |io_thread_| and waits for a reply.
bool PostTaskToIOThreadAndWait(base::OnceClosure closure) WARN_UNUSED_RESULT;
// Posts a task that returns a true/false success/fail value to the
// |io_thread_| and waits for a reply.
bool PostTaskToIOThreadAndWaitWithResult(base::OnceCallback<bool()> task)
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_;
ServerCertificateConfig cert_config_;
scoped_refptr<X509Certificate> x509_cert_;
bssl::UniquePtr<EVP_PKEY> private_key_;
std::unique_ptr<SSLServerContext> context_;
// HTTP server that handles AIA URLs that are embedded in this test server's
// certificate when the server certificate is one of the CERT_AUTO variants.
std::unique_ptr<EmbeddedTestServer> aia_http_server_;
base::WeakPtrFactory<EmbeddedTestServer> weak_factory_{this};
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_