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(kProtoSPDY2
) {}
46 HttpProxyClientSocketPoolTestParams(
47 HttpProxyType proxy_type
,
49 : proxy_type(proxy_type
),
52 HttpProxyType proxy_type
;
56 typedef ::testing::TestWithParam
<HttpProxyType
> TestWithHttpParam
;
60 class HttpProxyClientSocketPoolTest
61 : public ::testing::TestWithParam
<HttpProxyClientSocketPoolTestParams
> {
63 HttpProxyClientSocketPoolTest()
64 : session_deps_(GetParam().protocol
),
66 ignored_transport_socket_params_(
67 new TransportSocketParams(HostPortPair("proxy", 80),
71 OnHostResolutionCallback())),
72 ignored_ssl_socket_params_(
73 new SSLSocketParams(ignored_transport_socket_params_
,
76 ProxyServer::SCHEME_DIRECT
,
77 HostPortPair("www.google.com", 443),
83 tcp_histograms_("MockTCP"),
84 transport_socket_pool_(
88 session_deps_
.deterministic_socket_factory
.get()),
89 ssl_histograms_("MockSSL"),
90 ssl_socket_pool_(kMaxSockets
,
93 session_deps_
.host_resolver
.get(),
94 session_deps_
.cert_verifier
.get(),
95 NULL
/* server_bound_cert_store */,
96 NULL
/* transport_security_state */,
97 std::string() /* ssl_session_cache_shard */,
98 session_deps_
.deterministic_socket_factory
.get(),
99 &transport_socket_pool_
,
102 session_deps_
.ssl_config_service
.get(),
103 BoundNetLog().net_log()),
104 session_(CreateNetworkSession()),
105 http_proxy_histograms_("HttpProxyUnitTest"),
106 spdy_util_(GetParam().protocol
),
109 &http_proxy_histograms_
,
111 &transport_socket_pool_
,
115 virtual ~HttpProxyClientSocketPoolTest() {
118 void AddAuthToCache() {
119 const base::string16
kFoo(ASCIIToUTF16("foo"));
120 const base::string16
kBar(ASCIIToUTF16("bar"));
121 GURL
proxy_url(GetParam().proxy_type
== HTTP
? "http://proxy" : "https://proxy:80");
122 session_
->http_auth_cache()->Add(proxy_url
,
124 HttpAuth::AUTH_SCHEME_BASIC
,
125 "Basic realm=MyRealm1",
126 AuthCredentials(kFoo
, kBar
),
130 scoped_refptr
<TransportSocketParams
> GetTcpParams() {
131 if (GetParam().proxy_type
!= HTTP
)
132 return scoped_refptr
<TransportSocketParams
>();
133 return ignored_transport_socket_params_
;
136 scoped_refptr
<SSLSocketParams
> GetSslParams() {
137 if (GetParam().proxy_type
== HTTP
)
138 return scoped_refptr
<SSLSocketParams
>();
139 return ignored_ssl_socket_params_
;
142 // Returns the a correctly constructed HttpProxyParms
143 // for the HTTP or HTTPS proxy.
144 scoped_refptr
<HttpProxySocketParams
> GetParams(bool tunnel
) {
145 return scoped_refptr
<HttpProxySocketParams
>(new HttpProxySocketParams(
148 GURL(tunnel
? "https://www.google.com/" : "http://www.google.com"),
150 HostPortPair("www.google.com", tunnel
? 443 : 80),
151 session_
->http_auth_cache(),
152 session_
->http_auth_handler_factory(),
153 session_
->spdy_session_pool(),
157 scoped_refptr
<HttpProxySocketParams
> GetTunnelParams() {
158 return GetParams(true);
161 scoped_refptr
<HttpProxySocketParams
> GetNoTunnelParams() {
162 return GetParams(false);
165 DeterministicMockClientSocketFactory
& socket_factory() {
166 return *session_deps_
.deterministic_socket_factory
.get();
169 void Initialize(MockRead
* reads
, size_t reads_count
,
170 MockWrite
* writes
, size_t writes_count
,
171 MockRead
* spdy_reads
, size_t spdy_reads_count
,
172 MockWrite
* spdy_writes
, size_t spdy_writes_count
) {
173 if (GetParam().proxy_type
== SPDY
) {
174 data_
.reset(new DeterministicSocketData(spdy_reads
, spdy_reads_count
,
175 spdy_writes
, spdy_writes_count
));
177 data_
.reset(new DeterministicSocketData(reads
, reads_count
, writes
,
181 data_
->set_connect_data(MockConnect(SYNCHRONOUS
, OK
));
182 data_
->StopAfter(2); // Request / Response
184 socket_factory().AddSocketDataProvider(data_
.get());
186 if (GetParam().proxy_type
!= HTTP
) {
187 ssl_data_
.reset(new SSLSocketDataProvider(SYNCHRONOUS
, OK
));
188 if (GetParam().proxy_type
== SPDY
) {
191 socket_factory().AddSSLSocketDataProvider(ssl_data_
.get());
195 void InitializeSpdySsl() {
196 ssl_data_
->SetNextProto(GetParam().protocol
);
199 HttpNetworkSession
* CreateNetworkSession() {
200 return SpdySessionDependencies::SpdyCreateSessionDeterministic(
205 SpdySessionDependencies session_deps_
;
206 SSLConfig ssl_config_
;
208 scoped_refptr
<TransportSocketParams
> ignored_transport_socket_params_
;
209 scoped_refptr
<SSLSocketParams
> ignored_ssl_socket_params_
;
210 ClientSocketPoolHistograms tcp_histograms_
;
211 MockTransportClientSocketPool transport_socket_pool_
;
212 ClientSocketPoolHistograms ssl_histograms_
;
213 MockHostResolver host_resolver_
;
214 scoped_ptr
<CertVerifier
> cert_verifier_
;
215 SSLClientSocketPool ssl_socket_pool_
;
217 const scoped_refptr
<HttpNetworkSession
> session_
;
218 ClientSocketPoolHistograms http_proxy_histograms_
;
221 SpdyTestUtil spdy_util_
;
222 scoped_ptr
<SSLSocketDataProvider
> ssl_data_
;
223 scoped_ptr
<DeterministicSocketData
> data_
;
224 HttpProxyClientSocketPool pool_
;
225 ClientSocketHandle handle_
;
226 TestCompletionCallback callback_
;
229 //-----------------------------------------------------------------------------
230 // All tests are run with three different proxy types: HTTP, HTTPS (non-SPDY)
233 // TODO(akalin): Use ::testing::Combine() when we are able to use
235 INSTANTIATE_TEST_CASE_P(
236 HttpProxyClientSocketPoolTests
,
237 HttpProxyClientSocketPoolTest
,
239 HttpProxyClientSocketPoolTestParams(HTTP
, kProtoSPDY2
),
240 HttpProxyClientSocketPoolTestParams(HTTPS
, kProtoSPDY2
),
241 HttpProxyClientSocketPoolTestParams(SPDY
, kProtoSPDY2
),
242 HttpProxyClientSocketPoolTestParams(HTTP
, kProtoSPDY3
),
243 HttpProxyClientSocketPoolTestParams(HTTPS
, kProtoSPDY3
),
244 HttpProxyClientSocketPoolTestParams(SPDY
, kProtoSPDY3
),
245 HttpProxyClientSocketPoolTestParams(HTTP
, kProtoSPDY31
),
246 HttpProxyClientSocketPoolTestParams(HTTPS
, kProtoSPDY31
),
247 HttpProxyClientSocketPoolTestParams(SPDY
, kProtoSPDY31
),
248 HttpProxyClientSocketPoolTestParams(HTTP
, kProtoSPDY4a2
),
249 HttpProxyClientSocketPoolTestParams(HTTPS
, kProtoSPDY4a2
),
250 HttpProxyClientSocketPoolTestParams(SPDY
, kProtoSPDY4a2
)));
252 TEST_P(HttpProxyClientSocketPoolTest
, NoTunnel
) {
253 Initialize(NULL
, 0, NULL
, 0, NULL
, 0, NULL
, 0);
255 int rv
= handle_
.Init("a", GetNoTunnelParams(), LOW
, CompletionCallback(),
256 &pool_
, BoundNetLog());
258 EXPECT_TRUE(handle_
.is_initialized());
259 ASSERT_TRUE(handle_
.socket());
260 HttpProxyClientSocket
* tunnel_socket
=
261 static_cast<HttpProxyClientSocket
*>(handle_
.socket());
262 EXPECT_TRUE(tunnel_socket
->IsConnected());
265 TEST_P(HttpProxyClientSocketPoolTest
, NeedAuth
) {
266 MockWrite writes
[] = {
267 MockWrite(ASYNC
, 0, "CONNECT www.google.com:443 HTTP/1.1\r\n"
268 "Host: www.google.com\r\n"
269 "Proxy-Connection: keep-alive\r\n\r\n"),
273 MockRead(ASYNC
, 1, "HTTP/1.1 407 Proxy Authentication Required\r\n"),
274 MockRead(ASYNC
, 2, "Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
275 MockRead(ASYNC
, 3, "Content-Length: 10\r\n\r\n"),
276 MockRead(ASYNC
, 4, "0123456789"),
278 scoped_ptr
<SpdyFrame
> req(
279 spdy_util_
.ConstructSpdyConnect(NULL
, 0, 1));
280 scoped_ptr
<SpdyFrame
> rst(
281 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_CANCEL
));
282 MockWrite spdy_writes
[] = {
283 CreateMockWrite(*req
, 0, ASYNC
),
284 CreateMockWrite(*rst
, 2, ASYNC
),
286 const char* const kAuthChallenge
[] = {
287 spdy_util_
.GetStatusKey(), "407 Proxy Authentication Required",
288 spdy_util_
.GetVersionKey(), "HTTP/1.1",
289 "proxy-authenticate", "Basic realm=\"MyRealm1\"",
291 scoped_ptr
<SpdyFrame
> resp(
292 spdy_util_
.ConstructSpdyControlFrame(NULL
,
300 arraysize(kAuthChallenge
),
302 MockRead spdy_reads
[] = {
303 CreateMockRead(*resp
, 1, ASYNC
),
304 MockRead(ASYNC
, 0, 3)
307 Initialize(reads
, arraysize(reads
), writes
, arraysize(writes
),
308 spdy_reads
, arraysize(spdy_reads
), spdy_writes
,
309 arraysize(spdy_writes
));
312 int rv
= handle_
.Init("a", GetTunnelParams(), LOW
, callback_
.callback(),
313 &pool_
, BoundNetLog());
314 EXPECT_EQ(ERR_IO_PENDING
, rv
);
315 EXPECT_FALSE(handle_
.is_initialized());
316 EXPECT_FALSE(handle_
.socket());
318 data_
->RunFor(GetParam().proxy_type
== SPDY
? 2 : 4);
319 rv
= callback_
.WaitForResult();
320 EXPECT_EQ(ERR_PROXY_AUTH_REQUESTED
, rv
);
321 EXPECT_TRUE(handle_
.is_initialized());
322 ASSERT_TRUE(handle_
.socket());
323 ProxyClientSocket
* tunnel_socket
=
324 static_cast<ProxyClientSocket
*>(handle_
.socket());
325 if (GetParam().proxy_type
== SPDY
) {
326 EXPECT_TRUE(tunnel_socket
->IsConnected());
327 EXPECT_TRUE(tunnel_socket
->IsUsingSpdy());
329 EXPECT_FALSE(tunnel_socket
->IsConnected());
330 EXPECT_FALSE(tunnel_socket
->IsUsingSpdy());
331 EXPECT_FALSE(tunnel_socket
->IsUsingSpdy());
335 TEST_P(HttpProxyClientSocketPoolTest
, HaveAuth
) {
336 // It's pretty much impossible to make the SPDY case behave synchronously
337 // so we skip this test for SPDY
338 if (GetParam().proxy_type
== SPDY
)
340 MockWrite writes
[] = {
341 MockWrite(SYNCHRONOUS
, 0,
342 "CONNECT www.google.com:443 HTTP/1.1\r\n"
343 "Host: www.google.com\r\n"
344 "Proxy-Connection: keep-alive\r\n"
345 "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
348 MockRead(SYNCHRONOUS
, 1, "HTTP/1.1 200 Connection Established\r\n\r\n"),
351 Initialize(reads
, arraysize(reads
), writes
, arraysize(writes
), NULL
, 0,
355 int rv
= handle_
.Init("a", GetTunnelParams(), LOW
, callback_
.callback(),
356 &pool_
, BoundNetLog());
358 EXPECT_TRUE(handle_
.is_initialized());
359 ASSERT_TRUE(handle_
.socket());
360 HttpProxyClientSocket
* tunnel_socket
=
361 static_cast<HttpProxyClientSocket
*>(handle_
.socket());
362 EXPECT_TRUE(tunnel_socket
->IsConnected());
365 TEST_P(HttpProxyClientSocketPoolTest
, AsyncHaveAuth
) {
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"
370 "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
373 MockRead(ASYNC
, 1, "HTTP/1.1 200 Connection Established\r\n\r\n"),
376 scoped_ptr
<SpdyFrame
> req(
377 spdy_util_
.ConstructSpdyConnect(kAuthHeaders
, kAuthHeadersSize
, 1));
378 MockWrite spdy_writes
[] = {
379 CreateMockWrite(*req
, 0, ASYNC
)
381 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
382 MockRead spdy_reads
[] = {
383 CreateMockRead(*resp
, 1, ASYNC
),
384 MockRead(ASYNC
, 0, 2)
387 Initialize(reads
, arraysize(reads
), writes
, arraysize(writes
),
388 spdy_reads
, arraysize(spdy_reads
), spdy_writes
,
389 arraysize(spdy_writes
));
392 int rv
= handle_
.Init("a", GetTunnelParams(), LOW
, callback_
.callback(),
393 &pool_
, BoundNetLog());
394 EXPECT_EQ(ERR_IO_PENDING
, rv
);
395 EXPECT_FALSE(handle_
.is_initialized());
396 EXPECT_FALSE(handle_
.socket());
399 EXPECT_EQ(OK
, callback_
.WaitForResult());
400 EXPECT_TRUE(handle_
.is_initialized());
401 ASSERT_TRUE(handle_
.socket());
402 HttpProxyClientSocket
* tunnel_socket
=
403 static_cast<HttpProxyClientSocket
*>(handle_
.socket());
404 EXPECT_TRUE(tunnel_socket
->IsConnected());
407 TEST_P(HttpProxyClientSocketPoolTest
, TCPError
) {
408 if (GetParam().proxy_type
== SPDY
) return;
409 data_
.reset(new DeterministicSocketData(NULL
, 0, NULL
, 0));
410 data_
->set_connect_data(MockConnect(ASYNC
, ERR_CONNECTION_CLOSED
));
412 socket_factory().AddSocketDataProvider(data_
.get());
414 int rv
= handle_
.Init("a", GetTunnelParams(), LOW
, callback_
.callback(),
415 &pool_
, BoundNetLog());
416 EXPECT_EQ(ERR_IO_PENDING
, rv
);
417 EXPECT_FALSE(handle_
.is_initialized());
418 EXPECT_FALSE(handle_
.socket());
420 EXPECT_EQ(ERR_PROXY_CONNECTION_FAILED
, callback_
.WaitForResult());
422 EXPECT_FALSE(handle_
.is_initialized());
423 EXPECT_FALSE(handle_
.socket());
426 TEST_P(HttpProxyClientSocketPoolTest
, SSLError
) {
427 if (GetParam().proxy_type
== HTTP
) return;
428 data_
.reset(new DeterministicSocketData(NULL
, 0, NULL
, 0));
429 data_
->set_connect_data(MockConnect(ASYNC
, OK
));
430 socket_factory().AddSocketDataProvider(data_
.get());
432 ssl_data_
.reset(new SSLSocketDataProvider(ASYNC
,
433 ERR_CERT_AUTHORITY_INVALID
));
434 if (GetParam().proxy_type
== SPDY
) {
437 socket_factory().AddSSLSocketDataProvider(ssl_data_
.get());
439 int rv
= handle_
.Init("a", GetTunnelParams(), LOW
, callback_
.callback(),
440 &pool_
, BoundNetLog());
441 EXPECT_EQ(ERR_IO_PENDING
, rv
);
442 EXPECT_FALSE(handle_
.is_initialized());
443 EXPECT_FALSE(handle_
.socket());
445 EXPECT_EQ(ERR_PROXY_CERTIFICATE_INVALID
, callback_
.WaitForResult());
447 EXPECT_FALSE(handle_
.is_initialized());
448 EXPECT_FALSE(handle_
.socket());
451 TEST_P(HttpProxyClientSocketPoolTest
, SslClientAuth
) {
452 if (GetParam().proxy_type
== HTTP
) return;
453 data_
.reset(new DeterministicSocketData(NULL
, 0, NULL
, 0));
454 data_
->set_connect_data(MockConnect(ASYNC
, OK
));
455 socket_factory().AddSocketDataProvider(data_
.get());
457 ssl_data_
.reset(new SSLSocketDataProvider(ASYNC
,
458 ERR_SSL_CLIENT_AUTH_CERT_NEEDED
));
459 if (GetParam().proxy_type
== SPDY
) {
462 socket_factory().AddSSLSocketDataProvider(ssl_data_
.get());
464 int rv
= handle_
.Init("a", GetTunnelParams(), LOW
, callback_
.callback(),
465 &pool_
, BoundNetLog());
466 EXPECT_EQ(ERR_IO_PENDING
, rv
);
467 EXPECT_FALSE(handle_
.is_initialized());
468 EXPECT_FALSE(handle_
.socket());
470 EXPECT_EQ(ERR_SSL_CLIENT_AUTH_CERT_NEEDED
, callback_
.WaitForResult());
472 EXPECT_FALSE(handle_
.is_initialized());
473 EXPECT_FALSE(handle_
.socket());
476 TEST_P(HttpProxyClientSocketPoolTest
, TunnelUnexpectedClose
) {
477 MockWrite writes
[] = {
479 "CONNECT www.google.com:443 HTTP/1.1\r\n"
480 "Host: www.google.com\r\n"
481 "Proxy-Connection: keep-alive\r\n"
482 "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
485 MockRead(ASYNC
, 1, "HTTP/1.1 200 Conn"),
486 MockRead(ASYNC
, ERR_CONNECTION_CLOSED
, 2),
488 scoped_ptr
<SpdyFrame
> req(
489 spdy_util_
.ConstructSpdyConnect(kAuthHeaders
, kAuthHeadersSize
, 1));
490 MockWrite spdy_writes
[] = {
491 CreateMockWrite(*req
, 0, ASYNC
)
493 MockRead spdy_reads
[] = {
494 MockRead(ASYNC
, ERR_CONNECTION_CLOSED
, 1),
497 Initialize(reads
, arraysize(reads
), writes
, arraysize(writes
),
498 spdy_reads
, arraysize(spdy_reads
), spdy_writes
,
499 arraysize(spdy_writes
));
502 int rv
= handle_
.Init("a", GetTunnelParams(), LOW
, callback_
.callback(),
503 &pool_
, BoundNetLog());
504 EXPECT_EQ(ERR_IO_PENDING
, rv
);
505 EXPECT_FALSE(handle_
.is_initialized());
506 EXPECT_FALSE(handle_
.socket());
509 if (GetParam().proxy_type
== SPDY
) {
510 // SPDY cannot process a headers block unless it's complete and so it
511 // returns ERR_CONNECTION_CLOSED in this case.
512 EXPECT_EQ(ERR_CONNECTION_CLOSED
, callback_
.WaitForResult());
514 EXPECT_EQ(ERR_RESPONSE_HEADERS_TRUNCATED
, callback_
.WaitForResult());
516 EXPECT_FALSE(handle_
.is_initialized());
517 EXPECT_FALSE(handle_
.socket());
520 TEST_P(HttpProxyClientSocketPoolTest
, TunnelSetupError
) {
521 MockWrite writes
[] = {
523 "CONNECT www.google.com:443 HTTP/1.1\r\n"
524 "Host: www.google.com\r\n"
525 "Proxy-Connection: keep-alive\r\n"
526 "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
529 MockRead(ASYNC
, 1, "HTTP/1.1 304 Not Modified\r\n\r\n"),
531 scoped_ptr
<SpdyFrame
> req(
532 spdy_util_
.ConstructSpdyConnect(kAuthHeaders
, kAuthHeadersSize
, 1));
533 scoped_ptr
<SpdyFrame
> rst(
534 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_CANCEL
));
535 MockWrite spdy_writes
[] = {
536 CreateMockWrite(*req
, 0, ASYNC
),
537 CreateMockWrite(*rst
, 2, ASYNC
),
539 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdySynReplyError(1));
540 MockRead spdy_reads
[] = {
541 CreateMockRead(*resp
, 1, ASYNC
),
542 MockRead(ASYNC
, 0, 3),
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", GetTunnelParams(), LOW
, callback_
.callback(),
551 &pool_
, BoundNetLog());
552 EXPECT_EQ(ERR_IO_PENDING
, rv
);
553 EXPECT_FALSE(handle_
.is_initialized());
554 EXPECT_FALSE(handle_
.socket());
558 rv
= callback_
.WaitForResult();
559 // All Proxy CONNECT responses are not trustworthy
560 EXPECT_EQ(ERR_TUNNEL_CONNECTION_FAILED
, rv
);
561 EXPECT_FALSE(handle_
.is_initialized());
562 EXPECT_FALSE(handle_
.socket());
565 TEST_P(HttpProxyClientSocketPoolTest
, TunnelSetupRedirect
) {
566 const std::string redirectTarget
= "https://foo.google.com/";
568 const std::string responseText
= "HTTP/1.1 302 Found\r\n"
569 "Location: " + redirectTarget
+ "\r\n"
570 "Set-Cookie: foo=bar\r\n"
572 MockWrite writes
[] = {
574 "CONNECT www.google.com:443 HTTP/1.1\r\n"
575 "Host: www.google.com\r\n"
576 "Proxy-Connection: keep-alive\r\n"
577 "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
580 MockRead(ASYNC
, 1, responseText
.c_str()),
582 scoped_ptr
<SpdyFrame
> req(
583 spdy_util_
.ConstructSpdyConnect(kAuthHeaders
, kAuthHeadersSize
, 1));
584 scoped_ptr
<SpdyFrame
> rst(
585 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_CANCEL
));
587 MockWrite spdy_writes
[] = {
588 CreateMockWrite(*req
, 0, ASYNC
),
589 CreateMockWrite(*rst
, 3, ASYNC
),
592 const char* const responseHeaders
[] = {
593 "location", redirectTarget
.c_str(),
594 "set-cookie", "foo=bar",
596 const int responseHeadersSize
= arraysize(responseHeaders
) / 2;
597 scoped_ptr
<SpdyFrame
> resp(
598 spdy_util_
.ConstructSpdySynReplyError(
600 responseHeaders
, responseHeadersSize
,
602 MockRead spdy_reads
[] = {
603 CreateMockRead(*resp
, 1, ASYNC
),
604 MockRead(ASYNC
, 0, 2),
607 Initialize(reads
, arraysize(reads
), writes
, arraysize(writes
),
608 spdy_reads
, arraysize(spdy_reads
), spdy_writes
,
609 arraysize(spdy_writes
));
612 int rv
= handle_
.Init("a", GetTunnelParams(), LOW
, callback_
.callback(),
613 &pool_
, BoundNetLog());
614 EXPECT_EQ(ERR_IO_PENDING
, rv
);
615 EXPECT_FALSE(handle_
.is_initialized());
616 EXPECT_FALSE(handle_
.socket());
620 rv
= callback_
.WaitForResult();
622 if (GetParam().proxy_type
== HTTP
) {
623 // We don't trust 302 responses to CONNECT from HTTP proxies.
624 EXPECT_EQ(ERR_TUNNEL_CONNECTION_FAILED
, rv
);
625 EXPECT_FALSE(handle_
.is_initialized());
626 EXPECT_FALSE(handle_
.socket());
628 // Expect ProxyClientSocket to return the proxy's response, sanitized.
629 EXPECT_EQ(ERR_HTTPS_PROXY_TUNNEL_RESPONSE
, rv
);
630 EXPECT_TRUE(handle_
.is_initialized());
631 ASSERT_TRUE(handle_
.socket());
633 const ProxyClientSocket
* tunnel_socket
=
634 static_cast<ProxyClientSocket
*>(handle_
.socket());
635 const HttpResponseInfo
* response
= tunnel_socket
->GetConnectResponseInfo();
636 const HttpResponseHeaders
* headers
= response
->headers
.get();
638 // Make sure Set-Cookie header was stripped.
639 EXPECT_FALSE(headers
->HasHeader("set-cookie"));
641 // Make sure Content-Length: 0 header was added.
642 EXPECT_TRUE(headers
->HasHeaderValue("content-length", "0"));
644 // Make sure Location header was included and correct.
645 std::string location
;
646 EXPECT_TRUE(headers
->IsRedirect(&location
));
647 EXPECT_EQ(location
, redirectTarget
);
651 // It would be nice to also test the timeouts in HttpProxyClientSocketPool.