| Index: net/url_request/url_request_unittest.h
 | 
| ===================================================================
 | 
| --- net/url_request/url_request_unittest.h	(revision 7499)
 | 
| +++ net/url_request/url_request_unittest.h	(working copy)
 | 
| @@ -9,6 +9,7 @@
 | 
|  
 | 
|  #include <sstream>
 | 
|  #include <string>
 | 
| +#include <vector>
 | 
|  
 | 
|  #include "base/file_path.h"
 | 
|  #include "base/file_util.h"
 | 
| @@ -27,7 +28,9 @@
 | 
|  #include "testing/gtest/include/gtest/gtest.h"
 | 
|  #include "googleurl/src/url_util.h"
 | 
|  
 | 
| -const int kDefaultPort = 1337;
 | 
| +const int kHTTPDefaultPort = 1337;
 | 
| +const int kFTPDefaultPort = 1338;
 | 
| +
 | 
|  const std::string kDefaultHostName("localhost");
 | 
|  
 | 
|  // This URLRequestContext does not use a local cache.
 | 
| @@ -190,29 +193,37 @@
 | 
|    char buf_[4096];
 | 
|  };
 | 
|  
 | 
| -// This object bounds the lifetime of an external python-based HTTP server
 | 
| +// This object bounds the lifetime of an external python-based HTTP/FTP server
 | 
|  // that can provide various responses useful for testing.
 | 
