Home | History | Annotate | Download | only in http
      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