1 // Copyright (c) 2012 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 #include "net/url_request/url_request_ftp_job.h" 6 7 #include "base/memory/ref_counted.h" 8 #include "base/memory/scoped_ptr.h" 9 #include "base/memory/scoped_vector.h" 10 #include "base/run_loop.h" 11 #include "net/base/host_port_pair.h" 12 #include "net/base/request_priority.h" 13 #include "net/ftp/ftp_auth_cache.h" 14 #include "net/http/http_transaction_test_util.h" 15 #include "net/proxy/mock_proxy_resolver.h" 16 #include "net/proxy/proxy_config_service.h" 17 #include "net/proxy/proxy_config_service_fixed.h" 18 #include "net/socket/socket_test_util.h" 19 #include "net/url_request/ftp_protocol_handler.h" 20 #include "net/url_request/url_request.h" 21 #include "net/url_request/url_request_context.h" 22 #include "net/url_request/url_request_job_factory_impl.h" 23 #include "net/url_request/url_request_status.h" 24 #include "net/url_request/url_request_test_util.h" 25 #include "testing/gtest/include/gtest/gtest.h" 26 #include "url/gurl.h" 27 28 using base::ASCIIToUTF16; 29 30 namespace net { 31 32 class FtpTestURLRequestContext : public TestURLRequestContext { 33 public: 34 FtpTestURLRequestContext(ClientSocketFactory* socket_factory, 35 ProxyService* proxy_service, 36 NetworkDelegate* network_delegate, 37 FtpTransactionFactory* ftp_transaction_factory) 38 : TestURLRequestContext(true), 39 ftp_protocol_handler_(new FtpProtocolHandler(ftp_transaction_factory)) { 40 set_client_socket_factory(socket_factory); 41 context_storage_.set_proxy_service(proxy_service); 42 set_network_delegate(network_delegate); 43 URLRequestJobFactoryImpl* job_factory = new URLRequestJobFactoryImpl; 44 job_factory->SetProtocolHandler("ftp", ftp_protocol_handler_); 45 context_storage_.set_job_factory(job_factory); 46 Init(); 47 } 48 49 FtpAuthCache* GetFtpAuthCache() { 50 return ftp_protocol_handler_->ftp_auth_cache_.get(); 51 } 52 53 void set_proxy_service(ProxyService* proxy_service) { 54 context_storage_.set_proxy_service(proxy_service); 55 } 56 57 private: 58 FtpProtocolHandler* ftp_protocol_handler_; 59 }; 60 61 namespace { 62 63 class SimpleProxyConfigService : public ProxyConfigService { 64 public: 65 SimpleProxyConfigService() { 66 // Any FTP requests that ever go through HTTP paths are proxied requests. 67 config_.proxy_rules().ParseFromString("ftp=localhost"); 68 } 69 70 virtual void AddObserver(Observer* observer) OVERRIDE { 71 observer_ = observer; 72 } 73 74 virtual void RemoveObserver(Observer* observer) OVERRIDE { 75 if (observer_ == observer) { 76 observer_ = NULL; 77 } 78 } 79 80 virtual ConfigAvailability GetLatestProxyConfig( 81 ProxyConfig* config) OVERRIDE { 82 *config = config_; 83 return CONFIG_VALID; 84 } 85 86 void IncrementConfigId() { 87 config_.set_id(config_.id() + 1); 88 observer_->OnProxyConfigChanged(config_, ProxyConfigService::CONFIG_VALID); 89 } 90 91 private: 92 ProxyConfig config_; 93 Observer* observer_; 94 }; 95 96 // Inherit from URLRequestFtpJob to expose the priority and some 97 // other hidden functions. 98 class TestURLRequestFtpJob : public URLRequestFtpJob { 99 public: 100 TestURLRequestFtpJob(URLRequest* request, 101 FtpTransactionFactory* ftp_factory, 102 FtpAuthCache* ftp_auth_cache) 103 : URLRequestFtpJob(request, NULL, ftp_factory, ftp_auth_cache) {} 104 105 using URLRequestFtpJob::SetPriority; 106 using URLRequestFtpJob::Start; 107 using URLRequestFtpJob::Kill; 108 using URLRequestFtpJob::priority; 109 110 protected: 111 virtual ~TestURLRequestFtpJob() {} 112 }; 113 114 class MockFtpTransactionFactory : public FtpTransactionFactory { 115 public: 116 virtual FtpTransaction* CreateTransaction() OVERRIDE { 117 return NULL; 118 } 119 120 virtual void Suspend(bool suspend) OVERRIDE {} 121 }; 122 123 // Fixture for priority-related tests. Priority matters when there is 124 // an HTTP proxy. 125 class URLRequestFtpJobPriorityTest : public testing::Test { 126 protected: 127 URLRequestFtpJobPriorityTest() 128 : proxy_service_(new SimpleProxyConfigService, NULL, NULL), 129 req_(context_.CreateRequest(GURL("ftp://ftp.example.com"), 130 DEFAULT_PRIORITY, 131 &delegate_, 132 NULL)) { 133 context_.set_proxy_service(&proxy_service_); 134 context_.set_http_transaction_factory(&network_layer_); 135 } 136 137 ProxyService proxy_service_; 138 MockNetworkLayer network_layer_; 139 MockFtpTransactionFactory ftp_factory_; 140 FtpAuthCache ftp_auth_cache_; 141 TestURLRequestContext context_; 142 TestDelegate delegate_; 143 scoped_ptr<URLRequest> req_; 144 }; 145 146 // Make sure that SetPriority actually sets the URLRequestFtpJob's 147 // priority, both before and after start. 148 TEST_F(URLRequestFtpJobPriorityTest, SetPriorityBasic) { 149 scoped_refptr<TestURLRequestFtpJob> job(new TestURLRequestFtpJob( 150 req_.get(), &ftp_factory_, &ftp_auth_cache_)); 151 EXPECT_EQ(DEFAULT_PRIORITY, job->priority()); 152 153 job->SetPriority(LOWEST); 154 EXPECT_EQ(LOWEST, job->priority()); 155 156 job->SetPriority(LOW); 157 EXPECT_EQ(LOW, job->priority()); 158 159 job->Start(); 160 EXPECT_EQ(LOW, job->priority()); 161 162 job->SetPriority(MEDIUM); 163 EXPECT_EQ(MEDIUM, job->priority()); 164 } 165 166 // Make sure that URLRequestFtpJob passes on its priority to its 167 // transaction on start. 168 TEST_F(URLRequestFtpJobPriorityTest, SetTransactionPriorityOnStart) { 169 scoped_refptr<TestURLRequestFtpJob> job(new TestURLRequestFtpJob( 170 req_.get(), &ftp_factory_, &ftp_auth_cache_)); 171 job->SetPriority(LOW); 172 173 EXPECT_FALSE(network_layer_.last_transaction()); 174 175 job->Start(); 176 177 ASSERT_TRUE(network_layer_.last_transaction()); 178 EXPECT_EQ(LOW, network_layer_.last_transaction()->priority()); 179 } 180 181 // Make sure that URLRequestFtpJob passes on its priority updates to 182 // its transaction. 183 TEST_F(URLRequestFtpJobPriorityTest, SetTransactionPriority) { 184 scoped_refptr<TestURLRequestFtpJob> job(new TestURLRequestFtpJob( 185 req_.get(), &ftp_factory_, &ftp_auth_cache_)); 186 job->SetPriority(LOW); 187 job->Start(); 188 ASSERT_TRUE(network_layer_.last_transaction()); 189 EXPECT_EQ(LOW, network_layer_.last_transaction()->priority()); 190 191 job->SetPriority(HIGHEST); 192 EXPECT_EQ(HIGHEST, network_layer_.last_transaction()->priority()); 193 } 194 195 // Make sure that URLRequestFtpJob passes on its priority updates to 196 // newly-created transactions after the first one. 197 TEST_F(URLRequestFtpJobPriorityTest, SetSubsequentTransactionPriority) { 198 scoped_refptr<TestURLRequestFtpJob> job(new TestURLRequestFtpJob( 199 req_.get(), &ftp_factory_, &ftp_auth_cache_)); 200 job->Start(); 201 202 job->SetPriority(LOW); 203 ASSERT_TRUE(network_layer_.last_transaction()); 204 EXPECT_EQ(LOW, network_layer_.last_transaction()->priority()); 205 206 job->Kill(); 207 network_layer_.ClearLastTransaction(); 208 209 // Creates a second transaction. 210 job->Start(); 211 ASSERT_TRUE(network_layer_.last_transaction()); 212 EXPECT_EQ(LOW, network_layer_.last_transaction()->priority()); 213 } 214 215 class URLRequestFtpJobTest : public testing::Test { 216 public: 217 URLRequestFtpJobTest() 218 : request_context_(&socket_factory_, 219 new ProxyService( 220 new SimpleProxyConfigService, NULL, NULL), 221 &network_delegate_, 222 &ftp_transaction_factory_) { 223 } 224 225 virtual ~URLRequestFtpJobTest() { 226 // Clean up any remaining tasks that mess up unrelated tests. 227 base::RunLoop run_loop; 228 run_loop.RunUntilIdle(); 229 } 230 231 void AddSocket(MockRead* reads, size_t reads_size, 232 MockWrite* writes, size_t writes_size) { 233 DeterministicSocketData* socket_data = new DeterministicSocketData( 234 reads, reads_size, writes, writes_size); 235 socket_data->set_connect_data(MockConnect(SYNCHRONOUS, OK)); 236 socket_data->StopAfter(reads_size + writes_size - 1); 237 socket_factory_.AddSocketDataProvider(socket_data); 238 239 socket_data_.push_back(socket_data); 240 } 241 242 FtpTestURLRequestContext* request_context() { return &request_context_; } 243 TestNetworkDelegate* network_delegate() { return &network_delegate_; } 244 DeterministicSocketData* socket_data(size_t index) { 245 return socket_data_[index]; 246 } 247 248 private: 249 ScopedVector<DeterministicSocketData> socket_data_; 250 DeterministicMockClientSocketFactory socket_factory_; 251 TestNetworkDelegate network_delegate_; 252 MockFtpTransactionFactory ftp_transaction_factory_; 253 254 FtpTestURLRequestContext request_context_; 255 }; 256 257 TEST_F(URLRequestFtpJobTest, FtpProxyRequest) { 258 MockWrite writes[] = { 259 MockWrite(ASYNC, 0, "GET ftp://ftp.example.com/ HTTP/1.1\r\n" 260 "Host: ftp.example.com\r\n" 261 "Proxy-Connection: keep-alive\r\n\r\n"), 262 }; 263 MockRead reads[] = { 264 MockRead(ASYNC, 1, "HTTP/1.1 200 OK\r\n"), 265 MockRead(ASYNC, 2, "Content-Length: 9\r\n\r\n"), 266 MockRead(ASYNC, 3, "test.html"), 267 }; 268 269 AddSocket(reads, arraysize(reads), writes, arraysize(writes)); 270 271 TestDelegate request_delegate; 272 scoped_ptr<URLRequest> url_request(request_context()->CreateRequest( 273 GURL("ftp://ftp.example.com/"), DEFAULT_PRIORITY, 274 &request_delegate, NULL)); 275 url_request->Start(); 276 ASSERT_TRUE(url_request->is_pending()); 277 socket_data(0)->RunFor(4); 278 279 EXPECT_TRUE(url_request->status().is_success()); 280 EXPECT_TRUE(url_request->proxy_server().Equals( 281 net::HostPortPair::FromString("localhost:80"))); 282 EXPECT_EQ(1, network_delegate()->completed_requests()); 283 EXPECT_EQ(0, network_delegate()->error_count()); 284 EXPECT_FALSE(request_delegate.auth_required_called()); 285 EXPECT_EQ("test.html", request_delegate.data_received()); 286 } 287 288 // Regression test for http://crbug.com/237526 . 289 TEST_F(URLRequestFtpJobTest, FtpProxyRequestOrphanJob) { 290 // Use a PAC URL so that URLRequestFtpJob's |pac_request_| field is non-NULL. 291 request_context()->set_proxy_service( 292 new ProxyService( 293 new ProxyConfigServiceFixed( 294 ProxyConfig::CreateFromCustomPacURL(GURL("http://foo"))), 295 new MockAsyncProxyResolver, NULL)); 296 297 TestDelegate request_delegate; 298 scoped_ptr<URLRequest> url_request(request_context()->CreateRequest( 299 GURL("ftp://ftp.example.com/"), DEFAULT_PRIORITY, &request_delegate, 300 NULL)); 301 url_request->Start(); 302 303 // Now |url_request| will be deleted before its completion, 304 // resulting in it being orphaned. It should not crash. 305 } 306 307 TEST_F(URLRequestFtpJobTest, FtpProxyRequestNeedProxyAuthNoCredentials) { 308 MockWrite writes[] = { 309 MockWrite(ASYNC, 0, "GET ftp://ftp.example.com/ HTTP/1.1\r\n" 310 "Host: ftp.example.com\r\n" 311 "Proxy-Connection: keep-alive\r\n\r\n"), 312 }; 313 MockRead reads[] = { 314 // No credentials. 315 MockRead(ASYNC, 1, "HTTP/1.1 407 Proxy Authentication Required\r\n"), 316 MockRead(ASYNC, 2, "Proxy-Authenticate: Basic " 317 "realm=\"MyRealm1\"\r\n"), 318 MockRead(ASYNC, 3, "Content-Length: 9\r\n\r\n"), 319 MockRead(ASYNC, 4, "test.html"), 320 }; 321 322 AddSocket(reads, arraysize(reads), writes, arraysize(writes)); 323 324 TestDelegate request_delegate; 325 scoped_ptr<URLRequest> url_request(request_context()->CreateRequest( 326 GURL("ftp://ftp.example.com/"), DEFAULT_PRIORITY, &request_delegate, 327 NULL)); 328 url_request->Start(); 329 ASSERT_TRUE(url_request->is_pending()); 330 socket_data(0)->RunFor(5); 331 332 EXPECT_TRUE(url_request->status().is_success()); 333 EXPECT_TRUE(url_request->proxy_server().Equals( 334 net::HostPortPair::FromString("localhost:80"))); 335 EXPECT_EQ(1, network_delegate()->completed_requests()); 336 EXPECT_EQ(0, network_delegate()->error_count()); 337 EXPECT_TRUE(request_delegate.auth_required_called()); 338 EXPECT_EQ("test.html", request_delegate.data_received()); 339 } 340 341 TEST_F(URLRequestFtpJobTest, FtpProxyRequestNeedProxyAuthWithCredentials) { 342 MockWrite writes[] = { 343 MockWrite(ASYNC, 0, "GET ftp://ftp.example.com/ HTTP/1.1\r\n" 344 "Host: ftp.example.com\r\n" 345 "Proxy-Connection: keep-alive\r\n\r\n"), 346 MockWrite(ASYNC, 5, "GET ftp://ftp.example.com/ HTTP/1.1\r\n" 347 "Host: ftp.example.com\r\n" 348 "Proxy-Connection: keep-alive\r\n" 349 "Proxy-Authorization: Basic bXl1c2VyOm15cGFzcw==\r\n\r\n"), 350 }; 351 MockRead reads[] = { 352 // No credentials. 353 MockRead(ASYNC, 1, "HTTP/1.1 407 Proxy Authentication Required\r\n"), 354 MockRead(ASYNC, 2, "Proxy-Authenticate: Basic " 355 "realm=\"MyRealm1\"\r\n"), 356 MockRead(ASYNC, 3, "Content-Length: 9\r\n\r\n"), 357 MockRead(ASYNC, 4, "test.html"), 358 359 // Second response. 360 MockRead(ASYNC, 6, "HTTP/1.1 200 OK\r\n"), 361 MockRead(ASYNC, 7, "Content-Length: 10\r\n\r\n"), 362 MockRead(ASYNC, 8, "test2.html"), 363 }; 364 365 AddSocket(reads, arraysize(reads), writes, arraysize(writes)); 366 367 TestDelegate request_delegate; 368 request_delegate.set_credentials( 369 AuthCredentials(ASCIIToUTF16("myuser"), ASCIIToUTF16("mypass"))); 370 scoped_ptr<URLRequest> url_request(request_context()->CreateRequest( 371 GURL("ftp://ftp.example.com/"), DEFAULT_PRIORITY, &request_delegate, 372 NULL)); 373 url_request->Start(); 374 ASSERT_TRUE(url_request->is_pending()); 375 socket_data(0)->RunFor(9); 376 377 EXPECT_TRUE(url_request->status().is_success()); 378 EXPECT_EQ(1, network_delegate()->completed_requests()); 379 EXPECT_EQ(0, network_delegate()->error_count()); 380 EXPECT_TRUE(request_delegate.auth_required_called()); 381 EXPECT_EQ("test2.html", request_delegate.data_received()); 382 } 383 384 TEST_F(URLRequestFtpJobTest, FtpProxyRequestNeedServerAuthNoCredentials) { 385 MockWrite writes[] = { 386 MockWrite(ASYNC, 0, "GET ftp://ftp.example.com/ HTTP/1.1\r\n" 387 "Host: ftp.example.com\r\n" 388 "Proxy-Connection: keep-alive\r\n\r\n"), 389 }; 390 MockRead reads[] = { 391 // No credentials. 392 MockRead(ASYNC, 1, "HTTP/1.1 401 Unauthorized\r\n"), 393 MockRead(ASYNC, 2, "WWW-Authenticate: Basic " 394 "realm=\"MyRealm1\"\r\n"), 395 MockRead(ASYNC, 3, "Content-Length: 9\r\n\r\n"), 396 MockRead(ASYNC, 4, "test.html"), 397 }; 398 399 AddSocket(reads, arraysize(reads), writes, arraysize(writes)); 400 401 TestDelegate request_delegate; 402 scoped_ptr<URLRequest> url_request(request_context()->CreateRequest( 403 GURL("ftp://ftp.example.com/"), DEFAULT_PRIORITY, &request_delegate, 404 NULL)); 405 url_request->Start(); 406 ASSERT_TRUE(url_request->is_pending()); 407 socket_data(0)->RunFor(5); 408 409 EXPECT_TRUE(url_request->status().is_success()); 410 EXPECT_EQ(1, network_delegate()->completed_requests()); 411 EXPECT_EQ(0, network_delegate()->error_count()); 412 EXPECT_TRUE(request_delegate.auth_required_called()); 413 EXPECT_EQ("test.html", request_delegate.data_received()); 414 } 415 416 TEST_F(URLRequestFtpJobTest, FtpProxyRequestNeedServerAuthWithCredentials) { 417 MockWrite writes[] = { 418 MockWrite(ASYNC, 0, "GET ftp://ftp.example.com/ HTTP/1.1\r\n" 419 "Host: ftp.example.com\r\n" 420 "Proxy-Connection: keep-alive\r\n\r\n"), 421 MockWrite(ASYNC, 5, "GET ftp://ftp.example.com/ HTTP/1.1\r\n" 422 "Host: ftp.example.com\r\n" 423 "Proxy-Connection: keep-alive\r\n" 424 "Authorization: Basic bXl1c2VyOm15cGFzcw==\r\n\r\n"), 425 }; 426 MockRead reads[] = { 427 // No credentials. 428 MockRead(ASYNC, 1, "HTTP/1.1 401 Unauthorized\r\n"), 429 MockRead(ASYNC, 2, "WWW-Authenticate: Basic " 430 "realm=\"MyRealm1\"\r\n"), 431 MockRead(ASYNC, 3, "Content-Length: 9\r\n\r\n"), 432 MockRead(ASYNC, 4, "test.html"), 433 434 // Second response. 435 MockRead(ASYNC, 6, "HTTP/1.1 200 OK\r\n"), 436 MockRead(ASYNC, 7, "Content-Length: 10\r\n\r\n"), 437 MockRead(ASYNC, 8, "test2.html"), 438 }; 439 440 AddSocket(reads, arraysize(reads), writes, arraysize(writes)); 441 442 TestDelegate request_delegate; 443 request_delegate.set_credentials( 444 AuthCredentials(ASCIIToUTF16("myuser"), ASCIIToUTF16("mypass"))); 445 scoped_ptr<URLRequest> url_request(request_context()->CreateRequest( 446 GURL("ftp://ftp.example.com/"), DEFAULT_PRIORITY, &request_delegate, 447 NULL)); 448 url_request->Start(); 449 ASSERT_TRUE(url_request->is_pending()); 450 socket_data(0)->RunFor(9); 451 452 EXPECT_TRUE(url_request->status().is_success()); 453 EXPECT_EQ(1, network_delegate()->completed_requests()); 454 EXPECT_EQ(0, network_delegate()->error_count()); 455 EXPECT_TRUE(request_delegate.auth_required_called()); 456 EXPECT_EQ("test2.html", request_delegate.data_received()); 457 } 458 459 TEST_F(URLRequestFtpJobTest, FtpProxyRequestNeedProxyAndServerAuth) { 460 MockWrite writes[] = { 461 MockWrite(ASYNC, 0, "GET ftp://ftp.example.com/ HTTP/1.1\r\n" 462 "Host: ftp.example.com\r\n" 463 "Proxy-Connection: keep-alive\r\n\r\n"), 464 MockWrite(ASYNC, 5, "GET ftp://ftp.example.com/ HTTP/1.1\r\n" 465 "Host: ftp.example.com\r\n" 466 "Proxy-Connection: keep-alive\r\n" 467 "Proxy-Authorization: Basic " 468 "cHJveHl1c2VyOnByb3h5cGFzcw==\r\n\r\n"), 469 MockWrite(ASYNC, 10, "GET ftp://ftp.example.com/ HTTP/1.1\r\n" 470 "Host: ftp.example.com\r\n" 471 "Proxy-Connection: keep-alive\r\n" 472 "Proxy-Authorization: Basic " 473 "cHJveHl1c2VyOnByb3h5cGFzcw==\r\n" 474 "Authorization: Basic bXl1c2VyOm15cGFzcw==\r\n\r\n"), 475 }; 476 MockRead reads[] = { 477 // No credentials. 478 MockRead(ASYNC, 1, "HTTP/1.1 407 Proxy Authentication Required\r\n"), 479 MockRead(ASYNC, 2, "Proxy-Authenticate: Basic " 480 "realm=\"MyRealm1\"\r\n"), 481 MockRead(ASYNC, 3, "Content-Length: 9\r\n\r\n"), 482 MockRead(ASYNC, 4, "test.html"), 483 484 // Second response. 485 MockRead(ASYNC, 6, "HTTP/1.1 401 Unauthorized\r\n"), 486 MockRead(ASYNC, 7, "WWW-Authenticate: Basic " 487 "realm=\"MyRealm1\"\r\n"), 488 MockRead(ASYNC, 8, "Content-Length: 9\r\n\r\n"), 489 MockRead(ASYNC, 9, "test.html"), 490 491 // Third response. 492 MockRead(ASYNC, 11, "HTTP/1.1 200 OK\r\n"), 493 MockRead(ASYNC, 12, "Content-Length: 10\r\n\r\n"), 494 MockRead(ASYNC, 13, "test2.html"), 495 }; 496 497 AddSocket(reads, arraysize(reads), writes, arraysize(writes)); 498 499 GURL url("ftp://ftp.example.com"); 500 501 // Make sure cached FTP credentials are not used for proxy authentication. 502 request_context()->GetFtpAuthCache()->Add( 503 url.GetOrigin(), 504 AuthCredentials(ASCIIToUTF16("userdonotuse"), 505 ASCIIToUTF16("passworddonotuse"))); 506 507 TestDelegate request_delegate; 508 request_delegate.set_credentials( 509 AuthCredentials(ASCIIToUTF16("proxyuser"), ASCIIToUTF16("proxypass"))); 510 scoped_ptr<URLRequest> url_request(request_context()->CreateRequest( 511 url, DEFAULT_PRIORITY, &request_delegate, NULL)); 512 url_request->Start(); 513 ASSERT_TRUE(url_request->is_pending()); 514 socket_data(0)->RunFor(5); 515 516 request_delegate.set_credentials( 517 AuthCredentials(ASCIIToUTF16("myuser"), ASCIIToUTF16("mypass"))); 518 socket_data(0)->RunFor(9); 519 520 EXPECT_TRUE(url_request->status().is_success()); 521 EXPECT_EQ(1, network_delegate()->completed_requests()); 522 EXPECT_EQ(0, network_delegate()->error_count()); 523 EXPECT_TRUE(request_delegate.auth_required_called()); 524 EXPECT_EQ("test2.html", request_delegate.data_received()); 525 } 526 527 TEST_F(URLRequestFtpJobTest, FtpProxyRequestDoNotSaveCookies) { 528 MockWrite writes[] = { 529 MockWrite(ASYNC, 0, "GET ftp://ftp.example.com/ HTTP/1.1\r\n" 530 "Host: ftp.example.com\r\n" 531 "Proxy-Connection: keep-alive\r\n\r\n"), 532 }; 533 MockRead reads[] = { 534 MockRead(ASYNC, 1, "HTTP/1.1 200 OK\r\n"), 535 MockRead(ASYNC, 2, "Content-Length: 9\r\n"), 536 MockRead(ASYNC, 3, "Set-Cookie: name=value\r\n\r\n"), 537 MockRead(ASYNC, 4, "test.html"), 538 }; 539 540 AddSocket(reads, arraysize(reads), writes, arraysize(writes)); 541 542 TestDelegate request_delegate; 543 scoped_ptr<URLRequest> url_request(request_context()->CreateRequest( 544 GURL("ftp://ftp.example.com/"), DEFAULT_PRIORITY, &request_delegate, 545 NULL)); 546 url_request->Start(); 547 ASSERT_TRUE(url_request->is_pending()); 548 549 socket_data(0)->RunFor(5); 550 551 EXPECT_TRUE(url_request->status().is_success()); 552 EXPECT_EQ(1, network_delegate()->completed_requests()); 553 EXPECT_EQ(0, network_delegate()->error_count()); 554 555 // Make sure we do not accept cookies. 556 EXPECT_EQ(0, network_delegate()->set_cookie_count()); 557 558 EXPECT_FALSE(request_delegate.auth_required_called()); 559 EXPECT_EQ("test.html", request_delegate.data_received()); 560 } 561 562 TEST_F(URLRequestFtpJobTest, FtpProxyRequestDoNotFollowRedirects) { 563 MockWrite writes[] = { 564 MockWrite(SYNCHRONOUS, 0, "GET ftp://ftp.example.com/ HTTP/1.1\r\n" 565 "Host: ftp.example.com\r\n" 566 "Proxy-Connection: keep-alive\r\n\r\n"), 567 }; 568 MockRead reads[] = { 569 MockRead(SYNCHRONOUS, 1, "HTTP/1.1 302 Found\r\n"), 570 MockRead(ASYNC, 2, "Location: http://other.example.com/\r\n\r\n"), 571 }; 572 573 AddSocket(reads, arraysize(reads), writes, arraysize(writes)); 574 575 TestDelegate request_delegate; 576 scoped_ptr<URLRequest> url_request(request_context()->CreateRequest( 577 GURL("ftp://ftp.example.com/"), DEFAULT_PRIORITY, &request_delegate, 578 NULL)); 579 url_request->Start(); 580 EXPECT_TRUE(url_request->is_pending()); 581 582 base::MessageLoop::current()->RunUntilIdle(); 583 584 EXPECT_TRUE(url_request->is_pending()); 585 EXPECT_EQ(0, request_delegate.response_started_count()); 586 EXPECT_EQ(0, network_delegate()->error_count()); 587 ASSERT_TRUE(url_request->status().is_success()); 588 589 socket_data(0)->RunFor(1); 590 591 EXPECT_EQ(1, network_delegate()->completed_requests()); 592 EXPECT_EQ(1, network_delegate()->error_count()); 593 EXPECT_FALSE(url_request->status().is_success()); 594 EXPECT_EQ(ERR_UNSAFE_REDIRECT, url_request->status().error()); 595 } 596 597 // We should re-use socket for requests using the same scheme, host, and port. 598 TEST_F(URLRequestFtpJobTest, FtpProxyRequestReuseSocket) { 599 MockWrite writes[] = { 600 MockWrite(ASYNC, 0, "GET ftp://ftp.example.com/first HTTP/1.1\r\n" 601 "Host: ftp.example.com\r\n" 602 "Proxy-Connection: keep-alive\r\n\r\n"), 603 MockWrite(ASYNC, 4, "GET ftp://ftp.example.com/second HTTP/1.1\r\n" 604 "Host: ftp.example.com\r\n" 605 "Proxy-Connection: keep-alive\r\n\r\n"), 606 }; 607 MockRead reads[] = { 608 MockRead(ASYNC, 1, "HTTP/1.1 200 OK\r\n"), 609 MockRead(ASYNC, 2, "Content-Length: 10\r\n\r\n"), 610 MockRead(ASYNC, 3, "test1.html"), 611 MockRead(ASYNC, 5, "HTTP/1.1 200 OK\r\n"), 612 MockRead(ASYNC, 6, "Content-Length: 10\r\n\r\n"), 613 MockRead(ASYNC, 7, "test2.html"), 614 }; 615 616 AddSocket(reads, arraysize(reads), writes, arraysize(writes)); 617 618 TestDelegate request_delegate1; 619 620 scoped_ptr<URLRequest> url_request1(request_context()->CreateRequest( 621 GURL("ftp://ftp.example.com/first"), DEFAULT_PRIORITY, &request_delegate1, 622 NULL)); 623 url_request1->Start(); 624 ASSERT_TRUE(url_request1->is_pending()); 625 socket_data(0)->RunFor(4); 626 627 EXPECT_TRUE(url_request1->status().is_success()); 628 EXPECT_TRUE(url_request1->proxy_server().Equals( 629 net::HostPortPair::FromString("localhost:80"))); 630 EXPECT_EQ(1, network_delegate()->completed_requests()); 631 EXPECT_EQ(0, network_delegate()->error_count()); 632 EXPECT_FALSE(request_delegate1.auth_required_called()); 633 EXPECT_EQ("test1.html", request_delegate1.data_received()); 634 635 TestDelegate request_delegate2; 636 scoped_ptr<URLRequest> url_request2(request_context()->CreateRequest( 637 GURL("ftp://ftp.example.com/second"), DEFAULT_PRIORITY, 638 &request_delegate2, NULL)); 639 url_request2->Start(); 640 ASSERT_TRUE(url_request2->is_pending()); 641 socket_data(0)->RunFor(4); 642 643 EXPECT_TRUE(url_request2->status().is_success()); 644 EXPECT_EQ(2, network_delegate()->completed_requests()); 645 EXPECT_EQ(0, network_delegate()->error_count()); 646 EXPECT_FALSE(request_delegate2.auth_required_called()); 647 EXPECT_EQ("test2.html", request_delegate2.data_received()); 648 } 649 650 // We should not re-use socket when there are two requests to the same host, 651 // but one is FTP and the other is HTTP. 652 TEST_F(URLRequestFtpJobTest, FtpProxyRequestDoNotReuseSocket) { 653 MockWrite writes1[] = { 654 MockWrite(ASYNC, 0, "GET ftp://ftp.example.com/first HTTP/1.1\r\n" 655 "Host: ftp.example.com\r\n" 656 "Proxy-Connection: keep-alive\r\n\r\n"), 657 }; 658 MockWrite writes2[] = { 659 MockWrite(ASYNC, 0, "GET /second HTTP/1.1\r\n" 660 "Host: ftp.example.com\r\n" 661 "Connection: keep-alive\r\n" 662 "User-Agent:\r\n" 663 "Accept-Encoding: gzip, deflate\r\n" 664 "Accept-Language: en-us,fr\r\n\r\n"), 665 }; 666 MockRead reads1[] = { 667 MockRead(ASYNC, 1, "HTTP/1.1 200 OK\r\n"), 668 MockRead(ASYNC, 2, "Content-Length: 10\r\n\r\n"), 669 MockRead(ASYNC, 3, "test1.html"), 670 }; 671 MockRead reads2[] = { 672 MockRead(ASYNC, 1, "HTTP/1.1 200 OK\r\n"), 673 MockRead(ASYNC, 2, "Content-Length: 10\r\n\r\n"), 674 MockRead(ASYNC, 3, "test2.html"), 675 }; 676 677 AddSocket(reads1, arraysize(reads1), writes1, arraysize(writes1)); 678 AddSocket(reads2, arraysize(reads2), writes2, arraysize(writes2)); 679 680 TestDelegate request_delegate1; 681 scoped_ptr<URLRequest> url_request1(request_context()->CreateRequest( 682 GURL("ftp://ftp.example.com/first"), DEFAULT_PRIORITY, 683 &request_delegate1, NULL)); 684 url_request1->Start(); 685 ASSERT_TRUE(url_request1->is_pending()); 686 socket_data(0)->RunFor(4); 687 688 EXPECT_TRUE(url_request1->status().is_success()); 689 EXPECT_EQ(1, network_delegate()->completed_requests()); 690 EXPECT_EQ(0, network_delegate()->error_count()); 691 EXPECT_FALSE(request_delegate1.auth_required_called()); 692 EXPECT_EQ("test1.html", request_delegate1.data_received()); 693 694 TestDelegate request_delegate2; 695 scoped_ptr<URLRequest> url_request2(request_context()->CreateRequest( 696 GURL("http://ftp.example.com/second"), DEFAULT_PRIORITY, 697 &request_delegate2, NULL)); 698 url_request2->Start(); 699 ASSERT_TRUE(url_request2->is_pending()); 700 socket_data(1)->RunFor(4); 701 702 EXPECT_TRUE(url_request2->status().is_success()); 703 EXPECT_EQ(2, network_delegate()->completed_requests()); 704 EXPECT_EQ(0, network_delegate()->error_count()); 705 EXPECT_FALSE(request_delegate2.auth_required_called()); 706 EXPECT_EQ("test2.html", request_delegate2.data_received()); 707 } 708 709 } // namespace 710 711 } // namespace net 712