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

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

Powered by Google App Engine
This is Rietveld 408576698