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

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

Powered by Google App Engine
This is Rietveld 408576698