| -class TestServer : public base::ProcessFilter {
 | 
| - public:
 | 
| -  TestServer(const std::wstring& document_root)
 | 
| -      : process_handle_(NULL),
 | 
| -        is_shutdown_(true) {
 | 
| -    Init(kDefaultHostName, kDefaultPort, document_root, std::wstring());
 | 
| +class BaseTestServer : public base::ProcessFilter,
 | 
| +                       public base::RefCounted<BaseTestServer> {
 | 
| + protected:
 | 
| +  BaseTestServer()
 | 
| +      : process_handle_(NULL) {
 | 
|    }
 | 
|  
 | 
| -  virtual ~TestServer() {
 | 
| -    Shutdown();
 | 
| + public:
 | 
| +  virtual ~BaseTestServer() {
 | 
| +    if (process_handle_) {
 | 
| +#if defined(OS_WIN)
 | 
| +      CloseHandle(process_handle_);
 | 
| +#endif
 | 
| +      process_handle_ = NULL;
 | 
| +    }
 | 
| +    // Make sure we don't leave any stray testserver processes laying around.
 | 
| +    std::wstring testserver_name =
 | 
| +    file_util::GetFilenameFromPath(python_runtime_);
 | 
| +    base::CleanupProcesses(testserver_name, 10000, 1, this);
 | 
| +    EXPECT_EQ(0, base::GetProcessCount(testserver_name, this));
 | 
|    }
 | 
|  
 | 
|    // Implementation of ProcessFilter
 | 
|    virtual bool Includes(uint32 pid, uint32 parent_pid) const {
 | 
| -    // This function may be called after Shutdown(), in which process_handle_ is
 | 
| -    // set to NULL. Since no process handle is set, it can't be included in the
 | 
| -    // filter.
 | 
| +    // Since no process handle is set, it can't be included in the filter.
 | 
|      if (!process_handle_)
 | 
|        return false;
 | 
|      // TODO(port): rationalize return value of GetProcId
 | 
| -    return pid == (uint32)base::GetProcId(process_handle_);
 | 
| +    return pid == static_cast<uint32>(base::GetProcId(process_handle_));
 | 
|    }
 | 
|  
 | 
|    GURL TestServerPage(const std::string& path) {
 | 
| @@ -223,101 +234,46 @@
 | 
|      return GURL(base_address_ + WideToUTF8(path));
 | 
|    }
 | 
|  
 | 
| -  // A subclass may wish to send the request in a different manner
 | 
| -  virtual bool MakeGETRequest(const std::string& page_name) {
 | 
| -    const GURL& url = TestServerPage(page_name);
 | 
| +  void SetPythonPaths() {
 | 
| +#if defined(OS_WIN)
 | 
| +     // Set up PYTHONPATH so that Python is able to find the in-tree copy of
 | 
| +    // pyftpdlib.
 | 
| +    static bool set_python_path = false;
 | 
| +    if (!set_python_path) {
 | 
| +      FilePath pyftpdlib_path;
 | 
| +      ASSERT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &pyftpdlib_path));
 | 
| +      pyftpdlib_path = pyftpdlib_path.Append(L"third_party");
 | 
| +      pyftpdlib_path = pyftpdlib_path.Append(L"pyftpdlib");
 | 
|  
 | 
| -    // Spin up a background thread for this request so that we have access to
 | 
| -    // an IO message loop, and in cases where this thread already has an IO
 | 
| -    // message loop, we also want to avoid spinning a nested message loop.
 | 
| -    
 | 
| -    SyncTestDelegate d;
 | 
| -    {
 | 
| -      base::Thread io_thread("MakeGETRequest");
 | 
| -      base::Thread::Options options;
 | 
| -      options.message_loop_type = MessageLoop::TYPE_IO;
 | 
| -      io_thread.StartWithOptions(options);
 | 
| -      io_thread.message_loop()->PostTask(FROM_HERE, NewRunnableFunction(
 | 
| -          &TestServer::StartGETRequest, url, &d));
 | 
| -      d.Wait();
 | 
| -    }
 | 
| -    return d.did_succeed();
 | 
| -  }
 | 
| +      const wchar_t kPythonPath[] = L"PYTHONPATH";
 | 
| +      wchar_t python_path_c[1024];
 | 
| +      if (GetEnvironmentVariable(kPythonPath, python_path_c, 1023) > 0) {
 | 
| +        // PYTHONPATH is already set, append to it.
 | 
| +        std::wstring python_path(python_path_c);
 | 
| +        python_path.append(L":");
 | 
| +        python_path.append(pyftpdlib_path.value());
 | 
| +        SetEnvironmentVariableW(kPythonPath, python_path.c_str());
 | 
| +      } else {
 | 
| +        SetEnvironmentVariableW(kPythonPath, pyftpdlib_path.value().c_str());
 | 
| +      }
 | 
|  
 | 
| -  bool init_successful() const { return init_successful_; }
 | 
| -
 | 
| - protected:
 | 
| -  struct ManualInit {};
 | 
| -
 | 
| -  // Used by subclasses that need to defer initialization until they are fully
 | 
| -  // constructed.  The subclass should call Init once it is ready (usually in
 | 
| -  // its constructor).
 | 
| -  TestServer(ManualInit)
 | 
| -      : process_handle_(NULL),
 | 
| -        init_successful_(false),
 | 
| -        is_shutdown_(true) {
 | 
| -  }
 | 
| -
 | 
| -  virtual std::string scheme() { return std::string("http"); }
 | 
| -
 | 
| -  // This is in a separate function so that we can have assertions and so that
 | 
| -  // subclasses can call this later.
 | 
| -  void Init(const std::string& host_name, int port,
 | 
| -            const std::wstring& document_root,
 | 
| -            const std::wstring& cert_path) {
 | 
| -    std::stringstream ss;
 | 
| -    std::string port_str;
 | 
| -    ss << (port ? port : kDefaultPort);
 | 
| -    ss >> port_str;
 | 
| -    base_address_ = scheme() + "://" + host_name + ":" + port_str + "/";
 | 
| -
 | 
| -    std::wstring testserver_path;
 | 
| -    ASSERT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &testserver_path));
 | 
| -    file_util::AppendToPath(&testserver_path, L"net");
 | 
| -    file_util::AppendToPath(&testserver_path, L"tools");
 | 
| -    file_util::AppendToPath(&testserver_path, L"testserver");
 | 
| -    file_util::AppendToPath(&testserver_path, L"testserver.py");
 | 
| -
 | 
| -    ASSERT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &python_runtime_));
 | 
| -    file_util::AppendToPath(&python_runtime_, L"third_party");
 | 
| -    file_util::AppendToPath(&python_runtime_, L"python_24");
 | 
| -    file_util::AppendToPath(&python_runtime_, L"python.exe");
 | 
| -
 | 
| -    std::wstring test_data_directory;
 | 
| -    PathService::Get(base::DIR_SOURCE_ROOT, &test_data_directory);
 | 
| -    std::wstring normalized_document_root = document_root;
 | 
| -#if defined(OS_WIN)
 | 
| -    std::replace(normalized_document_root.begin(),
 | 
| -                 normalized_document_root.end(),
 | 
| -                 L'/', FilePath::kSeparators[0]);
 | 
| -#endif
 | 
| -    file_util::AppendToPath(&test_data_directory, normalized_document_root);
 | 
| -
 | 
| -#if defined(OS_WIN)
 | 
| -    std::wstring command_line =
 | 
| -        L"\"" + python_runtime_ + L"\" " + L"\"" + testserver_path +
 | 
| -        L"\" --port=" + UTF8ToWide(port_str) + L" --data-dir=\"" +
 | 
| -        test_data_directory + L"\"";
 | 
| -    if (!cert_path.empty()) {
 | 
| -      command_line.append(L" --https=\"");
 | 
| -      command_line.append(cert_path);
 | 
| -      command_line.append(L"\"");
 | 
| +      set_python_path = true;
 | 
|      }
 | 
| -
 | 
| -    ASSERT_TRUE(
 | 
| -        base::LaunchApp(command_line, false, true, &process_handle_)) <<
 | 
| -        "Failed to launch " << command_line;
 | 
|  #elif defined(OS_POSIX)
 | 
|      // Set up PYTHONPATH so that Python is able to find the in-tree copy of
 | 
| -    // tlslite.
 | 
| -
 | 
| +    // tlslite and pyftpdlib.
 | 
|      static bool set_python_path = false;
 | 
|      if (!set_python_path) {
 | 
|        FilePath tlslite_path;
 | 
| +      FilePath pyftpdlib_path;
 | 
|        ASSERT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &tlslite_path));
 | 
