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.
5 #include "net/spdy/spdy_websocket_stream.h"
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"
26 struct SpdyWebSocketStreamEvent
{
30 EVENT_RECEIVED_HEADER
,
35 SpdyWebSocketStreamEvent(EventType type
,
36 const SpdyHeaderBlock
& headers
,
38 const std::string
& data
)
45 SpdyHeaderBlock headers
;
50 class SpdyWebSocketStreamEventRecorder
: public SpdyWebSocketStream::Delegate
{
52 explicit SpdyWebSocketStreamEventRecorder(const CompletionCallback
& callback
)
53 : callback_(callback
) {}
54 virtual ~SpdyWebSocketStreamEventRecorder() {}
56 typedef base::Callback
<void(SpdyWebSocketStreamEvent
*)> StreamEventCallback
;
58 void SetOnCreated(const StreamEventCallback
& callback
) {
59 on_created_
= callback
;
61 void SetOnSentHeaders(const StreamEventCallback
& callback
) {
62 on_sent_headers_
= callback
;
64 void SetOnReceivedHeader(const StreamEventCallback
& callback
) {
65 on_received_header_
= callback
;
67 void SetOnSentData(const StreamEventCallback
& callback
) {
68 on_sent_data_
= callback
;
70 void SetOnReceivedData(const StreamEventCallback
& callback
) {
71 on_received_data_
= callback
;
73 void SetOnClose(const StreamEventCallback
& callback
) {
77 virtual void OnCreatedSpdyStream(int result
) OVERRIDE
{
79 SpdyWebSocketStreamEvent(SpdyWebSocketStreamEvent::EVENT_CREATED
,
83 if (!on_created_
.is_null())
84 on_created_
.Run(&events_
.back());
86 virtual void OnSentSpdyHeaders() OVERRIDE
{
88 SpdyWebSocketStreamEvent(SpdyWebSocketStreamEvent::EVENT_SENT_HEADERS
,
92 if (!on_sent_data_
.is_null())
93 on_sent_data_
.Run(&events_
.back());
95 virtual void OnSpdyResponseHeadersUpdated(
96 const SpdyHeaderBlock
& response_headers
) OVERRIDE
{
98 SpdyWebSocketStreamEvent(
99 SpdyWebSocketStreamEvent::EVENT_RECEIVED_HEADER
,
103 if (!on_received_header_
.is_null())
104 on_received_header_
.Run(&events_
.back());
106 virtual void OnSentSpdyData(size_t bytes_sent
) OVERRIDE
{
108 SpdyWebSocketStreamEvent(
109 SpdyWebSocketStreamEvent::EVENT_SENT_DATA
,
111 static_cast<int>(bytes_sent
),
113 if (!on_sent_data_
.is_null())
114 on_sent_data_
.Run(&events_
.back());
116 virtual void OnReceivedSpdyData(scoped_ptr
<SpdyBuffer
> buffer
) OVERRIDE
{
117 std::string buffer_data
;
118 size_t buffer_len
= 0;
120 buffer_len
= buffer
->GetRemainingSize();
121 buffer_data
.append(buffer
->GetRemainingData(), buffer_len
);
124 SpdyWebSocketStreamEvent(
125 SpdyWebSocketStreamEvent::EVENT_RECEIVED_DATA
,
129 if (!on_received_data_
.is_null())
130 on_received_data_
.Run(&events_
.back());
132 virtual void OnCloseSpdyStream() OVERRIDE
{
134 SpdyWebSocketStreamEvent(
135 SpdyWebSocketStreamEvent::EVENT_CLOSE
,
139 if (!on_close_
.is_null())
140 on_close_
.Run(&events_
.back());
141 if (!callback_
.is_null())
145 const std::vector
<SpdyWebSocketStreamEvent
>& GetSeenEvents() const {
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_
;
159 DISALLOW_COPY_AND_ASSIGN(SpdyWebSocketStreamEventRecorder
);
164 class SpdyWebSocketStreamTest
165 : public ::testing::Test
,
166 public ::testing::WithParamInterface
<NextProto
> {
168 OrderedSocketData
* data() { return data_
.get(); }
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
);
176 void DoSendClosingFrame(SpdyWebSocketStreamEvent
* event
) {
177 websocket_stream_
->SendData(kClosingFrame
, kClosingFrameLength
);
180 void DoClose(SpdyWebSocketStreamEvent
* event
) {
181 websocket_stream_
->Close();
184 void DoSync(SpdyWebSocketStreamEvent
* event
) {
185 sync_callback_
.callback().Run(OK
);
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()),
196 created_stream_id_(0) {}
197 virtual ~SpdyWebSocketStreamTest() {}
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
);
206 spdy_settings_to_send_
[spdy_settings_id_to_set_
] =
207 SettingsFlagsAndValue(
208 SETTINGS_FLAG_PERSISTED
, spdy_settings_value_to_set_
);
211 virtual void TearDown() {
212 base::MessageLoop::current()->RunUntilIdle();
215 void Prepare(SpdyStreamId stream_id
) {
216 stream_id_
= stream_id
;
218 request_frame_
.reset(spdy_util_
.ConstructSpdyWebSocketSynStream(
222 "http://example.com/wsdemo"));
224 response_frame_
.reset(
225 spdy_util_
.ConstructSpdyWebSocketSynReply(stream_id_
));
227 message_frame_
.reset(spdy_util_
.ConstructSpdyWebSocketDataFrame(
233 closing_frame_
.reset(spdy_util_
.ConstructSpdyWebSocketDataFrame(
239 closing_frame_fin_
.reset(spdy_util_
.ConstructSpdyWebSocketDataFrame(
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());
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());
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_
;
288 static const char kMessageFrame
[];
289 static const char kClosingFrame
[];
290 static const size_t kMessageFrameLength
;
291 static const size_t kClosingFrameLength
;
294 INSTANTIATE_TEST_CASE_P(
296 SpdyWebSocketStreamTest
,
297 testing::Values(kProtoDeprecatedSPDY2
,
298 kProtoSPDY3
, kProtoSPDY31
, kProtoSPDY4
));
300 // TODO(toyoshim): Replace old framing data to new one, then use HEADERS and
302 const char SpdyWebSocketStreamTest::kMessageFrame
[] = "\x81\x05hello";
303 const char SpdyWebSocketStreamTest::kClosingFrame
[] = "\x88\0";
304 const size_t SpdyWebSocketStreamTest::kMessageFrameLength
=
305 arraysize(SpdyWebSocketStreamTest::kMessageFrame
) - 1;
306 const size_t SpdyWebSocketStreamTest::kClosingFrameLength
=
307 arraysize(SpdyWebSocketStreamTest::kClosingFrame
) - 1;
309 TEST_P(SpdyWebSocketStreamTest
, Basic
) {
311 MockWrite writes
[] = {
312 CreateMockWrite(*request_frame_
.get(), 1),
313 CreateMockWrite(*message_frame_
.get(), 3),
314 CreateMockWrite(*closing_frame_
.get(), 5)
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.
325 InitSession(reads
, arraysize(reads
), writes
, arraysize(writes
));
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)));
335 websocket_stream_
.reset(new SpdyWebSocketStream(session_
, &delegate
));
338 GURL
url("ws://example.com/echo");
339 ASSERT_EQ(OK
, websocket_stream_
->InitializeStream(url
, HIGHEST
, net_log
));
341 ASSERT_TRUE(websocket_stream_
->stream_
.get());
345 completion_callback_
.WaitForResult();
347 EXPECT_EQ(stream_id_
, created_stream_id_
);
349 websocket_stream_
.reset();
351 const std::vector
<SpdyWebSocketStreamEvent
>& events
=
352 delegate
.GetSeenEvents();
353 ASSERT_EQ(7U, events
.size());
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
);
377 // EOF close SPDY session.
379 HasSpdySession(http_session_
->spdy_session_pool(), spdy_session_key_
));
380 EXPECT_TRUE(data()->at_read_eof());
381 EXPECT_TRUE(data()->at_write_eof());
384 // A SPDY websocket may still send it's close frame after
385 // recieving a close with SPDY stream FIN.
386 TEST_P(SpdyWebSocketStreamTest
, RemoteCloseWithFin
) {
388 MockWrite writes
[] = {
389 CreateMockWrite(*request_frame_
.get(), 1),
390 CreateMockWrite(*closing_frame_
.get(), 4),
393 CreateMockRead(*response_frame_
.get(), 2),
394 CreateMockRead(*closing_frame_fin_
.get(), 3),
395 MockRead(SYNCHRONOUS
, 0, 5) // EOF cause OnCloseSpdyStream event.
397 InitSession(reads
, arraysize(reads
), writes
, arraysize(writes
));
399 SpdyWebSocketStreamEventRecorder
delegate(completion_callback_
.callback());
400 delegate
.SetOnReceivedData(
401 base::Bind(&SpdyWebSocketStreamTest::DoSendClosingFrame
,
402 base::Unretained(this)));
404 websocket_stream_
.reset(new SpdyWebSocketStream(session_
, &delegate
));
406 GURL
url("ws://example.com/echo");
407 ASSERT_EQ(OK
, websocket_stream_
->InitializeStream(url
, HIGHEST
, net_log
));
410 completion_callback_
.WaitForResult();
411 websocket_stream_
.reset();
413 const std::vector
<SpdyWebSocketStreamEvent
>& events
=
414 delegate
.GetSeenEvents();
415 EXPECT_EQ(5U, events
.size());
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
);
433 // EOF closes SPDY session.
435 HasSpdySession(http_session_
->spdy_session_pool(), spdy_session_key_
));
436 EXPECT_TRUE(data()->at_read_eof());
437 EXPECT_TRUE(data()->at_write_eof());
440 TEST_P(SpdyWebSocketStreamTest
, DestructionBeforeClose
) {
442 MockWrite writes
[] = {
443 CreateMockWrite(*request_frame_
.get(), 1),
444 CreateMockWrite(*message_frame_
.get(), 3)
448 CreateMockRead(*response_frame_
.get(), 2),
449 CreateMockRead(*message_frame_
.get(), 4),
450 MockRead(ASYNC
, ERR_IO_PENDING
, 5)
453 InitSession(reads
, arraysize(reads
), writes
, arraysize(writes
));
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)));
463 websocket_stream_
.reset(new SpdyWebSocketStream(session_
, &delegate
));
466 GURL
url("ws://example.com/echo");
467 ASSERT_EQ(OK
, websocket_stream_
->InitializeStream(url
, HIGHEST
, net_log
));
471 sync_callback_
.WaitForResult();
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_
));
478 const std::vector
<SpdyWebSocketStreamEvent
>& events
=
479 delegate
.GetSeenEvents();
480 ASSERT_GE(4U, events
.size());
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
);
496 HasSpdySession(http_session_
->spdy_session_pool(), spdy_session_key_
));
497 EXPECT_TRUE(data()->at_read_eof());
498 EXPECT_TRUE(data()->at_write_eof());
501 TEST_P(SpdyWebSocketStreamTest
, DestructionAfterExplicitClose
) {
503 MockWrite writes
[] = {
504 CreateMockWrite(*request_frame_
.get(), 1),
505 CreateMockWrite(*message_frame_
.get(), 3),
506 CreateMockWrite(*closing_frame_
.get(), 5)
510 CreateMockRead(*response_frame_
.get(), 2),
511 CreateMockRead(*message_frame_
.get(), 4),
512 MockRead(ASYNC
, ERR_IO_PENDING
, 6)
515 InitSession(reads
, arraysize(reads
), writes
, arraysize(writes
));
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)));
525 websocket_stream_
.reset(new SpdyWebSocketStream(session_
, &delegate
));
528 GURL
url("ws://example.com/echo");
529 ASSERT_EQ(OK
, websocket_stream_
->InitializeStream(url
, HIGHEST
, net_log
));
533 completion_callback_
.WaitForResult();
535 // SPDY stream has already been removed from the session by Close().
536 EXPECT_FALSE(session_
->IsStreamActive(stream_id_
));
537 websocket_stream_
.reset();
539 const std::vector
<SpdyWebSocketStreamEvent
>& events
=
540 delegate
.GetSeenEvents();
541 ASSERT_EQ(5U, events
.size());
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
);
558 HasSpdySession(http_session_
->spdy_session_pool(), spdy_session_key_
));
561 TEST_P(SpdyWebSocketStreamTest
, IOPending
) {
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)
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.
581 DeterministicSocketData
data(reads
, arraysize(reads
),
582 writes
, arraysize(writes
));
583 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
585 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_
);
587 session_
= CreateInsecureSpdySession(
588 http_session_
, spdy_session_key_
, BoundNetLog());
590 // Create a dummy WebSocketStream which cause ERR_IO_PENDING to another
591 // WebSocketStream under test.
592 SpdyWebSocketStreamEventRecorder
block_delegate((CompletionCallback()));
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");
599 block_stream
->InitializeStream(block_url
, HIGHEST
, block_net_log
));
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)));
615 websocket_stream_
.reset(new SpdyWebSocketStream(session_
, &delegate
));
617 GURL
url("ws://example.com/echo");
618 ASSERT_EQ(ERR_IO_PENDING
, websocket_stream_
->InitializeStream(
619 url
, HIGHEST
, net_log
));
621 // Delete the fist stream to allow create the second stream.
622 block_stream
.reset();
623 ASSERT_EQ(OK
, sync_callback_
.WaitForResult());
628 completion_callback_
.WaitForResult();
630 websocket_stream_
.reset();
632 const std::vector
<SpdyWebSocketStreamEvent
>& block_events
=
633 block_delegate
.GetSeenEvents();
634 ASSERT_EQ(0U, block_events
.size());
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
);
664 // EOF close SPDY session.
666 HasSpdySession(http_session_
->spdy_session_pool(), spdy_session_key_
));
667 EXPECT_TRUE(data
.at_read_eof());
668 EXPECT_TRUE(data
.at_write_eof());