http_network_layer_unittest.cc revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
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
23namespace net {
24
25namespace {
26
27class 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);
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_of_retry,
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_of_retry.empty())
165      data_reads2[data_reads2_index++] = MockRead(content_of_retry.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_of_retry,
179                                              "server", "not-proxy");
180    } else {
181      ExecuteRequestExpectingContentAndHeader(method, "Bypass message", "", "");
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
279TEST_F(HttpNetworkLayerTest, CreateAndDestroy) {
280  scoped_ptr<HttpTransaction> trans;
281  int rv = factory_->CreateTransaction(DEFAULT_PRIORITY, &trans);
282  EXPECT_EQ(OK, rv);
283  EXPECT_TRUE(trans.get() != NULL);
284}
285
286TEST_F(HttpNetworkLayerTest, Suspend) {
287  scoped_ptr<HttpTransaction> trans;
288  int rv = factory_->CreateTransaction(DEFAULT_PRIORITY, &trans);
289  EXPECT_EQ(OK, rv);
290
291  trans.reset();
292
293  factory_->OnSuspend();
294
295  rv = factory_->CreateTransaction(DEFAULT_PRIORITY, &trans);
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);
303  EXPECT_EQ(OK, rv);
304}
305
306TEST_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);
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)
357TEST_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
364TEST_F(HttpNetworkLayerTest, ServerTwoProxyBypassFixed) {
365  std::string bad_proxy = GetChromeProxy();
366  ConfigureTestDependencies(
367      ProxyService::CreateFixed(bad_proxy +", good:8080"));
368  TestProxyFallback(bad_proxy);
369}
370
371TEST_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
432TEST_F(HttpNetworkLayerTest, ServerOneProxyWithDirectBypassPac) {
433  std::string bad_proxy = GetChromeProxy();
434  ConfigureTestDependencies(ProxyService::CreateFixedFromPacResult(
435      "PROXY " + bad_proxy + "; DIRECT"));
436  TestProxyFallbackToDirect(bad_proxy);
437}
438
439TEST_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)
447TEST_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
456TEST_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
466TEST_F(HttpNetworkLayerTest, ServerOneProxyNoDirectBypassPac) {
467  std::string bad_proxy = GetChromeProxy();
468  ConfigureTestDependencies(ProxyService::CreateFixedFromPacResult(
469      "PROXY " + bad_proxy));
470  TestProxyFallbackFail(1u, bad_proxy, "");
471}
472
473TEST_F(HttpNetworkLayerTest, ServerOneProxyNoDirectBypassFixed) {
474  std::string bad_proxy = GetChromeProxy();
475  ConfigureTestDependencies(ProxyService::CreateFixed(bad_proxy));
476  TestProxyFallbackFail(1u, bad_proxy, "");
477}
478
479TEST_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);
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
569TEST_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);
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)
615TEST_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
637TEST_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
656TEST_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
674TEST_F(HttpNetworkLayerTest, NoServerFallbackWithChainedViaHeader) {
675  // Verify that Chrome will not be induced to bypass the Chrome proxy when
676  // the Chrome Proxy via header is present, even if that header is chained.
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 200 OK\r\n"
683             "Connection: keep-alive\r\n"
684             "Via: 1.1 Chrome-Compression-Proxy, 1.0 some-other-proxy\r\n\r\n"),
685    MockRead("Bypass message"),
686    MockRead(SYNCHRONOUS, OK),
687  };
688
689  TestProxyFallbackByMethodWithMockReads(chrome_proxy, std::string(),
690                                         data_reads, arraysize(data_reads),
691                                         "GET", std::string(), false, 0);
692}
693
694TEST_F(HttpNetworkLayerTest, NoServerFallbackWithDeprecatedViaHeader) {
695  // Verify that Chrome will not be induced to bypass the Chrome proxy when
696  // the Chrome Proxy via header is present, even if that header is chained.
697  std::string chrome_proxy = GetChromeProxy();
698  ConfigureTestDependencies(ProxyService::CreateFixedFromPacResult(
699      "PROXY " + chrome_proxy + "; PROXY good:8080"));
700
701  MockRead data_reads[] = {
702    MockRead("HTTP/1.1 200 OK\r\n"
703             "Connection: keep-alive\r\n"
704             "Via: 1.1 Chrome Compression Proxy\r\n\r\n"),
705    MockRead("Bypass message"),
706    MockRead(SYNCHRONOUS, OK),
707  };
708
709  TestProxyFallbackByMethodWithMockReads(chrome_proxy, std::string(),
710                                         data_reads, arraysize(data_reads),
711                                         "GET", std::string(), false, 0);
712}
713
714#if defined(DATA_REDUCTION_FALLBACK_HOST)
715TEST_F(HttpNetworkLayerTest, ServerFallbackWithProxyTimedBypassAll) {
716  // Verify that a Chrome-Proxy: block=<seconds> header bypasses a
717  // a configured Chrome-Proxy and fallback and induces proxy fallback to a
718  // third proxy, if configured.
719  std::string bad_proxy = GetChromeProxy();
720  std::string fallback_proxy = GetChromeFallbackProxy();
721  ConfigureTestDependencies(ProxyService::CreateFixedFromPacResult(
722      "PROXY " + bad_proxy + "; PROXY " + fallback_proxy +
723      "; PROXY good:8080"));
724
725  MockRead data_reads[] = {
726    MockRead("HTTP/1.1 200 OK\r\n"
727             "Connection: keep-alive\r\n"
728             "Chrome-Proxy: block=86400\r\n"
729             "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n"),
730    MockRead("Bypass message"),
731    MockRead(SYNCHRONOUS, OK),
732  };
733
734  TestProxyFallbackWithMockReads(bad_proxy, fallback_proxy, data_reads,
735                                 arraysize(data_reads), 2u);
736  EXPECT_EQ(base::TimeDelta::FromSeconds(86400),
737            (*proxy_service_->proxy_retry_info().begin()).second.current_delay);
738}
739#endif  // defined(DATA_REDUCTION_FALLBACK_HOST)
740#endif  // defined(SPDY_PROXY_AUTH_ORIGIN)
741
742TEST_F(HttpNetworkLayerTest, NetworkVerified) {
743  MockRead data_reads[] = {
744    MockRead("HTTP/1.0 200 OK\r\n\r\n"),
745    MockRead("hello world"),
746    MockRead(SYNCHRONOUS, OK),
747  };
748  MockWrite data_writes[] = {
749    MockWrite("GET / HTTP/1.1\r\n"
750              "Host: www.google.com\r\n"
751              "Connection: keep-alive\r\n"
752              "User-Agent: Foo/1.0\r\n\r\n"),
753  };
754  StaticSocketDataProvider data(data_reads, arraysize(data_reads),
755                                data_writes, arraysize(data_writes));
756  mock_socket_factory_.AddSocketDataProvider(&data);
757
758  TestCompletionCallback callback;
759
760  HttpRequestInfo request_info;
761  request_info.url = GURL("http://www.google.com/");
762  request_info.method = "GET";
763  request_info.extra_headers.SetHeader(HttpRequestHeaders::kUserAgent,
764                                       "Foo/1.0");
765  request_info.load_flags = LOAD_NORMAL;
766
767  scoped_ptr<HttpTransaction> trans;
768  int rv = factory_->CreateTransaction(DEFAULT_PRIORITY, &trans);
769  EXPECT_EQ(OK, rv);
770
771  rv = trans->Start(&request_info, callback.callback(), BoundNetLog());
772  ASSERT_EQ(OK, callback.GetResult(rv));
773
774  EXPECT_TRUE(trans->GetResponseInfo()->network_accessed);
775}
776
777TEST_F(HttpNetworkLayerTest, NetworkUnVerified) {
778  MockRead data_reads[] = {
779    MockRead(ASYNC, ERR_CONNECTION_RESET),
780  };
781  MockWrite data_writes[] = {
782    MockWrite("GET / HTTP/1.1\r\n"
783              "Host: www.google.com\r\n"
784              "Connection: keep-alive\r\n"
785              "User-Agent: Foo/1.0\r\n\r\n"),
786  };
787  StaticSocketDataProvider data(data_reads, arraysize(data_reads),
788                                data_writes, arraysize(data_writes));
789  mock_socket_factory_.AddSocketDataProvider(&data);
790
791  TestCompletionCallback callback;
792
793  HttpRequestInfo request_info;
794  request_info.url = GURL("http://www.google.com/");
795  request_info.method = "GET";
796  request_info.extra_headers.SetHeader(HttpRequestHeaders::kUserAgent,
797                                       "Foo/1.0");
798  request_info.load_flags = LOAD_NORMAL;
799
800  scoped_ptr<HttpTransaction> trans;
801  int rv = factory_->CreateTransaction(DEFAULT_PRIORITY, &trans);
802  EXPECT_EQ(OK, rv);
803
804  rv = trans->Start(&request_info, callback.callback(), BoundNetLog());
805  ASSERT_EQ(ERR_CONNECTION_RESET, callback.GetResult(rv));
806
807  // If the response info is null, that means that any consumer won't
808  // see the network accessed bit set.
809  EXPECT_EQ(NULL, trans->GetResponseInfo());
810}
811
812}  // namespace
813
814}  // namespace net
815