|        tlslite_path = tlslite_path.Append("third_party");
 | 
|        tlslite_path = tlslite_path.Append("tlslite");
 | 
|  
 | 
| +      ASSERT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &pyftpdlib_path));
 | 
| +      pyftpdlib_path = pyftpdlib_path.Append("third_party");
 | 
| +      pyftpdlib_path = pyftpdlib_path.Append("pyftpdlib");
 | 
| +
 | 
|        const char kPythonPath[] = "PYTHONPATH";
 | 
|        char* python_path_c = getenv(kPythonPath);
 | 
|        if (python_path_c) {
 | 
| @@ -325,81 +281,89 @@
 | 
|          std::string python_path(python_path_c);
 | 
|          python_path.append(":");
 | 
|          python_path.append(tlslite_path.value());
 | 
| +        python_path.append(":");
 | 
| +        python_path.append(pyftpdlib_path.value());
 | 
|          setenv(kPythonPath, python_path.c_str(), 1);
 | 
|        } else {
 | 
| -        setenv(kPythonPath, tlslite_path.value().c_str(), 1);
 | 
| +        std::string python_path = tlslite_path.value().c_str();
 | 
| +        python_path.append(":");
 | 
| +        python_path.append(pyftpdlib_path.value());
 | 
| +        setenv(kPythonPath, python_path.c_str(), 1);
 | 
|        }
 | 
| -
 | 
|        set_python_path = true;
 | 
|      }
 | 
| -
 | 
| -    std::vector<std::string> command_line;
 | 
| -    command_line.push_back("python");
 | 
| -    command_line.push_back(WideToUTF8(testserver_path));
 | 
| -    command_line.push_back("--port=" + port_str);
 | 
| -    command_line.push_back("--data-dir=" + WideToUTF8(test_data_directory));
 | 
| -    if (!cert_path.empty()) 
 | 
| -      command_line.push_back("--https=" + WideToUTF8(cert_path));
 | 
| -
 | 
| -    base::file_handle_mapping_vector no_mappings;
 | 
| -    ASSERT_TRUE(
 | 
| -        base::LaunchApp(command_line, no_mappings, false, &process_handle_)) <<
 | 
| -        "Failed to launch " << command_line[0] << " ...";
 | 
|  #endif
 | 
| +  }
 | 
|  
 | 
| -    // Verify that the webserver is actually started.
 | 
