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_proxy_client_socket_pool.h"
      6 
      7 #include "base/callback.h"
      8 #include "base/compiler_specific.h"
      9 #include "base/strings/string_util.h"
     10 #include "base/strings/utf_string_conversions.h"
     11 #include "net/base/net_errors.h"
     12 #include "net/base/test_completion_callback.h"
     13 #include "net/http/http_network_session.h"
     14 #include "net/http/http_proxy_client_socket.h"
     15 #include "net/http/http_response_headers.h"
     16 #include "net/socket/client_socket_handle.h"
     17 #include "net/socket/client_socket_pool_histograms.h"
     18 #include "net/socket/next_proto.h"
     19 #include "net/socket/socket_test_util.h"
     20 #include "net/spdy/spdy_protocol.h"
     21 #include "net/spdy/spdy_test_util_common.h"
     22 #include "testing/gtest/include/gtest/gtest.h"
     23 
     24 namespace net {
     25 
     26 namespace {
     27 
     28 const int kMaxSockets = 32;
     29 const int kMaxSocketsPerGroup = 6;
     30 const char * const kAuthHeaders[] = {
     31   "proxy-authorization", "Basic Zm9vOmJhcg=="
     32 };
     33 const int kAuthHeadersSize = arraysize(kAuthHeaders) / 2;
     34 
     35 enum HttpProxyType {
     36   HTTP,
     37   HTTPS,
     38   SPDY
     39 };
     40 
     41 struct HttpProxyClientSocketPoolTestParams {
     42   HttpProxyClientSocketPoolTestParams()
     43       : proxy_type(HTTP),
     44         protocol(kProtoSPDY2) {}
     45 
     46   HttpProxyClientSocketPoolTestParams(
     47       HttpProxyType proxy_type,
     48       NextProto protocol)
     49       : proxy_type(proxy_type),
     50         protocol(protocol) {}
     51 
     52   HttpProxyType proxy_type;
     53   NextProto protocol;
     54 };
     55 
     56 typedef ::testing::TestWithParam<HttpProxyType> TestWithHttpParam;
     57 
     58 }  // namespace
     59 
     60 class HttpProxyClientSocketPoolTest
     61     : public ::testing::TestWithParam<HttpProxyClientSocketPoolTestParams> {
     62  protected:
     63   HttpProxyClientSocketPoolTest()
     64       : session_deps_(GetParam().protocol),
     65         ssl_config_(),
     66         ignored_transport_socket_params_(
     67             new TransportSocketParams(HostPortPair("proxy", 80),
     68                                       LOWEST,
     69                                       false,
     70                                       false,
     71                                       OnHostResolutionCallback())),
     72         ignored_ssl_socket_params_(
     73             new SSLSocketParams(ignored_transport_socket_params_,
     74                                 NULL,
     75                                 NULL,
     76                                 ProxyServer::SCHEME_DIRECT,
     77                                 HostPortPair("www.google.com", 443),
     78                                 ssl_config_,
     79                                 kPrivacyModeDisabled,
     80                                 0,
     81                                 false,
     82                                 false)),
     83         tcp_histograms_("MockTCP"),
     84         transport_socket_pool_(
     85             kMaxSockets,
     86             kMaxSocketsPerGroup,
     87             &tcp_histograms_,
     88             session_deps_.deterministic_socket_factory.get()),
     89         ssl_histograms_("MockSSL"),
     90         ssl_socket_pool_(kMaxSockets,
     91                          kMaxSocketsPerGroup,
     92                          &ssl_histograms_,
     93                          session_deps_.host_resolver.get(),
     94                          session_deps_.cert_verifier.get(),
     95                          NULL /* server_bound_cert_store */,
     96                          NULL /* transport_security_state */,
     97                          std::string() /* ssl_session_cache_shard */,
     98                          session_deps_.deterministic_socket_factory.get(),
     99                          &transport_socket_pool_,
    100                          NULL,
    101                          NULL,
    102                          session_deps_.ssl_config_service.get(),
    103                          BoundNetLog().net_log()),
    104         session_(CreateNetworkSession()),
    105         http_proxy_histograms_("HttpProxyUnitTest"),
    106         spdy_util_(GetParam().protocol),
    107         pool_(kMaxSockets,
    108               kMaxSocketsPerGroup,
    109               &http_proxy_histograms_,
    110               NULL,
    111               &transport_socket_pool_,
    112               &ssl_socket_pool_,
    113               NULL) {}
    114 
    115   virtual ~HttpProxyClientSocketPoolTest() {
    116   }
    117 
    118   void AddAuthToCache() {
    119     const base::string16 kFoo(ASCIIToUTF16("foo"));
    120     const base::string16 kBar(ASCIIToUTF16("bar"));
    121     GURL proxy_url(GetParam().proxy_type == HTTP ? "http://proxy" : "https://proxy:80");
    122     session_->http_auth_cache()->Add(proxy_url,
    123                                      "MyRealm1",
    124                                      HttpAuth::AUTH_SCHEME_BASIC,
    125                                      "Basic realm=MyRealm1",
    126                                      AuthCredentials(kFoo, kBar),
    127                                      "/");
    128   }
    129 
    130   scoped_refptr<TransportSocketParams> GetTcpParams() {
    131     if (GetParam().proxy_type != HTTP)
    132       return scoped_refptr<TransportSocketParams>();
    133     return ignored_transport_socket_params_;
    134   }
    135 
    136   scoped_refptr<SSLSocketParams> GetSslParams() {
    137     if (GetParam().proxy_type == HTTP)
    138       return scoped_refptr<SSLSocketParams>();
    139     return ignored_ssl_socket_params_;
    140   }
    141 
    142   // Returns the a correctly constructed HttpProxyParms
    143   // for the HTTP or HTTPS proxy.
    144   scoped_refptr<HttpProxySocketParams> GetParams(bool tunnel) {
    145     return scoped_refptr<HttpProxySocketParams>(new HttpProxySocketParams(
    146         GetTcpParams(),
    147         GetSslParams(),
    148         GURL(tunnel ? "https://www.google.com/" : "http://www.google.com"),
    149         std::string(),
    150         HostPortPair("www.google.com", tunnel ? 443 : 80),
    151         session_->http_auth_cache(),
    152         session_->http_auth_handler_factory(),
    153         session_->spdy_session_pool(),
    154         tunnel));
    155   }
    156 
    157   scoped_refptr<HttpProxySocketParams> GetTunnelParams() {
    158     return GetParams(true);
    159   }
    160 
    161   scoped_refptr<HttpProxySocketParams> GetNoTunnelParams() {
    162     return GetParams(false);
    163   }
    164 
    165   DeterministicMockClientSocketFactory& socket_factory() {
    166     return *session_deps_.deterministic_socket_factory.get();
    167   }
    168 
    169   void Initialize(MockRead* reads, size_t reads_count,
    170                   MockWrite* writes, size_t writes_count,
    171                   MockRead* spdy_reads, size_t spdy_reads_count,
    172                   MockWrite* spdy_writes, size_t spdy_writes_count) {
    173     if (GetParam().proxy_type == SPDY) {
    174       data_.reset(new DeterministicSocketData(spdy_reads, spdy_reads_count,
    175                                               spdy_writes, spdy_writes_count));
    176     } else {
    177       data_.reset(new DeterministicSocketData(reads, reads_count, writes,
    178                                               writes_count));
    179     }
    180 
    181     data_->set_connect_data(MockConnect(SYNCHRONOUS, OK));
    182     data_->StopAfter(2);  // Request / Response
    183 
    184     socket_factory().AddSocketDataProvider(data_.get());
    185 
    186     if (GetParam().proxy_type != HTTP) {
    187       ssl_data_.reset(new SSLSocketDataProvider(SYNCHRONOUS, OK));
    188       if (GetParam().proxy_type == SPDY) {
    189         InitializeSpdySsl();
    190       }
    191       socket_factory().AddSSLSocketDataProvider(ssl_data_.get());
    192     }
    193   }
    194 
    195   void InitializeSpdySsl() {
    196     ssl_data_->SetNextProto(GetParam().protocol);
    197   }
    198 
    199   HttpNetworkSession* CreateNetworkSession() {
    200     return SpdySessionDependencies::SpdyCreateSessionDeterministic(
    201         &session_deps_);
    202   }
    203 
    204  private:
    205   SpdySessionDependencies session_deps_;
    206   SSLConfig ssl_config_;
    207 
    208   scoped_refptr<TransportSocketParams> ignored_transport_socket_params_;
    209   scoped_refptr<SSLSocketParams> ignored_ssl_socket_params_;
    210   ClientSocketPoolHistograms tcp_histograms_;
    211   MockTransportClientSocketPool transport_socket_pool_;
    212   ClientSocketPoolHistograms ssl_histograms_;
    213   MockHostResolver host_resolver_;
    214   scoped_ptr<CertVerifier> cert_verifier_;
    215   SSLClientSocketPool ssl_socket_pool_;
    216 
    217   const scoped_refptr<HttpNetworkSession> session_;
    218   ClientSocketPoolHistograms http_proxy_histograms_;
    219 
    220  protected:
    221   SpdyTestUtil spdy_util_;
    222   scoped_ptr<SSLSocketDataProvider> ssl_data_;
    223   scoped_ptr<DeterministicSocketData> data_;
    224   HttpProxyClientSocketPool pool_;
    225   ClientSocketHandle handle_;
    226   TestCompletionCallback callback_;
    227 };
    228 
    229 //-----------------------------------------------------------------------------
    230 // All tests are run with three different proxy types: HTTP, HTTPS (non-SPDY)
    231 // and SPDY.
    232 //
    233 // TODO(akalin): Use ::testing::Combine() when we are able to use
    234 // <tr1/tuple>.
    235 INSTANTIATE_TEST_CASE_P(
    236     HttpProxyClientSocketPoolTests,
    237     HttpProxyClientSocketPoolTest,
    238     ::testing::Values(
    239         HttpProxyClientSocketPoolTestParams(HTTP, kProtoSPDY2),
    240         HttpProxyClientSocketPoolTestParams(HTTPS, kProtoSPDY2),
    241         HttpProxyClientSocketPoolTestParams(SPDY, kProtoSPDY2),
    242         HttpProxyClientSocketPoolTestParams(HTTP, kProtoSPDY3),
    243         HttpProxyClientSocketPoolTestParams(HTTPS, kProtoSPDY3),
    244         HttpProxyClientSocketPoolTestParams(SPDY, kProtoSPDY3),
    245         HttpProxyClientSocketPoolTestParams(HTTP, kProtoSPDY31),
    246         HttpProxyClientSocketPoolTestParams(HTTPS, kProtoSPDY31),
    247         HttpProxyClientSocketPoolTestParams(SPDY, kProtoSPDY31),
    248         HttpProxyClientSocketPoolTestParams(HTTP, kProtoSPDY4a2),
    249         HttpProxyClientSocketPoolTestParams(HTTPS, kProtoSPDY4a2),
    250         HttpProxyClientSocketPoolTestParams(SPDY, kProtoSPDY4a2),
    251         HttpProxyClientSocketPoolTestParams(HTTP, kProtoHTTP2Draft04),
    252         HttpProxyClientSocketPoolTestParams(HTTPS, kProtoHTTP2Draft04),
    253         HttpProxyClientSocketPoolTestParams(SPDY, kProtoHTTP2Draft04)));
    254 
    255 TEST_P(HttpProxyClientSocketPoolTest, NoTunnel) {
    256   Initialize(NULL, 0, NULL, 0, NULL, 0, NULL, 0);
    257 
    258   int rv = handle_.Init("a", GetNoTunnelParams(), LOW, CompletionCallback(),
    259                         &pool_, BoundNetLog());
    260   EXPECT_EQ(OK, rv);
    261   EXPECT_TRUE(handle_.is_initialized());
    262   ASSERT_TRUE(handle_.socket());
    263   HttpProxyClientSocket* tunnel_socket =
    264           static_cast<HttpProxyClientSocket*>(handle_.socket());
    265   EXPECT_TRUE(tunnel_socket->IsConnected());
    266 }
    267 
    268 TEST_P(HttpProxyClientSocketPoolTest, NeedAuth) {
    269   MockWrite writes[] = {
    270     MockWrite(ASYNC, 0, "CONNECT www.google.com:443 HTTP/1.1\r\n"
    271               "Host: www.google.com\r\n"
    272               "Proxy-Connection: keep-alive\r\n\r\n"),
    273   };
    274   MockRead reads[] = {
    275     // No credentials.
    276     MockRead(ASYNC, 1, "HTTP/1.1 407 Proxy Authentication Required\r\n"),
    277     MockRead(ASYNC, 2, "Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
    278     MockRead(ASYNC, 3, "Content-Length: 10\r\n\r\n"),
    279     MockRead(ASYNC, 4, "0123456789"),
    280   };
    281   scoped_ptr<SpdyFrame> req(
    282       spdy_util_.ConstructSpdyConnect(NULL, 0, 1));
    283   scoped_ptr<SpdyFrame> rst(
    284       spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL));
    285   MockWrite spdy_writes[] = {
    286     CreateMockWrite(*req, 0, ASYNC),
    287     CreateMockWrite(*rst, 2, ASYNC),
    288   };
    289   const char* const kAuthChallenge[] = {
    290     spdy_util_.GetStatusKey(), "407 Proxy Authentication Required",
    291     spdy_util_.GetVersionKey(), "HTTP/1.1",
    292     "proxy-authenticate", "Basic realm=\"MyRealm1\"",
    293   };
    294   scoped_ptr<SpdyFrame> resp(
    295       spdy_util_.ConstructSpdyControlFrame(NULL,
    296                                            0,
    297                                            false,
    298                                            1,
    299                                            LOWEST,
    300                                            SYN_REPLY,
    301                                            CONTROL_FLAG_NONE,
    302                                            kAuthChallenge,
    303                                            arraysize(kAuthChallenge),
    304                                            0));
    305   MockRead spdy_reads[] = {
    306     CreateMockRead(*resp, 1, ASYNC),
    307     MockRead(ASYNC, 0, 3)
    308   };
    309 
    310   Initialize(reads, arraysize(reads), writes, arraysize(writes),
    311              spdy_reads, arraysize(spdy_reads), spdy_writes,
    312              arraysize(spdy_writes));
    313 
    314   data_->StopAfter(4);
    315   int rv = handle_.Init("a", GetTunnelParams(), LOW, callback_.callback(),
    316                         &pool_, BoundNetLog());
    317   EXPECT_EQ(ERR_IO_PENDING, rv);
    318   EXPECT_FALSE(handle_.is_initialized());
    319   EXPECT_FALSE(handle_.socket());
    320 
    321   data_->RunFor(GetParam().proxy_type == SPDY ? 2 : 4);
    322   rv = callback_.WaitForResult();
    323   EXPECT_EQ(ERR_PROXY_AUTH_REQUESTED, rv);
    324   EXPECT_TRUE(handle_.is_initialized());
    325   ASSERT_TRUE(handle_.socket());
    326   ProxyClientSocket* tunnel_socket =
    327       static_cast<ProxyClientSocket*>(handle_.socket());
    328   if (GetParam().proxy_type == SPDY) {
    329     EXPECT_TRUE(tunnel_socket->IsConnected());
    330     EXPECT_TRUE(tunnel_socket->IsUsingSpdy());
    331   } else {
    332     EXPECT_FALSE(tunnel_socket->IsConnected());
    333     EXPECT_FALSE(tunnel_socket->IsUsingSpdy());
    334     EXPECT_FALSE(tunnel_socket->IsUsingSpdy());
    335   }
    336 }
    337 
    338 TEST_P(HttpProxyClientSocketPoolTest, HaveAuth) {
    339   // It's pretty much impossible to make the SPDY case behave synchronously
    340   // so we skip this test for SPDY
    341   if (GetParam().proxy_type == SPDY)
    342     return;
    343   MockWrite writes[] = {
    344     MockWrite(SYNCHRONOUS, 0,
    345               "CONNECT www.google.com:443 HTTP/1.1\r\n"
    346               "Host: www.google.com\r\n"
    347               "Proxy-Connection: keep-alive\r\n"
    348               "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
    349   };
    350   MockRead reads[] = {
    351     MockRead(SYNCHRONOUS, 1, "HTTP/1.1 200 Connection Established\r\n\r\n"),
    352   };
    353 
    354   Initialize(reads, arraysize(reads), writes, arraysize(writes), NULL, 0,
    355              NULL, 0);
    356   AddAuthToCache();
    357 
    358   int rv = handle_.Init("a", GetTunnelParams(), LOW, callback_.callback(),
    359                         &pool_, BoundNetLog());
    360   EXPECT_EQ(OK, rv);
    361   EXPECT_TRUE(handle_.is_initialized());
    362   ASSERT_TRUE(handle_.socket());
    363   HttpProxyClientSocket* tunnel_socket =
    364           static_cast<HttpProxyClientSocket*>(handle_.socket());
    365   EXPECT_TRUE(tunnel_socket->IsConnected());
    366 }
    367 
    368 TEST_P(HttpProxyClientSocketPoolTest, AsyncHaveAuth) {
    369   MockWrite writes[] = {
    370     MockWrite(ASYNC, 0, "CONNECT www.google.com:443 HTTP/1.1\r\n"
    371               "Host: www.google.com\r\n"
    372               "Proxy-Connection: keep-alive\r\n"
    373               "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
    374   };
    375   MockRead reads[] = {
    376     MockRead(ASYNC, 1, "HTTP/1.1 200 Connection Established\r\n\r\n"),
    377   };
    378 
    379   scoped_ptr<SpdyFrame> req(
    380       spdy_util_.ConstructSpdyConnect(kAuthHeaders, kAuthHeadersSize, 1));
    381   MockWrite spdy_writes[] = {
    382     CreateMockWrite(*req, 0, ASYNC)
    383   };
    384   scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
    385   MockRead spdy_reads[] = {
    386     CreateMockRead(*resp, 1, ASYNC),
    387     MockRead(ASYNC, 0, 2)
    388   };
    389 
    390   Initialize(reads, arraysize(reads), writes, arraysize(writes),
    391              spdy_reads, arraysize(spdy_reads), spdy_writes,
    392              arraysize(spdy_writes));
    393   AddAuthToCache();
    394 
    395   int rv = handle_.Init("a", GetTunnelParams(), LOW, callback_.callback(),
    396                         &pool_, BoundNetLog());
    397   EXPECT_EQ(ERR_IO_PENDING, rv);
    398   EXPECT_FALSE(handle_.is_initialized());
    399   EXPECT_FALSE(handle_.socket());
    400 
    401   data_->RunFor(2);
    402   EXPECT_EQ(OK, callback_.WaitForResult());
    403   EXPECT_TRUE(handle_.is_initialized());
    404   ASSERT_TRUE(handle_.socket());
    405   HttpProxyClientSocket* tunnel_socket =
    406           static_cast<HttpProxyClientSocket*>(handle_.socket());
    407   EXPECT_TRUE(tunnel_socket->IsConnected());
    408 }
    409 
    410 TEST_P(HttpProxyClientSocketPoolTest, TCPError) {
    411   if (GetParam().proxy_type == SPDY) return;
    412   data_.reset(new DeterministicSocketData(NULL, 0, NULL, 0));
    413   data_->set_connect_data(MockConnect(ASYNC, ERR_CONNECTION_CLOSED));
    414 
    415   socket_factory().AddSocketDataProvider(data_.get());
    416 
    417   int rv = handle_.Init("a", GetTunnelParams(), LOW, callback_.callback(),
    418                         &pool_, BoundNetLog());
    419   EXPECT_EQ(ERR_IO_PENDING, rv);
    420   EXPECT_FALSE(handle_.is_initialized());
    421   EXPECT_FALSE(handle_.socket());
    422 
    423   EXPECT_EQ(ERR_PROXY_CONNECTION_FAILED, callback_.WaitForResult());
    424 
    425   EXPECT_FALSE(handle_.is_initialized());
    426   EXPECT_FALSE(handle_.socket());
    427 }
    428 
    429 TEST_P(HttpProxyClientSocketPoolTest, SSLError) {
    430   if (GetParam().proxy_type == HTTP) return;
    431   data_.reset(new DeterministicSocketData(NULL, 0, NULL, 0));
    432   data_->set_connect_data(MockConnect(ASYNC, OK));
    433   socket_factory().AddSocketDataProvider(data_.get());
    434 
    435   ssl_data_.reset(new SSLSocketDataProvider(ASYNC,
    436                                             ERR_CERT_AUTHORITY_INVALID));
    437   if (GetParam().proxy_type == SPDY) {
    438     InitializeSpdySsl();
    439   }
    440   socket_factory().AddSSLSocketDataProvider(ssl_data_.get());
    441 
    442   int rv = handle_.Init("a", GetTunnelParams(), LOW, callback_.callback(),
    443                         &pool_, BoundNetLog());
    444   EXPECT_EQ(ERR_IO_PENDING, rv);
    445   EXPECT_FALSE(handle_.is_initialized());
    446   EXPECT_FALSE(handle_.socket());
    447 
    448   EXPECT_EQ(ERR_PROXY_CERTIFICATE_INVALID, callback_.WaitForResult());
    449 
    450   EXPECT_FALSE(handle_.is_initialized());
    451   EXPECT_FALSE(handle_.socket());
    452 }
    453 
    454 TEST_P(HttpProxyClientSocketPoolTest, SslClientAuth) {
    455   if (GetParam().proxy_type == HTTP) return;
    456   data_.reset(new DeterministicSocketData(NULL, 0, NULL, 0));
    457   data_->set_connect_data(MockConnect(ASYNC, OK));
    458   socket_factory().AddSocketDataProvider(data_.get());
    459 
    460   ssl_data_.reset(new SSLSocketDataProvider(ASYNC,
    461                                             ERR_SSL_CLIENT_AUTH_CERT_NEEDED));
    462   if (GetParam().proxy_type == SPDY) {
    463     InitializeSpdySsl();
    464   }
    465   socket_factory().AddSSLSocketDataProvider(ssl_data_.get());
    466 
    467   int rv = handle_.Init("a", GetTunnelParams(), LOW, callback_.callback(),
    468                         &pool_, BoundNetLog());
    469   EXPECT_EQ(ERR_IO_PENDING, rv);
    470   EXPECT_FALSE(handle_.is_initialized());
    471   EXPECT_FALSE(handle_.socket());
    472 
    473   EXPECT_EQ(ERR_SSL_CLIENT_AUTH_CERT_NEEDED, callback_.WaitForResult());
    474 
    475   EXPECT_FALSE(handle_.is_initialized());
    476   EXPECT_FALSE(handle_.socket());
    477 }
    478 
    479 TEST_P(HttpProxyClientSocketPoolTest, TunnelUnexpectedClose) {
    480   MockWrite writes[] = {
    481     MockWrite(ASYNC, 0,
    482               "CONNECT www.google.com:443 HTTP/1.1\r\n"
    483               "Host: www.google.com\r\n"
    484               "Proxy-Connection: keep-alive\r\n"
    485               "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
    486   };
    487   MockRead reads[] = {
    488     MockRead(ASYNC, 1, "HTTP/1.1 200 Conn"),
    489     MockRead(ASYNC, ERR_CONNECTION_CLOSED, 2),
    490   };
    491   scoped_ptr<SpdyFrame> req(
    492       spdy_util_.ConstructSpdyConnect(kAuthHeaders, kAuthHeadersSize, 1));
    493   MockWrite spdy_writes[] = {
    494     CreateMockWrite(*req, 0, ASYNC)
    495   };
    496   MockRead spdy_reads[] = {
    497     MockRead(ASYNC, ERR_CONNECTION_CLOSED, 1),
    498   };
    499 
    500   Initialize(reads, arraysize(reads), writes, arraysize(writes),
    501              spdy_reads, arraysize(spdy_reads), spdy_writes,
    502              arraysize(spdy_writes));
    503   AddAuthToCache();
    504 
    505   int rv = handle_.Init("a", GetTunnelParams(), LOW, callback_.callback(),
    506                         &pool_, BoundNetLog());
    507   EXPECT_EQ(ERR_IO_PENDING, rv);
    508   EXPECT_FALSE(handle_.is_initialized());
    509   EXPECT_FALSE(handle_.socket());
    510 
    511   data_->RunFor(3);
    512   if (GetParam().proxy_type == SPDY) {
    513     // SPDY cannot process a headers block unless it's complete and so it
    514     // returns ERR_CONNECTION_CLOSED in this case.
    515     EXPECT_EQ(ERR_CONNECTION_CLOSED, callback_.WaitForResult());
    516   } else {
    517     EXPECT_EQ(ERR_RESPONSE_HEADERS_TRUNCATED, callback_.WaitForResult());
    518   }
    519   EXPECT_FALSE(handle_.is_initialized());
    520   EXPECT_FALSE(handle_.socket());
    521 }
    522 
    523 TEST_P(HttpProxyClientSocketPoolTest, Tunnel1xxResponse) {
    524   // Tests that 1xx responses are rejected for a CONNECT request.
    525   if (GetParam().proxy_type == SPDY) {
    526     // SPDY doesn't have 1xx responses.
    527     return;
    528   }
    529 
    530   MockWrite writes[] = {
    531     MockWrite(ASYNC, 0,
    532               "CONNECT www.google.com:443 HTTP/1.1\r\n"
    533               "Host: www.google.com\r\n"
    534               "Proxy-Connection: keep-alive\r\n\r\n"),
    535   };
    536   MockRead reads[] = {
    537     MockRead(ASYNC, 1, "HTTP/1.1 100 Continue\r\n\r\n"),
    538     MockRead(ASYNC, 2, "HTTP/1.1 200 Connection Established\r\n\r\n"),
    539   };
    540 
    541   Initialize(reads, arraysize(reads), writes, arraysize(writes),
    542              NULL, 0, NULL, 0);
    543 
    544   int rv = handle_.Init("a", CreateTunnelParams(), LOW, callback_.callback(),
    545                         &pool_, BoundNetLog());
    546   EXPECT_EQ(ERR_IO_PENDING, rv);
    547   EXPECT_FALSE(handle_.is_initialized());
    548   EXPECT_FALSE(handle_.socket());
    549 
    550   data_->RunFor(2);
    551   EXPECT_EQ(ERR_TUNNEL_CONNECTION_FAILED, callback_.WaitForResult());
    552 }
    553 
    554 TEST_P(HttpProxyClientSocketPoolTest, TunnelSetupError) {
    555   MockWrite writes[] = {
    556     MockWrite(ASYNC, 0,
    557               "CONNECT www.google.com:443 HTTP/1.1\r\n"
    558               "Host: www.google.com\r\n"
    559               "Proxy-Connection: keep-alive\r\n"
    560               "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
    561   };
    562   MockRead reads[] = {
    563     MockRead(ASYNC, 1, "HTTP/1.1 304 Not Modified\r\n\r\n"),
    564   };
    565   scoped_ptr<SpdyFrame> req(
    566       spdy_util_.ConstructSpdyConnect(kAuthHeaders, kAuthHeadersSize, 1));
    567   scoped_ptr<SpdyFrame> rst(
    568       spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL));
    569   MockWrite spdy_writes[] = {
    570     CreateMockWrite(*req, 0, ASYNC),
    571     CreateMockWrite(*rst, 2, ASYNC),
    572   };
    573   scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdySynReplyError(1));
    574   MockRead spdy_reads[] = {
    575     CreateMockRead(*resp, 1, ASYNC),
    576     MockRead(ASYNC, 0, 3),
    577   };
    578 
    579   Initialize(reads, arraysize(reads), writes, arraysize(writes),
    580              spdy_reads, arraysize(spdy_reads), spdy_writes,
    581              arraysize(spdy_writes));
    582   AddAuthToCache();
    583 
    584   int rv = handle_.Init("a", GetTunnelParams(), LOW, callback_.callback(),
    585                         &pool_, BoundNetLog());
    586   EXPECT_EQ(ERR_IO_PENDING, rv);
    587   EXPECT_FALSE(handle_.is_initialized());
    588   EXPECT_FALSE(handle_.socket());
    589 
    590   data_->RunFor(2);
    591 
    592   rv = callback_.WaitForResult();
    593   // All Proxy CONNECT responses are not trustworthy
    594   EXPECT_EQ(ERR_TUNNEL_CONNECTION_FAILED, rv);
    595   EXPECT_FALSE(handle_.is_initialized());
    596   EXPECT_FALSE(handle_.socket());
    597 }
    598 
    599 TEST_P(HttpProxyClientSocketPoolTest, TunnelSetupRedirect) {
    600   const std::string redirectTarget = "https://foo.google.com/";
    601 
    602   const std::string responseText = "HTTP/1.1 302 Found\r\n"
    603                                    "Location: " + redirectTarget + "\r\n"
    604                                    "Set-Cookie: foo=bar\r\n"
    605                                    "\r\n";
    606   MockWrite writes[] = {
    607     MockWrite(ASYNC, 0,
    608               "CONNECT www.google.com:443 HTTP/1.1\r\n"
    609               "Host: www.google.com\r\n"
    610               "Proxy-Connection: keep-alive\r\n"
    611               "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
    612   };
    613   MockRead reads[] = {
    614     MockRead(ASYNC, 1, responseText.c_str()),
    615   };
    616   scoped_ptr<SpdyFrame> req(
    617       spdy_util_.ConstructSpdyConnect(kAuthHeaders, kAuthHeadersSize, 1));
    618   scoped_ptr<SpdyFrame> rst(
    619       spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL));
    620 
    621   MockWrite spdy_writes[] = {
    622     CreateMockWrite(*req, 0, ASYNC),
    623     CreateMockWrite(*rst, 3, ASYNC),
    624   };
    625 
    626   const char* const responseHeaders[] = {
    627     "location", redirectTarget.c_str(),
    628     "set-cookie", "foo=bar",
    629   };
    630   const int responseHeadersSize = arraysize(responseHeaders) / 2;
    631   scoped_ptr<SpdyFrame> resp(
    632       spdy_util_.ConstructSpdySynReplyError(
    633           "302 Found",
    634           responseHeaders, responseHeadersSize,
    635           1));
    636   MockRead spdy_reads[] = {
    637     CreateMockRead(*resp, 1, ASYNC),
    638     MockRead(ASYNC, 0, 2),
    639   };
    640 
    641   Initialize(reads, arraysize(reads), writes, arraysize(writes),
    642              spdy_reads, arraysize(spdy_reads), spdy_writes,
    643              arraysize(spdy_writes));
    644   AddAuthToCache();
    645 
    646   int rv = handle_.Init("a", GetTunnelParams(), LOW, callback_.callback(),
    647                         &pool_, BoundNetLog());
    648   EXPECT_EQ(ERR_IO_PENDING, rv);
    649   EXPECT_FALSE(handle_.is_initialized());
    650   EXPECT_FALSE(handle_.socket());
    651 
    652   data_->RunFor(2);
    653 
    654   rv = callback_.WaitForResult();
    655 
    656   if (GetParam().proxy_type == HTTP) {
    657     // We don't trust 302 responses to CONNECT from HTTP proxies.
    658     EXPECT_EQ(ERR_TUNNEL_CONNECTION_FAILED, rv);
    659     EXPECT_FALSE(handle_.is_initialized());
    660     EXPECT_FALSE(handle_.socket());
    661   } else {
    662     // Expect ProxyClientSocket to return the proxy's response, sanitized.
    663     EXPECT_EQ(ERR_HTTPS_PROXY_TUNNEL_RESPONSE, rv);
    664     EXPECT_TRUE(handle_.is_initialized());
    665     ASSERT_TRUE(handle_.socket());
    666 
    667     const ProxyClientSocket* tunnel_socket =
    668         static_cast<ProxyClientSocket*>(handle_.socket());
    669     const HttpResponseInfo* response = tunnel_socket->GetConnectResponseInfo();
    670     const HttpResponseHeaders* headers = response->headers.get();
    671 
    672     // Make sure Set-Cookie header was stripped.
    673     EXPECT_FALSE(headers->HasHeader("set-cookie"));
    674 
    675     // Make sure Content-Length: 0 header was added.
    676     EXPECT_TRUE(headers->HasHeaderValue("content-length", "0"));
    677 
    678     // Make sure Location header was included and correct.
    679     std::string location;
    680     EXPECT_TRUE(headers->IsRedirect(&location));
    681     EXPECT_EQ(location, redirectTarget);
    682   }
    683 }
    684 
    685 // It would be nice to also test the timeouts in HttpProxyClientSocketPool.
    686 
    687 }  // namespace net
    688