1// Copyright (c) 2011 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/utf_string_conversions.h"
8#include "net/base/address_list.h"
9#include "net/base/net_log.h"
10#include "net/base/net_log_unittest.h"
11#include "net/base/mock_host_resolver.h"
12#include "net/base/test_completion_callback.h"
13#include "net/base/winsock_init.h"
14#include "net/http/http_response_info.h"
15#include "net/http/http_response_headers.h"
16#include "net/socket/client_socket_factory.h"
17#include "net/socket/tcp_client_socket.h"
18#include "net/socket/socket_test_util.h"
19#include "net/spdy/spdy_http_utils.h"
20#include "net/spdy/spdy_protocol.h"
21#include "net/spdy/spdy_session_pool.h"
22#include "net/spdy/spdy_test_util.h"
23#include "testing/platform_test.h"
24#include "testing/gtest/include/gtest/gtest.h"
25
26//-----------------------------------------------------------------------------
27
28namespace {
29
30static const char kUrl[] = "https://www.google.com/";
31static const char kOriginHost[] = "www.google.com";
32static const int kOriginPort = 443;
33static const char kOriginHostPort[] = "www.google.com:443";
34static const char kProxyUrl[] = "http://myproxy:6121/";
35static const char kProxyHost[] = "myproxy";
36static const int kProxyPort = 6121;
37static const char kUserAgent[] = "Mozilla/1.0";
38
39static const int kStreamId = 1;
40
41static const char kMsg1[] = "\0hello!\xff";
42static const int kLen1 = 8;
43static const char kMsg2[] = "\012345678\0";
44static const int kLen2 = 10;
45static const char kMsg3[] = "bye!";
46static const int kLen3 = 4;
47static const char kMsg33[] = "bye!bye!";
48static const int kLen33 = kLen3 + kLen3;
49static const char kMsg333[] = "bye!bye!bye!";
50static const int kLen333 = kLen3 + kLen3 + kLen3;
51
52}  // anonymous namespace
53
54namespace net {
55
56class SpdyProxyClientSocketTest : public PlatformTest {
57 public:
58  SpdyProxyClientSocketTest();
59
60  virtual void TearDown();
61
62 protected:
63  void Initialize(MockRead* reads, size_t reads_count, MockWrite* writes,
64                  size_t writes_count);
65  spdy::SpdyFrame* ConstructConnectRequestFrame();
66  spdy::SpdyFrame* ConstructConnectAuthRequestFrame();
67  spdy::SpdyFrame* ConstructConnectReplyFrame();
68  spdy::SpdyFrame* ConstructConnectAuthReplyFrame();
69  spdy::SpdyFrame* ConstructConnectErrorReplyFrame();
70  spdy::SpdyFrame* ConstructBodyFrame(const char* data, int length);
71  scoped_refptr<IOBufferWithSize> CreateBuffer(const char* data, int size);
72  void AssertConnectSucceeds();
73  void AssertConnectFails(int result);
74  void AssertConnectionEstablished();
75  void AssertSyncReadEquals(const char* data, int len);
76  void AssertAsyncReadEquals(const char* data, int len);
77  void AssertReadStarts(const char* data, int len);
78  void AssertReadReturns(const char* data, int len);
79  void AssertAsyncWriteSucceeds(const char* data, int len);
80  void AssertWriteReturns(const char* data, int len, int rv);
81  void AssertWriteLength(int len);
82  void AssertAsyncWriteWithReadsSucceeds(const char* data, int len,
83                                        int num_reads);
84
85  void AddAuthToCache() {
86    const string16 kFoo(ASCIIToUTF16("foo"));
87    const string16 kBar(ASCIIToUTF16("bar"));
88    session_->http_auth_cache()->Add(GURL(kProxyUrl),
89                                     "MyRealm1",
90                                     HttpAuth::AUTH_SCHEME_BASIC,
91                                     "Basic realm=MyRealm1",
92                                     kFoo,
93                                     kBar,
94                                     "/");
95  }
96
97  void Run(int steps) {
98    data_->StopAfter(steps);
99    data_->Run();
100  }
101
102  scoped_ptr<SpdyProxyClientSocket> sock_;
103  TestCompletionCallback read_callback_;
104  TestCompletionCallback write_callback_;
105  scoped_refptr<DeterministicSocketData> data_;
106
107 private:
108  scoped_refptr<HttpNetworkSession> session_;
109  scoped_refptr<IOBuffer> read_buf_;
110  SpdySessionDependencies session_deps_;
111  MockConnect connect_data_;
112  scoped_refptr<SpdySession> spdy_session_;
113  scoped_refptr<SpdyStream> spdy_stream_;
114  spdy::SpdyFramer framer_;
115
116  std::string user_agent_;
117  GURL url_;
118  HostPortPair proxy_host_port_;
119  HostPortPair endpoint_host_port_pair_;
120  ProxyServer proxy_;
121  HostPortProxyPair endpoint_host_port_proxy_pair_;
122  scoped_refptr<TransportSocketParams> transport_params_;
123
124  DISALLOW_COPY_AND_ASSIGN(SpdyProxyClientSocketTest);
125};
126
127SpdyProxyClientSocketTest::SpdyProxyClientSocketTest()
128    : sock_(NULL),
129      read_callback_(),
130      write_callback_(),
131      data_(NULL),
132      session_(NULL),
133      read_buf_(NULL),
134      session_deps_(),
135      connect_data_(false, OK),
136      spdy_session_(NULL),
137      spdy_stream_(NULL),
138      framer_(),
139      user_agent_(kUserAgent),
140      url_(kUrl),
141      proxy_host_port_(kProxyHost, kProxyPort),
142      endpoint_host_port_pair_(kOriginHost, kOriginPort),
143      proxy_(ProxyServer::SCHEME_HTTPS, proxy_host_port_),
144      endpoint_host_port_proxy_pair_(endpoint_host_port_pair_, proxy_),
145      transport_params_(new TransportSocketParams(proxy_host_port_,
146                                            LOWEST,
147                                            url_,
148                                            false,
149                                            false)) {
150}
151
152void SpdyProxyClientSocketTest::TearDown() {
153  if (session_ != NULL)
154    session_->spdy_session_pool()->CloseAllSessions();
155
156  spdy::SpdyFramer::set_enable_compression_default(true);
157  // Empty the current queue.
158  MessageLoop::current()->RunAllPending();
159  PlatformTest::TearDown();
160}
161
162void SpdyProxyClientSocketTest::Initialize(MockRead* reads,
163                                           size_t reads_count,
164                                           MockWrite* writes,
165                                           size_t writes_count) {
166  data_ = new DeterministicSocketData(reads, reads_count, writes, writes_count);
167  data_->set_connect_data(connect_data_);
168  data_->SetStop(2);
169
170  session_deps_.deterministic_socket_factory->AddSocketDataProvider(
171      data_.get());
172  session_deps_.host_resolver->set_synchronous_mode(true);
173
174  session_ = SpdySessionDependencies::SpdyCreateSessionDeterministic(
175      &session_deps_);
176  SpdySession::SetSSLMode(false);
177  spdy::SpdyFramer::set_enable_compression_default(false);
178
179  // Creates a new spdy session
180  spdy_session_ =
181      session_->spdy_session_pool()->Get(endpoint_host_port_proxy_pair_,
182                                         BoundNetLog());
183
184  // Perform the TCP connect
185  scoped_ptr<ClientSocketHandle> connection(new ClientSocketHandle);
186  EXPECT_EQ(OK,
187            connection->Init(endpoint_host_port_pair_.ToString(),
188                             transport_params_,
189                             LOWEST, NULL, session_->transport_socket_pool(),
190                             BoundNetLog()));
191  spdy_session_->InitializeWithSocket(connection.release(), false, OK);
192
193  // Create the SPDY Stream
194  ASSERT_EQ(
195      OK,
196      spdy_session_->CreateStream(url_, LOWEST, &spdy_stream_, BoundNetLog(),
197                                  NULL));
198
199  // Create the SpdyProxyClientSocket
200  sock_.reset(
201      new SpdyProxyClientSocket(spdy_stream_, user_agent_,
202                                endpoint_host_port_pair_, url_,
203                                proxy_host_port_, session_->http_auth_cache(),
204                                session_->http_auth_handler_factory()));
205}
206
207scoped_refptr<IOBufferWithSize> SpdyProxyClientSocketTest::CreateBuffer(
208    const char* data, int size) {
209  scoped_refptr<IOBufferWithSize> buf(new IOBufferWithSize(size));
210  memcpy(buf->data(), data, size);
211  return buf;
212}
213
214void SpdyProxyClientSocketTest::AssertConnectSucceeds() {
215  ASSERT_EQ(ERR_IO_PENDING, sock_->Connect(&read_callback_));
216  data_->Run();
217  ASSERT_EQ(OK, read_callback_.WaitForResult());
218}
219
220void SpdyProxyClientSocketTest::AssertConnectFails(int result) {
221  ASSERT_EQ(ERR_IO_PENDING, sock_->Connect(&read_callback_));
222  data_->Run();
223  ASSERT_EQ(result, read_callback_.WaitForResult());
224}
225
226void SpdyProxyClientSocketTest::AssertConnectionEstablished() {
227  const HttpResponseInfo* response = sock_->GetConnectResponseInfo();
228  ASSERT_TRUE(response != NULL);
229  ASSERT_EQ(200, response->headers->response_code());
230  ASSERT_EQ("Connection Established", response->headers->GetStatusText());
231}
232
233void SpdyProxyClientSocketTest::AssertSyncReadEquals(const char* data,
234                                                     int len) {
235  scoped_refptr<IOBuffer> buf(new IOBuffer(len));
236  ASSERT_EQ(len, sock_->Read(buf, len, NULL));
237  ASSERT_EQ(std::string(data, len), std::string(buf->data(), len));
238  ASSERT_TRUE(sock_->IsConnected());
239}
240
241void SpdyProxyClientSocketTest::AssertAsyncReadEquals(const char* data,
242                                                     int len) {
243  data_->StopAfter(1);
244  // Issue the read, which will be completed asynchronously
245  scoped_refptr<IOBuffer> buf(new IOBuffer(len));
246  ASSERT_EQ(ERR_IO_PENDING, sock_->Read(buf, len, &read_callback_));
247  EXPECT_TRUE(sock_->IsConnected());
248  data_->Run();
249
250  EXPECT_TRUE(sock_->IsConnected());
251
252  // Now the read will return
253  EXPECT_EQ(len, read_callback_.WaitForResult());
254  ASSERT_EQ(std::string(data, len), std::string(buf->data(), len));
255}
256
257void SpdyProxyClientSocketTest::AssertReadStarts(const char* data, int len) {
258  data_->StopAfter(1);
259  // Issue the read, which will be completed asynchronously
260  read_buf_ = new IOBuffer(len);
261  ASSERT_EQ(ERR_IO_PENDING, sock_->Read(read_buf_, len, &read_callback_));
262  EXPECT_TRUE(sock_->IsConnected());
263}
264
265void SpdyProxyClientSocketTest::AssertReadReturns(const char* data, int len) {
266  EXPECT_TRUE(sock_->IsConnected());
267
268  // Now the read will return
269  EXPECT_EQ(len, read_callback_.WaitForResult());
270  ASSERT_EQ(std::string(data, len), std::string(read_buf_->data(), len));
271}
272
273void SpdyProxyClientSocketTest::AssertAsyncWriteSucceeds(const char* data,
274                                                        int len) {
275  AssertWriteReturns(data, len, ERR_IO_PENDING);
276  data_->RunFor(1);
277  AssertWriteLength(len);
278}
279
280void SpdyProxyClientSocketTest::AssertWriteReturns(const char* data, int len,
281                                                   int rv) {
282  scoped_refptr<IOBufferWithSize> buf(CreateBuffer(data, len));
283  EXPECT_EQ(rv, sock_->Write(buf, buf->size(), &write_callback_));
284}
285
286void SpdyProxyClientSocketTest::AssertWriteLength(int len) {
287  EXPECT_EQ(len, write_callback_.WaitForResult());
288}
289
290void SpdyProxyClientSocketTest::AssertAsyncWriteWithReadsSucceeds(
291    const char* data, int len, int num_reads) {
292  scoped_refptr<IOBufferWithSize> buf(CreateBuffer(data, len));
293
294  EXPECT_EQ(ERR_IO_PENDING, sock_->Write(buf, buf->size(), &write_callback_));
295
296  for (int i = 0; i < num_reads; i++) {
297    Run(1);
298    AssertSyncReadEquals(kMsg2, kLen2);
299  }
300
301  write_callback_.WaitForResult();
302}
303
304// Constructs a standard SPDY SYN_STREAM frame for a CONNECT request.
305spdy::SpdyFrame* SpdyProxyClientSocketTest::ConstructConnectRequestFrame() {
306  const SpdyHeaderInfo kSynStartHeader = {
307    spdy::SYN_STREAM,
308    kStreamId,
309    0,
310    net::ConvertRequestPriorityToSpdyPriority(LOWEST),
311    spdy::CONTROL_FLAG_NONE,
312    false,
313    spdy::INVALID,
314    NULL,
315    0,
316    spdy::DATA_FLAG_NONE
317  };
318  const char* const kConnectHeaders[] = {
319    "method", "CONNECT",
320    "url", kOriginHostPort,
321    "host", kOriginHost,
322    "user-agent", kUserAgent,
323    "version", "HTTP/1.1",
324  };
325  return ConstructSpdyPacket(
326      kSynStartHeader, NULL, 0, kConnectHeaders, arraysize(kConnectHeaders)/2);
327}
328
329// Constructs a SPDY SYN_STREAM frame for a CONNECT request which includes
330// Proxy-Authorization headers.
331spdy::SpdyFrame* SpdyProxyClientSocketTest::ConstructConnectAuthRequestFrame() {
332  const SpdyHeaderInfo kSynStartHeader = {
333    spdy::SYN_STREAM,
334    kStreamId,
335    0,
336    net::ConvertRequestPriorityToSpdyPriority(LOWEST),
337    spdy::CONTROL_FLAG_NONE,
338    false,
339    spdy::INVALID,
340    NULL,
341    0,
342    spdy::DATA_FLAG_NONE
343  };
344  const char* const kConnectHeaders[] = {
345    "method", "CONNECT",
346    "url", kOriginHostPort,
347    "host", kOriginHost,
348    "user-agent", kUserAgent,
349    "version", "HTTP/1.1",
350    "proxy-authorization", "Basic Zm9vOmJhcg==",
351  };
352  return ConstructSpdyPacket(
353      kSynStartHeader, NULL, 0, kConnectHeaders, arraysize(kConnectHeaders)/2);
354}
355
356// Constructs a standard SPDY SYN_REPLY frame to match the SPDY CONNECT.
357spdy::SpdyFrame* SpdyProxyClientSocketTest::ConstructConnectReplyFrame() {
358  const char* const kStandardReplyHeaders[] = {
359      "status", "200 Connection Established",
360      "version", "HTTP/1.1"
361  };
362  return ConstructSpdyControlFrame(NULL,
363                                   0,
364                                   false,
365                                   kStreamId,
366                                   LOWEST,
367                                   spdy::SYN_REPLY,
368                                   spdy::CONTROL_FLAG_NONE,
369                                   kStandardReplyHeaders,
370                                   arraysize(kStandardReplyHeaders));
371}
372
373// Constructs a standard SPDY SYN_REPLY frame to match the SPDY CONNECT.
374spdy::SpdyFrame* SpdyProxyClientSocketTest::ConstructConnectAuthReplyFrame() {
375  const char* const kStandardReplyHeaders[] = {
376      "status", "407 Proxy Authentication Required",
377      "version", "HTTP/1.1",
378      "proxy-authenticate", "Basic realm=\"MyRealm1\"",
379  };
380
381  return ConstructSpdyControlFrame(NULL,
382                                   0,
383                                   false,
384                                   kStreamId,
385                                   LOWEST,
386                                   spdy::SYN_REPLY,
387                                   spdy::CONTROL_FLAG_NONE,
388                                   kStandardReplyHeaders,
389                                   arraysize(kStandardReplyHeaders));
390}
391
392// Constructs a SPDY SYN_REPLY frame with an HTTP 500 error.
393spdy::SpdyFrame* SpdyProxyClientSocketTest::ConstructConnectErrorReplyFrame() {
394  const char* const kStandardReplyHeaders[] = {
395      "status", "500 Internal Server Error",
396      "version", "HTTP/1.1",
397  };
398
399  return ConstructSpdyControlFrame(NULL,
400                                   0,
401                                   false,
402                                   kStreamId,
403                                   LOWEST,
404                                   spdy::SYN_REPLY,
405                                   spdy::CONTROL_FLAG_NONE,
406                                   kStandardReplyHeaders,
407                                   arraysize(kStandardReplyHeaders));
408}
409
410spdy::SpdyFrame* SpdyProxyClientSocketTest::ConstructBodyFrame(const char* data,
411                                                               int length) {
412  return framer_.CreateDataFrame(kStreamId, data, length, spdy::DATA_FLAG_NONE);
413}
414
415// ----------- Connect
416
417TEST_F(SpdyProxyClientSocketTest, ConnectSendsCorrectRequest) {
418  scoped_ptr<spdy::SpdyFrame> conn(ConstructConnectRequestFrame());
419  MockWrite writes[] = {
420    CreateMockWrite(*conn, 0, false),
421  };
422
423  scoped_ptr<spdy::SpdyFrame> resp(ConstructConnectReplyFrame());
424  MockRead reads[] = {
425    CreateMockRead(*resp, 1, true),
426    MockRead(true, 0, 3),  // EOF
427  };
428
429  Initialize(reads, arraysize(reads), writes, arraysize(writes));
430
431  ASSERT_FALSE(sock_->IsConnected());
432
433  AssertConnectSucceeds();
434
435  AssertConnectionEstablished();
436}
437
438TEST_F(SpdyProxyClientSocketTest, ConnectWithAuthRequested) {
439  scoped_ptr<spdy::SpdyFrame> conn(ConstructConnectRequestFrame());
440  MockWrite writes[] = {
441    CreateMockWrite(*conn, 0, false),
442  };
443
444  scoped_ptr<spdy::SpdyFrame> resp(ConstructConnectAuthReplyFrame());
445  MockRead reads[] = {
446    CreateMockRead(*resp, 1, true),
447    MockRead(true, 0, 3),  // EOF
448  };
449
450  Initialize(reads, arraysize(reads), writes, arraysize(writes));
451
452  AssertConnectFails(ERR_TUNNEL_CONNECTION_FAILED);
453
454  const HttpResponseInfo* response = sock_->GetConnectResponseInfo();
455  ASSERT_TRUE(response != NULL);
456  ASSERT_EQ(407, response->headers->response_code());
457  ASSERT_EQ("Proxy Authentication Required",
458            response->headers->GetStatusText());
459}
460
461TEST_F(SpdyProxyClientSocketTest, ConnectWithAuthCredentials) {
462  scoped_ptr<spdy::SpdyFrame> conn(ConstructConnectAuthRequestFrame());
463  MockWrite writes[] = {
464    CreateMockWrite(*conn, 0, false),
465  };
466
467  scoped_ptr<spdy::SpdyFrame> resp(ConstructConnectReplyFrame());
468  MockRead reads[] = {
469    CreateMockRead(*resp, 1, true),
470    MockRead(true, 0, 3),  // EOF
471  };
472
473  Initialize(reads, arraysize(reads), writes, arraysize(writes));
474  AddAuthToCache();
475
476  AssertConnectSucceeds();
477
478  AssertConnectionEstablished();
479}
480
481TEST_F(SpdyProxyClientSocketTest, ConnectFails) {
482  scoped_ptr<spdy::SpdyFrame> conn(ConstructConnectRequestFrame());
483  MockWrite writes[] = {
484    CreateMockWrite(*conn, 0, false),
485  };
486
487  scoped_ptr<spdy::SpdyFrame> resp(ConstructConnectReplyFrame());
488  MockRead reads[] = {
489    MockRead(true, 0, 1),  // EOF
490  };
491
492  Initialize(reads, arraysize(reads), writes, arraysize(writes));
493
494  ASSERT_FALSE(sock_->IsConnected());
495
496  AssertConnectFails(ERR_CONNECTION_CLOSED);
497
498  ASSERT_FALSE(sock_->IsConnected());
499}
500
501// ----------- WasEverUsed
502
503TEST_F(SpdyProxyClientSocketTest, WasEverUsedReturnsCorrectValues) {
504  scoped_ptr<spdy::SpdyFrame> conn(ConstructConnectRequestFrame());
505  MockWrite writes[] = {
506    CreateMockWrite(*conn, 0, false),
507  };
508
509  scoped_ptr<spdy::SpdyFrame> resp(ConstructConnectReplyFrame());
510  MockRead reads[] = {
511    CreateMockRead(*resp, 1, true),
512    MockRead(true, 0, 2),  // EOF
513  };
514
515  Initialize(reads, arraysize(reads), writes, arraysize(writes));
516
517  EXPECT_FALSE(sock_->WasEverUsed());
518  AssertConnectSucceeds();
519  EXPECT_TRUE(sock_->WasEverUsed());
520  sock_->Disconnect();
521  EXPECT_TRUE(sock_->WasEverUsed());
522}
523
524// ----------- GetPeerAddress
525
526TEST_F(SpdyProxyClientSocketTest, GetPeerAddressReturnsCorrectValues) {
527  scoped_ptr<spdy::SpdyFrame> conn(ConstructConnectRequestFrame());
528  MockWrite writes[] = {
529    CreateMockWrite(*conn, 0, false),
530  };
531
532  scoped_ptr<spdy::SpdyFrame> resp(ConstructConnectReplyFrame());
533  MockRead reads[] = {
534    CreateMockRead(*resp, 1, true),
535    MockRead(true, 0, 2),  // EOF
536  };
537
538  Initialize(reads, arraysize(reads), writes, arraysize(writes));
539
540  net::AddressList addr;
541  EXPECT_EQ(ERR_SOCKET_NOT_CONNECTED, sock_->GetPeerAddress(&addr));
542
543  AssertConnectSucceeds();
544  EXPECT_TRUE(sock_->IsConnected());
545  EXPECT_EQ(OK, sock_->GetPeerAddress(&addr));
546
547  sock_->Disconnect();
548  EXPECT_EQ(ERR_SOCKET_NOT_CONNECTED, sock_->GetPeerAddress(&addr));
549}
550
551// ----------- Write
552
553TEST_F(SpdyProxyClientSocketTest, WriteSendsDataInDataFrame) {
554  scoped_ptr<spdy::SpdyFrame> conn(ConstructConnectRequestFrame());
555  scoped_ptr<spdy::SpdyFrame> msg1(ConstructBodyFrame(kMsg1, kLen1));
556  scoped_ptr<spdy::SpdyFrame> msg2(ConstructBodyFrame(kMsg2, kLen2));
557  MockWrite writes[] = {
558    CreateMockWrite(*conn, 0, false),
559    CreateMockWrite(*msg1, 2, false),
560    CreateMockWrite(*msg2, 3, false),
561  };
562
563  scoped_ptr<spdy::SpdyFrame> resp(ConstructConnectReplyFrame());
564  MockRead reads[] = {
565    CreateMockRead(*resp, 1, true),
566    MockRead(true, 0, 4),  // EOF
567  };
568
569  Initialize(reads, arraysize(reads), writes, arraysize(writes));
570
571  AssertConnectSucceeds();
572
573  AssertAsyncWriteSucceeds(kMsg1, kLen1);
574  AssertAsyncWriteSucceeds(kMsg2, kLen2);
575}
576
577TEST_F(SpdyProxyClientSocketTest, WriteSplitsLargeDataIntoMultipleFrames) {
578  std::string chunk_data(kMaxSpdyFrameChunkSize, 'x');
579  scoped_ptr<spdy::SpdyFrame> conn(ConstructConnectRequestFrame());
580  scoped_ptr<spdy::SpdyFrame> chunk(ConstructBodyFrame(chunk_data.data(),
581                                                       chunk_data.length()));
582  MockWrite writes[] = {
583    CreateMockWrite(*conn, 0, false),
584    CreateMockWrite(*chunk, 2, false),
585    CreateMockWrite(*chunk, 3, false),
586    CreateMockWrite(*chunk, 4, false)
587  };
588
589  scoped_ptr<spdy::SpdyFrame> resp(ConstructConnectReplyFrame());
590  MockRead reads[] = {
591    CreateMockRead(*resp, 1, true),
592    MockRead(true, 0, 5),  // EOF
593  };
594
595  Initialize(reads, arraysize(reads), writes, arraysize(writes));
596
597  AssertConnectSucceeds();
598
599  std::string big_data(kMaxSpdyFrameChunkSize * 3, 'x');
600  scoped_refptr<IOBufferWithSize> buf(CreateBuffer(big_data.data(),
601                                                   big_data.length()));
602
603  EXPECT_EQ(ERR_IO_PENDING, sock_->Write(buf, buf->size(), &write_callback_));
604  data_->RunFor(3);
605
606  EXPECT_EQ(buf->size(), write_callback_.WaitForResult());
607}
608
609// ----------- Read
610
611TEST_F(SpdyProxyClientSocketTest, ReadReadsDataInDataFrame) {
612  scoped_ptr<spdy::SpdyFrame> conn(ConstructConnectRequestFrame());
613  MockWrite writes[] = {
614    CreateMockWrite(*conn, 0, false),
615  };
616
617  scoped_ptr<spdy::SpdyFrame> resp(ConstructConnectReplyFrame());
618  scoped_ptr<spdy::SpdyFrame> msg1(ConstructBodyFrame(kMsg1, kLen1));
619  MockRead reads[] = {
620    CreateMockRead(*resp, 1, true),
621    CreateMockRead(*msg1, 2, true),
622    MockRead(true, 0, 3),  // EOF
623  };
624
625  Initialize(reads, arraysize(reads), writes, arraysize(writes));
626
627  AssertConnectSucceeds();
628
629  Run(1);  // SpdySession consumes the next read and sends it to
630           // sock_ to be buffered.
631  AssertSyncReadEquals(kMsg1, kLen1);
632}
633
634TEST_F(SpdyProxyClientSocketTest, ReadDataFromBufferedFrames) {
635  scoped_ptr<spdy::SpdyFrame> conn(ConstructConnectRequestFrame());
636  MockWrite writes[] = {
637    CreateMockWrite(*conn, 0, false),
638  };
639
640  scoped_ptr<spdy::SpdyFrame> resp(ConstructConnectReplyFrame());
641  scoped_ptr<spdy::SpdyFrame> msg1(ConstructBodyFrame(kMsg1, kLen1));
642  scoped_ptr<spdy::SpdyFrame> msg2(ConstructBodyFrame(kMsg2, kLen2));
643  MockRead reads[] = {
644    CreateMockRead(*resp, 1, true),
645    CreateMockRead(*msg1, 2, true),
646    CreateMockRead(*msg2, 3, true),
647    MockRead(true, 0, 4),  // EOF
648  };
649
650  Initialize(reads, arraysize(reads), writes, arraysize(writes));
651
652  AssertConnectSucceeds();
653
654  Run(1);  // SpdySession consumes the next read and sends it to
655           // sock_ to be buffered.
656  AssertSyncReadEquals(kMsg1, kLen1);
657  Run(1);  // SpdySession consumes the next read and sends it to
658           // sock_ to be buffered.
659  AssertSyncReadEquals(kMsg2, kLen2);
660}
661
662TEST_F(SpdyProxyClientSocketTest, ReadDataMultipleBufferedFrames) {
663  scoped_ptr<spdy::SpdyFrame> conn(ConstructConnectRequestFrame());
664  MockWrite writes[] = {
665    CreateMockWrite(*conn, 0, false),
666  };
667
668  scoped_ptr<spdy::SpdyFrame> resp(ConstructConnectReplyFrame());
669  scoped_ptr<spdy::SpdyFrame> msg1(ConstructBodyFrame(kMsg1, kLen1));
670  scoped_ptr<spdy::SpdyFrame> msg2(ConstructBodyFrame(kMsg2, kLen2));
671  MockRead reads[] = {
672    CreateMockRead(*resp, 1, true),
673    CreateMockRead(*msg1, 2, true),
674    CreateMockRead(*msg2, 3, true),
675    MockRead(true, 0, 4),  // EOF
676  };
677
678  Initialize(reads, arraysize(reads), writes, arraysize(writes));
679
680  AssertConnectSucceeds();
681
682  Run(2);  // SpdySession consumes the next two reads and sends then to
683           // sock_ to be buffered.
684  AssertSyncReadEquals(kMsg1, kLen1);
685  AssertSyncReadEquals(kMsg2, kLen2);
686}
687
688TEST_F(SpdyProxyClientSocketTest, LargeReadWillMergeDataFromDifferentFrames) {
689  scoped_ptr<spdy::SpdyFrame> conn(ConstructConnectRequestFrame());
690  MockWrite writes[] = {
691    CreateMockWrite(*conn, 0, false),
692  };
693
694  scoped_ptr<spdy::SpdyFrame> resp(ConstructConnectReplyFrame());
695  scoped_ptr<spdy::SpdyFrame> msg1(ConstructBodyFrame(kMsg1, kLen1));
696  scoped_ptr<spdy::SpdyFrame> msg3(ConstructBodyFrame(kMsg3, kLen3));
697  MockRead reads[] = {
698    CreateMockRead(*resp, 1, true),
699    CreateMockRead(*msg3, 2, true),
700    CreateMockRead(*msg3, 3, true),
701    MockRead(true, 0, 4),  // EOF
702  };
703
704  Initialize(reads, arraysize(reads), writes, arraysize(writes));
705
706  AssertConnectSucceeds();
707
708  Run(2);  // SpdySession consumes the next two reads and sends then to
709           // sock_ to be buffered.
710  // The payload from two data frames, each with kMsg3 will be combined
711  // together into a single read().
712  AssertSyncReadEquals(kMsg33, kLen33);
713}
714
715TEST_F(SpdyProxyClientSocketTest, MultipleShortReadsThenMoreRead) {
716  scoped_ptr<spdy::SpdyFrame> conn(ConstructConnectRequestFrame());
717  MockWrite writes[] = {
718    CreateMockWrite(*conn, 0, false),
719  };
720
721  scoped_ptr<spdy::SpdyFrame> resp(ConstructConnectReplyFrame());
722  scoped_ptr<spdy::SpdyFrame> msg1(ConstructBodyFrame(kMsg1, kLen1));
723  scoped_ptr<spdy::SpdyFrame> msg3(ConstructBodyFrame(kMsg3, kLen3));
724  scoped_ptr<spdy::SpdyFrame> msg2(ConstructBodyFrame(kMsg2, kLen2));
725  MockRead reads[] = {
726    CreateMockRead(*resp, 1, true),
727    CreateMockRead(*msg1, 2, true),
728    CreateMockRead(*msg3, 3, true),
729    CreateMockRead(*msg3, 4, true),
730    CreateMockRead(*msg2, 5, true),
731    MockRead(true, 0, 6),  // EOF
732  };
733
734  Initialize(reads, arraysize(reads), writes, arraysize(writes));
735
736  AssertConnectSucceeds();
737
738  Run(4);  // SpdySession consumes the next four reads and sends then to
739           // sock_ to be buffered.
740  AssertSyncReadEquals(kMsg1, kLen1);
741  // The payload from two data frames, each with kMsg3 will be combined
742  // together into a single read().
743  AssertSyncReadEquals(kMsg33, kLen33);
744  AssertSyncReadEquals(kMsg2, kLen2);
745}
746
747TEST_F(SpdyProxyClientSocketTest, ReadWillSplitDataFromLargeFrame) {
748  scoped_ptr<spdy::SpdyFrame> conn(ConstructConnectRequestFrame());
749  MockWrite writes[] = {
750    CreateMockWrite(*conn, 0, false),
751  };
752
753  scoped_ptr<spdy::SpdyFrame> resp(ConstructConnectReplyFrame());
754  scoped_ptr<spdy::SpdyFrame> msg1(ConstructBodyFrame(kMsg1, kLen1));
755  scoped_ptr<spdy::SpdyFrame> msg33(ConstructBodyFrame(kMsg33, kLen33));
756  scoped_ptr<spdy::SpdyFrame> msg2(ConstructBodyFrame(kMsg2, kLen2));
757  MockRead reads[] = {
758    CreateMockRead(*resp, 1, true),
759    CreateMockRead(*msg1, 2, true),
760    CreateMockRead(*msg33, 3, true),
761    MockRead(true, 0, 4),  // EOF
762  };
763
764  Initialize(reads, arraysize(reads), writes, arraysize(writes));
765
766  AssertConnectSucceeds();
767
768  Run(2);  // SpdySession consumes the next two reads and sends then to
769           // sock_ to be buffered.
770  AssertSyncReadEquals(kMsg1, kLen1);
771  // The payload from the single large data frame will be read across
772  // two different reads.
773  AssertSyncReadEquals(kMsg3, kLen3);
774  AssertSyncReadEquals(kMsg3, kLen3);
775}
776
777TEST_F(SpdyProxyClientSocketTest, MultipleReadsFromSameLargeFrame) {
778  scoped_ptr<spdy::SpdyFrame> conn(ConstructConnectRequestFrame());
779  MockWrite writes[] = {
780    CreateMockWrite(*conn, 0, false),
781  };
782
783  scoped_ptr<spdy::SpdyFrame> resp(ConstructConnectReplyFrame());
784  scoped_ptr<spdy::SpdyFrame> msg333(ConstructBodyFrame(kMsg333, kLen333));
785  MockRead reads[] = {
786    CreateMockRead(*resp, 1, true),
787    CreateMockRead(*msg333, 2, true),
788    MockRead(true, 0, 3),  // EOF
789  };
790
791  Initialize(reads, arraysize(reads), writes, arraysize(writes));
792
793  AssertConnectSucceeds();
794
795  Run(1);  // SpdySession consumes the next read and sends it to
796           // sock_ to be buffered.
797  // The payload from the single large data frame will be read across
798  // two different reads.
799  AssertSyncReadEquals(kMsg33, kLen33);
800
801  // Now attempt to do a read of more data than remains buffered
802  scoped_refptr<IOBuffer> buf(new IOBuffer(kLen33));
803  ASSERT_EQ(kLen3, sock_->Read(buf, kLen33, &read_callback_));
804  ASSERT_EQ(std::string(kMsg3, kLen3), std::string(buf->data(), kLen3));
805  ASSERT_TRUE(sock_->IsConnected());
806}
807
808TEST_F(SpdyProxyClientSocketTest, ReadAuthResponseBody) {
809  scoped_ptr<spdy::SpdyFrame> conn(ConstructConnectRequestFrame());
810  MockWrite writes[] = {
811    CreateMockWrite(*conn, 0, false),
812  };
813
814  scoped_ptr<spdy::SpdyFrame> resp(ConstructConnectAuthReplyFrame());
815  scoped_ptr<spdy::SpdyFrame> msg1(ConstructBodyFrame(kMsg1, kLen1));
816  scoped_ptr<spdy::SpdyFrame> msg2(ConstructBodyFrame(kMsg2, kLen2));
817  MockRead reads[] = {
818    CreateMockRead(*resp, 1, true),
819    CreateMockRead(*msg1, 2, true),
820    CreateMockRead(*msg2, 3, true),
821    MockRead(true, 0, 4),  // EOF
822  };
823
824  Initialize(reads, arraysize(reads), writes, arraysize(writes));
825
826  AssertConnectFails(ERR_TUNNEL_CONNECTION_FAILED);
827
828  Run(2);  // SpdySession consumes the next two reads and sends then to
829           // sock_ to be buffered.
830  AssertSyncReadEquals(kMsg1, kLen1);
831  AssertSyncReadEquals(kMsg2, kLen2);
832}
833
834TEST_F(SpdyProxyClientSocketTest, ReadErrorResponseBody) {
835  scoped_ptr<spdy::SpdyFrame> conn(ConstructConnectRequestFrame());
836  MockWrite writes[] = {
837    CreateMockWrite(*conn, 0, false),
838  };
839
840  scoped_ptr<spdy::SpdyFrame> resp(ConstructConnectErrorReplyFrame());
841  scoped_ptr<spdy::SpdyFrame> msg1(ConstructBodyFrame(kMsg1, kLen1));
842  scoped_ptr<spdy::SpdyFrame> msg2(ConstructBodyFrame(kMsg2, kLen2));
843  MockRead reads[] = {
844    CreateMockRead(*resp, 1, true),
845    CreateMockRead(*msg1, 2, true),
846    CreateMockRead(*msg2, 3, true),
847    MockRead(true, 0, 4),  // EOF
848  };
849
850  Initialize(reads, arraysize(reads), writes, arraysize(writes));
851
852  AssertConnectFails(ERR_HTTPS_PROXY_TUNNEL_RESPONSE);
853
854  Run(2);  // SpdySession consumes the next two reads and sends then to
855           // sock_ to be buffered.
856  EXPECT_EQ(ERR_SOCKET_NOT_CONNECTED, sock_->Read(NULL, 1, NULL));
857  scoped_refptr<IOBuffer> buf(new IOBuffer(kLen1 + kLen2));
858  scoped_ptr<HttpStream> stream(sock_->CreateConnectResponseStream());
859  stream->ReadResponseBody(buf, kLen1 + kLen2, &read_callback_);
860}
861
862// ----------- Reads and Writes
863
864TEST_F(SpdyProxyClientSocketTest, AsyncReadAroundWrite) {
865  scoped_ptr<spdy::SpdyFrame> conn(ConstructConnectRequestFrame());
866  scoped_ptr<spdy::SpdyFrame> msg2(ConstructBodyFrame(kMsg2, kLen2));
867  MockWrite writes[] = {
868    CreateMockWrite(*conn, 0, false),
869    CreateMockWrite(*msg2, 3, false),
870  };
871
872  scoped_ptr<spdy::SpdyFrame> resp(ConstructConnectReplyFrame());
873  scoped_ptr<spdy::SpdyFrame> msg1(ConstructBodyFrame(kMsg1, kLen1));
874  scoped_ptr<spdy::SpdyFrame> msg3(ConstructBodyFrame(kMsg3, kLen3));
875  MockRead reads[] = {
876    CreateMockRead(*resp, 1, true),
877    CreateMockRead(*msg1, 2, true),  // sync read
878    CreateMockRead(*msg3, 4, true),  // async read
879    MockRead(true, 0, 5),  // EOF
880  };
881
882  Initialize(reads, arraysize(reads), writes, arraysize(writes));
883
884  AssertConnectSucceeds();
885
886  Run(1);
887  AssertSyncReadEquals(kMsg1, kLen1);
888
889  AssertReadStarts(kMsg3, kLen3);
890  // Read should block until after the write succeeds
891
892  AssertAsyncWriteSucceeds(kMsg2, kLen2);  // Runs 1 step
893
894  ASSERT_FALSE(read_callback_.have_result());
895  Run(1);
896  // Now the read will return
897  AssertReadReturns(kMsg3, kLen3);
898}
899
900TEST_F(SpdyProxyClientSocketTest, AsyncWriteAroundReads) {
901  scoped_ptr<spdy::SpdyFrame> conn(ConstructConnectRequestFrame());
902  scoped_ptr<spdy::SpdyFrame> msg2(ConstructBodyFrame(kMsg2, kLen2));
903  MockWrite writes[] = {
904    CreateMockWrite(*conn, 0, false),
905    CreateMockWrite(*msg2, 4, true),
906  };
907
908  scoped_ptr<spdy::SpdyFrame> resp(ConstructConnectReplyFrame());
909  scoped_ptr<spdy::SpdyFrame> msg1(ConstructBodyFrame(kMsg1, kLen1));
910  scoped_ptr<spdy::SpdyFrame> msg3(ConstructBodyFrame(kMsg3, kLen3));
911  MockRead reads[] = {
912    CreateMockRead(*resp, 1, true),
913    CreateMockRead(*msg1, 2, true),
914    CreateMockRead(*msg3, 3, true),
915    MockRead(true, 0, 5),  // EOF
916  };
917
918  Initialize(reads, arraysize(reads), writes, arraysize(writes));
919
920  AssertConnectSucceeds();
921
922  Run(1);
923  AssertSyncReadEquals(kMsg1, kLen1);
924  // Write should block until the read completes
925  AssertWriteReturns(kMsg2, kLen2, ERR_IO_PENDING);
926
927  AssertAsyncReadEquals(kMsg3, kLen3);
928
929  ASSERT_FALSE(write_callback_.have_result());
930
931  // Now the write will complete
932  Run(1);
933  AssertWriteLength(kLen2);
934}
935
936// ----------- Reading/Writing on Closed socket
937
938// Reading from an already closed socket should return 0
939TEST_F(SpdyProxyClientSocketTest, ReadOnClosedSocketReturnsZero) {
940  scoped_ptr<spdy::SpdyFrame> conn(ConstructConnectRequestFrame());
941  MockWrite writes[] = {
942    CreateMockWrite(*conn, 0, false),
943  };
944
945  scoped_ptr<spdy::SpdyFrame> resp(ConstructConnectReplyFrame());
946  MockRead reads[] = {
947    CreateMockRead(*resp, 1, true),
948    MockRead(true, 0, 2),  // EOF
949  };
950
951  Initialize(reads, arraysize(reads), writes, arraysize(writes));
952
953  AssertConnectSucceeds();
954
955  Run(1);
956
957  ASSERT_EQ(0, sock_->Read(NULL, 1, NULL));
958  ASSERT_EQ(ERR_CONNECTION_CLOSED, sock_->Read(NULL, 1, NULL));
959  ASSERT_EQ(ERR_CONNECTION_CLOSED, sock_->Read(NULL, 1, NULL));
960}
961
962// Read pending when socket is closed should return 0
963TEST_F(SpdyProxyClientSocketTest, PendingReadOnCloseReturnsZero) {
964  scoped_ptr<spdy::SpdyFrame> conn(ConstructConnectRequestFrame());
965  MockWrite writes[] = {
966    CreateMockWrite(*conn, 0, false),
967  };
968
969  scoped_ptr<spdy::SpdyFrame> resp(ConstructConnectReplyFrame());
970  MockRead reads[] = {
971    CreateMockRead(*resp, 1, true),
972    MockRead(true, 0, 2),  // EOF
973  };
974
975  Initialize(reads, arraysize(reads), writes, arraysize(writes));
976
977  AssertConnectSucceeds();
978
979  AssertReadStarts(kMsg1, kLen1);
980
981  Run(1);
982
983  ASSERT_EQ(0, read_callback_.WaitForResult());
984}
985
986// Reading from a disconnected socket is an error
987TEST_F(SpdyProxyClientSocketTest, ReadOnDisconnectSocketReturnsNotConnected) {
988  scoped_ptr<spdy::SpdyFrame> conn(ConstructConnectRequestFrame());
989  MockWrite writes[] = {
990    CreateMockWrite(*conn, 0, false),
991  };
992
993  scoped_ptr<spdy::SpdyFrame> resp(ConstructConnectReplyFrame());
994  MockRead reads[] = {
995    CreateMockRead(*resp, 1, true),
996    MockRead(true, 0, 2),  // EOF
997  };
998
999  Initialize(reads, arraysize(reads), writes, arraysize(writes));
1000
1001  AssertConnectSucceeds();
1002
1003  sock_->Disconnect();
1004
1005  ASSERT_EQ(ERR_SOCKET_NOT_CONNECTED, sock_->Read(NULL, 1, NULL));
1006}
1007
1008// Reading buffered data from an already closed socket should return
1009// buffered data, then 0.
1010TEST_F(SpdyProxyClientSocketTest, ReadOnClosedSocketReturnsBufferedData) {
1011  scoped_ptr<spdy::SpdyFrame> conn(ConstructConnectRequestFrame());
1012  MockWrite writes[] = {
1013    CreateMockWrite(*conn, 0, false),
1014  };
1015
1016  scoped_ptr<spdy::SpdyFrame> resp(ConstructConnectReplyFrame());
1017  scoped_ptr<spdy::SpdyFrame> msg1(ConstructBodyFrame(kMsg1, kLen1));
1018  MockRead reads[] = {
1019    CreateMockRead(*resp, 1, true),
1020    CreateMockRead(*msg1, 2, true),
1021    MockRead(true, 0, 3),  // EOF
1022  };
1023
1024  Initialize(reads, arraysize(reads), writes, arraysize(writes));
1025
1026  AssertConnectSucceeds();
1027
1028  Run(2);
1029
1030  AssertSyncReadEquals(kMsg1, kLen1);
1031  ASSERT_EQ(0, sock_->Read(NULL, 1, NULL));
1032  ASSERT_EQ(ERR_CONNECTION_CLOSED, sock_->Read(NULL, 1, NULL));
1033  // Verify that read *still* returns ERR_CONNECTION_CLOSED
1034  ASSERT_EQ(ERR_CONNECTION_CLOSED, sock_->Read(NULL, 1, NULL));
1035}
1036
1037// Calling Write() on a closed socket is an error
1038TEST_F(SpdyProxyClientSocketTest, WriteOnClosedStream) {
1039  scoped_ptr<spdy::SpdyFrame> conn(ConstructConnectRequestFrame());
1040  MockWrite writes[] = {
1041    CreateMockWrite(*conn, 0, false),
1042  };
1043
1044  scoped_ptr<spdy::SpdyFrame> resp(ConstructConnectReplyFrame());
1045  scoped_ptr<spdy::SpdyFrame> msg1(ConstructBodyFrame(kMsg1, kLen1));
1046  MockRead reads[] = {
1047    CreateMockRead(*resp, 1, true),
1048    MockRead(true, 0, 2),  // EOF
1049  };
1050
1051  Initialize(reads, arraysize(reads), writes, arraysize(writes));
1052
1053  AssertConnectSucceeds();
1054
1055  Run(1);  // Read EOF which will close the stream
1056  scoped_refptr<IOBufferWithSize> buf(CreateBuffer(kMsg1, kLen1));
1057  EXPECT_EQ(ERR_CONNECTION_CLOSED, sock_->Write(buf, buf->size(), NULL));
1058}
1059
1060// Calling Write() on a disconnected socket is an error
1061TEST_F(SpdyProxyClientSocketTest, WriteOnDisconnectedSocket) {
1062  scoped_ptr<spdy::SpdyFrame> conn(ConstructConnectRequestFrame());
1063  MockWrite writes[] = {
1064    CreateMockWrite(*conn, 0, false),
1065  };
1066
1067  scoped_ptr<spdy::SpdyFrame> resp(ConstructConnectReplyFrame());
1068  scoped_ptr<spdy::SpdyFrame> msg1(ConstructBodyFrame(kMsg1, kLen1));
1069  MockRead reads[] = {
1070    CreateMockRead(*resp, 1, true),
1071    MockRead(true, 0, 2),  // EOF
1072  };
1073
1074  Initialize(reads, arraysize(reads), writes, arraysize(writes));
1075
1076  AssertConnectSucceeds();
1077
1078  sock_->Disconnect();
1079
1080  scoped_refptr<IOBufferWithSize> buf(CreateBuffer(kMsg1, kLen1));
1081  EXPECT_EQ(ERR_SOCKET_NOT_CONNECTED, sock_->Write(buf, buf->size(), NULL));
1082}
1083
1084// If the socket is closed with a pending Write(), the callback
1085// should be called with ERR_CONNECTION_CLOSED.
1086TEST_F(SpdyProxyClientSocketTest, WritePendingOnClose) {
1087  scoped_ptr<spdy::SpdyFrame> conn(ConstructConnectRequestFrame());
1088  MockWrite writes[] = {
1089    CreateMockWrite(*conn, 0, false),
1090    MockWrite(true, ERR_IO_PENDING, 2),
1091  };
1092
1093  scoped_ptr<spdy::SpdyFrame> resp(ConstructConnectReplyFrame());
1094  MockRead reads[] = {
1095    CreateMockRead(*resp, 1, true),
1096    MockRead(true, 0, 3),  // EOF
1097  };
1098
1099  Initialize(reads, arraysize(reads), writes, arraysize(writes));
1100
1101  AssertConnectSucceeds();
1102
1103  EXPECT_TRUE(sock_->IsConnected());
1104
1105  scoped_refptr<IOBufferWithSize> buf(CreateBuffer(kMsg1, kLen1));
1106  EXPECT_EQ(ERR_IO_PENDING, sock_->Write(buf, buf->size(), &write_callback_));
1107
1108  Run(1);
1109
1110  EXPECT_EQ(ERR_CONNECTION_CLOSED, write_callback_.WaitForResult());
1111}
1112
1113// If the socket is Disconnected with a pending Write(), the callback
1114// should not be called.
1115TEST_F(SpdyProxyClientSocketTest, DisconnectWithWritePending) {
1116  scoped_ptr<spdy::SpdyFrame> conn(ConstructConnectRequestFrame());
1117  MockWrite writes[] = {
1118    CreateMockWrite(*conn, 0, false),
1119    MockWrite(false, 0, 2),  // EOF
1120  };
1121
1122  scoped_ptr<spdy::SpdyFrame> resp(ConstructConnectReplyFrame());
1123  MockRead reads[] = {
1124    CreateMockRead(*resp, 1, true),
1125    MockRead(true, 0, 3),  // EOF
1126  };
1127
1128  Initialize(reads, arraysize(reads), writes, arraysize(writes));
1129
1130  AssertConnectSucceeds();
1131
1132  EXPECT_TRUE(sock_->IsConnected());
1133
1134  scoped_refptr<IOBufferWithSize> buf(CreateBuffer(kMsg1, kLen1));
1135  EXPECT_EQ(ERR_IO_PENDING, sock_->Write(buf, buf->size(), &write_callback_));
1136
1137  sock_->Disconnect();
1138
1139  EXPECT_FALSE(sock_->IsConnected());
1140  EXPECT_FALSE(write_callback_.have_result());
1141}
1142
1143// If the socket is Disconnected with a pending Read(), the callback
1144// should not be called.
1145TEST_F(SpdyProxyClientSocketTest, DisconnectWithReadPending) {
1146  scoped_ptr<spdy::SpdyFrame> conn(ConstructConnectRequestFrame());
1147  MockWrite writes[] = {
1148    CreateMockWrite(*conn, 0, false),
1149  };
1150
1151  scoped_ptr<spdy::SpdyFrame> resp(ConstructConnectReplyFrame());
1152  MockRead reads[] = {
1153    CreateMockRead(*resp, 1, true),
1154    MockRead(true, 0, 2),  // EOF
1155  };
1156
1157  Initialize(reads, arraysize(reads), writes, arraysize(writes));
1158
1159  AssertConnectSucceeds();
1160
1161  EXPECT_TRUE(sock_->IsConnected());
1162
1163  scoped_refptr<IOBuffer> buf(new IOBuffer(kLen1));
1164  ASSERT_EQ(ERR_IO_PENDING, sock_->Read(buf, kLen1, &read_callback_));
1165
1166  sock_->Disconnect();
1167
1168  EXPECT_FALSE(sock_->IsConnected());
1169  EXPECT_FALSE(read_callback_.have_result());
1170}
1171
1172}  // namespace net
1173