• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
22 namespace net {
23 
24 namespace {
25 
26 struct 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   };
SpdyWebSocketStreamEventnet::__anon14bbe03e0111::SpdyWebSocketStreamEvent35   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 
50 class SpdyWebSocketStreamEventRecorder : public SpdyWebSocketStream::Delegate {
51  public:
SpdyWebSocketStreamEventRecorder(const CompletionCallback & callback)52   explicit SpdyWebSocketStreamEventRecorder(const CompletionCallback& callback)
53       : callback_(callback) {}
~SpdyWebSocketStreamEventRecorder()54   virtual ~SpdyWebSocketStreamEventRecorder() {}
55 
56   typedef base::Callback<void(SpdyWebSocketStreamEvent*)> StreamEventCallback;
57 
SetOnCreated(const StreamEventCallback & callback)58   void SetOnCreated(const StreamEventCallback& callback) {
59     on_created_ = callback;
60   }
SetOnSentHeaders(const StreamEventCallback & callback)61   void SetOnSentHeaders(const StreamEventCallback& callback) {
62     on_sent_headers_ = callback;
63   }
SetOnReceivedHeader(const StreamEventCallback & callback)64   void SetOnReceivedHeader(const StreamEventCallback& callback) {
65     on_received_header_ = callback;
66   }
SetOnSentData(const StreamEventCallback & callback)67   void SetOnSentData(const StreamEventCallback& callback) {
68     on_sent_data_ = callback;
69   }
SetOnReceivedData(const StreamEventCallback & callback)70   void SetOnReceivedData(const StreamEventCallback& callback) {
71     on_received_data_ = callback;
72   }
SetOnClose(const StreamEventCallback & callback)73   void SetOnClose(const StreamEventCallback& callback) {
74     on_close_ = callback;
75   }
76 
OnCreatedSpdyStream(int result)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   }
OnSentSpdyHeaders()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   }
OnSpdyResponseHeadersUpdated(const SpdyHeaderBlock & response_headers)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   }
OnSentSpdyData(size_t bytes_sent)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   }
OnReceivedSpdyData(scoped_ptr<SpdyBuffer> buffer)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   }
OnCloseSpdyStream()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 
GetSeenEvents() const145   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 
164 class SpdyWebSocketStreamTest
165     : public ::testing::Test,
166       public ::testing::WithParamInterface<NextProto> {
167  public:
data()168   OrderedSocketData* data() { return data_.get(); }
169 
DoSendHelloFrame(SpdyWebSocketStreamEvent * event)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 
DoSendClosingFrame(SpdyWebSocketStreamEvent * event)176   void DoSendClosingFrame(SpdyWebSocketStreamEvent* event) {
177     websocket_stream_->SendData(kClosingFrame, kClosingFrameLength);
178   }
179 
DoClose(SpdyWebSocketStreamEvent * event)180   void DoClose(SpdyWebSocketStreamEvent* event) {
181     websocket_stream_->Close();
182   }
183 
DoSync(SpdyWebSocketStreamEvent * event)184   void DoSync(SpdyWebSocketStreamEvent* event) {
185     sync_callback_.callback().Run(OK);
186   }
187 
188  protected:
SpdyWebSocketStreamTest()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) {}
~SpdyWebSocketStreamTest()197   virtual ~SpdyWebSocketStreamTest() {}
198 
SetUp()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                                        kPrivacyModeDisabled);
205 
206     spdy_settings_to_send_[spdy_settings_id_to_set_] =
207         SettingsFlagsAndValue(
208             SETTINGS_FLAG_PERSISTED, spdy_settings_value_to_set_);
209   }
210 
TearDown()211   virtual void TearDown() {
212     base::MessageLoop::current()->RunUntilIdle();
213   }
214 
Prepare(SpdyStreamId stream_id)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 
InitSession(MockRead * reads,size_t reads_count,MockWrite * writes,size_t writes_count)240   void InitSession(MockRead* reads, size_t reads_count,
241                    MockWrite* writes, size_t writes_count) {
242     data_.reset(new OrderedSocketData(reads, reads_count,
243                                       writes, writes_count));
244     session_deps_.socket_factory->AddSocketDataProvider(data_.get());
245     http_session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_);
246     session_ = CreateInsecureSpdySession(
247         http_session_, spdy_session_key_, BoundNetLog());
248   }
249 
SendRequest()250   void SendRequest() {
251     scoped_ptr<SpdyHeaderBlock> headers(new SpdyHeaderBlock);
252     spdy_util_.SetHeader("path", "/echo", headers.get());
253     spdy_util_.SetHeader("host", "example.com", headers.get());
254     spdy_util_.SetHeader("version", "WebSocket/13", headers.get());
255     spdy_util_.SetHeader("scheme", "ws", headers.get());
256     spdy_util_.SetHeader("origin", "http://example.com/wsdemo", headers.get());
257     websocket_stream_->SendRequest(headers.Pass());
258   }
259 
260   SpdyWebSocketTestUtil spdy_util_;
261   SpdySettingsIds spdy_settings_id_to_set_;
262   SpdySettingsFlags spdy_settings_flags_to_set_;
263   uint32 spdy_settings_value_to_set_;
264   SettingsMap spdy_settings_to_send_;
265   SpdySessionDependencies session_deps_;
266   scoped_ptr<OrderedSocketData> data_;
267   scoped_refptr<HttpNetworkSession> http_session_;
268   base::WeakPtr<SpdySession> session_;
269   scoped_ptr<SpdyWebSocketStream> websocket_stream_;
270   SpdyStreamId stream_id_;
271   SpdyStreamId created_stream_id_;
272   scoped_ptr<SpdyFrame> request_frame_;
273   scoped_ptr<SpdyFrame> response_frame_;
274   scoped_ptr<SpdyFrame> message_frame_;
275   scoped_ptr<SpdyFrame> closing_frame_;
276   HostPortPair host_port_pair_;
277   SpdySessionKey spdy_session_key_;
278   TestCompletionCallback completion_callback_;
279   TestCompletionCallback sync_callback_;
280 
281   static const char kMessageFrame[];
282   static const char kClosingFrame[];
283   static const size_t kMessageFrameLength;
284   static const size_t kClosingFrameLength;
285 };
286 
287 INSTANTIATE_TEST_CASE_P(
288     NextProto,
289     SpdyWebSocketStreamTest,
290     testing::Values(kProtoDeprecatedSPDY2,
291                     kProtoSPDY3, kProtoSPDY31, kProtoSPDY4a2,
292                     kProtoHTTP2Draft04));
293 
294 // TODO(toyoshim): Replace old framing data to new one, then use HEADERS and
295 // data frames.
296 const char SpdyWebSocketStreamTest::kMessageFrame[] = "\x81\x05hello";
297 const char SpdyWebSocketStreamTest::kClosingFrame[] = "\x88\0";
298 const size_t SpdyWebSocketStreamTest::kMessageFrameLength =
299     arraysize(SpdyWebSocketStreamTest::kMessageFrame) - 1;
300 const size_t SpdyWebSocketStreamTest::kClosingFrameLength =
301     arraysize(SpdyWebSocketStreamTest::kClosingFrame) - 1;
302 
TEST_P(SpdyWebSocketStreamTest,Basic)303 TEST_P(SpdyWebSocketStreamTest, Basic) {
304   Prepare(1);
305   MockWrite writes[] = {
306     CreateMockWrite(*request_frame_.get(), 1),
307     CreateMockWrite(*message_frame_.get(), 3),
308     CreateMockWrite(*closing_frame_.get(), 5)
309   };
310 
311   MockRead reads[] = {
312     CreateMockRead(*response_frame_.get(), 2),
313     CreateMockRead(*message_frame_.get(), 4),
314     // Skip sequence 6 to notify closing has been sent.
315     CreateMockRead(*closing_frame_.get(), 7),
316     MockRead(SYNCHRONOUS, 0, 8)  // EOF cause OnCloseSpdyStream event.
317   };
318 
319   InitSession(reads, arraysize(reads), writes, arraysize(writes));
320 
321   SpdyWebSocketStreamEventRecorder delegate(completion_callback_.callback());
322   delegate.SetOnReceivedHeader(
323       base::Bind(&SpdyWebSocketStreamTest::DoSendHelloFrame,
324                  base::Unretained(this)));
325   delegate.SetOnReceivedData(
326       base::Bind(&SpdyWebSocketStreamTest::DoSendClosingFrame,
327                  base::Unretained(this)));
328 
329   websocket_stream_.reset(new SpdyWebSocketStream(session_, &delegate));
330 
331   BoundNetLog net_log;
332   GURL url("ws://example.com/echo");
333   ASSERT_EQ(OK, websocket_stream_->InitializeStream(url, HIGHEST, net_log));
334 
335   ASSERT_TRUE(websocket_stream_->stream_.get());
336 
337   SendRequest();
338 
339   completion_callback_.WaitForResult();
340 
341   EXPECT_EQ(stream_id_, created_stream_id_);
342 
343   websocket_stream_.reset();
344 
345   const std::vector<SpdyWebSocketStreamEvent>& events =
346       delegate.GetSeenEvents();
347   ASSERT_EQ(7U, events.size());
348 
349   EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_SENT_HEADERS,
350             events[0].event_type);
351   EXPECT_EQ(OK, events[0].result);
352   EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_RECEIVED_HEADER,
353             events[1].event_type);
354   EXPECT_EQ(OK, events[1].result);
355   EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_SENT_DATA,
356             events[2].event_type);
357   EXPECT_EQ(static_cast<int>(kMessageFrameLength), events[2].result);
358   EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_RECEIVED_DATA,
359             events[3].event_type);
360   EXPECT_EQ(static_cast<int>(kMessageFrameLength), events[3].result);
361   EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_SENT_DATA,
362             events[4].event_type);
363   EXPECT_EQ(static_cast<int>(kClosingFrameLength), events[4].result);
364   EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_RECEIVED_DATA,
365             events[5].event_type);
366   EXPECT_EQ(static_cast<int>(kClosingFrameLength), events[5].result);
367   EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_CLOSE,
368             events[6].event_type);
369   EXPECT_EQ(OK, events[6].result);
370 
371   // EOF close SPDY session.
372   EXPECT_FALSE(
373       HasSpdySession(http_session_->spdy_session_pool(), spdy_session_key_));
374   EXPECT_TRUE(data()->at_read_eof());
375   EXPECT_TRUE(data()->at_write_eof());
376 }
377 
TEST_P(SpdyWebSocketStreamTest,DestructionBeforeClose)378 TEST_P(SpdyWebSocketStreamTest, DestructionBeforeClose) {
379   Prepare(1);
380   MockWrite writes[] = {
381     CreateMockWrite(*request_frame_.get(), 1),
382     CreateMockWrite(*message_frame_.get(), 3)
383   };
384 
385   MockRead reads[] = {
386     CreateMockRead(*response_frame_.get(), 2),
387     CreateMockRead(*message_frame_.get(), 4),
388     MockRead(ASYNC, ERR_IO_PENDING, 5)
389   };
390 
391   InitSession(reads, arraysize(reads), writes, arraysize(writes));
392 
393   SpdyWebSocketStreamEventRecorder delegate(completion_callback_.callback());
394   delegate.SetOnReceivedHeader(
395       base::Bind(&SpdyWebSocketStreamTest::DoSendHelloFrame,
396                  base::Unretained(this)));
397   delegate.SetOnReceivedData(
398       base::Bind(&SpdyWebSocketStreamTest::DoSync,
399                  base::Unretained(this)));
400 
401   websocket_stream_.reset(new SpdyWebSocketStream(session_, &delegate));
402 
403   BoundNetLog net_log;
404   GURL url("ws://example.com/echo");
405   ASSERT_EQ(OK, websocket_stream_->InitializeStream(url, HIGHEST, net_log));
406 
407   SendRequest();
408 
409   sync_callback_.WaitForResult();
410 
411   // WebSocketStream destruction remove its SPDY stream from the session.
412   EXPECT_TRUE(session_->IsStreamActive(stream_id_));
413   websocket_stream_.reset();
414   EXPECT_FALSE(session_->IsStreamActive(stream_id_));
415 
416   const std::vector<SpdyWebSocketStreamEvent>& events =
417       delegate.GetSeenEvents();
418   ASSERT_GE(4U, events.size());
419 
420   EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_SENT_HEADERS,
421             events[0].event_type);
422   EXPECT_EQ(OK, events[0].result);
423   EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_RECEIVED_HEADER,
424             events[1].event_type);
425   EXPECT_EQ(OK, events[1].result);
426   EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_SENT_DATA,
427             events[2].event_type);
428   EXPECT_EQ(static_cast<int>(kMessageFrameLength), events[2].result);
429   EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_RECEIVED_DATA,
430             events[3].event_type);
431   EXPECT_EQ(static_cast<int>(kMessageFrameLength), events[3].result);
432 
433   EXPECT_TRUE(
434       HasSpdySession(http_session_->spdy_session_pool(), spdy_session_key_));
435   EXPECT_TRUE(data()->at_read_eof());
436   EXPECT_TRUE(data()->at_write_eof());
437 }
438 
TEST_P(SpdyWebSocketStreamTest,DestructionAfterExplicitClose)439 TEST_P(SpdyWebSocketStreamTest, DestructionAfterExplicitClose) {
440   Prepare(1);
441   MockWrite writes[] = {
442     CreateMockWrite(*request_frame_.get(), 1),
443     CreateMockWrite(*message_frame_.get(), 3),
444     CreateMockWrite(*closing_frame_.get(), 5)
445   };
446 
447   MockRead reads[] = {
448     CreateMockRead(*response_frame_.get(), 2),
449     CreateMockRead(*message_frame_.get(), 4),
450     MockRead(ASYNC, ERR_IO_PENDING, 6)
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::DoClose,
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   completion_callback_.WaitForResult();
472 
473   // SPDY stream has already been removed from the session by Close().
474   EXPECT_FALSE(session_->IsStreamActive(stream_id_));
475   websocket_stream_.reset();
476 
477   const std::vector<SpdyWebSocketStreamEvent>& events =
478       delegate.GetSeenEvents();
479   ASSERT_EQ(5U, events.size());
480 
481   EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_SENT_HEADERS,
482             events[0].event_type);
483   EXPECT_EQ(OK, events[0].result);
484   EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_RECEIVED_HEADER,
485             events[1].event_type);
486   EXPECT_EQ(OK, events[1].result);
487   EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_SENT_DATA,
488             events[2].event_type);
489   EXPECT_EQ(static_cast<int>(kMessageFrameLength), events[2].result);
490   EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_RECEIVED_DATA,
491             events[3].event_type);
492   EXPECT_EQ(static_cast<int>(kMessageFrameLength), events[3].result);
493   EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_CLOSE, events[4].event_type);
494 
495   EXPECT_TRUE(
496       HasSpdySession(http_session_->spdy_session_pool(), spdy_session_key_));
497 }
498 
TEST_P(SpdyWebSocketStreamTest,IOPending)499 TEST_P(SpdyWebSocketStreamTest, IOPending) {
500   Prepare(1);
501   scoped_ptr<SpdyFrame> settings_frame(
502       spdy_util_.ConstructSpdySettings(spdy_settings_to_send_));
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(*settings_frame.get(), 0),
511     CreateMockRead(*response_frame_.get(), 2),
512     CreateMockRead(*message_frame_.get(), 4),
513     CreateMockRead(*closing_frame_.get(), 6),
514     MockRead(SYNCHRONOUS, 0, 7)  // EOF cause OnCloseSpdyStream event.
515   };
516 
517   DeterministicSocketData data(reads, arraysize(reads),
518                                writes, arraysize(writes));
519   session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
520   http_session_ =
521       SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
522 
523   session_ = CreateInsecureSpdySession(
524       http_session_, spdy_session_key_, BoundNetLog());
525 
526   // Create a dummy WebSocketStream which cause ERR_IO_PENDING to another
527   // WebSocketStream under test.
528   SpdyWebSocketStreamEventRecorder block_delegate((CompletionCallback()));
529 
530   scoped_ptr<SpdyWebSocketStream> block_stream(
531       new SpdyWebSocketStream(session_, &block_delegate));
532   BoundNetLog block_net_log;
533   GURL block_url("ws://example.com/block");
534   ASSERT_EQ(OK,
535             block_stream->InitializeStream(block_url, HIGHEST, block_net_log));
536 
537   data.RunFor(1);
538 
539   // Create a WebSocketStream under test.
540   SpdyWebSocketStreamEventRecorder delegate(completion_callback_.callback());
541   delegate.SetOnCreated(
542       base::Bind(&SpdyWebSocketStreamTest::DoSync,
543                  base::Unretained(this)));
544   delegate.SetOnReceivedHeader(
545       base::Bind(&SpdyWebSocketStreamTest::DoSendHelloFrame,
546                  base::Unretained(this)));
547   delegate.SetOnReceivedData(
548       base::Bind(&SpdyWebSocketStreamTest::DoSendClosingFrame,
549                  base::Unretained(this)));
550 
551   websocket_stream_.reset(new SpdyWebSocketStream(session_, &delegate));
552   BoundNetLog net_log;
553   GURL url("ws://example.com/echo");
554   ASSERT_EQ(ERR_IO_PENDING, websocket_stream_->InitializeStream(
555       url, HIGHEST, net_log));
556 
557   // Delete the fist stream to allow create the second stream.
558   block_stream.reset();
559   ASSERT_EQ(OK, sync_callback_.WaitForResult());
560 
561   SendRequest();
562 
563   data.RunFor(7);
564   completion_callback_.WaitForResult();
565 
566   websocket_stream_.reset();
567 
568   const std::vector<SpdyWebSocketStreamEvent>& block_events =
569       block_delegate.GetSeenEvents();
570   ASSERT_EQ(0U, block_events.size());
571 
572   const std::vector<SpdyWebSocketStreamEvent>& events =
573       delegate.GetSeenEvents();
574   ASSERT_EQ(8U, events.size());
575   EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_CREATED,
576             events[0].event_type);
577   EXPECT_EQ(0, events[0].result);
578   EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_SENT_HEADERS,
579             events[1].event_type);
580   EXPECT_EQ(OK, events[1].result);
581   EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_RECEIVED_HEADER,
582             events[2].event_type);
583   EXPECT_EQ(OK, events[2].result);
584   EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_SENT_DATA,
585             events[3].event_type);
586   EXPECT_EQ(static_cast<int>(kMessageFrameLength), events[3].result);
587   EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_RECEIVED_DATA,
588             events[4].event_type);
589   EXPECT_EQ(static_cast<int>(kMessageFrameLength), events[4].result);
590   EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_SENT_DATA,
591             events[5].event_type);
592   EXPECT_EQ(static_cast<int>(kClosingFrameLength), events[5].result);
593   EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_RECEIVED_DATA,
594             events[6].event_type);
595   EXPECT_EQ(static_cast<int>(kClosingFrameLength), events[6].result);
596   EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_CLOSE,
597             events[7].event_type);
598   EXPECT_EQ(OK, events[7].result);
599 
600   // EOF close SPDY session.
601   EXPECT_FALSE(
602       HasSpdySession(http_session_->spdy_session_pool(), spdy_session_key_));
603   EXPECT_TRUE(data.at_read_eof());
604   EXPECT_TRUE(data.at_write_eof());
605 }
606 
607 }  // namespace net
608