| -    // Otherwise tests can fail if they run faster than Python can start.
 | 
| -    int retries = 10;
 | 
| -    bool success;
 | 
| -    while ((success = MakeGETRequest("hello.html")) == false && retries > 0) {
 | 
| -      retries--;
 | 
| -      PlatformThread::Sleep(500);
 | 
| +  void SetAppPath(const std::string& host_name, int port,
 | 
| +      const std::wstring& document_root, const std::string& scheme,
 | 
| +      std::wstring* testserver_path, std::wstring* test_data_directory) {
 | 
| +    port_str_ = IntToString(port);
 | 
| +    if (url_user_.empty()) {
 | 
| +      base_address_ = scheme + "://" + host_name + ":" + port_str_ + "/";
 | 
| +    } else {
 | 
| +      if (url_password_.empty())
 | 
| +        base_address_ = scheme + "://" + url_user_ + "@" +
 | 
| +            host_name + ":" + port_str_ + "/";
 | 
| +      else
 | 
| +        base_address_ = scheme + "://" + url_user_ + ":" + url_password_ +
 | 
| +            "@" + host_name + ":" + port_str_ + "/";
 | 
|      }
 | 
| -    ASSERT_TRUE(success) << "Webserver not starting properly.";
 | 
|  
 | 
| -    init_successful_ = true;
 | 
| -    is_shutdown_ = false;
 | 
| -  }
 | 
| +    ASSERT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, testserver_path));
 | 
| +    file_util::AppendToPath(testserver_path, L"net");
 | 
| +    file_util::AppendToPath(testserver_path, L"tools");
 | 
| +    file_util::AppendToPath(testserver_path, L"testserver");
 | 
| +    file_util::AppendToPath(testserver_path, L"testserver.py");
 | 
|  
 | 
| -  void Shutdown() {
 | 
| -    if (is_shutdown_)
 | 
| -      return;
 | 
| +    ASSERT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &python_runtime_));
 | 
| +    file_util::AppendToPath(&python_runtime_, L"third_party");
 | 
| +    file_util::AppendToPath(&python_runtime_, L"python_24");
 | 
| +    file_util::AppendToPath(&python_runtime_, L"python.exe");
 | 
|  
 | 
| -    // here we append the time to avoid problems where the kill page
 | 
| -    // is being cached rather than being executed on the server
 | 
| -    std::ostringstream page_name;
 | 
| -    page_name << "kill?" << (unsigned int)(base::Time::Now().ToInternalValue());
 | 
| -    int retry_count = 5;
 | 
| -    while (retry_count > 0) {
 | 
| -      bool r = MakeGETRequest(page_name.str());
 | 
| -      // BUG #1048625 causes the kill GET to fail.  For now we just retry.
 | 
| -      // Once the bug is fixed, we should remove the while loop and put back
 | 
| -      // the following DCHECK.
 | 
| -      // DCHECK(r);
 | 
| -      if (r)
 | 
| -        break;
 | 
| -      retry_count--;
 | 
| -    }
 | 
| -    // Make sure we were successfull in stopping the testserver.
 | 
| -    DCHECK(retry_count > 0);
 | 
| +    PathService::Get(base::DIR_SOURCE_ROOT, test_data_directory);
 | 
| +    std::wstring normalized_document_root = document_root;
 | 
|  
 | 
| -    if (process_handle_) {
 | 
|  #if defined(OS_WIN)
 | 
| -      CloseHandle(process_handle_);
 | 
| +    // It is just for windows only and have no effect on other OS
 | 
| +    std::replace(normalized_document_root.begin(),
 | 
| +        normalized_document_root.end(),
 | 
| +        L'/', FilePath::kSeparators[0]);
 | 
|  #endif
 | 
| -      process_handle_ = NULL;
 | 
| -    }
 | 
| +    if (!normalized_document_root.empty())
 | 
| +      file_util::AppendToPath(test_data_directory, normalized_document_root);
 | 
|  
 | 
| -    // Make sure we don't leave any stray testserver processes laying around.
 | 
| -    std::wstring testserver_name =
 | 
| -        file_util::GetFilenameFromPath(python_runtime_);
 | 
