[SyncFS] Use variadic template in callback_tracker_internal.h
[chromium-blink-merge.git] / net / http / http_proxy_client_socket_pool_unittest.cc
blobc6433af1347e62b97ff087ad8eeb377fcc3d0150
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(kProtoSPDY3) {}
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_headers_received_called_(false) {
69 virtual ~TestProxyDelegate() OVERRIDE {
72 bool on_before_tunnel_request_called() const {
73 return on_before_tunnel_request_called_;
76 bool on_tunnel_headers_received_called() const {
77 return on_tunnel_headers_received_called_;
80 void VerifyOnTunnelHeadersReceived(const std::string& origin,
81 const std::string& proxy_server,
82 const std::string& status_line) const {
83 EXPECT_TRUE(on_tunnel_headers_received_called_);
84 EXPECT_TRUE(HostPortPair::FromString(origin).Equals(
85 on_tunnel_headers_received_origin_));
86 EXPECT_TRUE(HostPortPair::FromString(proxy_server).Equals(
87 on_tunnel_headers_received_proxy_server_));
88 EXPECT_EQ(status_line, on_tunnel_headers_received_status_line_);
91 // ProxyDelegate:
92 virtual void OnResolveProxy(const GURL& url,
93 int load_flags,
94 const ProxyService& proxy_service,
95 ProxyInfo* result) OVERRIDE {
98 virtual void OnFallback(const ProxyServer& bad_proxy,
99 int net_error) OVERRIDE {
102 virtual void OnBeforeSendHeaders(URLRequest* request,
103 const ProxyInfo& proxy_info,
104 HttpRequestHeaders* headers) OVERRIDE {
107 virtual void OnBeforeTunnelRequest(
108 const net::HostPortPair& proxy_server,
109 net::HttpRequestHeaders* extra_headers) OVERRIDE {
110 on_before_tunnel_request_called_ = true;
111 if (extra_headers) {
112 extra_headers->SetHeader("Foo", proxy_server.ToString());
116 virtual void OnTunnelHeadersReceived(
117 const net::HostPortPair& origin,
118 const net::HostPortPair& proxy_server,
119 const net::HttpResponseHeaders& response_headers) OVERRIDE {
120 on_tunnel_headers_received_called_ = true;
121 on_tunnel_headers_received_origin_ = origin;
122 on_tunnel_headers_received_proxy_server_ = proxy_server;
123 on_tunnel_headers_received_status_line_ = response_headers.GetStatusLine();
126 private:
127 bool on_before_tunnel_request_called_;
128 bool on_tunnel_headers_received_called_;
129 HostPortPair on_tunnel_headers_received_origin_;
130 HostPortPair on_tunnel_headers_received_proxy_server_;
131 std::string on_tunnel_headers_received_status_line_;
135 class HttpProxyClientSocketPoolTest
136 : public ::testing::TestWithParam<HttpProxyClientSocketPoolTestParams> {
137 protected:
138 HttpProxyClientSocketPoolTest()
139 : session_deps_(GetParam().protocol),
140 tcp_histograms_("MockTCP"),
141 transport_socket_pool_(
142 kMaxSockets,
143 kMaxSocketsPerGroup,
144 &tcp_histograms_,
145 session_deps_.deterministic_socket_factory.get()),
146 ssl_histograms_("MockSSL"),
147 ssl_socket_pool_(kMaxSockets,
148 kMaxSocketsPerGroup,
149 &ssl_histograms_,
150 session_deps_.host_resolver.get(),
151 session_deps_.cert_verifier.get(),
152 NULL /* channel_id_store */,
153 NULL /* transport_security_state */,
154 NULL /* cert_transparency_verifier */,
155 std::string() /* ssl_session_cache_shard */,
156 session_deps_.deterministic_socket_factory.get(),
157 &transport_socket_pool_,
158 NULL,
159 NULL,
160 session_deps_.ssl_config_service.get(),
161 false,
162 BoundNetLog().net_log()),
163 session_(CreateNetworkSession()),
164 http_proxy_histograms_("HttpProxyUnitTest"),
165 spdy_util_(GetParam().protocol),
166 pool_(kMaxSockets,
167 kMaxSocketsPerGroup,
168 &http_proxy_histograms_,
169 NULL,
170 &transport_socket_pool_,
171 &ssl_socket_pool_,
172 NULL,
173 NULL) {}
175 virtual ~HttpProxyClientSocketPoolTest() {
178 void AddAuthToCache() {
179 const base::string16 kFoo(base::ASCIIToUTF16("foo"));
180 const base::string16 kBar(base::ASCIIToUTF16("bar"));
181 GURL proxy_url(GetParam().proxy_type == HTTP ?
182 (std::string("http://") + kHttpProxyHost) :
183 (std::string("https://") + kHttpsProxyHost));
184 session_->http_auth_cache()->Add(proxy_url,
185 "MyRealm1",
186 HttpAuth::AUTH_SCHEME_BASIC,
187 "Basic realm=MyRealm1",
188 AuthCredentials(kFoo, kBar),
189 "/");
192 scoped_refptr<TransportSocketParams> CreateHttpProxyParams() const {
193 if (GetParam().proxy_type != HTTP)
194 return NULL;
195 return new TransportSocketParams(
196 HostPortPair(kHttpProxyHost, 80),
197 false,
198 false,
199 OnHostResolutionCallback(),
200 TransportSocketParams::COMBINE_CONNECT_AND_WRITE_DEFAULT);
203 scoped_refptr<SSLSocketParams> CreateHttpsProxyParams() const {
204 if (GetParam().proxy_type == HTTP)
205 return NULL;
206 return new SSLSocketParams(
207 new TransportSocketParams(
208 HostPortPair(kHttpsProxyHost, 443),
209 false,
210 false,
211 OnHostResolutionCallback(),
212 TransportSocketParams::COMBINE_CONNECT_AND_WRITE_DEFAULT),
213 NULL,
214 NULL,
215 HostPortPair(kHttpsProxyHost, 443),
216 SSLConfig(),
217 PRIVACY_MODE_DISABLED,
219 false,
220 false);
223 // Returns the a correctly constructed HttpProxyParms
224 // for the HTTP or HTTPS proxy.
225 scoped_refptr<HttpProxySocketParams> CreateParams(
226 bool tunnel,
227 ProxyDelegate* proxy_delegate) {
228 return scoped_refptr<HttpProxySocketParams>(new HttpProxySocketParams(
229 CreateHttpProxyParams(),
230 CreateHttpsProxyParams(),
231 GURL(tunnel ? "https://www.google.com/" : "http://www.google.com"),
232 std::string(),
233 HostPortPair("www.google.com", tunnel ? 443 : 80),
234 session_->http_auth_cache(),
235 session_->http_auth_handler_factory(),
236 session_->spdy_session_pool(),
237 tunnel,
238 proxy_delegate));
241 scoped_refptr<HttpProxySocketParams> CreateTunnelParams(
242 ProxyDelegate* proxy_delegate) {
243 return CreateParams(true, proxy_delegate);
246 scoped_refptr<HttpProxySocketParams> CreateNoTunnelParams(
247 ProxyDelegate* proxy_delegate) {
248 return CreateParams(false, proxy_delegate);
251 DeterministicMockClientSocketFactory* socket_factory() {
252 return session_deps_.deterministic_socket_factory.get();
255 void Initialize(MockRead* reads, size_t reads_count,
256 MockWrite* writes, size_t writes_count,
257 MockRead* spdy_reads, size_t spdy_reads_count,
258 MockWrite* spdy_writes, size_t spdy_writes_count) {
259 if (GetParam().proxy_type == SPDY) {
260 data_.reset(new DeterministicSocketData(spdy_reads, spdy_reads_count,
261 spdy_writes, spdy_writes_count));
262 } else {
263 data_.reset(new DeterministicSocketData(reads, reads_count, writes,
264 writes_count));
267 data_->set_connect_data(MockConnect(SYNCHRONOUS, OK));
268 data_->StopAfter(2); // Request / Response
270 socket_factory()->AddSocketDataProvider(data_.get());
272 if (GetParam().proxy_type != HTTP) {
273 ssl_data_.reset(new SSLSocketDataProvider(SYNCHRONOUS, OK));
274 if (GetParam().proxy_type == SPDY) {
275 InitializeSpdySsl();
277 socket_factory()->AddSSLSocketDataProvider(ssl_data_.get());
281 void InitializeSpdySsl() {
282 ssl_data_->SetNextProto(GetParam().protocol);
285 HttpNetworkSession* CreateNetworkSession() {
286 return SpdySessionDependencies::SpdyCreateSessionDeterministic(
287 &session_deps_);
290 RequestPriority GetLastTransportRequestPriority() const {
291 return transport_socket_pool_.last_request_priority();
294 private:
295 SpdySessionDependencies session_deps_;
297 ClientSocketPoolHistograms tcp_histograms_;
298 MockTransportClientSocketPool transport_socket_pool_;
299 ClientSocketPoolHistograms ssl_histograms_;
300 MockHostResolver host_resolver_;
301 scoped_ptr<CertVerifier> cert_verifier_;
302 SSLClientSocketPool ssl_socket_pool_;
304 const scoped_refptr<HttpNetworkSession> session_;
305 ClientSocketPoolHistograms http_proxy_histograms_;
307 protected:
308 SpdyTestUtil spdy_util_;
309 scoped_ptr<SSLSocketDataProvider> ssl_data_;
310 scoped_ptr<DeterministicSocketData> data_;
311 HttpProxyClientSocketPool pool_;
312 ClientSocketHandle handle_;
313 TestCompletionCallback callback_;
316 //-----------------------------------------------------------------------------
317 // All tests are run with three different proxy types: HTTP, HTTPS (non-SPDY)
318 // and SPDY.
320 // TODO(akalin): Use ::testing::Combine() when we are able to use
321 // <tr1/tuple>.
322 INSTANTIATE_TEST_CASE_P(
323 HttpProxyClientSocketPoolTests,
324 HttpProxyClientSocketPoolTest,
325 ::testing::Values(
326 HttpProxyClientSocketPoolTestParams(HTTP, kProtoDeprecatedSPDY2),
327 HttpProxyClientSocketPoolTestParams(HTTPS, kProtoDeprecatedSPDY2),
328 HttpProxyClientSocketPoolTestParams(SPDY, kProtoDeprecatedSPDY2),
329 HttpProxyClientSocketPoolTestParams(HTTP, kProtoSPDY3),
330 HttpProxyClientSocketPoolTestParams(HTTPS, kProtoSPDY3),
331 HttpProxyClientSocketPoolTestParams(SPDY, kProtoSPDY3),
332 HttpProxyClientSocketPoolTestParams(HTTP, kProtoSPDY31),
333 HttpProxyClientSocketPoolTestParams(HTTPS, kProtoSPDY31),
334 HttpProxyClientSocketPoolTestParams(SPDY, kProtoSPDY31),
335 HttpProxyClientSocketPoolTestParams(HTTP, kProtoSPDY4),
336 HttpProxyClientSocketPoolTestParams(HTTPS, kProtoSPDY4),
337 HttpProxyClientSocketPoolTestParams(SPDY, kProtoSPDY4)));
339 TEST_P(HttpProxyClientSocketPoolTest, NoTunnel) {
340 Initialize(NULL, 0, NULL, 0, NULL, 0, NULL, 0);
342 scoped_ptr<TestProxyDelegate> proxy_delegate(new TestProxyDelegate());
343 int rv = handle_.Init("a", CreateNoTunnelParams(proxy_delegate.get()), LOW,
344 CompletionCallback(), &pool_, BoundNetLog());
345 EXPECT_EQ(OK, rv);
346 EXPECT_TRUE(handle_.is_initialized());
347 ASSERT_TRUE(handle_.socket());
348 HttpProxyClientSocket* tunnel_socket =
349 static_cast<HttpProxyClientSocket*>(handle_.socket());
350 EXPECT_TRUE(tunnel_socket->IsConnected());
351 EXPECT_FALSE(proxy_delegate->on_before_tunnel_request_called());
352 EXPECT_FALSE(proxy_delegate->on_tunnel_headers_received_called());
355 // Make sure that HttpProxyConnectJob passes on its priority to its
356 // (non-SSL) socket request on Init.
357 TEST_P(HttpProxyClientSocketPoolTest, SetSocketRequestPriorityOnInit) {
358 Initialize(NULL, 0, NULL, 0, NULL, 0, NULL, 0);
359 EXPECT_EQ(OK,
360 handle_.Init("a", CreateNoTunnelParams(NULL), HIGHEST,
361 CompletionCallback(), &pool_, BoundNetLog()));
362 EXPECT_EQ(HIGHEST, GetLastTransportRequestPriority());
365 TEST_P(HttpProxyClientSocketPoolTest, NeedAuth) {
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\r\n"),
371 MockRead reads[] = {
372 // No credentials.
373 MockRead(ASYNC, 1, "HTTP/1.1 407 Proxy Authentication Required\r\n"),
374 MockRead(ASYNC, 2, "Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
375 MockRead(ASYNC, 3, "Content-Length: 10\r\n\r\n"),
376 MockRead(ASYNC, 4, "0123456789"),
378 scoped_ptr<SpdyFrame> req(
379 spdy_util_.ConstructSpdyConnect(NULL, 0, 1, LOW));
380 scoped_ptr<SpdyFrame> rst(
381 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL));
382 MockWrite spdy_writes[] = {
383 CreateMockWrite(*req, 0, ASYNC),
384 CreateMockWrite(*rst, 2, ASYNC),
386 SpdyHeaderBlock resp_block;
387 resp_block[spdy_util_.GetStatusKey()] = "407";
388 resp_block["proxy-authenticate"] = "Basic realm=\"MyRealm1\"";
389 spdy_util_.MaybeAddVersionHeader(&resp_block);
391 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyReply(1, resp_block));
392 MockRead spdy_reads[] = {
393 CreateMockRead(*resp, 1, ASYNC),
394 MockRead(ASYNC, 0, 3)
397 Initialize(reads, arraysize(reads), writes, arraysize(writes),
398 spdy_reads, arraysize(spdy_reads), spdy_writes,
399 arraysize(spdy_writes));
401 data_->StopAfter(4);
402 int rv = handle_.Init("a", CreateTunnelParams(NULL), LOW,
403 callback_.callback(), &pool_, BoundNetLog());
404 EXPECT_EQ(ERR_IO_PENDING, rv);
405 EXPECT_FALSE(handle_.is_initialized());
406 EXPECT_FALSE(handle_.socket());
408 data_->RunFor(GetParam().proxy_type == SPDY ? 2 : 4);
409 rv = callback_.WaitForResult();
410 EXPECT_EQ(ERR_PROXY_AUTH_REQUESTED, rv);
411 EXPECT_TRUE(handle_.is_initialized());
412 ASSERT_TRUE(handle_.socket());
413 ProxyClientSocket* tunnel_socket =
414 static_cast<ProxyClientSocket*>(handle_.socket());
415 if (GetParam().proxy_type == SPDY) {
416 EXPECT_TRUE(tunnel_socket->IsConnected());
417 EXPECT_TRUE(tunnel_socket->IsUsingSpdy());
418 } else {
419 EXPECT_FALSE(tunnel_socket->IsConnected());
420 EXPECT_FALSE(tunnel_socket->IsUsingSpdy());
424 TEST_P(HttpProxyClientSocketPoolTest, HaveAuth) {
425 // It's pretty much impossible to make the SPDY case behave synchronously
426 // so we skip this test for SPDY
427 if (GetParam().proxy_type == SPDY)
428 return;
429 std::string proxy_host_port =
430 GetParam().proxy_type == HTTP ?
431 (kHttpProxyHost + std::string(":80")) :
432 (kHttpsProxyHost + std::string(":443"));
433 std::string request =
434 "CONNECT www.google.com:443 HTTP/1.1\r\n"
435 "Host: www.google.com\r\n"
436 "Proxy-Connection: keep-alive\r\n"
437 "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n"
438 "Foo: " + proxy_host_port + "\r\n\r\n";
439 MockWrite writes[] = {
440 MockWrite(SYNCHRONOUS, 0, request.c_str()),
442 MockRead reads[] = {
443 MockRead(SYNCHRONOUS, 1, "HTTP/1.1 200 Connection Established\r\n\r\n"),
446 Initialize(reads, arraysize(reads), writes, arraysize(writes), NULL, 0,
447 NULL, 0);
448 AddAuthToCache();
450 scoped_ptr<TestProxyDelegate> proxy_delegate(new TestProxyDelegate());
451 int rv = handle_.Init("a", CreateTunnelParams(proxy_delegate.get()), LOW,
452 callback_.callback(), &pool_, BoundNetLog());
453 EXPECT_EQ(OK, rv);
454 EXPECT_TRUE(handle_.is_initialized());
455 ASSERT_TRUE(handle_.socket());
456 HttpProxyClientSocket* tunnel_socket =
457 static_cast<HttpProxyClientSocket*>(handle_.socket());
458 EXPECT_TRUE(tunnel_socket->IsConnected());
459 proxy_delegate->VerifyOnTunnelHeadersReceived(
460 "www.google.com:443",
461 proxy_host_port.c_str(),
462 "HTTP/1.1 200 Connection Established");
465 TEST_P(HttpProxyClientSocketPoolTest, AsyncHaveAuth) {
466 MockWrite writes[] = {
467 MockWrite(ASYNC, 0, "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\r\n"),
472 MockRead reads[] = {
473 MockRead(ASYNC, 1, "HTTP/1.1 200 Connection Established\r\n\r\n"),
476 scoped_ptr<SpdyFrame> req(
477 spdy_util_.ConstructSpdyConnect(kAuthHeaders, kAuthHeadersSize, 1, LOW));
478 MockWrite spdy_writes[] = {
479 CreateMockWrite(*req, 0, ASYNC)
481 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
482 MockRead spdy_reads[] = {
483 CreateMockRead(*resp, 1, ASYNC),
484 MockRead(ASYNC, 0, 2)
487 Initialize(reads, arraysize(reads), writes, arraysize(writes),
488 spdy_reads, arraysize(spdy_reads), spdy_writes,
489 arraysize(spdy_writes));
490 AddAuthToCache();
492 int rv = handle_.Init("a", CreateTunnelParams(NULL), LOW,
493 callback_.callback(), &pool_, BoundNetLog());
494 EXPECT_EQ(ERR_IO_PENDING, rv);
495 EXPECT_FALSE(handle_.is_initialized());
496 EXPECT_FALSE(handle_.socket());
498 data_->RunFor(2);
499 EXPECT_EQ(OK, callback_.WaitForResult());
500 EXPECT_TRUE(handle_.is_initialized());
501 ASSERT_TRUE(handle_.socket());
502 HttpProxyClientSocket* tunnel_socket =
503 static_cast<HttpProxyClientSocket*>(handle_.socket());
504 EXPECT_TRUE(tunnel_socket->IsConnected());
507 // Make sure that HttpProxyConnectJob passes on its priority to its
508 // SPDY session's socket request on Init (if applicable).
509 TEST_P(HttpProxyClientSocketPoolTest,
510 SetSpdySessionSocketRequestPriorityOnInit) {
511 if (GetParam().proxy_type != SPDY)
512 return;
514 scoped_ptr<SpdyFrame> req(
515 spdy_util_.ConstructSpdyConnect(kAuthHeaders, kAuthHeadersSize,
516 1, MEDIUM));
517 MockWrite spdy_writes[] = {
518 CreateMockWrite(*req, 0, ASYNC)
520 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
521 MockRead spdy_reads[] = {
522 CreateMockRead(*resp, 1, ASYNC),
523 MockRead(ASYNC, 0, 2)
526 Initialize(NULL, 0, NULL, 0,
527 spdy_reads, arraysize(spdy_reads),
528 spdy_writes, arraysize(spdy_writes));
529 AddAuthToCache();
531 EXPECT_EQ(ERR_IO_PENDING,
532 handle_.Init("a", CreateTunnelParams(NULL), MEDIUM,
533 callback_.callback(), &pool_, BoundNetLog()));
534 EXPECT_EQ(MEDIUM, GetLastTransportRequestPriority());
536 data_->RunFor(2);
537 EXPECT_EQ(OK, callback_.WaitForResult());
540 TEST_P(HttpProxyClientSocketPoolTest, TCPError) {
541 if (GetParam().proxy_type == SPDY) return;
542 data_.reset(new DeterministicSocketData(NULL, 0, NULL, 0));
543 data_->set_connect_data(MockConnect(ASYNC, ERR_CONNECTION_CLOSED));
545 socket_factory()->AddSocketDataProvider(data_.get());
547 int rv = handle_.Init("a", CreateTunnelParams(NULL), LOW,
548 callback_.callback(), &pool_, BoundNetLog());
549 EXPECT_EQ(ERR_IO_PENDING, rv);
550 EXPECT_FALSE(handle_.is_initialized());
551 EXPECT_FALSE(handle_.socket());
553 EXPECT_EQ(ERR_PROXY_CONNECTION_FAILED, callback_.WaitForResult());
555 EXPECT_FALSE(handle_.is_initialized());
556 EXPECT_FALSE(handle_.socket());
559 TEST_P(HttpProxyClientSocketPoolTest, SSLError) {
560 if (GetParam().proxy_type == HTTP) return;
561 data_.reset(new DeterministicSocketData(NULL, 0, NULL, 0));
562 data_->set_connect_data(MockConnect(ASYNC, OK));
563 socket_factory()->AddSocketDataProvider(data_.get());
565 ssl_data_.reset(new SSLSocketDataProvider(ASYNC,
566 ERR_CERT_AUTHORITY_INVALID));
567 if (GetParam().proxy_type == SPDY) {
568 InitializeSpdySsl();
570 socket_factory()->AddSSLSocketDataProvider(ssl_data_.get());
572 int rv = handle_.Init("a", CreateTunnelParams(NULL), LOW,
573 callback_.callback(), &pool_, BoundNetLog());
574 EXPECT_EQ(ERR_IO_PENDING, rv);
575 EXPECT_FALSE(handle_.is_initialized());
576 EXPECT_FALSE(handle_.socket());
578 EXPECT_EQ(ERR_PROXY_CERTIFICATE_INVALID, callback_.WaitForResult());
580 EXPECT_FALSE(handle_.is_initialized());
581 EXPECT_FALSE(handle_.socket());
584 TEST_P(HttpProxyClientSocketPoolTest, SslClientAuth) {
585 if (GetParam().proxy_type == HTTP) return;
586 data_.reset(new DeterministicSocketData(NULL, 0, NULL, 0));
587 data_->set_connect_data(MockConnect(ASYNC, OK));
588 socket_factory()->AddSocketDataProvider(data_.get());
590 ssl_data_.reset(new SSLSocketDataProvider(ASYNC,
591 ERR_SSL_CLIENT_AUTH_CERT_NEEDED));
592 if (GetParam().proxy_type == SPDY) {
593 InitializeSpdySsl();
595 socket_factory()->AddSSLSocketDataProvider(ssl_data_.get());
597 int rv = handle_.Init("a", CreateTunnelParams(NULL), LOW,
598 callback_.callback(), &pool_, BoundNetLog());
599 EXPECT_EQ(ERR_IO_PENDING, rv);
600 EXPECT_FALSE(handle_.is_initialized());
601 EXPECT_FALSE(handle_.socket());
603 EXPECT_EQ(ERR_SSL_CLIENT_AUTH_CERT_NEEDED, callback_.WaitForResult());
605 EXPECT_FALSE(handle_.is_initialized());
606 EXPECT_FALSE(handle_.socket());
609 TEST_P(HttpProxyClientSocketPoolTest, TunnelUnexpectedClose) {
610 MockWrite writes[] = {
611 MockWrite(ASYNC, 0,
612 "CONNECT www.google.com:443 HTTP/1.1\r\n"
613 "Host: www.google.com\r\n"
614 "Proxy-Connection: keep-alive\r\n"
615 "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
617 MockRead reads[] = {
618 MockRead(ASYNC, 1, "HTTP/1.1 200 Conn"),
619 MockRead(ASYNC, ERR_CONNECTION_CLOSED, 2),
621 scoped_ptr<SpdyFrame> req(
622 spdy_util_.ConstructSpdyConnect(kAuthHeaders, kAuthHeadersSize, 1, LOW));
623 MockWrite spdy_writes[] = {
624 CreateMockWrite(*req, 0, ASYNC)
626 MockRead spdy_reads[] = {
627 MockRead(ASYNC, ERR_CONNECTION_CLOSED, 1),
630 Initialize(reads, arraysize(reads), writes, arraysize(writes),
631 spdy_reads, arraysize(spdy_reads), spdy_writes,
632 arraysize(spdy_writes));
633 AddAuthToCache();
635 int rv = handle_.Init("a", CreateTunnelParams(NULL), LOW,
636 callback_.callback(), &pool_, BoundNetLog());
637 EXPECT_EQ(ERR_IO_PENDING, rv);
638 EXPECT_FALSE(handle_.is_initialized());
639 EXPECT_FALSE(handle_.socket());
641 data_->RunFor(3);
642 if (GetParam().proxy_type == SPDY) {
643 // SPDY cannot process a headers block unless it's complete and so it
644 // returns ERR_CONNECTION_CLOSED in this case.
645 EXPECT_EQ(ERR_CONNECTION_CLOSED, callback_.WaitForResult());
646 } else {
647 EXPECT_EQ(ERR_RESPONSE_HEADERS_TRUNCATED, callback_.WaitForResult());
649 EXPECT_FALSE(handle_.is_initialized());
650 EXPECT_FALSE(handle_.socket());
653 TEST_P(HttpProxyClientSocketPoolTest, Tunnel1xxResponse) {
654 // Tests that 1xx responses are rejected for a CONNECT request.
655 if (GetParam().proxy_type == SPDY) {
656 // SPDY doesn't have 1xx responses.
657 return;
660 MockWrite writes[] = {
661 MockWrite(ASYNC, 0,
662 "CONNECT www.google.com:443 HTTP/1.1\r\n"
663 "Host: www.google.com\r\n"
664 "Proxy-Connection: keep-alive\r\n\r\n"),
666 MockRead reads[] = {
667 MockRead(ASYNC, 1, "HTTP/1.1 100 Continue\r\n\r\n"),
668 MockRead(ASYNC, 2, "HTTP/1.1 200 Connection Established\r\n\r\n"),
671 Initialize(reads, arraysize(reads), writes, arraysize(writes),
672 NULL, 0, NULL, 0);
674 int rv = handle_.Init("a", CreateTunnelParams(NULL), LOW,
675 callback_.callback(), &pool_, BoundNetLog());
676 EXPECT_EQ(ERR_IO_PENDING, rv);
677 EXPECT_FALSE(handle_.is_initialized());
678 EXPECT_FALSE(handle_.socket());
680 data_->RunFor(2);
681 EXPECT_EQ(ERR_TUNNEL_CONNECTION_FAILED, callback_.WaitForResult());
684 TEST_P(HttpProxyClientSocketPoolTest, TunnelSetupError) {
685 MockWrite writes[] = {
686 MockWrite(ASYNC, 0,
687 "CONNECT www.google.com:443 HTTP/1.1\r\n"
688 "Host: www.google.com\r\n"
689 "Proxy-Connection: keep-alive\r\n"
690 "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
692 MockRead reads[] = {
693 MockRead(ASYNC, 1, "HTTP/1.1 304 Not Modified\r\n\r\n"),
695 scoped_ptr<SpdyFrame> req(
696 spdy_util_.ConstructSpdyConnect(kAuthHeaders, kAuthHeadersSize, 1, LOW));
697 scoped_ptr<SpdyFrame> rst(
698 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL));
699 MockWrite spdy_writes[] = {
700 CreateMockWrite(*req, 0, ASYNC),
701 CreateMockWrite(*rst, 2, ASYNC),
703 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdySynReplyError(1));
704 MockRead spdy_reads[] = {
705 CreateMockRead(*resp, 1, ASYNC),
706 MockRead(ASYNC, 0, 3),
709 Initialize(reads, arraysize(reads), writes, arraysize(writes),
710 spdy_reads, arraysize(spdy_reads), spdy_writes,
711 arraysize(spdy_writes));
712 AddAuthToCache();
714 int rv = handle_.Init("a", CreateTunnelParams(NULL), LOW,
715 callback_.callback(), &pool_, BoundNetLog());
716 EXPECT_EQ(ERR_IO_PENDING, rv);
717 EXPECT_FALSE(handle_.is_initialized());
718 EXPECT_FALSE(handle_.socket());
720 data_->RunFor(2);
722 rv = callback_.WaitForResult();
723 // All Proxy CONNECT responses are not trustworthy
724 EXPECT_EQ(ERR_TUNNEL_CONNECTION_FAILED, rv);
725 EXPECT_FALSE(handle_.is_initialized());
726 EXPECT_FALSE(handle_.socket());
729 TEST_P(HttpProxyClientSocketPoolTest, TunnelSetupRedirect) {
730 const std::string redirectTarget = "https://foo.google.com/";
732 const std::string responseText = "HTTP/1.1 302 Found\r\n"
733 "Location: " + redirectTarget + "\r\n"
734 "Set-Cookie: foo=bar\r\n"
735 "\r\n";
736 MockWrite writes[] = {
737 MockWrite(ASYNC, 0,
738 "CONNECT www.google.com:443 HTTP/1.1\r\n"
739 "Host: www.google.com\r\n"
740 "Proxy-Connection: keep-alive\r\n"
741 "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
743 MockRead reads[] = {
744 MockRead(ASYNC, 1, responseText.c_str()),
746 scoped_ptr<SpdyFrame> req(
747 spdy_util_.ConstructSpdyConnect(kAuthHeaders, kAuthHeadersSize, 1, LOW));
748 scoped_ptr<SpdyFrame> rst(
749 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL));
751 MockWrite spdy_writes[] = {
752 CreateMockWrite(*req, 0, ASYNC),
753 CreateMockWrite(*rst, 3, ASYNC),
756 const char* const responseHeaders[] = {
757 "location", redirectTarget.c_str(),
758 "set-cookie", "foo=bar",
760 const int responseHeadersSize = arraysize(responseHeaders) / 2;
761 scoped_ptr<SpdyFrame> resp(
762 spdy_util_.ConstructSpdySynReplyError(
763 "302 Found",
764 responseHeaders, responseHeadersSize,
765 1));
766 MockRead spdy_reads[] = {
767 CreateMockRead(*resp, 1, ASYNC),
768 MockRead(ASYNC, 0, 2),
771 Initialize(reads, arraysize(reads), writes, arraysize(writes),
772 spdy_reads, arraysize(spdy_reads), spdy_writes,
773 arraysize(spdy_writes));
774 AddAuthToCache();
776 int rv = handle_.Init("a", CreateTunnelParams(NULL), LOW,
777 callback_.callback(), &pool_, BoundNetLog());
778 EXPECT_EQ(ERR_IO_PENDING, rv);
779 EXPECT_FALSE(handle_.is_initialized());
780 EXPECT_FALSE(handle_.socket());
782 data_->RunFor(2);
784 rv = callback_.WaitForResult();
786 if (GetParam().proxy_type == HTTP) {
787 // We don't trust 302 responses to CONNECT from HTTP proxies.
788 EXPECT_EQ(ERR_TUNNEL_CONNECTION_FAILED, rv);
789 EXPECT_FALSE(handle_.is_initialized());
790 EXPECT_FALSE(handle_.socket());
791 } else {
792 // Expect ProxyClientSocket to return the proxy's response, sanitized.
793 EXPECT_EQ(ERR_HTTPS_PROXY_TUNNEL_RESPONSE, rv);
794 EXPECT_TRUE(handle_.is_initialized());
795 ASSERT_TRUE(handle_.socket());
797 const ProxyClientSocket* tunnel_socket =
798 static_cast<ProxyClientSocket*>(handle_.socket());
799 const HttpResponseInfo* response = tunnel_socket->GetConnectResponseInfo();
800 const HttpResponseHeaders* headers = response->headers.get();
802 // Make sure Set-Cookie header was stripped.
803 EXPECT_FALSE(headers->HasHeader("set-cookie"));
805 // Make sure Content-Length: 0 header was added.
806 EXPECT_TRUE(headers->HasHeaderValue("content-length", "0"));
808 // Make sure Location header was included and correct.
809 std::string location;
810 EXPECT_TRUE(headers->IsRedirect(&location));
811 EXPECT_EQ(location, redirectTarget);
815 // It would be nice to also test the timeouts in HttpProxyClientSocketPool.
817 } // namespace
819 } // namespace net