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/http/http_network_layer.h" 6 7 #include "base/basictypes.h" 8 #include "base/strings/stringprintf.h" 9 #include "net/base/net_log.h" 10 #include "net/cert/mock_cert_verifier.h" 11 #include "net/dns/mock_host_resolver.h" 12 #include "net/http/http_network_session.h" 13 #include "net/http/http_server_properties_impl.h" 14 #include "net/http/http_transaction_unittest.h" 15 #include "net/http/transport_security_state.h" 16 #include "net/proxy/proxy_service.h" 17 #include "net/socket/socket_test_util.h" 18 #include "net/spdy/spdy_session_pool.h" 19 #include "net/ssl/ssl_config_service_defaults.h" 20 #include "testing/gtest/include/gtest/gtest.h" 21 #include "testing/platform_test.h" 22 23 namespace net { 24 25 namespace { 26 27 class HttpNetworkLayerTest : public PlatformTest { 28 protected: 29 HttpNetworkLayerTest() : ssl_config_service_(new SSLConfigServiceDefaults) {} 30 31 virtual void SetUp() { 32 ConfigureTestDependencies(ProxyService::CreateDirect()); 33 } 34 35 void ConfigureTestDependencies(ProxyService* proxy_service) { 36 cert_verifier_.reset(new MockCertVerifier); 37 transport_security_state_.reset(new TransportSecurityState); 38 proxy_service_.reset(proxy_service); 39 HttpNetworkSession::Params session_params; 40 session_params.client_socket_factory = &mock_socket_factory_; 41 session_params.host_resolver = &host_resolver_; 42 session_params.cert_verifier = cert_verifier_.get(); 43 session_params.transport_security_state = transport_security_state_.get(); 44 session_params.proxy_service = proxy_service_.get(); 45 session_params.ssl_config_service = ssl_config_service_.get(); 46 session_params.http_server_properties = 47 http_server_properties_.GetWeakPtr(); 48 network_session_ = new HttpNetworkSession(session_params); 49 factory_.reset(new HttpNetworkLayer(network_session_.get())); 50 } 51 52 #if defined(SPDY_PROXY_AUTH_ORIGIN) 53 std::string GetChromeProxy() { 54 return HostPortPair::FromURL(GURL(SPDY_PROXY_AUTH_ORIGIN)).ToString(); 55 } 56 #endif 57 58 #if defined(SPDY_PROXY_AUTH_ORIGIN) && defined(DATA_REDUCTION_FALLBACK_HOST) 59 std::string GetChromeFallbackProxy() { 60 return HostPortPair::FromURL(GURL(DATA_REDUCTION_FALLBACK_HOST)).ToString(); 61 } 62 #endif 63 64 void ExecuteRequestExpectingContentAndHeader(const std::string& method, 65 const std::string& content, 66 const std::string& header, 67 const std::string& value) { 68 TestCompletionCallback callback; 69 70 HttpRequestInfo request_info; 71 request_info.url = GURL("http://www.google.com/"); 72 request_info.method = method; 73 request_info.load_flags = LOAD_NORMAL; 74 75 scoped_ptr<HttpTransaction> trans; 76 int rv = factory_->CreateTransaction(DEFAULT_PRIORITY, &trans, NULL); 77 EXPECT_EQ(OK, rv); 78 79 rv = trans->Start(&request_info, callback.callback(), BoundNetLog()); 80 if (rv == ERR_IO_PENDING) 81 rv = callback.WaitForResult(); 82 ASSERT_EQ(OK, rv); 83 84 std::string contents; 85 rv = ReadTransaction(trans.get(), &contents); 86 EXPECT_EQ(OK, rv); 87 EXPECT_EQ(content, contents); 88 89 if (!header.empty()) { 90 // We also have a server header here that isn't set by the proxy. 91 EXPECT_TRUE(trans->GetResponseInfo()->headers->HasHeaderValue( 92 header, value)); 93 } 94 } 95 96 // Check that |proxy_count| proxies are in the retry list. 97 // These will be, in order, |bad_proxy| and |bad_proxy2|". 98 void TestBadProxies(unsigned int proxy_count, const std::string& bad_proxy, 99 const std::string& bad_proxy2) { 100 const ProxyRetryInfoMap& retry_info = proxy_service_->proxy_retry_info(); 101 ASSERT_EQ(proxy_count, retry_info.size()); 102 if (proxy_count > 0) 103 ASSERT_TRUE(retry_info.find(bad_proxy) != retry_info.end()); 104 if (proxy_count > 1) 105 ASSERT_TRUE(retry_info.find(bad_proxy2) != retry_info.end()); 106 } 107 108 // Simulates a request through a proxy which returns a bypass, which is then 109 // retried through a second proxy that doesn't bypass. 110 // Checks that the expected requests were issued, the expected content was 111 // recieved, and the first proxy |bad_proxy| was marked as bad. 112 void TestProxyFallback(const std::string& bad_proxy) { 113 MockRead data_reads[] = { 114 MockRead("HTTP/1.1 200 OK\r\n" 115 "Chrome-Proxy: bypass=0\r\n\r\n"), 116 MockRead("Bypass message"), 117 MockRead(SYNCHRONOUS, OK), 118 }; 119 TestProxyFallbackWithMockReads(bad_proxy, "", data_reads, 120 arraysize(data_reads), 1u); 121 } 122 123 void TestProxyFallbackWithMockReads(const std::string& bad_proxy, 124 const std::string& bad_proxy2, 125 MockRead data_reads[], 126 int data_reads_size, 127 unsigned int expected_retry_info_size) { 128 TestProxyFallbackByMethodWithMockReads(bad_proxy, bad_proxy2, data_reads, 129 data_reads_size, "GET", "content", 130 true, expected_retry_info_size); 131 } 132 133 void TestProxyFallbackByMethodWithMockReads( 134 const std::string& bad_proxy, 135 const std::string& bad_proxy2, 136 MockRead data_reads[], 137 int data_reads_size, 138 std::string method, 139 std::string content, 140 bool retry_expected, 141 unsigned int expected_retry_info_size) { 142 std::string trailer = 143 (method == "HEAD" || method == "PUT" || method == "POST") ? 144 "Content-Length: 0\r\n\r\n" : "\r\n"; 145 std::string request = 146 base::StringPrintf("%s http://www.google.com/ HTTP/1.1\r\n" 147 "Host: www.google.com\r\n" 148 "Proxy-Connection: keep-alive\r\n" 149 "%s", method.c_str(), trailer.c_str()); 150 151 MockWrite data_writes[] = { 152 MockWrite(request.c_str()), 153 }; 154 155 StaticSocketDataProvider data1(data_reads, data_reads_size, 156 data_writes, arraysize(data_writes)); 157 mock_socket_factory_.AddSocketDataProvider(&data1); 158 159 // Second data provider returns the expected content. 160 MockRead data_reads2[3]; 161 size_t data_reads2_index = 0; 162 data_reads2[data_reads2_index++] = MockRead("HTTP/1.0 200 OK\r\n" 163 "Server: not-proxy\r\n\r\n"); 164 if (!content.empty()) 165 data_reads2[data_reads2_index++] = MockRead(content.c_str()); 166 data_reads2[data_reads2_index++] = MockRead(SYNCHRONOUS, OK); 167 168 MockWrite data_writes2[] = { 169 MockWrite(request.c_str()), 170 }; 171 StaticSocketDataProvider data2(data_reads2, data_reads2_index, 172 data_writes2, arraysize(data_writes2)); 173 mock_socket_factory_.AddSocketDataProvider(&data2); 174 175 // Expect that we get "content" and not "Bypass message", and that there's 176 // a "not-proxy" "Server:" header in the final response. 177 if (retry_expected) { 178 ExecuteRequestExpectingContentAndHeader(method, content, 179 "server", "not-proxy"); 180 } else { 181 ExecuteRequestExpectingContentAndHeader(method, content, "", ""); 182 } 183 184 // We should also observe the bad proxy in the retry list. 185 TestBadProxies(expected_retry_info_size, bad_proxy, bad_proxy2); 186 } 187 188 // Simulates a request through a proxy which returns a bypass, which is then 189 // retried through a direct connection to the origin site. 190 // Checks that the expected requests were issued, the expected content was 191 // received, and the proxy |bad_proxy| was marked as bad. 192 void TestProxyFallbackToDirect(const std::string& bad_proxy) { 193 MockRead data_reads[] = { 194 MockRead("HTTP/1.1 200 OK\r\n" 195 "Chrome-Proxy: bypass=0\r\n\r\n"), 196 MockRead("Bypass message"), 197 MockRead(SYNCHRONOUS, OK), 198 }; 199 MockWrite data_writes[] = { 200 MockWrite("GET http://www.google.com/ HTTP/1.1\r\n" 201 "Host: www.google.com\r\n" 202 "Proxy-Connection: keep-alive\r\n\r\n"), 203 }; 204 StaticSocketDataProvider data1(data_reads, arraysize(data_reads), 205 data_writes, arraysize(data_writes)); 206 mock_socket_factory_.AddSocketDataProvider(&data1); 207 208 // Second data provider returns the expected content. 209 MockRead data_reads2[] = { 210 MockRead("HTTP/1.0 200 OK\r\n" 211 "Server: not-proxy\r\n\r\n"), 212 MockRead("content"), 213 MockRead(SYNCHRONOUS, OK), 214 }; 215 MockWrite data_writes2[] = { 216 MockWrite("GET / HTTP/1.1\r\n" 217 "Host: www.google.com\r\n" 218 "Connection: keep-alive\r\n\r\n"), 219 }; 220 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), 221 data_writes2, arraysize(data_writes2)); 222 mock_socket_factory_.AddSocketDataProvider(&data2); 223 224 // Expect that we get "content" and not "Bypass message", and that there's 225 // a "not-proxy" "Server:" header in the final response. 226 ExecuteRequestExpectingContentAndHeader("GET", "content", 227 "server", "not-proxy"); 228 229 // We should also observe the bad proxy in the retry list. 230 TestBadProxies(1u, bad_proxy, ""); 231 } 232 233 // Simulates a request through a proxy which returns a bypass, under a 234 // configuration where there is no valid bypass. |proxy_count| proxies 235 // are expected to be configured. 236 // Checks that the expected requests were issued, the bypass message was the 237 // final received content, and all proxies were marked as bad. 238 void TestProxyFallbackFail(unsigned int proxy_count, 239 const std::string& bad_proxy, 240 const std::string& bad_proxy2) { 241 MockRead data_reads[] = { 242 MockRead("HTTP/1.1 200 OK\r\n" 243 "Chrome-Proxy: bypass=0\r\n\r\n"), 244 MockRead("Bypass message"), 245 MockRead(SYNCHRONOUS, OK), 246 }; 247 MockWrite data_writes[] = { 248 MockWrite("GET http://www.google.com/ HTTP/1.1\r\n" 249 "Host: www.google.com\r\n" 250 "Proxy-Connection: keep-alive\r\n\r\n"), 251 }; 252 StaticSocketDataProvider data1(data_reads, arraysize(data_reads), 253 data_writes, arraysize(data_writes)); 254 StaticSocketDataProvider data2(data_reads, arraysize(data_reads), 255 data_writes, arraysize(data_writes)); 256 257 mock_socket_factory_.AddSocketDataProvider(&data1); 258 if (proxy_count > 1) 259 mock_socket_factory_.AddSocketDataProvider(&data2); 260 261 // Expect that we get "Bypass message", and not "content".. 262 ExecuteRequestExpectingContentAndHeader("GET", "Bypass message", "", ""); 263 264 // We should also observe the bad proxy or proxies in the retry list. 265 TestBadProxies(proxy_count, bad_proxy, bad_proxy2); 266 } 267 268 MockClientSocketFactory mock_socket_factory_; 269 MockHostResolver host_resolver_; 270 scoped_ptr<CertVerifier> cert_verifier_; 271 scoped_ptr<TransportSecurityState> transport_security_state_; 272 scoped_ptr<ProxyService> proxy_service_; 273 const scoped_refptr<SSLConfigService> ssl_config_service_; 274 scoped_refptr<HttpNetworkSession> network_session_; 275 scoped_ptr<HttpNetworkLayer> factory_; 276 HttpServerPropertiesImpl http_server_properties_; 277 }; 278 279 TEST_F(HttpNetworkLayerTest, CreateAndDestroy) { 280 scoped_ptr<HttpTransaction> trans; 281 int rv = factory_->CreateTransaction(DEFAULT_PRIORITY, &trans, NULL); 282 EXPECT_EQ(OK, rv); 283 EXPECT_TRUE(trans.get() != NULL); 284 } 285 286 TEST_F(HttpNetworkLayerTest, Suspend) { 287 scoped_ptr<HttpTransaction> trans; 288 int rv = factory_->CreateTransaction(DEFAULT_PRIORITY, &trans, NULL); 289 EXPECT_EQ(OK, rv); 290 291 trans.reset(); 292 293 factory_->OnSuspend(); 294 295 rv = factory_->CreateTransaction(DEFAULT_PRIORITY, &trans, NULL); 296 EXPECT_EQ(ERR_NETWORK_IO_SUSPENDED, rv); 297 298 ASSERT_TRUE(trans == NULL); 299 300 factory_->OnResume(); 301 302 rv = factory_->CreateTransaction(DEFAULT_PRIORITY, &trans, NULL); 303 EXPECT_EQ(OK, rv); 304 } 305 306 TEST_F(HttpNetworkLayerTest, GET) { 307 MockRead data_reads[] = { 308 MockRead("HTTP/1.0 200 OK\r\n\r\n"), 309 MockRead("hello world"), 310 MockRead(SYNCHRONOUS, OK), 311 }; 312 MockWrite data_writes[] = { 313 MockWrite("GET / HTTP/1.1\r\n" 314 "Host: www.google.com\r\n" 315 "Connection: keep-alive\r\n" 316 "User-Agent: Foo/1.0\r\n\r\n"), 317 }; 318 StaticSocketDataProvider data(data_reads, arraysize(data_reads), 319 data_writes, arraysize(data_writes)); 320 mock_socket_factory_.AddSocketDataProvider(&data); 321 322 TestCompletionCallback callback; 323 324 HttpRequestInfo request_info; 325 request_info.url = GURL("http://www.google.com/"); 326 request_info.method = "GET"; 327 request_info.extra_headers.SetHeader(HttpRequestHeaders::kUserAgent, 328 "Foo/1.0"); 329 request_info.load_flags = LOAD_NORMAL; 330 331 scoped_ptr<HttpTransaction> trans; 332 int rv = factory_->CreateTransaction(DEFAULT_PRIORITY, &trans, NULL); 333 EXPECT_EQ(OK, rv); 334 335 rv = trans->Start(&request_info, callback.callback(), BoundNetLog()); 336 rv = callback.GetResult(rv); 337 ASSERT_EQ(OK, rv); 338 339 std::string contents; 340 rv = ReadTransaction(trans.get(), &contents); 341 EXPECT_EQ(OK, rv); 342 EXPECT_EQ("hello world", contents); 343 } 344 345 // Proxy bypass tests. These tests run through various server-induced 346 // proxy bypass scenarios using both PAC file and fixed proxy params. 347 // The test scenarios are: 348 // - bypass with two proxies configured and the first but not the second 349 // is bypassed. 350 // - bypass with one proxy configured and an explicit fallback to direct 351 // connections 352 // - bypass with two proxies configured and both are bypassed 353 // - bypass with one proxy configured which is bypassed with no defined 354 // fallback 355 356 #if defined(SPDY_PROXY_AUTH_ORIGIN) 357 TEST_F(HttpNetworkLayerTest, ServerTwoProxyBypassPac) { 358 std::string bad_proxy = GetChromeProxy(); 359 ConfigureTestDependencies(ProxyService::CreateFixedFromPacResult( 360 "PROXY " + bad_proxy + "; PROXY good:8080")); 361 TestProxyFallback(bad_proxy); 362 } 363 364 TEST_F(HttpNetworkLayerTest, ServerTwoProxyBypassFixed) { 365 std::string bad_proxy = GetChromeProxy(); 366 ConfigureTestDependencies( 367 ProxyService::CreateFixed(bad_proxy +", good:8080")); 368 TestProxyFallback(bad_proxy); 369 } 370 371 TEST_F(HttpNetworkLayerTest, BypassAndRetryIdempotentMethods) { 372 std::string bad_proxy = GetChromeProxy(); 373 const struct { 374 std::string method; 375 std::string content; 376 bool expected_to_retry; 377 } tests[] = { 378 { 379 "GET", 380 "content", 381 true, 382 }, 383 { 384 "OPTIONS", 385 "content", 386 true, 387 }, 388 { 389 "HEAD", 390 "", 391 true, 392 }, 393 { 394 "PUT", 395 "", 396 true, 397 }, 398 { 399 "DELETE", 400 "content", 401 true, 402 }, 403 { 404 "TRACE", 405 "content", 406 true, 407 }, 408 { 409 "POST", 410 "Bypass message", 411 false, 412 }, 413 }; 414 415 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) { 416 ConfigureTestDependencies( 417 ProxyService::CreateFixed(bad_proxy +", good:8080")); 418 MockRead data_reads[] = { 419 MockRead("HTTP/1.1 200 OK\r\n" 420 "Chrome-Proxy: bypass=0\r\n\r\n"), 421 MockRead("Bypass message"), 422 MockRead(SYNCHRONOUS, OK), 423 }; 424 TestProxyFallbackByMethodWithMockReads(bad_proxy, "", data_reads, 425 arraysize(data_reads), 426 tests[i].method, 427 tests[i].content, 428 tests[i].expected_to_retry, 1u); 429 } 430 } 431 432 TEST_F(HttpNetworkLayerTest, ServerOneProxyWithDirectBypassPac) { 433 std::string bad_proxy = GetChromeProxy(); 434 ConfigureTestDependencies(ProxyService::CreateFixedFromPacResult( 435 "PROXY " + bad_proxy + "; DIRECT")); 436 TestProxyFallbackToDirect(bad_proxy); 437 } 438 439 TEST_F(HttpNetworkLayerTest, ServerOneProxyWithDirectBypassFixed) { 440 std::string bad_proxy = GetChromeProxy(); 441 ConfigureTestDependencies( 442 ProxyService::CreateFixed(bad_proxy + ", direct://")); 443 TestProxyFallbackToDirect(bad_proxy); 444 } 445 446 #if defined(DATA_REDUCTION_FALLBACK_HOST) 447 TEST_F(HttpNetworkLayerTest, ServerTwoProxyDoubleBypassPac) { 448 std::string bad_proxy = GetChromeProxy(); 449 std::string bad_proxy2 = 450 HostPortPair::FromURL(GURL(DATA_REDUCTION_FALLBACK_HOST)).ToString(); 451 ConfigureTestDependencies(ProxyService::CreateFixedFromPacResult( 452 "PROXY " + bad_proxy + "; PROXY " + bad_proxy2)); 453 TestProxyFallbackFail(2u, bad_proxy, bad_proxy2); 454 } 455 456 TEST_F(HttpNetworkLayerTest, ServerTwoProxyDoubleBypassFixed) { 457 std::string bad_proxy = GetChromeProxy(); 458 std::string bad_proxy2 = 459 HostPortPair::FromURL(GURL(DATA_REDUCTION_FALLBACK_HOST)).ToString(); 460 ConfigureTestDependencies(ProxyService::CreateFixed( 461 bad_proxy + ", " + bad_proxy2)); 462 TestProxyFallbackFail(2u, bad_proxy, bad_proxy2); 463 } 464 #endif 465 466 TEST_F(HttpNetworkLayerTest, ServerOneProxyNoDirectBypassPac) { 467 std::string bad_proxy = GetChromeProxy(); 468 ConfigureTestDependencies(ProxyService::CreateFixedFromPacResult( 469 "PROXY " + bad_proxy)); 470 TestProxyFallbackFail(1u, bad_proxy, ""); 471 } 472 473 TEST_F(HttpNetworkLayerTest, ServerOneProxyNoDirectBypassFixed) { 474 std::string bad_proxy = GetChromeProxy(); 475 ConfigureTestDependencies(ProxyService::CreateFixed(bad_proxy)); 476 TestProxyFallbackFail(1u, bad_proxy, ""); 477 } 478 479 TEST_F(HttpNetworkLayerTest, ServerFallbackOn5xxError) { 480 // Verify that "500 Internal Server Error", "502 Bad Gateway", and 481 // "503 Service Unavailable" via the data reduction proxy induce proxy 482 // fallback to a second proxy, if configured. 483 484 // To configure this test, we need to wire up a custom proxy service to use 485 // a pair of proxies. We'll induce fallback via the first and return 486 // the expected data via the second. 487 std::string data_reduction_proxy( 488 HostPortPair::FromURL(GURL(SPDY_PROXY_AUTH_ORIGIN)).ToString()); 489 std::string pac_string = base::StringPrintf( 490 "PROXY %s; PROXY good:8080", data_reduction_proxy.data()); 491 492 std::string headers[] = { 493 "HTTP/1.1 500 Internal Server Error\r\n\r\n", 494 "HTTP/1.1 502 Bad Gateway\r\n\r\n", 495 "HTTP/1.1 503 Service Unavailable\r\n\r\n" 496 }; 497 498 for (size_t i = 0; i < arraysize(headers); ++i) { 499 ConfigureTestDependencies( 500 ProxyService::CreateFixedFromPacResult(pac_string)); 501 502 MockRead data_reads[] = { 503 MockRead(headers[i].c_str()), 504 MockRead("Bypass message"), 505 MockRead(SYNCHRONOUS, OK), 506 }; 507 508 MockWrite data_writes[] = { 509 MockWrite("GET http://www.google.com/ HTTP/1.1\r\n" 510 "Host: www.google.com\r\n" 511 "Proxy-Connection: keep-alive\r\n\r\n"), 512 }; 513 514 StaticSocketDataProvider data1(data_reads, arraysize(data_reads), 515 data_writes, arraysize(data_writes)); 516 mock_socket_factory_.AddSocketDataProvider(&data1); 517 518 // Second data provider returns the expected content. 519 MockRead data_reads2[] = { 520 MockRead("HTTP/1.0 200 OK\r\n" 521 "Server: not-proxy\r\n\r\n"), 522 MockRead("content"), 523 MockRead(SYNCHRONOUS, OK), 524 }; 525 MockWrite data_writes2[] = { 526 MockWrite("GET http://www.google.com/ HTTP/1.1\r\n" 527 "Host: www.google.com\r\n" 528 "Proxy-Connection: keep-alive\r\n\r\n"), 529 }; 530 531 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), 532 data_writes2, arraysize(data_writes2)); 533 mock_socket_factory_.AddSocketDataProvider(&data2); 534 535 TestCompletionCallback callback; 536 537 HttpRequestInfo request_info; 538 request_info.url = GURL("http://www.google.com/"); 539 request_info.method = "GET"; 540 request_info.load_flags = LOAD_NORMAL; 541 542 scoped_ptr<HttpTransaction> trans; 543 int rv = factory_->CreateTransaction(DEFAULT_PRIORITY, &trans, NULL); 544 EXPECT_EQ(OK, rv); 545 546 rv = trans->Start(&request_info, callback.callback(), BoundNetLog()); 547 if (rv == ERR_IO_PENDING) 548 rv = callback.WaitForResult(); 549 ASSERT_EQ(OK, rv); 550 551 std::string contents; 552 rv = ReadTransaction(trans.get(), &contents); 553 EXPECT_EQ(OK, rv); 554 555 // We should obtain content from the second socket provider write 556 // corresponding to the fallback proxy. 557 EXPECT_EQ("content", contents); 558 // We also have a server header here that isn't set by the proxy. 559 EXPECT_TRUE(trans->GetResponseInfo()->headers->HasHeaderValue( 560 "server", "not-proxy")); 561 // We should also observe the data reduction proxy in the retry list. 562 ASSERT_EQ(1u, proxy_service_->proxy_retry_info().size()); 563 EXPECT_EQ(data_reduction_proxy, 564 (*proxy_service_->proxy_retry_info().begin()).first); 565 } 566 } 567 #endif // defined(SPDY_PROXY_AUTH_ORIGIN) 568 569 TEST_F(HttpNetworkLayerTest, ProxyBypassIgnoredOnDirectConnectionPac) { 570 // Verify that a Chrome-Proxy header is ignored when returned from a directly 571 // connected origin server. 572 ConfigureTestDependencies(ProxyService::CreateFixedFromPacResult("DIRECT")); 573 574 MockRead data_reads[] = { 575 MockRead("HTTP/1.1 200 OK\r\n" 576 "Chrome-Proxy: bypass=0\r\n\r\n"), 577 MockRead("Bypass message"), 578 MockRead(SYNCHRONOUS, OK), 579 }; 580 MockWrite data_writes[] = { 581 MockWrite("GET / HTTP/1.1\r\n" 582 "Host: www.google.com\r\n" 583 "Connection: keep-alive\r\n\r\n"), 584 }; 585 StaticSocketDataProvider data1(data_reads, arraysize(data_reads), 586 data_writes, arraysize(data_writes)); 587 mock_socket_factory_.AddSocketDataProvider(&data1); 588 TestCompletionCallback callback; 589 590 HttpRequestInfo request_info; 591 request_info.url = GURL("http://www.google.com/"); 592 request_info.method = "GET"; 593 request_info.load_flags = LOAD_NORMAL; 594 595 scoped_ptr<HttpTransaction> trans; 596 int rv = factory_->CreateTransaction(DEFAULT_PRIORITY, &trans, NULL); 597 EXPECT_EQ(OK, rv); 598 599 rv = trans->Start(&request_info, callback.callback(), BoundNetLog()); 600 if (rv == ERR_IO_PENDING) 601 rv = callback.WaitForResult(); 602 ASSERT_EQ(OK, rv); 603 604 // We should have read the original page data. 605 std::string contents; 606 rv = ReadTransaction(trans.get(), &contents); 607 EXPECT_EQ(OK, rv); 608 EXPECT_EQ("Bypass message", contents); 609 610 // We should have no entries in our bad proxy list. 611 ASSERT_EQ(0u, proxy_service_->proxy_retry_info().size()); 612 } 613 614 #if defined(SPDY_PROXY_AUTH_ORIGIN) 615 TEST_F(HttpNetworkLayerTest, ServerFallbackWithProxyTimedBypass) { 616 // Verify that a Chrome-Proxy: bypass=<seconds> header induces proxy 617 // fallback to a second proxy, if configured. 618 std::string bad_proxy = GetChromeProxy(); 619 ConfigureTestDependencies(ProxyService::CreateFixedFromPacResult( 620 "PROXY " + bad_proxy + "; PROXY good:8080")); 621 622 MockRead data_reads[] = { 623 MockRead("HTTP/1.1 200 OK\r\n" 624 "Connection: keep-alive\r\n" 625 "Chrome-Proxy: bypass=86400\r\n" 626 "Via: 1.1 Chrome Compression Proxy\r\n\r\n"), 627 MockRead("Bypass message"), 628 MockRead(SYNCHRONOUS, OK), 629 }; 630 631 TestProxyFallbackWithMockReads(bad_proxy, "", data_reads, 632 arraysize(data_reads), 1u); 633 EXPECT_EQ(base::TimeDelta::FromSeconds(86400), 634 (*proxy_service_->proxy_retry_info().begin()).second.current_delay); 635 } 636 637 TEST_F(HttpNetworkLayerTest, ServerFallbackWithWrongViaHeader) { 638 // Verify that a Via header that lacks the Chrome-Proxy induces proxy fallback 639 // to a second proxy, if configured. 640 std::string chrome_proxy = GetChromeProxy(); 641 ConfigureTestDependencies(ProxyService::CreateFixedFromPacResult( 642 "PROXY " + chrome_proxy + "; PROXY good:8080")); 643 644 MockRead data_reads[] = { 645 MockRead("HTTP/1.1 200 OK\r\n" 646 "Connection: keep-alive\r\n" 647 "Via: 1.0 some-other-proxy\r\n\r\n"), 648 MockRead("Bypass message"), 649 MockRead(SYNCHRONOUS, OK), 650 }; 651 652 TestProxyFallbackWithMockReads(chrome_proxy, std::string(), data_reads, 653 arraysize(data_reads), 1u); 654 } 655 656 TEST_F(HttpNetworkLayerTest, ServerFallbackWithNoViaHeader) { 657 // Verify that the lack of a Via header induces proxy fallback to a second 658 // proxy, if configured. 659 std::string chrome_proxy = GetChromeProxy(); 660 ConfigureTestDependencies(ProxyService::CreateFixedFromPacResult( 661 "PROXY " + chrome_proxy + "; PROXY good:8080")); 662 663 MockRead data_reads[] = { 664 MockRead("HTTP/1.1 200 OK\r\n" 665 "Connection: keep-alive\r\n\r\n"), 666 MockRead("Bypass message"), 667 MockRead(SYNCHRONOUS, OK), 668 }; 669 670 TestProxyFallbackWithMockReads(chrome_proxy, std::string(), data_reads, 671 arraysize(data_reads), 1u); 672 } 673 674 TEST_F(HttpNetworkLayerTest, NoServerFallbackWith304Response) { 675 // Verify that Chrome will not be induced to bypass the Chrome proxy when 676 // the Chrome Proxy via header is absent on a 304. 677 std::string chrome_proxy = GetChromeProxy(); 678 ConfigureTestDependencies(ProxyService::CreateFixedFromPacResult( 679 "PROXY " + chrome_proxy + "; PROXY good:8080")); 680 681 MockRead data_reads[] = { 682 MockRead("HTTP/1.1 304 Not Modified\r\n" 683 "Connection: keep-alive\r\n\r\n"), 684 MockRead(SYNCHRONOUS, OK), 685 }; 686 687 TestProxyFallbackByMethodWithMockReads(chrome_proxy, std::string(), 688 data_reads, arraysize(data_reads), 689 "GET", std::string(), false, 0); 690 } 691 692 TEST_F(HttpNetworkLayerTest, NoServerFallbackWithChainedViaHeader) { 693 // Verify that Chrome will not be induced to bypass the Chrome proxy when 694 // the Chrome Proxy via header is present, even if that header is chained. 695 std::string chrome_proxy = GetChromeProxy(); 696 ConfigureTestDependencies(ProxyService::CreateFixedFromPacResult( 697 "PROXY " + chrome_proxy + "; PROXY good:8080")); 698 699 MockRead data_reads[] = { 700 MockRead("HTTP/1.1 200 OK\r\n" 701 "Connection: keep-alive\r\n" 702 "Via: 1.1 Chrome Compression Proxy, 1.0 some-other-proxy\r\n\r\n"), 703 MockRead("Bypass message"), 704 MockRead(SYNCHRONOUS, OK), 705 }; 706 707 TestProxyFallbackByMethodWithMockReads(chrome_proxy, std::string(), 708 data_reads, arraysize(data_reads), 709 "GET", "Bypass message", false, 0); 710 } 711 712 #if defined(DATA_REDUCTION_FALLBACK_HOST) 713 TEST_F(HttpNetworkLayerTest, ServerFallbackWithProxyTimedBypassAll) { 714 // Verify that a Chrome-Proxy: block=<seconds> header bypasses a 715 // a configured Chrome-Proxy and fallback and induces proxy fallback to a 716 // third proxy, if configured. 717 std::string bad_proxy = GetChromeProxy(); 718 std::string fallback_proxy = GetChromeFallbackProxy(); 719 ConfigureTestDependencies(ProxyService::CreateFixedFromPacResult( 720 "PROXY " + bad_proxy + "; PROXY " + fallback_proxy + 721 "; PROXY good:8080")); 722 723 MockRead data_reads[] = { 724 MockRead("HTTP/1.1 200 OK\r\n" 725 "Connection: keep-alive\r\n" 726 "Chrome-Proxy: block=86400\r\n" 727 "Via: 1.1 Chrome Compression Proxy\r\n\r\n"), 728 MockRead("Bypass message"), 729 MockRead(SYNCHRONOUS, OK), 730 }; 731 732 TestProxyFallbackWithMockReads(bad_proxy, fallback_proxy, data_reads, 733 arraysize(data_reads), 2u); 734 EXPECT_EQ(base::TimeDelta::FromSeconds(86400), 735 (*proxy_service_->proxy_retry_info().begin()).second.current_delay); 736 } 737 #endif // defined(DATA_REDUCTION_FALLBACK_HOST) 738 #endif // defined(SPDY_PROXY_AUTH_ORIGIN) 739 740 TEST_F(HttpNetworkLayerTest, NetworkVerified) { 741 MockRead data_reads[] = { 742 MockRead("HTTP/1.0 200 OK\r\n\r\n"), 743 MockRead("hello world"), 744 MockRead(SYNCHRONOUS, OK), 745 }; 746 MockWrite data_writes[] = { 747 MockWrite("GET / HTTP/1.1\r\n" 748 "Host: www.google.com\r\n" 749 "Connection: keep-alive\r\n" 750 "User-Agent: Foo/1.0\r\n\r\n"), 751 }; 752 StaticSocketDataProvider data(data_reads, arraysize(data_reads), 753 data_writes, arraysize(data_writes)); 754 mock_socket_factory_.AddSocketDataProvider(&data); 755 756 TestCompletionCallback callback; 757 758 HttpRequestInfo request_info; 759 request_info.url = GURL("http://www.google.com/"); 760 request_info.method = "GET"; 761 request_info.extra_headers.SetHeader(HttpRequestHeaders::kUserAgent, 762 "Foo/1.0"); 763 request_info.load_flags = LOAD_NORMAL; 764 765 scoped_ptr<HttpTransaction> trans; 766 int rv = factory_->CreateTransaction(DEFAULT_PRIORITY, &trans, NULL); 767 EXPECT_EQ(OK, rv); 768 769 rv = trans->Start(&request_info, callback.callback(), BoundNetLog()); 770 ASSERT_EQ(OK, callback.GetResult(rv)); 771 772 EXPECT_TRUE(trans->GetResponseInfo()->network_accessed); 773 } 774 775 TEST_F(HttpNetworkLayerTest, NetworkUnVerified) { 776 MockRead data_reads[] = { 777 MockRead(ASYNC, ERR_CONNECTION_RESET), 778 }; 779 MockWrite data_writes[] = { 780 MockWrite("GET / HTTP/1.1\r\n" 781 "Host: www.google.com\r\n" 782 "Connection: keep-alive\r\n" 783 "User-Agent: Foo/1.0\r\n\r\n"), 784 }; 785 StaticSocketDataProvider data(data_reads, arraysize(data_reads), 786 data_writes, arraysize(data_writes)); 787 mock_socket_factory_.AddSocketDataProvider(&data); 788 789 TestCompletionCallback callback; 790 791 HttpRequestInfo request_info; 792 request_info.url = GURL("http://www.google.com/"); 793 request_info.method = "GET"; 794 request_info.extra_headers.SetHeader(HttpRequestHeaders::kUserAgent, 795 "Foo/1.0"); 796 request_info.load_flags = LOAD_NORMAL; 797 798 scoped_ptr<HttpTransaction> trans; 799 int rv = factory_->CreateTransaction(DEFAULT_PRIORITY, &trans, NULL); 800 EXPECT_EQ(OK, rv); 801 802 rv = trans->Start(&request_info, callback.callback(), BoundNetLog()); 803 ASSERT_EQ(ERR_CONNECTION_RESET, callback.GetResult(rv)); 804 805 // If the response info is null, that means that any consumer won't 806 // see the network accessed bit set. 807 EXPECT_EQ(NULL, trans->GetResponseInfo()); 808 } 809 810 } // namespace 811 812 } // namespace net 813