Include all dupe types (event when value is zero) in scan stats.
[chromium-blink-merge.git] / net / http / http_proxy_client_socket_pool_unittest.cc
blobfffb897fab78ae0930dc5085c8d9c86e8011f77b
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_(
159 kMaxSockets,
160 kMaxSocketsPerGroup,
161 session_deps_.deterministic_socket_factory.get()),
162 ssl_socket_pool_(kMaxSockets,
163 kMaxSocketsPerGroup,
164 session_deps_.cert_verifier.get(),
165 NULL /* channel_id_store */,
166 NULL /* transport_security_state */,
167 NULL /* cert_transparency_verifier */,
168 NULL /* cert_policy_enforcer */,
169 std::string() /* ssl_session_cache_shard */,
170 session_deps_.deterministic_socket_factory.get(),
171 &transport_socket_pool_,
172 NULL,
173 NULL,
174 session_deps_.ssl_config_service.get(),
175 BoundNetLog().net_log()),
176 session_(CreateNetworkSession()),
177 spdy_util_(GetParam().protocol),
178 pool_(kMaxSockets,
179 kMaxSocketsPerGroup,
180 &transport_socket_pool_,
181 &ssl_socket_pool_,
182 NULL) {}
184 virtual ~HttpProxyClientSocketPoolTest() {
187 void AddAuthToCache() {
188 const base::string16 kFoo(base::ASCIIToUTF16("foo"));
189 const base::string16 kBar(base::ASCIIToUTF16("bar"));
190 GURL proxy_url(GetParam().proxy_type == HTTP ?
191 (std::string("http://") + kHttpProxyHost) :
192 (std::string("https://") + kHttpsProxyHost));
193 session_->http_auth_cache()->Add(proxy_url,
194 "MyRealm1",
195 HttpAuth::AUTH_SCHEME_BASIC,
196 "Basic realm=MyRealm1",
197 AuthCredentials(kFoo, kBar),
198 "/");
201 scoped_refptr<TransportSocketParams> CreateHttpProxyParams() const {
202 if (GetParam().proxy_type != HTTP)
203 return NULL;
204 return new TransportSocketParams(
205 HostPortPair(kHttpProxyHost, 80),
206 false,
207 false,
208 OnHostResolutionCallback(),
209 TransportSocketParams::COMBINE_CONNECT_AND_WRITE_DEFAULT);
212 scoped_refptr<SSLSocketParams> CreateHttpsProxyParams() const {
213 if (GetParam().proxy_type == HTTP)
214 return NULL;
215 return new SSLSocketParams(
216 new TransportSocketParams(
217 HostPortPair(kHttpsProxyHost, 443),
218 false,
219 false,
220 OnHostResolutionCallback(),
221 TransportSocketParams::COMBINE_CONNECT_AND_WRITE_DEFAULT),
222 NULL,
223 NULL,
224 HostPortPair(kHttpsProxyHost, 443),
225 SSLConfig(),
226 PRIVACY_MODE_DISABLED,
228 false);
231 // Returns the a correctly constructed HttpProxyParms
232 // for the HTTP or HTTPS proxy.
233 scoped_refptr<HttpProxySocketParams> CreateParams(
234 bool tunnel,
235 ProxyDelegate* proxy_delegate) {
236 return scoped_refptr<HttpProxySocketParams>(new HttpProxySocketParams(
237 CreateHttpProxyParams(),
238 CreateHttpsProxyParams(),
239 std::string(),
240 HostPortPair("www.google.com", tunnel ? 443 : 80),
241 session_->http_auth_cache(),
242 session_->http_auth_handler_factory(),
243 session_->spdy_session_pool(),
244 tunnel,
245 proxy_delegate));
248 scoped_refptr<HttpProxySocketParams> CreateTunnelParams(
249 ProxyDelegate* proxy_delegate) {
250 return CreateParams(true, proxy_delegate);
253 scoped_refptr<HttpProxySocketParams> CreateNoTunnelParams(
254 ProxyDelegate* proxy_delegate) {
255 return CreateParams(false, proxy_delegate);
258 DeterministicMockClientSocketFactory* socket_factory() {
259 return session_deps_.deterministic_socket_factory.get();
262 void Initialize(MockRead* reads, size_t reads_count,
263 MockWrite* writes, size_t writes_count,
264 MockRead* spdy_reads, size_t spdy_reads_count,
265 MockWrite* spdy_writes, size_t spdy_writes_count) {
266 if (GetParam().proxy_type == SPDY) {
267 data_.reset(new DeterministicSocketData(spdy_reads, spdy_reads_count,
268 spdy_writes, spdy_writes_count));
269 } else {
270 data_.reset(new DeterministicSocketData(reads, reads_count, writes,
271 writes_count));
274 data_->set_connect_data(MockConnect(SYNCHRONOUS, OK));
275 data_->StopAfter(2); // Request / Response
277 socket_factory()->AddSocketDataProvider(data_.get());
279 if (GetParam().proxy_type != HTTP) {
280 ssl_data_.reset(new SSLSocketDataProvider(SYNCHRONOUS, OK));
281 if (GetParam().proxy_type == SPDY) {
282 InitializeSpdySsl();
284 socket_factory()->AddSSLSocketDataProvider(ssl_data_.get());
288 void InitializeSpdySsl() {
289 ssl_data_->SetNextProto(GetParam().protocol);
292 HttpNetworkSession* CreateNetworkSession() {
293 return SpdySessionDependencies::SpdyCreateSessionDeterministic(
294 &session_deps_);
297 RequestPriority GetLastTransportRequestPriority() const {
298 return transport_socket_pool_.last_request_priority();
301 private:
302 SpdySessionDependencies session_deps_;
304 MockTransportClientSocketPool transport_socket_pool_;
305 MockHostResolver host_resolver_;
306 scoped_ptr<CertVerifier> cert_verifier_;
307 SSLClientSocketPool ssl_socket_pool_;
309 const scoped_refptr<HttpNetworkSession> session_;
311 protected:
312 SpdyTestUtil spdy_util_;
313 scoped_ptr<SSLSocketDataProvider> ssl_data_;
314 scoped_ptr<DeterministicSocketData> data_;
315 HttpProxyClientSocketPool pool_;
316 ClientSocketHandle handle_;
317 TestCompletionCallback callback_;
320 //-----------------------------------------------------------------------------
321 // All tests are run with three different proxy types: HTTP, HTTPS (non-SPDY)
322 // and SPDY.
324 // TODO(akalin): Use ::testing::Combine() when we are able to use
325 // <tr1/tuple>.
326 INSTANTIATE_TEST_CASE_P(
327 HttpProxyClientSocketPoolTests,
328 HttpProxyClientSocketPoolTest,
329 ::testing::Values(
330 HttpProxyClientSocketPoolTestParams(HTTP, kProtoSPDY31),
331 HttpProxyClientSocketPoolTestParams(HTTPS, kProtoSPDY31),
332 HttpProxyClientSocketPoolTestParams(SPDY, kProtoSPDY31),
333 HttpProxyClientSocketPoolTestParams(HTTP, kProtoSPDY4_14),
334 HttpProxyClientSocketPoolTestParams(HTTPS, kProtoSPDY4_14),
335 HttpProxyClientSocketPoolTestParams(SPDY, kProtoSPDY4_14),
336 HttpProxyClientSocketPoolTestParams(HTTP, kProtoSPDY4),
337 HttpProxyClientSocketPoolTestParams(HTTPS, kProtoSPDY4),
338 HttpProxyClientSocketPoolTestParams(SPDY, kProtoSPDY4)));
340 TEST_P(HttpProxyClientSocketPoolTest, NoTunnel) {
341 Initialize(NULL, 0, NULL, 0, NULL, 0, NULL, 0);
343 scoped_ptr<TestProxyDelegate> proxy_delegate(new TestProxyDelegate());
344 int rv = handle_.Init("a", CreateNoTunnelParams(proxy_delegate.get()), LOW,
345 CompletionCallback(), &pool_, BoundNetLog());
346 EXPECT_EQ(OK, rv);
347 EXPECT_TRUE(handle_.is_initialized());
348 ASSERT_TRUE(handle_.socket());
349 HttpProxyClientSocket* tunnel_socket =
350 static_cast<HttpProxyClientSocket*>(handle_.socket());
351 EXPECT_TRUE(tunnel_socket->IsConnected());
352 EXPECT_FALSE(proxy_delegate->on_before_tunnel_request_called());
353 EXPECT_FALSE(proxy_delegate->on_tunnel_headers_received_called());
354 EXPECT_TRUE(proxy_delegate->on_tunnel_request_completed_called());
357 // Make sure that HttpProxyConnectJob passes on its priority to its
358 // (non-SSL) socket request on Init.
359 TEST_P(HttpProxyClientSocketPoolTest, SetSocketRequestPriorityOnInit) {
360 Initialize(NULL, 0, NULL, 0, NULL, 0, NULL, 0);
361 EXPECT_EQ(OK,
362 handle_.Init("a", CreateNoTunnelParams(NULL), HIGHEST,
363 CompletionCallback(), &pool_, BoundNetLog()));
364 EXPECT_EQ(HIGHEST, GetLastTransportRequestPriority());
367 TEST_P(HttpProxyClientSocketPoolTest, NeedAuth) {
368 MockWrite writes[] = {
369 MockWrite(ASYNC, 0, "CONNECT www.google.com:443 HTTP/1.1\r\n"
370 "Host: www.google.com\r\n"
371 "Proxy-Connection: keep-alive\r\n\r\n"),
373 MockRead reads[] = {
374 // No credentials.
375 MockRead(ASYNC, 1, "HTTP/1.1 407 Proxy Authentication Required\r\n"),
376 MockRead(ASYNC, 2, "Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
377 MockRead(ASYNC, 3, "Content-Length: 10\r\n\r\n"),
378 MockRead(ASYNC, 4, "0123456789"),
380 scoped_ptr<SpdyFrame> req(spdy_util_.ConstructSpdyConnect(
381 NULL, 0, 1, LOW, HostPortPair("www.google.com", 443)));
382 scoped_ptr<SpdyFrame> rst(
383 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL));
384 MockWrite spdy_writes[] = {
385 CreateMockWrite(*req, 0, ASYNC),
386 CreateMockWrite(*rst, 2, ASYNC),
388 SpdyHeaderBlock resp_block;
389 resp_block[spdy_util_.GetStatusKey()] = "407";
390 resp_block["proxy-authenticate"] = "Basic realm=\"MyRealm1\"";
391 spdy_util_.MaybeAddVersionHeader(&resp_block);
393 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyReply(1, resp_block));
394 MockRead spdy_reads[] = {
395 CreateMockRead(*resp, 1, ASYNC),
396 MockRead(ASYNC, 0, 3)
399 Initialize(reads, arraysize(reads), writes, arraysize(writes),
400 spdy_reads, arraysize(spdy_reads), spdy_writes,
401 arraysize(spdy_writes));
403 data_->StopAfter(4);
404 int rv = handle_.Init("a", CreateTunnelParams(NULL), LOW,
405 callback_.callback(), &pool_, BoundNetLog());
406 EXPECT_EQ(ERR_IO_PENDING, rv);
407 EXPECT_FALSE(handle_.is_initialized());
408 EXPECT_FALSE(handle_.socket());
410 data_->RunFor(GetParam().proxy_type == SPDY ? 2 : 4);
411 rv = callback_.WaitForResult();
412 EXPECT_EQ(ERR_PROXY_AUTH_REQUESTED, rv);
413 EXPECT_TRUE(handle_.is_initialized());
414 ASSERT_TRUE(handle_.socket());
415 ProxyClientSocket* tunnel_socket =
416 static_cast<ProxyClientSocket*>(handle_.socket());
417 if (GetParam().proxy_type == SPDY) {
418 EXPECT_TRUE(tunnel_socket->IsConnected());
419 EXPECT_TRUE(tunnel_socket->IsUsingSpdy());
420 } else {
421 EXPECT_FALSE(tunnel_socket->IsConnected());
422 EXPECT_FALSE(tunnel_socket->IsUsingSpdy());
426 TEST_P(HttpProxyClientSocketPoolTest, HaveAuth) {
427 // It's pretty much impossible to make the SPDY case behave synchronously
428 // so we skip this test for SPDY
429 if (GetParam().proxy_type == SPDY)
430 return;
431 std::string proxy_host_port =
432 GetParam().proxy_type == HTTP ?
433 (kHttpProxyHost + std::string(":80")) :
434 (kHttpsProxyHost + std::string(":443"));
435 std::string request =
436 "CONNECT www.google.com:443 HTTP/1.1\r\n"
437 "Host: www.google.com\r\n"
438 "Proxy-Connection: keep-alive\r\n"
439 "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n"
440 "Foo: " + proxy_host_port + "\r\n\r\n";
441 MockWrite writes[] = {
442 MockWrite(SYNCHRONOUS, 0, request.c_str()),
444 MockRead reads[] = {
445 MockRead(SYNCHRONOUS, 1, "HTTP/1.1 200 Connection Established\r\n\r\n"),
448 Initialize(reads, arraysize(reads), writes, arraysize(writes), NULL, 0,
449 NULL, 0);
450 AddAuthToCache();
452 scoped_ptr<TestProxyDelegate> proxy_delegate(new TestProxyDelegate());
453 int rv = handle_.Init("a", CreateTunnelParams(proxy_delegate.get()), LOW,
454 callback_.callback(), &pool_, BoundNetLog());
455 EXPECT_EQ(OK, rv);
456 EXPECT_TRUE(handle_.is_initialized());
457 ASSERT_TRUE(handle_.socket());
458 HttpProxyClientSocket* tunnel_socket =
459 static_cast<HttpProxyClientSocket*>(handle_.socket());
460 EXPECT_TRUE(tunnel_socket->IsConnected());
461 proxy_delegate->VerifyOnTunnelHeadersReceived(
462 "www.google.com:443",
463 proxy_host_port.c_str(),
464 "HTTP/1.1 200 Connection Established");
465 proxy_delegate->VerifyOnTunnelRequestCompleted(
466 "www.google.com:443",
467 proxy_host_port.c_str());
470 TEST_P(HttpProxyClientSocketPoolTest, AsyncHaveAuth) {
471 std::string proxy_host_port =
472 GetParam().proxy_type == HTTP ?
473 (kHttpProxyHost + std::string(":80")) :
474 (kHttpsProxyHost + std::string(":443"));
475 std::string request =
476 "CONNECT www.google.com:443 HTTP/1.1\r\n"
477 "Host: www.google.com\r\n"
478 "Proxy-Connection: keep-alive\r\n"
479 "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n"
480 "Foo: " + proxy_host_port + "\r\n\r\n";
481 MockWrite writes[] = {
482 MockWrite(ASYNC, 0, request.c_str()),
484 MockRead reads[] = {
485 MockRead(ASYNC, 1, "HTTP/1.1 200 Connection Established\r\n\r\n"),
488 scoped_ptr<SpdyFrame> req(
489 spdy_util_.ConstructSpdyConnect(kAuthHeaders, kAuthHeadersSize, 1, LOW,
490 HostPortPair("www.google.com", 443)));
491 MockWrite spdy_writes[] = {
492 CreateMockWrite(*req, 0, ASYNC)
494 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
495 MockRead spdy_reads[] = {
496 CreateMockRead(*resp, 1, ASYNC),
497 MockRead(ASYNC, 0, 2)
500 Initialize(reads, arraysize(reads), writes, arraysize(writes),
501 spdy_reads, arraysize(spdy_reads), spdy_writes,
502 arraysize(spdy_writes));
503 AddAuthToCache();
505 scoped_ptr<TestProxyDelegate> proxy_delegate(new TestProxyDelegate());
506 int rv = handle_.Init("a", CreateTunnelParams(proxy_delegate.get()), LOW,
507 callback_.callback(), &pool_, BoundNetLog());
508 EXPECT_EQ(ERR_IO_PENDING, rv);
509 EXPECT_FALSE(handle_.is_initialized());
510 EXPECT_FALSE(handle_.socket());
512 data_->RunFor(2);
513 EXPECT_EQ(OK, callback_.WaitForResult());
514 EXPECT_TRUE(handle_.is_initialized());
515 ASSERT_TRUE(handle_.socket());
516 EXPECT_TRUE(handle_.socket()->IsConnected());
517 proxy_delegate->VerifyOnTunnelRequestCompleted(
518 "www.google.com:443",
519 proxy_host_port.c_str());
522 // Make sure that HttpProxyConnectJob passes on its priority to its
523 // SPDY session's socket request on Init (if applicable).
524 TEST_P(HttpProxyClientSocketPoolTest,
525 SetSpdySessionSocketRequestPriorityOnInit) {
526 if (GetParam().proxy_type != SPDY)
527 return;
529 scoped_ptr<SpdyFrame> req(
530 spdy_util_.ConstructSpdyConnect(kAuthHeaders, kAuthHeadersSize, 1, MEDIUM,
531 HostPortPair("www.google.com", 443)));
532 MockWrite spdy_writes[] = {
533 CreateMockWrite(*req, 0, ASYNC)
535 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
536 MockRead spdy_reads[] = {
537 CreateMockRead(*resp, 1, ASYNC),
538 MockRead(ASYNC, 0, 2)
541 Initialize(NULL, 0, NULL, 0,
542 spdy_reads, arraysize(spdy_reads),
543 spdy_writes, arraysize(spdy_writes));
544 AddAuthToCache();
546 EXPECT_EQ(ERR_IO_PENDING,
547 handle_.Init("a", CreateTunnelParams(NULL), MEDIUM,
548 callback_.callback(), &pool_, BoundNetLog()));
549 EXPECT_EQ(MEDIUM, GetLastTransportRequestPriority());
551 data_->RunFor(2);
552 EXPECT_EQ(OK, callback_.WaitForResult());
555 TEST_P(HttpProxyClientSocketPoolTest, TCPError) {
556 if (GetParam().proxy_type == SPDY) return;
557 data_.reset(new DeterministicSocketData(NULL, 0, NULL, 0));
558 data_->set_connect_data(MockConnect(ASYNC, ERR_CONNECTION_CLOSED));
560 socket_factory()->AddSocketDataProvider(data_.get());
562 int rv = handle_.Init("a", CreateTunnelParams(NULL), LOW,
563 callback_.callback(), &pool_, BoundNetLog());
564 EXPECT_EQ(ERR_IO_PENDING, rv);
565 EXPECT_FALSE(handle_.is_initialized());
566 EXPECT_FALSE(handle_.socket());
568 EXPECT_EQ(ERR_PROXY_CONNECTION_FAILED, callback_.WaitForResult());
570 EXPECT_FALSE(handle_.is_initialized());
571 EXPECT_FALSE(handle_.socket());
574 TEST_P(HttpProxyClientSocketPoolTest, SSLError) {
575 if (GetParam().proxy_type == HTTP) return;
576 data_.reset(new DeterministicSocketData(NULL, 0, NULL, 0));
577 data_->set_connect_data(MockConnect(ASYNC, OK));
578 socket_factory()->AddSocketDataProvider(data_.get());
580 ssl_data_.reset(new SSLSocketDataProvider(ASYNC,
581 ERR_CERT_AUTHORITY_INVALID));
582 if (GetParam().proxy_type == SPDY) {
583 InitializeSpdySsl();
585 socket_factory()->AddSSLSocketDataProvider(ssl_data_.get());
587 int rv = handle_.Init("a", CreateTunnelParams(NULL), LOW,
588 callback_.callback(), &pool_, BoundNetLog());
589 EXPECT_EQ(ERR_IO_PENDING, rv);
590 EXPECT_FALSE(handle_.is_initialized());
591 EXPECT_FALSE(handle_.socket());
593 EXPECT_EQ(ERR_PROXY_CERTIFICATE_INVALID, callback_.WaitForResult());
595 EXPECT_FALSE(handle_.is_initialized());
596 EXPECT_FALSE(handle_.socket());
599 TEST_P(HttpProxyClientSocketPoolTest, SslClientAuth) {
600 if (GetParam().proxy_type == HTTP) return;
601 data_.reset(new DeterministicSocketData(NULL, 0, NULL, 0));
602 data_->set_connect_data(MockConnect(ASYNC, OK));
603 socket_factory()->AddSocketDataProvider(data_.get());
605 ssl_data_.reset(new SSLSocketDataProvider(ASYNC,
606 ERR_SSL_CLIENT_AUTH_CERT_NEEDED));
607 if (GetParam().proxy_type == SPDY) {
608 InitializeSpdySsl();
610 socket_factory()->AddSSLSocketDataProvider(ssl_data_.get());
612 int rv = handle_.Init("a", CreateTunnelParams(NULL), LOW,
613 callback_.callback(), &pool_, BoundNetLog());
614 EXPECT_EQ(ERR_IO_PENDING, rv);
615 EXPECT_FALSE(handle_.is_initialized());
616 EXPECT_FALSE(handle_.socket());
618 EXPECT_EQ(ERR_SSL_CLIENT_AUTH_CERT_NEEDED, callback_.WaitForResult());
620 EXPECT_FALSE(handle_.is_initialized());
621 EXPECT_FALSE(handle_.socket());
624 TEST_P(HttpProxyClientSocketPoolTest, TunnelUnexpectedClose) {
625 MockWrite writes[] = {
626 MockWrite(ASYNC, 0,
627 "CONNECT www.google.com:443 HTTP/1.1\r\n"
628 "Host: www.google.com\r\n"
629 "Proxy-Connection: keep-alive\r\n"
630 "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
632 MockRead reads[] = {
633 MockRead(ASYNC, 1, "HTTP/1.1 200 Conn"),
634 MockRead(ASYNC, ERR_CONNECTION_CLOSED, 2),
636 scoped_ptr<SpdyFrame> req(
637 spdy_util_.ConstructSpdyConnect(kAuthHeaders, kAuthHeadersSize, 1, LOW,
638 HostPortPair("www.google.com", 443)));
639 MockWrite spdy_writes[] = {
640 CreateMockWrite(*req, 0, ASYNC)
642 MockRead spdy_reads[] = {
643 MockRead(ASYNC, ERR_CONNECTION_CLOSED, 1),
646 Initialize(reads, arraysize(reads), writes, arraysize(writes),
647 spdy_reads, arraysize(spdy_reads), spdy_writes,
648 arraysize(spdy_writes));
649 AddAuthToCache();
651 int rv = handle_.Init("a", CreateTunnelParams(NULL), LOW,
652 callback_.callback(), &pool_, BoundNetLog());
653 EXPECT_EQ(ERR_IO_PENDING, rv);
654 EXPECT_FALSE(handle_.is_initialized());
655 EXPECT_FALSE(handle_.socket());
657 data_->RunFor(3);
658 if (GetParam().proxy_type == SPDY) {
659 // SPDY cannot process a headers block unless it's complete and so it
660 // returns ERR_CONNECTION_CLOSED in this case.
661 EXPECT_EQ(ERR_CONNECTION_CLOSED, callback_.WaitForResult());
662 } else {
663 EXPECT_EQ(ERR_RESPONSE_HEADERS_TRUNCATED, callback_.WaitForResult());
665 EXPECT_FALSE(handle_.is_initialized());
666 EXPECT_FALSE(handle_.socket());
669 TEST_P(HttpProxyClientSocketPoolTest, Tunnel1xxResponse) {
670 // Tests that 1xx responses are rejected for a CONNECT request.
671 if (GetParam().proxy_type == SPDY) {
672 // SPDY doesn't have 1xx responses.
673 return;
676 MockWrite writes[] = {
677 MockWrite(ASYNC, 0,
678 "CONNECT www.google.com:443 HTTP/1.1\r\n"
679 "Host: www.google.com\r\n"
680 "Proxy-Connection: keep-alive\r\n\r\n"),
682 MockRead reads[] = {
683 MockRead(ASYNC, 1, "HTTP/1.1 100 Continue\r\n\r\n"),
684 MockRead(ASYNC, 2, "HTTP/1.1 200 Connection Established\r\n\r\n"),
687 Initialize(reads, arraysize(reads), writes, arraysize(writes),
688 NULL, 0, NULL, 0);
690 int rv = handle_.Init("a", CreateTunnelParams(NULL), LOW,
691 callback_.callback(), &pool_, BoundNetLog());
692 EXPECT_EQ(ERR_IO_PENDING, rv);
693 EXPECT_FALSE(handle_.is_initialized());
694 EXPECT_FALSE(handle_.socket());
696 data_->RunFor(2);
697 EXPECT_EQ(ERR_TUNNEL_CONNECTION_FAILED, callback_.WaitForResult());
700 TEST_P(HttpProxyClientSocketPoolTest, TunnelSetupError) {
701 MockWrite writes[] = {
702 MockWrite(ASYNC, 0,
703 "CONNECT www.google.com:443 HTTP/1.1\r\n"
704 "Host: www.google.com\r\n"
705 "Proxy-Connection: keep-alive\r\n"
706 "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
708 MockRead reads[] = {
709 MockRead(ASYNC, 1, "HTTP/1.1 304 Not Modified\r\n\r\n"),
711 scoped_ptr<SpdyFrame> req(
712 spdy_util_.ConstructSpdyConnect(kAuthHeaders, kAuthHeadersSize, 1, LOW,
713 HostPortPair("www.google.com", 443)));
714 scoped_ptr<SpdyFrame> rst(
715 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL));
716 MockWrite spdy_writes[] = {
717 CreateMockWrite(*req, 0, ASYNC),
718 CreateMockWrite(*rst, 2, ASYNC),
720 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdySynReplyError(1));
721 MockRead spdy_reads[] = {
722 CreateMockRead(*resp, 1, ASYNC),
723 MockRead(ASYNC, 0, 3),
726 Initialize(reads, arraysize(reads), writes, arraysize(writes),
727 spdy_reads, arraysize(spdy_reads), spdy_writes,
728 arraysize(spdy_writes));
729 AddAuthToCache();
731 int rv = handle_.Init("a", CreateTunnelParams(NULL), LOW,
732 callback_.callback(), &pool_, BoundNetLog());
733 EXPECT_EQ(ERR_IO_PENDING, rv);
734 EXPECT_FALSE(handle_.is_initialized());
735 EXPECT_FALSE(handle_.socket());
737 data_->RunFor(2);
739 rv = callback_.WaitForResult();
740 // All Proxy CONNECT responses are not trustworthy
741 EXPECT_EQ(ERR_TUNNEL_CONNECTION_FAILED, rv);
742 EXPECT_FALSE(handle_.is_initialized());
743 EXPECT_FALSE(handle_.socket());
746 TEST_P(HttpProxyClientSocketPoolTest, TunnelSetupRedirect) {
747 const std::string redirectTarget = "https://foo.google.com/";
749 const std::string responseText = "HTTP/1.1 302 Found\r\n"
750 "Location: " + redirectTarget + "\r\n"
751 "Set-Cookie: foo=bar\r\n"
752 "\r\n";
753 MockWrite writes[] = {
754 MockWrite(ASYNC, 0,
755 "CONNECT www.google.com:443 HTTP/1.1\r\n"
756 "Host: www.google.com\r\n"
757 "Proxy-Connection: keep-alive\r\n"
758 "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
760 MockRead reads[] = {
761 MockRead(ASYNC, 1, responseText.c_str()),
763 scoped_ptr<SpdyFrame> req(
764 spdy_util_.ConstructSpdyConnect(kAuthHeaders, kAuthHeadersSize, 1, LOW,
765 HostPortPair("www.google.com", 443)));
766 scoped_ptr<SpdyFrame> rst(
767 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL));
769 MockWrite spdy_writes[] = {
770 CreateMockWrite(*req, 0, ASYNC),
771 CreateMockWrite(*rst, 3, ASYNC),
774 const char* const responseHeaders[] = {
775 "location", redirectTarget.c_str(),
776 "set-cookie", "foo=bar",
778 const int responseHeadersSize = arraysize(responseHeaders) / 2;
779 scoped_ptr<SpdyFrame> resp(
780 spdy_util_.ConstructSpdySynReplyError(
781 "302 Found",
782 responseHeaders, responseHeadersSize,
783 1));
784 MockRead spdy_reads[] = {
785 CreateMockRead(*resp, 1, ASYNC),
786 MockRead(ASYNC, 0, 2),
789 Initialize(reads, arraysize(reads), writes, arraysize(writes),
790 spdy_reads, arraysize(spdy_reads), spdy_writes,
791 arraysize(spdy_writes));
792 AddAuthToCache();
794 int rv = handle_.Init("a", CreateTunnelParams(NULL), LOW,
795 callback_.callback(), &pool_, BoundNetLog());
796 EXPECT_EQ(ERR_IO_PENDING, rv);
797 EXPECT_FALSE(handle_.is_initialized());
798 EXPECT_FALSE(handle_.socket());
800 data_->RunFor(2);
802 rv = callback_.WaitForResult();
804 if (GetParam().proxy_type == HTTP) {
805 // We don't trust 302 responses to CONNECT from HTTP proxies.
806 EXPECT_EQ(ERR_TUNNEL_CONNECTION_FAILED, rv);
807 EXPECT_FALSE(handle_.is_initialized());
808 EXPECT_FALSE(handle_.socket());
809 } else {
810 // Expect ProxyClientSocket to return the proxy's response, sanitized.
811 EXPECT_EQ(ERR_HTTPS_PROXY_TUNNEL_RESPONSE, rv);
812 EXPECT_TRUE(handle_.is_initialized());
813 ASSERT_TRUE(handle_.socket());
815 const ProxyClientSocket* tunnel_socket =
816 static_cast<ProxyClientSocket*>(handle_.socket());
817 const HttpResponseInfo* response = tunnel_socket->GetConnectResponseInfo();
818 const HttpResponseHeaders* headers = response->headers.get();
820 // Make sure Set-Cookie header was stripped.
821 EXPECT_FALSE(headers->HasHeader("set-cookie"));
823 // Make sure Content-Length: 0 header was added.
824 EXPECT_TRUE(headers->HasHeaderValue("content-length", "0"));
826 // Make sure Location header was included and correct.
827 std::string location;
828 EXPECT_TRUE(headers->IsRedirect(&location));
829 EXPECT_EQ(location, redirectTarget);
833 // It would be nice to also test the timeouts in HttpProxyClientSocketPool.
835 } // namespace
837 } // namespace net