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.
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/ssl_client_socket.h"
15 #include "net/spdy/spdy_http_utils.h"
16 #include "net/spdy/spdy_protocol.h"
17 #include "net/spdy/spdy_session.h"
18 #include "net/spdy/spdy_test_util_spdy3.h"
19 #include "net/spdy/spdy_websocket_test_util_spdy3.h"
20 #include "testing/gtest/include/gtest/gtest.h"
22 using namespace net::test_spdy3
;
28 struct SpdyWebSocketStreamEvent
{
32 EVENT_RECEIVED_HEADER
,
37 SpdyWebSocketStreamEvent(EventType type
,
38 const SpdyHeaderBlock
& headers
,
40 const std::string
& data
)
47 SpdyHeaderBlock headers
;
52 class SpdyWebSocketStreamEventRecorder
: public SpdyWebSocketStream::Delegate
{
54 explicit SpdyWebSocketStreamEventRecorder(const CompletionCallback
& callback
)
55 : callback_(callback
) {}
56 virtual ~SpdyWebSocketStreamEventRecorder() {}
58 typedef base::Callback
<void(SpdyWebSocketStreamEvent
*)> StreamEventCallback
;
60 void SetOnCreated(const StreamEventCallback
& callback
) {
61 on_created_
= callback
;
63 void SetOnSentHeaders(const StreamEventCallback
& callback
) {
64 on_sent_headers_
= callback
;
66 void SetOnReceivedHeader(const StreamEventCallback
& callback
) {
67 on_received_header_
= callback
;
69 void SetOnSentData(const StreamEventCallback
& callback
) {
70 on_sent_data_
= callback
;
72 void SetOnReceivedData(const StreamEventCallback
& callback
) {
73 on_received_data_
= callback
;
75 void SetOnClose(const StreamEventCallback
& callback
) {
79 virtual void OnCreatedSpdyStream(int result
) {
81 SpdyWebSocketStreamEvent(SpdyWebSocketStreamEvent::EVENT_CREATED
,
85 if (!on_created_
.is_null())
86 on_created_
.Run(&events_
.back());
88 virtual void OnSentSpdyHeaders(int result
) {
90 SpdyWebSocketStreamEvent(SpdyWebSocketStreamEvent::EVENT_SENT_HEADERS
,
94 if (!on_sent_data_
.is_null())
95 on_sent_data_
.Run(&events_
.back());
97 virtual int OnReceivedSpdyResponseHeader(
98 const SpdyHeaderBlock
& headers
, int status
) {
100 SpdyWebSocketStreamEvent(
101 SpdyWebSocketStreamEvent::EVENT_RECEIVED_HEADER
,
105 if (!on_received_header_
.is_null())
106 on_received_header_
.Run(&events_
.back());
109 virtual void OnSentSpdyData(int amount_sent
) {
111 SpdyWebSocketStreamEvent(
112 SpdyWebSocketStreamEvent::EVENT_SENT_DATA
,
116 if (!on_sent_data_
.is_null())
117 on_sent_data_
.Run(&events_
.back());
119 virtual void OnReceivedSpdyData(const char* data
, int length
) {
121 SpdyWebSocketStreamEvent(
122 SpdyWebSocketStreamEvent::EVENT_RECEIVED_DATA
,
125 std::string(data
, length
)));
126 if (!on_received_data_
.is_null())
127 on_received_data_
.Run(&events_
.back());
129 virtual void OnCloseSpdyStream() {
131 SpdyWebSocketStreamEvent(
132 SpdyWebSocketStreamEvent::EVENT_CLOSE
,
136 if (!on_close_
.is_null())
137 on_close_
.Run(&events_
.back());
138 if (!callback_
.is_null())
142 const std::vector
<SpdyWebSocketStreamEvent
>& GetSeenEvents() const {
147 std::vector
<SpdyWebSocketStreamEvent
> events_
;
148 StreamEventCallback on_created_
;
149 StreamEventCallback on_sent_headers_
;
150 StreamEventCallback on_received_header_
;
151 StreamEventCallback on_sent_data_
;
152 StreamEventCallback on_received_data_
;
153 StreamEventCallback on_close_
;
154 CompletionCallback callback_
;
156 DISALLOW_COPY_AND_ASSIGN(SpdyWebSocketStreamEventRecorder
);
161 class SpdyWebSocketStreamSpdy3Test
: public testing::Test
{
163 OrderedSocketData
* data() { return data_
.get(); }
165 void DoSendHelloFrame(SpdyWebSocketStreamEvent
* event
) {
166 // Record the actual stream_id.
167 created_stream_id_
= websocket_stream_
->stream_
->stream_id();
168 websocket_stream_
->SendData(kMessageFrame
, kMessageFrameLength
);
171 void DoSendClosingFrame(SpdyWebSocketStreamEvent
* event
) {
172 websocket_stream_
->SendData(kClosingFrame
, kClosingFrameLength
);
175 void DoClose(SpdyWebSocketStreamEvent
* event
) {
176 websocket_stream_
->Close();
179 void DoSync(SpdyWebSocketStreamEvent
* event
) {
180 sync_callback_
.callback().Run(OK
);
184 SpdyWebSocketStreamSpdy3Test() {}
185 virtual ~SpdyWebSocketStreamSpdy3Test() {}
187 virtual void SetUp() {
188 SpdySession::set_default_protocol(kProtoSPDY3
);
190 host_port_pair_
.set_host("example.com");
191 host_port_pair_
.set_port(80);
192 host_port_proxy_pair_
.first
= host_port_pair_
;
193 host_port_proxy_pair_
.second
= ProxyServer::Direct();
195 spdy_settings_id_to_set_
= SETTINGS_MAX_CONCURRENT_STREAMS
;
196 spdy_settings_flags_to_set_
= SETTINGS_FLAG_PLEASE_PERSIST
;
197 spdy_settings_value_to_set_
= 1;
199 spdy_settings_to_send_
[spdy_settings_id_to_set_
] =
200 SettingsFlagsAndValue(
201 SETTINGS_FLAG_PERSISTED
, spdy_settings_value_to_set_
);
204 virtual void TearDown() {
205 MessageLoop::current()->RunAllPending();
208 void Prepare(SpdyStreamId stream_id
) {
209 stream_id_
= stream_id
;
211 request_frame_
.reset(ConstructSpdyWebSocketSynStream(
215 "http://example.com/wsdemo"));
217 response_frame_
.reset(ConstructSpdyWebSocketSynReply(stream_id_
));
219 message_frame_
.reset(ConstructSpdyWebSocketDataFrame(
225 closing_frame_
.reset(ConstructSpdyWebSocketDataFrame(
232 int InitSession(MockRead
* reads
, size_t reads_count
,
233 MockWrite
* writes
, size_t writes_count
,
235 data_
.reset(new OrderedSocketData(reads
, reads_count
,
236 writes
, writes_count
));
237 session_deps_
.socket_factory
->AddSocketDataProvider(data_
.get());
238 http_session_
= SpdySessionDependencies::SpdyCreateSession(&session_deps_
);
239 SpdySessionPool
* spdy_session_pool(http_session_
->spdy_session_pool());
242 // Set max concurrent streams to 1.
243 spdy_session_pool
->http_server_properties()->SetSpdySetting(
245 spdy_settings_id_to_set_
,
246 spdy_settings_flags_to_set_
,
247 spdy_settings_value_to_set_
);
250 EXPECT_FALSE(spdy_session_pool
->HasSession(host_port_proxy_pair_
));
251 session_
= spdy_session_pool
->Get(host_port_proxy_pair_
, BoundNetLog());
252 EXPECT_TRUE(spdy_session_pool
->HasSession(host_port_proxy_pair_
));
253 transport_params_
= new TransportSocketParams(host_port_pair_
, MEDIUM
,
255 OnHostResolutionCallback());
256 TestCompletionCallback callback
;
257 scoped_ptr
<ClientSocketHandle
> connection(new ClientSocketHandle
);
258 EXPECT_EQ(ERR_IO_PENDING
,
259 connection
->Init(host_port_pair_
.ToString(), transport_params_
,
260 MEDIUM
, callback
.callback(),
261 http_session_
->GetTransportSocketPool(
262 HttpNetworkSession::NORMAL_SOCKET_POOL
),
264 EXPECT_EQ(OK
, callback
.WaitForResult());
265 return session_
->InitializeWithSocket(connection
.release(), false, OK
);
269 scoped_ptr
<SpdyHeaderBlock
> headers(new SpdyHeaderBlock
);
270 (*headers
)[":path"] = "/echo";
271 (*headers
)[":host"] = "example.com";
272 (*headers
)[":version"] = "WebSocket/13";
273 (*headers
)[":scheme"] = "ws";
274 (*headers
)[":origin"] = "http://example.com/wsdemo";
276 websocket_stream_
->SendRequest(headers
.Pass());
279 SpdySettingsIds spdy_settings_id_to_set_
;
280 SpdySettingsFlags spdy_settings_flags_to_set_
;
281 uint32 spdy_settings_value_to_set_
;
282 SettingsMap spdy_settings_to_send_
;
283 SpdySessionDependencies session_deps_
;
284 scoped_ptr
<OrderedSocketData
> data_
;
285 scoped_refptr
<HttpNetworkSession
> http_session_
;
286 scoped_refptr
<SpdySession
> session_
;
287 scoped_refptr
<TransportSocketParams
> transport_params_
;
288 scoped_ptr
<SpdyWebSocketStream
> websocket_stream_
;
289 SpdyStreamId stream_id_
;
290 SpdyStreamId created_stream_id_
;
291 scoped_ptr
<SpdyFrame
> request_frame_
;
292 scoped_ptr
<SpdyFrame
> response_frame_
;
293 scoped_ptr
<SpdyFrame
> message_frame_
;
294 scoped_ptr
<SpdyFrame
> closing_frame_
;
295 HostPortPair host_port_pair_
;
296 HostPortProxyPair host_port_proxy_pair_
;
297 TestCompletionCallback completion_callback_
;
298 TestCompletionCallback sync_callback_
;
300 static const char kMessageFrame
[];
301 static const char kClosingFrame
[];
302 static const size_t kMessageFrameLength
;
303 static const size_t kClosingFrameLength
;
306 SpdyTestStateHelper spdy_state_
;
309 // TODO(toyoshim): Replace old framing data to new one, then use HEADERS and
311 const char SpdyWebSocketStreamSpdy3Test::kMessageFrame
[] = "\x81\x05hello";
312 const char SpdyWebSocketStreamSpdy3Test::kClosingFrame
[] = "\x88\0";
313 const size_t SpdyWebSocketStreamSpdy3Test::kMessageFrameLength
=
314 arraysize(SpdyWebSocketStreamSpdy3Test::kMessageFrame
) - 1;
315 const size_t SpdyWebSocketStreamSpdy3Test::kClosingFrameLength
=
316 arraysize(SpdyWebSocketStreamSpdy3Test::kClosingFrame
) - 1;
318 TEST_F(SpdyWebSocketStreamSpdy3Test
, Basic
) {
320 MockWrite writes
[] = {
321 CreateMockWrite(*request_frame_
.get(), 1),
322 CreateMockWrite(*message_frame_
.get(), 3),
323 CreateMockWrite(*closing_frame_
.get(), 5)
327 CreateMockRead(*response_frame_
.get(), 2),
328 CreateMockRead(*message_frame_
.get(), 4),
329 // Skip sequence 6 to notify closing has been sent.
330 CreateMockRead(*closing_frame_
.get(), 7),
331 MockRead(SYNCHRONOUS
, 0, 8) // EOF cause OnCloseSpdyStream event.
334 EXPECT_EQ(OK
, InitSession(reads
, arraysize(reads
),
335 writes
, arraysize(writes
), false));
337 SpdyWebSocketStreamEventRecorder
delegate(completion_callback_
.callback());
338 delegate
.SetOnReceivedHeader(
339 base::Bind(&SpdyWebSocketStreamSpdy3Test::DoSendHelloFrame
,
340 base::Unretained(this)));
341 delegate
.SetOnReceivedData(
342 base::Bind(&SpdyWebSocketStreamSpdy3Test::DoSendClosingFrame
,
343 base::Unretained(this)));
345 websocket_stream_
.reset(new SpdyWebSocketStream(session_
, &delegate
));
348 GURL
url("ws://example.com/echo");
349 ASSERT_EQ(OK
, websocket_stream_
->InitializeStream(url
, HIGHEST
, net_log
));
351 ASSERT_TRUE(websocket_stream_
->stream_
);
355 completion_callback_
.WaitForResult();
357 EXPECT_EQ(stream_id_
, created_stream_id_
);
359 websocket_stream_
.reset();
361 const std::vector
<SpdyWebSocketStreamEvent
>& events
=
362 delegate
.GetSeenEvents();
363 ASSERT_EQ(7U, events
.size());
365 EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_SENT_HEADERS
,
366 events
[0].event_type
);
367 EXPECT_LT(0, events
[0].result
);
368 EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_RECEIVED_HEADER
,
369 events
[1].event_type
);
370 EXPECT_EQ(OK
, events
[1].result
);
371 EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_SENT_DATA
,
372 events
[2].event_type
);
373 EXPECT_EQ(static_cast<int>(kMessageFrameLength
), events
[2].result
);
374 EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_RECEIVED_DATA
,
375 events
[3].event_type
);
376 EXPECT_EQ(static_cast<int>(kMessageFrameLength
), events
[3].result
);
377 EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_SENT_DATA
,
378 events
[4].event_type
);
379 EXPECT_EQ(static_cast<int>(kClosingFrameLength
), events
[4].result
);
380 EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_RECEIVED_DATA
,
381 events
[5].event_type
);
382 EXPECT_EQ(static_cast<int>(kClosingFrameLength
), events
[5].result
);
383 EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_CLOSE
,
384 events
[6].event_type
);
385 EXPECT_EQ(OK
, events
[6].result
);
387 // EOF close SPDY session.
388 EXPECT_TRUE(!http_session_
->spdy_session_pool()->HasSession(
389 host_port_proxy_pair_
));
390 EXPECT_TRUE(data()->at_read_eof());
391 EXPECT_TRUE(data()->at_write_eof());
394 TEST_F(SpdyWebSocketStreamSpdy3Test
, DestructionBeforeClose
) {
396 MockWrite writes
[] = {
397 CreateMockWrite(*request_frame_
.get(), 1),
398 CreateMockWrite(*message_frame_
.get(), 3)
402 CreateMockRead(*response_frame_
.get(), 2),
403 CreateMockRead(*message_frame_
.get(), 4),
404 MockRead(ASYNC
, ERR_IO_PENDING
, 5)
407 EXPECT_EQ(OK
, InitSession(reads
, arraysize(reads
),
408 writes
, arraysize(writes
), false));
410 SpdyWebSocketStreamEventRecorder
delegate(completion_callback_
.callback());
411 delegate
.SetOnReceivedHeader(
412 base::Bind(&SpdyWebSocketStreamSpdy3Test::DoSendHelloFrame
,
413 base::Unretained(this)));
414 delegate
.SetOnReceivedData(
415 base::Bind(&SpdyWebSocketStreamSpdy3Test::DoSync
,
416 base::Unretained(this)));
418 websocket_stream_
.reset(new SpdyWebSocketStream(session_
, &delegate
));
421 GURL
url("ws://example.com/echo");
422 ASSERT_EQ(OK
, websocket_stream_
->InitializeStream(url
, HIGHEST
, net_log
));
426 sync_callback_
.WaitForResult();
428 // WebSocketStream destruction remove its SPDY stream from the session.
429 EXPECT_TRUE(session_
->IsStreamActive(stream_id_
));
430 websocket_stream_
.reset();
431 EXPECT_FALSE(session_
->IsStreamActive(stream_id_
));
433 const std::vector
<SpdyWebSocketStreamEvent
>& events
=
434 delegate
.GetSeenEvents();
435 ASSERT_GE(4U, events
.size());
437 EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_SENT_HEADERS
,
438 events
[0].event_type
);
439 EXPECT_LT(0, events
[0].result
);
440 EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_RECEIVED_HEADER
,
441 events
[1].event_type
);
442 EXPECT_EQ(OK
, events
[1].result
);
443 EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_SENT_DATA
,
444 events
[2].event_type
);
445 EXPECT_EQ(static_cast<int>(kMessageFrameLength
), events
[2].result
);
446 EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_RECEIVED_DATA
,
447 events
[3].event_type
);
448 EXPECT_EQ(static_cast<int>(kMessageFrameLength
), events
[3].result
);
450 EXPECT_TRUE(http_session_
->spdy_session_pool()->HasSession(
451 host_port_proxy_pair_
));
452 EXPECT_TRUE(data()->at_read_eof());
453 EXPECT_TRUE(data()->at_write_eof());
456 TEST_F(SpdyWebSocketStreamSpdy3Test
, DestructionAfterExplicitClose
) {
458 MockWrite writes
[] = {
459 CreateMockWrite(*request_frame_
.get(), 1),
460 CreateMockWrite(*message_frame_
.get(), 3),
461 CreateMockWrite(*closing_frame_
.get(), 5)
465 CreateMockRead(*response_frame_
.get(), 2),
466 CreateMockRead(*message_frame_
.get(), 4),
467 MockRead(ASYNC
, ERR_IO_PENDING
, 6)
470 EXPECT_EQ(OK
, InitSession(reads
, arraysize(reads
),
471 writes
, arraysize(writes
), false));
473 SpdyWebSocketStreamEventRecorder
delegate(completion_callback_
.callback());
474 delegate
.SetOnReceivedHeader(
475 base::Bind(&SpdyWebSocketStreamSpdy3Test::DoSendHelloFrame
,
476 base::Unretained(this)));
477 delegate
.SetOnReceivedData(
478 base::Bind(&SpdyWebSocketStreamSpdy3Test::DoClose
,
479 base::Unretained(this)));
481 websocket_stream_
.reset(new SpdyWebSocketStream(session_
, &delegate
));
484 GURL
url("ws://example.com/echo");
485 ASSERT_EQ(OK
, websocket_stream_
->InitializeStream(url
, HIGHEST
, net_log
));
489 completion_callback_
.WaitForResult();
491 // SPDY stream has already been removed from the session by Close().
492 EXPECT_FALSE(session_
->IsStreamActive(stream_id_
));
493 websocket_stream_
.reset();
495 const std::vector
<SpdyWebSocketStreamEvent
>& events
=
496 delegate
.GetSeenEvents();
497 ASSERT_EQ(5U, events
.size());
499 EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_SENT_HEADERS
,
500 events
[0].event_type
);
501 EXPECT_LT(0, events
[0].result
);
502 EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_RECEIVED_HEADER
,
503 events
[1].event_type
);
504 EXPECT_EQ(OK
, events
[1].result
);
505 EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_SENT_DATA
,
506 events
[2].event_type
);
507 EXPECT_EQ(static_cast<int>(kMessageFrameLength
), events
[2].result
);
508 EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_RECEIVED_DATA
,
509 events
[3].event_type
);
510 EXPECT_EQ(static_cast<int>(kMessageFrameLength
), events
[3].result
);
511 EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_CLOSE
, events
[4].event_type
);
513 EXPECT_TRUE(http_session_
->spdy_session_pool()->HasSession(
514 host_port_proxy_pair_
));
517 TEST_F(SpdyWebSocketStreamSpdy3Test
, IOPending
) {
519 scoped_ptr
<SpdyFrame
> settings_frame(
520 ConstructSpdySettings(spdy_settings_to_send_
));
521 MockWrite writes
[] = {
522 // Setting throttling make SpdySession send settings frame automatically.
523 CreateMockWrite(*settings_frame
.get(), 1),
524 CreateMockWrite(*request_frame_
.get(), 3),
525 CreateMockWrite(*message_frame_
.get(), 6),
526 CreateMockWrite(*closing_frame_
.get(), 9)
530 CreateMockRead(*settings_frame
.get(), 2),
531 CreateMockRead(*response_frame_
.get(), 4),
532 // Skip sequence 5 (I/O Pending)
533 CreateMockRead(*message_frame_
.get(), 7),
534 // Skip sequence 8 (I/O Pending)
535 CreateMockRead(*closing_frame_
.get(), 10),
536 MockRead(SYNCHRONOUS
, 0, 11) // EOF cause OnCloseSpdyStream event.
539 EXPECT_EQ(OK
, InitSession(reads
, arraysize(reads
),
540 writes
, arraysize(writes
), true));
542 // Create a dummy WebSocketStream which cause ERR_IO_PENDING to another
543 // WebSocketStream under test.
544 SpdyWebSocketStreamEventRecorder
block_delegate((CompletionCallback()));
546 scoped_ptr
<SpdyWebSocketStream
> block_stream(
547 new SpdyWebSocketStream(session_
, &block_delegate
));
548 BoundNetLog block_net_log
;
549 GURL
block_url("ws://example.com/block");
551 block_stream
->InitializeStream(block_url
, HIGHEST
, block_net_log
));
553 // Create a WebSocketStream under test.
554 SpdyWebSocketStreamEventRecorder
delegate(completion_callback_
.callback());
555 delegate
.SetOnCreated(
556 base::Bind(&SpdyWebSocketStreamSpdy3Test::DoSync
,
557 base::Unretained(this)));
558 delegate
.SetOnReceivedHeader(
559 base::Bind(&SpdyWebSocketStreamSpdy3Test::DoSendHelloFrame
,
560 base::Unretained(this)));
561 delegate
.SetOnReceivedData(
562 base::Bind(&SpdyWebSocketStreamSpdy3Test::DoSendClosingFrame
,
563 base::Unretained(this)));
565 websocket_stream_
.reset(new SpdyWebSocketStream(session_
, &delegate
));
567 GURL
url("ws://example.com/echo");
568 ASSERT_EQ(ERR_IO_PENDING
, websocket_stream_
->InitializeStream(
569 url
, HIGHEST
, net_log
));
571 // Delete the first stream to allow create the second stream.
572 block_stream
.reset();
573 ASSERT_EQ(OK
, sync_callback_
.WaitForResult());
577 completion_callback_
.WaitForResult();
579 websocket_stream_
.reset();
581 const std::vector
<SpdyWebSocketStreamEvent
>& block_events
=
582 block_delegate
.GetSeenEvents();
583 ASSERT_EQ(0U, block_events
.size());
585 const std::vector
<SpdyWebSocketStreamEvent
>& events
=
586 delegate
.GetSeenEvents();
587 ASSERT_EQ(8U, events
.size());
588 EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_CREATED
,
589 events
[0].event_type
);
590 EXPECT_EQ(0, events
[0].result
);
591 EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_SENT_HEADERS
,
592 events
[1].event_type
);
593 EXPECT_LT(0, events
[1].result
);
594 EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_RECEIVED_HEADER
,
595 events
[2].event_type
);
596 EXPECT_EQ(OK
, events
[2].result
);
597 EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_SENT_DATA
,
598 events
[3].event_type
);
599 EXPECT_EQ(static_cast<int>(kMessageFrameLength
), events
[3].result
);
600 EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_RECEIVED_DATA
,
601 events
[4].event_type
);
602 EXPECT_EQ(static_cast<int>(kMessageFrameLength
), events
[4].result
);
603 EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_SENT_DATA
,
604 events
[5].event_type
);
605 EXPECT_EQ(static_cast<int>(kClosingFrameLength
), events
[5].result
);
606 EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_RECEIVED_DATA
,
607 events
[6].event_type
);
608 EXPECT_EQ(static_cast<int>(kClosingFrameLength
), events
[6].result
);
609 EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_CLOSE
,
610 events
[7].event_type
);
611 EXPECT_EQ(OK
, events
[7].result
);
613 // EOF close SPDY session.
614 EXPECT_TRUE(!http_session_
->spdy_session_pool()->HasSession(
615 host_port_proxy_pair_
));
616 EXPECT_TRUE(data()->at_read_eof());
617 EXPECT_TRUE(data()->at_write_eof());