C++程序  |  210行  |  6.11 KB

// Copyright (c) 2011 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_TEST_SERVER_H_
#define NET_TEST_TEST_SERVER_H_
#pragma once

#include <string>
#include <utility>
#include <vector>

#include "build/build_config.h"

#include "base/compiler_specific.h"
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/process_util.h"
#include "net/base/host_port_pair.h"
#include "net/base/net_util.h"

#if defined(OS_WIN)
#include "base/win/scoped_handle.h"
#endif

class CommandLine;
class DictionaryValue;
class GURL;

namespace net {

class AddressList;

// This object bounds the lifetime of an external python-based HTTP/FTP server
// that can provide various responses useful for testing.
class TestServer {
 public:
  typedef std::pair<std::string, std::string> StringPair;

  enum Type {
    TYPE_FTP,
    TYPE_HTTP,
    TYPE_HTTPS,
    TYPE_SYNC,
  };

  // Container for various options to control how the HTTPS server is
  // initialized.
  struct HTTPSOptions {
    enum ServerCertificate {
      CERT_OK,
      CERT_MISMATCHED_NAME,
      CERT_EXPIRED,
    };

    // Bitmask of bulk encryption algorithms that the test server supports
    // and that can be selectively enabled or disabled.
    enum BulkCipher {
      // Special value used to indicate that any algorithm the server supports
      // is acceptable. Preferred over explicitly OR-ing all ciphers.
      BULK_CIPHER_ANY    = 0,

      BULK_CIPHER_RC4    = (1 << 0),
      BULK_CIPHER_AES128 = (1 << 1),
      BULK_CIPHER_AES256 = (1 << 2),

      // NOTE: 3DES support in the Python test server has external
      // dependencies and not be available on all machines. Clients may not
      // be able to connect if only 3DES is specified.
      BULK_CIPHER_3DES   = (1 << 3),
    };

    // Initialize a new HTTPSOptions using CERT_OK as the certificate.
    HTTPSOptions();

    // Initialize a new HTTPSOptions that will use the specified certificate.
    explicit HTTPSOptions(ServerCertificate cert);
    ~HTTPSOptions();

    // Returns the relative filename of the file that contains the
    // |server_certificate|.
    FilePath GetCertificateFile() const;

    // The certificate to use when serving requests.
    ServerCertificate server_certificate;

    // True if a CertificateRequest should be sent to the client during
    // handshaking.
    bool request_client_certificate;

    // 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<FilePath> client_authorities;

    // A bitwise-OR of BulkCipher that should be used by the
    // HTTPS server, or BULK_CIPHER_ANY to indicate that all implemented
    // ciphers are acceptable.
    int bulk_ciphers;
  };

  TestServer(Type type, const FilePath& document_root);

  // Initialize a HTTPS TestServer with a specific set of HTTPSOptions.
  TestServer(const HTTPSOptions& https_options,
             const FilePath& document_root);

  ~TestServer();

  bool Start() WARN_UNUSED_RESULT;

  // Stop the server started by Start().
  bool Stop();

  const FilePath& document_root() const { return document_root_; }
  const HostPortPair& host_port_pair() const;
  const DictionaryValue& server_data() const;
  std::string GetScheme() const;
  bool GetAddressList(AddressList* address_list) const WARN_UNUSED_RESULT;

  GURL GetURL(const std::string& path) 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);

 private:
  void Init(const FilePath& document_root);

  // Modify PYTHONPATH to contain libraries we need.
  bool SetPythonPath() WARN_UNUSED_RESULT;

  // Launches the Python test server. Returns true on success.
  bool LaunchPython(const FilePath& testserver_path) WARN_UNUSED_RESULT;

  // Waits for the server to start. Returns true on success.
  bool WaitToStart() WARN_UNUSED_RESULT;

  // Parses the server data read from the test server.  Returns true
  // on success.
  bool ParseServerData(const std::string& server_data) WARN_UNUSED_RESULT;

  // Returns path to the root certificate.
  FilePath GetRootCertificatePath() const;

  // Load the test root cert, if it hasn't been loaded yet.
  bool LoadTestRootCert() WARN_UNUSED_RESULT;

  // Add the command line arguments for the Python test server to
  // |command_line|. Return true on success.
  bool AddCommandLineArguments(CommandLine* command_line) const;

  // Document root of the test server.
  FilePath document_root_;

  // Directory that contains the SSL certificates.
  FilePath certificates_dir_;

  // Address the test server listens on.
  HostPortPair host_port_pair_;

  // Holds the data sent from the server (e.g., port number).
  scoped_ptr<DictionaryValue> server_data_;

  // Handle of the Python process running the test server.
  base::ProcessHandle process_handle_;

  scoped_ptr<net::ScopedPortException> allowed_port_;

#if defined(OS_WIN)
  // JobObject used to clean up orphaned child processes.
  base::win::ScopedHandle job_handle_;

  // The pipe file handle we read from.
  base::win::ScopedHandle child_read_fd_;

  // The pipe file handle the child and we write to.
  base::win::ScopedHandle child_write_fd_;
#endif

#if defined(OS_POSIX)
  // The file descriptor the child writes to when it starts.
  int child_fd_;
  file_util::ScopedFD child_fd_closer_;
#endif

  // If |type_| is TYPE_HTTPS, the TLS settings to use for the test server.
  HTTPSOptions https_options_;

  Type type_;

  // Has the server been started?
  bool started_;

  DISALLOW_COPY_AND_ASSIGN(TestServer);
};

}  // namespace net

#endif  // NET_TEST_TEST_SERVER_H_