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