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

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

Powered by Google App Engine
This is Rietveld 408576698