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

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

Powered by Google App Engine
This is Rietveld 408576698