Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(589)

Side by Side Diff: net/websockets/websocket_channel_test.cc

Issue 12764006: WebSocketChannel implementation (Closed) Base URL: http://git.chromium.org/chromium/src.git@web_socket_dispatcher
Patch Set: Fix potential NULL-pointer dereference in ProcessFrameChunks. Created 7 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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/websockets/websocket_channel.h"
6
7 #include <iostream>
8 #include <string>
9 #include <vector>
10
11 #include "base/bind.h"
12 #include "base/bind_helpers.h"
13 #include "base/callback.h"
14 #include "base/memory/scoped_ptr.h"
15 #include "base/memory/scoped_vector.h"
16 #include "base/message_loop/message_loop.h"
17 #include "base/strings/string_piece.h"
18 #include "googleurl/src/gurl.h"
19 #include "net/base/net_errors.h"
20 #include "net/url_request/url_request_context.h"
21 #include "net/websockets/websocket_errors.h"
22 #include "net/websockets/websocket_event_interface.h"
23 #include "net/websockets/websocket_mux.h"
24 #include "testing/gmock/include/gmock/gmock.h"
25 #include "testing/gtest/include/gtest/gtest.h"
26
27 namespace net {
28
29 // Printing helpers to allow GoogleMock to print frame chunks. These are
30 // explicitly designed to look like the static initialisation format we use in
31 // these tests. Static to reduce the risk of linker clashes.
32
33 static std::ostream& operator<<(std::ostream& os,
34 const WebSocketFrameHeader& header) {
35 return os << "{" << (header.final ? "FINAL_FRAME" : "NOT_FINAL_FRAME") << ", "
36 << header.opcode << ", "
37 << (header.masked ? "MASKED" : "NOT_MASKED") << ", "
38 << header.payload_length << "}";
39 }
40
41 static std::ostream& operator<<(std::ostream& os,
42 const WebSocketFrameChunk& chunk) {
43 os << "{";
44 if (chunk.header) {
45 os << *chunk.header;
46 } else {
47 os << "{NO_HEADER}";
48 }
49 return os << ", " << (chunk.final_chunk ? "FINAL_CHUNK" : "NOT_FINAL_CHUNK")
50 << ", \"" << base::StringPiece(chunk.data->data(),
51 chunk.data->size()) << "\"}";
52 }
53
54 namespace {
55
56 using ::testing::AnyNumber;
57 using ::testing::Field;
58 using ::testing::InSequence;
59 using ::testing::MockFunction;
60 using ::testing::Pointee;
61 using ::testing::Return;
62 using ::testing::SetArgPointee;
63 using ::testing::_;
64
65 // This mock is for testing expectations about how the EventInterface is used.
66 class MockWebSocketEventInterface : public WebSocketEventInterface {
67 public:
68 MOCK_METHOD2(OnAddChannelResponse, void(bool, const std::string&));
69 MOCK_METHOD3(OnSendFrame,
70 void(bool, WebSocketMessageType, const std::vector<char>&));
71 MOCK_METHOD1(OnFlowControl, void(int64));
72 MOCK_METHOD2(OnDropChannel, void(unsigned short, const std::string&));
73 };
74
75 // This fake EventInterface is for tests which need an WebSocketEventInterface
76 // implementation but are not verifying how it is used.
77 class FakeWebSocketEventInterface : public WebSocketEventInterface {
78 virtual void OnAddChannelResponse(bool fail,
79 const std::string& selected_protocol)
80 OVERRIDE {}
81 virtual void OnSendFrame(bool fin,
82 WebSocketMessageType type,
83 const std::vector<char>& data) OVERRIDE {}
84 virtual void OnFlowControl(int64 quota) OVERRIDE {}
85 virtual void OnDropChannel(unsigned short reason,
86 const std::string& reason_text) OVERRIDE {}
87 };
88
89 // This fake WebSocketStream is for tests that require a WebSocketStream but are
90 // are not testing the way it is used. It has minimal functionality to return
91 // the |protocol| and |extensions| that it was constructed with.
92 class FakeWebSocketStream : public WebSocketStream {
93 public:
94 // Construct with empty protocol and extensions.
95 FakeWebSocketStream() : WebSocketStream(), protocol_(), extensions_() {}
96
97 // Construct with specified protocol and extensions.
98 FakeWebSocketStream(const std::string& protocol,
99 const std::string& extensions)
100 : WebSocketStream(), protocol_(protocol), extensions_(extensions) {}
101
102 virtual int SendHandshakeRequest(const GURL& url,
103 const HttpRequestHeaders& headers,
104 HttpResponseInfo* response_info,
105 const CompletionCallback& callback)
106 OVERRIDE {
107 return ERR_IO_PENDING;
108 }
109
110 virtual int ReadHandshakeResponse(const CompletionCallback& callback)
111 OVERRIDE {
112 return ERR_IO_PENDING;
113 }
114
115 virtual int ReadFrames(ScopedVector<WebSocketFrameChunk>* frame_chunks,
116 const CompletionCallback& callback) OVERRIDE {
117 return ERR_IO_PENDING;
118 }
119
120 virtual int WriteFrames(ScopedVector<WebSocketFrameChunk>* frame_chunks,
121 const CompletionCallback& callback) OVERRIDE {
122 return ERR_IO_PENDING;
123 }
124
125 virtual void Close() OVERRIDE {}
126
127 // Returns the string passed to the constructor.
128 virtual std::string GetSubProtocol() const OVERRIDE { return protocol_; }
129
130 // Returns the string passed to the constructor.
131 virtual std::string GetExtensions() const OVERRIDE { return extensions_; }
132
133 private:
134 // The string to return from GetSubProtocol().
135 std::string protocol_;
136
137 // The string to return from GetExtensions().
138 std::string extensions_;
139 };
140
141 // To make the static initialisers easier to read, we use enums rather than
142 // bools.
143
144 // NO_HEADER means there shouldn't be a header included in the generated
145 // WebSocketFrameChunk. The static initialiser always has a header, but we can
146 // avoid specifying the rest of the fields.
147 enum IsFinal {
148 NO_HEADER,
149 NOT_FINAL_FRAME,
150 FINAL_FRAME
151 };
152
153 enum IsMasked {
154 NOT_MASKED,
155 MASKED
156 };
157
158 enum IsFinalChunk {
159 NOT_FINAL_CHUNK,
160 FINAL_CHUNK
161 };
162
163 // This is used to initialise a WebSocketFrameChunk but is statically
164 // initialisable.
165 struct InitFrameChunk {
166 struct FrameHeader {
167 IsFinal final;
168 // Reserved fields omitted for now. Add them if you need them.
169 WebSocketFrameHeader::OpCode opcode;
170 IsMasked masked;
171 uint64 payload_length;
172 };
173 FrameHeader header;
174
175 // Directly equivalent to WebSocketFrameChunk::final_chunk
176 IsFinalChunk final_chunk;
177
178 // Will be used to create the IOBuffer member. Can be NULL for null data.
179 const char *const data;
180 };
181
182 // Convert a const array of InitFrameChunks to the format used at
183 // runtime. Templated on the size of the array to save typing.
184 template <size_t N>
185 ScopedVector<WebSocketFrameChunk> CreateFrameChunkVector(
186 const InitFrameChunk (&chunks)[N]) {
187 ScopedVector<WebSocketFrameChunk> vector;
188 vector.reserve(N);
189 for (size_t i = 0; i < N; ++i) {
190 scoped_ptr<WebSocketFrameChunk> chunk(new WebSocketFrameChunk);
191 if (chunks[i].header.final != NO_HEADER) {
192 const InitFrameChunk::FrameHeader& in_header = chunks[i].header;
193 scoped_ptr<WebSocketFrameHeader> out_header(
194 new WebSocketFrameHeader(in_header.opcode));
195 out_header->final = in_header.final == FINAL_FRAME;
196 out_header->opcode = in_header.opcode;
197 out_header->masked = in_header.masked == MASKED;
198 out_header->payload_length = in_header.payload_length;
199 chunk->header.swap(out_header);
200 }
201 chunk->final_chunk = chunks[i].final_chunk == FINAL_CHUNK;
202 chunk->data = new IOBufferWithSize(strlen(chunks[i].data));
203 memcpy(chunk->data->data(), chunks[i].data, strlen(chunks[i].data));
204 vector.push_back(chunk.release());
205 }
206 return vector.Pass();
207 }
208
209 // A Google Mock action which can be used to respond to call to ReadFrames with
210 // some frames. Use like ReadFrames(_, _).WillOnce(ReturnChunks(chunks));
211 ACTION_P(ReturnChunks, chunks) {
212 *arg0 = CreateFrameChunkVector(chunks);
213 return OK;
214 }
215
216 // A FakeWebSocketStream whose ReadFrames() function returns data.
217 class ReadableFakeWebSocketStream : public FakeWebSocketStream {
218 public:
219 enum IsSync {
220 SYNC,
221 ASYNC
222 };
223
224 // After constructing the object, call PrepareReadFrames() once for each
225 // time you wish it to return from the test.
226 ReadableFakeWebSocketStream()
227 : FakeWebSocketStream(), responses_(), index_(0) {}
228
229 // Call PrepareReadFrames() to prepare the fake responses, in order. If
230 // |async| is true, then ReadFrames() will return ERR_IO_PENDING and the
231 // callback will be scheduled to run on the message loop. This requires the
232 // test case to run the message loop. If |async| is false, the response will
233 // be returned synchronously. |error| is returned directly from ReadFrames()
234 // in the synchronous case, or passed to the callback in the asynchronous
235 // case. |chunks| will be converted to a ScopedVector<WebSocketFrameChunks>
236 // and copied to the pointer that was passed to ReadFrames().
237 template <size_t N>
238 void PrepareReadFrames(IsSync async,
239 int error,
240 const InitFrameChunk (&chunks)[N]) {
241 responses_.push_back(
242 new Response(async, error, CreateFrameChunkVector(chunks)));
243 }
244
245 // Prepare a fake error response (ie. there is no data).
246 void PrepareReadFramesError(IsSync async, int error) {
247 responses_.push_back(
248 new Response(async, error, ScopedVector<WebSocketFrameChunk>()));
249 }
250
251 virtual int ReadFrames(ScopedVector<WebSocketFrameChunk>* frame_chunks,
252 const CompletionCallback& callback) OVERRIDE {
253 if (index_ >= responses_.size()) {
254 return ERR_IO_PENDING;
255 }
256 if (responses_[index_]->async == ASYNC) {
257 base::MessageLoop::current()->PostTask(
258 FROM_HERE,
259 base::Bind(&ReadableFakeWebSocketStream::DoCallback,
260 base::Unretained(this),
261 frame_chunks,
262 callback));
263 return ERR_IO_PENDING;
264 } else {
265 frame_chunks->swap(responses_[index_]->chunks);
266 return responses_[index_++]->error;
267 }
268 }
269
270 private:
271 void DoCallback(ScopedVector<WebSocketFrameChunk>* frame_chunks,
272 const CompletionCallback& callback) {
273 frame_chunks->swap(responses_[index_]->chunks);
274 callback.Run(responses_[index_++]->error);
275 return;
276 }
277
278 struct Response {
279 Response(IsSync async, int error, ScopedVector<WebSocketFrameChunk> chunks)
280 : async(async), error(error), chunks(chunks.Pass()) {}
281
282 IsSync async;
283 int error;
284 ScopedVector<WebSocketFrameChunk> chunks;
285
286 private:
287 // Bad things will happen if we attempt to copy or assign "chunks".
288 DISALLOW_COPY_AND_ASSIGN(Response);
289 };
290 ScopedVector<Response> responses_;
291 size_t index_;
292 };
293
294 // A FakeWebSocketStream where writes always complete successfully and
295 // synchronously.
296 class WriteableFakeWebSocketStream : public FakeWebSocketStream {
297 public:
298 virtual int WriteFrames(ScopedVector<WebSocketFrameChunk>* frame_chunks,
299 const CompletionCallback& callback) OVERRIDE {
300 return OK;
301 }
302 };
303
304 // A FakeWebSocketStream where writes always fail.
305 class UnWriteableFakeWebSocketStream : public FakeWebSocketStream {
306 public:
307 virtual int WriteFrames(ScopedVector<WebSocketFrameChunk>* frame_chunks,
308 const CompletionCallback& callback) OVERRIDE {
309 return ERR_CONNECTION_RESET;
310 }
311 };
312
313 // A FakeWebSocketStream which echoes any frames written back. It unset the
314 // "masked" header bit, but makes no other checks for validity. Tests using this
315 // must run the MessageLoop to receive the callback.
316 class EchoeyFakeWebSocketStream : public FakeWebSocketStream {
317 public:
318 EchoeyFakeWebSocketStream()
319 : stored_frame_chunks_(), read_callback_(), read_frame_chunks_(NULL) {}
320
321 virtual int WriteFrames(ScopedVector<WebSocketFrameChunk>* frame_chunks,
322 const CompletionCallback& callback) OVERRIDE {
323 // Users of WebSocketStream will not expect the ReadFrames() callback to be
324 // called from within WriteFrames(), so post it to the message loop instead.
325 stored_frame_chunks_.insert(stored_frame_chunks_.end(),
326 frame_chunks->begin(),
327 frame_chunks->end());
328 frame_chunks->weak_clear();
329 base::MessageLoop::current()->PostTask(
330 FROM_HERE,
331 base::Bind(&EchoeyFakeWebSocketStream::DoCallback,
332 base::Unretained(this)));
333 return OK;
334 }
335
336 virtual int ReadFrames(ScopedVector<WebSocketFrameChunk>* frame_chunks,
337 const CompletionCallback& callback) OVERRIDE {
338 read_callback_ = callback;
339 read_frame_chunks_ = frame_chunks;
340 return ERR_IO_PENDING;
341 }
342
343 private:
344 void DoCallback() {
345 if (!stored_frame_chunks_.empty()) {
346 MoveFrameChunks(read_frame_chunks_);
347 read_frame_chunks_ = NULL;
348 read_callback_.Run(OK);
349 read_callback_.Reset();
350 }
351 }
352
353 void MoveFrameChunks(ScopedVector<WebSocketFrameChunk>* to) {
354 to->assign(stored_frame_chunks_.begin(), stored_frame_chunks_.end());
355 for (ScopedVector<WebSocketFrameChunk>::iterator it = to->begin();
356 it != to->end();
357 ++it) {
358 if ((*it)->header && ((*it)->header->masked)) {
359 (*it)->header->masked = false;
360 }
361 }
362 stored_frame_chunks_.weak_clear();
363 }
364
365 ScopedVector<WebSocketFrameChunk> stored_frame_chunks_;
366 CompletionCallback read_callback_;
367 // Owned by the caller of ReadFrames().
368 ScopedVector<WebSocketFrameChunk>* read_frame_chunks_;
369 };
370
371 // This mock is for verifying that WebSocket protocol semantics are obeyed (to
372 // the extent that they are implemented in WebSocketCommon).
373 class MockWebSocketStream : public WebSocketStream {
374 public:
375 MOCK_METHOD2(ReadFrames,
376 int(ScopedVector<WebSocketFrameChunk>* frame_chunks,
377 const CompletionCallback& callback));
378 MOCK_METHOD2(WriteFrames,
379 int(ScopedVector<WebSocketFrameChunk>* frame_chunks,
380 const CompletionCallback& callback));
381 MOCK_METHOD0(Close, void());
382 MOCK_CONST_METHOD0(GetSubProtocol, std::string());
383 MOCK_CONST_METHOD0(GetExtensions, std::string());
384 MOCK_METHOD0(AsWebSocketStream, WebSocketStream*());
385 MOCK_METHOD4(SendHandshakeRequest,
386 int(const GURL& url,
387 const HttpRequestHeaders& headers,
388 HttpResponseInfo* response_info,
389 const CompletionCallback& callback));
390 MOCK_METHOD1(ReadHandshakeResponse, int(const CompletionCallback& callback));
391 };
392
393 struct ArgumentCopyingWebSocketFactory {
394 scoped_ptr<WebSocketStreamRequest> Factory(
395 const GURL& socket_url,
396 const std::vector<std::string>& requested_subprotocols,
397 const GURL& origin,
398 URLRequestContext* url_request_context,
399 const BoundNetLog& net_log,
400 scoped_ptr<WebSocketStream::ConnectDelegate> connect_delegate) {
401 this->socket_url = socket_url;
402 this->requested_subprotocols = requested_subprotocols;
403 this->origin = origin;
404 this->url_request_context = url_request_context;
405 this->net_log = net_log;
406 this->connect_delegate = connect_delegate.Pass();
407 return make_scoped_ptr(new WebSocketStreamRequest);
408 }
409
410 GURL socket_url;
411 GURL origin;
412 std::vector<std::string> requested_subprotocols;
413 URLRequestContext* url_request_context;
414 BoundNetLog net_log;
415 scoped_ptr<WebSocketStream::ConnectDelegate> connect_delegate;
416 };
417
418 // The WebSocketEventInterface handles data as vector<char>. For testing
419 // purposes, this function allows a vector<char> to be easily created from a
420 // string.
421 std::vector<char> AsVector(const std::string& s) {
422 return std::vector<char>(s.begin(), s.end());
423 }
424
425 // Base class for WebSocketChannelTests.
426 class WebSocketChannelTest : public ::testing::Test {
427 protected:
428 WebSocketChannelTest()
429 : data_(), channel_(), stream_(new FakeWebSocketStream) {}
430
431 // Create a new WebSocketChannel and connect it, using the settings stored in
432 // data_.
433 void CreateChannelAndConnect() {
434 channel_.reset(
435 new WebSocketChannel(data_.url, EventInterface()));
436 channel_->SendAddChannelRequestWithFactory(
437 data_.requested_subprotocols,
438 data_.origin,
439 &data_.url_request_context,
440 base::Bind(&ArgumentCopyingWebSocketFactory::Factory,
441 base::Unretained(&data_.factory)));
442 }
443
444 // Same as CreateChannelAndConnect(), but call the on_success callback as
445 // well. This method is virtual so that WebSocketChannelStreamTest can set the
446 // stream as well.
447 virtual void CreateChannelAndConnectSuccessfully() {
448 CreateChannelAndConnect();
449 data_.factory.connect_delegate->OnSuccess(stream_.Pass());
450 }
451
452 // Return a WebSocketEventInterface to be passed to the WebSocketChannel.
453 // This implementation returns a newly-created fake. Subclasses may return a
454 // mock instead.
455 virtual scoped_ptr<WebSocketEventInterface> EventInterface() {
456 return scoped_ptr<WebSocketEventInterface>(new FakeWebSocketEventInterface);
457 }
458
459 // Downcasting and moving a scoped_ptr in one operation doesn't seem to work
460 // (bug?). This function works around that and simplifies initialising stream_
461 // from a subclass.
462 template<class T>
463 void set_stream(scoped_ptr<T> stream) {
464 stream_.reset(stream.release());
465 }
466
467 // A struct containing the data that will be used to connect the channel.
468 struct ConnectData {
469 // URL to (pretend to) connect to.
470 GURL url;
471 // Origin of the request
472 GURL origin;
473 // Requested protocols for the request.
474 std::vector<std::string> requested_subprotocols;
475 // URLRequestContext object.
476 URLRequestContext url_request_context;
477 // A fake WebSocketFactory that just records its arguments.
478 ArgumentCopyingWebSocketFactory factory;
479 };
480 ConnectData data_;
481
482 // The channel we are testing. Not initialised until SetChannel() is called.
483 scoped_ptr<WebSocketChannel> channel_;
484
485 // A mock or fake stream for tests that need one.
486 scoped_ptr<WebSocketStream> stream_;
487 };
488
489 // Base class for tests which verify that EventInterface methods are called
490 // appropriately.
491 class WebSocketChannelEventInterfaceTest : public WebSocketChannelTest {
492 protected:
493 WebSocketChannelEventInterfaceTest()
494 : WebSocketChannelTest(),
495 event_interface_(new MockWebSocketEventInterface) {}
496
497 virtual scoped_ptr<WebSocketEventInterface> EventInterface() OVERRIDE {
498 return scoped_ptr<WebSocketEventInterface>(event_interface_.release());
499 }
500
501 scoped_ptr<MockWebSocketEventInterface> event_interface_;
502 };
503
504 // Base class for tests which verify that WebSocketStream methods are called
505 // appropriately by using a MockWebSocketStream.
506 class WebSocketChannelStreamTest : public WebSocketChannelTest {
507 protected:
508 WebSocketChannelStreamTest()
509 : WebSocketChannelTest(),
510 mock_(new MockWebSocketStream) {}
511
512 virtual void CreateChannelAndConnectSuccessfully() OVERRIDE {
513 set_stream(mock_.Pass());
514 WebSocketChannelTest::CreateChannelAndConnectSuccessfully();
515 }
516
517 scoped_ptr<MockWebSocketStream> mock_;
518 };
519
520 // Simple test that everything that should be passed to the factory function is
521 // passed to the factory function.
522 TEST_F(WebSocketChannelTest, EverythingIsPassedToTheFactoryFunction) {
523 data_.url = GURL("ws://example.com/test");
524 data_.origin = GURL("http://example.com/test");
525 data_.requested_subprotocols.push_back("Sinbad");
526
527 CreateChannelAndConnect();
528
529 EXPECT_EQ(data_.url, data_.factory.socket_url);
530 EXPECT_EQ(data_.origin, data_.factory.origin);
531 EXPECT_EQ(data_.requested_subprotocols, data_.factory.requested_subprotocols);
532 EXPECT_EQ(&data_.url_request_context, data_.factory.url_request_context);
533 }
534
535 TEST_F(WebSocketChannelEventInterfaceTest, ConnectSuccessReported) {
536 // false means success.
537 EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, ""));
538 // OnFlowControl is always called immediately after connect to provide initial
539 // quota to the renderer.
540 EXPECT_CALL(*event_interface_, OnFlowControl(_));
541
542 CreateChannelAndConnect();
543
544 data_.factory.connect_delegate->OnSuccess(stream_.Pass());
545 }
546
547 TEST_F(WebSocketChannelEventInterfaceTest, ConnectFailureReported) {
548 // true means failure.
549 EXPECT_CALL(*event_interface_, OnAddChannelResponse(true, ""));
550
551 CreateChannelAndConnect();
552
553 data_.factory.connect_delegate->OnFailure(kWebSocketErrorNoStatusReceived);
554 }
555
556 TEST_F(WebSocketChannelEventInterfaceTest, ProtocolPassed) {
557 EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, "Bob"));
558 EXPECT_CALL(*event_interface_, OnFlowControl(_));
559
560 CreateChannelAndConnect();
561
562 data_.factory.connect_delegate->OnSuccess(
563 scoped_ptr<WebSocketStream>(new FakeWebSocketStream("Bob", "")));
564 }
565
566 // The first frames from the server can arrive together with the handshake, in
567 // which case they will be available as soon as ReadFrames() is called the first
568 // time.
569 TEST_F(WebSocketChannelEventInterfaceTest, DataLeftFromHandshake) {
570 scoped_ptr<ReadableFakeWebSocketStream> stream(
571 new ReadableFakeWebSocketStream);
572 static const InitFrameChunk chunks[] = {
573 {{FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, NOT_MASKED, 5},
574 FINAL_CHUNK, "HELLO"},
575 };
576 stream->PrepareReadFrames(ReadableFakeWebSocketStream::SYNC, OK, chunks);
577 set_stream(stream.Pass());
578 {
579 InSequence s;
580 EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _));
581 EXPECT_CALL(*event_interface_, OnFlowControl(_));
582 EXPECT_CALL(
583 *event_interface_,
584 OnSendFrame(
585 true, WebSocketFrameHeader::kOpCodeText, AsVector("HELLO")));
586 }
587
588 CreateChannelAndConnectSuccessfully();
589 }
590
591 // A remote server could accept the handshake, but then immediately send a
592 // close frame.
593 TEST_F(WebSocketChannelEventInterfaceTest, CloseAfterHandshake) {
594 scoped_ptr<ReadableFakeWebSocketStream> stream(
595 new ReadableFakeWebSocketStream);
596 static const InitFrameChunk chunks[] = {
597 {{FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose, NOT_MASKED, 23},
598 FINAL_CHUNK, "\x03\xf3Internal Server Error"},
599 };
600 stream->PrepareReadFrames(ReadableFakeWebSocketStream::SYNC, OK, chunks);
601 set_stream(stream.Pass());
602 {
603 InSequence s;
604 EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _));
605 EXPECT_CALL(*event_interface_, OnFlowControl(_));
606 EXPECT_CALL(*event_interface_,
607 OnDropChannel(kWebSocketErrorInternalServerError,
608 "Internal Server Error"));
609 }
610
611 CreateChannelAndConnectSuccessfully();
612 }
613
614 // A remote server could close the connection immediately after sending the
615 // handshake response (most likely a bug in the server).
616 TEST_F(WebSocketChannelEventInterfaceTest, ConnectionCloseAfterHandshake) {
617 scoped_ptr<ReadableFakeWebSocketStream> stream(
618 new ReadableFakeWebSocketStream);
619 stream->PrepareReadFramesError(ReadableFakeWebSocketStream::SYNC,
620 ERR_CONNECTION_CLOSED);
621 set_stream(stream.Pass());
622 {
623 InSequence s;
624 EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _));
625 EXPECT_CALL(*event_interface_, OnFlowControl(_));
626 EXPECT_CALL(*event_interface_,
627 OnDropChannel(kWebSocketErrorAbnormalClosure,
628 "Abnormal Closure"));
629 }
630
631 CreateChannelAndConnectSuccessfully();
632 }
633
634 TEST_F(WebSocketChannelEventInterfaceTest, NormalAsyncRead) {
635 scoped_ptr<ReadableFakeWebSocketStream> stream(
636 new ReadableFakeWebSocketStream);
637 static const InitFrameChunk chunks[] = {
638 {{FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, NOT_MASKED, 5},
639 FINAL_CHUNK, "HELLO"},
640 };
641 // We use this checkpoint object to verify that the callback isn't called
642 // until we expect it to be.
643 MockFunction<void(int)> checkpoint;
644 stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, chunks);
645 set_stream(stream.Pass());
646 {
647 InSequence s;
648 EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _));
649 EXPECT_CALL(*event_interface_, OnFlowControl(_));
650 EXPECT_CALL(checkpoint, Call(1));
651 EXPECT_CALL(
652 *event_interface_,
653 OnSendFrame(
654 true, WebSocketFrameHeader::kOpCodeText, AsVector("HELLO")));
655 EXPECT_CALL(checkpoint, Call(2));
656 }
657
658 CreateChannelAndConnectSuccessfully();
659 checkpoint.Call(1);
660 base::MessageLoop::current()->RunUntilIdle();
661 checkpoint.Call(2);
662 }
663
664 // Extra data can arrive while a read is being processed, resulting in the next
665 // read completing synchronously.
666 TEST_F(WebSocketChannelEventInterfaceTest, AsyncThenSyncRead) {
667 scoped_ptr<ReadableFakeWebSocketStream> stream(
668 new ReadableFakeWebSocketStream);
669 static const InitFrameChunk chunks1[] = {
670 {{FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, NOT_MASKED, 5},
671 FINAL_CHUNK, "HELLO"},
672 };
673 static const InitFrameChunk chunks2[] = {
674 {{FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, NOT_MASKED, 5},
675 FINAL_CHUNK, "WORLD"},
676 };
677 stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, chunks1);
678 stream->PrepareReadFrames(ReadableFakeWebSocketStream::SYNC, OK, chunks2);
679 set_stream(stream.Pass());
680 {
681 InSequence s;
682 EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _));
683 EXPECT_CALL(*event_interface_, OnFlowControl(_));
684 EXPECT_CALL(
685 *event_interface_,
686 OnSendFrame(
687 true, WebSocketFrameHeader::kOpCodeText, AsVector("HELLO")));
688 EXPECT_CALL(
689 *event_interface_,
690 OnSendFrame(
691 true, WebSocketFrameHeader::kOpCodeText, AsVector("WORLD")));
692 }
693
694 CreateChannelAndConnectSuccessfully();
695 base::MessageLoop::current()->RunUntilIdle();
696 }
697
698 // Data frames that arrive in fragments are turned into individual frames
699 TEST_F(WebSocketChannelEventInterfaceTest, FragmentedFrames) {
700 scoped_ptr<ReadableFakeWebSocketStream> stream(
701 new ReadableFakeWebSocketStream);
702 // Here we have one message split into 3 frames which arrive in 3 chunks. The
703 // first frame is entirely in the first chunk, the second frame is split
704 // across all the chunks, and the final frame is entirely in the final
705 // chunk. This should be delivered as 5 frames.
706 static const InitFrameChunk chunks1[] = {
707 {{NOT_FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, NOT_MASKED, 5},
708 FINAL_CHUNK, "THREE"},
709 {{NOT_FINAL_FRAME, WebSocketFrameHeader::kOpCodeContinuation, NOT_MASKED,
710 7},
711 NOT_FINAL_CHUNK, " "},
712 };
713 static const InitFrameChunk chunks2[] = {{{NO_HEADER}, NOT_FINAL_CHUNK,
714 "SMALL"}};
715 static const InitFrameChunk chunks3[] = {
716 {{NO_HEADER}, FINAL_CHUNK, " "},
717 {{FINAL_FRAME, WebSocketFrameHeader::kOpCodeContinuation, NOT_MASKED, 6},
718 FINAL_CHUNK, "FRAMES"},
719 };
720 stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, chunks1);
721 stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, chunks2);
722 stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, chunks3);
723 set_stream(stream.Pass());
724 {
725 InSequence s;
726 EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _));
727 EXPECT_CALL(*event_interface_, OnFlowControl(_));
728 EXPECT_CALL(
729 *event_interface_,
730 OnSendFrame(
731 false, WebSocketFrameHeader::kOpCodeText, AsVector("THREE")));
732 EXPECT_CALL(
733 *event_interface_,
734 OnSendFrame(
735 false, WebSocketFrameHeader::kOpCodeContinuation, AsVector(" ")));
736 EXPECT_CALL(*event_interface_,
737 OnSendFrame(false,
738 WebSocketFrameHeader::kOpCodeContinuation,
739 AsVector("SMALL")));
740 EXPECT_CALL(
741 *event_interface_,
742 OnSendFrame(
743 false, WebSocketFrameHeader::kOpCodeContinuation, AsVector(" ")));
744 EXPECT_CALL(*event_interface_,
745 OnSendFrame(true,
746 WebSocketFrameHeader::kOpCodeContinuation,
747 AsVector("FRAMES")));
748 }
749
750 CreateChannelAndConnectSuccessfully();
751 base::MessageLoop::current()->RunUntilIdle();
752 }
753
754 // In the case when a single-frame message because fragmented, it must be
755 // correctly transformed to multiple frames.
756 TEST_F(WebSocketChannelEventInterfaceTest, MessageFragmentation) {
757 scoped_ptr<ReadableFakeWebSocketStream> stream(
758 new ReadableFakeWebSocketStream);
759 // Here we have one message split into 3 frames which arrive in 3 chunks. The
760 // first frame is entirely in the first chunk, the second frame is split
761 // across all the chunks, and the final frame is entirely in the final
762 // chunk. This should be delivered as 5 frames.
763 static const InitFrameChunk chunks1[] = {
764 {{FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, NOT_MASKED, 12},
765 NOT_FINAL_CHUNK, "TIME"},
766 };
767 static const InitFrameChunk chunks2[] = {{{NO_HEADER}, NOT_FINAL_CHUNK,
768 " FOR "}};
769 static const InitFrameChunk chunks3[] = {{{NO_HEADER}, FINAL_CHUNK, "TEA"}};
770 stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, chunks1);
771 stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, chunks2);
772 stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, chunks3);
773 set_stream(stream.Pass());
774 {
775 InSequence s;
776 EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _));
777 EXPECT_CALL(*event_interface_, OnFlowControl(_));
778 EXPECT_CALL(
779 *event_interface_,
780 OnSendFrame(
781 false, WebSocketFrameHeader::kOpCodeText, AsVector("TIME")));
782 EXPECT_CALL(*event_interface_,
783 OnSendFrame(false,
784 WebSocketFrameHeader::kOpCodeContinuation,
785 AsVector(" FOR ")));
786 EXPECT_CALL(
787 *event_interface_,
788 OnSendFrame(
789 true, WebSocketFrameHeader::kOpCodeContinuation, AsVector("TEA")));
790 }
791
792 CreateChannelAndConnectSuccessfully();
793 base::MessageLoop::current()->RunUntilIdle();
794 }
795
796 // If a control message is fragmented, it must be re-assembled before being
797 // delivered. A control message can only be fragmented at the network level; it
798 // is not permitted to be split into multiple frames.
799 TEST_F(WebSocketChannelEventInterfaceTest, FragmentedControlMessage) {
800 scoped_ptr<ReadableFakeWebSocketStream> stream(
801 new ReadableFakeWebSocketStream);
802 static const InitFrameChunk chunks1[] = {
803 {{FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose, NOT_MASKED, 7},
804 NOT_FINAL_CHUNK, "\x03\xe8"},
805 };
806 static const InitFrameChunk chunks2[] = {{{NO_HEADER}, NOT_FINAL_CHUNK,
807 "Clo"}};
808 static const InitFrameChunk chunks3[] = {{{NO_HEADER}, FINAL_CHUNK,
809 "se"}};
810 stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, chunks1);
811 stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, chunks2);
812 stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, chunks3);
813 set_stream(stream.Pass());
814 {
815 InSequence s;
816 EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _));
817 EXPECT_CALL(*event_interface_, OnFlowControl(_));
818 EXPECT_CALL(*event_interface_,
819 OnDropChannel(kWebSocketNormalClosure, "Close"));
820 }
821
822 CreateChannelAndConnectSuccessfully();
823 base::MessageLoop::current()->RunUntilIdle();
824 }
825
826 // Connection closed unexpectedly.
827 TEST_F(WebSocketChannelEventInterfaceTest, AsyncAbnormalClosure) {
828 scoped_ptr<ReadableFakeWebSocketStream> stream(
829 new ReadableFakeWebSocketStream);
830 stream->PrepareReadFramesError(ReadableFakeWebSocketStream::ASYNC,
831 ERR_CONNECTION_CLOSED);
832 set_stream(stream.Pass());
833 {
834 InSequence s;
835 EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _));
836 EXPECT_CALL(*event_interface_, OnFlowControl(_));
837 EXPECT_CALL(*event_interface_,
838 OnDropChannel(kWebSocketErrorAbnormalClosure, _));
839 }
840
841 CreateChannelAndConnectSuccessfully();
842 base::MessageLoop::current()->RunUntilIdle();
843 }
844
845 // Connection reset.
846 TEST_F(WebSocketChannelEventInterfaceTest, ConnectionReset) {
847 scoped_ptr<ReadableFakeWebSocketStream> stream(
848 new ReadableFakeWebSocketStream);
849 stream->PrepareReadFramesError(ReadableFakeWebSocketStream::ASYNC,
850 ERR_CONNECTION_RESET);
851 set_stream(stream.Pass());
852 {
853 InSequence s;
854 EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _));
855 EXPECT_CALL(*event_interface_, OnFlowControl(_));
856 EXPECT_CALL(*event_interface_,
857 OnDropChannel(kWebSocketErrorAbnormalClosure, _));
858 }
859
860 CreateChannelAndConnectSuccessfully();
861 base::MessageLoop::current()->RunUntilIdle();
862 }
863
864 // Connection closed in the middle of a Close message (server bug, etc.)
865 TEST_F(WebSocketChannelEventInterfaceTest, ConnectionClosedInMessage) {
866 scoped_ptr<ReadableFakeWebSocketStream> stream(
867 new ReadableFakeWebSocketStream);
868 static const InitFrameChunk chunks[] = {
869 {{FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose, NOT_MASKED, 7},
870 NOT_FINAL_CHUNK, "\x03\xe8"},
871 };
872
873 stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, chunks);
874 stream->PrepareReadFramesError(ReadableFakeWebSocketStream::ASYNC,
875 ERR_CONNECTION_CLOSED);
876 set_stream(stream.Pass());
877 {
878 InSequence s;
879 EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _));
880 EXPECT_CALL(*event_interface_, OnFlowControl(_));
881 EXPECT_CALL(*event_interface_,
882 OnDropChannel(kWebSocketErrorAbnormalClosure, _));
883 }
884
885 CreateChannelAndConnectSuccessfully();
886 base::MessageLoop::current()->RunUntilIdle();
887 }
888
889 // RFC6455 5.1 "A client MUST close a connection if it detects a masked frame."
890 TEST_F(WebSocketChannelEventInterfaceTest, MaskedFramesAreRejected) {
891 scoped_ptr<ReadableFakeWebSocketStream> stream(
892 new ReadableFakeWebSocketStream);
893 static const InitFrameChunk chunks[] = {
894 {{FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, MASKED, 5}, FINAL_CHUNK,
895 "HELLO"}
896 };
897
898 stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, chunks);
899 set_stream(stream.Pass());
900 {
901 InSequence s;
902 EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _));
903 EXPECT_CALL(*event_interface_, OnFlowControl(_));
904 EXPECT_CALL(*event_interface_,
905 OnDropChannel(kWebSocketErrorProtocolError, _));
906 }
907
908 CreateChannelAndConnectSuccessfully();
909 base::MessageLoop::current()->RunUntilIdle();
910 }
911
912 // RFC6455 5.2 "If an unknown opcode is received, the receiving endpoint MUST
913 // _Fail the WebSocket Connection_."
914 TEST_F(WebSocketChannelEventInterfaceTest, UnknownOpCodeIsRejected) {
915 scoped_ptr<ReadableFakeWebSocketStream> stream(
916 new ReadableFakeWebSocketStream);
917 static const InitFrameChunk chunks[] = {{{FINAL_FRAME, 4, NOT_MASKED, 5},
918 FINAL_CHUNK, "HELLO"}};
919
920 stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, chunks);
921 set_stream(stream.Pass());
922 {
923 InSequence s;
924 EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _));
925 EXPECT_CALL(*event_interface_, OnFlowControl(_));
926 EXPECT_CALL(*event_interface_,
927 OnDropChannel(kWebSocketErrorProtocolError, _));
928 }
929
930 CreateChannelAndConnectSuccessfully();
931 base::MessageLoop::current()->RunUntilIdle();
932 }
933
934 // RFC6455 5.4 "Control frames ... MAY be injected in the middle of a
935 // fragmented message."
936 TEST_F(WebSocketChannelEventInterfaceTest, ControlFrameInDataMessage) {
937 scoped_ptr<ReadableFakeWebSocketStream> stream(
938 new ReadableFakeWebSocketStream);
939 // We have one message of type Text split into two frames. In the middle is a
940 // control message of type Pong.
941 static const InitFrameChunk chunks1[] = {
942 {{NOT_FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, NOT_MASKED, 6},
943 FINAL_CHUNK, "SPLIT "},
944 };
945 static const InitFrameChunk chunks2[] = {
946 {{FINAL_FRAME, WebSocketFrameHeader::kOpCodePong, NOT_MASKED, 0},
947 FINAL_CHUNK, ""}
948 };
949 static const InitFrameChunk chunks3[] = {
950 {{FINAL_FRAME, WebSocketFrameHeader::kOpCodeContinuation, NOT_MASKED, 7},
951 FINAL_CHUNK, "MESSAGE"}
952 };
953 stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, chunks1);
954 stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, chunks2);
955 stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, chunks3);
956 set_stream(stream.Pass());
957 {
958 InSequence s;
959 EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _));
960 EXPECT_CALL(*event_interface_, OnFlowControl(_));
961 EXPECT_CALL(
962 *event_interface_,
963 OnSendFrame(
964 false, WebSocketFrameHeader::kOpCodeText, AsVector("SPLIT ")));
965 EXPECT_CALL(*event_interface_,
966 OnSendFrame(true,
967 WebSocketFrameHeader::kOpCodeContinuation,
968 AsVector("MESSAGE")));
969 }
970
971 CreateChannelAndConnectSuccessfully();
972 base::MessageLoop::current()->RunUntilIdle();
973 }
974
975 // If the renderer sends lots of small writes, we don't want to update the quota
976 // for each one.
977 TEST_F(WebSocketChannelEventInterfaceTest, SmallWriteDoesntUpdateQuota) {
978 set_stream(make_scoped_ptr(new WriteableFakeWebSocketStream));
979 {
980 InSequence s;
981 EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _));
982 EXPECT_CALL(*event_interface_, OnFlowControl(_));
983 }
984
985 CreateChannelAndConnectSuccessfully();
986 channel_->SendFrame(true, WebSocketFrameHeader::kOpCodeText, AsVector("B"));
987 }
988
989 // If we send enough to go below send_quota_low_water_mask_ we should get our
990 // quota refreshed.
991 TEST_F(WebSocketChannelEventInterfaceTest, LargeWriteUpdatesQuota) {
992 set_stream(make_scoped_ptr(new WriteableFakeWebSocketStream));
993 // We use this checkpoint object to verify that the quota update comes after
994 // the write.
995 MockFunction<void(int)> checkpoint;
996 {
997 InSequence s;
998 EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _));
999 EXPECT_CALL(*event_interface_, OnFlowControl(_));
1000 EXPECT_CALL(checkpoint, Call(1));
1001 EXPECT_CALL(*event_interface_, OnFlowControl(_));
1002 EXPECT_CALL(checkpoint, Call(2));
1003 }
1004
1005 CreateChannelAndConnectSuccessfully();
1006 checkpoint.Call(1);
1007 // TODO(ricea): If kDefaultSendQuotaHighWaterMark changes, then this value
1008 // will need to be updated.
1009 channel_->SendFrame(
1010 true, WebSocketFrameHeader::kOpCodeText, std::vector<char>(1 << 17, 'B'));
1011 checkpoint.Call(2);
1012 }
1013
1014 // Verify that our quota actually is refreshed when we are told it is.
1015 TEST_F(WebSocketChannelEventInterfaceTest, QuotaReallyIsRefreshed) {
1016 set_stream(make_scoped_ptr(new WriteableFakeWebSocketStream));
1017 MockFunction<void(int)> checkpoint;
1018 {
1019 InSequence s;
1020 EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _));
1021 EXPECT_CALL(*event_interface_, OnFlowControl(_));
1022 EXPECT_CALL(checkpoint, Call(1));
1023 EXPECT_CALL(*event_interface_, OnFlowControl(_));
1024 EXPECT_CALL(checkpoint, Call(2));
1025 // If quota was not really refreshed, we would get an OnDropChannel()
1026 // message.
1027 EXPECT_CALL(*event_interface_, OnFlowControl(_));
1028 EXPECT_CALL(checkpoint, Call(3));
1029 }
1030
1031 CreateChannelAndConnectSuccessfully();
1032 checkpoint.Call(1);
1033 // TODO(ricea): If kDefaultSendQuotaLowWaterMark and/or
1034 // kDefaultSendQuotaHighWaterMark change, then this value will need to be
1035 // updated.
1036 channel_->SendFrame(true,
1037 WebSocketFrameHeader::kOpCodeText,
1038 std::vector<char>((1 << 16) + 1, 'D'));
1039 checkpoint.Call(2);
1040 // We should have received more quota at this point.
1041 channel_->SendFrame(true,
1042 WebSocketFrameHeader::kOpCodeText,
1043 std::vector<char>((1 << 16) + 1, 'E'));
1044 checkpoint.Call(3);
1045 }
1046
1047 // If we send more than the available quota then the connection will be closed
1048 // with an error.
1049 TEST_F(WebSocketChannelEventInterfaceTest, WriteOverQuotaIsRejected) {
1050 set_stream(make_scoped_ptr(new WriteableFakeWebSocketStream));
1051 {
1052 InSequence s;
1053 EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _));
1054 // TODO(ricea): Change this if kDefaultSendQuotaHighWaterMark changes.
1055 EXPECT_CALL(*event_interface_, OnFlowControl(1 << 17));
1056 EXPECT_CALL(*event_interface_,
1057 OnDropChannel(kWebSocketMuxErrorSendQuotaViolation, _));
1058 }
1059
1060 CreateChannelAndConnectSuccessfully();
1061 channel_->SendFrame(true,
1062 WebSocketFrameHeader::kOpCodeText,
1063 std::vector<char>((1 << 17) + 1, 'C'));
1064 }
1065
1066 // If a write fails, the channel is dropped.
1067 TEST_F(WebSocketChannelEventInterfaceTest, FailedWrite) {
1068 set_stream(make_scoped_ptr(new UnWriteableFakeWebSocketStream));
1069 MockFunction<void(int)> checkpoint;
1070 {
1071 InSequence s;
1072 EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _));
1073 EXPECT_CALL(*event_interface_, OnFlowControl(_));
1074 EXPECT_CALL(checkpoint, Call(1));
1075 EXPECT_CALL(*event_interface_,
1076 OnDropChannel(kWebSocketErrorAbnormalClosure, _));
1077 EXPECT_CALL(checkpoint, Call(2));
1078 }
1079
1080 CreateChannelAndConnectSuccessfully();
1081 checkpoint.Call(1);
1082
1083 channel_->SendFrame(true, WebSocketFrameHeader::kOpCodeText, AsVector("H"));
1084 checkpoint.Call(2);
1085 }
1086
1087 // OnDropChannel() is called exactly once when SendDropChannel() is used.
1088 TEST_F(WebSocketChannelEventInterfaceTest, SendCloseDropsChannel) {
1089 set_stream(make_scoped_ptr(new EchoeyFakeWebSocketStream));
1090 {
1091 InSequence s;
1092 EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _));
1093 EXPECT_CALL(*event_interface_, OnFlowControl(_));
1094 EXPECT_CALL(*event_interface_,
1095 OnDropChannel(kWebSocketNormalClosure, "Fred"));
1096 }
1097
1098 CreateChannelAndConnectSuccessfully();
1099
1100 channel_->SendDropChannel(kWebSocketNormalClosure, "Fred");
1101 base::MessageLoop::current()->RunUntilIdle();
1102 }
1103
1104 // RGC6455 5.1 "a client MUST mask all frames that it sends to the server".
1105 // WebSocketChannel actually only sets the mask bit in the header, it doesn't
1106 // perform masking itself (not all transports actually use masking).
1107 TEST_F(WebSocketChannelStreamTest, SentFramesAreMasked) {
1108 EXPECT_CALL(*mock_, GetSubProtocol()).Times(AnyNumber());
1109 EXPECT_CALL(*mock_, ReadFrames(_, _)).WillOnce(Return(ERR_IO_PENDING));
1110 EXPECT_CALL(*mock_,
1111 WriteFrames(Pointee(
1112 ElementsAre(Pointee(Field(
1113 &WebSocketFrameChunk::header,
1114 Pointee(Field(&WebSocketFrameHeader::masked, true)))))),
1115 _)).WillOnce(Return(ERR_IO_PENDING));
1116
1117 CreateChannelAndConnectSuccessfully();
1118 channel_->SendFrame(
1119 true, WebSocketFrameHeader::kOpCodeText, AsVector("NEEDS MASKING"));
1120 }
1121
1122 } // namespace
1123 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698