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

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

Powered by Google App Engine
This is Rietveld 408576698