Rewrite AndroidSyncSettings to be significantly simpler.
[chromium-blink-merge.git] / net / http / http_proxy_client_socket_pool_unittest.cc
blobf80ef3df36920e691d1fa5d94c1d8e0d250dbede
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "net/http/http_proxy_client_socket_pool.h"
7 #include "base/callback.h"
8 #include "base/compiler_specific.h"
9 #include "base/strings/string_util.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "net/base/net_errors.h"
12 #include "net/base/proxy_delegate.h"
13 #include "net/base/test_completion_callback.h"
14 #include "net/http/http_network_session.h"
15 #include "net/http/http_proxy_client_socket.h"
16 #include "net/http/http_response_headers.h"
17 #include "net/socket/client_socket_handle.h"
18 #include "net/socket/client_socket_pool_histograms.h"
19 #include "net/socket/next_proto.h"
20 #include "net/socket/socket_test_util.h"
21 #include "net/spdy/spdy_protocol.h"
22 #include "net/spdy/spdy_test_util_common.h"
23 #include "testing/gtest/include/gtest/gtest.h"
25 namespace net {
27 namespace {
29 const int kMaxSockets = 32;
30 const int kMaxSocketsPerGroup = 6;
31 const char * const kAuthHeaders[] = {
32 "proxy-authorization", "Basic Zm9vOmJhcg=="
34 const int kAuthHeadersSize = arraysize(kAuthHeaders) / 2;
36 enum HttpProxyType {
37 HTTP,
38 HTTPS,
39 SPDY
42 struct HttpProxyClientSocketPoolTestParams {
43 HttpProxyClientSocketPoolTestParams()
44 : proxy_type(HTTP),
45 protocol(kProtoSPDY31) {}
47 HttpProxyClientSocketPoolTestParams(
48 HttpProxyType proxy_type,
49 NextProto protocol)
50 : proxy_type(proxy_type),
51 protocol(protocol) {}
53 HttpProxyType proxy_type;
54 NextProto protocol;
57 typedef ::testing::TestWithParam<HttpProxyType> TestWithHttpParam;
59 const char kHttpProxyHost[] = "httpproxy.example.com";
60 const char kHttpsProxyHost[] = "httpsproxy.example.com";
62 class TestProxyDelegate : public ProxyDelegate {
63 public:
64 TestProxyDelegate()
65 : on_before_tunnel_request_called_(false),
66 on_tunnel_request_completed_called_(false),
67 on_tunnel_headers_received_called_(false) {
70 ~TestProxyDelegate() override {}
72 bool on_before_tunnel_request_called() const {
73 return on_before_tunnel_request_called_;
76 bool on_tunnel_request_completed_called() const {
77 return on_tunnel_request_completed_called_;
80 bool on_tunnel_headers_received_called() const {
81 return on_tunnel_headers_received_called_;
84 void VerifyOnTunnelRequestCompleted(const std::string& endpoint,
85 const std::string& proxy_server) const {
86 EXPECT_TRUE(on_tunnel_request_completed_called_);
87 EXPECT_TRUE(HostPortPair::FromString(endpoint).Equals(
88 on_tunnel_request_completed_endpoint_));
89 EXPECT_TRUE(HostPortPair::FromString(proxy_server).Equals(
90 on_tunnel_request_completed_proxy_server_));
93 void VerifyOnTunnelHeadersReceived(const std::string& origin,
94 const std::string& proxy_server,
95 const std::string& status_line) const {
96 EXPECT_TRUE(on_tunnel_headers_received_called_);
97 EXPECT_TRUE(HostPortPair::FromString(origin).Equals(
98 on_tunnel_headers_received_origin_));
99 EXPECT_TRUE(HostPortPair::FromString(proxy_server).Equals(
100 on_tunnel_headers_received_proxy_server_));
101 EXPECT_EQ(status_line, on_tunnel_headers_received_status_line_);
104 // ProxyDelegate:
105 void OnResolveProxy(const GURL& url,
106 int load_flags,
107 const ProxyService& proxy_service,
108 ProxyInfo* result) override {}
110 void OnTunnelConnectCompleted(const HostPortPair& endpoint,
111 const HostPortPair& proxy_server,
112 int net_error) override {
113 on_tunnel_request_completed_called_ = true;
114 on_tunnel_request_completed_endpoint_ = endpoint;
115 on_tunnel_request_completed_proxy_server_ = proxy_server;
118 void OnFallback(const ProxyServer& bad_proxy, int net_error) override {}
120 void OnBeforeSendHeaders(URLRequest* request,
121 const ProxyInfo& proxy_info,
122 HttpRequestHeaders* headers) override {}
124 void OnBeforeTunnelRequest(const net::HostPortPair& proxy_server,
125 net::HttpRequestHeaders* extra_headers) override {
126 on_before_tunnel_request_called_ = true;
127 if (extra_headers) {
128 extra_headers->SetHeader("Foo", proxy_server.ToString());
132 void OnTunnelHeadersReceived(
133 const net::HostPortPair& origin,
134 const net::HostPortPair& proxy_server,
135 const net::HttpResponseHeaders& response_headers) override {
136 on_tunnel_headers_received_called_ = true;
137 on_tunnel_headers_received_origin_ = origin;
138 on_tunnel_headers_received_proxy_server_ = proxy_server;
139 on_tunnel_headers_received_status_line_ = response_headers.GetStatusLine();
142 private:
143 bool on_before_tunnel_request_called_;
144 bool on_tunnel_request_completed_called_;
145 bool on_tunnel_headers_received_called_;
146 HostPortPair on_tunnel_request_completed_endpoint_;
147 HostPortPair on_tunnel_request_completed_proxy_server_;
148 HostPortPair on_tunnel_headers_received_origin_;
149 HostPortPair on_tunnel_headers_received_proxy_server_;
150 std::string on_tunnel_headers_received_status_line_;
154 class HttpProxyClientSocketPoolTest
155 : public ::testing::TestWithParam<HttpProxyClientSocketPoolTestParams> {
156 protected:
157 HttpProxyClientSocketPoolTest()
158 : session_deps_(GetParam().protocol),
159 tcp_histograms_("MockTCP"),
160 transport_socket_pool_(
161 kMaxSockets,
162 kMaxSocketsPerGroup,
163 &tcp_histograms_,
164 session_deps_.deterministic_socket_factory.get()),
165 ssl_histograms_("MockSSL"),
166 ssl_socket_pool_(kMaxSockets,
167 kMaxSocketsPerGroup,
168 &ssl_histograms_,
169 session_deps_.cert_verifier.get(),
170 NULL /* channel_id_store */,
171 NULL /* transport_security_state */,
172 NULL /* cert_transparency_verifier */,
173 NULL /* cert_policy_enforcer */,
174 std::string() /* ssl_session_cache_shard */,
175 session_deps_.deterministic_socket_factory.get(),
176 &transport_socket_pool_,
177 NULL,
178 NULL,
179 session_deps_.ssl_config_service.get(),
180 false,
181 BoundNetLog().net_log()),
182 session_(CreateNetworkSession()),
183 http_proxy_histograms_("HttpProxyUnitTest"),
184 spdy_util_(GetParam().protocol),
185 pool_(kMaxSockets,
186 kMaxSocketsPerGroup,
187 &http_proxy_histograms_,
188 &transport_socket_pool_,
189 &ssl_socket_pool_,
190 NULL) {}
192 virtual ~HttpProxyClientSocketPoolTest() {
195 void AddAuthToCache() {
196 const base::string16 kFoo(base::ASCIIToUTF16("foo"));
197 const base::string16 kBar(base::ASCIIToUTF16("bar"));
198 GURL proxy_url(GetParam().proxy_type == HTTP ?
199 (std::string("http://") + kHttpProxyHost) :
200 (std::string("https://") + kHttpsProxyHost));
201 session_->http_auth_cache()->Add(proxy_url,
202 "MyRealm1",
203 HttpAuth::AUTH_SCHEME_BASIC,
204 "Basic realm=MyRealm1",
205 AuthCredentials(kFoo, kBar),
206 "/");
209 scoped_refptr<TransportSocketParams> CreateHttpProxyParams() const {
210 if (GetParam().proxy_type != HTTP)
211 return NULL;
212 return new TransportSocketParams(
213 HostPortPair(kHttpProxyHost, 80),
214 false,
215 false,
216 OnHostResolutionCallback(),
217 TransportSocketParams::COMBINE_CONNECT_AND_WRITE_DEFAULT);
220 scoped_refptr<SSLSocketParams> CreateHttpsProxyParams() const {
221 if (GetParam().proxy_type == HTTP)
222 return NULL;
223 return new SSLSocketParams(
224 new TransportSocketParams(
225 HostPortPair(kHttpsProxyHost, 443),
226 false,
227 false,
228 OnHostResolutionCallback(),
229 TransportSocketParams::COMBINE_CONNECT_AND_WRITE_DEFAULT),
230 NULL,
231 NULL,
232 HostPortPair(kHttpsProxyHost, 443),
233 SSLConfig(),
234 PRIVACY_MODE_DISABLED,
236 false,
237 false);
240 // Returns the a correctly constructed HttpProxyParms
241 // for the HTTP or HTTPS proxy.
242 scoped_refptr<HttpProxySocketParams> CreateParams(
243 bool tunnel,
244 ProxyDelegate* proxy_delegate) {
245 return scoped_refptr<HttpProxySocketParams>(new HttpProxySocketParams(
246 CreateHttpProxyParams(),
247 CreateHttpsProxyParams(),
248 GURL(tunnel ? "https://www.google.com/" : "http://www.google.com"),
249 std::string(),
250 HostPortPair("www.google.com", tunnel ? 443 : 80),
251 session_->http_auth_cache(),
252 session_->http_auth_handler_factory(),
253 session_->spdy_session_pool(),
254 tunnel,
255 proxy_delegate));
258 scoped_refptr<HttpProxySocketParams> CreateTunnelParams(
259 ProxyDelegate* proxy_delegate) {
260 return CreateParams(true, proxy_delegate);
263 scoped_refptr<HttpProxySocketParams> CreateNoTunnelParams(
264 ProxyDelegate* proxy_delegate) {
265 return CreateParams(false, proxy_delegate);
268 DeterministicMockClientSocketFactory* socket_factory() {
269 return session_deps_.deterministic_socket_factory.get();
272 void Initialize(MockRead* reads, size_t reads_count,
273 MockWrite* writes, size_t writes_count,
274 MockRead* spdy_reads, size_t spdy_reads_count,
275 MockWrite* spdy_writes, size_t spdy_writes_count) {
276 if (GetParam().proxy_type == SPDY) {
277 data_.reset(new DeterministicSocketData(spdy_reads, spdy_reads_count,
278 spdy_writes, spdy_writes_count));
279 } else {
280 data_.reset(new DeterministicSocketData(reads, reads_count, writes,
281 writes_count));
284 data_->set_connect_data(MockConnect(SYNCHRONOUS, OK));
285 data_->StopAfter(2); // Request / Response
287 socket_factory()->AddSocketDataProvider(data_.get());
289 if (GetParam().proxy_type != HTTP) {
290 ssl_data_.reset(new SSLSocketDataProvider(SYNCHRONOUS, OK));
291 if (GetParam().proxy_type == SPDY) {
292 InitializeSpdySsl();
294 socket_factory()->AddSSLSocketDataProvider(ssl_data_.get());
298 void InitializeSpdySsl() {
299 ssl_data_->SetNextProto(GetParam().protocol);
302 HttpNetworkSession* CreateNetworkSession() {
303 return SpdySessionDependencies::SpdyCreateSessionDeterministic(
304 &session_deps_);
307 RequestPriority GetLastTransportRequestPriority() const {
308 return transport_socket_pool_.last_request_priority();
311 private:
312 SpdySessionDependencies session_deps_;
314 ClientSocketPoolHistograms tcp_histograms_;
315 MockTransportClientSocketPool transport_socket_pool_;
316 ClientSocketPoolHistograms ssl_histograms_;
317 MockHostResolver host_resolver_;
318 scoped_ptr<CertVerifier> cert_verifier_;
319 SSLClientSocketPool ssl_socket_pool_;
321 const scoped_refptr<HttpNetworkSession> session_;
322 ClientSocketPoolHistograms http_proxy_histograms_;
324 protected:
325 SpdyTestUtil spdy_util_;
326 scoped_ptr<SSLSocketDataProvider> ssl_data_;
327 scoped_ptr<DeterministicSocketData> data_;
328 HttpProxyClientSocketPool pool_;
329 ClientSocketHandle handle_;
330 TestCompletionCallback callback_;
333 //-----------------------------------------------------------------------------
334 // All tests are run with three different proxy types: HTTP, HTTPS (non-SPDY)
335 // and SPDY.
337 // TODO(akalin): Use ::testing::Combine() when we are able to use
338 // <tr1/tuple>.
339 INSTANTIATE_TEST_CASE_P(
340 HttpProxyClientSocketPoolTests,
341 HttpProxyClientSocketPoolTest,
342 ::testing::Values(
343 HttpProxyClientSocketPoolTestParams(HTTP, kProtoSPDY31),
344 HttpProxyClientSocketPoolTestParams(HTTPS, kProtoSPDY31),
345 HttpProxyClientSocketPoolTestParams(SPDY, kProtoSPDY31),
346 HttpProxyClientSocketPoolTestParams(HTTP, kProtoSPDY4_14),
347 HttpProxyClientSocketPoolTestParams(HTTPS, kProtoSPDY4_14),
348 HttpProxyClientSocketPoolTestParams(SPDY, kProtoSPDY4_14),
349 HttpProxyClientSocketPoolTestParams(HTTP, kProtoSPDY4_15),
350 HttpProxyClientSocketPoolTestParams(HTTPS, kProtoSPDY4_15),
351 HttpProxyClientSocketPoolTestParams(SPDY, kProtoSPDY4_15)));
353 TEST_P(HttpProxyClientSocketPoolTest, NoTunnel) {
354 Initialize(NULL, 0, NULL, 0, NULL, 0, NULL, 0);
356 scoped_ptr<TestProxyDelegate> proxy_delegate(new TestProxyDelegate());
357 int rv = handle_.Init("a", CreateNoTunnelParams(proxy_delegate.get()), LOW,
358 CompletionCallback(), &pool_, BoundNetLog());
359 EXPECT_EQ(OK, rv);
360 EXPECT_TRUE(handle_.is_initialized());
361 ASSERT_TRUE(handle_.socket());
362 HttpProxyClientSocket* tunnel_socket =
363 static_cast<HttpProxyClientSocket*>(handle_.socket());
364 EXPECT_TRUE(tunnel_socket->IsConnected());
365 EXPECT_FALSE(proxy_delegate->on_before_tunnel_request_called());
366 EXPECT_FALSE(proxy_delegate->on_tunnel_headers_received_called());
367 EXPECT_TRUE(proxy_delegate->on_tunnel_request_completed_called());
370 // Make sure that HttpProxyConnectJob passes on its priority to its
371 // (non-SSL) socket request on Init.
372 TEST_P(HttpProxyClientSocketPoolTest, SetSocketRequestPriorityOnInit) {
373 Initialize(NULL, 0, NULL, 0, NULL, 0, NULL, 0);
374 EXPECT_EQ(OK,
375 handle_.Init("a", CreateNoTunnelParams(NULL), HIGHEST,
376 CompletionCallback(), &pool_, BoundNetLog()));
377 EXPECT_EQ(HIGHEST, GetLastTransportRequestPriority());
380 TEST_P(HttpProxyClientSocketPoolTest, NeedAuth) {
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\r\n"),
386 MockRead reads[] = {
387 // No credentials.
388 MockRead(ASYNC, 1, "HTTP/1.1 407 Proxy Authentication Required\r\n"),
389 MockRead(ASYNC, 2, "Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
390 MockRead(ASYNC, 3, "Content-Length: 10\r\n\r\n"),
391 MockRead(ASYNC, 4, "0123456789"),
393 scoped_ptr<SpdyFrame> req(spdy_util_.ConstructSpdyConnect(
394 NULL, 0, 1, LOW, HostPortPair("www.google.com", 443)));
395 scoped_ptr<SpdyFrame> rst(
396 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL));
397 MockWrite spdy_writes[] = {
398 CreateMockWrite(*req, 0, ASYNC),
399 CreateMockWrite(*rst, 2, ASYNC),
401 SpdyHeaderBlock resp_block;
402 resp_block[spdy_util_.GetStatusKey()] = "407";
403 resp_block["proxy-authenticate"] = "Basic realm=\"MyRealm1\"";
404 spdy_util_.MaybeAddVersionHeader(&resp_block);
406 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyReply(1, resp_block));
407 MockRead spdy_reads[] = {
408 CreateMockRead(*resp, 1, ASYNC),
409 MockRead(ASYNC, 0, 3)
412 Initialize(reads, arraysize(reads), writes, arraysize(writes),
413 spdy_reads, arraysize(spdy_reads), spdy_writes,
414 arraysize(spdy_writes));
416 data_->StopAfter(4);
417 int rv = handle_.Init("a", CreateTunnelParams(NULL), LOW,
418 callback_.callback(), &pool_, BoundNetLog());
419 EXPECT_EQ(ERR_IO_PENDING, rv);
420 EXPECT_FALSE(handle_.is_initialized());
421 EXPECT_FALSE(handle_.socket());
423 data_->RunFor(GetParam().proxy_type == SPDY ? 2 : 4);
424 rv = callback_.WaitForResult();
425 EXPECT_EQ(ERR_PROXY_AUTH_REQUESTED, rv);
426 EXPECT_TRUE(handle_.is_initialized());
427 ASSERT_TRUE(handle_.socket());
428 ProxyClientSocket* tunnel_socket =
429 static_cast<ProxyClientSocket*>(handle_.socket());
430 if (GetParam().proxy_type == SPDY) {
431 EXPECT_TRUE(tunnel_socket->IsConnected());
432 EXPECT_TRUE(tunnel_socket->IsUsingSpdy());
433 } else {
434 EXPECT_FALSE(tunnel_socket->IsConnected());
435 EXPECT_FALSE(tunnel_socket->IsUsingSpdy());
439 TEST_P(HttpProxyClientSocketPoolTest, HaveAuth) {
440 // It's pretty much impossible to make the SPDY case behave synchronously
441 // so we skip this test for SPDY
442 if (GetParam().proxy_type == SPDY)
443 return;
444 std::string proxy_host_port =
445 GetParam().proxy_type == HTTP ?
446 (kHttpProxyHost + std::string(":80")) :
447 (kHttpsProxyHost + std::string(":443"));
448 std::string request =
449 "CONNECT www.google.com:443 HTTP/1.1\r\n"
450 "Host: www.google.com\r\n"
451 "Proxy-Connection: keep-alive\r\n"
452 "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n"
453 "Foo: " + proxy_host_port + "\r\n\r\n";
454 MockWrite writes[] = {
455 MockWrite(SYNCHRONOUS, 0, request.c_str()),
457 MockRead reads[] = {
458 MockRead(SYNCHRONOUS, 1, "HTTP/1.1 200 Connection Established\r\n\r\n"),
461 Initialize(reads, arraysize(reads), writes, arraysize(writes), NULL, 0,
462 NULL, 0);
463 AddAuthToCache();
465 scoped_ptr<TestProxyDelegate> proxy_delegate(new TestProxyDelegate());
466 int rv = handle_.Init("a", CreateTunnelParams(proxy_delegate.get()), LOW,
467 callback_.callback(), &pool_, BoundNetLog());
468 EXPECT_EQ(OK, rv);
469 EXPECT_TRUE(handle_.is_initialized());
470 ASSERT_TRUE(handle_.socket());
471 HttpProxyClientSocket* tunnel_socket =
472 static_cast<HttpProxyClientSocket*>(handle_.socket());
473 EXPECT_TRUE(tunnel_socket->IsConnected());
474 proxy_delegate->VerifyOnTunnelHeadersReceived(
475 "www.google.com:443",
476 proxy_host_port.c_str(),
477 "HTTP/1.1 200 Connection Established");
478 proxy_delegate->VerifyOnTunnelRequestCompleted(
479 "www.google.com:443",
480 proxy_host_port.c_str());
483 TEST_P(HttpProxyClientSocketPoolTest, AsyncHaveAuth) {
484 std::string proxy_host_port =
485 GetParam().proxy_type == HTTP ?
486 (kHttpProxyHost + std::string(":80")) :
487 (kHttpsProxyHost + std::string(":443"));
488 std::string request =
489 "CONNECT www.google.com:443 HTTP/1.1\r\n"
490 "Host: www.google.com\r\n"
491 "Proxy-Connection: keep-alive\r\n"
492 "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n"
493 "Foo: " + proxy_host_port + "\r\n\r\n";
494 MockWrite writes[] = {
495 MockWrite(ASYNC, 0, request.c_str()),
497 MockRead reads[] = {
498 MockRead(ASYNC, 1, "HTTP/1.1 200 Connection Established\r\n\r\n"),
501 scoped_ptr<SpdyFrame> req(
502 spdy_util_.ConstructSpdyConnect(kAuthHeaders, kAuthHeadersSize, 1, LOW,
503 HostPortPair("www.google.com", 443)));
504 MockWrite spdy_writes[] = {
505 CreateMockWrite(*req, 0, ASYNC)
507 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
508 MockRead spdy_reads[] = {
509 CreateMockRead(*resp, 1, ASYNC),
510 MockRead(ASYNC, 0, 2)
513 Initialize(reads, arraysize(reads), writes, arraysize(writes),
514 spdy_reads, arraysize(spdy_reads), spdy_writes,
515 arraysize(spdy_writes));
516 AddAuthToCache();
518 scoped_ptr<TestProxyDelegate> proxy_delegate(new TestProxyDelegate());
519 int rv = handle_.Init("a", CreateTunnelParams(proxy_delegate.get()), LOW,
520 callback_.callback(), &pool_, BoundNetLog());
521 EXPECT_EQ(ERR_IO_PENDING, rv);
522 EXPECT_FALSE(handle_.is_initialized());
523 EXPECT_FALSE(handle_.socket());
525 data_->RunFor(2);
526 EXPECT_EQ(OK, callback_.WaitForResult());
527 EXPECT_TRUE(handle_.is_initialized());
528 ASSERT_TRUE(handle_.socket());
529 EXPECT_TRUE(handle_.socket()->IsConnected());
530 proxy_delegate->VerifyOnTunnelRequestCompleted(
531 "www.google.com:443",
532 proxy_host_port.c_str());
535 // Make sure that HttpProxyConnectJob passes on its priority to its
536 // SPDY session's socket request on Init (if applicable).
537 TEST_P(HttpProxyClientSocketPoolTest,
538 SetSpdySessionSocketRequestPriorityOnInit) {
539 if (GetParam().proxy_type != SPDY)
540 return;
542 scoped_ptr<SpdyFrame> req(
543 spdy_util_.ConstructSpdyConnect(kAuthHeaders, kAuthHeadersSize, 1, MEDIUM,
544 HostPortPair("www.google.com", 443)));
545 MockWrite spdy_writes[] = {
546 CreateMockWrite(*req, 0, ASYNC)
548 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
549 MockRead spdy_reads[] = {
550 CreateMockRead(*resp, 1, ASYNC),
551 MockRead(ASYNC, 0, 2)
554 Initialize(NULL, 0, NULL, 0,
555 spdy_reads, arraysize(spdy_reads),
556 spdy_writes, arraysize(spdy_writes));
557 AddAuthToCache();
559 EXPECT_EQ(ERR_IO_PENDING,
560 handle_.Init("a", CreateTunnelParams(NULL), MEDIUM,
561 callback_.callback(), &pool_, BoundNetLog()));
562 EXPECT_EQ(MEDIUM, GetLastTransportRequestPriority());
564 data_->RunFor(2);
565 EXPECT_EQ(OK, callback_.WaitForResult());
568 TEST_P(HttpProxyClientSocketPoolTest, TCPError) {
569 if (GetParam().proxy_type == SPDY) return;
570 data_.reset(new DeterministicSocketData(NULL, 0, NULL, 0));
571 data_->set_connect_data(MockConnect(ASYNC, ERR_CONNECTION_CLOSED));
573 socket_factory()->AddSocketDataProvider(data_.get());
575 int rv = handle_.Init("a", CreateTunnelParams(NULL), LOW,
576 callback_.callback(), &pool_, BoundNetLog());
577 EXPECT_EQ(ERR_IO_PENDING, rv);
578 EXPECT_FALSE(handle_.is_initialized());
579 EXPECT_FALSE(handle_.socket());
581 EXPECT_EQ(ERR_PROXY_CONNECTION_FAILED, callback_.WaitForResult());
583 EXPECT_FALSE(handle_.is_initialized());
584 EXPECT_FALSE(handle_.socket());
587 TEST_P(HttpProxyClientSocketPoolTest, SSLError) {
588 if (GetParam().proxy_type == HTTP) return;
589 data_.reset(new DeterministicSocketData(NULL, 0, NULL, 0));
590 data_->set_connect_data(MockConnect(ASYNC, OK));
591 socket_factory()->AddSocketDataProvider(data_.get());
593 ssl_data_.reset(new SSLSocketDataProvider(ASYNC,
594 ERR_CERT_AUTHORITY_INVALID));
595 if (GetParam().proxy_type == SPDY) {
596 InitializeSpdySsl();
598 socket_factory()->AddSSLSocketDataProvider(ssl_data_.get());
600 int rv = handle_.Init("a", CreateTunnelParams(NULL), LOW,
601 callback_.callback(), &pool_, BoundNetLog());
602 EXPECT_EQ(ERR_IO_PENDING, rv);
603 EXPECT_FALSE(handle_.is_initialized());
604 EXPECT_FALSE(handle_.socket());
606 EXPECT_EQ(ERR_PROXY_CERTIFICATE_INVALID, callback_.WaitForResult());
608 EXPECT_FALSE(handle_.is_initialized());
609 EXPECT_FALSE(handle_.socket());
612 TEST_P(HttpProxyClientSocketPoolTest, SslClientAuth) {
613 if (GetParam().proxy_type == HTTP) return;
614 data_.reset(new DeterministicSocketData(NULL, 0, NULL, 0));
615 data_->set_connect_data(MockConnect(ASYNC, OK));
616 socket_factory()->AddSocketDataProvider(data_.get());
618 ssl_data_.reset(new SSLSocketDataProvider(ASYNC,
619 ERR_SSL_CLIENT_AUTH_CERT_NEEDED));
620 if (GetParam().proxy_type == SPDY) {
621 InitializeSpdySsl();
623 socket_factory()->AddSSLSocketDataProvider(ssl_data_.get());
625 int rv = handle_.Init("a", CreateTunnelParams(NULL), LOW,
626 callback_.callback(), &pool_, BoundNetLog());
627 EXPECT_EQ(ERR_IO_PENDING, rv);
628 EXPECT_FALSE(handle_.is_initialized());
629 EXPECT_FALSE(handle_.socket());
631 EXPECT_EQ(ERR_SSL_CLIENT_AUTH_CERT_NEEDED, callback_.WaitForResult());
633 EXPECT_FALSE(handle_.is_initialized());
634 EXPECT_FALSE(handle_.socket());
637 TEST_P(HttpProxyClientSocketPoolTest, TunnelUnexpectedClose) {
638 MockWrite writes[] = {
639 MockWrite(ASYNC, 0,
640 "CONNECT www.google.com:443 HTTP/1.1\r\n"
641 "Host: www.google.com\r\n"
642 "Proxy-Connection: keep-alive\r\n"
643 "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
645 MockRead reads[] = {
646 MockRead(ASYNC, 1, "HTTP/1.1 200 Conn"),
647 MockRead(ASYNC, ERR_CONNECTION_CLOSED, 2),
649 scoped_ptr<SpdyFrame> req(
650 spdy_util_.ConstructSpdyConnect(kAuthHeaders, kAuthHeadersSize, 1, LOW,
651 HostPortPair("www.google.com", 443)));
652 MockWrite spdy_writes[] = {
653 CreateMockWrite(*req, 0, ASYNC)
655 MockRead spdy_reads[] = {
656 MockRead(ASYNC, ERR_CONNECTION_CLOSED, 1),
659 Initialize(reads, arraysize(reads), writes, arraysize(writes),
660 spdy_reads, arraysize(spdy_reads), spdy_writes,
661 arraysize(spdy_writes));
662 AddAuthToCache();
664 int rv = handle_.Init("a", CreateTunnelParams(NULL), LOW,
665 callback_.callback(), &pool_, BoundNetLog());
666 EXPECT_EQ(ERR_IO_PENDING, rv);
667 EXPECT_FALSE(handle_.is_initialized());
668 EXPECT_FALSE(handle_.socket());
670 data_->RunFor(3);
671 if (GetParam().proxy_type == SPDY) {
672 // SPDY cannot process a headers block unless it's complete and so it
673 // returns ERR_CONNECTION_CLOSED in this case.
674 EXPECT_EQ(ERR_CONNECTION_CLOSED, callback_.WaitForResult());
675 } else {
676 EXPECT_EQ(ERR_RESPONSE_HEADERS_TRUNCATED, callback_.WaitForResult());
678 EXPECT_FALSE(handle_.is_initialized());
679 EXPECT_FALSE(handle_.socket());
682 TEST_P(HttpProxyClientSocketPoolTest, Tunnel1xxResponse) {
683 // Tests that 1xx responses are rejected for a CONNECT request.
684 if (GetParam().proxy_type == SPDY) {
685 // SPDY doesn't have 1xx responses.
686 return;
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\r\n"),
695 MockRead reads[] = {
696 MockRead(ASYNC, 1, "HTTP/1.1 100 Continue\r\n\r\n"),
697 MockRead(ASYNC, 2, "HTTP/1.1 200 Connection Established\r\n\r\n"),
700 Initialize(reads, arraysize(reads), writes, arraysize(writes),
701 NULL, 0, NULL, 0);
703 int rv = handle_.Init("a", CreateTunnelParams(NULL), LOW,
704 callback_.callback(), &pool_, BoundNetLog());
705 EXPECT_EQ(ERR_IO_PENDING, rv);
706 EXPECT_FALSE(handle_.is_initialized());
707 EXPECT_FALSE(handle_.socket());
709 data_->RunFor(2);
710 EXPECT_EQ(ERR_TUNNEL_CONNECTION_FAILED, callback_.WaitForResult());
713 TEST_P(HttpProxyClientSocketPoolTest, TunnelSetupError) {
714 MockWrite writes[] = {
715 MockWrite(ASYNC, 0,
716 "CONNECT www.google.com:443 HTTP/1.1\r\n"
717 "Host: www.google.com\r\n"
718 "Proxy-Connection: keep-alive\r\n"
719 "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
721 MockRead reads[] = {
722 MockRead(ASYNC, 1, "HTTP/1.1 304 Not Modified\r\n\r\n"),
724 scoped_ptr<SpdyFrame> req(
725 spdy_util_.ConstructSpdyConnect(kAuthHeaders, kAuthHeadersSize, 1, LOW,
726 HostPortPair("www.google.com", 443)));
727 scoped_ptr<SpdyFrame> rst(
728 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL));
729 MockWrite spdy_writes[] = {
730 CreateMockWrite(*req, 0, ASYNC),
731 CreateMockWrite(*rst, 2, ASYNC),
733 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdySynReplyError(1));
734 MockRead spdy_reads[] = {
735 CreateMockRead(*resp, 1, ASYNC),
736 MockRead(ASYNC, 0, 3),
739 Initialize(reads, arraysize(reads), writes, arraysize(writes),
740 spdy_reads, arraysize(spdy_reads), spdy_writes,
741 arraysize(spdy_writes));
742 AddAuthToCache();
744 int rv = handle_.Init("a", CreateTunnelParams(NULL), LOW,
745 callback_.callback(), &pool_, BoundNetLog());
746 EXPECT_EQ(ERR_IO_PENDING, rv);
747 EXPECT_FALSE(handle_.is_initialized());
748 EXPECT_FALSE(handle_.socket());
750 data_->RunFor(2);
752 rv = callback_.WaitForResult();
753 // All Proxy CONNECT responses are not trustworthy
754 EXPECT_EQ(ERR_TUNNEL_CONNECTION_FAILED, rv);
755 EXPECT_FALSE(handle_.is_initialized());
756 EXPECT_FALSE(handle_.socket());
759 TEST_P(HttpProxyClientSocketPoolTest, TunnelSetupRedirect) {
760 const std::string redirectTarget = "https://foo.google.com/";
762 const std::string responseText = "HTTP/1.1 302 Found\r\n"
763 "Location: " + redirectTarget + "\r\n"
764 "Set-Cookie: foo=bar\r\n"
765 "\r\n";
766 MockWrite writes[] = {
767 MockWrite(ASYNC, 0,
768 "CONNECT www.google.com:443 HTTP/1.1\r\n"
769 "Host: www.google.com\r\n"
770 "Proxy-Connection: keep-alive\r\n"
771 "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
773 MockRead reads[] = {
774 MockRead(ASYNC, 1, responseText.c_str()),
776 scoped_ptr<SpdyFrame> req(
777 spdy_util_.ConstructSpdyConnect(kAuthHeaders, kAuthHeadersSize, 1, LOW,
778 HostPortPair("www.google.com", 443)));
779 scoped_ptr<SpdyFrame> rst(
780 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL));
782 MockWrite spdy_writes[] = {
783 CreateMockWrite(*req, 0, ASYNC),
784 CreateMockWrite(*rst, 3, ASYNC),
787 const char* const responseHeaders[] = {
788 "location", redirectTarget.c_str(),
789 "set-cookie", "foo=bar",
791 const int responseHeadersSize = arraysize(responseHeaders) / 2;
792 scoped_ptr<SpdyFrame> resp(
793 spdy_util_.ConstructSpdySynReplyError(
794 "302 Found",
795 responseHeaders, responseHeadersSize,
796 1));
797 MockRead spdy_reads[] = {
798 CreateMockRead(*resp, 1, ASYNC),
799 MockRead(ASYNC, 0, 2),
802 Initialize(reads, arraysize(reads), writes, arraysize(writes),
803 spdy_reads, arraysize(spdy_reads), spdy_writes,
804 arraysize(spdy_writes));
805 AddAuthToCache();
807 int rv = handle_.Init("a", CreateTunnelParams(NULL), LOW,
808 callback_.callback(), &pool_, BoundNetLog());
809 EXPECT_EQ(ERR_IO_PENDING, rv);
810 EXPECT_FALSE(handle_.is_initialized());
811 EXPECT_FALSE(handle_.socket());
813 data_->RunFor(2);
815 rv = callback_.WaitForResult();
817 if (GetParam().proxy_type == HTTP) {
818 // We don't trust 302 responses to CONNECT from HTTP proxies.
819 EXPECT_EQ(ERR_TUNNEL_CONNECTION_FAILED, rv);
820 EXPECT_FALSE(handle_.is_initialized());
821 EXPECT_FALSE(handle_.socket());
822 } else {
823 // Expect ProxyClientSocket to return the proxy's response, sanitized.
824 EXPECT_EQ(ERR_HTTPS_PROXY_TUNNEL_RESPONSE, rv);
825 EXPECT_TRUE(handle_.is_initialized());
826 ASSERT_TRUE(handle_.socket());
828 const ProxyClientSocket* tunnel_socket =
829 static_cast<ProxyClientSocket*>(handle_.socket());
830 const HttpResponseInfo* response = tunnel_socket->GetConnectResponseInfo();
831 const HttpResponseHeaders* headers = response->headers.get();
833 // Make sure Set-Cookie header was stripped.
834 EXPECT_FALSE(headers->HasHeader("set-cookie"));
836 // Make sure Content-Length: 0 header was added.
837 EXPECT_TRUE(headers->HasHeaderValue("content-length", "0"));
839 // Make sure Location header was included and correct.
840 std::string location;
841 EXPECT_TRUE(headers->IsRedirect(&location));
842 EXPECT_EQ(location, redirectTarget);
846 // It would be nice to also test the timeouts in HttpProxyClientSocketPool.
848 } // namespace
850 } // namespace net