1// Copyright 2013 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_websocket_stream.h"
6
7#include <string>
8#include <vector>
9
10#include "base/bind.h"
11#include "base/bind_helpers.h"
12#include "net/base/completion_callback.h"
13#include "net/proxy/proxy_server.h"
14#include "net/socket/next_proto.h"
15#include "net/socket/ssl_client_socket.h"
16#include "net/spdy/spdy_http_utils.h"
17#include "net/spdy/spdy_protocol.h"
18#include "net/spdy/spdy_session.h"
19#include "net/spdy/spdy_websocket_test_util.h"
20#include "testing/gtest/include/gtest/gtest.h"
21
22namespace net {
23
24namespace {
25
26struct SpdyWebSocketStreamEvent {
27  enum EventType {
28    EVENT_CREATED,
29    EVENT_SENT_HEADERS,
30    EVENT_RECEIVED_HEADER,
31    EVENT_SENT_DATA,
32    EVENT_RECEIVED_DATA,
33    EVENT_CLOSE,
34  };
35  SpdyWebSocketStreamEvent(EventType type,
36                           const SpdyHeaderBlock& headers,
37                           int result,
38                           const std::string& data)
39      : event_type(type),
40        headers(headers),
41        result(result),
42        data(data) {}
43
44  EventType event_type;
45  SpdyHeaderBlock headers;
46  int result;
47  std::string data;
48};
49
50class SpdyWebSocketStreamEventRecorder : public SpdyWebSocketStream::Delegate {
51 public:
52  explicit SpdyWebSocketStreamEventRecorder(const CompletionCallback& callback)
53      : callback_(callback) {}
54  virtual ~SpdyWebSocketStreamEventRecorder() {}
55
56  typedef base::Callback<void(SpdyWebSocketStreamEvent*)> StreamEventCallback;
57
58  void SetOnCreated(const StreamEventCallback& callback) {
59    on_created_ = callback;
60  }
61  void SetOnSentHeaders(const StreamEventCallback& callback) {
62    on_sent_headers_ = callback;
63  }
64  void SetOnReceivedHeader(const StreamEventCallback& callback) {
65    on_received_header_ = callback;
66  }
67  void SetOnSentData(const StreamEventCallback& callback) {
68    on_sent_data_ = callback;
69  }
70  void SetOnReceivedData(const StreamEventCallback& callback) {
71    on_received_data_ = callback;
72  }
73  void SetOnClose(const StreamEventCallback& callback) {
74    on_close_ = callback;
75  }
76
77  virtual void OnCreatedSpdyStream(int result) OVERRIDE {
78    events_.push_back(
79        SpdyWebSocketStreamEvent(SpdyWebSocketStreamEvent::EVENT_CREATED,
80                                 SpdyHeaderBlock(),
81                                 result,
82                                 std::string()));
83    if (!on_created_.is_null())
84      on_created_.Run(&events_.back());
85  }
86  virtual void OnSentSpdyHeaders() OVERRIDE {
87    events_.push_back(
88        SpdyWebSocketStreamEvent(SpdyWebSocketStreamEvent::EVENT_SENT_HEADERS,
89                                 SpdyHeaderBlock(),
90                                 OK,
91                                 std::string()));
92    if (!on_sent_data_.is_null())
93      on_sent_data_.Run(&events_.back());
94  }
95  virtual void OnSpdyResponseHeadersUpdated(
96      const SpdyHeaderBlock& response_headers) OVERRIDE {
97    events_.push_back(
98        SpdyWebSocketStreamEvent(
99            SpdyWebSocketStreamEvent::EVENT_RECEIVED_HEADER,
100            response_headers,
101            OK,
102            std::string()));
103    if (!on_received_header_.is_null())
104      on_received_header_.Run(&events_.back());
105  }
106  virtual void OnSentSpdyData(size_t bytes_sent) OVERRIDE {
107    events_.push_back(
108        SpdyWebSocketStreamEvent(
109            SpdyWebSocketStreamEvent::EVENT_SENT_DATA,
110            SpdyHeaderBlock(),
111            static_cast<int>(bytes_sent),
112            std::string()));
113    if (!on_sent_data_.is_null())
114      on_sent_data_.Run(&events_.back());
115  }
116  virtual void OnReceivedSpdyData(scoped_ptr<SpdyBuffer> buffer) OVERRIDE {
117    std::string buffer_data;
118    size_t buffer_len = 0;
119    if (buffer) {
120      buffer_len = buffer->GetRemainingSize();
121      buffer_data.append(buffer->GetRemainingData(), buffer_len);
122    }
123    events_.push_back(
124        SpdyWebSocketStreamEvent(
125            SpdyWebSocketStreamEvent::EVENT_RECEIVED_DATA,
126            SpdyHeaderBlock(),
127            buffer_len,
128            buffer_data));
129    if (!on_received_data_.is_null())
130      on_received_data_.Run(&events_.back());
131  }
132  virtual void OnCloseSpdyStream() OVERRIDE {
133    events_.push_back(
134        SpdyWebSocketStreamEvent(
135            SpdyWebSocketStreamEvent::EVENT_CLOSE,
136            SpdyHeaderBlock(),
137            OK,
138            std::string()));
139    if (!on_close_.is_null())
140      on_close_.Run(&events_.back());
141    if (!callback_.is_null())
142      callback_.Run(OK);
143  }
144
145  const std::vector<SpdyWebSocketStreamEvent>& GetSeenEvents() const {
146    return events_;
147  }
148
149 private:
150  std::vector<SpdyWebSocketStreamEvent> events_;
151  StreamEventCallback on_created_;
152  StreamEventCallback on_sent_headers_;
153  StreamEventCallback on_received_header_;
154  StreamEventCallback on_sent_data_;
155  StreamEventCallback on_received_data_;
156  StreamEventCallback on_close_;
157  CompletionCallback callback_;
158
159  DISALLOW_COPY_AND_ASSIGN(SpdyWebSocketStreamEventRecorder);
160};
161
162}  // namespace
163
164class SpdyWebSocketStreamTest
165    : public ::testing::Test,
166      public ::testing::WithParamInterface<NextProto> {
167 public:
168  OrderedSocketData* data() { return data_.get(); }
169
170  void DoSendHelloFrame(SpdyWebSocketStreamEvent* event) {
171    // Record the actual stream_id.
172    created_stream_id_ = websocket_stream_->stream_->stream_id();
173    websocket_stream_->SendData(kMessageFrame, kMessageFrameLength);
174  }
175
176  void DoSendClosingFrame(SpdyWebSocketStreamEvent* event) {
177    websocket_stream_->SendData(kClosingFrame, kClosingFrameLength);
178  }
179
180  void DoClose(SpdyWebSocketStreamEvent* event) {
181    websocket_stream_->Close();
182  }
183
184  void DoSync(SpdyWebSocketStreamEvent* event) {
185    sync_callback_.callback().Run(OK);
186  }
187
188 protected:
189  SpdyWebSocketStreamTest()
190      : spdy_util_(GetParam()),
191        spdy_settings_id_to_set_(SETTINGS_MAX_CONCURRENT_STREAMS),
192        spdy_settings_flags_to_set_(SETTINGS_FLAG_PLEASE_PERSIST),
193        spdy_settings_value_to_set_(1),
194        session_deps_(GetParam()),
195        stream_id_(0),
196        created_stream_id_(0) {}
197  virtual ~SpdyWebSocketStreamTest() {}
198
199  virtual void SetUp() {
200    host_port_pair_.set_host("example.com");
201    host_port_pair_.set_port(80);
202    spdy_session_key_ = SpdySessionKey(host_port_pair_,
203                                       ProxyServer::Direct(),
204                                       PRIVACY_MODE_DISABLED);
205
206    spdy_settings_to_send_[spdy_settings_id_to_set_] =
207        SettingsFlagsAndValue(
208            SETTINGS_FLAG_PERSISTED, spdy_settings_value_to_set_);
209  }
210
211  virtual void TearDown() {
212    base::MessageLoop::current()->RunUntilIdle();
213  }
214
215  void Prepare(SpdyStreamId stream_id) {
216    stream_id_ = stream_id;
217
218    request_frame_.reset(spdy_util_.ConstructSpdyWebSocketSynStream(
219        stream_id_,
220        "/echo",
221        "example.com",
222        "http://example.com/wsdemo"));
223
224    response_frame_.reset(
225        spdy_util_.ConstructSpdyWebSocketSynReply(stream_id_));
226
227    message_frame_.reset(spdy_util_.ConstructSpdyWebSocketDataFrame(
228        kMessageFrame,
229        kMessageFrameLength,
230        stream_id_,
231        false));
232
233    closing_frame_.reset(spdy_util_.ConstructSpdyWebSocketDataFrame(
234        kClosingFrame,
235        kClosingFrameLength,
236        stream_id_,
237        false));
238
239    closing_frame_fin_.reset(spdy_util_.ConstructSpdyWebSocketDataFrame(
240        kClosingFrame,
241        kClosingFrameLength,
242        stream_id_,
243        true));
244  }
245
246  void InitSession(MockRead* reads, size_t reads_count,
247                   MockWrite* writes, size_t writes_count) {
248    data_.reset(new OrderedSocketData(reads, reads_count,
249                                      writes, writes_count));
250    session_deps_.socket_factory->AddSocketDataProvider(data_.get());
251    http_session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_);
252    session_ = CreateInsecureSpdySession(
253        http_session_, spdy_session_key_, BoundNetLog());
254  }
255
256  void SendRequest() {
257    scoped_ptr<SpdyHeaderBlock> headers(new SpdyHeaderBlock);
258    spdy_util_.SetHeader("path", "/echo", headers.get());
259    spdy_util_.SetHeader("host", "example.com", headers.get());
260    spdy_util_.SetHeader("version", "WebSocket/13", headers.get());
261    spdy_util_.SetHeader("scheme", "ws", headers.get());
262    spdy_util_.SetHeader("origin", "http://example.com/wsdemo", headers.get());
263    websocket_stream_->SendRequest(headers.Pass());
264  }
265
266  SpdyWebSocketTestUtil spdy_util_;
267  SpdySettingsIds spdy_settings_id_to_set_;
268  SpdySettingsFlags spdy_settings_flags_to_set_;
269  uint32 spdy_settings_value_to_set_;
270  SettingsMap spdy_settings_to_send_;
271  SpdySessionDependencies session_deps_;
272  scoped_ptr<OrderedSocketData> data_;
273  scoped_refptr<HttpNetworkSession> http_session_;
274  base::WeakPtr<SpdySession> session_;
275  scoped_ptr<SpdyWebSocketStream> websocket_stream_;
276  SpdyStreamId stream_id_;
277  SpdyStreamId created_stream_id_;
278  scoped_ptr<SpdyFrame> request_frame_;
279  scoped_ptr<SpdyFrame> response_frame_;
280  scoped_ptr<SpdyFrame> message_frame_;
281  scoped_ptr<SpdyFrame> closing_frame_;
282  scoped_ptr<SpdyFrame> closing_frame_fin_;
283  HostPortPair host_port_pair_;
284  SpdySessionKey spdy_session_key_;
285  TestCompletionCallback completion_callback_;
286  TestCompletionCallback sync_callback_;
287
288  static const char kMessageFrame[];
289  static const char kClosingFrame[];
290  static const size_t kMessageFrameLength;
291  static const size_t kClosingFrameLength;
292};
293
294INSTANTIATE_TEST_CASE_P(
295    NextProto,
296    SpdyWebSocketStreamTest,
297    testing::Values(kProtoDeprecatedSPDY2,
298                    kProtoSPDY3, kProtoSPDY31, kProtoSPDY4));
299
300// TODO(toyoshim): Replace old framing data to new one, then use HEADERS and
301// data frames.
302const char SpdyWebSocketStreamTest::kMessageFrame[] = "\x81\x05hello";
303const char SpdyWebSocketStreamTest::kClosingFrame[] = "\x88\0";
304const size_t SpdyWebSocketStreamTest::kMessageFrameLength =
305    arraysize(SpdyWebSocketStreamTest::kMessageFrame) - 1;
306const size_t SpdyWebSocketStreamTest::kClosingFrameLength =
307    arraysize(SpdyWebSocketStreamTest::kClosingFrame) - 1;
308
309TEST_P(SpdyWebSocketStreamTest, Basic) {
310  Prepare(1);
311  MockWrite writes[] = {
312    CreateMockWrite(*request_frame_.get(), 1),
313    CreateMockWrite(*message_frame_.get(), 3),
314    CreateMockWrite(*closing_frame_.get(), 5)
315  };
316
317  MockRead reads[] = {
318    CreateMockRead(*response_frame_.get(), 2),
319    CreateMockRead(*message_frame_.get(), 4),
320    // Skip sequence 6 to notify closing has been sent.
321    CreateMockRead(*closing_frame_.get(), 7),
322    MockRead(SYNCHRONOUS, 0, 8)  // EOF cause OnCloseSpdyStream event.
323  };
324
325  InitSession(reads, arraysize(reads), writes, arraysize(writes));
326
327  SpdyWebSocketStreamEventRecorder delegate(completion_callback_.callback());
328  delegate.SetOnReceivedHeader(
329      base::Bind(&SpdyWebSocketStreamTest::DoSendHelloFrame,
330                 base::Unretained(this)));
331  delegate.SetOnReceivedData(
332      base::Bind(&SpdyWebSocketStreamTest::DoSendClosingFrame,
333                 base::Unretained(this)));
334
335  websocket_stream_.reset(new SpdyWebSocketStream(session_, &delegate));
336
337  BoundNetLog net_log;
338  GURL url("ws://example.com/echo");
339  ASSERT_EQ(OK, websocket_stream_->InitializeStream(url, HIGHEST, net_log));
340
341  ASSERT_TRUE(websocket_stream_->stream_.get());
342
343  SendRequest();
344
345  completion_callback_.WaitForResult();
346
347  EXPECT_EQ(stream_id_, created_stream_id_);
348
349  websocket_stream_.reset();
350
351  const std::vector<SpdyWebSocketStreamEvent>& events =
352      delegate.GetSeenEvents();
353  ASSERT_EQ(7U, events.size());
354
355  EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_SENT_HEADERS,
356            events[0].event_type);
357  EXPECT_EQ(OK, events[0].result);
358  EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_RECEIVED_HEADER,
359            events[1].event_type);
360  EXPECT_EQ(OK, events[1].result);
361  EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_SENT_DATA,
362            events[2].event_type);
363  EXPECT_EQ(static_cast<int>(kMessageFrameLength), events[2].result);
364  EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_RECEIVED_DATA,
365            events[3].event_type);
366  EXPECT_EQ(static_cast<int>(kMessageFrameLength), events[3].result);
367  EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_SENT_DATA,
368            events[4].event_type);
369  EXPECT_EQ(static_cast<int>(kClosingFrameLength), events[4].result);
370  EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_RECEIVED_DATA,
371            events[5].event_type);
372  EXPECT_EQ(static_cast<int>(kClosingFrameLength), events[5].result);
373  EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_CLOSE,
374            events[6].event_type);
375  EXPECT_EQ(OK, events[6].result);
376
377  // EOF close SPDY session.
378  EXPECT_FALSE(
379      HasSpdySession(http_session_->spdy_session_pool(), spdy_session_key_));
380  EXPECT_TRUE(data()->at_read_eof());
381  EXPECT_TRUE(data()->at_write_eof());
382}
383
384// A SPDY websocket may still send it's close frame after
385// recieving a close with SPDY stream FIN.
386TEST_P(SpdyWebSocketStreamTest, RemoteCloseWithFin) {
387  Prepare(1);
388  MockWrite writes[] = {
389    CreateMockWrite(*request_frame_.get(), 1),
390    CreateMockWrite(*closing_frame_.get(), 4),
391  };
392  MockRead reads[] = {
393    CreateMockRead(*response_frame_.get(), 2),
394    CreateMockRead(*closing_frame_fin_.get(), 3),
395    MockRead(SYNCHRONOUS, 0, 5)  // EOF cause OnCloseSpdyStream event.
396  };
397  InitSession(reads, arraysize(reads), writes, arraysize(writes));
398
399  SpdyWebSocketStreamEventRecorder delegate(completion_callback_.callback());
400  delegate.SetOnReceivedData(
401      base::Bind(&SpdyWebSocketStreamTest::DoSendClosingFrame,
402                 base::Unretained(this)));
403
404  websocket_stream_.reset(new SpdyWebSocketStream(session_, &delegate));
405  BoundNetLog net_log;
406  GURL url("ws://example.com/echo");
407  ASSERT_EQ(OK, websocket_stream_->InitializeStream(url, HIGHEST, net_log));
408
409  SendRequest();
410  completion_callback_.WaitForResult();
411  websocket_stream_.reset();
412
413  const std::vector<SpdyWebSocketStreamEvent>& events =
414      delegate.GetSeenEvents();
415  EXPECT_EQ(5U, events.size());
416
417  EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_SENT_HEADERS,
418            events[0].event_type);
419  EXPECT_EQ(OK, events[0].result);
420  EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_RECEIVED_HEADER,
421            events[1].event_type);
422  EXPECT_EQ(OK, events[1].result);
423  EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_RECEIVED_DATA,
424            events[2].event_type);
425  EXPECT_EQ(static_cast<int>(kClosingFrameLength), events[2].result);
426  EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_SENT_DATA,
427            events[3].event_type);
428  EXPECT_EQ(static_cast<int>(kClosingFrameLength), events[3].result);
429  EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_CLOSE,
430            events[4].event_type);
431  EXPECT_EQ(OK, events[4].result);
432
433  // EOF closes SPDY session.
434  EXPECT_FALSE(
435      HasSpdySession(http_session_->spdy_session_pool(), spdy_session_key_));
436  EXPECT_TRUE(data()->at_read_eof());
437  EXPECT_TRUE(data()->at_write_eof());
438}
439
440TEST_P(SpdyWebSocketStreamTest, DestructionBeforeClose) {
441  Prepare(1);
442  MockWrite writes[] = {
443    CreateMockWrite(*request_frame_.get(), 1),
444    CreateMockWrite(*message_frame_.get(), 3)
445  };
446
447  MockRead reads[] = {
448    CreateMockRead(*response_frame_.get(), 2),
449    CreateMockRead(*message_frame_.get(), 4),
450    MockRead(ASYNC, ERR_IO_PENDING, 5)
451  };
452
453  InitSession(reads, arraysize(reads), writes, arraysize(writes));
454
455  SpdyWebSocketStreamEventRecorder delegate(completion_callback_.callback());
456  delegate.SetOnReceivedHeader(
457      base::Bind(&SpdyWebSocketStreamTest::DoSendHelloFrame,
458                 base::Unretained(this)));
459  delegate.SetOnReceivedData(
460      base::Bind(&SpdyWebSocketStreamTest::DoSync,
461                 base::Unretained(this)));
462
463  websocket_stream_.reset(new SpdyWebSocketStream(session_, &delegate));
464
465  BoundNetLog net_log;
466  GURL url("ws://example.com/echo");
467  ASSERT_EQ(OK, websocket_stream_->InitializeStream(url, HIGHEST, net_log));
468
469  SendRequest();
470
471  sync_callback_.WaitForResult();
472
473  // WebSocketStream destruction remove its SPDY stream from the session.
474  EXPECT_TRUE(session_->IsStreamActive(stream_id_));
475  websocket_stream_.reset();
476  EXPECT_FALSE(session_->IsStreamActive(stream_id_));
477
478  const std::vector<SpdyWebSocketStreamEvent>& events =
479      delegate.GetSeenEvents();
480  ASSERT_GE(4U, events.size());
481
482  EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_SENT_HEADERS,
483            events[0].event_type);
484  EXPECT_EQ(OK, events[0].result);
485  EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_RECEIVED_HEADER,
486            events[1].event_type);
487  EXPECT_EQ(OK, events[1].result);
488  EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_SENT_DATA,
489            events[2].event_type);
490  EXPECT_EQ(static_cast<int>(kMessageFrameLength), events[2].result);
491  EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_RECEIVED_DATA,
492            events[3].event_type);
493  EXPECT_EQ(static_cast<int>(kMessageFrameLength), events[3].result);
494
495  EXPECT_TRUE(
496      HasSpdySession(http_session_->spdy_session_pool(), spdy_session_key_));
497  EXPECT_TRUE(data()->at_read_eof());
498  EXPECT_TRUE(data()->at_write_eof());
499}
500
501TEST_P(SpdyWebSocketStreamTest, DestructionAfterExplicitClose) {
502  Prepare(1);
503  MockWrite writes[] = {
504    CreateMockWrite(*request_frame_.get(), 1),
505    CreateMockWrite(*message_frame_.get(), 3),
506    CreateMockWrite(*closing_frame_.get(), 5)
507  };
508
509  MockRead reads[] = {
510    CreateMockRead(*response_frame_.get(), 2),
511    CreateMockRead(*message_frame_.get(), 4),
512    MockRead(ASYNC, ERR_IO_PENDING, 6)
513  };
514
515  InitSession(reads, arraysize(reads), writes, arraysize(writes));
516
517  SpdyWebSocketStreamEventRecorder delegate(completion_callback_.callback());
518  delegate.SetOnReceivedHeader(
519      base::Bind(&SpdyWebSocketStreamTest::DoSendHelloFrame,
520                 base::Unretained(this)));
521  delegate.SetOnReceivedData(
522      base::Bind(&SpdyWebSocketStreamTest::DoClose,
523                 base::Unretained(this)));
524
525  websocket_stream_.reset(new SpdyWebSocketStream(session_, &delegate));
526
527  BoundNetLog net_log;
528  GURL url("ws://example.com/echo");
529  ASSERT_EQ(OK, websocket_stream_->InitializeStream(url, HIGHEST, net_log));
530
531  SendRequest();
532
533  completion_callback_.WaitForResult();
534
535  // SPDY stream has already been removed from the session by Close().
536  EXPECT_FALSE(session_->IsStreamActive(stream_id_));
537  websocket_stream_.reset();
538
539  const std::vector<SpdyWebSocketStreamEvent>& events =
540      delegate.GetSeenEvents();
541  ASSERT_EQ(5U, events.size());
542
543  EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_SENT_HEADERS,
544            events[0].event_type);
545  EXPECT_EQ(OK, events[0].result);
546  EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_RECEIVED_HEADER,
547            events[1].event_type);
548  EXPECT_EQ(OK, events[1].result);
549  EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_SENT_DATA,
550            events[2].event_type);
551  EXPECT_EQ(static_cast<int>(kMessageFrameLength), events[2].result);
552  EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_RECEIVED_DATA,
553            events[3].event_type);
554  EXPECT_EQ(static_cast<int>(kMessageFrameLength), events[3].result);
555  EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_CLOSE, events[4].event_type);
556
557  EXPECT_TRUE(
558      HasSpdySession(http_session_->spdy_session_pool(), spdy_session_key_));
559}
560
561TEST_P(SpdyWebSocketStreamTest, IOPending) {
562  Prepare(1);
563  scoped_ptr<SpdyFrame> settings_frame(
564      spdy_util_.ConstructSpdySettings(spdy_settings_to_send_));
565  scoped_ptr<SpdyFrame> settings_ack(spdy_util_.ConstructSpdySettingsAck());
566  MockWrite writes[] = {
567    CreateMockWrite(*settings_ack, 1),
568    CreateMockWrite(*request_frame_.get(), 2),
569    CreateMockWrite(*message_frame_.get(), 4),
570    CreateMockWrite(*closing_frame_.get(), 6)
571  };
572
573  MockRead reads[] = {
574    CreateMockRead(*settings_frame.get(), 0),
575    CreateMockRead(*response_frame_.get(), 3),
576    CreateMockRead(*message_frame_.get(), 5),
577    CreateMockRead(*closing_frame_.get(), 7),
578    MockRead(SYNCHRONOUS, 0, 8)  // EOF cause OnCloseSpdyStream event.
579  };
580
581  DeterministicSocketData data(reads, arraysize(reads),
582                               writes, arraysize(writes));
583  session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
584  http_session_ =
585      SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
586
587  session_ = CreateInsecureSpdySession(
588      http_session_, spdy_session_key_, BoundNetLog());
589
590  // Create a dummy WebSocketStream which cause ERR_IO_PENDING to another
591  // WebSocketStream under test.
592  SpdyWebSocketStreamEventRecorder block_delegate((CompletionCallback()));
593
594  scoped_ptr<SpdyWebSocketStream> block_stream(
595      new SpdyWebSocketStream(session_, &block_delegate));
596  BoundNetLog block_net_log;
597  GURL block_url("ws://example.com/block");
598  ASSERT_EQ(OK,
599            block_stream->InitializeStream(block_url, HIGHEST, block_net_log));
600
601  data.RunFor(1);
602
603  // Create a WebSocketStream under test.
604  SpdyWebSocketStreamEventRecorder delegate(completion_callback_.callback());
605  delegate.SetOnCreated(
606      base::Bind(&SpdyWebSocketStreamTest::DoSync,
607                 base::Unretained(this)));
608  delegate.SetOnReceivedHeader(
609      base::Bind(&SpdyWebSocketStreamTest::DoSendHelloFrame,
610                 base::Unretained(this)));
611  delegate.SetOnReceivedData(
612      base::Bind(&SpdyWebSocketStreamTest::DoSendClosingFrame,
613                 base::Unretained(this)));
614
615  websocket_stream_.reset(new SpdyWebSocketStream(session_, &delegate));
616  BoundNetLog net_log;
617  GURL url("ws://example.com/echo");
618  ASSERT_EQ(ERR_IO_PENDING, websocket_stream_->InitializeStream(
619      url, HIGHEST, net_log));
620
621  // Delete the fist stream to allow create the second stream.
622  block_stream.reset();
623  ASSERT_EQ(OK, sync_callback_.WaitForResult());
624
625  SendRequest();
626
627  data.RunFor(8);
628  completion_callback_.WaitForResult();
629
630  websocket_stream_.reset();
631
632  const std::vector<SpdyWebSocketStreamEvent>& block_events =
633      block_delegate.GetSeenEvents();
634  ASSERT_EQ(0U, block_events.size());
635
636  const std::vector<SpdyWebSocketStreamEvent>& events =
637      delegate.GetSeenEvents();
638  ASSERT_EQ(8U, events.size());
639  EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_CREATED,
640            events[0].event_type);
641  EXPECT_EQ(0, events[0].result);
642  EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_SENT_HEADERS,
643            events[1].event_type);
644  EXPECT_EQ(OK, events[1].result);
645  EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_RECEIVED_HEADER,
646            events[2].event_type);
647  EXPECT_EQ(OK, events[2].result);
648  EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_SENT_DATA,
649            events[3].event_type);
650  EXPECT_EQ(static_cast<int>(kMessageFrameLength), events[3].result);
651  EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_RECEIVED_DATA,
652            events[4].event_type);
653  EXPECT_EQ(static_cast<int>(kMessageFrameLength), events[4].result);
654  EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_SENT_DATA,
655            events[5].event_type);
656  EXPECT_EQ(static_cast<int>(kClosingFrameLength), events[5].result);
657  EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_RECEIVED_DATA,
658            events[6].event_type);
659  EXPECT_EQ(static_cast<int>(kClosingFrameLength), events[6].result);
660  EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_CLOSE,
661            events[7].event_type);
662  EXPECT_EQ(OK, events[7].result);
663
664  // EOF close SPDY session.
665  EXPECT_FALSE(
666      HasSpdySession(http_session_->spdy_session_pool(), spdy_session_key_));
667  EXPECT_TRUE(data.at_read_eof());
668  EXPECT_TRUE(data.at_write_eof());
669}
670
671}  // namespace net
672