http_network_layer_unittest.cc revision 8bcbed890bc3ce4d7a057a8f32cab53fa534672e
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/strings/stringprintf.h" 8#include "net/base/net_log.h" 9#include "net/cert/mock_cert_verifier.h" 10#include "net/dns/mock_host_resolver.h" 11#include "net/http/http_network_session.h" 12#include "net/http/http_server_properties_impl.h" 13#include "net/http/http_transaction_unittest.h" 14#include "net/http/transport_security_state.h" 15#include "net/proxy/proxy_service.h" 16#include "net/socket/socket_test_util.h" 17#include "net/spdy/spdy_session_pool.h" 18#include "net/ssl/ssl_config_service_defaults.h" 19#include "testing/gtest/include/gtest/gtest.h" 20#include "testing/platform_test.h" 21 22namespace net { 23 24namespace { 25 26class HttpNetworkLayerTest : public PlatformTest { 27 protected: 28 HttpNetworkLayerTest() : ssl_config_service_(new SSLConfigServiceDefaults) {} 29 30 virtual void SetUp() { 31 ConfigureTestDependencies(ProxyService::CreateDirect()); 32 } 33 34 void ConfigureTestDependencies(ProxyService* proxy_service) { 35 cert_verifier_.reset(new MockCertVerifier); 36 transport_security_state_.reset(new TransportSecurityState); 37 proxy_service_.reset(proxy_service); 38 HttpNetworkSession::Params session_params; 39 session_params.client_socket_factory = &mock_socket_factory_; 40 session_params.host_resolver = &host_resolver_; 41 session_params.cert_verifier = cert_verifier_.get(); 42 session_params.transport_security_state = transport_security_state_.get(); 43 session_params.proxy_service = proxy_service_.get(); 44 session_params.ssl_config_service = ssl_config_service_.get(); 45 session_params.http_server_properties = 46 http_server_properties_.GetWeakPtr(); 47 network_session_ = new HttpNetworkSession(session_params); 48 factory_.reset(new HttpNetworkLayer(network_session_.get())); 49 } 50 51 void ExecuteRequestExpectingContentAndHeader(const std::string& content, 52 const std::string& header, 53 const std::string& value) { 54 TestCompletionCallback callback; 55 56 HttpRequestInfo request_info; 57 request_info.url = GURL("http://www.google.com/"); 58 request_info.method = "GET"; 59 request_info.load_flags = LOAD_NORMAL; 60 61 scoped_ptr<HttpTransaction> trans; 62 int rv = factory_->CreateTransaction(DEFAULT_PRIORITY, &trans, NULL); 63 EXPECT_EQ(OK, rv); 64 65 rv = trans->Start(&request_info, callback.callback(), BoundNetLog()); 66 if (rv == ERR_IO_PENDING) 67 rv = callback.WaitForResult(); 68 ASSERT_EQ(OK, rv); 69 70 std::string contents; 71 rv = ReadTransaction(trans.get(), &contents); 72 EXPECT_EQ(OK, rv); 73 EXPECT_EQ(content, contents); 74 75 if (!header.empty()) { 76 // We also have a server header here that isn't set by the proxy. 77 EXPECT_TRUE(trans->GetResponseInfo()->headers->HasHeaderValue( 78 header, value)); 79 } 80 } 81 82 // Check that |proxy_count| proxies are in the retry list. 83 // These will be, in order, "bad:8080" and "alsobad:8080". 84 void TestBadProxies(unsigned int proxy_count) { 85 const ProxyRetryInfoMap& retry_info = proxy_service_->proxy_retry_info(); 86 ASSERT_EQ(proxy_count, retry_info.size()); 87 ASSERT_TRUE(retry_info.find("bad:8080") != retry_info.end()); 88 if (proxy_count > 1) 89 ASSERT_TRUE(retry_info.find("alsobad:8080") != retry_info.end()); 90 } 91 92 // Simulates a request through a proxy which returns a bypass, which is then 93 // retried through a second proxy that doesn't bypass. 94 // Checks that the expected requests were issued, the expected content was 95 // recieved, and the first proxy ("bad:8080") was marked as bad. 96 void TestProxyFallback() { 97 MockRead data_reads[] = { 98 MockRead("HTTP/1.1 200 OK\r\n" 99 "Connection: proxy-bypass\r\n\r\n"), 100 MockRead("Bypass message"), 101 MockRead(SYNCHRONOUS, OK), 102 }; 103 MockWrite data_writes[] = { 104 MockWrite("GET http://www.google.com/ HTTP/1.1\r\n" 105 "Host: www.google.com\r\n" 106 "Proxy-Connection: keep-alive\r\n\r\n"), 107 }; 108 109 StaticSocketDataProvider data1(data_reads, arraysize(data_reads), 110 data_writes, arraysize(data_writes)); 111 mock_socket_factory_.AddSocketDataProvider(&data1); 112 113 // Second data provider returns the expected content. 114 MockRead data_reads2[] = { 115 MockRead("HTTP/1.0 200 OK\r\n" 116 "Server: not-proxy\r\n\r\n"), 117 MockRead("content"), 118 MockRead(SYNCHRONOUS, OK), 119 }; 120 MockWrite data_writes2[] = { 121 MockWrite("GET http://www.google.com/ HTTP/1.1\r\n" 122 "Host: www.google.com\r\n" 123 "Proxy-Connection: keep-alive\r\n\r\n"), 124 }; 125 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), 126 data_writes2, arraysize(data_writes2)); 127 mock_socket_factory_.AddSocketDataProvider(&data2); 128 129 // Expect that we get "content" and not "Bypass message", and that there's 130 // a "not-proxy" "Server:" header in the final response. 131 ExecuteRequestExpectingContentAndHeader("content", "server", "not-proxy"); 132 133 // We should also observe the bad proxy in the retry list. 134 TestBadProxies(1u); 135 } 136 137 // Simulates a request through a proxy which returns a bypass, which is then 138 // retried through a direct connection to the origin site. 139 // Checks that the expected requests were issued, the expected content was 140 // received, and the proxy ("bad:8080") was marked as bad. 141 void TestProxyFallbackToDirect() { 142 MockRead data_reads[] = { 143 MockRead("HTTP/1.1 200 OK\r\n" 144 "Connection: proxy-bypass\r\n\r\n"), 145 MockRead("Bypass message"), 146 MockRead(SYNCHRONOUS, OK), 147 }; 148 MockWrite data_writes[] = { 149 MockWrite("GET http://www.google.com/ HTTP/1.1\r\n" 150 "Host: www.google.com\r\n" 151 "Proxy-Connection: keep-alive\r\n\r\n"), 152 }; 153 StaticSocketDataProvider data1(data_reads, arraysize(data_reads), 154 data_writes, arraysize(data_writes)); 155 mock_socket_factory_.AddSocketDataProvider(&data1); 156 157 // Second data provider returns the expected content. 158 MockRead data_reads2[] = { 159 MockRead("HTTP/1.0 200 OK\r\n" 160 "Server: not-proxy\r\n\r\n"), 161 MockRead("content"), 162 MockRead(SYNCHRONOUS, OK), 163 }; 164 MockWrite data_writes2[] = { 165 MockWrite("GET / HTTP/1.1\r\n" 166 "Host: www.google.com\r\n" 167 "Connection: keep-alive\r\n\r\n"), 168 }; 169 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), 170 data_writes2, arraysize(data_writes2)); 171 mock_socket_factory_.AddSocketDataProvider(&data2); 172 173 // Expect that we get "content" and not "Bypass message", and that there's 174 // a "not-proxy" "Server:" header in the final response. 175 ExecuteRequestExpectingContentAndHeader("content", "server", "not-proxy"); 176 177 // We should also observe the bad proxy in the retry list. 178 TestBadProxies(1u); 179 } 180 181 // Simulates a request through a proxy which returns a bypass, under a 182 // configuration where there is no valid bypass. |proxy_count| proxies 183 // are expected to be configured. 184 // Checks that the expected requests were issued, the bypass message was the 185 // final received content, and all proxies were marked as bad. 186 void TestProxyFallbackFail(unsigned int proxy_count) { 187 MockRead data_reads[] = { 188 MockRead("HTTP/1.1 200 OK\r\n" 189 "Connection: proxy-bypass\r\n\r\n"), 190 MockRead("Bypass message"), 191 MockRead(SYNCHRONOUS, OK), 192 }; 193 MockWrite data_writes[] = { 194 MockWrite("GET http://www.google.com/ HTTP/1.1\r\n" 195 "Host: www.google.com\r\n" 196 "Proxy-Connection: keep-alive\r\n\r\n"), 197 }; 198 StaticSocketDataProvider data1(data_reads, arraysize(data_reads), 199 data_writes, arraysize(data_writes)); 200 StaticSocketDataProvider data2(data_reads, arraysize(data_reads), 201 data_writes, arraysize(data_writes)); 202 203 mock_socket_factory_.AddSocketDataProvider(&data1); 204 if (proxy_count > 1) 205 mock_socket_factory_.AddSocketDataProvider(&data2); 206 207 // Expect that we get "Bypass message", and not "content".. 208 ExecuteRequestExpectingContentAndHeader("Bypass message", "", ""); 209 210 // We should also observe the bad proxy or proxies in the retry list. 211 TestBadProxies(proxy_count); 212 } 213 214 MockClientSocketFactory mock_socket_factory_; 215 MockHostResolver host_resolver_; 216 scoped_ptr<CertVerifier> cert_verifier_; 217 scoped_ptr<TransportSecurityState> transport_security_state_; 218 scoped_ptr<ProxyService> proxy_service_; 219 const scoped_refptr<SSLConfigService> ssl_config_service_; 220 scoped_refptr<HttpNetworkSession> network_session_; 221 scoped_ptr<HttpNetworkLayer> factory_; 222 HttpServerPropertiesImpl http_server_properties_; 223}; 224 225TEST_F(HttpNetworkLayerTest, CreateAndDestroy) { 226 scoped_ptr<HttpTransaction> trans; 227 int rv = factory_->CreateTransaction(DEFAULT_PRIORITY, &trans, NULL); 228 EXPECT_EQ(OK, rv); 229 EXPECT_TRUE(trans.get() != NULL); 230} 231 232TEST_F(HttpNetworkLayerTest, Suspend) { 233 scoped_ptr<HttpTransaction> trans; 234 int rv = factory_->CreateTransaction(DEFAULT_PRIORITY, &trans, NULL); 235 EXPECT_EQ(OK, rv); 236 237 trans.reset(); 238 239 factory_->OnSuspend(); 240 241 rv = factory_->CreateTransaction(DEFAULT_PRIORITY, &trans, NULL); 242 EXPECT_EQ(ERR_NETWORK_IO_SUSPENDED, rv); 243 244 ASSERT_TRUE(trans == NULL); 245 246 factory_->OnResume(); 247 248 rv = factory_->CreateTransaction(DEFAULT_PRIORITY, &trans, NULL); 249 EXPECT_EQ(OK, rv); 250} 251 252TEST_F(HttpNetworkLayerTest, GET) { 253 MockRead data_reads[] = { 254 MockRead("HTTP/1.0 200 OK\r\n\r\n"), 255 MockRead("hello world"), 256 MockRead(SYNCHRONOUS, OK), 257 }; 258 MockWrite data_writes[] = { 259 MockWrite("GET / HTTP/1.1\r\n" 260 "Host: www.google.com\r\n" 261 "Connection: keep-alive\r\n" 262 "User-Agent: Foo/1.0\r\n\r\n"), 263 }; 264 StaticSocketDataProvider data(data_reads, arraysize(data_reads), 265 data_writes, arraysize(data_writes)); 266 mock_socket_factory_.AddSocketDataProvider(&data); 267 268 TestCompletionCallback callback; 269 270 HttpRequestInfo request_info; 271 request_info.url = GURL("http://www.google.com/"); 272 request_info.method = "GET"; 273 request_info.extra_headers.SetHeader(HttpRequestHeaders::kUserAgent, 274 "Foo/1.0"); 275 request_info.load_flags = LOAD_NORMAL; 276 277 scoped_ptr<HttpTransaction> trans; 278 int rv = factory_->CreateTransaction(DEFAULT_PRIORITY, &trans, NULL); 279 EXPECT_EQ(OK, rv); 280 281 rv = trans->Start(&request_info, callback.callback(), BoundNetLog()); 282 rv = callback.GetResult(rv); 283 ASSERT_EQ(OK, rv); 284 285 std::string contents; 286 rv = ReadTransaction(trans.get(), &contents); 287 EXPECT_EQ(OK, rv); 288 EXPECT_EQ("hello world", contents); 289} 290 291// Proxy bypass tests. These tests run through various server-induced 292// proxy-bypass scenarios using both PAC file and fixed proxy params. 293// The test scenarios are: 294// - bypass with two proxies configured and the first but not the second 295// is bypassed. 296// - bypass with one proxy configured and an explicit fallback to direct 297// connections 298// - bypass with two proxies configured and both are bypassed 299// - bypass with one proxy configured which is bypassed with no defined 300// fallback 301 302TEST_F(HttpNetworkLayerTest, ServerTwoProxyBypassPac) { 303 ConfigureTestDependencies(ProxyService::CreateFixedFromPacResult( 304 "PROXY bad:8080; PROXY good:8080")); 305 TestProxyFallback(); 306} 307 308TEST_F(HttpNetworkLayerTest, ServerTwoProxyBypassFixed) { 309 ConfigureTestDependencies(ProxyService::CreateFixed("bad:8080, good:8080")); 310 TestProxyFallback(); 311} 312 313TEST_F(HttpNetworkLayerTest, ServerOneProxyWithDirectBypassPac) { 314 ConfigureTestDependencies(ProxyService::CreateFixedFromPacResult( 315 "PROXY bad:8080; DIRECT")); 316 TestProxyFallbackToDirect(); 317} 318 319TEST_F(HttpNetworkLayerTest, ServerOneProxyWithDirectBypassFixed) { 320 ConfigureTestDependencies(ProxyService::CreateFixed( "bad:8080, direct://")); 321 TestProxyFallbackToDirect(); 322} 323 324TEST_F(HttpNetworkLayerTest, ServerTwoProxyDoubleBypassPac) { 325 ConfigureTestDependencies(ProxyService::CreateFixedFromPacResult( 326 "PROXY bad:8080; PROXY alsobad:8080")); 327 TestProxyFallbackFail(2u); 328} 329 330TEST_F(HttpNetworkLayerTest, ServerTwoProxyDoubleBypassFixed) { 331 ConfigureTestDependencies(ProxyService::CreateFixed( 332 "bad:8080, alsobad:8080")); 333 TestProxyFallbackFail(2u); 334} 335 336TEST_F(HttpNetworkLayerTest, ServerOneProxyNoDirectBypassPac) { 337 ConfigureTestDependencies(ProxyService::CreateFixedFromPacResult( 338 "PROXY bad:8080")); 339 TestProxyFallbackFail(1u); 340} 341 342TEST_F(HttpNetworkLayerTest, ServerOneProxyNoDirectBypassFixed) { 343 ConfigureTestDependencies(ProxyService::CreateFixed("bad:8080")); 344 TestProxyFallbackFail(1u); 345} 346 347#if defined(SPDY_PROXY_AUTH_ORIGIN) 348TEST_F(HttpNetworkLayerTest, ServerFallbackOnInternalServerError) { 349 // Verify that "500 Internal Server Error" via the data reduction proxy 350 // induces proxy fallback to a second proxy, if configured. 351 352 // To configure this test, we need to wire up a custom proxy service to use 353 // a pair of proxies. We'll induce fallback via the first and return 354 // the expected data via the second. 355 std::string data_reduction_proxy( 356 HostPortPair::FromURL(GURL(SPDY_PROXY_AUTH_ORIGIN)).ToString()); 357 std::string pac_string = base::StringPrintf( 358 "PROXY %s; PROXY good:8080", data_reduction_proxy.data()); 359 ConfigureTestDependencies(ProxyService::CreateFixedFromPacResult(pac_string)); 360 361 MockRead data_reads[] = { 362 MockRead("HTTP/1.1 500 Internal Server Error\r\n\r\n"), 363 MockRead("Bypass message"), 364 MockRead(SYNCHRONOUS, OK), 365 }; 366 MockWrite data_writes[] = { 367 MockWrite("GET http://www.google.com/ HTTP/1.1\r\n" 368 "Host: www.google.com\r\n" 369 "Proxy-Connection: keep-alive\r\n\r\n"), 370 }; 371 StaticSocketDataProvider data1(data_reads, arraysize(data_reads), 372 data_writes, arraysize(data_writes)); 373 mock_socket_factory_.AddSocketDataProvider(&data1); 374 375 // Second data provider returns the expected content. 376 MockRead data_reads2[] = { 377 MockRead("HTTP/1.0 200 OK\r\n" 378 "Server: not-proxy\r\n\r\n"), 379 MockRead("content"), 380 MockRead(SYNCHRONOUS, OK), 381 }; 382 MockWrite data_writes2[] = { 383 MockWrite("GET http://www.google.com/ HTTP/1.1\r\n" 384 "Host: www.google.com\r\n" 385 "Proxy-Connection: keep-alive\r\n\r\n"), 386 }; 387 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), 388 data_writes2, arraysize(data_writes2)); 389 mock_socket_factory_.AddSocketDataProvider(&data2); 390 391 TestCompletionCallback callback; 392 393 HttpRequestInfo request_info; 394 request_info.url = GURL("http://www.google.com/"); 395 request_info.method = "GET"; 396 request_info.load_flags = LOAD_NORMAL; 397 398 scoped_ptr<HttpTransaction> trans; 399 int rv = factory_->CreateTransaction(DEFAULT_PRIORITY, &trans, NULL); 400 EXPECT_EQ(OK, rv); 401 402 rv = trans->Start(&request_info, callback.callback(), BoundNetLog()); 403 if (rv == ERR_IO_PENDING) 404 rv = callback.WaitForResult(); 405 ASSERT_EQ(OK, rv); 406 407 std::string contents; 408 rv = ReadTransaction(trans.get(), &contents); 409 EXPECT_EQ(OK, rv); 410 411 // We should obtain content from the second socket provider write 412 // corresponding to the fallback proxy. 413 EXPECT_EQ("content", contents); 414 // We also have a server header here that isn't set by the proxy. 415 EXPECT_TRUE(trans->GetResponseInfo()->headers->HasHeaderValue( 416 "server", "not-proxy")); 417 // We should also observe the data reduction proxy in the retry list. 418 ASSERT_TRUE(1u == proxy_service_->proxy_retry_info().size()); 419 EXPECT_EQ(data_reduction_proxy, 420 (*proxy_service_->proxy_retry_info().begin()).first); 421} 422#endif // defined(SPDY_PROXY_AUTH_ORIGIN) 423 424TEST_F(HttpNetworkLayerTest, ProxyBypassIgnoredOnDirectConnectionPac) { 425 // Verify that a Connection: proxy-bypass header is ignored when returned 426 // from a directly connected origin server. 427 ConfigureTestDependencies(ProxyService::CreateFixedFromPacResult("DIRECT")); 428 429 MockRead data_reads[] = { 430 MockRead("HTTP/1.1 200 OK\r\n" 431 "Connection: proxy-bypass\r\n\r\n"), 432 MockRead("Bypass message"), 433 MockRead(SYNCHRONOUS, OK), 434 }; 435 MockWrite data_writes[] = { 436 MockWrite("GET / HTTP/1.1\r\n" 437 "Host: www.google.com\r\n" 438 "Connection: keep-alive\r\n\r\n"), 439 }; 440 StaticSocketDataProvider data1(data_reads, arraysize(data_reads), 441 data_writes, arraysize(data_writes)); 442 mock_socket_factory_.AddSocketDataProvider(&data1); 443 TestCompletionCallback callback; 444 445 HttpRequestInfo request_info; 446 request_info.url = GURL("http://www.google.com/"); 447 request_info.method = "GET"; 448 request_info.load_flags = LOAD_NORMAL; 449 450 scoped_ptr<HttpTransaction> trans; 451 int rv = factory_->CreateTransaction(DEFAULT_PRIORITY, &trans, NULL); 452 EXPECT_EQ(OK, rv); 453 454 rv = trans->Start(&request_info, callback.callback(), BoundNetLog()); 455 if (rv == ERR_IO_PENDING) 456 rv = callback.WaitForResult(); 457 ASSERT_EQ(OK, rv); 458 459 // We should have read the original page data. 460 std::string contents; 461 rv = ReadTransaction(trans.get(), &contents); 462 EXPECT_EQ(OK, rv); 463 EXPECT_EQ("Bypass message", contents); 464 465 // We should have no entries in our bad proxy list. 466 ASSERT_EQ(0u, proxy_service_->proxy_retry_info().size()); 467} 468 469TEST_F(HttpNetworkLayerTest, NetworkVerified) { 470 MockRead data_reads[] = { 471 MockRead("HTTP/1.0 200 OK\r\n\r\n"), 472 MockRead("hello world"), 473 MockRead(SYNCHRONOUS, OK), 474 }; 475 MockWrite data_writes[] = { 476 MockWrite("GET / HTTP/1.1\r\n" 477 "Host: www.google.com\r\n" 478 "Connection: keep-alive\r\n" 479 "User-Agent: Foo/1.0\r\n\r\n"), 480 }; 481 StaticSocketDataProvider data(data_reads, arraysize(data_reads), 482 data_writes, arraysize(data_writes)); 483 mock_socket_factory_.AddSocketDataProvider(&data); 484 485 TestCompletionCallback callback; 486 487 HttpRequestInfo request_info; 488 request_info.url = GURL("http://www.google.com/"); 489 request_info.method = "GET"; 490 request_info.extra_headers.SetHeader(HttpRequestHeaders::kUserAgent, 491 "Foo/1.0"); 492 request_info.load_flags = LOAD_NORMAL; 493 494 scoped_ptr<HttpTransaction> trans; 495 int rv = factory_->CreateTransaction(DEFAULT_PRIORITY, &trans, NULL); 496 EXPECT_EQ(OK, rv); 497 498 rv = trans->Start(&request_info, callback.callback(), BoundNetLog()); 499 ASSERT_EQ(OK, callback.GetResult(rv)); 500 501 EXPECT_TRUE(trans->GetResponseInfo()->network_accessed); 502} 503 504TEST_F(HttpNetworkLayerTest, NetworkUnVerified) { 505 MockRead data_reads[] = { 506 MockRead(ASYNC, ERR_CONNECTION_RESET), 507 }; 508 MockWrite data_writes[] = { 509 MockWrite("GET / HTTP/1.1\r\n" 510 "Host: www.google.com\r\n" 511 "Connection: keep-alive\r\n" 512 "User-Agent: Foo/1.0\r\n\r\n"), 513 }; 514 StaticSocketDataProvider data(data_reads, arraysize(data_reads), 515 data_writes, arraysize(data_writes)); 516 mock_socket_factory_.AddSocketDataProvider(&data); 517 518 TestCompletionCallback callback; 519 520 HttpRequestInfo request_info; 521 request_info.url = GURL("http://www.google.com/"); 522 request_info.method = "GET"; 523 request_info.extra_headers.SetHeader(HttpRequestHeaders::kUserAgent, 524 "Foo/1.0"); 525 request_info.load_flags = LOAD_NORMAL; 526 527 scoped_ptr<HttpTransaction> trans; 528 int rv = factory_->CreateTransaction(DEFAULT_PRIORITY, &trans, NULL); 529 EXPECT_EQ(OK, rv); 530 531 rv = trans->Start(&request_info, callback.callback(), BoundNetLog()); 532 ASSERT_EQ(ERR_CONNECTION_RESET, callback.GetResult(rv)); 533 534 // If the response info is null, that means that any consumer won't 535 // see the network accessed bit set. 536 EXPECT_EQ(NULL, trans->GetResponseInfo()); 537} 538 539} // namespace 540 541} // namespace net 542