| -    base::CleanupProcesses(testserver_name, 10000, 1, this);
 | 
| -    EXPECT_EQ(0, base::GetProcessCount(testserver_name, this));
 | 
| +  }
 | 
|  
 | 
| -    is_shutdown_ = true;
 | 
| +#if defined(OS_WIN)
 | 
| +  void LaunchApp(const std::wstring& command_line) {
 | 
| +    ASSERT_TRUE(base::LaunchApp(command_line, false, true, &process_handle_)) <<
 | 
| +                "Failed to launch " << command_line;
 | 
|    }
 | 
| +#elif defined(OS_POSIX)
 | 
| +  void LaunchApp(const std::vector<std::string>& command_line) {
 | 
| +    ASSERT_TRUE(base::LaunchApp(command_line, false, true, &process_handle_)) <<
 | 
| +                "Failed to launch " << command_line[0] << " ...";
 | 
| +  }
 | 
| +#endif
 | 
|  
 | 
| - private:
 | 
| +  virtual bool MakeGETRequest(const std::string& page_name) = 0;
 | 
| +
 | 
| +  // Verify that the Server is actually started.
 | 
| +  // Otherwise tests can fail if they run faster than Python can start.
 | 
| +  bool VerifyLaunchApp(const std::string& page_name) {
 | 
| +    int retries = 10;
 | 
| +    bool success;
 | 
| +    while ((success = MakeGETRequest(page_name)) == false && retries > 0) {
 | 
| +      retries--;
 | 
| +      PlatformThread::Sleep(500);
 | 
| +    }
 | 
| +    if (!success)
 | 
| +      return false;
 | 
| +    return true;
 | 
| +  }
 | 
| +
 | 
| + protected:
 | 
|    // Used by MakeGETRequest to implement sync load behavior.
 | 
|    class SyncTestDelegate : public TestDelegate {
 | 
|     public:
 | 
| @@ -417,6 +381,73 @@
 | 
|      bool success_;
 | 
|      DISALLOW_COPY_AND_ASSIGN(SyncTestDelegate);
 | 
|    };
 | 
| +
 | 
| +  std::string base_address_;
 | 
| +  std::string url_user_;
 | 
| +  std::string url_password_;
 | 
| +  std::wstring python_runtime_;
 | 
| +  base::ProcessHandle process_handle_;
 | 
| +  std::string port_str_;
 | 
| +};
 | 
| +
 | 
