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/test_completion_callback.h"
13 #include "net/http/http_network_session.h"
14 #include "net/http/http_proxy_client_socket.h"
15 #include "net/http/http_response_headers.h"
16 #include "net/socket/client_socket_handle.h"
17 #include "net/socket/client_socket_pool_histograms.h"
18 #include "net/socket/next_proto.h"
19 #include "net/socket/socket_test_util.h"
20 #include "net/spdy/spdy_protocol.h"
21 #include "net/spdy/spdy_test_util_common.h"
22 #include "testing/gtest/include/gtest/gtest.h"
28 const int kMaxSockets
= 32;
29 const int kMaxSocketsPerGroup
= 6;
30 const char * const kAuthHeaders
[] = {
31 "proxy-authorization", "Basic Zm9vOmJhcg=="
33 const int kAuthHeadersSize
= arraysize(kAuthHeaders
) / 2;
41 struct HttpProxyClientSocketPoolTestParams
{
42 HttpProxyClientSocketPoolTestParams()
44 protocol(kProtoSPDY3
) {}
46 HttpProxyClientSocketPoolTestParams(
47 HttpProxyType proxy_type
,
49 : proxy_type(proxy_type
),
52 HttpProxyType proxy_type
;
56 typedef ::testing::TestWithParam
<HttpProxyType
> TestWithHttpParam
;
58 const char kHttpProxyHost
[] = "httpproxy.example.com";
59 const char kHttpsProxyHost
[] = "httpsproxy.example.com";
61 class HttpProxyClientSocketPoolTest
62 : public ::testing::TestWithParam
<HttpProxyClientSocketPoolTestParams
> {
64 HttpProxyClientSocketPoolTest()
65 : session_deps_(GetParam().protocol
),
66 tcp_histograms_("MockTCP"),
67 transport_socket_pool_(
71 session_deps_
.deterministic_socket_factory
.get()),
72 ssl_histograms_("MockSSL"),
73 ssl_socket_pool_(kMaxSockets
,
76 session_deps_
.host_resolver
.get(),
77 session_deps_
.cert_verifier
.get(),
78 NULL
/* server_bound_cert_store */,
79 NULL
/* transport_security_state */,
80 NULL
/* cert_transparency_verifier */,
81 std::string() /* ssl_session_cache_shard */,
82 session_deps_
.deterministic_socket_factory
.get(),
83 &transport_socket_pool_
,
86 session_deps_
.ssl_config_service
.get(),
87 BoundNetLog().net_log()),
88 session_(CreateNetworkSession()),
89 http_proxy_histograms_("HttpProxyUnitTest"),
90 spdy_util_(GetParam().protocol
),
93 &http_proxy_histograms_
,
95 &transport_socket_pool_
,
99 virtual ~HttpProxyClientSocketPoolTest() {
102 void AddAuthToCache() {
103 const base::string16
kFoo(base::ASCIIToUTF16("foo"));
104 const base::string16
kBar(base::ASCIIToUTF16("bar"));
105 GURL
proxy_url(GetParam().proxy_type
== HTTP
?
106 (std::string("http://") + kHttpProxyHost
) :
107 (std::string("https://") + kHttpsProxyHost
));
108 session_
->http_auth_cache()->Add(proxy_url
,
110 HttpAuth::AUTH_SCHEME_BASIC
,
111 "Basic realm=MyRealm1",
112 AuthCredentials(kFoo
, kBar
),
116 scoped_refptr
<TransportSocketParams
> CreateHttpProxyParams() const {
117 if (GetParam().proxy_type
!= HTTP
)
119 return new TransportSocketParams(HostPortPair(kHttpProxyHost
, 80),
122 OnHostResolutionCallback());
125 scoped_refptr
<SSLSocketParams
> CreateHttpsProxyParams() const {
126 if (GetParam().proxy_type
== HTTP
)
128 return new SSLSocketParams(
129 new TransportSocketParams(
130 HostPortPair(kHttpsProxyHost
, 443),
133 OnHostResolutionCallback()),
136 HostPortPair(kHttpsProxyHost
, 443),
138 PRIVACY_MODE_DISABLED
,
144 // Returns the a correctly constructed HttpProxyParms
145 // for the HTTP or HTTPS proxy.
146 scoped_refptr
<HttpProxySocketParams
> CreateParams(bool tunnel
) {
147 return scoped_refptr
<HttpProxySocketParams
>(new HttpProxySocketParams(
148 CreateHttpProxyParams(),
149 CreateHttpsProxyParams(),
150 GURL(tunnel
? "https://www.google.com/" : "http://www.google.com"),
152 HostPortPair("www.google.com", tunnel
? 443 : 80),
153 session_
->http_auth_cache(),
154 session_
->http_auth_handler_factory(),
155 session_
->spdy_session_pool(),
159 scoped_refptr
<HttpProxySocketParams
> CreateTunnelParams() {
160 return CreateParams(true);
163 scoped_refptr
<HttpProxySocketParams
> CreateNoTunnelParams() {
164 return CreateParams(false);
167 DeterministicMockClientSocketFactory
* socket_factory() {
168 return session_deps_
.deterministic_socket_factory
.get();
171 void Initialize(MockRead
* reads
, size_t reads_count
,
172 MockWrite
* writes
, size_t writes_count
,
173 MockRead
* spdy_reads
, size_t spdy_reads_count
,
174 MockWrite
* spdy_writes
, size_t spdy_writes_count
) {
175 if (GetParam().proxy_type
== SPDY
) {
176 data_
.reset(new DeterministicSocketData(spdy_reads
, spdy_reads_count
,
177 spdy_writes
, spdy_writes_count
));
179 data_
.reset(new DeterministicSocketData(reads
, reads_count
, writes
,
183 data_
->set_connect_data(MockConnect(SYNCHRONOUS
, OK
));
184 data_
->StopAfter(2); // Request / Response
186 socket_factory()->AddSocketDataProvider(data_
.get());
188 if (GetParam().proxy_type
!= HTTP
) {
189 ssl_data_
.reset(new SSLSocketDataProvider(SYNCHRONOUS
, OK
));
190 if (GetParam().proxy_type
== SPDY
) {
193 socket_factory()->AddSSLSocketDataProvider(ssl_data_
.get());
197 void InitializeSpdySsl() {
198 ssl_data_
->SetNextProto(GetParam().protocol
);
201 HttpNetworkSession
* CreateNetworkSession() {
202 return SpdySessionDependencies::SpdyCreateSessionDeterministic(
206 RequestPriority
GetLastTransportRequestPriority() const {
207 return transport_socket_pool_
.last_request_priority();
211 SpdySessionDependencies session_deps_
;
213 ClientSocketPoolHistograms tcp_histograms_
;
214 MockTransportClientSocketPool transport_socket_pool_
;
215 ClientSocketPoolHistograms ssl_histograms_
;
216 MockHostResolver host_resolver_
;
217 scoped_ptr
<CertVerifier
> cert_verifier_
;
218 SSLClientSocketPool ssl_socket_pool_
;
220 const scoped_refptr
<HttpNetworkSession
> session_
;
221 ClientSocketPoolHistograms http_proxy_histograms_
;
224 SpdyTestUtil spdy_util_
;
225 scoped_ptr
<SSLSocketDataProvider
> ssl_data_
;
226 scoped_ptr
<DeterministicSocketData
> data_
;
227 HttpProxyClientSocketPool pool_
;
228 ClientSocketHandle handle_
;
229 TestCompletionCallback callback_
;
232 //-----------------------------------------------------------------------------
233 // All tests are run with three different proxy types: HTTP, HTTPS (non-SPDY)
236 // TODO(akalin): Use ::testing::Combine() when we are able to use
238 INSTANTIATE_TEST_CASE_P(
239 HttpProxyClientSocketPoolTests
,
240 HttpProxyClientSocketPoolTest
,
242 HttpProxyClientSocketPoolTestParams(HTTP
, kProtoDeprecatedSPDY2
),
243 HttpProxyClientSocketPoolTestParams(HTTPS
, kProtoDeprecatedSPDY2
),
244 HttpProxyClientSocketPoolTestParams(SPDY
, kProtoDeprecatedSPDY2
),
245 HttpProxyClientSocketPoolTestParams(HTTP
, kProtoSPDY3
),
246 HttpProxyClientSocketPoolTestParams(HTTPS
, kProtoSPDY3
),
247 HttpProxyClientSocketPoolTestParams(SPDY
, kProtoSPDY3
),
248 HttpProxyClientSocketPoolTestParams(HTTP
, kProtoSPDY31
),
249 HttpProxyClientSocketPoolTestParams(HTTPS
, kProtoSPDY31
),
250 HttpProxyClientSocketPoolTestParams(SPDY
, kProtoSPDY31
),
251 HttpProxyClientSocketPoolTestParams(HTTP
, kProtoSPDY4a2
),
252 HttpProxyClientSocketPoolTestParams(HTTPS
, kProtoSPDY4a2
),
253 HttpProxyClientSocketPoolTestParams(SPDY
, kProtoSPDY4a2
),
254 HttpProxyClientSocketPoolTestParams(HTTP
, kProtoHTTP2Draft04
),
255 HttpProxyClientSocketPoolTestParams(HTTPS
, kProtoHTTP2Draft04
),
256 HttpProxyClientSocketPoolTestParams(SPDY
, kProtoHTTP2Draft04
)));
258 TEST_P(HttpProxyClientSocketPoolTest
, NoTunnel
) {
259 Initialize(NULL
, 0, NULL
, 0, NULL
, 0, NULL
, 0);
261 int rv
= handle_
.Init("a", CreateNoTunnelParams(), LOW
, CompletionCallback(),
262 &pool_
, BoundNetLog());
264 EXPECT_TRUE(handle_
.is_initialized());
265 ASSERT_TRUE(handle_
.socket());
266 HttpProxyClientSocket
* tunnel_socket
=
267 static_cast<HttpProxyClientSocket
*>(handle_
.socket());
268 EXPECT_TRUE(tunnel_socket
->IsConnected());
271 // Make sure that HttpProxyConnectJob passes on its priority to its
272 // (non-SSL) socket request on Init.
273 TEST_P(HttpProxyClientSocketPoolTest
, SetSocketRequestPriorityOnInit
) {
274 Initialize(NULL
, 0, NULL
, 0, NULL
, 0, NULL
, 0);
276 handle_
.Init("a", CreateNoTunnelParams(), HIGHEST
,
277 CompletionCallback(), &pool_
, BoundNetLog()));
278 EXPECT_EQ(HIGHEST
, GetLastTransportRequestPriority());
281 TEST_P(HttpProxyClientSocketPoolTest
, NeedAuth
) {
282 MockWrite writes
[] = {
283 MockWrite(ASYNC
, 0, "CONNECT www.google.com:443 HTTP/1.1\r\n"
284 "Host: www.google.com\r\n"
285 "Proxy-Connection: keep-alive\r\n\r\n"),
289 MockRead(ASYNC
, 1, "HTTP/1.1 407 Proxy Authentication Required\r\n"),
290 MockRead(ASYNC
, 2, "Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
291 MockRead(ASYNC
, 3, "Content-Length: 10\r\n\r\n"),
292 MockRead(ASYNC
, 4, "0123456789"),
294 scoped_ptr
<SpdyFrame
> req(
295 spdy_util_
.ConstructSpdyConnect(NULL
, 0, 1, LOW
));
296 scoped_ptr
<SpdyFrame
> rst(
297 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_CANCEL
));
298 MockWrite spdy_writes
[] = {
299 CreateMockWrite(*req
, 0, ASYNC
),
300 CreateMockWrite(*rst
, 2, ASYNC
),
302 const char* const kAuthChallenge
[] = {
303 spdy_util_
.GetStatusKey(), "407 Proxy Authentication Required",
304 spdy_util_
.GetVersionKey(), "HTTP/1.1",
305 "proxy-authenticate", "Basic realm=\"MyRealm1\"",
307 scoped_ptr
<SpdyFrame
> resp(
308 spdy_util_
.ConstructSpdyControlFrame(NULL
,
316 arraysize(kAuthChallenge
),
318 MockRead spdy_reads
[] = {
319 CreateMockRead(*resp
, 1, ASYNC
),
320 MockRead(ASYNC
, 0, 3)
323 Initialize(reads
, arraysize(reads
), writes
, arraysize(writes
),
324 spdy_reads
, arraysize(spdy_reads
), spdy_writes
,
325 arraysize(spdy_writes
));
328 int rv
= handle_
.Init("a", CreateTunnelParams(), LOW
, callback_
.callback(),
329 &pool_
, BoundNetLog());
330 EXPECT_EQ(ERR_IO_PENDING
, rv
);
331 EXPECT_FALSE(handle_
.is_initialized());
332 EXPECT_FALSE(handle_
.socket());
334 data_
->RunFor(GetParam().proxy_type
== SPDY
? 2 : 4);
335 rv
= callback_
.WaitForResult();
336 EXPECT_EQ(ERR_PROXY_AUTH_REQUESTED
, rv
);
337 EXPECT_TRUE(handle_
.is_initialized());
338 ASSERT_TRUE(handle_
.socket());
339 ProxyClientSocket
* tunnel_socket
=
340 static_cast<ProxyClientSocket
*>(handle_
.socket());
341 if (GetParam().proxy_type
== SPDY
) {
342 EXPECT_TRUE(tunnel_socket
->IsConnected());
343 EXPECT_TRUE(tunnel_socket
->IsUsingSpdy());
345 EXPECT_FALSE(tunnel_socket
->IsConnected());
346 EXPECT_FALSE(tunnel_socket
->IsUsingSpdy());
350 TEST_P(HttpProxyClientSocketPoolTest
, HaveAuth
) {
351 // It's pretty much impossible to make the SPDY case behave synchronously
352 // so we skip this test for SPDY
353 if (GetParam().proxy_type
== SPDY
)
355 MockWrite writes
[] = {
356 MockWrite(SYNCHRONOUS
, 0,
357 "CONNECT www.google.com:443 HTTP/1.1\r\n"
358 "Host: www.google.com\r\n"
359 "Proxy-Connection: keep-alive\r\n"
360 "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
363 MockRead(SYNCHRONOUS
, 1, "HTTP/1.1 200 Connection Established\r\n\r\n"),
366 Initialize(reads
, arraysize(reads
), writes
, arraysize(writes
), NULL
, 0,
370 int rv
= handle_
.Init("a", CreateTunnelParams(), LOW
, callback_
.callback(),
371 &pool_
, BoundNetLog());
373 EXPECT_TRUE(handle_
.is_initialized());
374 ASSERT_TRUE(handle_
.socket());
375 HttpProxyClientSocket
* tunnel_socket
=
376 static_cast<HttpProxyClientSocket
*>(handle_
.socket());
377 EXPECT_TRUE(tunnel_socket
->IsConnected());
380 TEST_P(HttpProxyClientSocketPoolTest
, AsyncHaveAuth
) {
381 MockWrite writes
[] = {
382 MockWrite(ASYNC
, 0, "CONNECT www.google.com:443 HTTP/1.1\r\n"
383 "Host: www.google.com\r\n"
384 "Proxy-Connection: keep-alive\r\n"
385 "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
388 MockRead(ASYNC
, 1, "HTTP/1.1 200 Connection Established\r\n\r\n"),
391 scoped_ptr
<SpdyFrame
> req(
392 spdy_util_
.ConstructSpdyConnect(kAuthHeaders
, kAuthHeadersSize
, 1, LOW
));
393 MockWrite spdy_writes
[] = {
394 CreateMockWrite(*req
, 0, ASYNC
)
396 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
397 MockRead spdy_reads
[] = {
398 CreateMockRead(*resp
, 1, ASYNC
),
399 MockRead(ASYNC
, 0, 2)
402 Initialize(reads
, arraysize(reads
), writes
, arraysize(writes
),
403 spdy_reads
, arraysize(spdy_reads
), spdy_writes
,
404 arraysize(spdy_writes
));
407 int rv
= handle_
.Init("a", CreateTunnelParams(), LOW
, callback_
.callback(),
408 &pool_
, BoundNetLog());
409 EXPECT_EQ(ERR_IO_PENDING
, rv
);
410 EXPECT_FALSE(handle_
.is_initialized());
411 EXPECT_FALSE(handle_
.socket());
414 EXPECT_EQ(OK
, callback_
.WaitForResult());
415 EXPECT_TRUE(handle_
.is_initialized());
416 ASSERT_TRUE(handle_
.socket());
417 HttpProxyClientSocket
* tunnel_socket
=
418 static_cast<HttpProxyClientSocket
*>(handle_
.socket());
419 EXPECT_TRUE(tunnel_socket
->IsConnected());
422 // Make sure that HttpProxyConnectJob passes on its priority to its
423 // SPDY session's socket request on Init (if applicable).
424 TEST_P(HttpProxyClientSocketPoolTest
,
425 SetSpdySessionSocketRequestPriorityOnInit
) {
426 if (GetParam().proxy_type
!= SPDY
)
429 scoped_ptr
<SpdyFrame
> req(
430 spdy_util_
.ConstructSpdyConnect(kAuthHeaders
, kAuthHeadersSize
,
432 MockWrite spdy_writes
[] = {
433 CreateMockWrite(*req
, 0, ASYNC
)
435 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
436 MockRead spdy_reads
[] = {
437 CreateMockRead(*resp
, 1, ASYNC
),
438 MockRead(ASYNC
, 0, 2)
441 Initialize(NULL
, 0, NULL
, 0,
442 spdy_reads
, arraysize(spdy_reads
),
443 spdy_writes
, arraysize(spdy_writes
));
446 EXPECT_EQ(ERR_IO_PENDING
,
447 handle_
.Init("a", CreateTunnelParams(), MEDIUM
,
448 callback_
.callback(), &pool_
, BoundNetLog()));
449 EXPECT_EQ(MEDIUM
, GetLastTransportRequestPriority());
452 EXPECT_EQ(OK
, callback_
.WaitForResult());
455 TEST_P(HttpProxyClientSocketPoolTest
, TCPError
) {
456 if (GetParam().proxy_type
== SPDY
) return;
457 data_
.reset(new DeterministicSocketData(NULL
, 0, NULL
, 0));
458 data_
->set_connect_data(MockConnect(ASYNC
, ERR_CONNECTION_CLOSED
));
460 socket_factory()->AddSocketDataProvider(data_
.get());
462 int rv
= handle_
.Init("a", CreateTunnelParams(), LOW
, callback_
.callback(),
463 &pool_
, BoundNetLog());
464 EXPECT_EQ(ERR_IO_PENDING
, rv
);
465 EXPECT_FALSE(handle_
.is_initialized());
466 EXPECT_FALSE(handle_
.socket());
468 EXPECT_EQ(ERR_PROXY_CONNECTION_FAILED
, callback_
.WaitForResult());
470 EXPECT_FALSE(handle_
.is_initialized());
471 EXPECT_FALSE(handle_
.socket());
474 TEST_P(HttpProxyClientSocketPoolTest
, SSLError
) {
475 if (GetParam().proxy_type
== HTTP
) return;
476 data_
.reset(new DeterministicSocketData(NULL
, 0, NULL
, 0));
477 data_
->set_connect_data(MockConnect(ASYNC
, OK
));
478 socket_factory()->AddSocketDataProvider(data_
.get());
480 ssl_data_
.reset(new SSLSocketDataProvider(ASYNC
,
481 ERR_CERT_AUTHORITY_INVALID
));
482 if (GetParam().proxy_type
== SPDY
) {
485 socket_factory()->AddSSLSocketDataProvider(ssl_data_
.get());
487 int rv
= handle_
.Init("a", CreateTunnelParams(), LOW
, callback_
.callback(),
488 &pool_
, BoundNetLog());
489 EXPECT_EQ(ERR_IO_PENDING
, rv
);
490 EXPECT_FALSE(handle_
.is_initialized());
491 EXPECT_FALSE(handle_
.socket());
493 EXPECT_EQ(ERR_PROXY_CERTIFICATE_INVALID
, callback_
.WaitForResult());
495 EXPECT_FALSE(handle_
.is_initialized());
496 EXPECT_FALSE(handle_
.socket());
499 TEST_P(HttpProxyClientSocketPoolTest
, SslClientAuth
) {
500 if (GetParam().proxy_type
== HTTP
) return;
501 data_
.reset(new DeterministicSocketData(NULL
, 0, NULL
, 0));
502 data_
->set_connect_data(MockConnect(ASYNC
, OK
));
503 socket_factory()->AddSocketDataProvider(data_
.get());
505 ssl_data_
.reset(new SSLSocketDataProvider(ASYNC
,
506 ERR_SSL_CLIENT_AUTH_CERT_NEEDED
));
507 if (GetParam().proxy_type
== SPDY
) {
510 socket_factory()->AddSSLSocketDataProvider(ssl_data_
.get());
512 int rv
= handle_
.Init("a", CreateTunnelParams(), LOW
, callback_
.callback(),
513 &pool_
, BoundNetLog());
514 EXPECT_EQ(ERR_IO_PENDING
, rv
);
515 EXPECT_FALSE(handle_
.is_initialized());
516 EXPECT_FALSE(handle_
.socket());
518 EXPECT_EQ(ERR_SSL_CLIENT_AUTH_CERT_NEEDED
, callback_
.WaitForResult());
520 EXPECT_FALSE(handle_
.is_initialized());
521 EXPECT_FALSE(handle_
.socket());
524 TEST_P(HttpProxyClientSocketPoolTest
, TunnelUnexpectedClose
) {
525 MockWrite writes
[] = {
527 "CONNECT www.google.com:443 HTTP/1.1\r\n"
528 "Host: www.google.com\r\n"
529 "Proxy-Connection: keep-alive\r\n"
530 "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
533 MockRead(ASYNC
, 1, "HTTP/1.1 200 Conn"),
534 MockRead(ASYNC
, ERR_CONNECTION_CLOSED
, 2),
536 scoped_ptr
<SpdyFrame
> req(
537 spdy_util_
.ConstructSpdyConnect(kAuthHeaders
, kAuthHeadersSize
, 1, LOW
));
538 MockWrite spdy_writes
[] = {
539 CreateMockWrite(*req
, 0, ASYNC
)
541 MockRead spdy_reads
[] = {
542 MockRead(ASYNC
, ERR_CONNECTION_CLOSED
, 1),
545 Initialize(reads
, arraysize(reads
), writes
, arraysize(writes
),
546 spdy_reads
, arraysize(spdy_reads
), spdy_writes
,
547 arraysize(spdy_writes
));
550 int rv
= handle_
.Init("a", CreateTunnelParams(), LOW
, callback_
.callback(),
551 &pool_
, BoundNetLog());
552 EXPECT_EQ(ERR_IO_PENDING
, rv
);
553 EXPECT_FALSE(handle_
.is_initialized());
554 EXPECT_FALSE(handle_
.socket());
557 if (GetParam().proxy_type
== SPDY
) {
558 // SPDY cannot process a headers block unless it's complete and so it
559 // returns ERR_CONNECTION_CLOSED in this case.
560 EXPECT_EQ(ERR_CONNECTION_CLOSED
, callback_
.WaitForResult());
562 EXPECT_EQ(ERR_RESPONSE_HEADERS_TRUNCATED
, callback_
.WaitForResult());
564 EXPECT_FALSE(handle_
.is_initialized());
565 EXPECT_FALSE(handle_
.socket());
568 TEST_P(HttpProxyClientSocketPoolTest
, Tunnel1xxResponse
) {
569 // Tests that 1xx responses are rejected for a CONNECT request.
570 if (GetParam().proxy_type
== SPDY
) {
571 // SPDY doesn't have 1xx responses.
575 MockWrite writes
[] = {
577 "CONNECT www.google.com:443 HTTP/1.1\r\n"
578 "Host: www.google.com\r\n"
579 "Proxy-Connection: keep-alive\r\n\r\n"),
582 MockRead(ASYNC
, 1, "HTTP/1.1 100 Continue\r\n\r\n"),
583 MockRead(ASYNC
, 2, "HTTP/1.1 200 Connection Established\r\n\r\n"),
586 Initialize(reads
, arraysize(reads
), writes
, arraysize(writes
),
589 int rv
= handle_
.Init("a", CreateTunnelParams(), LOW
, callback_
.callback(),
590 &pool_
, BoundNetLog());
591 EXPECT_EQ(ERR_IO_PENDING
, rv
);
592 EXPECT_FALSE(handle_
.is_initialized());
593 EXPECT_FALSE(handle_
.socket());
596 EXPECT_EQ(ERR_TUNNEL_CONNECTION_FAILED
, callback_
.WaitForResult());
599 TEST_P(HttpProxyClientSocketPoolTest
, TunnelSetupError
) {
600 MockWrite writes
[] = {
602 "CONNECT www.google.com:443 HTTP/1.1\r\n"
603 "Host: www.google.com\r\n"
604 "Proxy-Connection: keep-alive\r\n"
605 "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
608 MockRead(ASYNC
, 1, "HTTP/1.1 304 Not Modified\r\n\r\n"),
610 scoped_ptr
<SpdyFrame
> req(
611 spdy_util_
.ConstructSpdyConnect(kAuthHeaders
, kAuthHeadersSize
, 1, LOW
));
612 scoped_ptr
<SpdyFrame
> rst(
613 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_CANCEL
));
614 MockWrite spdy_writes
[] = {
615 CreateMockWrite(*req
, 0, ASYNC
),
616 CreateMockWrite(*rst
, 2, ASYNC
),
618 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdySynReplyError(1));
619 MockRead spdy_reads
[] = {
620 CreateMockRead(*resp
, 1, ASYNC
),
621 MockRead(ASYNC
, 0, 3),
624 Initialize(reads
, arraysize(reads
), writes
, arraysize(writes
),
625 spdy_reads
, arraysize(spdy_reads
), spdy_writes
,
626 arraysize(spdy_writes
));
629 int rv
= handle_
.Init("a", CreateTunnelParams(), LOW
, callback_
.callback(),
630 &pool_
, BoundNetLog());
631 EXPECT_EQ(ERR_IO_PENDING
, rv
);
632 EXPECT_FALSE(handle_
.is_initialized());
633 EXPECT_FALSE(handle_
.socket());
637 rv
= callback_
.WaitForResult();
638 // All Proxy CONNECT responses are not trustworthy
639 EXPECT_EQ(ERR_TUNNEL_CONNECTION_FAILED
, rv
);
640 EXPECT_FALSE(handle_
.is_initialized());
641 EXPECT_FALSE(handle_
.socket());
644 TEST_P(HttpProxyClientSocketPoolTest
, TunnelSetupRedirect
) {
645 const std::string redirectTarget
= "https://foo.google.com/";
647 const std::string responseText
= "HTTP/1.1 302 Found\r\n"
648 "Location: " + redirectTarget
+ "\r\n"
649 "Set-Cookie: foo=bar\r\n"
651 MockWrite writes
[] = {
653 "CONNECT www.google.com:443 HTTP/1.1\r\n"
654 "Host: www.google.com\r\n"
655 "Proxy-Connection: keep-alive\r\n"
656 "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
659 MockRead(ASYNC
, 1, responseText
.c_str()),
661 scoped_ptr
<SpdyFrame
> req(
662 spdy_util_
.ConstructSpdyConnect(kAuthHeaders
, kAuthHeadersSize
, 1, LOW
));
663 scoped_ptr
<SpdyFrame
> rst(
664 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_CANCEL
));
666 MockWrite spdy_writes
[] = {
667 CreateMockWrite(*req
, 0, ASYNC
),
668 CreateMockWrite(*rst
, 3, ASYNC
),
671 const char* const responseHeaders
[] = {
672 "location", redirectTarget
.c_str(),
673 "set-cookie", "foo=bar",
675 const int responseHeadersSize
= arraysize(responseHeaders
) / 2;
676 scoped_ptr
<SpdyFrame
> resp(
677 spdy_util_
.ConstructSpdySynReplyError(
679 responseHeaders
, responseHeadersSize
,
681 MockRead spdy_reads
[] = {
682 CreateMockRead(*resp
, 1, ASYNC
),
683 MockRead(ASYNC
, 0, 2),
686 Initialize(reads
, arraysize(reads
), writes
, arraysize(writes
),
687 spdy_reads
, arraysize(spdy_reads
), spdy_writes
,
688 arraysize(spdy_writes
));
691 int rv
= handle_
.Init("a", CreateTunnelParams(), LOW
, callback_
.callback(),
692 &pool_
, BoundNetLog());
693 EXPECT_EQ(ERR_IO_PENDING
, rv
);
694 EXPECT_FALSE(handle_
.is_initialized());
695 EXPECT_FALSE(handle_
.socket());
699 rv
= callback_
.WaitForResult();
701 if (GetParam().proxy_type
== HTTP
) {
702 // We don't trust 302 responses to CONNECT from HTTP proxies.
703 EXPECT_EQ(ERR_TUNNEL_CONNECTION_FAILED
, rv
);
704 EXPECT_FALSE(handle_
.is_initialized());
705 EXPECT_FALSE(handle_
.socket());
707 // Expect ProxyClientSocket to return the proxy's response, sanitized.
708 EXPECT_EQ(ERR_HTTPS_PROXY_TUNNEL_RESPONSE
, rv
);
709 EXPECT_TRUE(handle_
.is_initialized());
710 ASSERT_TRUE(handle_
.socket());
712 const ProxyClientSocket
* tunnel_socket
=
713 static_cast<ProxyClientSocket
*>(handle_
.socket());
714 const HttpResponseInfo
* response
= tunnel_socket
->GetConnectResponseInfo();
715 const HttpResponseHeaders
* headers
= response
->headers
.get();
717 // Make sure Set-Cookie header was stripped.
718 EXPECT_FALSE(headers
->HasHeader("set-cookie"));
720 // Make sure Content-Length: 0 header was added.
721 EXPECT_TRUE(headers
->HasHeaderValue("content-length", "0"));
723 // Make sure Location header was included and correct.
724 std::string location
;
725 EXPECT_TRUE(headers
->IsRedirect(&location
));
726 EXPECT_EQ(location
, redirectTarget
);
730 // It would be nice to also test the timeouts in HttpProxyClientSocketPool.