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
) OVERRIDE
{
81 SpdyWebSocketStreamEvent(SpdyWebSocketStreamEvent::EVENT_CREATED
,
85 if (!on_created_
.is_null())
86 on_created_
.Run(&events_
.back());
88 virtual void OnSentSpdyHeaders() OVERRIDE
{
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
) OVERRIDE
{
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(size_t bytes_sent
) OVERRIDE
{
111 SpdyWebSocketStreamEvent(
112 SpdyWebSocketStreamEvent::EVENT_SENT_DATA
,
114 static_cast<int>(bytes_sent
),
116 if (!on_sent_data_
.is_null())
117 on_sent_data_
.Run(&events_
.back());
119 virtual void OnReceivedSpdyData(scoped_ptr
<SpdyBuffer
> buffer
) OVERRIDE
{
120 std::string buffer_data
;
121 size_t buffer_len
= 0;
123 buffer_len
= buffer
->GetRemainingSize();
124 buffer_data
.append(buffer
->GetRemainingData(), buffer_len
);
127 SpdyWebSocketStreamEvent(
128 SpdyWebSocketStreamEvent::EVENT_RECEIVED_DATA
,
132 if (!on_received_data_
.is_null())
133 on_received_data_
.Run(&events_
.back());
135 virtual void OnCloseSpdyStream() OVERRIDE
{
137 SpdyWebSocketStreamEvent(
138 SpdyWebSocketStreamEvent::EVENT_CLOSE
,
142 if (!on_close_
.is_null())
143 on_close_
.Run(&events_
.back());
144 if (!callback_
.is_null())
148 const std::vector
<SpdyWebSocketStreamEvent
>& GetSeenEvents() const {
153 std::vector
<SpdyWebSocketStreamEvent
> events_
;
154 StreamEventCallback on_created_
;
155 StreamEventCallback on_sent_headers_
;
156 StreamEventCallback on_received_header_
;
157 StreamEventCallback on_sent_data_
;
158 StreamEventCallback on_received_data_
;
159 StreamEventCallback on_close_
;
160 CompletionCallback callback_
;
162 DISALLOW_COPY_AND_ASSIGN(SpdyWebSocketStreamEventRecorder
);
167 class SpdyWebSocketStreamSpdy3Test
: public testing::Test
{
169 OrderedSocketData
* data() { return data_
.get(); }
171 void DoSendHelloFrame(SpdyWebSocketStreamEvent
* event
) {
172 // Record the actual stream_id.
173 created_stream_id_
= websocket_stream_
->stream_
->stream_id();
174 websocket_stream_
->SendData(kMessageFrame
, kMessageFrameLength
);
177 void DoSendClosingFrame(SpdyWebSocketStreamEvent
* event
) {
178 websocket_stream_
->SendData(kClosingFrame
, kClosingFrameLength
);
181 void DoClose(SpdyWebSocketStreamEvent
* event
) {
182 websocket_stream_
->Close();
185 void DoSync(SpdyWebSocketStreamEvent
* event
) {
186 sync_callback_
.callback().Run(OK
);
190 SpdyWebSocketStreamSpdy3Test() {}
191 virtual ~SpdyWebSocketStreamSpdy3Test() {}
193 virtual void SetUp() {
194 host_port_pair_
.set_host("example.com");
195 host_port_pair_
.set_port(80);
196 host_port_proxy_pair_
.first
= host_port_pair_
;
197 host_port_proxy_pair_
.second
= ProxyServer::Direct();
199 spdy_settings_id_to_set_
= SETTINGS_MAX_CONCURRENT_STREAMS
;
200 spdy_settings_flags_to_set_
= SETTINGS_FLAG_PLEASE_PERSIST
;
201 spdy_settings_value_to_set_
= 1;
203 spdy_settings_to_send_
[spdy_settings_id_to_set_
] =
204 SettingsFlagsAndValue(
205 SETTINGS_FLAG_PERSISTED
, spdy_settings_value_to_set_
);
208 virtual void TearDown() {
209 MessageLoop::current()->RunUntilIdle();
212 void Prepare(SpdyStreamId stream_id
) {
213 stream_id_
= stream_id
;
215 request_frame_
.reset(ConstructSpdyWebSocketSynStream(
219 "http://example.com/wsdemo"));
221 response_frame_
.reset(ConstructSpdyWebSocketSynReply(stream_id_
));
223 message_frame_
.reset(ConstructSpdyWebSocketDataFrame(
229 closing_frame_
.reset(ConstructSpdyWebSocketDataFrame(
236 int InitSession(MockRead
* reads
, size_t reads_count
,
237 MockWrite
* writes
, size_t writes_count
,
239 data_
.reset(new OrderedSocketData(reads
, reads_count
,
240 writes
, writes_count
));
241 session_deps_
.socket_factory
->AddSocketDataProvider(data_
.get());
242 http_session_
= SpdySessionDependencies::SpdyCreateSession(&session_deps_
);
243 SpdySessionPool
* spdy_session_pool(http_session_
->spdy_session_pool());
246 // Set max concurrent streams to 1.
247 spdy_session_pool
->http_server_properties()->SetSpdySetting(
249 spdy_settings_id_to_set_
,
250 spdy_settings_flags_to_set_
,
251 spdy_settings_value_to_set_
);
254 EXPECT_FALSE(spdy_session_pool
->HasSession(host_port_proxy_pair_
));
255 session_
= spdy_session_pool
->Get(host_port_proxy_pair_
, BoundNetLog());
256 EXPECT_TRUE(spdy_session_pool
->HasSession(host_port_proxy_pair_
));
257 transport_params_
= new TransportSocketParams(host_port_pair_
, MEDIUM
,
259 OnHostResolutionCallback());
260 TestCompletionCallback callback
;
261 scoped_ptr
<ClientSocketHandle
> connection(new ClientSocketHandle
);
262 EXPECT_EQ(ERR_IO_PENDING
,
263 connection
->Init(host_port_pair_
.ToString(), transport_params_
,
264 MEDIUM
, callback
.callback(),
265 http_session_
->GetTransportSocketPool(
266 HttpNetworkSession::NORMAL_SOCKET_POOL
),
268 EXPECT_EQ(OK
, callback
.WaitForResult());
269 return session_
->InitializeWithSocket(connection
.release(), false, OK
);
273 scoped_ptr
<SpdyHeaderBlock
> headers(new SpdyHeaderBlock
);
274 (*headers
)[":path"] = "/echo";
275 (*headers
)[":host"] = "example.com";
276 (*headers
)[":version"] = "WebSocket/13";
277 (*headers
)[":scheme"] = "ws";
278 (*headers
)[":origin"] = "http://example.com/wsdemo";
280 websocket_stream_
->SendRequest(headers
.Pass());
283 SpdySettingsIds spdy_settings_id_to_set_
;
284 SpdySettingsFlags spdy_settings_flags_to_set_
;
285 uint32 spdy_settings_value_to_set_
;
286 SettingsMap spdy_settings_to_send_
;
287 SpdySessionDependencies session_deps_
;
288 scoped_ptr
<OrderedSocketData
> data_
;
289 scoped_refptr
<HttpNetworkSession
> http_session_
;
290 scoped_refptr
<SpdySession
> session_
;
291 scoped_refptr
<TransportSocketParams
> transport_params_
;
292 scoped_ptr
<SpdyWebSocketStream
> websocket_stream_
;
293 SpdyStreamId stream_id_
;
294 SpdyStreamId created_stream_id_
;
295 scoped_ptr
<SpdyFrame
> request_frame_
;
296 scoped_ptr
<SpdyFrame
> response_frame_
;
297 scoped_ptr
<SpdyFrame
> message_frame_
;
298 scoped_ptr
<SpdyFrame
> closing_frame_
;
299 HostPortPair host_port_pair_
;
300 HostPortProxyPair host_port_proxy_pair_
;
301 TestCompletionCallback completion_callback_
;
302 TestCompletionCallback sync_callback_
;
304 static const char kMessageFrame
[];
305 static const char kClosingFrame
[];
306 static const size_t kMessageFrameLength
;
307 static const size_t kClosingFrameLength
;
310 // TODO(toyoshim): Replace old framing data to new one, then use HEADERS and
312 const char SpdyWebSocketStreamSpdy3Test::kMessageFrame
[] = "\x81\x05hello";
313 const char SpdyWebSocketStreamSpdy3Test::kClosingFrame
[] = "\x88\0";
314 const size_t SpdyWebSocketStreamSpdy3Test::kMessageFrameLength
=
315 arraysize(SpdyWebSocketStreamSpdy3Test::kMessageFrame
) - 1;
316 const size_t SpdyWebSocketStreamSpdy3Test::kClosingFrameLength
=
317 arraysize(SpdyWebSocketStreamSpdy3Test::kClosingFrame
) - 1;
319 TEST_F(SpdyWebSocketStreamSpdy3Test
, Basic
) {
321 MockWrite writes
[] = {
322 CreateMockWrite(*request_frame_
.get(), 1),
323 CreateMockWrite(*message_frame_
.get(), 3),
324 CreateMockWrite(*closing_frame_
.get(), 5)
328 CreateMockRead(*response_frame_
.get(), 2),
329 CreateMockRead(*message_frame_
.get(), 4),
330 // Skip sequence 6 to notify closing has been sent.
331 CreateMockRead(*closing_frame_
.get(), 7),
332 MockRead(SYNCHRONOUS
, 0, 8) // EOF cause OnCloseSpdyStream event.
335 EXPECT_EQ(OK
, InitSession(reads
, arraysize(reads
),
336 writes
, arraysize(writes
), false));
338 SpdyWebSocketStreamEventRecorder
delegate(completion_callback_
.callback());
339 delegate
.SetOnReceivedHeader(
340 base::Bind(&SpdyWebSocketStreamSpdy3Test::DoSendHelloFrame
,
341 base::Unretained(this)));
342 delegate
.SetOnReceivedData(
343 base::Bind(&SpdyWebSocketStreamSpdy3Test::DoSendClosingFrame
,
344 base::Unretained(this)));
346 websocket_stream_
.reset(new SpdyWebSocketStream(session_
, &delegate
));
349 GURL
url("ws://example.com/echo");
350 ASSERT_EQ(OK
, websocket_stream_
->InitializeStream(url
, HIGHEST
, net_log
));
352 ASSERT_TRUE(websocket_stream_
->stream_
);
356 completion_callback_
.WaitForResult();
358 EXPECT_EQ(stream_id_
, created_stream_id_
);
360 websocket_stream_
.reset();
362 const std::vector
<SpdyWebSocketStreamEvent
>& events
=
363 delegate
.GetSeenEvents();
364 ASSERT_EQ(7U, events
.size());
366 EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_SENT_HEADERS
,
367 events
[0].event_type
);
368 EXPECT_EQ(OK
, events
[0].result
);
369 EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_RECEIVED_HEADER
,
370 events
[1].event_type
);
371 EXPECT_EQ(OK
, events
[1].result
);
372 EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_SENT_DATA
,
373 events
[2].event_type
);
374 EXPECT_EQ(static_cast<int>(kMessageFrameLength
), events
[2].result
);
375 EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_RECEIVED_DATA
,
376 events
[3].event_type
);
377 EXPECT_EQ(static_cast<int>(kMessageFrameLength
), events
[3].result
);
378 EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_SENT_DATA
,
379 events
[4].event_type
);
380 EXPECT_EQ(static_cast<int>(kClosingFrameLength
), events
[4].result
);
381 EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_RECEIVED_DATA
,
382 events
[5].event_type
);
383 EXPECT_EQ(static_cast<int>(kClosingFrameLength
), events
[5].result
);
384 EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_CLOSE
,
385 events
[6].event_type
);
386 EXPECT_EQ(OK
, events
[6].result
);
388 // EOF close SPDY session.
389 EXPECT_TRUE(!http_session_
->spdy_session_pool()->HasSession(
390 host_port_proxy_pair_
));
391 EXPECT_TRUE(data()->at_read_eof());
392 EXPECT_TRUE(data()->at_write_eof());
395 TEST_F(SpdyWebSocketStreamSpdy3Test
, DestructionBeforeClose
) {
397 MockWrite writes
[] = {
398 CreateMockWrite(*request_frame_
.get(), 1),
399 CreateMockWrite(*message_frame_
.get(), 3)
403 CreateMockRead(*response_frame_
.get(), 2),
404 CreateMockRead(*message_frame_
.get(), 4),
405 MockRead(ASYNC
, ERR_IO_PENDING
, 5)
408 EXPECT_EQ(OK
, InitSession(reads
, arraysize(reads
),
409 writes
, arraysize(writes
), false));
411 SpdyWebSocketStreamEventRecorder
delegate(completion_callback_
.callback());
412 delegate
.SetOnReceivedHeader(
413 base::Bind(&SpdyWebSocketStreamSpdy3Test::DoSendHelloFrame
,
414 base::Unretained(this)));
415 delegate
.SetOnReceivedData(
416 base::Bind(&SpdyWebSocketStreamSpdy3Test::DoSync
,
417 base::Unretained(this)));
419 websocket_stream_
.reset(new SpdyWebSocketStream(session_
, &delegate
));
422 GURL
url("ws://example.com/echo");
423 ASSERT_EQ(OK
, websocket_stream_
->InitializeStream(url
, HIGHEST
, net_log
));
427 sync_callback_
.WaitForResult();
429 // WebSocketStream destruction remove its SPDY stream from the session.
430 EXPECT_TRUE(session_
->IsStreamActive(stream_id_
));
431 websocket_stream_
.reset();
432 EXPECT_FALSE(session_
->IsStreamActive(stream_id_
));
434 const std::vector
<SpdyWebSocketStreamEvent
>& events
=
435 delegate
.GetSeenEvents();
436 ASSERT_GE(4U, events
.size());
438 EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_SENT_HEADERS
,
439 events
[0].event_type
);
440 EXPECT_EQ(OK
, events
[0].result
);
441 EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_RECEIVED_HEADER
,
442 events
[1].event_type
);
443 EXPECT_EQ(OK
, events
[1].result
);
444 EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_SENT_DATA
,
445 events
[2].event_type
);
446 EXPECT_EQ(static_cast<int>(kMessageFrameLength
), events
[2].result
);
447 EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_RECEIVED_DATA
,
448 events
[3].event_type
);
449 EXPECT_EQ(static_cast<int>(kMessageFrameLength
), events
[3].result
);
451 EXPECT_TRUE(http_session_
->spdy_session_pool()->HasSession(
452 host_port_proxy_pair_
));
453 EXPECT_TRUE(data()->at_read_eof());
454 EXPECT_TRUE(data()->at_write_eof());
457 TEST_F(SpdyWebSocketStreamSpdy3Test
, DestructionAfterExplicitClose
) {
459 MockWrite writes
[] = {
460 CreateMockWrite(*request_frame_
.get(), 1),
461 CreateMockWrite(*message_frame_
.get(), 3),
462 CreateMockWrite(*closing_frame_
.get(), 5)
466 CreateMockRead(*response_frame_
.get(), 2),
467 CreateMockRead(*message_frame_
.get(), 4),
468 MockRead(ASYNC
, ERR_IO_PENDING
, 6)
471 EXPECT_EQ(OK
, InitSession(reads
, arraysize(reads
),
472 writes
, arraysize(writes
), false));
474 SpdyWebSocketStreamEventRecorder
delegate(completion_callback_
.callback());
475 delegate
.SetOnReceivedHeader(
476 base::Bind(&SpdyWebSocketStreamSpdy3Test::DoSendHelloFrame
,
477 base::Unretained(this)));
478 delegate
.SetOnReceivedData(
479 base::Bind(&SpdyWebSocketStreamSpdy3Test::DoClose
,
480 base::Unretained(this)));
482 websocket_stream_
.reset(new SpdyWebSocketStream(session_
, &delegate
));
485 GURL
url("ws://example.com/echo");
486 ASSERT_EQ(OK
, websocket_stream_
->InitializeStream(url
, HIGHEST
, net_log
));
490 completion_callback_
.WaitForResult();
492 // SPDY stream has already been removed from the session by Close().
493 EXPECT_FALSE(session_
->IsStreamActive(stream_id_
));
494 websocket_stream_
.reset();
496 const std::vector
<SpdyWebSocketStreamEvent
>& events
=
497 delegate
.GetSeenEvents();
498 ASSERT_EQ(5U, events
.size());
500 EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_SENT_HEADERS
,
501 events
[0].event_type
);
502 EXPECT_EQ(OK
, events
[0].result
);
503 EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_RECEIVED_HEADER
,
504 events
[1].event_type
);
505 EXPECT_EQ(OK
, events
[1].result
);
506 EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_SENT_DATA
,
507 events
[2].event_type
);
508 EXPECT_EQ(static_cast<int>(kMessageFrameLength
), events
[2].result
);
509 EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_RECEIVED_DATA
,
510 events
[3].event_type
);
511 EXPECT_EQ(static_cast<int>(kMessageFrameLength
), events
[3].result
);
512 EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_CLOSE
, events
[4].event_type
);
514 EXPECT_TRUE(http_session_
->spdy_session_pool()->HasSession(
515 host_port_proxy_pair_
));
518 TEST_F(SpdyWebSocketStreamSpdy3Test
, IOPending
) {
520 scoped_ptr
<SpdyFrame
> settings_frame(
521 ConstructSpdySettings(spdy_settings_to_send_
));
522 MockWrite writes
[] = {
523 // Setting throttling make SpdySession send settings frame automatically.
524 CreateMockWrite(*settings_frame
.get(), 1),
525 CreateMockWrite(*request_frame_
.get(), 3),
526 CreateMockWrite(*message_frame_
.get(), 6),
527 CreateMockWrite(*closing_frame_
.get(), 9)
531 CreateMockRead(*settings_frame
.get(), 2),
532 CreateMockRead(*response_frame_
.get(), 4),
533 // Skip sequence 5 (I/O Pending)
534 CreateMockRead(*message_frame_
.get(), 7),
535 // Skip sequence 8 (I/O Pending)
536 CreateMockRead(*closing_frame_
.get(), 10),
537 MockRead(SYNCHRONOUS
, 0, 11) // EOF cause OnCloseSpdyStream event.
540 EXPECT_EQ(OK
, InitSession(reads
, arraysize(reads
),
541 writes
, arraysize(writes
), true));
543 // Create a dummy WebSocketStream which cause ERR_IO_PENDING to another
544 // WebSocketStream under test.
545 SpdyWebSocketStreamEventRecorder
block_delegate((CompletionCallback()));
547 scoped_ptr
<SpdyWebSocketStream
> block_stream(
548 new SpdyWebSocketStream(session_
, &block_delegate
));
549 BoundNetLog block_net_log
;
550 GURL
block_url("ws://example.com/block");
552 block_stream
->InitializeStream(block_url
, HIGHEST
, block_net_log
));
554 // Create a WebSocketStream under test.
555 SpdyWebSocketStreamEventRecorder
delegate(completion_callback_
.callback());
556 delegate
.SetOnCreated(
557 base::Bind(&SpdyWebSocketStreamSpdy3Test::DoSync
,
558 base::Unretained(this)));
559 delegate
.SetOnReceivedHeader(
560 base::Bind(&SpdyWebSocketStreamSpdy3Test::DoSendHelloFrame
,
561 base::Unretained(this)));
562 delegate
.SetOnReceivedData(
563 base::Bind(&SpdyWebSocketStreamSpdy3Test::DoSendClosingFrame
,
564 base::Unretained(this)));
566 websocket_stream_
.reset(new SpdyWebSocketStream(session_
, &delegate
));
568 GURL
url("ws://example.com/echo");
569 ASSERT_EQ(ERR_IO_PENDING
, websocket_stream_
->InitializeStream(
570 url
, HIGHEST
, net_log
));
572 // Delete the first stream to allow create the second stream.
573 block_stream
.reset();
574 ASSERT_EQ(OK
, sync_callback_
.WaitForResult());
578 completion_callback_
.WaitForResult();
580 websocket_stream_
.reset();
582 const std::vector
<SpdyWebSocketStreamEvent
>& block_events
=
583 block_delegate
.GetSeenEvents();
584 ASSERT_EQ(0U, block_events
.size());
586 const std::vector
<SpdyWebSocketStreamEvent
>& events
=
587 delegate
.GetSeenEvents();
588 ASSERT_EQ(8U, events
.size());
589 EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_CREATED
,
590 events
[0].event_type
);
591 EXPECT_EQ(0, events
[0].result
);
592 EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_SENT_HEADERS
,
593 events
[1].event_type
);
594 EXPECT_EQ(OK
, events
[1].result
);
595 EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_RECEIVED_HEADER
,
596 events
[2].event_type
);
597 EXPECT_EQ(OK
, events
[2].result
);
598 EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_SENT_DATA
,
599 events
[3].event_type
);
600 EXPECT_EQ(static_cast<int>(kMessageFrameLength
), events
[3].result
);
601 EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_RECEIVED_DATA
,
602 events
[4].event_type
);
603 EXPECT_EQ(static_cast<int>(kMessageFrameLength
), events
[4].result
);
604 EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_SENT_DATA
,
605 events
[5].event_type
);
606 EXPECT_EQ(static_cast<int>(kClosingFrameLength
), events
[5].result
);
607 EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_RECEIVED_DATA
,
608 events
[6].event_type
);
609 EXPECT_EQ(static_cast<int>(kClosingFrameLength
), events
[6].result
);
610 EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_CLOSE
,
611 events
[7].event_type
);
612 EXPECT_EQ(OK
, events
[7].result
);
614 // EOF close SPDY session.
615 EXPECT_TRUE(!http_session_
->spdy_session_pool()->HasSession(
616 host_port_proxy_pair_
));
617 EXPECT_TRUE(data()->at_read_eof());
618 EXPECT_TRUE(data()->at_write_eof());