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

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: Fixes to comments and variable names. 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(OnDataFrame,
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
tyoshino (SeeGerritForStatus) 2013/07/01 08:53:32 a WebSocket...? Not sure but [w] is not vowel?
Adam Rice 2013/07/01 10:08:14 I wrote "an EventInterface" then changed it to "We
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 OnDataFrame(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 code, const std::string& reason)
86 OVERRIDE {}
87 };
88
89 // This fake WebSocketStream is for tests that require a WebSocketStream but are
tyoshino (SeeGerritForStatus) 2013/07/01 08:53:32 are are -> are
Adam Rice 2013/07/01 10:08:14 Well spotted! Fixed.
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.
tyoshino (SeeGerritForStatus) 2013/07/01 08:53:32 Constructs
Adam Rice 2013/07/01 10:08:14 Done.
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]) {
tyoshino (SeeGerritForStatus) 2013/07/01 08:53:32 chunks -> source_chunks
Adam Rice 2013/07/01 10:08:14 Done.
187 ScopedVector<WebSocketFrameChunk> vector;
tyoshino (SeeGerritForStatus) 2013/07/01 08:53:32 vector -> result_chunks
Adam Rice 2013/07/01 10:08:14 Done.
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(
326 stored_frame_chunks_.end(), frame_chunks->begin(), frame_chunks->end());
327 frame_chunks->weak_clear();
328 base::MessageLoop::current()->PostTask(
329 FROM_HERE,
330 base::Bind(&EchoeyFakeWebSocketStream::DoCallback,
331 base::Unretained(this)));
332 return OK;
333 }
334
335 virtual int ReadFrames(ScopedVector<WebSocketFrameChunk>* frame_chunks,
336 const CompletionCallback& callback) OVERRIDE {
337 read_callback_ = callback;
338 read_frame_chunks_ = frame_chunks;
339 return ERR_IO_PENDING;
340 }
341
342 private:
343 void DoCallback() {
344 if (!stored_frame_chunks_.empty()) {
345 MoveFrameChunks(read_frame_chunks_);
346 read_frame_chunks_ = NULL;
347 read_callback_.Run(OK);
348 read_callback_.Reset();
349 }
350 }
351
352 void MoveFrameChunks(ScopedVector<WebSocketFrameChunk>* to) {
353 to->assign(stored_frame_chunks_.begin(), stored_frame_chunks_.end());
354 for (ScopedVector<WebSocketFrameChunk>::iterator it = to->begin();
355 it != to->end();
356 ++it) {
357 if ((*it)->header && ((*it)->header->masked)) {
358 (*it)->header->masked = false;
359 }
360 }
361 stored_frame_chunks_.weak_clear();
362 }
363
364 ScopedVector<WebSocketFrameChunk> stored_frame_chunks_;
365 CompletionCallback read_callback_;
366 // Owned by the caller of ReadFrames().
367 ScopedVector<WebSocketFrameChunk>* read_frame_chunks_;
368 };
369
370 // This mock is for verifying that WebSocket protocol semantics are obeyed (to
371 // the extent that they are implemented in WebSocketCommon).
372 class MockWebSocketStream : public WebSocketStream {
373 public:
374 MOCK_METHOD2(ReadFrames,
375 int(ScopedVector<WebSocketFrameChunk>* frame_chunks,
376 const CompletionCallback& callback));
377 MOCK_METHOD2(WriteFrames,
378 int(ScopedVector<WebSocketFrameChunk>* frame_chunks,
379 const CompletionCallback& callback));
380 MOCK_METHOD0(Close, void());
381 MOCK_CONST_METHOD0(GetSubProtocol, std::string());
382 MOCK_CONST_METHOD0(GetExtensions, std::string());
383 MOCK_METHOD0(AsWebSocketStream, WebSocketStream*());
384 MOCK_METHOD4(SendHandshakeRequest,
385 int(const GURL& url,
386 const HttpRequestHeaders& headers,
387 HttpResponseInfo* response_info,
388 const CompletionCallback& callback));
389 MOCK_METHOD1(ReadHandshakeResponse, int(const CompletionCallback& callback));
390 };
391
392 struct ArgumentCopyingWebSocketFactory {
393 scoped_ptr<WebSocketStreamRequest> Factory(
394 const GURL& socket_url,
395 const std::vector<std::string>& requested_subprotocols,
396 const GURL& origin,
397 URLRequestContext* url_request_context,
398 const BoundNetLog& net_log,
399 scoped_ptr<WebSocketStream::ConnectDelegate> connect_delegate) {
400 this->socket_url = socket_url;
401 this->requested_subprotocols = requested_subprotocols;
402 this->origin = origin;
403 this->url_request_context = url_request_context;
404 this->net_log = net_log;
405 this->connect_delegate = connect_delegate.Pass();
406 return make_scoped_ptr(new WebSocketStreamRequest);
407 }
408
409 GURL socket_url;
410 GURL origin;
411 std::vector<std::string> requested_subprotocols;
412 URLRequestContext* url_request_context;
413 BoundNetLog net_log;
414 scoped_ptr<WebSocketStream::ConnectDelegate> connect_delegate;
415 };
416
417 // The WebSocketEventInterface handles data as vector<char>. For testing
418 // purposes, this function allows a vector<char> to be easily created from a
419 // string.
420 std::vector<char> AsVector(const std::string& s) {
421 return std::vector<char>(s.begin(), s.end());
422 }
423
424 // Base class for WebSocketChannelTests.
425 class WebSocketChannelTest : public ::testing::Test {
426 protected:
427 WebSocketChannelTest()
428 : data_(), channel_(), stream_(new FakeWebSocketStream) {}
429
430 // Create a new WebSocketChannel and connect it, using the settings stored in
431 // data_.
432 void CreateChannelAndConnect() {
433 channel_.reset(new WebSocketChannel(data_.url, EventInterface()));
434 channel_->SendAddChannelRequestWithFactory(
435 data_.requested_subprotocols,
436 data_.origin,
437 &data_.url_request_context,
438 base::Bind(&ArgumentCopyingWebSocketFactory::Factory,
439 base::Unretained(&data_.factory)));
440 }
441
442 // Same as CreateChannelAndConnect(), but call the on_success callback as
443 // well. This method is virtual so that WebSocketChannelStreamTest can set the
444 // stream as well.
445 virtual void CreateChannelAndConnectSuccessfully() {
446 CreateChannelAndConnect();
447 data_.factory.connect_delegate->OnSuccess(stream_.Pass());
448 }
449
450 // Return a WebSocketEventInterface to be passed to the WebSocketChannel.
451 // This implementation returns a newly-created fake. Subclasses may return a
452 // mock instead.
453 virtual scoped_ptr<WebSocketEventInterface> EventInterface() {
454 return scoped_ptr<WebSocketEventInterface>(new FakeWebSocketEventInterface);
455 }
456
457 // Downcasting and moving a scoped_ptr in one operation doesn't seem to work
458 // (bug?). This function works around that and simplifies initialising stream_
459 // from a subclass.
460 template <class T>
461 void set_stream(scoped_ptr<T> stream) {
462 stream_.reset(stream.release());
463 }
464
465 // A struct containing the data that will be used to connect the channel.
466 struct ConnectData {
467 // URL to (pretend to) connect to.
468 GURL url;
469 // Origin of the request
470 GURL origin;
471 // Requested protocols for the request.
472 std::vector<std::string> requested_subprotocols;
473 // URLRequestContext object.
474 URLRequestContext url_request_context;
475 // A fake WebSocketFactory that just records its arguments.
476 ArgumentCopyingWebSocketFactory factory;
477 };
478 ConnectData data_;
479
480 // The channel we are testing. Not initialised until SetChannel() is called.
481 scoped_ptr<WebSocketChannel> channel_;
482
483 // A mock or fake stream for tests that need one.
484 scoped_ptr<WebSocketStream> stream_;
485 };
486
487 // Base class for tests which verify that EventInterface methods are called
488 // appropriately.
489 class WebSocketChannelEventInterfaceTest : public WebSocketChannelTest {
490 protected:
491 WebSocketChannelEventInterfaceTest()
492 : WebSocketChannelTest(),
493 event_interface_(new MockWebSocketEventInterface) {}
494
495 virtual scoped_ptr<WebSocketEventInterface> EventInterface() OVERRIDE {
496 return scoped_ptr<WebSocketEventInterface>(event_interface_.release());
497 }
498
499 scoped_ptr<MockWebSocketEventInterface> event_interface_;
500 };
501
502 // Base class for tests which verify that WebSocketStream methods are called
503 // appropriately by using a MockWebSocketStream.
504 class WebSocketChannelStreamTest : public WebSocketChannelTest {
505 protected:
506 WebSocketChannelStreamTest()
507 : WebSocketChannelTest(), mock_(new MockWebSocketStream) {}
508
509 virtual void CreateChannelAndConnectSuccessfully() OVERRIDE {
510 set_stream(mock_.Pass());
511 WebSocketChannelTest::CreateChannelAndConnectSuccessfully();
512 }
513
514 scoped_ptr<MockWebSocketStream> mock_;
515 };
516
517 // Simple test that everything that should be passed to the factory function is
518 // passed to the factory function.
519 TEST_F(WebSocketChannelTest, EverythingIsPassedToTheFactoryFunction) {
520 data_.url = GURL("ws://example.com/test");
521 data_.origin = GURL("http://example.com/test");
522 data_.requested_subprotocols.push_back("Sinbad");
523
524 CreateChannelAndConnect();
525
526 EXPECT_EQ(data_.url, data_.factory.socket_url);
527 EXPECT_EQ(data_.origin, data_.factory.origin);
528 EXPECT_EQ(data_.requested_subprotocols, data_.factory.requested_subprotocols);
529 EXPECT_EQ(&data_.url_request_context, data_.factory.url_request_context);
530 }
531
532 TEST_F(WebSocketChannelEventInterfaceTest, ConnectSuccessReported) {
533 // false means success.
534 EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, ""));
535 // OnFlowControl is always called immediately after connect to provide initial
536 // quota to the renderer.
537 EXPECT_CALL(*event_interface_, OnFlowControl(_));
538
539 CreateChannelAndConnect();
540
541 data_.factory.connect_delegate->OnSuccess(stream_.Pass());
542 }
543
544 TEST_F(WebSocketChannelEventInterfaceTest, ConnectFailureReported) {
545 // true means failure.
546 EXPECT_CALL(*event_interface_, OnAddChannelResponse(true, ""));
547
548 CreateChannelAndConnect();
549
550 data_.factory.connect_delegate->OnFailure(kWebSocketErrorNoStatusReceived);
551 }
552
553 TEST_F(WebSocketChannelEventInterfaceTest, ProtocolPassed) {
554 EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, "Bob"));
555 EXPECT_CALL(*event_interface_, OnFlowControl(_));
556
557 CreateChannelAndConnect();
558
559 data_.factory.connect_delegate->OnSuccess(
560 scoped_ptr<WebSocketStream>(new FakeWebSocketStream("Bob", "")));
561 }
562
563 // The first frames from the server can arrive together with the handshake, in
564 // which case they will be available as soon as ReadFrames() is called the first
565 // time.
566 TEST_F(WebSocketChannelEventInterfaceTest, DataLeftFromHandshake) {
567 scoped_ptr<ReadableFakeWebSocketStream> stream(
568 new ReadableFakeWebSocketStream);
569 static const InitFrameChunk chunks[] = {
570 {{FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, NOT_MASKED, 5},
571 FINAL_CHUNK, "HELLO"},
572 };
573 stream->PrepareReadFrames(ReadableFakeWebSocketStream::SYNC, OK, chunks);
574 set_stream(stream.Pass());
575 {
576 InSequence s;
577 EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _));
578 EXPECT_CALL(*event_interface_, OnFlowControl(_));
579 EXPECT_CALL(
580 *event_interface_,
581 OnDataFrame(
582 true, WebSocketFrameHeader::kOpCodeText, AsVector("HELLO")));
583 }
584
585 CreateChannelAndConnectSuccessfully();
586 }
587
588 // A remote server could accept the handshake, but then immediately send a
589 // close frame.
590 TEST_F(WebSocketChannelEventInterfaceTest, CloseAfterHandshake) {
591 scoped_ptr<ReadableFakeWebSocketStream> stream(
592 new ReadableFakeWebSocketStream);
593 static const InitFrameChunk chunks[] = {
594 {{FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose, NOT_MASKED, 23},
595 FINAL_CHUNK, "\x03\xf3Internal Server Error"},
596 };
597 stream->PrepareReadFrames(ReadableFakeWebSocketStream::SYNC, OK, chunks);
598 set_stream(stream.Pass());
599 {
600 InSequence s;
601 EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _));
602 EXPECT_CALL(*event_interface_, OnFlowControl(_));
603 EXPECT_CALL(*event_interface_,
604 OnDropChannel(kWebSocketErrorInternalServerError,
605 "Internal Server Error"));
606 }
607
608 CreateChannelAndConnectSuccessfully();
609 }
610
611 // A remote server could close the connection immediately after sending the
612 // handshake response (most likely a bug in the server).
613 TEST_F(WebSocketChannelEventInterfaceTest, ConnectionCloseAfterHandshake) {
614 scoped_ptr<ReadableFakeWebSocketStream> stream(
615 new ReadableFakeWebSocketStream);
616 stream->PrepareReadFramesError(ReadableFakeWebSocketStream::SYNC,
617 ERR_CONNECTION_CLOSED);
618 set_stream(stream.Pass());
619 {
620 InSequence s;
621 EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _));
622 EXPECT_CALL(*event_interface_, OnFlowControl(_));
623 EXPECT_CALL(
624 *event_interface_,
625 OnDropChannel(kWebSocketErrorAbnormalClosure, "Abnormal Closure"));
626 }
627
628 CreateChannelAndConnectSuccessfully();
629 }
630
631 TEST_F(WebSocketChannelEventInterfaceTest, NormalAsyncRead) {
632 scoped_ptr<ReadableFakeWebSocketStream> stream(
633 new ReadableFakeWebSocketStream);
634 static const InitFrameChunk chunks[] = {
635 {{FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, NOT_MASKED, 5},
636 FINAL_CHUNK, "HELLO"},
637 };
638 // We use this checkpoint object to verify that the callback isn't called
639 // until we expect it to be.
640 MockFunction<void(int)> checkpoint;
641 stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, chunks);
642 set_stream(stream.Pass());
643 {
644 InSequence s;
645 EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _));
646 EXPECT_CALL(*event_interface_, OnFlowControl(_));
647 EXPECT_CALL(checkpoint, Call(1));
648 EXPECT_CALL(
649 *event_interface_,
650 OnDataFrame(
651 true, WebSocketFrameHeader::kOpCodeText, AsVector("HELLO")));
652 EXPECT_CALL(checkpoint, Call(2));
653 }
654
655 CreateChannelAndConnectSuccessfully();
656 checkpoint.Call(1);
657 base::MessageLoop::current()->RunUntilIdle();
658 checkpoint.Call(2);
659 }
660
661 // Extra data can arrive while a read is being processed, resulting in the next
662 // read completing synchronously.
663 TEST_F(WebSocketChannelEventInterfaceTest, AsyncThenSyncRead) {
664 scoped_ptr<ReadableFakeWebSocketStream> stream(
665 new ReadableFakeWebSocketStream);
666 static const InitFrameChunk chunks1[] = {
667 {{FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, NOT_MASKED, 5},
668 FINAL_CHUNK, "HELLO"},
669 };
670 static const InitFrameChunk chunks2[] = {
671 {{FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, NOT_MASKED, 5},
672 FINAL_CHUNK, "WORLD"},
673 };
674 stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, chunks1);
675 stream->PrepareReadFrames(ReadableFakeWebSocketStream::SYNC, OK, chunks2);
676 set_stream(stream.Pass());
677 {
678 InSequence s;
679 EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _));
680 EXPECT_CALL(*event_interface_, OnFlowControl(_));
681 EXPECT_CALL(
682 *event_interface_,
683 OnDataFrame(
684 true, WebSocketFrameHeader::kOpCodeText, AsVector("HELLO")));
685 EXPECT_CALL(
686 *event_interface_,
687 OnDataFrame(
688 true, WebSocketFrameHeader::kOpCodeText, AsVector("WORLD")));
689 }
690
691 CreateChannelAndConnectSuccessfully();
692 base::MessageLoop::current()->RunUntilIdle();
693 }
694
695 // Data frames that arrive in fragments are turned into individual frames
696 TEST_F(WebSocketChannelEventInterfaceTest, FragmentedFrames) {
697 scoped_ptr<ReadableFakeWebSocketStream> stream(
698 new ReadableFakeWebSocketStream);
699 // Here we have one message split into 3 frames which arrive in 3 chunks. The
700 // first frame is entirely in the first chunk, the second frame is split
701 // across all the chunks, and the final frame is entirely in the final
702 // chunk. This should be delivered as 5 frames.
703 static const InitFrameChunk chunks1[] = {
704 {{NOT_FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, NOT_MASKED, 5},
705 FINAL_CHUNK, "THREE"},
706 {{NOT_FINAL_FRAME, WebSocketFrameHeader::kOpCodeContinuation, NOT_MASKED,
707 7},
708 NOT_FINAL_CHUNK, " "},
709 };
710 static const InitFrameChunk chunks2[] = {{{NO_HEADER}, NOT_FINAL_CHUNK,
711 "SMALL"}};
712 static const InitFrameChunk chunks3[] = {
713 {{NO_HEADER}, FINAL_CHUNK, " "},
714 {{FINAL_FRAME, WebSocketFrameHeader::kOpCodeContinuation, NOT_MASKED, 6},
715 FINAL_CHUNK, "FRAMES"},
716 };
717 stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, chunks1);
718 stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, chunks2);
719 stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, chunks3);
720 set_stream(stream.Pass());
721 {
722 InSequence s;
723 EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _));
724 EXPECT_CALL(*event_interface_, OnFlowControl(_));
725 EXPECT_CALL(
726 *event_interface_,
727 OnDataFrame(
728 false, WebSocketFrameHeader::kOpCodeText, AsVector("THREE")));
729 EXPECT_CALL(
730 *event_interface_,
731 OnDataFrame(
732 false, WebSocketFrameHeader::kOpCodeContinuation, AsVector(" ")));
733 EXPECT_CALL(*event_interface_,
734 OnDataFrame(false,
735 WebSocketFrameHeader::kOpCodeContinuation,
736 AsVector("SMALL")));
737 EXPECT_CALL(
738 *event_interface_,
739 OnDataFrame(
740 false, WebSocketFrameHeader::kOpCodeContinuation, AsVector(" ")));
741 EXPECT_CALL(*event_interface_,
742 OnDataFrame(true,
743 WebSocketFrameHeader::kOpCodeContinuation,
744 AsVector("FRAMES")));
745 }
746
747 CreateChannelAndConnectSuccessfully();
748 base::MessageLoop::current()->RunUntilIdle();
749 }
750
751 // In the case when a single-frame message because fragmented, it must be
752 // correctly transformed to multiple frames.
753 TEST_F(WebSocketChannelEventInterfaceTest, MessageFragmentation) {
754 scoped_ptr<ReadableFakeWebSocketStream> stream(
755 new ReadableFakeWebSocketStream);
756 // Here we have one message split into 3 frames which arrive in 3 chunks. The
757 // first frame is entirely in the first chunk, the second frame is split
758 // across all the chunks, and the final frame is entirely in the final
759 // chunk. This should be delivered as 5 frames.
760 static const InitFrameChunk chunks1[] = {
761 {{FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, NOT_MASKED, 12},
762 NOT_FINAL_CHUNK, "TIME"},
763 };
764 static const InitFrameChunk chunks2[] = {{{NO_HEADER}, NOT_FINAL_CHUNK,
765 " FOR "}};
766 static const InitFrameChunk chunks3[] = {{{NO_HEADER}, FINAL_CHUNK, "TEA"}};
767 stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, chunks1);
768 stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, chunks2);
769 stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, chunks3);
770 set_stream(stream.Pass());
771 {
772 InSequence s;
773 EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _));
774 EXPECT_CALL(*event_interface_, OnFlowControl(_));
775 EXPECT_CALL(
776 *event_interface_,
777 OnDataFrame(
778 false, WebSocketFrameHeader::kOpCodeText, AsVector("TIME")));
779 EXPECT_CALL(*event_interface_,
780 OnDataFrame(false,
781 WebSocketFrameHeader::kOpCodeContinuation,
782 AsVector(" FOR ")));
783 EXPECT_CALL(
784 *event_interface_,
785 OnDataFrame(
786 true, WebSocketFrameHeader::kOpCodeContinuation, AsVector("TEA")));
787 }
788
789 CreateChannelAndConnectSuccessfully();
790 base::MessageLoop::current()->RunUntilIdle();
791 }
792
793 // If a control message is fragmented, it must be re-assembled before being
794 // delivered. A control message can only be fragmented at the network level; it
795 // is not permitted to be split into multiple frames.
796 TEST_F(WebSocketChannelEventInterfaceTest, FragmentedControlMessage) {
797 scoped_ptr<ReadableFakeWebSocketStream> stream(
798 new ReadableFakeWebSocketStream);
799 static const InitFrameChunk chunks1[] = {
800 {{FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose, NOT_MASKED, 7},
801 NOT_FINAL_CHUNK, "\x03\xe8"},
802 };
803 static const InitFrameChunk chunks2[] = {{{NO_HEADER}, NOT_FINAL_CHUNK,
804 "Clo"}};
805 static const InitFrameChunk chunks3[] = {{{NO_HEADER}, FINAL_CHUNK, "se"}};
806 stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, chunks1);
807 stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, chunks2);
808 stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, chunks3);
809 set_stream(stream.Pass());
810 {
811 InSequence s;
812 EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _));
813 EXPECT_CALL(*event_interface_, OnFlowControl(_));
814 EXPECT_CALL(*event_interface_,
815 OnDropChannel(kWebSocketNormalClosure, "Close"));
816 }
817
818 CreateChannelAndConnectSuccessfully();
819 base::MessageLoop::current()->RunUntilIdle();
820 }
821
822 // Connection closed unexpectedly.
823 TEST_F(WebSocketChannelEventInterfaceTest, AsyncAbnormalClosure) {
824 scoped_ptr<ReadableFakeWebSocketStream> stream(
825 new ReadableFakeWebSocketStream);
826 stream->PrepareReadFramesError(ReadableFakeWebSocketStream::ASYNC,
827 ERR_CONNECTION_CLOSED);
828 set_stream(stream.Pass());
829 {
830 InSequence s;
831 EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _));
832 EXPECT_CALL(*event_interface_, OnFlowControl(_));
833 EXPECT_CALL(*event_interface_,
834 OnDropChannel(kWebSocketErrorAbnormalClosure, _));
835 }
836
837 CreateChannelAndConnectSuccessfully();
838 base::MessageLoop::current()->RunUntilIdle();
839 }
840
841 // Connection reset.
842 TEST_F(WebSocketChannelEventInterfaceTest, ConnectionReset) {
843 scoped_ptr<ReadableFakeWebSocketStream> stream(
844 new ReadableFakeWebSocketStream);
845 stream->PrepareReadFramesError(ReadableFakeWebSocketStream::ASYNC,
846 ERR_CONNECTION_RESET);
847 set_stream(stream.Pass());
848 {
849 InSequence s;
850 EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _));
851 EXPECT_CALL(*event_interface_, OnFlowControl(_));
852 EXPECT_CALL(*event_interface_,
853 OnDropChannel(kWebSocketErrorAbnormalClosure, _));
854 }
855
856 CreateChannelAndConnectSuccessfully();
857 base::MessageLoop::current()->RunUntilIdle();
858 }
859
860 // Connection closed in the middle of a Close message (server bug, etc.)
861 TEST_F(WebSocketChannelEventInterfaceTest, ConnectionClosedInMessage) {
862 scoped_ptr<ReadableFakeWebSocketStream> stream(
863 new ReadableFakeWebSocketStream);
864 static const InitFrameChunk chunks[] = {
865 {{FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose, NOT_MASKED, 7},
866 NOT_FINAL_CHUNK, "\x03\xe8"},
867 };
868
869 stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, chunks);
870 stream->PrepareReadFramesError(ReadableFakeWebSocketStream::ASYNC,
871 ERR_CONNECTION_CLOSED);
872 set_stream(stream.Pass());
873 {
874 InSequence s;
875 EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _));
876 EXPECT_CALL(*event_interface_, OnFlowControl(_));
877 EXPECT_CALL(*event_interface_,
878 OnDropChannel(kWebSocketErrorAbnormalClosure, _));
879 }
880
881 CreateChannelAndConnectSuccessfully();
882 base::MessageLoop::current()->RunUntilIdle();
883 }
884
885 // RFC6455 5.1 "A client MUST close a connection if it detects a masked frame."
886 TEST_F(WebSocketChannelEventInterfaceTest, MaskedFramesAreRejected) {
887 scoped_ptr<ReadableFakeWebSocketStream> stream(
888 new ReadableFakeWebSocketStream);
889 static const InitFrameChunk chunks[] = {
890 {{FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, MASKED, 5}, FINAL_CHUNK,
891 "HELLO"}
892 };
893
894 stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, chunks);
895 set_stream(stream.Pass());
896 {
897 InSequence s;
898 EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _));
899 EXPECT_CALL(*event_interface_, OnFlowControl(_));
900 EXPECT_CALL(*event_interface_,
901 OnDropChannel(kWebSocketErrorProtocolError, _));
902 }
903
904 CreateChannelAndConnectSuccessfully();
905 base::MessageLoop::current()->RunUntilIdle();
906 }
907
908 // RFC6455 5.2 "If an unknown opcode is received, the receiving endpoint MUST
909 // _Fail the WebSocket Connection_."
910 TEST_F(WebSocketChannelEventInterfaceTest, UnknownOpCodeIsRejected) {
911 scoped_ptr<ReadableFakeWebSocketStream> stream(
912 new ReadableFakeWebSocketStream);
913 static const InitFrameChunk chunks[] = {{{FINAL_FRAME, 4, NOT_MASKED, 5},
914 FINAL_CHUNK, "HELLO"}};
915
916 stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, chunks);
917 set_stream(stream.Pass());
918 {
919 InSequence s;
920 EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _));
921 EXPECT_CALL(*event_interface_, OnFlowControl(_));
922 EXPECT_CALL(*event_interface_,
923 OnDropChannel(kWebSocketErrorProtocolError, _));
924 }
925
926 CreateChannelAndConnectSuccessfully();
927 base::MessageLoop::current()->RunUntilIdle();
928 }
929
930 // RFC6455 5.4 "Control frames ... MAY be injected in the middle of a
931 // fragmented message."
932 TEST_F(WebSocketChannelEventInterfaceTest, ControlFrameInDataMessage) {
933 scoped_ptr<ReadableFakeWebSocketStream> stream(
934 new ReadableFakeWebSocketStream);
935 // We have one message of type Text split into two frames. In the middle is a
936 // control message of type Pong.
937 static const InitFrameChunk chunks1[] = {
938 {{NOT_FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, NOT_MASKED, 6},
939 FINAL_CHUNK, "SPLIT "},
940 };
941 static const InitFrameChunk chunks2[] = {
942 {{FINAL_FRAME, WebSocketFrameHeader::kOpCodePong, NOT_MASKED, 0},
943 FINAL_CHUNK, ""}
944 };
945 static const InitFrameChunk chunks3[] = {
946 {{FINAL_FRAME, WebSocketFrameHeader::kOpCodeContinuation, NOT_MASKED, 7},
947 FINAL_CHUNK, "MESSAGE"}
948 };
949 stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, chunks1);
950 stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, chunks2);
951 stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, chunks3);
952 set_stream(stream.Pass());
953 {
954 InSequence s;
955 EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _));
956 EXPECT_CALL(*event_interface_, OnFlowControl(_));
957 EXPECT_CALL(
958 *event_interface_,
959 OnDataFrame(
960 false, WebSocketFrameHeader::kOpCodeText, AsVector("SPLIT ")));
961 EXPECT_CALL(*event_interface_,
962 OnDataFrame(true,
963 WebSocketFrameHeader::kOpCodeContinuation,
964 AsVector("MESSAGE")));
965 }
966
967 CreateChannelAndConnectSuccessfully();
968 base::MessageLoop::current()->RunUntilIdle();
969 }
970
971 // If the renderer sends lots of small writes, we don't want to update the quota
972 // for each one.
973 TEST_F(WebSocketChannelEventInterfaceTest, SmallWriteDoesntUpdateQuota) {
974 set_stream(make_scoped_ptr(new WriteableFakeWebSocketStream));
975 {
976 InSequence s;
977 EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _));
978 EXPECT_CALL(*event_interface_, OnFlowControl(_));
979 }
980
981 CreateChannelAndConnectSuccessfully();
982 channel_->SendFrame(true, WebSocketFrameHeader::kOpCodeText, AsVector("B"));
983 }
984
985 // If we send enough to go below send_quota_low_water_mask_ we should get our
986 // quota refreshed.
987 TEST_F(WebSocketChannelEventInterfaceTest, LargeWriteUpdatesQuota) {
988 set_stream(make_scoped_ptr(new WriteableFakeWebSocketStream));
989 // We use this checkpoint object to verify that the quota update comes after
990 // the write.
991 MockFunction<void(int)> checkpoint;
992 {
993 InSequence s;
994 EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _));
995 EXPECT_CALL(*event_interface_, OnFlowControl(_));
996 EXPECT_CALL(checkpoint, Call(1));
997 EXPECT_CALL(*event_interface_, OnFlowControl(_));
998 EXPECT_CALL(checkpoint, Call(2));
999 }
1000
1001 CreateChannelAndConnectSuccessfully();
1002 checkpoint.Call(1);
1003 // TODO(ricea): If kDefaultSendQuotaHighWaterMark changes, then this value
1004 // will need to be updated.
1005 channel_->SendFrame(
1006 true, WebSocketFrameHeader::kOpCodeText, std::vector<char>(1 << 17, 'B'));
1007 checkpoint.Call(2);
1008 }
1009
1010 // Verify that our quota actually is refreshed when we are told it is.
1011 TEST_F(WebSocketChannelEventInterfaceTest, QuotaReallyIsRefreshed) {
1012 set_stream(make_scoped_ptr(new WriteableFakeWebSocketStream));
1013 MockFunction<void(int)> checkpoint;
1014 {
1015 InSequence s;
1016 EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _));
1017 EXPECT_CALL(*event_interface_, OnFlowControl(_));
1018 EXPECT_CALL(checkpoint, Call(1));
1019 EXPECT_CALL(*event_interface_, OnFlowControl(_));
1020 EXPECT_CALL(checkpoint, Call(2));
1021 // If quota was not really refreshed, we would get an OnDropChannel()
1022 // message.
1023 EXPECT_CALL(*event_interface_, OnFlowControl(_));
1024 EXPECT_CALL(checkpoint, Call(3));
1025 }
1026
1027 CreateChannelAndConnectSuccessfully();
1028 checkpoint.Call(1);
1029 // TODO(ricea): If kDefaultSendQuotaLowWaterMark and/or
1030 // kDefaultSendQuotaHighWaterMark change, then this value will need to be
1031 // updated.
1032 channel_->SendFrame(true,
1033 WebSocketFrameHeader::kOpCodeText,
1034 std::vector<char>((1 << 16) + 1, 'D'));
1035 checkpoint.Call(2);
1036 // We should have received more quota at this point.
1037 channel_->SendFrame(true,
1038 WebSocketFrameHeader::kOpCodeText,
1039 std::vector<char>((1 << 16) + 1, 'E'));
1040 checkpoint.Call(3);
1041 }
1042
1043 // If we send more than the available quota then the connection will be closed
1044 // with an error.
1045 TEST_F(WebSocketChannelEventInterfaceTest, WriteOverQuotaIsRejected) {
1046 set_stream(make_scoped_ptr(new WriteableFakeWebSocketStream));
1047 {
1048 InSequence s;
1049 EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _));
1050 // TODO(ricea): Change this if kDefaultSendQuotaHighWaterMark changes.
1051 EXPECT_CALL(*event_interface_, OnFlowControl(1 << 17));
1052 EXPECT_CALL(*event_interface_,
1053 OnDropChannel(kWebSocketMuxErrorSendQuotaViolation, _));
1054 }
1055
1056 CreateChannelAndConnectSuccessfully();
1057 channel_->SendFrame(true,
1058 WebSocketFrameHeader::kOpCodeText,
1059 std::vector<char>((1 << 17) + 1, 'C'));
1060 }
1061
1062 // If a write fails, the channel is dropped.
1063 TEST_F(WebSocketChannelEventInterfaceTest, FailedWrite) {
1064 set_stream(make_scoped_ptr(new UnWriteableFakeWebSocketStream));
1065 MockFunction<void(int)> checkpoint;
1066 {
1067 InSequence s;
1068 EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _));
1069 EXPECT_CALL(*event_interface_, OnFlowControl(_));
1070 EXPECT_CALL(checkpoint, Call(1));
1071 EXPECT_CALL(*event_interface_,
1072 OnDropChannel(kWebSocketErrorAbnormalClosure, _));
1073 EXPECT_CALL(checkpoint, Call(2));
1074 }
1075
1076 CreateChannelAndConnectSuccessfully();
1077 checkpoint.Call(1);
1078
1079 channel_->SendFrame(true, WebSocketFrameHeader::kOpCodeText, AsVector("H"));
1080 checkpoint.Call(2);
1081 }
1082
1083 // OnDropChannel() is called exactly once when SendDropChannel() is used.
1084 TEST_F(WebSocketChannelEventInterfaceTest, SendCloseDropsChannel) {
1085 set_stream(make_scoped_ptr(new EchoeyFakeWebSocketStream));
1086 {
1087 InSequence s;
1088 EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _));
1089 EXPECT_CALL(*event_interface_, OnFlowControl(_));
1090 EXPECT_CALL(*event_interface_,
1091 OnDropChannel(kWebSocketNormalClosure, "Fred"));
1092 }
1093
1094 CreateChannelAndConnectSuccessfully();
1095
1096 channel_->SendDropChannel(kWebSocketNormalClosure, "Fred");
1097 base::MessageLoop::current()->RunUntilIdle();
1098 }
1099
1100 // RGC6455 5.1 "a client MUST mask all frames that it sends to the server".
1101 // WebSocketChannel actually only sets the mask bit in the header, it doesn't
1102 // perform masking itself (not all transports actually use masking).
1103 TEST_F(WebSocketChannelStreamTest, SentFramesAreMasked) {
1104 EXPECT_CALL(*mock_, GetSubProtocol()).Times(AnyNumber());
1105 EXPECT_CALL(*mock_, ReadFrames(_, _)).WillOnce(Return(ERR_IO_PENDING));
1106 EXPECT_CALL(
1107 *mock_,
1108 WriteFrames(Pointee(ElementsAre(Pointee(Field(
1109 &WebSocketFrameChunk::header,
1110 Pointee(Field(&WebSocketFrameHeader::masked, true)))))),
1111 _)).WillOnce(Return(ERR_IO_PENDING));
1112
1113 CreateChannelAndConnectSuccessfully();
1114 channel_->SendFrame(
1115 true, WebSocketFrameHeader::kOpCodeText, AsVector("NEEDS MASKING"));
1116 }
1117
1118 } // namespace
1119 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698