spdy_proxy_client_socket_unittest.cc revision eb525c5499e34cc9c4b825d6d9e75bb07cc06ace
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.
4
5#include "net/spdy/spdy_proxy_client_socket.h"
6
7#include "base/bind.h"
8#include "base/bind_helpers.h"
9#include "base/strings/utf_string_conversions.h"
10#include "net/base/address_list.h"
11#include "net/base/capturing_net_log.h"
12#include "net/base/net_log.h"
13#include "net/base/net_log_unittest.h"
14#include "net/base/test_completion_callback.h"
15#include "net/base/winsock_init.h"
16#include "net/dns/mock_host_resolver.h"
17#include "net/http/http_response_headers.h"
18#include "net/http/http_response_info.h"
19#include "net/socket/client_socket_factory.h"
20#include "net/socket/next_proto.h"
21#include "net/socket/socket_test_util.h"
22#include "net/socket/tcp_client_socket.h"
23#include "net/spdy/buffered_spdy_framer.h"
24#include "net/spdy/spdy_http_utils.h"
25#include "net/spdy/spdy_protocol.h"
26#include "net/spdy/spdy_session_pool.h"
27#include "net/spdy/spdy_test_util_common.h"
28#include "testing/gtest/include/gtest/gtest.h"
29#include "testing/platform_test.h"
30
31//-----------------------------------------------------------------------------
32
33namespace {
34
35static const char kRequestUrl[] = "https://www.google.com/";
36static const char kOriginHost[] = "www.google.com";
37static const int kOriginPort = 443;
38static const char kOriginHostPort[] = "www.google.com:443";
39static const char kProxyUrl[] = "https://myproxy:6121/";
40static const char kProxyHost[] = "myproxy";
41static const int kProxyPort = 6121;
42static const char kUserAgent[] = "Mozilla/1.0";
43
44static const int kStreamId = 1;
45
46static const char kMsg1[] = "\0hello!\xff";
47static const int kLen1 = 8;
48static const char kMsg2[] = "\00012345678\0";
49static const int kLen2 = 10;
50static const char kMsg3[] = "bye!";
51static const int kLen3 = 4;
52static const char kMsg33[] = "bye!bye!";
53static const int kLen33 = kLen3 + kLen3;
54static const char kMsg333[] = "bye!bye!bye!";
55static const int kLen333 = kLen3 + kLen3 + kLen3;
56
57static const char kRedirectUrl[] = "https://example.com/";
58
59}  // anonymous namespace
60
61namespace net {
62
63class SpdyProxyClientSocketTest
64    : public PlatformTest,
65      public testing::WithParamInterface<NextProto> {
66 public:
67  SpdyProxyClientSocketTest();
68
69  virtual void TearDown();
70
71 protected:
72  void Initialize(MockRead* reads, size_t reads_count, MockWrite* writes,
73                  size_t writes_count);
74  SpdyFrame* ConstructConnectRequestFrame();
75  SpdyFrame* ConstructConnectAuthRequestFrame();
76  SpdyFrame* ConstructConnectReplyFrame();
77  SpdyFrame* ConstructConnectAuthReplyFrame();
78  SpdyFrame* ConstructConnectRedirectReplyFrame();
79  SpdyFrame* ConstructConnectErrorReplyFrame();
80  SpdyFrame* ConstructBodyFrame(const char* data, int length);
81  scoped_refptr<IOBufferWithSize> CreateBuffer(const char* data, int size);
82  void AssertConnectSucceeds();
83  void AssertConnectFails(int result);
84  void AssertConnectionEstablished();
85  void AssertSyncReadEquals(const char* data, int len);
86  void AssertAsyncReadEquals(const char* data, int len);
87  void AssertReadStarts(const char* data, int len);
88  void AssertReadReturns(const char* data, int len);
89  void AssertAsyncWriteSucceeds(const char* data, int len);
90  void AssertWriteReturns(const char* data, int len, int rv);
91  void AssertWriteLength(int len);
92  void AssertAsyncWriteWithReadsSucceeds(const char* data, int len,
93                                        int num_reads);
94
95  void AddAuthToCache() {
96    const base::string16 kFoo(ASCIIToUTF16("foo"));
97    const base::string16 kBar(ASCIIToUTF16("bar"));
98    session_->http_auth_cache()->Add(GURL(kProxyUrl),
99                                     "MyRealm1",
100                                     HttpAuth::AUTH_SCHEME_BASIC,
101                                     "Basic realm=MyRealm1",
102                                     AuthCredentials(kFoo, kBar),
103                                     "/");
104  }
105
106  void Run(int steps) {
107    data_->StopAfter(steps);
108    data_->Run();
109  }
110
111  SpdyTestUtil spdy_util_;
112  scoped_ptr<SpdyProxyClientSocket> sock_;
113  TestCompletionCallback read_callback_;
114  TestCompletionCallback write_callback_;
115  scoped_ptr<DeterministicSocketData> data_;
116  CapturingBoundNetLog net_log_;
117
118 private:
119  scoped_refptr<HttpNetworkSession> session_;
120  scoped_refptr<IOBuffer> read_buf_;
121  SpdySessionDependencies session_deps_;
122  MockConnect connect_data_;
123  scoped_refptr<SpdySession> spdy_session_;
124  BufferedSpdyFramer framer_;
125
126  std::string user_agent_;
127  GURL url_;
128  HostPortPair proxy_host_port_;
129  HostPortPair endpoint_host_port_pair_;
130  ProxyServer proxy_;
131  SpdySessionKey endpoint_spdy_session_key_;
132  scoped_refptr<TransportSocketParams> transport_params_;
133
134  DISALLOW_COPY_AND_ASSIGN(SpdyProxyClientSocketTest);
135};
136
137INSTANTIATE_TEST_CASE_P(
138    NextProto,
139    SpdyProxyClientSocketTest,
140    testing::Values(kProtoSPDY2, kProtoSPDY3, kProtoSPDY31, kProtoSPDY4a2));
141
142SpdyProxyClientSocketTest::SpdyProxyClientSocketTest()
143    : spdy_util_(GetParam()),
144      session_(NULL),
145      read_buf_(NULL),
146      session_deps_(GetParam()),
147      connect_data_(SYNCHRONOUS, OK),
148      spdy_session_(NULL),
149      framer_(spdy_util_.spdy_version(), false),
150      user_agent_(kUserAgent),
151      url_(kRequestUrl),
152      proxy_host_port_(kProxyHost, kProxyPort),
153      endpoint_host_port_pair_(kOriginHost, kOriginPort),
154      proxy_(ProxyServer::SCHEME_HTTPS, proxy_host_port_),
155      endpoint_spdy_session_key_(endpoint_host_port_pair_,
156                                 proxy_,
157                                 kPrivacyModeDisabled),
158      transport_params_(new TransportSocketParams(proxy_host_port_,
159                                                  LOWEST,
160                                                  false,
161                                                  false,
162                                                  OnHostResolutionCallback())) {
163  session_deps_.net_log = net_log_.bound().net_log();
164}
165
166void SpdyProxyClientSocketTest::TearDown() {
167  sock_.reset(NULL);
168  if (session_.get() != NULL)
169    session_->spdy_session_pool()->CloseAllSessions();
170
171  // Empty the current queue.
172  base::MessageLoop::current()->RunUntilIdle();
173  PlatformTest::TearDown();
174}
175
176void SpdyProxyClientSocketTest::Initialize(MockRead* reads,
177                                                size_t reads_count,
178                                                MockWrite* writes,
179                                                size_t writes_count) {
180  data_.reset(new DeterministicSocketData(reads, reads_count,
181                                          writes, writes_count));
182  data_->set_connect_data(connect_data_);
183  data_->SetStop(2);
184
185  session_deps_.deterministic_socket_factory->AddSocketDataProvider(
186      data_.get());
187  session_deps_.host_resolver->set_synchronous_mode(true);
188
189  session_ = SpdySessionDependencies::SpdyCreateSessionDeterministic(
190      &session_deps_);
191
192  // Creates a new spdy session.
193  spdy_session_ =
194      session_->spdy_session_pool()->Get(endpoint_spdy_session_key_,
195                                         net_log_.bound());
196
197  // Perform the TCP connect.
198  scoped_ptr<ClientSocketHandle> connection(new ClientSocketHandle);
199  EXPECT_EQ(OK,
200            connection->Init(endpoint_host_port_pair_.ToString(),
201                             transport_params_, LOWEST, CompletionCallback(),
202                             session_->GetTransportSocketPool(
203                                 HttpNetworkSession::NORMAL_SOCKET_POOL),
204                             net_log_.bound()));
205  spdy_session_->InitializeWithSocket(connection.release(), false, OK);
206
207  // Create the SPDY Stream.
208  base::WeakPtr<SpdyStream> spdy_stream(
209      CreateStreamSynchronously(
210          SPDY_BIDIRECTIONAL_STREAM, spdy_session_, url_, LOWEST,
211          net_log_.bound()));
212  ASSERT_TRUE(spdy_stream.get() != NULL);
213
214  // Create the SpdyProxyClientSocket.
215  sock_.reset(
216      new SpdyProxyClientSocket(spdy_stream, user_agent_,
217                                endpoint_host_port_pair_, url_,
218                                proxy_host_port_, net_log_.bound(),
219                                session_->http_auth_cache(),
220                                session_->http_auth_handler_factory()));
221}
222
223scoped_refptr<IOBufferWithSize> SpdyProxyClientSocketTest::CreateBuffer(
224    const char* data, int size) {
225  scoped_refptr<IOBufferWithSize> buf(new IOBufferWithSize(size));
226  memcpy(buf->data(), data, size);
227  return buf;
228}
229
230void SpdyProxyClientSocketTest::AssertConnectSucceeds() {
231  ASSERT_EQ(ERR_IO_PENDING, sock_->Connect(read_callback_.callback()));
232  data_->Run();
233  ASSERT_EQ(OK, read_callback_.WaitForResult());
234}
235
236void SpdyProxyClientSocketTest::AssertConnectFails(int result) {
237  ASSERT_EQ(ERR_IO_PENDING, sock_->Connect(read_callback_.callback()));
238  data_->Run();
239  ASSERT_EQ(result, read_callback_.WaitForResult());
240}
241
242void SpdyProxyClientSocketTest::AssertConnectionEstablished() {
243  const HttpResponseInfo* response = sock_->GetConnectResponseInfo();
244  ASSERT_TRUE(response != NULL);
245  ASSERT_EQ(200, response->headers->response_code());
246  ASSERT_EQ("Connection Established", response->headers->GetStatusText());
247}
248
249void SpdyProxyClientSocketTest::AssertSyncReadEquals(const char* data,
250                                                     int len) {
251  scoped_refptr<IOBuffer> buf(new IOBuffer(len));
252  ASSERT_EQ(len, sock_->Read(buf.get(), len, CompletionCallback()));
253  ASSERT_EQ(std::string(data, len), std::string(buf->data(), len));
254  ASSERT_TRUE(sock_->IsConnected());
255}
256
257void SpdyProxyClientSocketTest::AssertAsyncReadEquals(const char* data,
258                                                           int len) {
259  data_->StopAfter(1);
260  // Issue the read, which will be completed asynchronously
261  scoped_refptr<IOBuffer> buf(new IOBuffer(len));
262  ASSERT_EQ(ERR_IO_PENDING,
263            sock_->Read(buf.get(), len, read_callback_.callback()));
264  EXPECT_TRUE(sock_->IsConnected());
265  data_->Run();
266
267  EXPECT_TRUE(sock_->IsConnected());
268
269  // Now the read will return
270  EXPECT_EQ(len, read_callback_.WaitForResult());
271  ASSERT_EQ(std::string(data, len), std::string(buf->data(), len));
272}
273
274void SpdyProxyClientSocketTest::AssertReadStarts(const char* data,
275                                                      int len) {
276  data_->StopAfter(1);
277  // Issue the read, which will be completed asynchronously
278  read_buf_ = new IOBuffer(len);
279  ASSERT_EQ(ERR_IO_PENDING,
280            sock_->Read(read_buf_.get(), len, read_callback_.callback()));
281  EXPECT_TRUE(sock_->IsConnected());
282}
283
284void SpdyProxyClientSocketTest::AssertReadReturns(const char* data,
285                                                       int len) {
286  EXPECT_TRUE(sock_->IsConnected());
287
288  // Now the read will return
289  EXPECT_EQ(len, read_callback_.WaitForResult());
290  ASSERT_EQ(std::string(data, len), std::string(read_buf_->data(), len));
291}
292
293void SpdyProxyClientSocketTest::AssertAsyncWriteSucceeds(const char* data,
294                                                              int len) {
295  AssertWriteReturns(data, len, ERR_IO_PENDING);
296  data_->RunFor(1);
297  AssertWriteLength(len);
298}
299
300void SpdyProxyClientSocketTest::AssertWriteReturns(const char* data,
301                                                        int len,
302                                                        int rv) {
303  scoped_refptr<IOBufferWithSize> buf(CreateBuffer(data, len));
304  EXPECT_EQ(rv,
305            sock_->Write(buf.get(), buf->size(), write_callback_.callback()));
306}
307
308void SpdyProxyClientSocketTest::AssertWriteLength(int len) {
309  EXPECT_EQ(len, write_callback_.WaitForResult());
310}
311
312void SpdyProxyClientSocketTest::AssertAsyncWriteWithReadsSucceeds(
313    const char* data, int len, int num_reads) {
314  scoped_refptr<IOBufferWithSize> buf(CreateBuffer(data, len));
315
316  EXPECT_EQ(ERR_IO_PENDING,
317            sock_->Write(buf.get(), buf->size(), write_callback_.callback()));
318
319  for (int i = 0; i < num_reads; i++) {
320    Run(1);
321    AssertSyncReadEquals(kMsg2, kLen2);
322  }
323
324  write_callback_.WaitForResult();
325}
326
327// Constructs a standard SPDY SYN_STREAM frame for a CONNECT request.
328SpdyFrame*
329SpdyProxyClientSocketTest::ConstructConnectRequestFrame() {
330  const SpdyHeaderInfo kSynStartHeader = {
331    SYN_STREAM,
332    kStreamId,
333    0,
334    net::ConvertRequestPriorityToSpdyPriority(
335        LOWEST, spdy_util_.spdy_version()),
336    0,
337    CONTROL_FLAG_NONE,
338    false,
339    RST_STREAM_INVALID,
340    NULL,
341    0,
342    DATA_FLAG_NONE
343  };
344  bool spdy2 = spdy_util_.is_spdy2();
345  const char* const kConnectHeaders[] = {
346    spdy2 ? "method"  : ":method",  "CONNECT",
347    spdy2 ? "url"     : ":path",    kOriginHostPort,
348    spdy2 ? "host"    : ":host",    kOriginHost,
349    "user-agent", kUserAgent,
350    spdy2 ? "version" : ":version", "HTTP/1.1",
351  };
352  return spdy_util_.ConstructSpdyFrame(
353      kSynStartHeader, NULL, 0, kConnectHeaders, arraysize(kConnectHeaders)/2);
354}
355
356// Constructs a SPDY SYN_STREAM frame for a CONNECT request which includes
357// Proxy-Authorization headers.
358SpdyFrame*
359SpdyProxyClientSocketTest::ConstructConnectAuthRequestFrame() {
360  const SpdyHeaderInfo kSynStartHeader = {
361    SYN_STREAM,
362    kStreamId,
363    0,
364    net::ConvertRequestPriorityToSpdyPriority(
365        LOWEST, spdy_util_.spdy_version()),
366    0,
367    CONTROL_FLAG_NONE,
368    false,
369    RST_STREAM_INVALID,
370    NULL,
371    0,
372    DATA_FLAG_NONE
373  };
374  bool spdy2 = spdy_util_.is_spdy2();
375  const char* const kConnectHeaders[] = {
376    spdy2 ? "method"  : ":method",  "CONNECT",
377    spdy2 ? "url"     : ":path",    kOriginHostPort,
378    spdy2 ? "host"    : ":host",    kOriginHost,
379    "user-agent", kUserAgent,
380    spdy2 ? "version" : ":version", "HTTP/1.1",
381    "proxy-authorization", "Basic Zm9vOmJhcg==",
382  };
383  return spdy_util_.ConstructSpdyFrame(
384      kSynStartHeader, NULL, 0, kConnectHeaders, arraysize(kConnectHeaders)/2);
385}
386
387// Constructs a standard SPDY SYN_REPLY frame to match the SPDY CONNECT.
388SpdyFrame* SpdyProxyClientSocketTest::ConstructConnectReplyFrame() {
389  bool spdy2 = spdy_util_.is_spdy2();
390  const char* const kStandardReplyHeaders[] = {
391      spdy2 ? "status"  : ":status",  "200 Connection Established",
392      spdy2 ? "version" : ":version", "HTTP/1.1"
393  };
394  return spdy_util_.ConstructSpdyControlFrame(NULL,
395                                              0,
396                                              false,
397                                              kStreamId,
398                                              LOWEST,
399                                              SYN_REPLY,
400                                              CONTROL_FLAG_NONE,
401                                              kStandardReplyHeaders,
402                                              arraysize(kStandardReplyHeaders),
403                                              0);
404}
405
406// Constructs a standard SPDY SYN_REPLY frame to match the SPDY CONNECT.
407SpdyFrame*
408SpdyProxyClientSocketTest::ConstructConnectAuthReplyFrame() {
409  bool spdy2 = spdy_util_.is_spdy2();
410
411  const char* const kStandardReplyHeaders[] = {
412      spdy2 ? "status"  : ":status",  "407 Proxy Authentication Required",
413      spdy2 ? "version" : ":version", "HTTP/1.1",
414      "proxy-authenticate", "Basic realm=\"MyRealm1\"",
415  };
416
417  return spdy_util_.ConstructSpdyControlFrame(NULL,
418                                              0,
419                                              false,
420                                              kStreamId,
421                                              LOWEST,
422                                              SYN_REPLY,
423                                              CONTROL_FLAG_NONE,
424                                              kStandardReplyHeaders,
425                                              arraysize(kStandardReplyHeaders),
426                                              0);
427}
428
429// Constructs a SPDY SYN_REPLY frame with an HTTP 302 redirect.
430SpdyFrame*
431SpdyProxyClientSocketTest::ConstructConnectRedirectReplyFrame() {
432  bool spdy2 = spdy_util_.is_spdy2();
433
434  const char* const kStandardReplyHeaders[] = {
435      spdy2 ? "status"  : ":status",  "302 Found",
436      spdy2 ? "version" : ":version", "HTTP/1.1",
437      "location", kRedirectUrl,
438      "set-cookie", "foo=bar"
439  };
440
441  return spdy_util_.ConstructSpdyControlFrame(NULL,
442                                              0,
443                                              false,
444                                              kStreamId,
445                                              LOWEST,
446                                              SYN_REPLY,
447                                              CONTROL_FLAG_NONE,
448                                              kStandardReplyHeaders,
449                                              arraysize(kStandardReplyHeaders),
450                                              0);
451}
452
453// Constructs a SPDY SYN_REPLY frame with an HTTP 500 error.
454SpdyFrame*
455SpdyProxyClientSocketTest::ConstructConnectErrorReplyFrame() {
456  bool spdy2 = spdy_util_.is_spdy2();
457
458  const char* const kStandardReplyHeaders[] = {
459      spdy2 ? "status"  : ":status",  "500 Internal Server Error",
460      spdy2 ? "version" : ":version", "HTTP/1.1",
461  };
462
463  return spdy_util_.ConstructSpdyControlFrame(NULL,
464                                              0,
465                                              false,
466                                              kStreamId,
467                                              LOWEST,
468                                              SYN_REPLY,
469                                              CONTROL_FLAG_NONE,
470                                              kStandardReplyHeaders,
471                                              arraysize(kStandardReplyHeaders),
472                                              0);
473}
474
475SpdyFrame* SpdyProxyClientSocketTest::ConstructBodyFrame(
476    const char* data,
477    int length) {
478  return framer_.CreateDataFrame(kStreamId, data, length, DATA_FLAG_NONE);
479}
480
481// ----------- Connect
482
483TEST_P(SpdyProxyClientSocketTest, ConnectSendsCorrectRequest) {
484  scoped_ptr<SpdyFrame> conn(ConstructConnectRequestFrame());
485  MockWrite writes[] = {
486    CreateMockWrite(*conn, 0, SYNCHRONOUS),
487  };
488
489  scoped_ptr<SpdyFrame> resp(ConstructConnectReplyFrame());
490  MockRead reads[] = {
491    CreateMockRead(*resp, 1, ASYNC),
492    MockRead(ASYNC, 0, 2),  // EOF
493  };
494
495  Initialize(reads, arraysize(reads), writes, arraysize(writes));
496
497  ASSERT_FALSE(sock_->IsConnected());
498
499  AssertConnectSucceeds();
500
501  AssertConnectionEstablished();
502}
503
504TEST_P(SpdyProxyClientSocketTest, ConnectWithAuthRequested) {
505  scoped_ptr<SpdyFrame> conn(ConstructConnectRequestFrame());
506  MockWrite writes[] = {
507    CreateMockWrite(*conn, 0, SYNCHRONOUS),
508  };
509
510  scoped_ptr<SpdyFrame> resp(ConstructConnectAuthReplyFrame());
511  MockRead reads[] = {
512    CreateMockRead(*resp, 1, ASYNC),
513    MockRead(ASYNC, 0, 2),  // EOF
514  };
515
516  Initialize(reads, arraysize(reads), writes, arraysize(writes));
517
518  AssertConnectFails(ERR_PROXY_AUTH_REQUESTED);
519
520  const HttpResponseInfo* response = sock_->GetConnectResponseInfo();
521  ASSERT_TRUE(response != NULL);
522  ASSERT_EQ(407, response->headers->response_code());
523  ASSERT_EQ("Proxy Authentication Required",
524            response->headers->GetStatusText());
525}
526
527TEST_P(SpdyProxyClientSocketTest, ConnectWithAuthCredentials) {
528  scoped_ptr<SpdyFrame> conn(ConstructConnectAuthRequestFrame());
529  MockWrite writes[] = {
530    CreateMockWrite(*conn, 0, SYNCHRONOUS),
531  };
532
533  scoped_ptr<SpdyFrame> resp(ConstructConnectReplyFrame());
534  MockRead reads[] = {
535    CreateMockRead(*resp, 1, ASYNC),
536    MockRead(ASYNC, 0, 2),  // EOF
537  };
538
539  Initialize(reads, arraysize(reads), writes, arraysize(writes));
540  AddAuthToCache();
541
542  AssertConnectSucceeds();
543
544  AssertConnectionEstablished();
545}
546
547TEST_P(SpdyProxyClientSocketTest, ConnectRedirects) {
548  scoped_ptr<SpdyFrame> conn(ConstructConnectRequestFrame());
549  MockWrite writes[] = {
550    CreateMockWrite(*conn, 0, SYNCHRONOUS),
551  };
552
553  scoped_ptr<SpdyFrame> resp(ConstructConnectRedirectReplyFrame());
554  MockRead reads[] = {
555    CreateMockRead(*resp, 1, ASYNC),
556    MockRead(ASYNC, 0, 2),  // EOF
557  };
558
559  Initialize(reads, arraysize(reads), writes, arraysize(writes));
560
561  AssertConnectFails(ERR_HTTPS_PROXY_TUNNEL_RESPONSE);
562
563  const HttpResponseInfo* response = sock_->GetConnectResponseInfo();
564  ASSERT_TRUE(response != NULL);
565
566  const HttpResponseHeaders* headers = response->headers.get();
567  ASSERT_EQ(302, headers->response_code());
568  ASSERT_FALSE(headers->HasHeader("set-cookie"));
569  ASSERT_TRUE(headers->HasHeaderValue("content-length", "0"));
570
571  std::string location;
572  ASSERT_TRUE(headers->IsRedirect(&location));
573  ASSERT_EQ(location, kRedirectUrl);
574}
575
576TEST_P(SpdyProxyClientSocketTest, ConnectFails) {
577  scoped_ptr<SpdyFrame> conn(ConstructConnectRequestFrame());
578  MockWrite writes[] = {
579    CreateMockWrite(*conn, 0, SYNCHRONOUS),
580  };
581
582  scoped_ptr<SpdyFrame> resp(ConstructConnectReplyFrame());
583  MockRead reads[] = {
584    MockRead(ASYNC, 0, 1),  // EOF
585  };
586
587  Initialize(reads, arraysize(reads), writes, arraysize(writes));
588
589  ASSERT_FALSE(sock_->IsConnected());
590
591  AssertConnectFails(ERR_CONNECTION_CLOSED);
592
593  ASSERT_FALSE(sock_->IsConnected());
594}
595
596// ----------- WasEverUsed
597
598TEST_P(SpdyProxyClientSocketTest, WasEverUsedReturnsCorrectValues) {
599  scoped_ptr<SpdyFrame> conn(ConstructConnectRequestFrame());
600  MockWrite writes[] = {
601    CreateMockWrite(*conn, 0, SYNCHRONOUS),
602  };
603
604  scoped_ptr<SpdyFrame> resp(ConstructConnectReplyFrame());
605  MockRead reads[] = {
606    CreateMockRead(*resp, 1, ASYNC),
607    MockRead(ASYNC, 0, 2),  // EOF
608  };
609
610  Initialize(reads, arraysize(reads), writes, arraysize(writes));
611
612  EXPECT_FALSE(sock_->WasEverUsed());
613  AssertConnectSucceeds();
614  EXPECT_TRUE(sock_->WasEverUsed());
615  sock_->Disconnect();
616  EXPECT_TRUE(sock_->WasEverUsed());
617}
618
619// ----------- GetPeerAddress
620
621TEST_P(SpdyProxyClientSocketTest, GetPeerAddressReturnsCorrectValues) {
622  scoped_ptr<SpdyFrame> conn(ConstructConnectRequestFrame());
623  MockWrite writes[] = {
624    CreateMockWrite(*conn, 0, SYNCHRONOUS),
625  };
626
627  scoped_ptr<SpdyFrame> resp(ConstructConnectReplyFrame());
628  MockRead reads[] = {
629    CreateMockRead(*resp, 1, ASYNC),
630    MockRead(ASYNC, 0, 2),  // EOF
631  };
632
633  Initialize(reads, arraysize(reads), writes, arraysize(writes));
634
635  net::IPEndPoint addr;
636  EXPECT_EQ(ERR_SOCKET_NOT_CONNECTED, sock_->GetPeerAddress(&addr));
637
638  AssertConnectSucceeds();
639  EXPECT_TRUE(sock_->IsConnected());
640  EXPECT_EQ(OK, sock_->GetPeerAddress(&addr));
641
642  Run(1);
643
644  EXPECT_FALSE(sock_->IsConnected());
645  EXPECT_EQ(ERR_SOCKET_NOT_CONNECTED, sock_->GetPeerAddress(&addr));
646
647  sock_->Disconnect();
648
649  EXPECT_EQ(ERR_SOCKET_NOT_CONNECTED, sock_->GetPeerAddress(&addr));
650}
651
652// ----------- Write
653
654TEST_P(SpdyProxyClientSocketTest, WriteSendsDataInDataFrame) {
655  scoped_ptr<SpdyFrame> conn(ConstructConnectRequestFrame());
656  scoped_ptr<SpdyFrame> msg1(ConstructBodyFrame(kMsg1, kLen1));
657  scoped_ptr<SpdyFrame> msg2(ConstructBodyFrame(kMsg2, kLen2));
658  MockWrite writes[] = {
659    CreateMockWrite(*conn, 0, SYNCHRONOUS),
660    CreateMockWrite(*msg1, 2, SYNCHRONOUS),
661    CreateMockWrite(*msg2, 3, SYNCHRONOUS),
662  };
663
664  scoped_ptr<SpdyFrame> resp(ConstructConnectReplyFrame());
665  MockRead reads[] = {
666    CreateMockRead(*resp, 1, ASYNC),
667    MockRead(ASYNC, 0, 4),  // EOF
668  };
669
670  Initialize(reads, arraysize(reads), writes, arraysize(writes));
671
672  AssertConnectSucceeds();
673
674  AssertAsyncWriteSucceeds(kMsg1, kLen1);
675  AssertAsyncWriteSucceeds(kMsg2, kLen2);
676}
677
678TEST_P(SpdyProxyClientSocketTest, WriteSplitsLargeDataIntoMultipleFrames) {
679  std::string chunk_data(kMaxSpdyFrameChunkSize, 'x');
680  scoped_ptr<SpdyFrame> conn(ConstructConnectRequestFrame());
681  scoped_ptr<SpdyFrame> chunk(ConstructBodyFrame(chunk_data.data(),
682                                                       chunk_data.length()));
683  MockWrite writes[] = {
684    CreateMockWrite(*conn, 0, SYNCHRONOUS),
685    CreateMockWrite(*chunk, 2, SYNCHRONOUS),
686    CreateMockWrite(*chunk, 3, SYNCHRONOUS),
687    CreateMockWrite(*chunk, 4, SYNCHRONOUS)
688  };
689
690  scoped_ptr<SpdyFrame> resp(ConstructConnectReplyFrame());
691  MockRead reads[] = {
692    CreateMockRead(*resp, 1, ASYNC),
693    MockRead(ASYNC, 0, 5),  // EOF
694  };
695
696  Initialize(reads, arraysize(reads), writes, arraysize(writes));
697
698  AssertConnectSucceeds();
699
700  std::string big_data(kMaxSpdyFrameChunkSize * 3, 'x');
701  scoped_refptr<IOBufferWithSize> buf(CreateBuffer(big_data.data(),
702                                                   big_data.length()));
703
704  EXPECT_EQ(ERR_IO_PENDING,
705            sock_->Write(buf.get(), buf->size(), write_callback_.callback()));
706  data_->RunFor(3);
707
708  EXPECT_EQ(buf->size(), write_callback_.WaitForResult());
709}
710
711// ----------- Read
712
713TEST_P(SpdyProxyClientSocketTest, ReadReadsDataInDataFrame) {
714  scoped_ptr<SpdyFrame> conn(ConstructConnectRequestFrame());
715  MockWrite writes[] = {
716    CreateMockWrite(*conn, 0, SYNCHRONOUS),
717  };
718
719  scoped_ptr<SpdyFrame> resp(ConstructConnectReplyFrame());
720  scoped_ptr<SpdyFrame> msg1(ConstructBodyFrame(kMsg1, kLen1));
721  MockRead reads[] = {
722    CreateMockRead(*resp, 1, ASYNC),
723    CreateMockRead(*msg1, 2, ASYNC),
724    MockRead(ASYNC, 0, 3),  // EOF
725  };
726
727  Initialize(reads, arraysize(reads), writes, arraysize(writes));
728
729  AssertConnectSucceeds();
730
731  Run(1);  // SpdySession consumes the next read and sends it to
732           // sock_ to be buffered.
733  AssertSyncReadEquals(kMsg1, kLen1);
734}
735
736TEST_P(SpdyProxyClientSocketTest, ReadDataFromBufferedFrames) {
737  scoped_ptr<SpdyFrame> conn(ConstructConnectRequestFrame());
738  MockWrite writes[] = {
739    CreateMockWrite(*conn, 0, SYNCHRONOUS),
740  };
741
742  scoped_ptr<SpdyFrame> resp(ConstructConnectReplyFrame());
743  scoped_ptr<SpdyFrame> msg1(ConstructBodyFrame(kMsg1, kLen1));
744  scoped_ptr<SpdyFrame> msg2(ConstructBodyFrame(kMsg2, kLen2));
745  MockRead reads[] = {
746    CreateMockRead(*resp, 1, ASYNC),
747    CreateMockRead(*msg1, 2, ASYNC),
748    CreateMockRead(*msg2, 3, ASYNC),
749    MockRead(ASYNC, 0, 4),  // EOF
750  };
751
752  Initialize(reads, arraysize(reads), writes, arraysize(writes));
753
754  AssertConnectSucceeds();
755
756  Run(1);  // SpdySession consumes the next read and sends it to
757           // sock_ to be buffered.
758  AssertSyncReadEquals(kMsg1, kLen1);
759  Run(1);  // SpdySession consumes the next read and sends it to
760           // sock_ to be buffered.
761  AssertSyncReadEquals(kMsg2, kLen2);
762}
763
764TEST_P(SpdyProxyClientSocketTest, ReadDataMultipleBufferedFrames) {
765  scoped_ptr<SpdyFrame> conn(ConstructConnectRequestFrame());
766  MockWrite writes[] = {
767    CreateMockWrite(*conn, 0, SYNCHRONOUS),
768  };
769
770  scoped_ptr<SpdyFrame> resp(ConstructConnectReplyFrame());
771  scoped_ptr<SpdyFrame> msg1(ConstructBodyFrame(kMsg1, kLen1));
772  scoped_ptr<SpdyFrame> msg2(ConstructBodyFrame(kMsg2, kLen2));
773  MockRead reads[] = {
774    CreateMockRead(*resp, 1, ASYNC),
775    CreateMockRead(*msg1, 2, ASYNC),
776    CreateMockRead(*msg2, 3, ASYNC),
777    MockRead(ASYNC, 0, 4),  // EOF
778  };
779
780  Initialize(reads, arraysize(reads), writes, arraysize(writes));
781
782  AssertConnectSucceeds();
783
784  Run(2);  // SpdySession consumes the next two reads and sends then to
785           // sock_ to be buffered.
786  AssertSyncReadEquals(kMsg1, kLen1);
787  AssertSyncReadEquals(kMsg2, kLen2);
788}
789
790TEST_P(SpdyProxyClientSocketTest,
791       LargeReadWillMergeDataFromDifferentFrames) {
792  scoped_ptr<SpdyFrame> conn(ConstructConnectRequestFrame());
793  MockWrite writes[] = {
794    CreateMockWrite(*conn, 0, SYNCHRONOUS),
795  };
796
797  scoped_ptr<SpdyFrame> resp(ConstructConnectReplyFrame());
798  scoped_ptr<SpdyFrame> msg1(ConstructBodyFrame(kMsg1, kLen1));
799  scoped_ptr<SpdyFrame> msg3(ConstructBodyFrame(kMsg3, kLen3));
800  MockRead reads[] = {
801    CreateMockRead(*resp, 1, ASYNC),
802    CreateMockRead(*msg3, 2, ASYNC),
803    CreateMockRead(*msg3, 3, ASYNC),
804    MockRead(ASYNC, 0, 4),  // EOF
805  };
806
807  Initialize(reads, arraysize(reads), writes, arraysize(writes));
808
809  AssertConnectSucceeds();
810
811  Run(2);  // SpdySession consumes the next two reads and sends then to
812           // sock_ to be buffered.
813  // The payload from two data frames, each with kMsg3 will be combined
814  // together into a single read().
815  AssertSyncReadEquals(kMsg33, kLen33);
816}
817
818TEST_P(SpdyProxyClientSocketTest, MultipleShortReadsThenMoreRead) {
819  scoped_ptr<SpdyFrame> conn(ConstructConnectRequestFrame());
820  MockWrite writes[] = {
821    CreateMockWrite(*conn, 0, SYNCHRONOUS),
822  };
823
824  scoped_ptr<SpdyFrame> resp(ConstructConnectReplyFrame());
825  scoped_ptr<SpdyFrame> msg1(ConstructBodyFrame(kMsg1, kLen1));
826  scoped_ptr<SpdyFrame> msg3(ConstructBodyFrame(kMsg3, kLen3));
827  scoped_ptr<SpdyFrame> msg2(ConstructBodyFrame(kMsg2, kLen2));
828  MockRead reads[] = {
829    CreateMockRead(*resp, 1, ASYNC),
830    CreateMockRead(*msg1, 2, ASYNC),
831    CreateMockRead(*msg3, 3, ASYNC),
832    CreateMockRead(*msg3, 4, ASYNC),
833    CreateMockRead(*msg2, 5, ASYNC),
834    MockRead(ASYNC, 0, 6),  // EOF
835  };
836
837  Initialize(reads, arraysize(reads), writes, arraysize(writes));
838
839  AssertConnectSucceeds();
840
841  Run(4);  // SpdySession consumes the next four reads and sends then to
842           // sock_ to be buffered.
843  AssertSyncReadEquals(kMsg1, kLen1);
844  // The payload from two data frames, each with kMsg3 will be combined
845  // together into a single read().
846  AssertSyncReadEquals(kMsg33, kLen33);
847  AssertSyncReadEquals(kMsg2, kLen2);
848}
849
850TEST_P(SpdyProxyClientSocketTest, ReadWillSplitDataFromLargeFrame) {
851  scoped_ptr<SpdyFrame> conn(ConstructConnectRequestFrame());
852  MockWrite writes[] = {
853    CreateMockWrite(*conn, 0, SYNCHRONOUS),
854  };
855
856  scoped_ptr<SpdyFrame> resp(ConstructConnectReplyFrame());
857  scoped_ptr<SpdyFrame> msg1(ConstructBodyFrame(kMsg1, kLen1));
858  scoped_ptr<SpdyFrame> msg33(ConstructBodyFrame(kMsg33, kLen33));
859  scoped_ptr<SpdyFrame> msg2(ConstructBodyFrame(kMsg2, kLen2));
860  MockRead reads[] = {
861    CreateMockRead(*resp, 1, ASYNC),
862    CreateMockRead(*msg1, 2, ASYNC),
863    CreateMockRead(*msg33, 3, ASYNC),
864    MockRead(ASYNC, 0, 4),  // EOF
865  };
866
867  Initialize(reads, arraysize(reads), writes, arraysize(writes));
868
869  AssertConnectSucceeds();
870
871  Run(2);  // SpdySession consumes the next two reads and sends then to
872           // sock_ to be buffered.
873  AssertSyncReadEquals(kMsg1, kLen1);
874  // The payload from the single large data frame will be read across
875  // two different reads.
876  AssertSyncReadEquals(kMsg3, kLen3);
877  AssertSyncReadEquals(kMsg3, kLen3);
878}
879
880TEST_P(SpdyProxyClientSocketTest, MultipleReadsFromSameLargeFrame) {
881  scoped_ptr<SpdyFrame> conn(ConstructConnectRequestFrame());
882  MockWrite writes[] = {
883    CreateMockWrite(*conn, 0, SYNCHRONOUS),
884  };
885
886  scoped_ptr<SpdyFrame> resp(ConstructConnectReplyFrame());
887  scoped_ptr<SpdyFrame> msg333(ConstructBodyFrame(kMsg333, kLen333));
888  MockRead reads[] = {
889    CreateMockRead(*resp, 1, ASYNC),
890    CreateMockRead(*msg333, 2, ASYNC),
891    MockRead(ASYNC, 0, 3),  // EOF
892  };
893
894  Initialize(reads, arraysize(reads), writes, arraysize(writes));
895
896  AssertConnectSucceeds();
897
898  Run(1);  // SpdySession consumes the next read and sends it to
899           // sock_ to be buffered.
900  // The payload from the single large data frame will be read across
901  // two different reads.
902  AssertSyncReadEquals(kMsg33, kLen33);
903
904  // Now attempt to do a read of more data than remains buffered
905  scoped_refptr<IOBuffer> buf(new IOBuffer(kLen33));
906  ASSERT_EQ(kLen3, sock_->Read(buf.get(), kLen33, read_callback_.callback()));
907  ASSERT_EQ(std::string(kMsg3, kLen3), std::string(buf->data(), kLen3));
908  ASSERT_TRUE(sock_->IsConnected());
909}
910
911TEST_P(SpdyProxyClientSocketTest, ReadAuthResponseBody) {
912  scoped_ptr<SpdyFrame> conn(ConstructConnectRequestFrame());
913  MockWrite writes[] = {
914    CreateMockWrite(*conn, 0, SYNCHRONOUS),
915  };
916
917  scoped_ptr<SpdyFrame> resp(ConstructConnectAuthReplyFrame());
918  scoped_ptr<SpdyFrame> msg1(ConstructBodyFrame(kMsg1, kLen1));
919  scoped_ptr<SpdyFrame> msg2(ConstructBodyFrame(kMsg2, kLen2));
920  MockRead reads[] = {
921    CreateMockRead(*resp, 1, ASYNC),
922    CreateMockRead(*msg1, 2, ASYNC),
923    CreateMockRead(*msg2, 3, ASYNC),
924    MockRead(ASYNC, 0, 4),  // EOF
925  };
926
927  Initialize(reads, arraysize(reads), writes, arraysize(writes));
928
929  AssertConnectFails(ERR_PROXY_AUTH_REQUESTED);
930
931  Run(2);  // SpdySession consumes the next two reads and sends then to
932           // sock_ to be buffered.
933  AssertSyncReadEquals(kMsg1, kLen1);
934  AssertSyncReadEquals(kMsg2, kLen2);
935}
936
937TEST_P(SpdyProxyClientSocketTest, ReadErrorResponseBody) {
938  scoped_ptr<SpdyFrame> conn(ConstructConnectRequestFrame());
939  MockWrite writes[] = {
940    CreateMockWrite(*conn, 0, SYNCHRONOUS),
941  };
942
943  scoped_ptr<SpdyFrame> resp(ConstructConnectErrorReplyFrame());
944  scoped_ptr<SpdyFrame> msg1(ConstructBodyFrame(kMsg1, kLen1));
945  scoped_ptr<SpdyFrame> msg2(ConstructBodyFrame(kMsg2, kLen2));
946  MockRead reads[] = {
947    CreateMockRead(*resp, 1, ASYNC),
948    CreateMockRead(*msg1, 2, ASYNC),
949    CreateMockRead(*msg2, 3, ASYNC),
950    MockRead(ASYNC, 0, 4),  // EOF
951  };
952
953  Initialize(reads, arraysize(reads), writes, arraysize(writes));
954
955  AssertConnectFails(ERR_TUNNEL_CONNECTION_FAILED);
956}
957
958// ----------- Reads and Writes
959
960TEST_P(SpdyProxyClientSocketTest, AsyncReadAroundWrite) {
961  scoped_ptr<SpdyFrame> conn(ConstructConnectRequestFrame());
962  scoped_ptr<SpdyFrame> msg2(ConstructBodyFrame(kMsg2, kLen2));
963  MockWrite writes[] = {
964    CreateMockWrite(*conn, 0, SYNCHRONOUS),
965    CreateMockWrite(*msg2, 3, SYNCHRONOUS),
966  };
967
968  scoped_ptr<SpdyFrame> resp(ConstructConnectReplyFrame());
969  scoped_ptr<SpdyFrame> msg1(ConstructBodyFrame(kMsg1, kLen1));
970  scoped_ptr<SpdyFrame> msg3(ConstructBodyFrame(kMsg3, kLen3));
971  MockRead reads[] = {
972    CreateMockRead(*resp, 1, ASYNC),
973    CreateMockRead(*msg1, 2, ASYNC),  // sync read
974    CreateMockRead(*msg3, 4, ASYNC),  // async read
975    MockRead(ASYNC, 0, 5),  // EOF
976  };
977
978  Initialize(reads, arraysize(reads), writes, arraysize(writes));
979
980  AssertConnectSucceeds();
981
982  Run(1);
983  AssertSyncReadEquals(kMsg1, kLen1);
984
985  AssertReadStarts(kMsg3, kLen3);
986  // Read should block until after the write succeeds
987
988  AssertAsyncWriteSucceeds(kMsg2, kLen2);  // Runs 1 step
989
990  ASSERT_FALSE(read_callback_.have_result());
991  Run(1);
992  // Now the read will return
993  AssertReadReturns(kMsg3, kLen3);
994}
995
996TEST_P(SpdyProxyClientSocketTest, AsyncWriteAroundReads) {
997  scoped_ptr<SpdyFrame> conn(ConstructConnectRequestFrame());
998  scoped_ptr<SpdyFrame> msg2(ConstructBodyFrame(kMsg2, kLen2));
999  MockWrite writes[] = {
1000    CreateMockWrite(*conn, 0, SYNCHRONOUS),
1001    CreateMockWrite(*msg2, 4, ASYNC),
1002  };
1003
1004  scoped_ptr<SpdyFrame> resp(ConstructConnectReplyFrame());
1005  scoped_ptr<SpdyFrame> msg1(ConstructBodyFrame(kMsg1, kLen1));
1006  scoped_ptr<SpdyFrame> msg3(ConstructBodyFrame(kMsg3, kLen3));
1007  MockRead reads[] = {
1008    CreateMockRead(*resp, 1, ASYNC),
1009    CreateMockRead(*msg1, 2, ASYNC),
1010    CreateMockRead(*msg3, 3, ASYNC),
1011    MockRead(ASYNC, 0, 5),  // EOF
1012  };
1013
1014  Initialize(reads, arraysize(reads), writes, arraysize(writes));
1015
1016  AssertConnectSucceeds();
1017
1018  Run(1);
1019  AssertSyncReadEquals(kMsg1, kLen1);
1020  // Write should block until the read completes
1021  AssertWriteReturns(kMsg2, kLen2, ERR_IO_PENDING);
1022
1023  AssertAsyncReadEquals(kMsg3, kLen3);
1024
1025  ASSERT_FALSE(write_callback_.have_result());
1026
1027  // Now the write will complete
1028  Run(1);
1029  AssertWriteLength(kLen2);
1030}
1031
1032// ----------- Reading/Writing on Closed socket
1033
1034// Reading from an already closed socket should return 0
1035TEST_P(SpdyProxyClientSocketTest, ReadOnClosedSocketReturnsZero) {
1036  scoped_ptr<SpdyFrame> conn(ConstructConnectRequestFrame());
1037  MockWrite writes[] = {
1038    CreateMockWrite(*conn, 0, SYNCHRONOUS),
1039  };
1040
1041  scoped_ptr<SpdyFrame> resp(ConstructConnectReplyFrame());
1042  MockRead reads[] = {
1043    CreateMockRead(*resp, 1, ASYNC),
1044    MockRead(ASYNC, 0, 2),  // EOF
1045  };
1046
1047  Initialize(reads, arraysize(reads), writes, arraysize(writes));
1048
1049  AssertConnectSucceeds();
1050
1051  Run(1);
1052
1053  ASSERT_FALSE(sock_->IsConnected());
1054  ASSERT_EQ(0, sock_->Read(NULL, 1, CompletionCallback()));
1055  ASSERT_EQ(0, sock_->Read(NULL, 1, CompletionCallback()));
1056  ASSERT_EQ(0, sock_->Read(NULL, 1, CompletionCallback()));
1057  ASSERT_FALSE(sock_->IsConnectedAndIdle());
1058}
1059
1060// Read pending when socket is closed should return 0
1061TEST_P(SpdyProxyClientSocketTest, PendingReadOnCloseReturnsZero) {
1062  scoped_ptr<SpdyFrame> conn(ConstructConnectRequestFrame());
1063  MockWrite writes[] = {
1064    CreateMockWrite(*conn, 0, SYNCHRONOUS),
1065  };
1066
1067  scoped_ptr<SpdyFrame> resp(ConstructConnectReplyFrame());
1068  MockRead reads[] = {
1069    CreateMockRead(*resp, 1, ASYNC),
1070    MockRead(ASYNC, 0, 2),  // EOF
1071  };
1072
1073  Initialize(reads, arraysize(reads), writes, arraysize(writes));
1074
1075  AssertConnectSucceeds();
1076
1077  AssertReadStarts(kMsg1, kLen1);
1078
1079  Run(1);
1080
1081  ASSERT_EQ(0, read_callback_.WaitForResult());
1082}
1083
1084// Reading from a disconnected socket is an error
1085TEST_P(SpdyProxyClientSocketTest,
1086       ReadOnDisconnectSocketReturnsNotConnected) {
1087  scoped_ptr<SpdyFrame> conn(ConstructConnectRequestFrame());
1088  MockWrite writes[] = {
1089    CreateMockWrite(*conn, 0, SYNCHRONOUS),
1090  };
1091
1092  scoped_ptr<SpdyFrame> resp(ConstructConnectReplyFrame());
1093  MockRead reads[] = {
1094    CreateMockRead(*resp, 1, ASYNC),
1095    MockRead(ASYNC, 0, 2),  // EOF
1096  };
1097
1098  Initialize(reads, arraysize(reads), writes, arraysize(writes));
1099
1100  AssertConnectSucceeds();
1101
1102  sock_->Disconnect();
1103
1104  ASSERT_EQ(ERR_SOCKET_NOT_CONNECTED,
1105            sock_->Read(NULL, 1, CompletionCallback()));
1106}
1107
1108// Reading buffered data from an already closed socket should return
1109// buffered data, then 0.
1110TEST_P(SpdyProxyClientSocketTest, ReadOnClosedSocketReturnsBufferedData) {
1111  scoped_ptr<SpdyFrame> conn(ConstructConnectRequestFrame());
1112  MockWrite writes[] = {
1113    CreateMockWrite(*conn, 0, SYNCHRONOUS),
1114  };
1115
1116  scoped_ptr<SpdyFrame> resp(ConstructConnectReplyFrame());
1117  scoped_ptr<SpdyFrame> msg1(ConstructBodyFrame(kMsg1, kLen1));
1118  MockRead reads[] = {
1119    CreateMockRead(*resp, 1, ASYNC),
1120    CreateMockRead(*msg1, 2, ASYNC),
1121    MockRead(ASYNC, 0, 3),  // EOF
1122  };
1123
1124  Initialize(reads, arraysize(reads), writes, arraysize(writes));
1125
1126  AssertConnectSucceeds();
1127
1128  Run(2);
1129
1130  ASSERT_FALSE(sock_->IsConnected());
1131  scoped_refptr<IOBuffer> buf(new IOBuffer(kLen1));
1132  ASSERT_EQ(kLen1, sock_->Read(buf.get(), kLen1, CompletionCallback()));
1133  ASSERT_EQ(std::string(kMsg1, kLen1), std::string(buf->data(), kLen1));
1134
1135  ASSERT_EQ(0, sock_->Read(NULL, 1, CompletionCallback()));
1136  ASSERT_EQ(0, sock_->Read(NULL, 1, CompletionCallback()));
1137  sock_->Disconnect();
1138  ASSERT_EQ(ERR_SOCKET_NOT_CONNECTED,
1139            sock_->Read(NULL, 1, CompletionCallback()));
1140}
1141
1142// Calling Write() on a closed socket is an error
1143TEST_P(SpdyProxyClientSocketTest, WriteOnClosedStream) {
1144  scoped_ptr<SpdyFrame> conn(ConstructConnectRequestFrame());
1145  MockWrite writes[] = {
1146    CreateMockWrite(*conn, 0, SYNCHRONOUS),
1147  };
1148
1149  scoped_ptr<SpdyFrame> resp(ConstructConnectReplyFrame());
1150  scoped_ptr<SpdyFrame> msg1(ConstructBodyFrame(kMsg1, kLen1));
1151  MockRead reads[] = {
1152    CreateMockRead(*resp, 1, ASYNC),
1153    MockRead(ASYNC, 0, 2),  // EOF
1154  };
1155
1156  Initialize(reads, arraysize(reads), writes, arraysize(writes));
1157
1158  AssertConnectSucceeds();
1159
1160  Run(1);  // Read EOF which will close the stream
1161  scoped_refptr<IOBufferWithSize> buf(CreateBuffer(kMsg1, kLen1));
1162  EXPECT_EQ(ERR_SOCKET_NOT_CONNECTED,
1163            sock_->Write(buf.get(), buf->size(), CompletionCallback()));
1164}
1165
1166// Calling Write() on a disconnected socket is an error
1167TEST_P(SpdyProxyClientSocketTest, WriteOnDisconnectedSocket) {
1168  scoped_ptr<SpdyFrame> conn(ConstructConnectRequestFrame());
1169  MockWrite writes[] = {
1170    CreateMockWrite(*conn, 0, SYNCHRONOUS),
1171  };
1172
1173  scoped_ptr<SpdyFrame> resp(ConstructConnectReplyFrame());
1174  scoped_ptr<SpdyFrame> msg1(ConstructBodyFrame(kMsg1, kLen1));
1175  MockRead reads[] = {
1176    CreateMockRead(*resp, 1, ASYNC),
1177    MockRead(ASYNC, 0, 2),  // EOF
1178  };
1179
1180  Initialize(reads, arraysize(reads), writes, arraysize(writes));
1181
1182  AssertConnectSucceeds();
1183
1184  sock_->Disconnect();
1185
1186  scoped_refptr<IOBufferWithSize> buf(CreateBuffer(kMsg1, kLen1));
1187  EXPECT_EQ(ERR_SOCKET_NOT_CONNECTED,
1188            sock_->Write(buf.get(), buf->size(), CompletionCallback()));
1189}
1190
1191// If the socket is closed with a pending Write(), the callback
1192// should be called with ERR_CONNECTION_CLOSED.
1193TEST_P(SpdyProxyClientSocketTest, WritePendingOnClose) {
1194  scoped_ptr<SpdyFrame> conn(ConstructConnectRequestFrame());
1195  MockWrite writes[] = {
1196    CreateMockWrite(*conn, 0, SYNCHRONOUS),
1197    MockWrite(ASYNC, ERR_IO_PENDING, 2),
1198  };
1199
1200  scoped_ptr<SpdyFrame> resp(ConstructConnectReplyFrame());
1201  MockRead reads[] = {
1202    CreateMockRead(*resp, 1, ASYNC),
1203    MockRead(ASYNC, 0, 3),  // EOF
1204  };
1205
1206  Initialize(reads, arraysize(reads), writes, arraysize(writes));
1207
1208  AssertConnectSucceeds();
1209
1210  EXPECT_TRUE(sock_->IsConnected());
1211
1212  scoped_refptr<IOBufferWithSize> buf(CreateBuffer(kMsg1, kLen1));
1213  EXPECT_EQ(ERR_IO_PENDING,
1214            sock_->Write(buf.get(), buf->size(), write_callback_.callback()));
1215
1216  Run(1);
1217
1218  EXPECT_EQ(ERR_CONNECTION_CLOSED, write_callback_.WaitForResult());
1219}
1220
1221// If the socket is Disconnected with a pending Write(), the callback
1222// should not be called.
1223TEST_P(SpdyProxyClientSocketTest, DisconnectWithWritePending) {
1224  scoped_ptr<SpdyFrame> conn(ConstructConnectRequestFrame());
1225  MockWrite writes[] = {
1226    CreateMockWrite(*conn, 0, SYNCHRONOUS),
1227    MockWrite(SYNCHRONOUS, 0, 2),  // EOF
1228  };
1229
1230  scoped_ptr<SpdyFrame> resp(ConstructConnectReplyFrame());
1231  MockRead reads[] = {
1232    CreateMockRead(*resp, 1, ASYNC),
1233    MockRead(ASYNC, 0, 3),  // EOF
1234  };
1235
1236  Initialize(reads, arraysize(reads), writes, arraysize(writes));
1237
1238  AssertConnectSucceeds();
1239
1240  EXPECT_TRUE(sock_->IsConnected());
1241
1242  scoped_refptr<IOBufferWithSize> buf(CreateBuffer(kMsg1, kLen1));
1243  EXPECT_EQ(ERR_IO_PENDING,
1244            sock_->Write(buf.get(), buf->size(), write_callback_.callback()));
1245
1246  sock_->Disconnect();
1247
1248  EXPECT_FALSE(sock_->IsConnected());
1249  EXPECT_FALSE(write_callback_.have_result());
1250}
1251
1252// If the socket is Disconnected with a pending Read(), the callback
1253// should not be called.
1254TEST_P(SpdyProxyClientSocketTest, DisconnectWithReadPending) {
1255  scoped_ptr<SpdyFrame> conn(ConstructConnectRequestFrame());
1256  MockWrite writes[] = {
1257    CreateMockWrite(*conn, 0, SYNCHRONOUS),
1258  };
1259
1260  scoped_ptr<SpdyFrame> resp(ConstructConnectReplyFrame());
1261  MockRead reads[] = {
1262    CreateMockRead(*resp, 1, ASYNC),
1263    MockRead(ASYNC, 0, 2),  // EOF
1264  };
1265
1266  Initialize(reads, arraysize(reads), writes, arraysize(writes));
1267
1268  AssertConnectSucceeds();
1269
1270  EXPECT_TRUE(sock_->IsConnected());
1271
1272  scoped_refptr<IOBuffer> buf(new IOBuffer(kLen1));
1273  ASSERT_EQ(ERR_IO_PENDING,
1274            sock_->Read(buf.get(), kLen1, read_callback_.callback()));
1275
1276  sock_->Disconnect();
1277
1278  EXPECT_FALSE(sock_->IsConnected());
1279  EXPECT_FALSE(read_callback_.have_result());
1280}
1281
1282// If the socket is Reset when both a read and write are pending,
1283// both should be called back.
1284TEST_P(SpdyProxyClientSocketTest, RstWithReadAndWritePending) {
1285  scoped_ptr<SpdyFrame> conn(ConstructConnectRequestFrame());
1286  MockWrite writes[] = {
1287    CreateMockWrite(*conn, 0, SYNCHRONOUS),
1288    MockWrite(ASYNC, ERR_IO_PENDING, 2),
1289  };
1290
1291  scoped_ptr<SpdyFrame> resp(ConstructConnectReplyFrame());
1292  scoped_ptr<SpdyFrame> rst(
1293      spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL));
1294  MockRead reads[] = {
1295    CreateMockRead(*resp, 1, ASYNC),
1296    CreateMockRead(*rst, 3, ASYNC),
1297  };
1298
1299  Initialize(reads, arraysize(reads), writes, arraysize(writes));
1300
1301  AssertConnectSucceeds();
1302
1303  EXPECT_TRUE(sock_->IsConnected());
1304
1305  scoped_refptr<IOBuffer> read_buf(new IOBuffer(kLen1));
1306  ASSERT_EQ(ERR_IO_PENDING,
1307            sock_->Read(read_buf.get(), kLen1, read_callback_.callback()));
1308
1309  scoped_refptr<IOBufferWithSize> write_buf(CreateBuffer(kMsg1, kLen1));
1310  EXPECT_EQ(
1311      ERR_IO_PENDING,
1312      sock_->Write(
1313          write_buf.get(), write_buf->size(), write_callback_.callback()));
1314
1315  Run(2);
1316
1317  EXPECT_TRUE(sock_.get());
1318  EXPECT_TRUE(read_callback_.have_result());
1319  EXPECT_TRUE(write_callback_.have_result());
1320}
1321
1322// Makes sure the proxy client socket's source gets the expected NetLog events
1323// and only the expected NetLog events (No SpdySession events).
1324TEST_P(SpdyProxyClientSocketTest, NetLog) {
1325  scoped_ptr<SpdyFrame> conn(ConstructConnectRequestFrame());
1326  MockWrite writes[] = {
1327    CreateMockWrite(*conn, 0, SYNCHRONOUS),
1328  };
1329
1330  scoped_ptr<SpdyFrame> resp(ConstructConnectReplyFrame());
1331  scoped_ptr<SpdyFrame> msg1(ConstructBodyFrame(kMsg1, kLen1));
1332  MockRead reads[] = {
1333    CreateMockRead(*resp, 1, ASYNC),
1334    CreateMockRead(*msg1, 2, ASYNC),
1335    MockRead(ASYNC, 0, 3),  // EOF
1336  };
1337
1338  Initialize(reads, arraysize(reads), writes, arraysize(writes));
1339
1340  AssertConnectSucceeds();
1341
1342  Run(1);  // SpdySession consumes the next read and sends it to
1343           // sock_ to be buffered.
1344  AssertSyncReadEquals(kMsg1, kLen1);
1345
1346  NetLog::Source sock_source = sock_->NetLog().source();
1347  sock_.reset();
1348
1349  CapturingNetLog::CapturedEntryList entry_list;
1350  net_log_.GetEntriesForSource(sock_source, &entry_list);
1351
1352  ASSERT_EQ(entry_list.size(), 10u);
1353  EXPECT_TRUE(LogContainsBeginEvent(entry_list, 0, NetLog::TYPE_SOCKET_ALIVE));
1354  EXPECT_TRUE(LogContainsEvent(entry_list, 1,
1355                  NetLog::TYPE_SPDY_PROXY_CLIENT_SESSION,
1356                  NetLog::PHASE_NONE));
1357  EXPECT_TRUE(LogContainsBeginEvent(entry_list, 2,
1358                  NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_SEND_REQUEST));
1359  EXPECT_TRUE(LogContainsEvent(entry_list, 3,
1360                  NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS,
1361                  NetLog::PHASE_NONE));
1362  EXPECT_TRUE(LogContainsEndEvent(entry_list, 4,
1363                  NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_SEND_REQUEST));
1364  EXPECT_TRUE(LogContainsBeginEvent(entry_list, 5,
1365                  NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_READ_HEADERS));
1366  EXPECT_TRUE(LogContainsEvent(entry_list, 6,
1367                  NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS,
1368                  NetLog::PHASE_NONE));
1369  EXPECT_TRUE(LogContainsEndEvent(entry_list, 7,
1370                  NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_READ_HEADERS));
1371  EXPECT_TRUE(LogContainsEvent(entry_list, 8,
1372                  NetLog::TYPE_SOCKET_BYTES_RECEIVED,
1373                  NetLog::PHASE_NONE));
1374  EXPECT_TRUE(LogContainsEndEvent(entry_list, 9, NetLog::TYPE_SOCKET_ALIVE));
1375}
1376
1377// CompletionCallback that causes the SpdyProxyClientSocket to be
1378// deleted when Run is invoked.
1379class DeleteSockCallback : public TestCompletionCallbackBase {
1380 public:
1381  explicit DeleteSockCallback(scoped_ptr<SpdyProxyClientSocket>* sock)
1382      : sock_(sock),
1383        callback_(base::Bind(&DeleteSockCallback::OnComplete,
1384                             base::Unretained(this))) {
1385  }
1386
1387  virtual ~DeleteSockCallback() {
1388  }
1389
1390  const CompletionCallback& callback() const { return callback_; }
1391
1392 private:
1393  void OnComplete(int result) {
1394    sock_->reset(NULL);
1395    SetResult(result);
1396  }
1397
1398  scoped_ptr<SpdyProxyClientSocket>* sock_;
1399  CompletionCallback callback_;
1400
1401  DISALLOW_COPY_AND_ASSIGN(DeleteSockCallback);
1402};
1403
1404// If the socket is Reset when both a read and write are pending, and the
1405// read callback causes the socket to be deleted, the write callback should
1406// not be called.
1407TEST_P(SpdyProxyClientSocketTest, RstWithReadAndWritePendingDelete) {
1408  scoped_ptr<SpdyFrame> conn(ConstructConnectRequestFrame());
1409  MockWrite writes[] = {
1410    CreateMockWrite(*conn, 0, SYNCHRONOUS),
1411    MockWrite(ASYNC, ERR_IO_PENDING, 2),
1412  };
1413
1414  scoped_ptr<SpdyFrame> resp(ConstructConnectReplyFrame());
1415  scoped_ptr<SpdyFrame> rst(
1416      spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL));
1417  MockRead reads[] = {
1418    CreateMockRead(*resp, 1, ASYNC),
1419    CreateMockRead(*rst, 3, ASYNC),
1420  };
1421
1422  Initialize(reads, arraysize(reads), writes, arraysize(writes));
1423
1424  AssertConnectSucceeds();
1425
1426  EXPECT_TRUE(sock_->IsConnected());
1427
1428  DeleteSockCallback read_callback(&sock_);
1429
1430  scoped_refptr<IOBuffer> read_buf(new IOBuffer(kLen1));
1431  ASSERT_EQ(ERR_IO_PENDING,
1432            sock_->Read(read_buf.get(), kLen1, read_callback.callback()));
1433
1434  scoped_refptr<IOBufferWithSize> write_buf(CreateBuffer(kMsg1, kLen1));
1435  EXPECT_EQ(
1436      ERR_IO_PENDING,
1437      sock_->Write(
1438          write_buf.get(), write_buf->size(), write_callback_.callback()));
1439
1440  Run(2);
1441
1442  EXPECT_FALSE(sock_.get());
1443  EXPECT_TRUE(read_callback.have_result());
1444  EXPECT_FALSE(write_callback_.have_result());
1445}
1446
1447}  // namespace net
1448