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

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

Powered by Google App Engine
This is Rietveld 408576698