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