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