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 22 namespace net { 23 24 namespace { 25 26 class 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 MockClientSocketFactory mock_socket_factory_; 52 MockHostResolver host_resolver_; 53 scoped_ptr<CertVerifier> cert_verifier_; 54 scoped_ptr<TransportSecurityState> transport_security_state_; 55 scoped_ptr<ProxyService> proxy_service_; 56 const scoped_refptr<SSLConfigService> ssl_config_service_; 57 scoped_refptr<HttpNetworkSession> network_session_; 58 scoped_ptr<HttpNetworkLayer> factory_; 59 HttpServerPropertiesImpl http_server_properties_; 60 }; 61 62 TEST_F(HttpNetworkLayerTest, CreateAndDestroy) { 63 scoped_ptr<HttpTransaction> trans; 64 int rv = factory_->CreateTransaction(DEFAULT_PRIORITY, &trans, NULL); 65 EXPECT_EQ(OK, rv); 66 EXPECT_TRUE(trans.get() != NULL); 67 } 68 69 TEST_F(HttpNetworkLayerTest, Suspend) { 70 scoped_ptr<HttpTransaction> trans; 71 int rv = factory_->CreateTransaction(DEFAULT_PRIORITY, &trans, NULL); 72 EXPECT_EQ(OK, rv); 73 74 trans.reset(); 75 76 factory_->OnSuspend(); 77 78 rv = factory_->CreateTransaction(DEFAULT_PRIORITY, &trans, NULL); 79 EXPECT_EQ(ERR_NETWORK_IO_SUSPENDED, rv); 80 81 ASSERT_TRUE(trans == NULL); 82 83 factory_->OnResume(); 84 85 rv = factory_->CreateTransaction(DEFAULT_PRIORITY, &trans, NULL); 86 EXPECT_EQ(OK, rv); 87 } 88 89 TEST_F(HttpNetworkLayerTest, GET) { 90 MockRead data_reads[] = { 91 MockRead("HTTP/1.0 200 OK\r\n\r\n"), 92 MockRead("hello world"), 93 MockRead(SYNCHRONOUS, OK), 94 }; 95 MockWrite data_writes[] = { 96 MockWrite("GET / HTTP/1.1\r\n" 97 "Host: www.google.com\r\n" 98 "Connection: keep-alive\r\n" 99 "User-Agent: Foo/1.0\r\n\r\n"), 100 }; 101 StaticSocketDataProvider data(data_reads, arraysize(data_reads), 102 data_writes, arraysize(data_writes)); 103 mock_socket_factory_.AddSocketDataProvider(&data); 104 105 TestCompletionCallback callback; 106 107 HttpRequestInfo request_info; 108 request_info.url = GURL("http://www.google.com/"); 109 request_info.method = "GET"; 110 request_info.extra_headers.SetHeader(HttpRequestHeaders::kUserAgent, 111 "Foo/1.0"); 112 request_info.load_flags = LOAD_NORMAL; 113 114 scoped_ptr<HttpTransaction> trans; 115 int rv = factory_->CreateTransaction(DEFAULT_PRIORITY, &trans, NULL); 116 EXPECT_EQ(OK, rv); 117 118 rv = trans->Start(&request_info, callback.callback(), BoundNetLog()); 119 rv = callback.GetResult(rv); 120 ASSERT_EQ(OK, rv); 121 122 std::string contents; 123 rv = ReadTransaction(trans.get(), &contents); 124 EXPECT_EQ(OK, rv); 125 EXPECT_EQ("hello world", contents); 126 } 127 128 TEST_F(HttpNetworkLayerTest, ServerFallback) { 129 // Verify that a Connection: Proxy-Bypass header induces proxy fallback to 130 // a second proxy, if configured. 131 132 // To configure this test, we need to wire up a custom proxy service to use 133 // a pair of proxies. We'll induce fallback via the first and return 134 // the expected data via the second. 135 ConfigureTestDependencies(ProxyService::CreateFixedFromPacResult( 136 "PROXY bad:8080; PROXY good:8080")); 137 138 MockRead data_reads[] = { 139 MockRead("HTTP/1.1 200 OK\r\n" 140 "Connection: proxy-bypass\r\n\r\n"), 141 MockRead("Bypass message"), 142 MockRead(SYNCHRONOUS, OK), 143 }; 144 MockWrite data_writes[] = { 145 MockWrite("GET http://www.google.com/ HTTP/1.1\r\n" 146 "Host: www.google.com\r\n" 147 "Proxy-Connection: keep-alive\r\n\r\n"), 148 }; 149 StaticSocketDataProvider data1(data_reads, arraysize(data_reads), 150 data_writes, arraysize(data_writes)); 151 mock_socket_factory_.AddSocketDataProvider(&data1); 152 153 // Second data provider returns the expected content. 154 MockRead data_reads2[] = { 155 MockRead("HTTP/1.0 200 OK\r\n" 156 "Server: not-proxy\r\n\r\n"), 157 MockRead("content"), 158 MockRead(SYNCHRONOUS, OK), 159 }; 160 MockWrite data_writes2[] = { 161 MockWrite("GET http://www.google.com/ HTTP/1.1\r\n" 162 "Host: www.google.com\r\n" 163 "Proxy-Connection: keep-alive\r\n\r\n"), 164 }; 165 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), 166 data_writes2, arraysize(data_writes2)); 167 mock_socket_factory_.AddSocketDataProvider(&data2); 168 169 TestCompletionCallback callback; 170 171 HttpRequestInfo request_info; 172 request_info.url = GURL("http://www.google.com/"); 173 request_info.method = "GET"; 174 request_info.load_flags = LOAD_NORMAL; 175 176 scoped_ptr<HttpTransaction> trans; 177 int rv = factory_->CreateTransaction(DEFAULT_PRIORITY, &trans, NULL); 178 EXPECT_EQ(OK, rv); 179 180 rv = trans->Start(&request_info, callback.callback(), BoundNetLog()); 181 if (rv == ERR_IO_PENDING) 182 rv = callback.WaitForResult(); 183 ASSERT_EQ(OK, rv); 184 185 std::string contents; 186 rv = ReadTransaction(trans.get(), &contents); 187 EXPECT_EQ(OK, rv); 188 189 // We should obtain content from the second socket provider write 190 // corresponding to the fallback proxy. 191 EXPECT_EQ("content", contents); 192 // We also have a server header here that isn't set by the proxy. 193 EXPECT_TRUE(trans->GetResponseInfo()->headers->HasHeaderValue( 194 "server", "not-proxy")); 195 // We should also observe the bad proxy in the retry list. 196 ASSERT_TRUE(1u == proxy_service_->proxy_retry_info().size()); 197 EXPECT_EQ("bad:8080", (*proxy_service_->proxy_retry_info().begin()).first); 198 } 199 200 #if defined(SPDY_PROXY_AUTH_ORIGIN) 201 TEST_F(HttpNetworkLayerTest, ServerFallbackOnInternalServerError) { 202 // Verify that "500 Internal Server Error" via the data reduction proxy 203 // induces proxy fallback to a second proxy, if configured. 204 205 // To configure this test, we need to wire up a custom proxy service to use 206 // a pair of proxies. We'll induce fallback via the first and return 207 // the expected data via the second. 208 std::string data_reduction_proxy( 209 HostPortPair::FromURL(GURL(SPDY_PROXY_AUTH_ORIGIN)).ToString()); 210 std::string pac_string = base::StringPrintf( 211 "PROXY %s; PROXY good:8080", data_reduction_proxy.data()); 212 ConfigureTestDependencies(ProxyService::CreateFixedFromPacResult(pac_string)); 213 214 MockRead data_reads[] = { 215 MockRead("HTTP/1.1 500 Internal Server Error\r\n\r\n"), 216 MockRead("Bypass message"), 217 MockRead(SYNCHRONOUS, OK), 218 }; 219 MockWrite data_writes[] = { 220 MockWrite("GET http://www.google.com/ HTTP/1.1\r\n" 221 "Host: www.google.com\r\n" 222 "Proxy-Connection: keep-alive\r\n\r\n"), 223 }; 224 StaticSocketDataProvider data1(data_reads, arraysize(data_reads), 225 data_writes, arraysize(data_writes)); 226 mock_socket_factory_.AddSocketDataProvider(&data1); 227 228 // Second data provider returns the expected content. 229 MockRead data_reads2[] = { 230 MockRead("HTTP/1.0 200 OK\r\n" 231 "Server: not-proxy\r\n\r\n"), 232 MockRead("content"), 233 MockRead(SYNCHRONOUS, OK), 234 }; 235 MockWrite data_writes2[] = { 236 MockWrite("GET http://www.google.com/ HTTP/1.1\r\n" 237 "Host: www.google.com\r\n" 238 "Proxy-Connection: keep-alive\r\n\r\n"), 239 }; 240 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), 241 data_writes2, arraysize(data_writes2)); 242 mock_socket_factory_.AddSocketDataProvider(&data2); 243 244 TestCompletionCallback callback; 245 246 HttpRequestInfo request_info; 247 request_info.url = GURL("http://www.google.com/"); 248 request_info.method = "GET"; 249 request_info.load_flags = LOAD_NORMAL; 250 251 scoped_ptr<HttpTransaction> trans; 252 int rv = factory_->CreateTransaction(DEFAULT_PRIORITY, &trans, NULL); 253 EXPECT_EQ(OK, rv); 254 255 rv = trans->Start(&request_info, callback.callback(), BoundNetLog()); 256 if (rv == ERR_IO_PENDING) 257 rv = callback.WaitForResult(); 258 ASSERT_EQ(OK, rv); 259 260 std::string contents; 261 rv = ReadTransaction(trans.get(), &contents); 262 EXPECT_EQ(OK, rv); 263 264 // We should obtain content from the second socket provider write 265 // corresponding to the fallback proxy. 266 EXPECT_EQ("content", contents); 267 // We also have a server header here that isn't set by the proxy. 268 EXPECT_TRUE(trans->GetResponseInfo()->headers->HasHeaderValue( 269 "server", "not-proxy")); 270 // We should also observe the data reduction proxy in the retry list. 271 ASSERT_TRUE(1u == proxy_service_->proxy_retry_info().size()); 272 EXPECT_EQ(data_reduction_proxy, 273 (*proxy_service_->proxy_retry_info().begin()).first); 274 } 275 #endif // defined(SPDY_PROXY_AUTH_ORIGIN) 276 277 TEST_F(HttpNetworkLayerTest, ServerFallbackDoesntLoop) { 278 // Verify that a Connection: Proxy-Bypass header will display the original 279 // proxy's error page content if a fallback option is not configured. 280 ConfigureTestDependencies(ProxyService::CreateFixedFromPacResult( 281 "PROXY bad:8080; PROXY alsobad:8080")); 282 283 MockRead data_reads[] = { 284 MockRead("HTTP/1.1 200 OK\r\n" 285 "Connection: proxy-bypass\r\n\r\n"), 286 MockRead("Bypass message"), 287 MockRead(SYNCHRONOUS, OK), 288 }; 289 MockWrite data_writes[] = { 290 MockWrite("GET http://www.google.com/ HTTP/1.1\r\n" 291 "Host: www.google.com\r\n" 292 "Proxy-Connection: keep-alive\r\n\r\n"), 293 }; 294 StaticSocketDataProvider data1(data_reads, arraysize(data_reads), 295 data_writes, arraysize(data_writes)); 296 StaticSocketDataProvider data2(data_reads, arraysize(data_reads), 297 data_writes, arraysize(data_writes)); 298 mock_socket_factory_.AddSocketDataProvider(&data1); 299 mock_socket_factory_.AddSocketDataProvider(&data2); 300 301 TestCompletionCallback callback; 302 303 HttpRequestInfo request_info; 304 request_info.url = GURL("http://www.google.com/"); 305 request_info.method = "GET"; 306 request_info.load_flags = LOAD_NORMAL; 307 308 scoped_ptr<HttpTransaction> trans; 309 int rv = factory_->CreateTransaction(DEFAULT_PRIORITY, &trans, NULL); 310 EXPECT_EQ(OK, rv); 311 312 rv = trans->Start(&request_info, callback.callback(), BoundNetLog()); 313 if (rv == ERR_IO_PENDING) 314 rv = callback.WaitForResult(); 315 ASSERT_EQ(OK, rv); 316 317 std::string contents; 318 rv = ReadTransaction(trans.get(), &contents); 319 EXPECT_EQ(OK, rv); 320 EXPECT_EQ("Bypass message", contents); 321 322 // Despite not falling back to anything, we should still observe the proxies 323 // in the bad proxies list. 324 const ProxyRetryInfoMap& retry_info = proxy_service_->proxy_retry_info(); 325 ASSERT_EQ(2u, retry_info.size()); 326 ASSERT_TRUE(retry_info.find("bad:8080") != retry_info.end()); 327 ASSERT_TRUE(retry_info.find("alsobad:8080") != retry_info.end()); 328 } 329 330 TEST_F(HttpNetworkLayerTest, ProxyBypassIgnoredOnDirectConnection) { 331 // Verify that a Connection: proxy-bypass header is ignored when returned 332 // from a directly connected origin server. 333 ConfigureTestDependencies(ProxyService::CreateFixedFromPacResult("DIRECT")); 334 335 MockRead data_reads[] = { 336 MockRead("HTTP/1.1 200 OK\r\n" 337 "Connection: proxy-bypass\r\n\r\n"), 338 MockRead("Bypass message"), 339 MockRead(SYNCHRONOUS, OK), 340 }; 341 MockWrite data_writes[] = { 342 MockWrite("GET / HTTP/1.1\r\n" 343 "Host: www.google.com\r\n" 344 "Connection: keep-alive\r\n\r\n"), 345 }; 346 StaticSocketDataProvider data1(data_reads, arraysize(data_reads), 347 data_writes, arraysize(data_writes)); 348 mock_socket_factory_.AddSocketDataProvider(&data1); 349 TestCompletionCallback callback; 350 351 HttpRequestInfo request_info; 352 request_info.url = GURL("http://www.google.com/"); 353 request_info.method = "GET"; 354 request_info.load_flags = LOAD_NORMAL; 355 356 scoped_ptr<HttpTransaction> trans; 357 int rv = factory_->CreateTransaction(DEFAULT_PRIORITY, &trans, NULL); 358 EXPECT_EQ(OK, rv); 359 360 rv = trans->Start(&request_info, callback.callback(), BoundNetLog()); 361 if (rv == ERR_IO_PENDING) 362 rv = callback.WaitForResult(); 363 ASSERT_EQ(OK, rv); 364 365 // We should have read the original page data. 366 std::string contents; 367 rv = ReadTransaction(trans.get(), &contents); 368 EXPECT_EQ(OK, rv); 369 EXPECT_EQ("Bypass message", contents); 370 371 // We should have no entries in our bad proxy list. 372 ASSERT_EQ(0u, proxy_service_->proxy_retry_info().size()); 373 } 374 375 TEST_F(HttpNetworkLayerTest, NetworkVerified) { 376 MockRead data_reads[] = { 377 MockRead("HTTP/1.0 200 OK\r\n\r\n"), 378 MockRead("hello world"), 379 MockRead(SYNCHRONOUS, OK), 380 }; 381 MockWrite data_writes[] = { 382 MockWrite("GET / HTTP/1.1\r\n" 383 "Host: www.google.com\r\n" 384 "Connection: keep-alive\r\n" 385 "User-Agent: Foo/1.0\r\n\r\n"), 386 }; 387 StaticSocketDataProvider data(data_reads, arraysize(data_reads), 388 data_writes, arraysize(data_writes)); 389 mock_socket_factory_.AddSocketDataProvider(&data); 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.extra_headers.SetHeader(HttpRequestHeaders::kUserAgent, 397 "Foo/1.0"); 398 request_info.load_flags = LOAD_NORMAL; 399 400 scoped_ptr<HttpTransaction> trans; 401 int rv = factory_->CreateTransaction(DEFAULT_PRIORITY, &trans, NULL); 402 EXPECT_EQ(OK, rv); 403 404 rv = trans->Start(&request_info, callback.callback(), BoundNetLog()); 405 ASSERT_EQ(OK, callback.GetResult(rv)); 406 407 EXPECT_TRUE(trans->GetResponseInfo()->network_accessed); 408 } 409 410 TEST_F(HttpNetworkLayerTest, NetworkUnVerified) { 411 MockRead data_reads[] = { 412 MockRead(ASYNC, ERR_CONNECTION_RESET), 413 }; 414 MockWrite data_writes[] = { 415 MockWrite("GET / HTTP/1.1\r\n" 416 "Host: www.google.com\r\n" 417 "Connection: keep-alive\r\n" 418 "User-Agent: Foo/1.0\r\n\r\n"), 419 }; 420 StaticSocketDataProvider data(data_reads, arraysize(data_reads), 421 data_writes, arraysize(data_writes)); 422 mock_socket_factory_.AddSocketDataProvider(&data); 423 424 TestCompletionCallback callback; 425 426 HttpRequestInfo request_info; 427 request_info.url = GURL("http://www.google.com/"); 428 request_info.method = "GET"; 429 request_info.extra_headers.SetHeader(HttpRequestHeaders::kUserAgent, 430 "Foo/1.0"); 431 request_info.load_flags = LOAD_NORMAL; 432 433 scoped_ptr<HttpTransaction> trans; 434 int rv = factory_->CreateTransaction(DEFAULT_PRIORITY, &trans, NULL); 435 EXPECT_EQ(OK, rv); 436 437 rv = trans->Start(&request_info, callback.callback(), BoundNetLog()); 438 ASSERT_EQ(ERR_CONNECTION_RESET, callback.GetResult(rv)); 439 440 // If the response info is null, that means that any consumer won't 441 // see the network accessed bit set. 442 EXPECT_EQ(NULL, trans->GetResponseInfo()); 443 } 444 445 } // namespace 446 447 } // namespace net 448