blob: 195c68dcddc6301e183d598f501176290e2b9ae2 [file] [log] [blame]
// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// NOTE: spawned_test_server is deprecated, since it frequently causes test
// flakiness. Please consider using embedded_test_server if possible.
#ifndef NET_TEST_SPAWNED_TEST_SERVER_BASE_TEST_SERVER_H_
#define NET_TEST_SPAWNED_TEST_SERVER_BASE_TEST_SERVER_H_
#include <stdint.h>
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "base/files/file_path.h"
#include "base/memory/scoped_refptr.h"
#include "base/values.h"
#include "net/base/host_port_pair.h"
#include "net/cert/test_root_certs.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
class GURL;
namespace net {
class AddressList;
class ScopedPortException;
class ScopedTestRoot;
class X509Certificate;
// The base class of Test server implementation.
class BaseTestServer {
public:
typedef std::pair<std::string, std::string> StringPair;
enum Type {
TYPE_BASIC_AUTH_PROXY,
TYPE_WS,
TYPE_WSS,
TYPE_PROXY,
};
// Container for various options to control how the HTTPS or WSS server is
// initialized.
struct SSLOptions {
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,
// 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 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,
};
// Initialize a new SSLOptions using CERT_OK as the certificate.
SSLOptions();
// Initialize a new SSLOptions that will use the specified certificate.
explicit SSLOptions(ServerCertificate cert);
explicit SSLOptions(base::FilePath cert);
SSLOptions(const SSLOptions& other);
~SSLOptions();
// Returns the relative filename of the file that contains the
// |server_certificate|.
base::FilePath GetCertificateFile() const;
// The certificate to use when serving requests.
ServerCertificate server_certificate = CERT_OK;
base::FilePath custom_certificate;
// True if a CertificateRequest should be sent to the client during
// handshaking.
bool request_client_certificate = false;
// If |request_client_certificate| is true, an optional list of files,
// each containing a single, PEM-encoded X.509 certificates. The subject
// from each certificate will be added to the certificate_authorities
// field of the CertificateRequest.
std::vector<base::FilePath> client_authorities;
};
// Initialize a TestServer.
explicit BaseTestServer(Type type);
// Initialize a TestServer with a specific set of SSLOptions for HTTPS or WSS.
BaseTestServer(Type type, const SSLOptions& ssl_options);
BaseTestServer(const BaseTestServer&) = delete;
BaseTestServer& operator=(const BaseTestServer&) = delete;
// Starts the server blocking until the server is ready.
[[nodiscard]] bool Start();
// Start the test server without blocking. Use this if you need multiple test
// servers (such as WebSockets and HTTP, or HTTP and HTTPS). You must call
// BlockUntilStarted on all servers your test requires before executing the
// test. For example:
//
// // Start the servers in parallel.
// ASSERT_TRUE(http_server.StartInBackground());
// ASSERT_TRUE(websocket_server.StartInBackground());
// // Wait for both servers to be ready.
// ASSERT_TRUE(http_server.BlockUntilStarted());
// ASSERT_TRUE(websocket_server.BlockUntilStarted());
// RunMyTest();
//
// Returns true on success.
[[nodiscard]] virtual bool StartInBackground() = 0;
// Block until the test server is ready. Returns true on success. See
// StartInBackground() documentation for more information.
[[nodiscard]] virtual bool BlockUntilStarted() = 0;
// Returns the host port pair used by current Python based test server only
// if the server is started.
const HostPortPair& host_port_pair() const;
const base::FilePath& document_root() const { return document_root_; }
std::string GetScheme() const;
[[nodiscard]] bool GetAddressList(AddressList* address_list) const;
GURL GetURL(const std::string& path) const;
GURL GetURL(const std::string& hostname,
const std::string& relative_url) const;
GURL GetURLWithUser(const std::string& path,
const std::string& user) const;
GURL GetURLWithUserAndPassword(const std::string& path,
const std::string& user,
const std::string& password) const;
static bool GetFilePathWithReplacements(
const std::string& original_path,
const std::vector<StringPair>& text_to_replace,
std::string* replacement_path);
static bool UsingSSL(Type type) { return type == BaseTestServer::TYPE_WSS; }
// Enable HTTP basic authentication. Currently this only works for TYPE_WS and
// TYPE_WSS.
void set_websocket_basic_auth(bool ws_basic_auth) {
ws_basic_auth_ = ws_basic_auth;
}
// Redirect proxied CONNECT requests to localhost.
void set_redirect_connect_to_localhost(bool redirect_connect_to_localhost) {
redirect_connect_to_localhost_ = redirect_connect_to_localhost;
}
// Registers the test server's certs for the current process.
[[nodiscard]] static ScopedTestRoot RegisterTestCerts();
// Marks the root certificate of an HTTPS test server as trusted for
// the duration of tests.
[[nodiscard]] bool LoadTestRootCert();
// Returns the certificate that the server is using.
scoped_refptr<X509Certificate> GetCertificate() const;
protected:
virtual ~BaseTestServer();
Type type() const { return type_; }
const SSLOptions& ssl_options() const { return ssl_options_; }
bool started() const { return started_; }
// Gets port currently assigned to host_port_pair_ without checking
// whether it's available (server started) or not.
uint16_t GetPort();
// Sets |port| as the actual port used by Python based test server.
void SetPort(uint16_t port);
// Set up internal status when the server is started.
[[nodiscard]] bool SetupWhenServerStarted();
// Clean up internal status when starting to stop server.
void CleanUpWhenStoppingServer();
// Set path of test resources.
void SetResourcePath(const base::FilePath& document_root,
const base::FilePath& certificates_dir);
// Parses the server data read from the test server and sets |server_data_|.
// *port is set to the port number specified in server_data. The port may be
// different from the local port set in |host_port_pair_|, specifically when
// using RemoteTestServer (which proxies connections from 127.0.0.1 to a
// different IP). Returns true on success.
[[nodiscard]] bool SetAndParseServerData(const std::string& server_data,
int* port);
// Returns a base::Value::Dict with the arguments for launching the external
// Python test server, in the form of
// { argument-name: argument-value, ... }
//
// Returns nullopt if an invalid configuration is specified.
absl::optional<base::Value::Dict> GenerateArguments() const;
private:
void Init(const std::string& host);
// Document root of the test server.
base::FilePath document_root_;
// Directory that contains the SSL certificates.
base::FilePath certificates_dir_;
ScopedTestRoot scoped_test_root_;
// Address on which the tests should connect to the server. With
// RemoteTestServer it may be different from the address on which the server
// listens on.
HostPortPair host_port_pair_;
// If |UsingSSL(type_)|, the TLS settings to use for the test server.
SSLOptions ssl_options_;
Type type_;
// Has the server been started?
bool started_ = false;
// Enables logging of the server to the console.
bool log_to_console_ = false;
// Is WebSocket basic HTTP authentication enabled?
bool ws_basic_auth_ = false;
// Redirect proxied CONNECT requests to localhost?
bool redirect_connect_to_localhost_ = false;
std::unique_ptr<ScopedPortException> allowed_port_;
};
} // namespace net
#endif // NET_TEST_SPAWNED_TEST_SERVER_BASE_TEST_SERVER_H_