• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
TestCookiePolicy(int options_bit_mask)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 
CanGetCookies(const GURL & url,const GURL & first_party,net::CompletionCallback * callback)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 
CanSetCookie(const GURL & url,const GURL & first_party,const std::string & cookie_line,net::CompletionCallback * callback)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:
DoGetCookiesPolicy(const GURL & url,const GURL & first_party)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 
DoSetCookiePolicy(const GURL & url,const GURL & first_party,const std::string & cookie_line)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:
TestURLRequestContext()128   TestURLRequestContext() {
129     host_resolver_ = net::CreateSystemHostResolver(NULL);
130     proxy_service_ = net::ProxyService::CreateNull();
131     Init();
132   }
133 
TestURLRequestContext(const std::string & proxy)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 
set_cookie_policy(net::CookiePolicy * policy)142   void set_cookie_policy(net::CookiePolicy* policy) {
143     cookie_policy_ = policy;
144   }
145 
146  protected:
~TestURLRequestContext()147   virtual ~TestURLRequestContext() {
148     delete ftp_transaction_factory_;
149     delete http_transaction_factory_;
150   }
151 
152  private:
Init()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:
TestURLRequest(const GURL & url,Delegate * delegate)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:
TestDelegate()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 
OnReceivedRedirect(URLRequest * request,const GURL & new_url,bool * defer_redirect)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 
OnResponseStarted(URLRequest * request)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 
OnReadCompleted(URLRequest * request,int bytes_read)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 
OnResponseCompleted(URLRequest * request)273   virtual void OnResponseCompleted(URLRequest* request) {
274     if (quit_on_complete_)
275       MessageLoop::current()->Quit();
276   }
277 
OnAuthRequired(URLRequest * request,net::AuthChallengeInfo * auth_info)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 
OnSSLCertificateError(URLRequest * request,int cert_error,net::X509Certificate * cert)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 
set_cancel_in_received_redirect(bool val)299   void set_cancel_in_received_redirect(bool val) { cancel_in_rr_ = val; }
set_cancel_in_response_started(bool val)300   void set_cancel_in_response_started(bool val) { cancel_in_rs_ = val; }
set_cancel_in_received_data(bool val)301   void set_cancel_in_received_data(bool val) { cancel_in_rd_ = val; }
set_cancel_in_received_data_pending(bool val)302   void set_cancel_in_received_data_pending(bool val) {
303     cancel_in_rd_pending_ = val;
304   }
set_quit_on_complete(bool val)305   void set_quit_on_complete(bool val) { quit_on_complete_ = val; }
set_quit_on_redirect(bool val)306   void set_quit_on_redirect(bool val) { quit_on_redirect_ = val; }
set_allow_certificate_errors(bool val)307   void set_allow_certificate_errors(bool val) {
308     allow_certificate_errors_ = val;
309   }
set_username(const std::wstring & u)310   void set_username(const std::wstring& u) { username_ = u; }
set_password(const std::wstring & p)311   void set_password(const std::wstring& p) { password_ = p; }
312 
313   // query state
data_received()314   const std::string& data_received() const { return data_received_; }
bytes_received()315   int bytes_received() const { return static_cast<int>(data_received_.size()); }
response_started_count()316   int response_started_count() const { return response_started_count_; }
received_redirect_count()317   int received_redirect_count() const { return received_redirect_count_; }
received_data_before_response()318   bool received_data_before_response() const {
319     return received_data_before_response_;
320   }
request_failed()321   bool request_failed() const { return request_failed_; }
have_certificate_errors()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:
BaseTestServer()357   BaseTestServer() {}
BaseTestServer(int connection_attempts,int connection_timeout)358   BaseTestServer(int connection_attempts, int connection_timeout)
359       : launcher_(connection_attempts, connection_timeout) {}
360 
361  public:
set_forking(bool forking)362   void set_forking(bool forking) {
363     launcher_.set_forking(forking);
364   }
365 
366   // Used with e.g. HTTPTestServer::SendQuit()
WaitToFinish(int milliseconds)367   bool WaitToFinish(int milliseconds) {
368     return launcher_.WaitToFinish(milliseconds);
369   }
370 
Stop()371   bool Stop() {
372     return launcher_.Stop();
373   }
374 
TestServerPage(const std::string & base_address,const std::string & path)375   GURL TestServerPage(const std::string& base_address,
376       const std::string& path) {
377     return GURL(base_address + path);
378   }
379 
TestServerPage(const std::string & path)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 
TestServerPage(const std::string & path,const std::string & user,const std::string & password)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.
TestServerPageW(const std::wstring & path)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 
GetDataDirectory()406   FilePath GetDataDirectory() {
407     return launcher_.GetDocumentRootPath();
408   }
409 
410  protected:
411   friend class base::RefCounted<BaseTestServer>;
~BaseTestServer()412   virtual ~BaseTestServer() { }
413 
Start(net::TestServerLauncher::Protocol protocol,const std::string & host_name,int port,const FilePath & document_root,const FilePath & cert_path,const std::wstring & file_root_url)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:
SyncTestDelegate()438     SyncTestDelegate() : event_(false, false), success_(false) {
439     }
OnResponseCompleted(URLRequest * request)440     virtual void OnResponseCompleted(URLRequest* request) {
441       MessageLoop::current()->DeleteSoon(FROM_HERE, request);
442       success_ = request->status().is_success();
443       event_.Signal();
444     }
Wait(int64 secs)445     bool Wait(int64 secs) {
446       TimeDelta td = TimeDelta::FromSeconds(secs);
447       if (event_.TimedWait(td))
448         return true;
449       return false;
450     }
did_succeed()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:
HTTPTestServer()469   explicit HTTPTestServer() : loop_(NULL) {
470   }
471 
HTTPTestServer(int connection_attempts,int connection_timeout)472   explicit HTTPTestServer(int connection_attempts, int connection_timeout)
473       : BaseTestServer(connection_attempts, connection_timeout), loop_(NULL) {
474   }
475 
~HTTPTestServer()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.
CreateServer(const std::wstring & document_root,MessageLoop * loop)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 
CreateServer(const std::wstring & document_root,MessageLoop * loop,int connection_attempts,int connection_timeout)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 
CreateServerWithFileRootURL(const std::wstring & document_root,const std::wstring & file_root_url,MessageLoop * loop)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 
CreateForkingServer(const std::wstring & document_root)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 
CreateServerWithFileRootURL(const std::wstring & document_root,const std::wstring & file_root_url,MessageLoop * loop,int connection_attempts,int connection_timeout)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 
StartTestServer(HTTPTestServer * server,const FilePath & document_root,const FilePath & cert_path,const std::wstring & file_root_url)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
MakeGETRequest(const std::string & page_name)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 
StartGETRequest(const GURL & url,URLRequest::Delegate * delegate)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.
SendQuit()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 
scheme()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:
HTTPSTestServer()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
CreateGoodServer(const std::wstring & document_root)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
CreateMismatchedServer(const std::wstring & document_root)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
CreateExpiredServer(const std::wstring & document_root)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
CreateServer(const std::string & host_name,int port,const std::wstring & document_root,const std::wstring & cert_path)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:
~HTTPSTestServer()690   virtual ~HTTPSTestServer() {}
691 };
692 
693 //-----------------------------------------------------------------------------
694 
695 class FTPTestServer : public BaseTestServer {
696  public:
FTPTestServer()697   FTPTestServer() {
698   }
699 
CreateServer(const std::wstring & document_root)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 
MakeGETRequest(const std::string & page_name)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:
~FTPTestServer()729   ~FTPTestServer() {}
730 };
731 
732 #endif  // NET_URL_REQUEST_URL_REQUEST_UNITTEST_H_
733