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.
5 #include "net/http/http_proxy_client_socket_pool.h"
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"
29 const int kMaxSockets = 32;
30 const int kMaxSocketsPerGroup = 6;
31 const char * const kAuthHeaders[] = {
32 "proxy-authorization", "Basic Zm9vOmJhcg=="
34 const int kAuthHeadersSize = arraysize(kAuthHeaders) / 2;
42 struct HttpProxyClientSocketPoolTestParams {
43 HttpProxyClientSocketPoolTestParams()
45 protocol(kProtoSPDY3) {}
47 HttpProxyClientSocketPoolTestParams(
48 HttpProxyType proxy_type,
50 : proxy_type(proxy_type),
53 HttpProxyType proxy_type;
57 typedef ::testing::TestWithParam<HttpProxyType> TestWithHttpParam;
59 const char kHttpProxyHost[] = "httpproxy.example.com";
60 const char kHttpsProxyHost[] = "httpsproxy.example.com";
62 class TestProxyDelegate : public ProxyDelegate {
65 : on_before_tunnel_request_called_(false),
66 on_tunnel_request_completed_called_(false),
67 on_tunnel_headers_received_called_(false) {
70 ~TestProxyDelegate() override {}
72 bool on_before_tunnel_request_called() const {
73 return on_before_tunnel_request_called_;
76 bool on_tunnel_request_completed_called() const {
77 return on_tunnel_request_completed_called_;
80 bool on_tunnel_headers_received_called() const {
81 return on_tunnel_headers_received_called_;
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_));
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_);
105 void OnResolveProxy(const GURL& url,
107 const ProxyService& proxy_service,
108 ProxyInfo* result) override {}
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;
118 void OnFallback(const ProxyServer& bad_proxy, int net_error) override {}
120 void OnBeforeSendHeaders(URLRequest* request,
121 const ProxyInfo& proxy_info,
122 HttpRequestHeaders* headers) override {}
124 void OnBeforeTunnelRequest(const net::HostPortPair& proxy_server,
125 net::HttpRequestHeaders* extra_headers) override {
126 on_before_tunnel_request_called_ = true;
128 extra_headers->SetHeader("Foo", proxy_server.ToString());
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();
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_;
154 class HttpProxyClientSocketPoolTest
155 : public ::testing::TestWithParam<HttpProxyClientSocketPoolTestParams> {
157 HttpProxyClientSocketPoolTest()
158 : session_deps_(GetParam().protocol),
159 tcp_histograms_("MockTCP"),
160 transport_socket_pool_(
164 session_deps_.deterministic_socket_factory.get()),
165 ssl_histograms_("MockSSL"),
166 ssl_socket_pool_(kMaxSockets,
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_,
179 session_deps_.ssl_config_service.get(),
181 BoundNetLog().net_log()),
182 session_(CreateNetworkSession()),
183 http_proxy_histograms_("HttpProxyUnitTest"),
184 spdy_util_(GetParam().protocol),
187 &http_proxy_histograms_,
189 &transport_socket_pool_,
194 virtual ~HttpProxyClientSocketPoolTest() {
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,
205 HttpAuth::AUTH_SCHEME_BASIC,
206 "Basic realm=MyRealm1",
207 AuthCredentials(kFoo, kBar),
211 scoped_refptr<TransportSocketParams> CreateHttpProxyParams() const {
212 if (GetParam().proxy_type != HTTP)
214 return new TransportSocketParams(
215 HostPortPair(kHttpProxyHost, 80),
218 OnHostResolutionCallback(),
219 TransportSocketParams::COMBINE_CONNECT_AND_WRITE_DEFAULT);
222 scoped_refptr<SSLSocketParams> CreateHttpsProxyParams() const {
223 if (GetParam().proxy_type == HTTP)
225 return new SSLSocketParams(
226 new TransportSocketParams(
227 HostPortPair(kHttpsProxyHost, 443),
230 OnHostResolutionCallback(),
231 TransportSocketParams::COMBINE_CONNECT_AND_WRITE_DEFAULT),
234 HostPortPair(kHttpsProxyHost, 443),
236 PRIVACY_MODE_DISABLED,
242 // Returns the a correctly constructed HttpProxyParms
243 // for the HTTP or HTTPS proxy.
244 scoped_refptr<HttpProxySocketParams> CreateParams(
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"),
252 HostPortPair("www.google.com", tunnel ? 443 : 80),
253 session_->http_auth_cache(),
254 session_->http_auth_handler_factory(),
255 session_->spdy_session_pool(),
260 scoped_refptr<HttpProxySocketParams> CreateTunnelParams(
261 ProxyDelegate* proxy_delegate) {
262 return CreateParams(true, proxy_delegate);
265 scoped_refptr<HttpProxySocketParams> CreateNoTunnelParams(
266 ProxyDelegate* proxy_delegate) {
267 return CreateParams(false, proxy_delegate);
270 DeterministicMockClientSocketFactory* socket_factory() {
271 return session_deps_.deterministic_socket_factory.get();
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));
282 data_.reset(new DeterministicSocketData(reads, reads_count, writes,
286 data_->set_connect_data(MockConnect(SYNCHRONOUS, OK));
287 data_->StopAfter(2); // Request / Response
289 socket_factory()->AddSocketDataProvider(data_.get());
291 if (GetParam().proxy_type != HTTP) {
292 ssl_data_.reset(new SSLSocketDataProvider(SYNCHRONOUS, OK));
293 if (GetParam().proxy_type == SPDY) {
296 socket_factory()->AddSSLSocketDataProvider(ssl_data_.get());
300 void InitializeSpdySsl() {
301 ssl_data_->SetNextProto(GetParam().protocol);
304 HttpNetworkSession* CreateNetworkSession() {
305 return SpdySessionDependencies::SpdyCreateSessionDeterministic(
309 RequestPriority GetLastTransportRequestPriority() const {
310 return transport_socket_pool_.last_request_priority();
314 SpdySessionDependencies session_deps_;
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_;
323 const scoped_refptr<HttpNetworkSession> session_;
324 ClientSocketPoolHistograms http_proxy_histograms_;
327 SpdyTestUtil spdy_util_;
328 scoped_ptr<SSLSocketDataProvider> ssl_data_;
329 scoped_ptr<DeterministicSocketData> data_;
330 HttpProxyClientSocketPool pool_;
331 ClientSocketHandle handle_;
332 TestCompletionCallback callback_;
335 //-----------------------------------------------------------------------------
336 // All tests are run with three different proxy types: HTTP, HTTPS (non-SPDY)
339 // TODO(akalin): Use ::testing::Combine() when we are able to use
341 INSTANTIATE_TEST_CASE_P(
342 HttpProxyClientSocketPoolTests,
343 HttpProxyClientSocketPoolTest,
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)));
358 TEST_P(HttpProxyClientSocketPoolTest, NoTunnel) {
359 Initialize(NULL, 0, NULL, 0, NULL, 0, NULL, 0);
361 scoped_ptr<TestProxyDelegate> proxy_delegate(new TestProxyDelegate());
362 int rv = handle_.Init("a", CreateNoTunnelParams(proxy_delegate.get()), LOW,
363 CompletionCallback(), &pool_, BoundNetLog());
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());
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);
380 handle_.Init("a", CreateNoTunnelParams(NULL), HIGHEST,
381 CompletionCallback(), &pool_, BoundNetLog()));
382 EXPECT_EQ(HIGHEST, GetLastTransportRequestPriority());
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"),
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"),
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),
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);
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)
417 Initialize(reads, arraysize(reads), writes, arraysize(writes),
418 spdy_reads, arraysize(spdy_reads), spdy_writes,
419 arraysize(spdy_writes));
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());
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());
439 EXPECT_FALSE(tunnel_socket->IsConnected());
440 EXPECT_FALSE(tunnel_socket->IsUsingSpdy());
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)
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()),
463 MockRead(SYNCHRONOUS, 1, "HTTP/1.1 200 Connection Established\r\n\r\n"),
466 Initialize(reads, arraysize(reads), writes, arraysize(writes), NULL, 0,
470 scoped_ptr<TestProxyDelegate> proxy_delegate(new TestProxyDelegate());
471 int rv = handle_.Init("a", CreateTunnelParams(proxy_delegate.get()), LOW,
472 callback_.callback(), &pool_, BoundNetLog());
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());
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()),
503 MockRead(ASYNC, 1, "HTTP/1.1 200 Connection Established\r\n\r\n"),
506 scoped_ptr<SpdyFrame> req(
507 spdy_util_.ConstructSpdyConnect(kAuthHeaders, kAuthHeadersSize, 1, LOW));
508 MockWrite spdy_writes[] = {
509 CreateMockWrite(*req, 0, ASYNC)
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)
517 Initialize(reads, arraysize(reads), writes, arraysize(writes),
518 spdy_reads, arraysize(spdy_reads), spdy_writes,
519 arraysize(spdy_writes));
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());
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());
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)
548 scoped_ptr<SpdyFrame> req(
549 spdy_util_.ConstructSpdyConnect(kAuthHeaders, kAuthHeadersSize,
551 MockWrite spdy_writes[] = {
552 CreateMockWrite(*req, 0, ASYNC)
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)
560 Initialize(NULL, 0, NULL, 0,
561 spdy_reads, arraysize(spdy_reads),
562 spdy_writes, arraysize(spdy_writes));
565 EXPECT_EQ(ERR_IO_PENDING,
566 handle_.Init("a", CreateTunnelParams(NULL), MEDIUM,
567 callback_.callback(), &pool_, BoundNetLog()));
568 EXPECT_EQ(MEDIUM, GetLastTransportRequestPriority());
571 EXPECT_EQ(OK, callback_.WaitForResult());
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));
579 socket_factory()->AddSocketDataProvider(data_.get());
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());
587 EXPECT_EQ(ERR_PROXY_CONNECTION_FAILED, callback_.WaitForResult());
589 EXPECT_FALSE(handle_.is_initialized());
590 EXPECT_FALSE(handle_.socket());
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());
599 ssl_data_.reset(new SSLSocketDataProvider(ASYNC,
600 ERR_CERT_AUTHORITY_INVALID));
601 if (GetParam().proxy_type == SPDY) {
604 socket_factory()->AddSSLSocketDataProvider(ssl_data_.get());
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());
612 EXPECT_EQ(ERR_PROXY_CERTIFICATE_INVALID, callback_.WaitForResult());
614 EXPECT_FALSE(handle_.is_initialized());
615 EXPECT_FALSE(handle_.socket());
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());
624 ssl_data_.reset(new SSLSocketDataProvider(ASYNC,
625 ERR_SSL_CLIENT_AUTH_CERT_NEEDED));
626 if (GetParam().proxy_type == SPDY) {
629 socket_factory()->AddSSLSocketDataProvider(ssl_data_.get());
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());
637 EXPECT_EQ(ERR_SSL_CLIENT_AUTH_CERT_NEEDED, callback_.WaitForResult());
639 EXPECT_FALSE(handle_.is_initialized());
640 EXPECT_FALSE(handle_.socket());
643 TEST_P(HttpProxyClientSocketPoolTest, TunnelUnexpectedClose) {
644 MockWrite writes[] = {
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"),
652 MockRead(ASYNC, 1, "HTTP/1.1 200 Conn"),
653 MockRead(ASYNC, ERR_CONNECTION_CLOSED, 2),
655 scoped_ptr<SpdyFrame> req(
656 spdy_util_.ConstructSpdyConnect(kAuthHeaders, kAuthHeadersSize, 1, LOW));
657 MockWrite spdy_writes[] = {
658 CreateMockWrite(*req, 0, ASYNC)
660 MockRead spdy_reads[] = {
661 MockRead(ASYNC, ERR_CONNECTION_CLOSED, 1),
664 Initialize(reads, arraysize(reads), writes, arraysize(writes),
665 spdy_reads, arraysize(spdy_reads), spdy_writes,
666 arraysize(spdy_writes));
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());
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());
681 EXPECT_EQ(ERR_RESPONSE_HEADERS_TRUNCATED, callback_.WaitForResult());
683 EXPECT_FALSE(handle_.is_initialized());
684 EXPECT_FALSE(handle_.socket());
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.
694 MockWrite writes[] = {
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"),
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"),
705 Initialize(reads, arraysize(reads), writes, arraysize(writes),
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());
715 EXPECT_EQ(ERR_TUNNEL_CONNECTION_FAILED, callback_.WaitForResult());
718 TEST_P(HttpProxyClientSocketPoolTest, TunnelSetupError) {
719 MockWrite writes[] = {
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"),
727 MockRead(ASYNC, 1, "HTTP/1.1 304 Not Modified\r\n\r\n"),
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),
737 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdySynReplyError(1));
738 MockRead spdy_reads[] = {
739 CreateMockRead(*resp, 1, ASYNC),
740 MockRead(ASYNC, 0, 3),
743 Initialize(reads, arraysize(reads), writes, arraysize(writes),
744 spdy_reads, arraysize(spdy_reads), spdy_writes,
745 arraysize(spdy_writes));
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());
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());
763 TEST_P(HttpProxyClientSocketPoolTest, TunnelSetupRedirect) {
764 const std::string redirectTarget = "https://foo.google.com/";
766 const std::string responseText = "HTTP/1.1 302 Found\r\n"
767 "Location: " + redirectTarget + "\r\n"
768 "Set-Cookie: foo=bar\r\n"
770 MockWrite writes[] = {
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"),
778 MockRead(ASYNC, 1, responseText.c_str()),
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));
785 MockWrite spdy_writes[] = {
786 CreateMockWrite(*req, 0, ASYNC),
787 CreateMockWrite(*rst, 3, ASYNC),
790 const char* const responseHeaders[] = {
791 "location", redirectTarget.c_str(),
792 "set-cookie", "foo=bar",
794 const int responseHeadersSize = arraysize(responseHeaders) / 2;
795 scoped_ptr<SpdyFrame> resp(
796 spdy_util_.ConstructSpdySynReplyError(
798 responseHeaders, responseHeadersSize,
800 MockRead spdy_reads[] = {
801 CreateMockRead(*resp, 1, ASYNC),
802 MockRead(ASYNC, 0, 2),
805 Initialize(reads, arraysize(reads), writes, arraysize(writes),
806 spdy_reads, arraysize(spdy_reads), spdy_writes,
807 arraysize(spdy_writes));
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());
818 rv = callback_.WaitForResult();
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());
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());
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();
836 // Make sure Set-Cookie header was stripped.
837 EXPECT_FALSE(headers->HasHeader("set-cookie"));
839 // Make sure Content-Length: 0 header was added.
840 EXPECT_TRUE(headers->HasHeaderValue("content-length", "0"));
842 // Make sure Location header was included and correct.
843 std::string location;
844 EXPECT_TRUE(headers->IsRedirect(&location));
845 EXPECT_EQ(location, redirectTarget);
849 // It would be nice to also test the timeouts in HttpProxyClientSocketPool.