Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / net / http / http_proxy_client_socket_pool_unittest.cc
blob6b44dbbee495857cc6cba401724eb66d474e751a
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/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"
24 namespace net {
26 namespace {
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;
35 enum HttpProxyType {
36 HTTP,
37 HTTPS,
38 SPDY
41 struct HttpProxyClientSocketPoolTestParams {
42 HttpProxyClientSocketPoolTestParams()
43 : proxy_type(HTTP),
44 protocol(kProtoSPDY31) {}
46 HttpProxyClientSocketPoolTestParams(
47 HttpProxyType proxy_type,
48 NextProto protocol)
49 : proxy_type(proxy_type),
50 protocol(protocol) {}
52 HttpProxyType proxy_type;
53 NextProto protocol;
56 typedef ::testing::TestWithParam<HttpProxyType> TestWithHttpParam;
58 const char kHttpProxyHost[] = "httpproxy.example.com";
59 const char kHttpsProxyHost[] = "httpsproxy.example.com";
61 class TestProxyDelegate : public ProxyDelegate {
62 public:
63 TestProxyDelegate()
64 : on_before_tunnel_request_called_(false),
65 on_tunnel_request_completed_called_(false),
66 on_tunnel_headers_received_called_(false) {
69 ~TestProxyDelegate() override {}
71 bool on_before_tunnel_request_called() const {
72 return on_before_tunnel_request_called_;
75 bool on_tunnel_request_completed_called() const {
76 return on_tunnel_request_completed_called_;
79 bool on_tunnel_headers_received_called() const {
80 return on_tunnel_headers_received_called_;
83 void VerifyOnTunnelRequestCompleted(const std::string& endpoint,
84 const std::string& proxy_server) const {
85 EXPECT_TRUE(on_tunnel_request_completed_called_);
86 EXPECT_TRUE(HostPortPair::FromString(endpoint).Equals(
87 on_tunnel_request_completed_endpoint_));
88 EXPECT_TRUE(HostPortPair::FromString(proxy_server).Equals(
89 on_tunnel_request_completed_proxy_server_));
92 void VerifyOnTunnelHeadersReceived(const std::string& origin,
93 const std::string& proxy_server,
94 const std::string& status_line) const {
95 EXPECT_TRUE(on_tunnel_headers_received_called_);
96 EXPECT_TRUE(HostPortPair::FromString(origin).Equals(
97 on_tunnel_headers_received_origin_));
98 EXPECT_TRUE(HostPortPair::FromString(proxy_server).Equals(
99 on_tunnel_headers_received_proxy_server_));
100 EXPECT_EQ(status_line, on_tunnel_headers_received_status_line_);
103 // ProxyDelegate:
104 void OnResolveProxy(const GURL& url,
105 int load_flags,
106 const ProxyService& proxy_service,
107 ProxyInfo* result) override {}
109 void OnTunnelConnectCompleted(const HostPortPair& endpoint,
110 const HostPortPair& proxy_server,
111 int net_error) override {
112 on_tunnel_request_completed_called_ = true;
113 on_tunnel_request_completed_endpoint_ = endpoint;
114 on_tunnel_request_completed_proxy_server_ = proxy_server;
117 void OnFallback(const ProxyServer& bad_proxy, int net_error) override {}
119 void OnBeforeSendHeaders(URLRequest* request,
120 const ProxyInfo& proxy_info,
121 HttpRequestHeaders* headers) override {}
123 void OnBeforeTunnelRequest(const HostPortPair& proxy_server,
124 HttpRequestHeaders* extra_headers) override {
125 on_before_tunnel_request_called_ = true;
126 if (extra_headers) {
127 extra_headers->SetHeader("Foo", proxy_server.ToString());
131 void OnTunnelHeadersReceived(
132 const HostPortPair& origin,
133 const HostPortPair& proxy_server,
134 const HttpResponseHeaders& response_headers) override {
135 on_tunnel_headers_received_called_ = true;
136 on_tunnel_headers_received_origin_ = origin;
137 on_tunnel_headers_received_proxy_server_ = proxy_server;
138 on_tunnel_headers_received_status_line_ = response_headers.GetStatusLine();
141 private:
142 bool on_before_tunnel_request_called_;
143 bool on_tunnel_request_completed_called_;
144 bool on_tunnel_headers_received_called_;
145 HostPortPair on_tunnel_request_completed_endpoint_;
146 HostPortPair on_tunnel_request_completed_proxy_server_;
147 HostPortPair on_tunnel_headers_received_origin_;
148 HostPortPair on_tunnel_headers_received_proxy_server_;
149 std::string on_tunnel_headers_received_status_line_;
153 class HttpProxyClientSocketPoolTest
154 : public ::testing::TestWithParam<HttpProxyClientSocketPoolTestParams> {
155 protected:
156 HttpProxyClientSocketPoolTest()
157 : session_deps_(GetParam().protocol),
158 transport_socket_pool_(kMaxSockets,
159 kMaxSocketsPerGroup,
160 session_deps_.socket_factory.get()),
161 ssl_socket_pool_(kMaxSockets,
162 kMaxSocketsPerGroup,
163 session_deps_.cert_verifier.get(),
164 NULL /* channel_id_store */,
165 NULL /* transport_security_state */,
166 NULL /* cert_transparency_verifier */,
167 NULL /* cert_policy_enforcer */,
168 std::string() /* ssl_session_cache_shard */,
169 session_deps_.socket_factory.get(),
170 &transport_socket_pool_,
171 NULL,
172 NULL,
173 session_deps_.ssl_config_service.get(),
174 BoundNetLog().net_log()),
175 session_(CreateNetworkSession()),
176 spdy_util_(GetParam().protocol),
177 pool_(kMaxSockets,
178 kMaxSocketsPerGroup,
179 &transport_socket_pool_,
180 &ssl_socket_pool_,
181 NULL) {}
183 virtual ~HttpProxyClientSocketPoolTest() {
186 void AddAuthToCache() {
187 const base::string16 kFoo(base::ASCIIToUTF16("foo"));
188 const base::string16 kBar(base::ASCIIToUTF16("bar"));
189 GURL proxy_url(GetParam().proxy_type == HTTP ?
190 (std::string("http://") + kHttpProxyHost) :
191 (std::string("https://") + kHttpsProxyHost));
192 session_->http_auth_cache()->Add(proxy_url,
193 "MyRealm1",
194 HttpAuth::AUTH_SCHEME_BASIC,
195 "Basic realm=MyRealm1",
196 AuthCredentials(kFoo, kBar),
197 "/");
200 scoped_refptr<TransportSocketParams> CreateHttpProxyParams() const {
201 if (GetParam().proxy_type != HTTP)
202 return NULL;
203 return new TransportSocketParams(
204 HostPortPair(kHttpProxyHost, 80),
205 false,
206 false,
207 OnHostResolutionCallback(),
208 TransportSocketParams::COMBINE_CONNECT_AND_WRITE_DEFAULT);
211 scoped_refptr<SSLSocketParams> CreateHttpsProxyParams() const {
212 if (GetParam().proxy_type == HTTP)
213 return NULL;
214 return new SSLSocketParams(
215 new TransportSocketParams(
216 HostPortPair(kHttpsProxyHost, 443),
217 false,
218 false,
219 OnHostResolutionCallback(),
220 TransportSocketParams::COMBINE_CONNECT_AND_WRITE_DEFAULT),
221 NULL,
222 NULL,
223 HostPortPair(kHttpsProxyHost, 443),
224 SSLConfig(),
225 PRIVACY_MODE_DISABLED,
227 false);
230 // Returns the a correctly constructed HttpProxyParms
231 // for the HTTP or HTTPS proxy.
232 scoped_refptr<HttpProxySocketParams> CreateParams(
233 bool tunnel,
234 ProxyDelegate* proxy_delegate) {
235 return scoped_refptr<HttpProxySocketParams>(new HttpProxySocketParams(
236 CreateHttpProxyParams(),
237 CreateHttpsProxyParams(),
238 std::string(),
239 HostPortPair("www.google.com", tunnel ? 443 : 80),
240 session_->http_auth_cache(),
241 session_->http_auth_handler_factory(),
242 session_->spdy_session_pool(),
243 tunnel,
244 proxy_delegate));
247 scoped_refptr<HttpProxySocketParams> CreateTunnelParams(
248 ProxyDelegate* proxy_delegate) {
249 return CreateParams(true, proxy_delegate);
252 scoped_refptr<HttpProxySocketParams> CreateNoTunnelParams(
253 ProxyDelegate* proxy_delegate) {
254 return CreateParams(false, proxy_delegate);
257 MockClientSocketFactory* socket_factory() {
258 return session_deps_.socket_factory.get();
261 void Initialize(MockRead* reads, size_t reads_count,
262 MockWrite* writes, size_t writes_count,
263 MockRead* spdy_reads, size_t spdy_reads_count,
264 MockWrite* spdy_writes, size_t spdy_writes_count) {
265 if (GetParam().proxy_type == SPDY) {
266 data_.reset(new SequencedSocketData(spdy_reads, spdy_reads_count,
267 spdy_writes, spdy_writes_count));
268 } else {
269 data_.reset(
270 new SequencedSocketData(reads, reads_count, writes, writes_count));
273 data_->set_connect_data(MockConnect(SYNCHRONOUS, OK));
275 socket_factory()->AddSocketDataProvider(data_.get());
277 if (GetParam().proxy_type != HTTP) {
278 ssl_data_.reset(new SSLSocketDataProvider(SYNCHRONOUS, OK));
279 if (GetParam().proxy_type == SPDY) {
280 InitializeSpdySsl();
282 socket_factory()->AddSSLSocketDataProvider(ssl_data_.get());
286 void InitializeSpdySsl() {
287 ssl_data_->SetNextProto(GetParam().protocol);
290 HttpNetworkSession* CreateNetworkSession() {
291 return SpdySessionDependencies::SpdyCreateSession(&session_deps_);
294 RequestPriority GetLastTransportRequestPriority() const {
295 return transport_socket_pool_.last_request_priority();
298 private:
299 SpdySessionDependencies session_deps_;
301 MockTransportClientSocketPool transport_socket_pool_;
302 MockHostResolver host_resolver_;
303 scoped_ptr<CertVerifier> cert_verifier_;
304 SSLClientSocketPool ssl_socket_pool_;
306 const scoped_refptr<HttpNetworkSession> session_;
308 protected:
309 SpdyTestUtil spdy_util_;
310 scoped_ptr<SSLSocketDataProvider> ssl_data_;
311 scoped_ptr<SequencedSocketData> data_;
312 HttpProxyClientSocketPool pool_;
313 ClientSocketHandle handle_;
314 TestCompletionCallback callback_;
317 //-----------------------------------------------------------------------------
318 // All tests are run with three different proxy types: HTTP, HTTPS (non-SPDY)
319 // and SPDY.
321 // TODO(akalin): Use ::testing::Combine() when we are able to use
322 // <tr1/tuple>.
323 INSTANTIATE_TEST_CASE_P(
324 HttpProxyClientSocketPoolTests,
325 HttpProxyClientSocketPoolTest,
326 ::testing::Values(HttpProxyClientSocketPoolTestParams(HTTP, kProtoSPDY31),
327 HttpProxyClientSocketPoolTestParams(HTTPS, kProtoSPDY31),
328 HttpProxyClientSocketPoolTestParams(SPDY, kProtoSPDY31),
329 HttpProxyClientSocketPoolTestParams(HTTP, kProtoHTTP2),
330 HttpProxyClientSocketPoolTestParams(HTTPS, kProtoHTTP2),
331 HttpProxyClientSocketPoolTestParams(SPDY, kProtoHTTP2)));
333 TEST_P(HttpProxyClientSocketPoolTest, NoTunnel) {
334 Initialize(NULL, 0, NULL, 0, NULL, 0, NULL, 0);
336 scoped_ptr<TestProxyDelegate> proxy_delegate(new TestProxyDelegate());
337 int rv = handle_.Init("a", CreateNoTunnelParams(proxy_delegate.get()), LOW,
338 CompletionCallback(), &pool_, BoundNetLog());
339 EXPECT_EQ(OK, rv);
340 EXPECT_TRUE(handle_.is_initialized());
341 ASSERT_TRUE(handle_.socket());
342 HttpProxyClientSocket* tunnel_socket =
343 static_cast<HttpProxyClientSocket*>(handle_.socket());
344 EXPECT_TRUE(tunnel_socket->IsConnected());
345 EXPECT_FALSE(proxy_delegate->on_before_tunnel_request_called());
346 EXPECT_FALSE(proxy_delegate->on_tunnel_headers_received_called());
347 EXPECT_TRUE(proxy_delegate->on_tunnel_request_completed_called());
350 // Make sure that HttpProxyConnectJob passes on its priority to its
351 // (non-SSL) socket request on Init.
352 TEST_P(HttpProxyClientSocketPoolTest, SetSocketRequestPriorityOnInit) {
353 Initialize(NULL, 0, NULL, 0, NULL, 0, NULL, 0);
354 EXPECT_EQ(OK,
355 handle_.Init("a", CreateNoTunnelParams(NULL), HIGHEST,
356 CompletionCallback(), &pool_, BoundNetLog()));
357 EXPECT_EQ(HIGHEST, GetLastTransportRequestPriority());
360 TEST_P(HttpProxyClientSocketPoolTest, NeedAuth) {
361 MockWrite writes[] = {
362 MockWrite(ASYNC, 0, "CONNECT www.google.com:443 HTTP/1.1\r\n"
363 "Host: www.google.com\r\n"
364 "Proxy-Connection: keep-alive\r\n\r\n"),
366 MockRead reads[] = {
367 // No credentials.
368 MockRead(ASYNC, 1, "HTTP/1.1 407 Proxy Authentication Required\r\n"),
369 MockRead(ASYNC, 2, "Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
370 MockRead(ASYNC, 3, "Content-Length: 10\r\n\r\n"),
371 MockRead(ASYNC, 4, "0123456789"),
373 scoped_ptr<SpdyFrame> req(spdy_util_.ConstructSpdyConnect(
374 NULL, 0, 1, LOW, HostPortPair("www.google.com", 443)));
375 scoped_ptr<SpdyFrame> rst(
376 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL));
377 MockWrite spdy_writes[] = {
378 CreateMockWrite(*req, 0, ASYNC),
379 CreateMockWrite(*rst, 2, ASYNC),
381 SpdyHeaderBlock resp_block;
382 resp_block[spdy_util_.GetStatusKey()] = "407";
383 resp_block["proxy-authenticate"] = "Basic realm=\"MyRealm1\"";
384 spdy_util_.MaybeAddVersionHeader(&resp_block);
386 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyReply(1, resp_block));
387 MockRead spdy_reads[] = {
388 CreateMockRead(*resp, 1, ASYNC),
389 MockRead(ASYNC, 0, 3)
392 Initialize(reads, arraysize(reads), writes, arraysize(writes),
393 spdy_reads, arraysize(spdy_reads), spdy_writes,
394 arraysize(spdy_writes));
396 int rv = handle_.Init("a", CreateTunnelParams(NULL), LOW,
397 callback_.callback(), &pool_, BoundNetLog());
398 EXPECT_EQ(ERR_IO_PENDING, rv);
399 EXPECT_FALSE(handle_.is_initialized());
400 EXPECT_FALSE(handle_.socket());
402 rv = callback_.WaitForResult();
403 EXPECT_EQ(ERR_PROXY_AUTH_REQUESTED, rv);
404 EXPECT_TRUE(handle_.is_initialized());
405 ASSERT_TRUE(handle_.socket());
406 ProxyClientSocket* tunnel_socket =
407 static_cast<ProxyClientSocket*>(handle_.socket());
408 if (GetParam().proxy_type == SPDY) {
409 EXPECT_TRUE(tunnel_socket->IsConnected());
410 EXPECT_TRUE(tunnel_socket->IsUsingSpdy());
411 } else {
412 EXPECT_FALSE(tunnel_socket->IsConnected());
413 EXPECT_FALSE(tunnel_socket->IsUsingSpdy());
417 TEST_P(HttpProxyClientSocketPoolTest, HaveAuth) {
418 // It's pretty much impossible to make the SPDY case behave synchronously
419 // so we skip this test for SPDY
420 if (GetParam().proxy_type == SPDY)
421 return;
422 std::string proxy_host_port =
423 GetParam().proxy_type == HTTP ?
424 (kHttpProxyHost + std::string(":80")) :
425 (kHttpsProxyHost + std::string(":443"));
426 std::string request =
427 "CONNECT www.google.com:443 HTTP/1.1\r\n"
428 "Host: www.google.com\r\n"
429 "Proxy-Connection: keep-alive\r\n"
430 "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n"
431 "Foo: " + proxy_host_port + "\r\n\r\n";
432 MockWrite writes[] = {
433 MockWrite(SYNCHRONOUS, 0, request.c_str()),
435 MockRead reads[] = {
436 MockRead(SYNCHRONOUS, 1, "HTTP/1.1 200 Connection Established\r\n\r\n"),
439 Initialize(reads, arraysize(reads), writes, arraysize(writes), NULL, 0,
440 NULL, 0);
441 AddAuthToCache();
443 scoped_ptr<TestProxyDelegate> proxy_delegate(new TestProxyDelegate());
444 int rv = handle_.Init("a", CreateTunnelParams(proxy_delegate.get()), LOW,
445 callback_.callback(), &pool_, BoundNetLog());
446 EXPECT_EQ(OK, rv);
447 EXPECT_TRUE(handle_.is_initialized());
448 ASSERT_TRUE(handle_.socket());
449 HttpProxyClientSocket* tunnel_socket =
450 static_cast<HttpProxyClientSocket*>(handle_.socket());
451 EXPECT_TRUE(tunnel_socket->IsConnected());
452 proxy_delegate->VerifyOnTunnelHeadersReceived(
453 "www.google.com:443",
454 proxy_host_port.c_str(),
455 "HTTP/1.1 200 Connection Established");
456 proxy_delegate->VerifyOnTunnelRequestCompleted(
457 "www.google.com:443",
458 proxy_host_port.c_str());
461 TEST_P(HttpProxyClientSocketPoolTest, AsyncHaveAuth) {
462 std::string proxy_host_port =
463 GetParam().proxy_type == HTTP ?
464 (kHttpProxyHost + std::string(":80")) :
465 (kHttpsProxyHost + std::string(":443"));
466 std::string request =
467 "CONNECT www.google.com:443 HTTP/1.1\r\n"
468 "Host: www.google.com\r\n"
469 "Proxy-Connection: keep-alive\r\n"
470 "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n"
471 "Foo: " + proxy_host_port + "\r\n\r\n";
472 MockWrite writes[] = {
473 MockWrite(ASYNC, 0, request.c_str()),
475 MockRead reads[] = {
476 MockRead(ASYNC, 1, "HTTP/1.1 200 Connection Established\r\n\r\n"),
479 scoped_ptr<SpdyFrame> req(
480 spdy_util_.ConstructSpdyConnect(kAuthHeaders, kAuthHeadersSize, 1, LOW,
481 HostPortPair("www.google.com", 443)));
482 MockWrite spdy_writes[] = {
483 CreateMockWrite(*req, 0, ASYNC)
485 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
486 MockRead spdy_reads[] = {
487 CreateMockRead(*resp, 1, ASYNC),
488 // Connection stays open.
489 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 2),
492 Initialize(reads, arraysize(reads), writes, arraysize(writes),
493 spdy_reads, arraysize(spdy_reads), spdy_writes,
494 arraysize(spdy_writes));
495 AddAuthToCache();
497 scoped_ptr<TestProxyDelegate> proxy_delegate(new TestProxyDelegate());
498 int rv = handle_.Init("a", CreateTunnelParams(proxy_delegate.get()), LOW,
499 callback_.callback(), &pool_, BoundNetLog());
500 EXPECT_EQ(ERR_IO_PENDING, rv);
501 EXPECT_FALSE(handle_.is_initialized());
502 EXPECT_FALSE(handle_.socket());
504 EXPECT_EQ(OK, callback_.WaitForResult());
505 EXPECT_TRUE(handle_.is_initialized());
506 ASSERT_TRUE(handle_.socket());
507 EXPECT_TRUE(handle_.socket()->IsConnected());
508 proxy_delegate->VerifyOnTunnelRequestCompleted(
509 "www.google.com:443",
510 proxy_host_port.c_str());
513 // Make sure that HttpProxyConnectJob passes on its priority to its
514 // SPDY session's socket request on Init (if applicable).
515 TEST_P(HttpProxyClientSocketPoolTest,
516 SetSpdySessionSocketRequestPriorityOnInit) {
517 if (GetParam().proxy_type != SPDY)
518 return;
520 scoped_ptr<SpdyFrame> req(
521 spdy_util_.ConstructSpdyConnect(kAuthHeaders, kAuthHeadersSize, 1, MEDIUM,
522 HostPortPair("www.google.com", 443)));
523 MockWrite spdy_writes[] = {
524 CreateMockWrite(*req, 0, ASYNC)
526 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
527 MockRead spdy_reads[] = {
528 CreateMockRead(*resp, 1, ASYNC),
529 MockRead(ASYNC, 0, 2)
532 Initialize(NULL, 0, NULL, 0,
533 spdy_reads, arraysize(spdy_reads),
534 spdy_writes, arraysize(spdy_writes));
535 AddAuthToCache();
537 EXPECT_EQ(ERR_IO_PENDING,
538 handle_.Init("a", CreateTunnelParams(NULL), MEDIUM,
539 callback_.callback(), &pool_, BoundNetLog()));
540 EXPECT_EQ(MEDIUM, GetLastTransportRequestPriority());
542 EXPECT_EQ(OK, callback_.WaitForResult());
545 TEST_P(HttpProxyClientSocketPoolTest, TCPError) {
546 if (GetParam().proxy_type == SPDY) return;
547 data_.reset(new SequencedSocketData(NULL, 0, NULL, 0));
548 data_->set_connect_data(MockConnect(ASYNC, ERR_CONNECTION_CLOSED));
550 socket_factory()->AddSocketDataProvider(data_.get());
552 int rv = handle_.Init("a", CreateTunnelParams(NULL), LOW,
553 callback_.callback(), &pool_, BoundNetLog());
554 EXPECT_EQ(ERR_IO_PENDING, rv);
555 EXPECT_FALSE(handle_.is_initialized());
556 EXPECT_FALSE(handle_.socket());
558 EXPECT_EQ(ERR_PROXY_CONNECTION_FAILED, callback_.WaitForResult());
560 EXPECT_FALSE(handle_.is_initialized());
561 EXPECT_FALSE(handle_.socket());
564 TEST_P(HttpProxyClientSocketPoolTest, SSLError) {
565 if (GetParam().proxy_type == HTTP) return;
566 data_.reset(new SequencedSocketData(NULL, 0, NULL, 0));
567 data_->set_connect_data(MockConnect(ASYNC, OK));
568 socket_factory()->AddSocketDataProvider(data_.get());
570 ssl_data_.reset(new SSLSocketDataProvider(ASYNC,
571 ERR_CERT_AUTHORITY_INVALID));
572 if (GetParam().proxy_type == SPDY) {
573 InitializeSpdySsl();
575 socket_factory()->AddSSLSocketDataProvider(ssl_data_.get());
577 int rv = handle_.Init("a", CreateTunnelParams(NULL), LOW,
578 callback_.callback(), &pool_, BoundNetLog());
579 EXPECT_EQ(ERR_IO_PENDING, rv);
580 EXPECT_FALSE(handle_.is_initialized());
581 EXPECT_FALSE(handle_.socket());
583 EXPECT_EQ(ERR_PROXY_CERTIFICATE_INVALID, callback_.WaitForResult());
585 EXPECT_FALSE(handle_.is_initialized());
586 EXPECT_FALSE(handle_.socket());
589 TEST_P(HttpProxyClientSocketPoolTest, SslClientAuth) {
590 if (GetParam().proxy_type == HTTP) return;
591 data_.reset(new SequencedSocketData(NULL, 0, NULL, 0));
592 data_->set_connect_data(MockConnect(ASYNC, OK));
593 socket_factory()->AddSocketDataProvider(data_.get());
595 ssl_data_.reset(new SSLSocketDataProvider(ASYNC,
596 ERR_SSL_CLIENT_AUTH_CERT_NEEDED));
597 if (GetParam().proxy_type == SPDY) {
598 InitializeSpdySsl();
600 socket_factory()->AddSSLSocketDataProvider(ssl_data_.get());
602 int rv = handle_.Init("a", CreateTunnelParams(NULL), LOW,
603 callback_.callback(), &pool_, BoundNetLog());
604 EXPECT_EQ(ERR_IO_PENDING, rv);
605 EXPECT_FALSE(handle_.is_initialized());
606 EXPECT_FALSE(handle_.socket());
608 EXPECT_EQ(ERR_SSL_CLIENT_AUTH_CERT_NEEDED, callback_.WaitForResult());
610 EXPECT_FALSE(handle_.is_initialized());
611 EXPECT_FALSE(handle_.socket());
614 TEST_P(HttpProxyClientSocketPoolTest, TunnelUnexpectedClose) {
615 MockWrite writes[] = {
616 MockWrite(ASYNC, 0,
617 "CONNECT www.google.com:443 HTTP/1.1\r\n"
618 "Host: www.google.com\r\n"
619 "Proxy-Connection: keep-alive\r\n"
620 "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
622 MockRead reads[] = {
623 MockRead(ASYNC, 1, "HTTP/1.1 200 Conn"),
624 MockRead(ASYNC, ERR_CONNECTION_CLOSED, 2),
626 scoped_ptr<SpdyFrame> req(
627 spdy_util_.ConstructSpdyConnect(kAuthHeaders, kAuthHeadersSize, 1, LOW,
628 HostPortPair("www.google.com", 443)));
629 MockWrite spdy_writes[] = {
630 CreateMockWrite(*req, 0, ASYNC)
632 MockRead spdy_reads[] = {
633 MockRead(ASYNC, ERR_CONNECTION_CLOSED, 1),
636 Initialize(reads, arraysize(reads), writes, arraysize(writes),
637 spdy_reads, arraysize(spdy_reads), spdy_writes,
638 arraysize(spdy_writes));
639 AddAuthToCache();
641 int rv = handle_.Init("a", CreateTunnelParams(NULL), LOW,
642 callback_.callback(), &pool_, BoundNetLog());
643 EXPECT_EQ(ERR_IO_PENDING, rv);
644 EXPECT_FALSE(handle_.is_initialized());
645 EXPECT_FALSE(handle_.socket());
647 if (GetParam().proxy_type == SPDY) {
648 // SPDY cannot process a headers block unless it's complete and so it
649 // returns ERR_CONNECTION_CLOSED in this case.
650 EXPECT_EQ(ERR_CONNECTION_CLOSED, callback_.WaitForResult());
651 } else {
652 EXPECT_EQ(ERR_RESPONSE_HEADERS_TRUNCATED, callback_.WaitForResult());
654 EXPECT_FALSE(handle_.is_initialized());
655 EXPECT_FALSE(handle_.socket());
658 TEST_P(HttpProxyClientSocketPoolTest, Tunnel1xxResponse) {
659 // Tests that 1xx responses are rejected for a CONNECT request.
660 if (GetParam().proxy_type == SPDY) {
661 // SPDY doesn't have 1xx responses.
662 return;
665 MockWrite writes[] = {
666 MockWrite(ASYNC, 0,
667 "CONNECT www.google.com:443 HTTP/1.1\r\n"
668 "Host: www.google.com\r\n"
669 "Proxy-Connection: keep-alive\r\n\r\n"),
671 MockRead reads[] = {
672 MockRead(ASYNC, 1, "HTTP/1.1 100 Continue\r\n\r\n"),
673 MockRead(ASYNC, 2, "HTTP/1.1 200 Connection Established\r\n\r\n"),
676 Initialize(reads, arraysize(reads), writes, arraysize(writes),
677 NULL, 0, NULL, 0);
679 int rv = handle_.Init("a", CreateTunnelParams(NULL), LOW,
680 callback_.callback(), &pool_, BoundNetLog());
681 EXPECT_EQ(ERR_IO_PENDING, rv);
682 EXPECT_FALSE(handle_.is_initialized());
683 EXPECT_FALSE(handle_.socket());
685 EXPECT_EQ(ERR_TUNNEL_CONNECTION_FAILED, callback_.WaitForResult());
688 TEST_P(HttpProxyClientSocketPoolTest, TunnelSetupError) {
689 MockWrite writes[] = {
690 MockWrite(ASYNC, 0,
691 "CONNECT www.google.com:443 HTTP/1.1\r\n"
692 "Host: www.google.com\r\n"
693 "Proxy-Connection: keep-alive\r\n"
694 "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
696 MockRead reads[] = {
697 MockRead(ASYNC, 1, "HTTP/1.1 304 Not Modified\r\n\r\n"),
699 scoped_ptr<SpdyFrame> req(
700 spdy_util_.ConstructSpdyConnect(kAuthHeaders, kAuthHeadersSize, 1, LOW,
701 HostPortPair("www.google.com", 443)));
702 scoped_ptr<SpdyFrame> rst(
703 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL));
704 MockWrite spdy_writes[] = {
705 CreateMockWrite(*req, 0, ASYNC),
706 CreateMockWrite(*rst, 2, ASYNC),
708 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdySynReplyError(1));
709 MockRead spdy_reads[] = {
710 CreateMockRead(*resp, 1, ASYNC),
711 MockRead(ASYNC, 0, 3),
714 Initialize(reads, arraysize(reads), writes, arraysize(writes),
715 spdy_reads, arraysize(spdy_reads), spdy_writes,
716 arraysize(spdy_writes));
717 AddAuthToCache();
719 int rv = handle_.Init("a", CreateTunnelParams(NULL), LOW,
720 callback_.callback(), &pool_, BoundNetLog());
721 EXPECT_EQ(ERR_IO_PENDING, rv);
722 EXPECT_FALSE(handle_.is_initialized());
723 EXPECT_FALSE(handle_.socket());
725 rv = callback_.WaitForResult();
726 // All Proxy CONNECT responses are not trustworthy
727 EXPECT_EQ(ERR_TUNNEL_CONNECTION_FAILED, rv);
728 EXPECT_FALSE(handle_.is_initialized());
729 EXPECT_FALSE(handle_.socket());
732 TEST_P(HttpProxyClientSocketPoolTest, TunnelSetupRedirect) {
733 const std::string redirectTarget = "https://foo.google.com/";
735 const std::string responseText = "HTTP/1.1 302 Found\r\n"
736 "Location: " + redirectTarget + "\r\n"
737 "Set-Cookie: foo=bar\r\n"
738 "\r\n";
739 MockWrite writes[] = {
740 MockWrite(ASYNC, 0,
741 "CONNECT www.google.com:443 HTTP/1.1\r\n"
742 "Host: www.google.com\r\n"
743 "Proxy-Connection: keep-alive\r\n"
744 "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
746 MockRead reads[] = {
747 MockRead(ASYNC, 1, responseText.c_str()),
749 scoped_ptr<SpdyFrame> req(
750 spdy_util_.ConstructSpdyConnect(kAuthHeaders, kAuthHeadersSize, 1, LOW,
751 HostPortPair("www.google.com", 443)));
752 scoped_ptr<SpdyFrame> rst(
753 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL));
755 MockWrite spdy_writes[] = {
756 CreateMockWrite(*req, 0, ASYNC),
757 CreateMockWrite(*rst, 3, ASYNC),
760 const char* const responseHeaders[] = {
761 "location", redirectTarget.c_str(),
762 "set-cookie", "foo=bar",
764 const int responseHeadersSize = arraysize(responseHeaders) / 2;
765 scoped_ptr<SpdyFrame> resp(
766 spdy_util_.ConstructSpdySynReplyError(
767 "302 Found",
768 responseHeaders, responseHeadersSize,
769 1));
770 MockRead spdy_reads[] = {
771 CreateMockRead(*resp, 1, ASYNC),
772 MockRead(ASYNC, 0, 2),
775 Initialize(reads, arraysize(reads), writes, arraysize(writes),
776 spdy_reads, arraysize(spdy_reads), spdy_writes,
777 arraysize(spdy_writes));
778 AddAuthToCache();
780 int rv = handle_.Init("a", CreateTunnelParams(NULL), LOW,
781 callback_.callback(), &pool_, BoundNetLog());
782 EXPECT_EQ(ERR_IO_PENDING, rv);
783 EXPECT_FALSE(handle_.is_initialized());
784 EXPECT_FALSE(handle_.socket());
786 rv = callback_.WaitForResult();
788 if (GetParam().proxy_type == HTTP) {
789 // We don't trust 302 responses to CONNECT from HTTP proxies.
790 EXPECT_EQ(ERR_TUNNEL_CONNECTION_FAILED, rv);
791 EXPECT_FALSE(handle_.is_initialized());
792 EXPECT_FALSE(handle_.socket());
793 } else {
794 // Expect ProxyClientSocket to return the proxy's response, sanitized.
795 EXPECT_EQ(ERR_HTTPS_PROXY_TUNNEL_RESPONSE, rv);
796 EXPECT_TRUE(handle_.is_initialized());
797 ASSERT_TRUE(handle_.socket());
799 const ProxyClientSocket* tunnel_socket =
800 static_cast<ProxyClientSocket*>(handle_.socket());
801 const HttpResponseInfo* response = tunnel_socket->GetConnectResponseInfo();
802 const HttpResponseHeaders* headers = response->headers.get();
804 // Make sure Set-Cookie header was stripped.
805 EXPECT_FALSE(headers->HasHeader("set-cookie"));
807 // Make sure Content-Length: 0 header was added.
808 EXPECT_TRUE(headers->HasHeaderValue("content-length", "0"));
810 // Make sure Location header was included and correct.
811 std::string location;
812 EXPECT_TRUE(headers->IsRedirect(&location));
813 EXPECT_EQ(location, redirectTarget);
817 // It would be nice to also test the timeouts in HttpProxyClientSocketPool.
819 } // namespace
821 } // namespace net