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