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