Home | History | Annotate | Download | only in url_request
      1 // Copyright (c) 2009 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #ifndef NET_URL_REQUEST_URL_REQUEST_UNITTEST_H_
      6 #define NET_URL_REQUEST_URL_REQUEST_UNITTEST_H_
      7 
      8 #include <stdlib.h>
      9 
     10 #include <sstream>
     11 #include <string>
     12 #include <vector>
     13 
     14 #include "base/file_path.h"
     15 #include "base/file_util.h"
     16 #include "base/logging.h"
     17 #include "base/message_loop.h"
     18 #include "base/path_service.h"
     19 #include "base/process_util.h"
     20 #include "base/string_util.h"
     21 #include "base/thread.h"
     22 #include "base/time.h"
     23 #include "base/waitable_event.h"
     24 #include "net/base/cookie_monster.h"
     25 #include "net/base/cookie_policy.h"
     26 #include "net/base/host_resolver.h"
     27 #include "net/base/io_buffer.h"
     28 #include "net/base/net_errors.h"
     29 #include "net/base/net_test_constants.h"
     30 #include "net/base/ssl_config_service_defaults.h"
     31 #include "net/disk_cache/disk_cache.h"
     32 #include "net/ftp/ftp_network_layer.h"
     33 #include "net/http/http_cache.h"
     34 #include "net/http/http_network_layer.h"
     35 #include "net/socket/ssl_test_util.h"
     36 #include "net/url_request/url_request.h"
     37 #include "net/url_request/url_request_context.h"
     38 #include "net/proxy/proxy_service.h"
     39 #include "testing/gtest/include/gtest/gtest.h"
     40 #include "googleurl/src/url_util.h"
     41 
     42 const int kHTTPDefaultPort = 1337;
     43 const int kFTPDefaultPort = 1338;
     44 
     45 const std::string kDefaultHostName("localhost");
     46 
     47 using base::TimeDelta;
     48 
     49 //-----------------------------------------------------------------------------
     50 
     51 class TestCookiePolicy : public net::CookiePolicy {
     52  public:
     53   enum Options {
     54     NO_GET_COOKIES = 1 << 0,
     55     NO_SET_COOKIE  = 1 << 1,
     56     ASYNC          = 1 << 2
     57   };
     58 
     59   explicit TestCookiePolicy(int options_bit_mask)
     60       : ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)),
     61         options_(options_bit_mask),
     62         callback_(NULL) {
     63   }
     64 
     65   virtual int CanGetCookies(const GURL& url, const GURL& first_party,
     66                             net::CompletionCallback* callback) {
     67     if ((options_ & ASYNC) && callback) {
     68       callback_ = callback;
     69       MessageLoop::current()->PostTask(FROM_HERE,
     70           method_factory_.NewRunnableMethod(
     71               &TestCookiePolicy::DoGetCookiesPolicy, url, first_party));
     72       return net::ERR_IO_PENDING;
     73     }
     74 
     75     if (options_ & NO_GET_COOKIES)
     76       return net::ERR_ACCESS_DENIED;
     77 
     78     return net::OK;
     79   }
     80 
     81   virtual int CanSetCookie(const GURL& url, const GURL& first_party,
     82                            const std::string& cookie_line,
     83                            net::CompletionCallback* callback) {
     84     if ((options_ & ASYNC) && callback) {
     85       callback_ = callback;
     86       MessageLoop::current()->PostTask(FROM_HERE,
     87           method_factory_.NewRunnableMethod(
     88               &TestCookiePolicy::DoSetCookiePolicy, url, first_party,
     89               cookie_line));
     90       return net::ERR_IO_PENDING;
     91     }
     92 
     93     if (options_ & NO_SET_COOKIE)
     94       return net::ERR_ACCESS_DENIED;
     95 
     96     return net::OK;
     97   }
     98 
     99  private:
    100   void DoGetCookiesPolicy(const GURL& url, const GURL& first_party) {
    101     int policy = CanGetCookies(url, first_party, NULL);
    102 
    103     DCHECK(callback_);
    104     net::CompletionCallback* callback = callback_;
    105     callback_ = NULL;
    106     callback->Run(policy);
    107   }
    108 
    109   void DoSetCookiePolicy(const GURL& url, const GURL& first_party,
    110                          const std::string& cookie_line) {
    111     int policy = CanSetCookie(url, first_party, cookie_line, NULL);
    112 
    113     DCHECK(callback_);
    114     net::CompletionCallback* callback = callback_;
    115     callback_ = NULL;
    116     callback->Run(policy);
    117   }
    118 
    119   ScopedRunnableMethodFactory<TestCookiePolicy> method_factory_;
    120   int options_;
    121   net::CompletionCallback* callback_;
    122 };
    123 
    124 //-----------------------------------------------------------------------------
    125 
    126 class TestURLRequestContext : public URLRequestContext {
    127  public:
    128   TestURLRequestContext() {
    129     host_resolver_ = net::CreateSystemHostResolver(NULL);
    130     proxy_service_ = net::ProxyService::CreateNull();
    131     Init();
    132   }
    133 
    134   explicit TestURLRequestContext(const std::string& proxy) {
    135     host_resolver_ = net::CreateSystemHostResolver(NULL);
    136     net::ProxyConfig proxy_config;
    137     proxy_config.proxy_rules.ParseFromString(proxy);
    138     proxy_service_ = net::ProxyService::CreateFixed(proxy_config);
    139     Init();
    140   }
    141 
    142   void set_cookie_policy(net::CookiePolicy* policy) {
    143     cookie_policy_ = policy;
    144   }
    145 
    146  protected:
    147   virtual ~TestURLRequestContext() {
    148     delete ftp_transaction_factory_;
    149     delete http_transaction_factory_;
    150   }
    151 
    152  private:
    153   void Init() {
    154     ftp_transaction_factory_ = new net::FtpNetworkLayer(host_resolver_);
    155     ssl_config_service_ = new net::SSLConfigServiceDefaults;
    156     http_transaction_factory_ =
    157         new net::HttpCache(
    158           net::HttpNetworkLayer::CreateFactory(NULL, host_resolver_,
    159                                                proxy_service_,
    160                                                ssl_config_service_),
    161           disk_cache::CreateInMemoryCacheBackend(0));
    162     // In-memory cookie store.
    163     cookie_store_ = new net::CookieMonster();
    164     accept_language_ = "en-us,fr";
    165     accept_charset_ = "iso-8859-1,*,utf-8";
    166   }
    167 };
    168 
    169 // TODO(phajdan.jr): Migrate callers to the new name and remove the typedef.
    170 typedef TestURLRequestContext URLRequestTestContext;
    171 
    172 //-----------------------------------------------------------------------------
    173 
    174 class TestURLRequest : public URLRequest {
    175  public:
    176   TestURLRequest(const GURL& url, Delegate* delegate)
    177       : URLRequest(url, delegate) {
    178     set_context(new TestURLRequestContext());
    179   }
    180 };
    181 
    182 //-----------------------------------------------------------------------------
    183 
    184 class TestDelegate : public URLRequest::Delegate {
    185  public:
    186   TestDelegate()
    187       : cancel_in_rr_(false),
    188         cancel_in_rs_(false),
    189         cancel_in_rd_(false),
    190         cancel_in_rd_pending_(false),
    191         quit_on_complete_(true),
    192         quit_on_redirect_(false),
    193         allow_certificate_errors_(false),
    194         response_started_count_(0),
    195         received_bytes_count_(0),
    196         received_redirect_count_(0),
    197         received_data_before_response_(false),
    198         request_failed_(false),
    199         have_certificate_errors_(false),
    200         buf_(new net::IOBuffer(kBufferSize)) {
    201   }
    202 
    203   virtual void OnReceivedRedirect(URLRequest* request, const GURL& new_url,
    204                                   bool* defer_redirect) {
    205     received_redirect_count_++;
    206     if (quit_on_redirect_) {
    207       *defer_redirect = true;
    208       MessageLoop::current()->Quit();
    209     } else if (cancel_in_rr_) {
    210       request->Cancel();
    211     }
    212   }
    213 
    214   virtual void OnResponseStarted(URLRequest* request) {
    215     // It doesn't make sense for the request to have IO pending at this point.
    216     DCHECK(!request->status().is_io_pending());
    217 
    218     response_started_count_++;
    219     if (cancel_in_rs_) {
    220       request->Cancel();
    221       OnResponseCompleted(request);
    222     } else if (!request->status().is_success()) {
    223       DCHECK(request->status().status() == URLRequestStatus::FAILED ||
    224              request->status().status() == URLRequestStatus::CANCELED);
    225       request_failed_ = true;
    226       OnResponseCompleted(request);
    227     } else {
    228       // Initiate the first read.
    229       int bytes_read = 0;
    230       if (request->Read(buf_, kBufferSize, &bytes_read))
    231         OnReadCompleted(request, bytes_read);
    232       else if (!request->status().is_io_pending())
    233         OnResponseCompleted(request);
    234     }
    235   }
    236 
    237   virtual void OnReadCompleted(URLRequest* request, int bytes_read) {
    238     // It doesn't make sense for the request to have IO pending at this point.
    239     DCHECK(!request->status().is_io_pending());
    240 
    241     if (response_started_count_ == 0)
    242       received_data_before_response_ = true;
    243 
    244     if (cancel_in_rd_)
    245       request->Cancel();
    246 
    247     if (bytes_read >= 0) {
    248       // There is data to read.
    249       received_bytes_count_ += bytes_read;
    250 
    251       // consume the data
    252       data_received_.append(buf_->data(), bytes_read);
    253     }
    254 
    255     // If it was not end of stream, request to read more.
    256     if (request->status().is_success() && bytes_read > 0) {
    257       bytes_read = 0;
    258       while (request->Read(buf_, kBufferSize, &bytes_read)) {
    259         if (bytes_read > 0) {
    260           data_received_.append(buf_->data(), bytes_read);
    261           received_bytes_count_ += bytes_read;
    262         } else {
    263           break;
    264         }
    265       }
    266     }
    267     if (!request->status().is_io_pending())
    268       OnResponseCompleted(request);
    269     else if (cancel_in_rd_pending_)
    270       request->Cancel();
    271   }
    272 
    273   virtual void OnResponseCompleted(URLRequest* request) {
    274     if (quit_on_complete_)
    275       MessageLoop::current()->Quit();
    276   }
    277 
    278   void OnAuthRequired(URLRequest* request, net::AuthChallengeInfo* auth_info) {
    279     if (!username_.empty() || !password_.empty()) {
    280       request->SetAuth(username_, password_);
    281     } else {
    282       request->CancelAuth();
    283     }
    284   }
    285 
    286   virtual void OnSSLCertificateError(URLRequest* request,
    287                                      int cert_error,
    288                                      net::X509Certificate* cert) {
    289     // The caller can control whether it needs all SSL requests to go through,
    290     // independent of any possible errors, or whether it wants SSL errors to
    291     // cancel the request.
    292     have_certificate_errors_ = true;
    293     if (allow_certificate_errors_)
    294       request->ContinueDespiteLastError();
    295     else
    296       request->Cancel();
    297   }
    298 
    299   void set_cancel_in_received_redirect(bool val) { cancel_in_rr_ = val; }
    300   void set_cancel_in_response_started(bool val) { cancel_in_rs_ = val; }
    301   void set_cancel_in_received_data(bool val) { cancel_in_rd_ = val; }
    302   void set_cancel_in_received_data_pending(bool val) {
    303     cancel_in_rd_pending_ = val;
    304   }
    305   void set_quit_on_complete(bool val) { quit_on_complete_ = val; }
    306   void set_quit_on_redirect(bool val) { quit_on_redirect_ = val; }
    307   void set_allow_certificate_errors(bool val) {
    308     allow_certificate_errors_ = val;
    309   }
    310   void set_username(const std::wstring& u) { username_ = u; }
    311   void set_password(const std::wstring& p) { password_ = p; }
    312 
    313   // query state
    314   const std::string& data_received() const { return data_received_; }
    315   int bytes_received() const { return static_cast<int>(data_received_.size()); }
    316   int response_started_count() const { return response_started_count_; }
    317   int received_redirect_count() const { return received_redirect_count_; }
    318   bool received_data_before_response() const {
    319     return received_data_before_response_;
    320   }
    321   bool request_failed() const { return request_failed_; }
    322   bool have_certificate_errors() const { return have_certificate_errors_; }
    323 
    324  private:
    325   static const int kBufferSize = 4096;
    326   // options for controlling behavior
    327   bool cancel_in_rr_;
    328   bool cancel_in_rs_;
    329   bool cancel_in_rd_;
    330   bool cancel_in_rd_pending_;
    331   bool quit_on_complete_;
    332   bool quit_on_redirect_;
    333   bool allow_certificate_errors_;
    334 
    335   std::wstring username_;
    336   std::wstring password_;
    337 
    338   // tracks status of callbacks
    339   int response_started_count_;
    340   int received_bytes_count_;
    341   int received_redirect_count_;
    342   bool received_data_before_response_;
    343   bool request_failed_;
    344   bool have_certificate_errors_;
    345   std::string data_received_;
    346 
    347   // our read buffer
    348   scoped_refptr<net::IOBuffer> buf_;
    349 };
    350 
    351 //-----------------------------------------------------------------------------
    352 
    353 // This object bounds the lifetime of an external python-based HTTP/FTP server
    354 // that can provide various responses useful for testing.
    355 class BaseTestServer : public base::RefCounted<BaseTestServer> {
    356  protected:
    357   BaseTestServer() {}
    358   BaseTestServer(int connection_attempts, int connection_timeout)
    359       : launcher_(connection_attempts, connection_timeout) {}
    360 
    361  public:
    362   void set_forking(bool forking) {
    363     launcher_.set_forking(forking);
    364   }
    365 
    366   // Used with e.g. HTTPTestServer::SendQuit()
    367   bool WaitToFinish(int milliseconds) {
    368     return launcher_.WaitToFinish(milliseconds);
    369   }
    370 
    371   bool Stop() {
    372     return launcher_.Stop();
    373   }
    374 
    375   GURL TestServerPage(const std::string& base_address,
    376       const std::string& path) {
    377     return GURL(base_address + path);
    378   }
    379 
    380   GURL TestServerPage(const std::string& path) {
    381     // TODO(phajdan.jr): Check for problems with IPv6.
    382     return GURL(scheme_ + "://" + host_name_ + ":" + port_str_ + "/" + path);
    383   }
    384 
    385   GURL TestServerPage(const std::string& path,
    386                       const std::string& user,
    387                       const std::string& password) {
    388     // TODO(phajdan.jr): Check for problems with IPv6.
    389 
    390     if (password.empty())
    391       return GURL(scheme_ + "://" + user + "@" +
    392                   host_name_ + ":" + port_str_ + "/" + path);
    393 
    394     return GURL(scheme_ + "://" + user + ":" + password +
    395                 "@" + host_name_ + ":" + port_str_ + "/" + path);
    396   }
    397 
    398   // Deprecated in favor of TestServerPage.
    399   // TODO(phajdan.jr): Remove TestServerPageW.
    400   GURL TestServerPageW(const std::wstring& path) {
    401     return TestServerPage(WideToUTF8(path));
    402   }
    403 
    404   virtual bool MakeGETRequest(const std::string& page_name) = 0;
    405 
    406   FilePath GetDataDirectory() {
    407     return launcher_.GetDocumentRootPath();
    408   }
    409 
    410  protected:
    411   friend class base::RefCounted<BaseTestServer>;
    412   virtual ~BaseTestServer() { }
    413 
    414   bool Start(net::TestServerLauncher::Protocol protocol,
    415              const std::string& host_name, int port,
    416              const FilePath& document_root,
    417              const FilePath& cert_path,
    418              const std::wstring& file_root_url) {
    419     if (!launcher_.Start(protocol,
    420         host_name, port, document_root, cert_path, file_root_url))
    421       return false;
    422 
    423     if (protocol == net::TestServerLauncher::ProtoFTP)
    424       scheme_ = "ftp";
    425     else
    426       scheme_ = "http";
    427     if (!cert_path.empty())
    428       scheme_.push_back('s');
    429 
    430     host_name_ = host_name;
    431     port_str_ = IntToString(port);
    432     return true;
    433   }
    434 
    435   // Used by MakeGETRequest to implement sync load behavior.
    436   class SyncTestDelegate : public TestDelegate {
    437    public:
    438     SyncTestDelegate() : event_(false, false), success_(false) {
    439     }
    440     virtual void OnResponseCompleted(URLRequest* request) {
    441       MessageLoop::current()->DeleteSoon(FROM_HERE, request);
    442       success_ = request->status().is_success();
    443       event_.Signal();
    444     }
    445     bool Wait(int64 secs) {
    446       TimeDelta td = TimeDelta::FromSeconds(secs);
    447       if (event_.TimedWait(td))
    448         return true;
    449       return false;
    450     }
    451     bool did_succeed() const { return success_; }
    452    private:
    453     base::WaitableEvent event_;
    454     bool success_;
    455     DISALLOW_COPY_AND_ASSIGN(SyncTestDelegate);
    456   };
    457 
    458   net::TestServerLauncher launcher_;
    459   std::string scheme_;
    460   std::string host_name_;
    461   std::string port_str_;
    462 };
    463 
    464 //-----------------------------------------------------------------------------
    465 
    466 // HTTP
    467 class HTTPTestServer : public BaseTestServer {
    468  protected:
    469   explicit HTTPTestServer() : loop_(NULL) {
    470   }
    471 
    472   explicit HTTPTestServer(int connection_attempts, int connection_timeout)
    473       : BaseTestServer(connection_attempts, connection_timeout), loop_(NULL) {
    474   }
    475 
    476   virtual ~HTTPTestServer() {}
    477 
    478  public:
    479   // Creates and returns a new HTTPTestServer. If |loop| is non-null, requests
    480   // are serviced on it, otherwise a new thread and message loop are created.
    481   static scoped_refptr<HTTPTestServer> CreateServer(
    482       const std::wstring& document_root,
    483       MessageLoop* loop) {
    484     return CreateServerWithFileRootURL(document_root, std::wstring(), loop);
    485   }
    486 
    487   static scoped_refptr<HTTPTestServer> CreateServer(
    488       const std::wstring& document_root,
    489       MessageLoop* loop,
    490       int connection_attempts,
    491       int connection_timeout) {
    492     return CreateServerWithFileRootURL(document_root, std::wstring(), loop,
    493                                        connection_attempts,
    494                                        connection_timeout);
    495   }
    496 
    497   static scoped_refptr<HTTPTestServer> CreateServerWithFileRootURL(
    498       const std::wstring& document_root,
    499       const std::wstring& file_root_url,
    500       MessageLoop* loop) {
    501     return CreateServerWithFileRootURL(document_root, file_root_url, loop,
    502                                        net::kDefaultTestConnectionAttempts,
    503                                        net::kDefaultTestConnectionTimeout);
    504   }
    505 
    506   static scoped_refptr<HTTPTestServer> CreateForkingServer(
    507       const std::wstring& document_root) {
    508     scoped_refptr<HTTPTestServer> test_server =
    509         new HTTPTestServer(net::kDefaultTestConnectionAttempts,
    510                            net::kDefaultTestConnectionTimeout);
    511     test_server->set_forking(true);
    512     FilePath no_cert;
    513     FilePath docroot = FilePath::FromWStringHack(document_root);
    514     if (!StartTestServer(test_server.get(), docroot, no_cert, std::wstring()))
    515       return NULL;
    516     return test_server;
    517   }
    518 
    519   static scoped_refptr<HTTPTestServer> CreateServerWithFileRootURL(
    520       const std::wstring& document_root,
    521       const std::wstring& file_root_url,
    522       MessageLoop* loop,
    523       int connection_attempts,
    524       int connection_timeout) {
    525     scoped_refptr<HTTPTestServer> test_server =
    526         new HTTPTestServer(connection_attempts, connection_timeout);
    527     test_server->loop_ = loop;
    528     FilePath no_cert;
    529     FilePath docroot = FilePath::FromWStringHack(document_root);
    530     if (!StartTestServer(test_server.get(), docroot, no_cert, file_root_url))
    531       return NULL;
    532     return test_server;
    533   }
    534 
    535   static bool StartTestServer(HTTPTestServer* server,
    536                               const FilePath& document_root,
    537                               const FilePath& cert_path,
    538                               const std::wstring& file_root_url) {
    539     return server->Start(net::TestServerLauncher::ProtoHTTP, kDefaultHostName,
    540                          kHTTPDefaultPort, document_root, cert_path,
    541                          file_root_url);
    542   }
    543 
    544   // A subclass may wish to send the request in a different manner
    545   virtual bool MakeGETRequest(const std::string& page_name) {
    546     const GURL& url = TestServerPage(page_name);
    547 
    548     // Spin up a background thread for this request so that we have access to
    549     // an IO message loop, and in cases where this thread already has an IO
    550     // message loop, we also want to avoid spinning a nested message loop.
    551     SyncTestDelegate d;
    552     {
    553       MessageLoop* loop = loop_;
    554       scoped_ptr<base::Thread> io_thread;
    555 
    556       if (!loop) {
    557         io_thread.reset(new base::Thread("MakeGETRequest"));
    558         base::Thread::Options options;
    559         options.message_loop_type = MessageLoop::TYPE_IO;
    560         io_thread->StartWithOptions(options);
    561         loop = io_thread->message_loop();
    562       }
    563       loop->PostTask(FROM_HERE, NewRunnableFunction(
    564             &HTTPTestServer::StartGETRequest, url, &d));
    565 
    566       // Build bot wait for only 300 seconds we should ensure wait do not take
    567       // more than 300 seconds
    568       if (!d.Wait(250))
    569         return false;
    570     }
    571     return d.did_succeed();
    572   }
    573 
    574   static void StartGETRequest(const GURL& url, URLRequest::Delegate* delegate) {
    575     URLRequest* request = new URLRequest(url, delegate);
    576     request->set_context(new TestURLRequestContext());
    577     request->set_method("GET");
    578     request->Start();
    579     EXPECT_TRUE(request->is_pending());
    580   }
    581 
    582   // Some tests use browser javascript to fetch a 'kill' url that causes
    583   // the server to exit by itself (rather than letting TestServerLauncher's
    584   // destructor kill it).
    585   // This method does the same thing so we can unit test that mechanism.
    586   // You can then use WaitToFinish() to sleep until the server terminates.
    587   void SendQuit() {
    588     // Append the time to avoid problems where the kill page
    589     // is being cached rather than being executed on the server
    590     std::string page_name = StringPrintf("kill?%u",
    591         static_cast<int>(base::Time::Now().ToInternalValue()));
    592     int retry_count = 5;
    593     while (retry_count > 0) {
    594       bool r = MakeGETRequest(page_name);
    595       // BUG #1048625 causes the kill GET to fail.  For now we just retry.
    596       // Once the bug is fixed, we should remove the while loop and put back
    597       // the following DCHECK.
    598       // DCHECK(r);
    599       if (r)
    600         break;
    601       retry_count--;
    602     }
    603     // Make sure we were successful in stopping the testserver.
    604     DCHECK_GT(retry_count, 0);
    605   }
    606 
    607   virtual std::string scheme() { return "http"; }
    608 
    609  private:
    610   // If non-null a background thread isn't created and instead this message loop
    611   // is used.
    612   MessageLoop* loop_;
    613 };
    614 
    615 //-----------------------------------------------------------------------------
    616 
    617 class HTTPSTestServer : public HTTPTestServer {
    618  protected:
    619   explicit HTTPSTestServer() {
    620   }
    621 
    622  public:
    623   // Create a server with a valid certificate
    624   // TODO(dkegel): HTTPSTestServer should not require an instance to specify
    625   // stock test certificates
    626   static scoped_refptr<HTTPSTestServer> CreateGoodServer(
    627       const std::wstring& document_root) {
    628     scoped_refptr<HTTPSTestServer> test_server = new HTTPSTestServer();
    629     FilePath docroot = FilePath::FromWStringHack(document_root);
    630     FilePath certpath = test_server->launcher_.GetOKCertPath();
    631     if (!test_server->Start(net::TestServerLauncher::ProtoHTTP,
    632         net::TestServerLauncher::kHostName,
    633         net::TestServerLauncher::kOKHTTPSPort,
    634         docroot, certpath, std::wstring())) {
    635       return NULL;
    636     }
    637     return test_server;
    638   }
    639 
    640   // Create a server with an up to date certificate for the wrong hostname
    641   // for this host
    642   static scoped_refptr<HTTPSTestServer> CreateMismatchedServer(
    643       const std::wstring& document_root) {
    644     scoped_refptr<HTTPSTestServer> test_server = new HTTPSTestServer();
    645     FilePath docroot = FilePath::FromWStringHack(document_root);
    646     FilePath certpath = test_server->launcher_.GetOKCertPath();
    647     if (!test_server->Start(net::TestServerLauncher::ProtoHTTP,
    648         net::TestServerLauncher::kMismatchedHostName,
    649         net::TestServerLauncher::kOKHTTPSPort,
    650         docroot, certpath, std::wstring())) {
    651       return NULL;
    652     }
    653     return test_server;
    654   }
    655 
    656   // Create a server with an expired certificate
    657   static scoped_refptr<HTTPSTestServer> CreateExpiredServer(
    658       const std::wstring& document_root) {
    659     scoped_refptr<HTTPSTestServer> test_server = new HTTPSTestServer();
    660     FilePath docroot = FilePath::FromWStringHack(document_root);
    661     FilePath certpath = test_server->launcher_.GetExpiredCertPath();
    662     if (!test_server->Start(net::TestServerLauncher::ProtoHTTP,
    663         net::TestServerLauncher::kHostName,
    664         net::TestServerLauncher::kBadHTTPSPort,
    665         docroot, certpath, std::wstring())) {
    666       return NULL;
    667     }
    668     return test_server;
    669   }
    670 
    671   // Create a server with an arbitrary certificate
    672   static scoped_refptr<HTTPSTestServer> CreateServer(
    673       const std::string& host_name, int port,
    674       const std::wstring& document_root,
    675       const std::wstring& cert_path) {
    676     scoped_refptr<HTTPSTestServer> test_server = new HTTPSTestServer();
    677     FilePath docroot = FilePath::FromWStringHack(document_root);
    678     FilePath certpath = FilePath::FromWStringHack(cert_path);
    679     if (!test_server->Start(net::TestServerLauncher::ProtoHTTP,
    680         host_name, port, docroot, certpath, std::wstring())) {
    681       return NULL;
    682     }
    683     return test_server;
    684   }
    685 
    686  protected:
    687   std::wstring cert_path_;
    688 
    689  private:
    690   virtual ~HTTPSTestServer() {}
    691 };
    692 
    693 //-----------------------------------------------------------------------------
    694 
    695 class FTPTestServer : public BaseTestServer {
    696  public:
    697   FTPTestServer() {
    698   }
    699 
    700   static scoped_refptr<FTPTestServer> CreateServer(
    701       const std::wstring& document_root) {
    702     scoped_refptr<FTPTestServer> test_server = new FTPTestServer();
    703     FilePath docroot = FilePath::FromWStringHack(document_root);
    704     FilePath no_cert;
    705     if (!test_server->Start(net::TestServerLauncher::ProtoFTP,
    706         kDefaultHostName, kFTPDefaultPort, docroot, no_cert, std::wstring())) {
    707       return NULL;
    708     }
    709     return test_server;
    710   }
    711 
    712   virtual bool MakeGETRequest(const std::string& page_name) {
    713     const GURL& url = TestServerPage(page_name);
    714     TestDelegate d;
    715     URLRequest request(url, &d);
    716     request.set_context(new TestURLRequestContext());
    717     request.set_method("GET");
    718     request.Start();
    719     EXPECT_TRUE(request.is_pending());
    720 
    721     MessageLoop::current()->Run();
    722     if (request.is_pending())
    723       return false;
    724 
    725     return true;
    726   }
    727 
    728  private:
    729   ~FTPTestServer() {}
    730 };
    731 
    732 #endif  // NET_URL_REQUEST_URL_REQUEST_UNITTEST_H_
    733