| +class HTTPTestServer : public BaseTestServer {
 | 
| + protected:
 | 
| +  HTTPTestServer() {
 | 
| +  }
 | 
| +
 | 
| + public:
 | 
| +  static HTTPTestServer* CreateServer(const std::wstring& document_root) {
 | 
| +    HTTPTestServer* test_server = new HTTPTestServer();
 | 
| +    if (!test_server->Init(kDefaultHostName, kHTTPDefaultPort, document_root)) {
 | 
| +      delete test_server;
 | 
| +      return NULL;
 | 
| +    }
 | 
| +    return test_server;
 | 
| +  }
 | 
| +
 | 
| +  bool Init(const std::string& host_name, int port,
 | 
| +            const std::wstring& document_root) {
 | 
| +    std::wstring testserver_path;
 | 
| +    std::wstring test_data_directory;
 | 
| +#if defined(OS_WIN)
 | 
| +    std::wstring command_line;
 | 
| +#elif defined(OS_POSIX)
 | 
| +    std::vector<std::string> command_line;
 | 
| +#endif
 | 
| +
 | 
| +    // Set PYTHONPATH for tlslite and pyftpdlib
 | 
| +    SetPythonPaths();
 | 
| +    SetAppPath(kDefaultHostName, port, document_root, scheme(),
 | 
| +        &testserver_path, &test_data_directory);
 | 
| +    SetCommandLineOption(testserver_path, test_data_directory, &command_line);
 | 
| +    LaunchApp(command_line);
 | 
| +    if (!VerifyLaunchApp("hello.html")) {
 | 
| +      LOG(ERROR) << "Webserver not starting properly";
 | 
| +      return false;
 | 
| +    }
 | 
| +    return true;
 | 
| +  }
 | 
| +
 | 
| +  // A subclass may wish to send the request in a different manner
 | 
| +  virtual bool MakeGETRequest(const std::string& page_name) {
 | 
| +    const GURL& url = TestServerPage(page_name);
 | 
| +
 | 
| +    // Spin up a background thread for this request so that we have access to
 | 
| +    // an IO message loop, and in cases where this thread already has an IO
 | 
| +    // message loop, we also want to avoid spinning a nested message loop.
 | 
| +    SyncTestDelegate d;
 | 
| +    {
 | 
| +      base::Thread io_thread("MakeGETRequest");
 | 
| +      base::Thread::Options options;
 | 
| +      options.message_loop_type = MessageLoop::TYPE_IO;
 | 
| +      io_thread.StartWithOptions(options);
 | 
| +      io_thread.message_loop()->PostTask(FROM_HERE, NewRunnableFunction(
 | 
| +          &HTTPTestServer::StartGETRequest, url, &d));
 | 
| +      d.Wait();
 | 
| +    }
 | 
| +    return d.did_succeed();
 | 
| +  }
 | 
| +
 | 
|    static void StartGETRequest(const GURL& url, URLRequest::Delegate* delegate) {
 | 
|      URLRequest* request = new URLRequest(url, delegate);
 | 
|      request->set_context(new TestURLRequestContext());
 | 
| @@ -425,23 +456,212 @@
 | 
|      EXPECT_TRUE(request->is_pending());
 | 
|    }
 | 
|  
 | 
| -  std::string base_address_;
 | 
| -  std::wstring python_runtime_;
 | 
| -  base::ProcessHandle process_handle_;
 | 
| -  bool init_successful_;
 | 
| -  bool is_shutdown_;
 | 
| +  virtual ~HTTPTestServer() {
 | 
| +    // here we append the time to avoid problems where the kill page
 | 
| +    // is being cached rather than being executed on the server
 | 
| +    std::string page_name = StringPrintf("kill?%u",
 | 
| +        static_cast<int>(base::Time::Now().ToInternalValue()));
 | 
| +    int retry_count = 5;
 | 
| +    while (retry_count > 0) {
 | 
| +      bool r = MakeGETRequest(page_name);
 | 
| +      // BUG #1048625 causes the kill GET to fail.  For now we just retry.
 | 
| +      // Once the bug is fixed, we should remove the while loop and put back
 | 
| +      // the following DCHECK.
 | 
| +      // DCHECK(r);
 | 
| +      if (r)
 | 
| +        break;
 | 
| +      retry_count--;
 | 
| +    }
 | 
| +    // Make sure we were successfull in stopping the testserver.
 | 
| +    DCHECK(retry_count > 0);
 | 
| +  }
 | 
| +
 | 
| +  virtual std::string scheme() { return "http"; }
 | 
| +
 | 
| +#if defined(OS_WIN)
 | 
| +  virtual void SetCommandLineOption(const std::wstring& testserver_path,
 | 
| +                            const std::wstring& test_data_directory,
 | 
| +                            std::wstring* command_line ) {
 | 
| +    command_line->append(L"\"" + python_runtime_ + L"\" " + L"\"" +
 | 
| +    testserver_path + L"\" --port=" + UTF8ToWide(port_str_) +
 | 
| +    L" --data-dir=\"" + test_data_directory + L"\"");
 | 
| +  }
 | 
| +#elif defined(OS_POSIX)
 | 
| +  virtual void SetCommandLineOption(const std::wstring& testserver_path,
 | 
| +                            const std::wstring& test_data_directory,
 | 
| +                            std::vector<std::string>* command_line) {
 | 
| +    command_line->push_back("python");
 | 
| +    command_line->push_back(WideToUTF8(testserver_path));
 | 
| +    command_line->push_back("--port=" + port_str_);
 | 
| +    command_line->push_back("--data-dir=" + WideToUTF8(test_data_directory));
 | 
| +  }
 | 
| +#endif
 | 
|  };
 | 
|  
 | 
