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