| -class HTTPSTestServer : public TestServer {
 | 
| +class HTTPSTestServer : public HTTPTestServer {
 | 
| + protected:
 | 
| +  explicit HTTPSTestServer(const std::wstring& cert_path)
 | 
| +      : cert_path_(cert_path) {
 | 
| +  }
 | 
| +
 | 
|   public:
 | 
| -   HTTPSTestServer(const std::string& host_name, int port,
 | 
| -                   const std::wstring& document_root,
 | 
| -                   const std::wstring& cert_path) : TestServer(ManualInit()) {
 | 
| -    Init(host_name, port, document_root, cert_path);
 | 
| +  static HTTPSTestServer* CreateServer(const std::string& host_name, int port,
 | 
| +                                       const std::wstring& document_root,
 | 
| +                                       const std::wstring& cert_path) {
 | 
| +    HTTPSTestServer* test_server = new HTTPSTestServer(cert_path);
 | 
| +    if (!test_server->Init(host_name, port, document_root)) {
 | 
| +      delete test_server;
 | 
| +      return NULL;
 | 
| +    }
 | 
| +    return test_server;
 | 
|    }
 | 
|  
 | 
| -  virtual std::string scheme() { return std::string("https"); }
 | 
| +#if defined(OS_WIN)
 | 
| +  virtual void SetCommandLineOption(const std::wstring& testserver_path,
 | 
| +                            const std::wstring& test_data_directory,
 | 
| +                            std::wstring* command_line ) {
 | 
| +    command_line->append(L"\"" + python_runtime_ + L"\" " + L"\"" +
 | 
| +    testserver_path + L"\"" + L" --port=" +
 | 
| +    UTF8ToWide(port_str_) + L" --data-dir=\"" +
 | 
| +    test_data_directory + L"\"");
 | 
| +    if (!cert_path_.empty()) {
 | 
| +      command_line->append(L" --https=\"");
 | 
| +      command_line->append(cert_path_);
 | 
| +      command_line->append(L"\"");
 | 
| +    }
 | 
| +  }
 | 
| +#elif defined(OS_POSIX)
 | 
| +  virtual void SetCommandLineOption(const std::wstring& testserver_path,
 | 
| +                            const std::wstring& test_data_directory,
 | 
| +                            std::vector<std::string>* command_line) {
 | 
| +    command_line->push_back("python");
 | 
| +    command_line->push_back(WideToUTF8(testserver_path));
 | 
| +    command_line->push_back("--port=" + port_str_);
 | 
| +    command_line->push_back("--data-dir=" + WideToUTF8(test_data_directory));
 | 
| +    if (!cert_path_.empty())
 | 
| +      command_line->push_back("--https=" + WideToUTF8(cert_path_));
 | 
| +}
 | 
| +#endif
 | 
| +
 | 
| +  virtual std::string scheme() { return "https"; }
 | 
| +
 | 
| +  virtual ~HTTPSTestServer() {
 | 
| +  }
 | 
| +
 | 
| + protected:
 | 
| +  std::wstring cert_path_;
 | 
|  };
 | 
|  
 | 
| +
 | 
| +class FTPTestServer : public BaseTestServer {
 | 
| + protected:
 | 
| +  FTPTestServer() {
 | 
| +  }
 | 
| +
 | 
| + public:
 | 
| +  FTPTestServer(const std::string& url_user, const std::string& url_password) {
 | 
| +    url_user_ = url_user;
 | 
| +    url_password_ = url_password;
 | 
| +  }
 | 
| +
 | 
| +  static FTPTestServer* CreateServer(const std::wstring& document_root) {
 | 
| +    FTPTestServer* test_server = new FTPTestServer();
 | 
| +    if (!test_server->Init(kDefaultHostName, kFTPDefaultPort, document_root)) {
 | 
| +      delete test_server;
 | 
| +      return NULL;
 | 
| +    }
 | 
| +    return test_server;
 | 
| +  }
 | 
| +
 | 
| +  static FTPTestServer* CreateServer(const std::wstring& document_root,
 | 
| +                                     const std::string& url_user,
 | 
| +                                     const std::string& url_password) {
 | 
| +    FTPTestServer* test_server = new FTPTestServer(url_user, url_password);
 | 
| +    if (!test_server->Init(kDefaultHostName, kFTPDefaultPort, document_root)) {
 | 
| +      delete test_server;
 | 
| +      return NULL;
 | 
| +    }
 | 
| +    return test_server;
 | 
| +  }
 | 
| +
 | 
| +  bool Init(const std::string& host_name, int port,
 | 
| +            const std::wstring& document_root) {
 | 
| +    std::wstring testserver_path;
 | 
| +    std::wstring test_data_directory;
 | 
| +
 | 
| +#if defined(OS_WIN)
 | 
| +    std::wstring command_line;
 | 
| +#elif defined(OS_POSIX)
 | 
| +    std::vector<std::string> command_line;
 | 
| +#endif
 | 
| +
 | 
| +    // Set PYTHONPATH for tlslite and pyftpdlib
 | 
| +    SetPythonPaths();
 | 
| +    SetAppPath(kDefaultHostName, port, document_root, scheme(),
 | 
| +        &testserver_path, &test_data_directory);
 | 
| +    SetCommandLineOption(testserver_path, test_data_directory, &command_line);
 | 
| +    LaunchApp(command_line);
 | 
| +    if (!VerifyLaunchApp("/LICENSE")) {
 | 
| +      LOG(ERROR) << "FTPServer not starting properly.";
 | 
| +      return false;
 | 
| +    }
 | 
| +    return true;
 | 
| +  }
 | 
| +
 | 
| +  virtual ~FTPTestServer() {
 | 
| +    int retry_count = 5;
 | 
| +    while (retry_count > 0) {
 | 
| +      bool r = MakeGETRequest("kill");
 | 
| +      // BUG #1048625 causes the kill GET to fail.  For now we just retry.
 | 
| +      // Once the bug is fixed, we should remove the while loop and put back
 | 
| +      // the following DCHECK.
 | 
| +      // DCHECK(r);
 | 
| +      if (r)
 | 
| +        break;
 | 
| +      retry_count--;
 | 
| +    }
 | 
| +    // Make sure we were successfull in stopping the testserver.
 | 
| +    DCHECK(retry_count > 0);
 | 
| +  }
 | 
| +
 | 
| +  virtual std::string scheme() { return "ftp"; }
 | 
| +
 | 
| +  virtual bool MakeGETRequest(const std::string& page_name) {
 | 
| +    const GURL& url = TestServerPage(page_name);
 | 
| +    TestDelegate d;
 | 
| +    URLRequest request(url, &d);
 | 
| +    request.set_context(new TestURLRequestContext());
 | 
| +    request.set_method("GET");
 | 
| +    request.Start();
 | 
| +    EXPECT_TRUE(request.is_pending());
 | 
| +
 | 
| +    MessageLoop::current()->Run();
 | 
| +    if (request.is_pending())
 | 
| +      return false;
 | 
| +
 | 
| +    return true;
 | 
| +  }
 | 
| +
 | 
| +#if defined(OS_WIN)
 | 
| +  virtual void SetCommandLineOption(const std::wstring& testserver_path,
 | 
| +                            const std::wstring& test_data_directory,
 | 
| +                            std::wstring* command_line ) {
 | 
| +    command_line->append(L"\"" + python_runtime_ + L"\" " + L"\"" +
 | 
| +    testserver_path + L"\"" + L" -f " + L" --port=" +
 | 
| +    UTF8ToWide(port_str_) + L" --data-dir=\"" +
 | 
| +    test_data_directory + L"\"");
 | 
| +  }
 | 
| +#elif defined(OS_POSIX)
 | 
| +  virtual void SetCommandLineOption(const std::wstring& testserver_path,
 | 
| +                            const std::wstring& test_data_directory,
 | 
| +                            std::vector<std::string>* command_line) {
 | 
| +    command_line->push_back("python");
 | 
| +    command_line->push_back(" -f ");
 | 
| +    command_line->push_back("--data-dir=" + WideToUTF8(test_data_directory));
 | 
| +    command_line->push_back("--port=" + port_str_);
 | 
| +    command_line->push_back("--data-dir=" + WideToUTF8(test_data_directory));
 | 
| +  }
 | 
| +#endif
 | 
| +};
 | 
| +
 | 
|  #endif  // NET_URL_REQUEST_URL_REQUEST_UNITTEST_H_
 | 
| -
 | 
| 
 |