19ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch// Copyright 2013 The Chromium Authors. All rights reserved.
29ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch// Use of this source code is governed by a BSD-style license that can be
39ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch// found in the LICENSE file.
49ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
59ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "net/websockets/websocket_channel.h"
69ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
7effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include <limits.h>
8558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch#include <string.h>
9558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
109ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include <iostream>
119ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include <string>
129ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include <vector>
139ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
149ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "base/bind.h"
159ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "base/bind_helpers.h"
169ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "base/callback.h"
17558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch#include "base/location.h"
189ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "base/memory/scoped_ptr.h"
199ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "base/memory/scoped_vector.h"
201e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "base/memory/weak_ptr.h"
219ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "base/message_loop/message_loop.h"
229ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "base/strings/string_piece.h"
239ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "net/base/net_errors.h"
241e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "net/base/test_completion_callback.h"
255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "net/http/http_response_headers.h"
269ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "net/url_request/url_request_context.h"
279ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "net/websockets/websocket_errors.h"
289ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "net/websockets/websocket_event_interface.h"
295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "net/websockets/websocket_handshake_request_info.h"
305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "net/websockets/websocket_handshake_response_info.h"
319ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "net/websockets/websocket_mux.h"
329ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "testing/gmock/include/gmock/gmock.h"
339ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "testing/gtest/include/gtest/gtest.h"
34ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include "url/gurl.h"
35a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "url/origin.h"
369ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
37558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch// Hacky macros to construct the body of a Close message from a code and a
38558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch// string, while ensuring the result is a compile-time constant string.
39558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch// Use like CLOSE_DATA(NORMAL_CLOSURE, "Explanation String")
40558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch#define CLOSE_DATA(code, string) WEBSOCKET_CLOSE_CODE_AS_STRING_##code string
41558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch#define WEBSOCKET_CLOSE_CODE_AS_STRING_NORMAL_CLOSURE "\x03\xe8"
42558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch#define WEBSOCKET_CLOSE_CODE_AS_STRING_GOING_AWAY "\x03\xe9"
434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#define WEBSOCKET_CLOSE_CODE_AS_STRING_PROTOCOL_ERROR "\x03\xea"
445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#define WEBSOCKET_CLOSE_CODE_AS_STRING_ABNORMAL_CLOSURE "\x03\xee"
45558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch#define WEBSOCKET_CLOSE_CODE_AS_STRING_SERVER_ERROR "\x03\xf3"
46558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
479ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdochnamespace net {
489ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// Printing helpers to allow GoogleMock to print frames. These are explicitly
504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// designed to look like the static initialisation format we use in these
514e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// tests. They have to live in the net namespace in order to be found by
529ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch// GoogleMock; a nested anonymous namespace will not work.
539ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
549ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdochstd::ostream& operator<<(std::ostream& os, const WebSocketFrameHeader& header) {
554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return os << (header.final ? "FINAL_FRAME" : "NOT_FINAL_FRAME") << ", "
569ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch            << header.opcode << ", "
574e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)            << (header.masked ? "MASKED" : "NOT_MASKED");
589ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch}
599ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)std::ostream& operator<<(std::ostream& os, const WebSocketFrame& frame) {
614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  os << "{" << frame.header << ", ";
621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (frame.data.get()) {
634e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return os << "\"" << base::StringPiece(frame.data->data(),
644e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                           frame.header.payload_length)
654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)              << "\"}";
669ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  }
674e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return os << "NULL}";
68558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch}
69558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
70558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdochstd::ostream& operator<<(std::ostream& os,
714e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                         const ScopedVector<WebSocketFrame>& vector) {
72558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  os << "{";
73558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  bool first = true;
744e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  for (ScopedVector<WebSocketFrame>::const_iterator it = vector.begin();
75558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch       it != vector.end();
76558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch       ++it) {
77558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    if (!first) {
78558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      os << ",\n";
79558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    } else {
80558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      first = false;
81558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    }
82558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    os << **it;
83558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  }
84558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  return os << "}";
85558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch}
86558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
87558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdochstd::ostream& operator<<(std::ostream& os,
884e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                         const ScopedVector<WebSocketFrame>* vector) {
89558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  return os << '&' << *vector;
909ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch}
919ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
929ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdochnamespace {
939ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
941e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)using ::base::TimeDelta;
951e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
969ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdochusing ::testing::AnyNumber;
971e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)using ::testing::DefaultValue;
989ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdochusing ::testing::InSequence;
999ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdochusing ::testing::MockFunction;
10046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)using ::testing::NotNull;
1019ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdochusing ::testing::Return;
102558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdochusing ::testing::SaveArg;
1039ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdochusing ::testing::StrictMock;
1049ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdochusing ::testing::_;
1059ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
106558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch// A selection of characters that have traditionally been mangled in some
107558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch// environment or other, for testing 8-bit cleanliness.
1084e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)const char kBinaryBlob[] = {'\n',   '\r',    // BACKWARDS CRNL
109558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch                            '\0',            // nul
110558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch                            '\x7F',          // DEL
111558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch                            '\x80', '\xFF',  // NOT VALID UTF-8
112558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch                            '\x1A',          // Control-Z, EOF on DOS
113558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch                            '\x03',          // Control-C
114558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch                            '\x04',          // EOT, special for Unix terms
115558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch                            '\x1B',          // ESC, often special
116558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch                            '\b',            // backspace
117558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch                            '\'',            // single-quote, special in PHP
118558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch};
119558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdochconst size_t kBinaryBlobSize = arraysize(kBinaryBlob);
120558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
121558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch// The amount of quota a new connection gets by default.
122558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch// TODO(ricea): If kDefaultSendQuotaHighWaterMark changes, then this value will
123558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch// need to be updated.
124558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdochconst size_t kDefaultInitialQuota = 1 << 17;
125558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch// The amount of bytes we need to send after the initial connection to trigger a
126558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch// quota refresh. TODO(ricea): Change this if kDefaultSendQuotaHighWaterMark or
127558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch// kDefaultSendQuotaLowWaterMark change.
128558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdochconst size_t kDefaultQuotaRefreshTrigger = (1 << 16) + 1;
129558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
1301e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// TestTimeouts::tiny_timeout() is 100ms! I could run halfway around the world
1311e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// in that time! I would like my tests to run a bit quicker.
1321e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)const int kVeryTinyTimeoutMillis = 1;
1331e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
134effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// Enough quota to pass any test.
135effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochconst int64 kPlentyOfQuota = INT_MAX;
136effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
1371e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)typedef WebSocketEventInterface::ChannelState ChannelState;
1381e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)const ChannelState CHANNEL_ALIVE = WebSocketEventInterface::CHANNEL_ALIVE;
1391e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)const ChannelState CHANNEL_DELETED = WebSocketEventInterface::CHANNEL_DELETED;
1401e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
1411e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// This typedef mainly exists to avoid having to repeat the "NOLINT" incantation
1421e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// all over the place.
143effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochtypedef StrictMock< MockFunction<void(int)> > Checkpoint;  // NOLINT
1441e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
1459ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch// This mock is for testing expectations about how the EventInterface is used.
1469ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdochclass MockWebSocketEventInterface : public WebSocketEventInterface {
1479ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch public:
1485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  MockWebSocketEventInterface() {}
1495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  MOCK_METHOD3(OnAddChannelResponse,
1515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)               ChannelState(bool,
1525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            const std::string&,
1535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            const std::string&));  // NOLINT
1549ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  MOCK_METHOD3(OnDataFrame,
1551e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)               ChannelState(bool,
1561e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                            WebSocketMessageType,
1571e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                            const std::vector<char>&));  // NOLINT
1585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  MOCK_METHOD1(OnFlowControl, ChannelState(int64));  // NOLINT
1591e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  MOCK_METHOD0(OnClosingHandshake, ChannelState(void));  // NOLINT
1605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  MOCK_METHOD1(OnFailChannel, ChannelState(const std::string&));  // NOLINT
1615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  MOCK_METHOD3(OnDropChannel,
1625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)               ChannelState(bool, uint16, const std::string&));  // NOLINT
1635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // We can't use GMock with scoped_ptr.
1655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ChannelState OnStartOpeningHandshake(
1665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      scoped_ptr<WebSocketHandshakeRequestInfo>) OVERRIDE {
1675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    OnStartOpeningHandshakeCalled();
1685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return CHANNEL_ALIVE;
1695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ChannelState OnFinishOpeningHandshake(
1715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      scoped_ptr<WebSocketHandshakeResponseInfo>) OVERRIDE {
1725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    OnFinishOpeningHandshakeCalled();
1735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return CHANNEL_ALIVE;
1745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
17546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  virtual ChannelState OnSSLCertificateError(
17646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      scoped_ptr<SSLErrorCallbacks> ssl_error_callbacks,
17746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      const GURL& url,
17846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      const SSLInfo& ssl_info,
17946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      bool fatal) OVERRIDE {
18046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    OnSSLCertificateErrorCalled(
18146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        ssl_error_callbacks.get(), url, ssl_info, fatal);
18246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    return CHANNEL_ALIVE;
18346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  }
1845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  MOCK_METHOD0(OnStartOpeningHandshakeCalled, void());  // NOLINT
1865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  MOCK_METHOD0(OnFinishOpeningHandshakeCalled, void());  // NOLINT
18746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  MOCK_METHOD4(
18846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      OnSSLCertificateErrorCalled,
18946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      void(SSLErrorCallbacks*, const GURL&, const SSLInfo&, bool));  // NOLINT
1909ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch};
1919ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
1929ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch// This fake EventInterface is for tests which need a WebSocketEventInterface
1939ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch// implementation but are not verifying how it is used.
1949ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdochclass FakeWebSocketEventInterface : public WebSocketEventInterface {
1951e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  virtual ChannelState OnAddChannelResponse(
1969ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch      bool fail,
1975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      const std::string& selected_protocol,
1985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      const std::string& extensions) OVERRIDE {
1991e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    return fail ? CHANNEL_DELETED : CHANNEL_ALIVE;
2001e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  }
2011e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  virtual ChannelState OnDataFrame(bool fin,
2021e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                                   WebSocketMessageType type,
2031e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                                   const std::vector<char>& data) OVERRIDE {
2041e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    return CHANNEL_ALIVE;
2051e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  }
2061e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  virtual ChannelState OnFlowControl(int64 quota) OVERRIDE {
2071e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    return CHANNEL_ALIVE;
2081e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  }
2091e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  virtual ChannelState OnClosingHandshake() OVERRIDE { return CHANNEL_ALIVE; }
2105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  virtual ChannelState OnFailChannel(const std::string& message) OVERRIDE {
2115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return CHANNEL_DELETED;
2125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  virtual ChannelState OnDropChannel(bool was_clean,
2145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                     uint16 code,
2151e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                                     const std::string& reason) OVERRIDE {
2161e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    return CHANNEL_DELETED;
2171e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  }
2185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  virtual ChannelState OnStartOpeningHandshake(
2195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      scoped_ptr<WebSocketHandshakeRequestInfo> request) OVERRIDE {
2205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return CHANNEL_ALIVE;
2215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  virtual ChannelState OnFinishOpeningHandshake(
2235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      scoped_ptr<WebSocketHandshakeResponseInfo> response) OVERRIDE {
2245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return CHANNEL_ALIVE;
2255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
22646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  virtual ChannelState OnSSLCertificateError(
22746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      scoped_ptr<SSLErrorCallbacks> ssl_error_callbacks,
22846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      const GURL& url,
22946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      const SSLInfo& ssl_info,
23046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      bool fatal) OVERRIDE {
23146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    return CHANNEL_ALIVE;
23246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  }
2339ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch};
2349ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
2359ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch// This fake WebSocketStream is for tests that require a WebSocketStream but are
2369ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch// not testing the way it is used. It has minimal functionality to return
2379ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch// the |protocol| and |extensions| that it was constructed with.
2389ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdochclass FakeWebSocketStream : public WebSocketStream {
2399ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch public:
2409ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  // Constructs with empty protocol and extensions.
2419ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  FakeWebSocketStream() {}
2429ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
2439ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  // Constructs with specified protocol and extensions.
2449ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  FakeWebSocketStream(const std::string& protocol,
2459ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch                      const std::string& extensions)
2469ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch      : protocol_(protocol), extensions_(extensions) {}
2479ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
2484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  virtual int ReadFrames(ScopedVector<WebSocketFrame>* frames,
2499ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch                         const CompletionCallback& callback) OVERRIDE {
2509ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    return ERR_IO_PENDING;
2519ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  }
2529ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
2534e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  virtual int WriteFrames(ScopedVector<WebSocketFrame>* frames,
2549ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch                          const CompletionCallback& callback) OVERRIDE {
2559ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    return ERR_IO_PENDING;
2569ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  }
2579ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
2589ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  virtual void Close() OVERRIDE {}
2599ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
2609ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  // Returns the string passed to the constructor.
2619ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  virtual std::string GetSubProtocol() const OVERRIDE { return protocol_; }
2629ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
2639ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  // Returns the string passed to the constructor.
2649ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  virtual std::string GetExtensions() const OVERRIDE { return extensions_; }
2659ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
2669ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch private:
2679ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  // The string to return from GetSubProtocol().
2689ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  std::string protocol_;
2699ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
2709ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  // The string to return from GetExtensions().
2719ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  std::string extensions_;
2729ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch};
2739ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
2749ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch// To make the static initialisers easier to read, we use enums rather than
2759ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch// bools.
2765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)enum IsFinal { NOT_FINAL_FRAME, FINAL_FRAME };
2779ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
2785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)enum IsMasked { NOT_MASKED, MASKED };
2799ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
2804e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// This is used to initialise a WebSocketFrame but is statically initialisable.
2814e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)struct InitFrame {
2824e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  IsFinal final;
2834e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Reserved fields omitted for now. Add them if you need them.
2844e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  WebSocketFrameHeader::OpCode opcode;
2854e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  IsMasked masked;
2869ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
2879ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  // Will be used to create the IOBuffer member. Can be NULL for NULL data. Is a
2884e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // nul-terminated string for ease-of-use. |header.payload_length| is
2894e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // initialised from |strlen(data)|. This means it is not 8-bit clean, but this
2904e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // is not an issue for test data.
2919ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  const char* const data;
2929ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch};
2939ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
294558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch// For GoogleMock
2954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)std::ostream& operator<<(std::ostream& os, const InitFrame& frame) {
2964e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  os << "{" << (frame.final == FINAL_FRAME ? "FINAL_FRAME" : "NOT_FINAL_FRAME")
2974e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)     << ", " << frame.opcode << ", "
2984e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)     << (frame.masked == MASKED ? "MASKED" : "NOT_MASKED") << ", ";
2994e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (frame.data) {
3004e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return os << "\"" << frame.data << "\"}";
301558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  }
3024e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return os << "NULL}";
303558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch}
304558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
305558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdochtemplate <size_t N>
3064e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)std::ostream& operator<<(std::ostream& os, const InitFrame (&frames)[N]) {
307558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  os << "{";
308558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  bool first = true;
309558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  for (size_t i = 0; i < N; ++i) {
310558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    if (!first) {
311558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      os << ",\n";
312558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    } else {
313558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      first = false;
314558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    }
3154e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    os << frames[i];
316558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  }
317558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  return os << "}";
318558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch}
319558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
3204e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// Convert a const array of InitFrame structs to the format used at
3219ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch// runtime. Templated on the size of the array to save typing.
3229ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdochtemplate <size_t N>
3234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)ScopedVector<WebSocketFrame> CreateFrameVector(
3244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    const InitFrame (&source_frames)[N]) {
3254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  ScopedVector<WebSocketFrame> result_frames;
3264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  result_frames.reserve(N);
3279ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  for (size_t i = 0; i < N; ++i) {
3284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    const InitFrame& source_frame = source_frames[i];
3294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    scoped_ptr<WebSocketFrame> result_frame(
3304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        new WebSocketFrame(source_frame.opcode));
3314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    size_t frame_length = source_frame.data ? strlen(source_frame.data) : 0;
3324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    WebSocketFrameHeader& result_header = result_frame->header;
3334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    result_header.final = (source_frame.final == FINAL_FRAME);
3344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    result_header.masked = (source_frame.masked == MASKED);
3354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    result_header.payload_length = frame_length;
3364e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    if (source_frame.data) {
3374e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      result_frame->data = new IOBuffer(frame_length);
3384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      memcpy(result_frame->data->data(), source_frame.data, frame_length);
3399ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    }
3404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    result_frames.push_back(result_frame.release());
3419ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  }
3424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return result_frames.Pass();
3439ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch}
3449ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
3459ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch// A GoogleMock action which can be used to respond to call to ReadFrames with
3464e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// some frames. Use like ReadFrames(_, _).WillOnce(ReturnFrames(&frames));
3474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// |frames| is an array of InitFrame. |frames| needs to be passed by pointer
3484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// because otherwise it will be treated as a pointer and the array size
3494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// information will be lost.
3504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)ACTION_P(ReturnFrames, source_frames) {
3514e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  *arg0 = CreateFrameVector(*source_frames);
3529ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  return OK;
3539ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch}
3549ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
355558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch// The implementation of a GoogleMock matcher which can be used to compare a
3564e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// ScopedVector<WebSocketFrame>* against an expectation defined as an array of
3574e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// InitFrame objects. Although it is possible to compose built-in GoogleMock
3584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// matchers to check the contents of a WebSocketFrame, the results are so
359558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch// unreadable that it is better to use this matcher.
360558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdochtemplate <size_t N>
3614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)class EqualsFramesMatcher
3624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    : public ::testing::MatcherInterface<ScopedVector<WebSocketFrame>*> {
363558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch public:
3644e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  EqualsFramesMatcher(const InitFrame (*expect_frames)[N])
3654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      : expect_frames_(expect_frames) {}
366558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
3674e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  virtual bool MatchAndExplain(ScopedVector<WebSocketFrame>* actual_frames,
368558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch                               ::testing::MatchResultListener* listener) const {
3694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    if (actual_frames->size() != N) {
3704e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      *listener << "the vector size is " << actual_frames->size();
371558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      return false;
372558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    }
373558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    for (size_t i = 0; i < N; ++i) {
3744e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      const WebSocketFrame& actual_frame = *(*actual_frames)[i];
3754e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      const InitFrame& expected_frame = (*expect_frames_)[i];
3764e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      if (actual_frame.header.final != (expected_frame.final == FINAL_FRAME)) {
3774e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        *listener << "the frame is marked as "
3784e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                  << (actual_frame.header.final ? "" : "not ") << "final";
379558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch        return false;
380558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      }
3814e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      if (actual_frame.header.opcode != expected_frame.opcode) {
3824e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        *listener << "the opcode is " << actual_frame.header.opcode;
3834e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        return false;
384558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      }
3854e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      if (actual_frame.header.masked != (expected_frame.masked == MASKED)) {
3864e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        *listener << "the frame is "
3874e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                  << (actual_frame.header.masked ? "masked" : "not masked");
388558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch        return false;
389558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      }
3904e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      const size_t expected_length =
3914e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          expected_frame.data ? strlen(expected_frame.data) : 0;
3924e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      if (actual_frame.header.payload_length != expected_length) {
3934e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        *listener << "the payload length is "
3944e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                  << actual_frame.header.payload_length;
395558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch        return false;
396558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      }
3974e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      if (expected_length != 0 &&
3984e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          memcmp(actual_frame.data->data(),
3994e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                 expected_frame.data,
4004e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                 actual_frame.header.payload_length) != 0) {
401558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch        *listener << "the data content differs";
402558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch        return false;
403558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      }
404558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    }
405558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    return true;
406558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  }
407558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
408558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  virtual void DescribeTo(std::ostream* os) const {
4094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    *os << "matches " << *expect_frames_;
410558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  }
411558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
412558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  virtual void DescribeNegationTo(std::ostream* os) const {
4134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    *os << "does not match " << *expect_frames_;
414558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  }
415558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
416558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch private:
4174e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  const InitFrame (*expect_frames_)[N];
418558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch};
419558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
4204e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// The definition of EqualsFrames GoogleMock matcher. Unlike the ReturnFrames
421558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch// action, this can take the array by reference.
422558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdochtemplate <size_t N>
4234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)::testing::Matcher<ScopedVector<WebSocketFrame>*> EqualsFrames(
4244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    const InitFrame (&frames)[N]) {
4254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return ::testing::MakeMatcher(new EqualsFramesMatcher<N>(&frames));
426558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch}
427558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
4281e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// TestClosure works like TestCompletionCallback, but doesn't take an argument.
4291e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)class TestClosure {
4301e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) public:
4311e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  base::Closure closure() { return base::Bind(callback_.callback(), OK); }
4321e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
4331e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  void WaitForResult() { callback_.WaitForResult(); }
4341e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
4351e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) private:
4361e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // Delegate to TestCompletionCallback for the implementation.
4371e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  TestCompletionCallback callback_;
4381e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)};
4391e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
4401e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// A GoogleMock action to run a Closure.
4411e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)ACTION_P(InvokeClosure, closure) { closure.Run(); }
4421e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
4431e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// A GoogleMock action to run a Closure and return CHANNEL_DELETED.
4441e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)ACTION_P(InvokeClosureReturnDeleted, closure) {
4451e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  closure.Run();
4461e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  return WebSocketEventInterface::CHANNEL_DELETED;
4471e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
4481e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
4499ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch// A FakeWebSocketStream whose ReadFrames() function returns data.
4509ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdochclass ReadableFakeWebSocketStream : public FakeWebSocketStream {
4519ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch public:
4525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  enum IsSync { SYNC, ASYNC };
4539ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
4549ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  // After constructing the object, call PrepareReadFrames() once for each
4559ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  // time you wish it to return from the test.
4569ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  ReadableFakeWebSocketStream() : index_(0), read_frames_pending_(false) {}
4579ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
4589ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  // Check that all the prepared responses have been consumed.
4599ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  virtual ~ReadableFakeWebSocketStream() {
4609ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    CHECK(index_ >= responses_.size());
4619ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    CHECK(!read_frames_pending_);
4629ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  }
4639ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
4644e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Prepares a fake response. Fake responses will be returned from ReadFrames()
4654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // in the same order they were prepared with PrepareReadFrames() and
4664e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // PrepareReadFramesError(). If |async| is ASYNC, then ReadFrames() will
4679ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  // return ERR_IO_PENDING and the callback will be scheduled to run on the
4689ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  // message loop. This requires the test case to run the message loop. If
4699ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  // |async| is SYNC, the response will be returned synchronously. |error| is
4709ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  // returned directly from ReadFrames() in the synchronous case, or passed to
4714e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // the callback in the asynchronous case. |frames| will be converted to a
4724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // ScopedVector<WebSocketFrame> and copied to the pointer that was passed to
4734e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // ReadFrames().
4749ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  template <size_t N>
4759ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  void PrepareReadFrames(IsSync async,
4769ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch                         int error,
4774e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                         const InitFrame (&frames)[N]) {
4784e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    responses_.push_back(new Response(async, error, CreateFrameVector(frames)));
4799ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  }
4809ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
481558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  // An alternate version of PrepareReadFrames for when we need to construct
482558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  // the frames manually.
483558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  void PrepareRawReadFrames(IsSync async,
484558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch                            int error,
4854e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                            ScopedVector<WebSocketFrame> frames) {
4864e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    responses_.push_back(new Response(async, error, frames.Pass()));
487558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  }
488558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
4899ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  // Prepares a fake error response (ie. there is no data).
4909ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  void PrepareReadFramesError(IsSync async, int error) {
4919ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    responses_.push_back(
4924e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        new Response(async, error, ScopedVector<WebSocketFrame>()));
4939ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  }
4949ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
4954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  virtual int ReadFrames(ScopedVector<WebSocketFrame>* frames,
4969ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch                         const CompletionCallback& callback) OVERRIDE {
4979ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    CHECK(!read_frames_pending_);
4989ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    if (index_ >= responses_.size())
4999ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch      return ERR_IO_PENDING;
5009ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    if (responses_[index_]->async == ASYNC) {
5019ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch      read_frames_pending_ = true;
5029ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch      base::MessageLoop::current()->PostTask(
5039ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch          FROM_HERE,
5049ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch          base::Bind(&ReadableFakeWebSocketStream::DoCallback,
5059ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch                     base::Unretained(this),
5064e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                     frames,
5079ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch                     callback));
5089ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch      return ERR_IO_PENDING;
5099ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    } else {
5104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      frames->swap(responses_[index_]->frames);
5119ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch      return responses_[index_++]->error;
5129ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    }
5139ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  }
5149ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
5159ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch private:
5164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  void DoCallback(ScopedVector<WebSocketFrame>* frames,
5179ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch                  const CompletionCallback& callback) {
5189ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    read_frames_pending_ = false;
5194e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    frames->swap(responses_[index_]->frames);
5209ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    callback.Run(responses_[index_++]->error);
5219ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    return;
5229ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  }
5239ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
5249ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  struct Response {
5254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    Response(IsSync async, int error, ScopedVector<WebSocketFrame> frames)
5264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        : async(async), error(error), frames(frames.Pass()) {}
5279ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
5289ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    IsSync async;
5299ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    int error;
5304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    ScopedVector<WebSocketFrame> frames;
5319ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
5329ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch   private:
5334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    // Bad things will happen if we attempt to copy or assign |frames|.
5349ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    DISALLOW_COPY_AND_ASSIGN(Response);
5359ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  };
5369ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  ScopedVector<Response> responses_;
5379ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
5389ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  // The index into the responses_ array of the next response to be returned.
5399ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  size_t index_;
5409ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
5419ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  // True when an async response from ReadFrames() is pending. This only applies
5429ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  // to "real" async responses. Once all the prepared responses have been
5439ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  // returned, ReadFrames() returns ERR_IO_PENDING but read_frames_pending_ is
5449ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  // not set to true.
5459ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  bool read_frames_pending_;
5469ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch};
5479ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
5489ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch// A FakeWebSocketStream where writes always complete successfully and
5499ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch// synchronously.
5509ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdochclass WriteableFakeWebSocketStream : public FakeWebSocketStream {
5519ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch public:
5524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  virtual int WriteFrames(ScopedVector<WebSocketFrame>* frames,
5539ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch                          const CompletionCallback& callback) OVERRIDE {
5549ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    return OK;
5559ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  }
5569ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch};
5579ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
5589ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch// A FakeWebSocketStream where writes always fail.
5599ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdochclass UnWriteableFakeWebSocketStream : public FakeWebSocketStream {
5609ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch public:
5614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  virtual int WriteFrames(ScopedVector<WebSocketFrame>* frames,
5629ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch                          const CompletionCallback& callback) OVERRIDE {
5639ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    return ERR_CONNECTION_RESET;
5649ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  }
5659ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch};
5669ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
5679ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch// A FakeWebSocketStream which echoes any frames written back. Clears the
5689ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch// "masked" header bit, but makes no other checks for validity. Tests using this
5699ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch// must run the MessageLoop to receive the callback(s). If a message with opcode
5709ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch// Close is echoed, then an ERR_CONNECTION_CLOSED is returned in the next
5719ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch// callback. The test must do something to cause WriteFrames() to be called,
5729ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch// otherwise the ReadFrames() callback will never be called.
5739ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdochclass EchoeyFakeWebSocketStream : public FakeWebSocketStream {
5749ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch public:
5754e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  EchoeyFakeWebSocketStream() : read_frames_(NULL), done_(false) {}
5769ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
5774e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  virtual int WriteFrames(ScopedVector<WebSocketFrame>* frames,
5789ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch                          const CompletionCallback& callback) OVERRIDE {
5799ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    // Users of WebSocketStream will not expect the ReadFrames() callback to be
5809ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    // called from within WriteFrames(), so post it to the message loop instead.
5814e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    stored_frames_.insert(stored_frames_.end(), frames->begin(), frames->end());
5824e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    frames->weak_clear();
5839ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    PostCallback();
5849ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    return OK;
5859ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  }
5869ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
5874e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  virtual int ReadFrames(ScopedVector<WebSocketFrame>* frames,
5889ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch                         const CompletionCallback& callback) OVERRIDE {
5899ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    read_callback_ = callback;
5904e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    read_frames_ = frames;
5919ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    if (done_)
5929ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch      PostCallback();
5939ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    return ERR_IO_PENDING;
5949ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  }
5959ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
5969ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch private:
5979ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  void PostCallback() {
5989ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    base::MessageLoop::current()->PostTask(
5999ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch        FROM_HERE,
6009ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch        base::Bind(&EchoeyFakeWebSocketStream::DoCallback,
6019ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch                   base::Unretained(this)));
6029ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  }
6039ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
6049ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  void DoCallback() {
6059ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    if (done_) {
6069ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch      read_callback_.Run(ERR_CONNECTION_CLOSED);
6074e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    } else if (!stored_frames_.empty()) {
6084e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      done_ = MoveFrames(read_frames_);
6094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      read_frames_ = NULL;
6109ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch      read_callback_.Run(OK);
6119ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    }
6129ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  }
6139ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
6144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Copy the frames stored in stored_frames_ to |out|, while clearing the
6159ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  // "masked" header bit. Returns true if a Close Frame was seen, false
6169ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  // otherwise.
6174e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  bool MoveFrames(ScopedVector<WebSocketFrame>* out) {
6189ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    bool seen_close = false;
6194e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    *out = stored_frames_.Pass();
6204e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    for (ScopedVector<WebSocketFrame>::iterator it = out->begin();
6219ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch         it != out->end();
6229ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch         ++it) {
6234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      WebSocketFrameHeader& header = (*it)->header;
6244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      header.masked = false;
6254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      if (header.opcode == WebSocketFrameHeader::kOpCodeClose)
6264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        seen_close = true;
6279ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    }
6289ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    return seen_close;
6299ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  }
6309ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
6314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  ScopedVector<WebSocketFrame> stored_frames_;
6329ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  CompletionCallback read_callback_;
6339ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  // Owned by the caller of ReadFrames().
6344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  ScopedVector<WebSocketFrame>* read_frames_;
6359ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  // True if we should close the connection.
6369ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  bool done_;
6379ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch};
6389ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
639558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch// A FakeWebSocketStream where writes trigger a connection reset.
640558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch// This differs from UnWriteableFakeWebSocketStream in that it is asynchronous
641558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch// and triggers ReadFrames to return a reset as well. Tests using this need to
6421e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// run the message loop. There are two tricky parts here:
6431e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// 1. Calling the write callback may call Close(), after which the read callback
6441e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)//    should not be called.
6451e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// 2. Calling either callback may delete the stream altogether.
646558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdochclass ResetOnWriteFakeWebSocketStream : public FakeWebSocketStream {
647558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch public:
6481e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  ResetOnWriteFakeWebSocketStream() : closed_(false), weak_ptr_factory_(this) {}
6491e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
6504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  virtual int WriteFrames(ScopedVector<WebSocketFrame>* frames,
651558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch                          const CompletionCallback& callback) OVERRIDE {
652558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    base::MessageLoop::current()->PostTask(
6531e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        FROM_HERE,
6541e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        base::Bind(&ResetOnWriteFakeWebSocketStream::CallCallbackUnlessClosed,
6551e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                   weak_ptr_factory_.GetWeakPtr(),
6561e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                   callback,
6571e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                   ERR_CONNECTION_RESET));
658558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    base::MessageLoop::current()->PostTask(
6591e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        FROM_HERE,
6601e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        base::Bind(&ResetOnWriteFakeWebSocketStream::CallCallbackUnlessClosed,
6611e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                   weak_ptr_factory_.GetWeakPtr(),
6621e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                   read_callback_,
6631e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                   ERR_CONNECTION_RESET));
664558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    return ERR_IO_PENDING;
665558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  }
666558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
6674e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  virtual int ReadFrames(ScopedVector<WebSocketFrame>* frames,
668558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch                         const CompletionCallback& callback) OVERRIDE {
669558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    read_callback_ = callback;
670558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    return ERR_IO_PENDING;
671558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  }
672558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
6731e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  virtual void Close() OVERRIDE { closed_ = true; }
6741e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
675558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch private:
6761e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  void CallCallbackUnlessClosed(const CompletionCallback& callback, int value) {
6771e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    if (!closed_)
6781e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      callback.Run(value);
6791e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  }
6801e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
681558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  CompletionCallback read_callback_;
6821e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  bool closed_;
6831e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // An IO error can result in the socket being deleted, so we use weak pointers
6841e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // to ensure correct behaviour in that case.
6851e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  base::WeakPtrFactory<ResetOnWriteFakeWebSocketStream> weak_ptr_factory_;
686558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch};
687558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
6889ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch// This mock is for verifying that WebSocket protocol semantics are obeyed (to
6899ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch// the extent that they are implemented in WebSocketCommon).
6909ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdochclass MockWebSocketStream : public WebSocketStream {
6919ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch public:
6929ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  MOCK_METHOD2(ReadFrames,
6934e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)               int(ScopedVector<WebSocketFrame>* frames,
6949ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch                   const CompletionCallback& callback));
6959ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  MOCK_METHOD2(WriteFrames,
6964e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)               int(ScopedVector<WebSocketFrame>* frames,
6979ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch                   const CompletionCallback& callback));
6989ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  MOCK_METHOD0(Close, void());
6999ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  MOCK_CONST_METHOD0(GetSubProtocol, std::string());
7009ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  MOCK_CONST_METHOD0(GetExtensions, std::string());
7019ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  MOCK_METHOD0(AsWebSocketStream, WebSocketStream*());
7029ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch};
7039ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
704f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)struct ArgumentCopyingWebSocketStreamCreator {
705f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  scoped_ptr<WebSocketStreamRequest> Create(
7069ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch      const GURL& socket_url,
7079ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch      const std::vector<std::string>& requested_subprotocols,
708a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      const url::Origin& origin,
7099ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch      URLRequestContext* url_request_context,
7109ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch      const BoundNetLog& net_log,
7119ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch      scoped_ptr<WebSocketStream::ConnectDelegate> connect_delegate) {
7129ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    this->socket_url = socket_url;
7139ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    this->requested_subprotocols = requested_subprotocols;
7149ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    this->origin = origin;
7159ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    this->url_request_context = url_request_context;
7169ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    this->net_log = net_log;
7179ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    this->connect_delegate = connect_delegate.Pass();
7189ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    return make_scoped_ptr(new WebSocketStreamRequest);
7199ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  }
7209ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
7219ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  GURL socket_url;
722a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  url::Origin origin;
7239ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  std::vector<std::string> requested_subprotocols;
7249ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  URLRequestContext* url_request_context;
7259ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  BoundNetLog net_log;
7269ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  scoped_ptr<WebSocketStream::ConnectDelegate> connect_delegate;
7279ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch};
7289ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
7299ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch// Converts a std::string to a std::vector<char>. For test purposes, it is
7309ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch// convenient to be able to specify data as a string, but the
7319ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch// WebSocketEventInterface requires the vector<char> type.
7329ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdochstd::vector<char> AsVector(const std::string& s) {
7339ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  return std::vector<char>(s.begin(), s.end());
7349ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch}
7359ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
73646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)class FakeSSLErrorCallbacks
73746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    : public WebSocketEventInterface::SSLErrorCallbacks {
73846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) public:
73946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  virtual void CancelSSLRequest(int error, const SSLInfo* ssl_info) OVERRIDE {}
74046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  virtual void ContinueSSLRequest() OVERRIDE {}
74146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)};
74246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
7439ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch// Base class for all test fixtures.
7449ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdochclass WebSocketChannelTest : public ::testing::Test {
7459ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch protected:
7469ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  WebSocketChannelTest() : stream_(new FakeWebSocketStream) {}
7479ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
7489ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  // Creates a new WebSocketChannel and connects it, using the settings stored
7499ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  // in |connect_data_|.
7509ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  void CreateChannelAndConnect() {
7514e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    channel_.reset(new WebSocketChannel(CreateEventInterface(),
7524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                        &connect_data_.url_request_context));
7539ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    channel_->SendAddChannelRequestForTesting(
7548bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)        connect_data_.socket_url,
7559ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch        connect_data_.requested_subprotocols,
7569ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch        connect_data_.origin,
757f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        base::Bind(&ArgumentCopyingWebSocketStreamCreator::Create,
758f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                   base::Unretained(&connect_data_.creator)));
7599ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  }
7609ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
7619ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  // Same as CreateChannelAndConnect(), but calls the on_success callback as
7629ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  // well. This method is virtual so that subclasses can also set the stream.
7639ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  virtual void CreateChannelAndConnectSuccessfully() {
7649ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    CreateChannelAndConnect();
765effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    // Most tests aren't concerned with flow control from the renderer, so allow
766effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    // MAX_INT quota units.
767effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    channel_->SendFlowControl(kPlentyOfQuota);
768f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    connect_data_.creator.connect_delegate->OnSuccess(stream_.Pass());
7699ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  }
7709ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
7719ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  // Returns a WebSocketEventInterface to be passed to the WebSocketChannel.
7729ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  // This implementation returns a newly-created fake. Subclasses may return a
7739ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  // mock instead.
7749ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  virtual scoped_ptr<WebSocketEventInterface> CreateEventInterface() {
7759ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    return scoped_ptr<WebSocketEventInterface>(new FakeWebSocketEventInterface);
7769ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  }
7779ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
7789ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  // This method serves no other purpose than to provide a nice syntax for
7799ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  // assigning to stream_. class T must be a subclass of WebSocketStream or you
7809ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  // will have unpleasant compile errors.
7819ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  template <class T>
7829ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  void set_stream(scoped_ptr<T> stream) {
7839ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    // Since the definition of "PassAs" depends on the type T, the C++ standard
7849ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    // requires the "template" keyword to indicate that "PassAs" should be
7859ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    // parsed as a template method.
7869ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    stream_ = stream.template PassAs<WebSocketStream>();
7879ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  }
7889ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
7899ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  // A struct containing the data that will be used to connect the channel.
7908bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // Grouped for readability.
7919ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  struct ConnectData {
792a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    ConnectData() : socket_url("ws://ws/"), origin("http://ws") {}
793f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
7948bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    // URLRequestContext object.
7958bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    URLRequestContext url_request_context;
7968bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
7979ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    // URL to (pretend to) connect to.
7988bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    GURL socket_url;
7999ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    // Requested protocols for the request.
8009ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    std::vector<std::string> requested_subprotocols;
8018bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    // Origin of the request
802a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    url::Origin origin;
8038bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
804f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // A fake WebSocketStreamCreator that just records its arguments.
805f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    ArgumentCopyingWebSocketStreamCreator creator;
8069ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  };
8079ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  ConnectData connect_data_;
8089ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
8099ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  // The channel we are testing. Not initialised until SetChannel() is called.
8109ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  scoped_ptr<WebSocketChannel> channel_;
8119ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
8129ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  // A mock or fake stream for tests that need one.
8139ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  scoped_ptr<WebSocketStream> stream_;
8149ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch};
8159ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
8161e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// enum of WebSocketEventInterface calls. These are intended to be or'd together
8171e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// in order to instruct WebSocketChannelDeletingTest when it should fail.
8181e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)enum EventInterfaceCall {
8191e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  EVENT_ON_ADD_CHANNEL_RESPONSE = 0x1,
8201e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  EVENT_ON_DATA_FRAME = 0x2,
8211e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  EVENT_ON_FLOW_CONTROL = 0x4,
8221e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  EVENT_ON_CLOSING_HANDSHAKE = 0x8,
8235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EVENT_ON_FAIL_CHANNEL = 0x10,
8245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EVENT_ON_DROP_CHANNEL = 0x20,
8255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EVENT_ON_START_OPENING_HANDSHAKE = 0x40,
8265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EVENT_ON_FINISH_OPENING_HANDSHAKE = 0x80,
82746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  EVENT_ON_SSL_CERTIFICATE_ERROR = 0x100,
8281e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)};
8291e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
830558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdochclass WebSocketChannelDeletingTest : public WebSocketChannelTest {
831558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch public:
8321e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  ChannelState DeleteIfDeleting(EventInterfaceCall call) {
8331e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    if (deleting_ & call) {
8341e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      channel_.reset();
8351e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      return CHANNEL_DELETED;
8361e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    } else {
8371e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      return CHANNEL_ALIVE;
8381e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    }
8391e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  }
840558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
841558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch protected:
8421e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  WebSocketChannelDeletingTest()
8431e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      : deleting_(EVENT_ON_ADD_CHANNEL_RESPONSE | EVENT_ON_DATA_FRAME |
8441e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                  EVENT_ON_FLOW_CONTROL |
8451e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                  EVENT_ON_CLOSING_HANDSHAKE |
8465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                  EVENT_ON_FAIL_CHANNEL |
8475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                  EVENT_ON_DROP_CHANNEL |
8485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                  EVENT_ON_START_OPENING_HANDSHAKE |
84946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                  EVENT_ON_FINISH_OPENING_HANDSHAKE |
85046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                  EVENT_ON_SSL_CERTIFICATE_ERROR) {}
851558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  // Create a ChannelDeletingFakeWebSocketEventInterface. Defined out-of-line to
852558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  // avoid circular dependency.
853558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  virtual scoped_ptr<WebSocketEventInterface> CreateEventInterface() OVERRIDE;
8541e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
8551e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // Tests can set deleting_ to a bitmap of EventInterfaceCall members that they
8561e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // want to cause Channel deletion. The default is for all calls to cause
8571e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // deletion.
8581e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  int deleting_;
859558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch};
860558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
861558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch// A FakeWebSocketEventInterface that deletes the WebSocketChannel on failure to
862558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch// connect.
863558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdochclass ChannelDeletingFakeWebSocketEventInterface
864558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    : public FakeWebSocketEventInterface {
865558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch public:
866558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  ChannelDeletingFakeWebSocketEventInterface(
867558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      WebSocketChannelDeletingTest* fixture)
868558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      : fixture_(fixture) {}
869558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
8701e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  virtual ChannelState OnAddChannelResponse(
871558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      bool fail,
8725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      const std::string& selected_protocol,
8735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      const std::string& extensions) OVERRIDE {
8741e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    return fixture_->DeleteIfDeleting(EVENT_ON_ADD_CHANNEL_RESPONSE);
8751e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  }
8761e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
8771e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  virtual ChannelState OnDataFrame(bool fin,
8781e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                                   WebSocketMessageType type,
8791e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                                   const std::vector<char>& data) OVERRIDE {
8801e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    return fixture_->DeleteIfDeleting(EVENT_ON_DATA_FRAME);
8811e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  }
8821e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
8831e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  virtual ChannelState OnFlowControl(int64 quota) OVERRIDE {
8841e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    return fixture_->DeleteIfDeleting(EVENT_ON_FLOW_CONTROL);
8851e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  }
8861e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
8871e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  virtual ChannelState OnClosingHandshake() OVERRIDE {
8881e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    return fixture_->DeleteIfDeleting(EVENT_ON_CLOSING_HANDSHAKE);
8891e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  }
8901e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
8915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  virtual ChannelState OnFailChannel(const std::string& message) OVERRIDE {
8925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return fixture_->DeleteIfDeleting(EVENT_ON_FAIL_CHANNEL);
8935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
8945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
8955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  virtual ChannelState OnDropChannel(bool was_clean,
8965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                     uint16 code,
8971e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                                     const std::string& reason) OVERRIDE {
8981e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    return fixture_->DeleteIfDeleting(EVENT_ON_DROP_CHANNEL);
899558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  }
900558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
9015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  virtual ChannelState OnStartOpeningHandshake(
9025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      scoped_ptr<WebSocketHandshakeRequestInfo> request) OVERRIDE {
9035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return fixture_->DeleteIfDeleting(EVENT_ON_START_OPENING_HANDSHAKE);
9045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
9055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  virtual ChannelState OnFinishOpeningHandshake(
9065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      scoped_ptr<WebSocketHandshakeResponseInfo> response) OVERRIDE {
9075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return fixture_->DeleteIfDeleting(EVENT_ON_FINISH_OPENING_HANDSHAKE);
9085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
90946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  virtual ChannelState OnSSLCertificateError(
91046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      scoped_ptr<SSLErrorCallbacks> ssl_error_callbacks,
91146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      const GURL& url,
91246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      const SSLInfo& ssl_info,
91346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      bool fatal) OVERRIDE {
91446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    return fixture_->DeleteIfDeleting(EVENT_ON_SSL_CERTIFICATE_ERROR);
91546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  }
9165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
917558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch private:
918558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  // A pointer to the test fixture. Owned by the test harness; this object will
919558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  // be deleted before it is.
920558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  WebSocketChannelDeletingTest* fixture_;
921558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch};
922558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
923558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdochscoped_ptr<WebSocketEventInterface>
924558790d6acca3451cf3a6b497803a5f07d0bec58Ben MurdochWebSocketChannelDeletingTest::CreateEventInterface() {
925558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  return scoped_ptr<WebSocketEventInterface>(
926558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      new ChannelDeletingFakeWebSocketEventInterface(this));
927558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch}
928558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
9299ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch// Base class for tests which verify that EventInterface methods are called
9309ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch// appropriately.
9319ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdochclass WebSocketChannelEventInterfaceTest : public WebSocketChannelTest {
9329ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch protected:
9339ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  WebSocketChannelEventInterfaceTest()
9341e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      : event_interface_(new StrictMock<MockWebSocketEventInterface>) {
9351e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    DefaultValue<ChannelState>::Set(CHANNEL_ALIVE);
9365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ON_CALL(*event_interface_, OnAddChannelResponse(true, _, _))
9375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        .WillByDefault(Return(CHANNEL_DELETED));
9385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ON_CALL(*event_interface_, OnDropChannel(_, _, _))
9391e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        .WillByDefault(Return(CHANNEL_DELETED));
9405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ON_CALL(*event_interface_, OnFailChannel(_))
9411e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        .WillByDefault(Return(CHANNEL_DELETED));
9421e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  }
9431e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
9441e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  virtual ~WebSocketChannelEventInterfaceTest() {
9451e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    DefaultValue<ChannelState>::Clear();
9461e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  }
9479ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
9489ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  // Tests using this fixture must set expectations on the event_interface_ mock
9499ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  // object before calling CreateChannelAndConnect() or
9509ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  // CreateChannelAndConnectSuccessfully(). This will only work once per test
9519ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  // case, but once should be enough.
9529ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  virtual scoped_ptr<WebSocketEventInterface> CreateEventInterface() OVERRIDE {
9539ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    return scoped_ptr<WebSocketEventInterface>(event_interface_.release());
9549ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  }
9559ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
9569ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  scoped_ptr<MockWebSocketEventInterface> event_interface_;
9579ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch};
9589ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
9599ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch// Base class for tests which verify that WebSocketStream methods are called
9609ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch// appropriately by using a MockWebSocketStream.
9619ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdochclass WebSocketChannelStreamTest : public WebSocketChannelTest {
9629ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch protected:
9639ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  WebSocketChannelStreamTest()
9649ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch      : mock_stream_(new StrictMock<MockWebSocketStream>) {}
9659ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
9669ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  virtual void CreateChannelAndConnectSuccessfully() OVERRIDE {
9679ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    set_stream(mock_stream_.Pass());
9689ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    WebSocketChannelTest::CreateChannelAndConnectSuccessfully();
9699ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  }
9709ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
9719ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  scoped_ptr<MockWebSocketStream> mock_stream_;
9729ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch};
9739ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
9745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Fixture for tests which test UTF-8 validation of sent Text frames via the
9755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// EventInterface.
9765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)class WebSocketChannelSendUtf8Test
9775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    : public WebSocketChannelEventInterfaceTest {
9785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) public:
9795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  virtual void SetUp() {
9805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    set_stream(make_scoped_ptr(new WriteableFakeWebSocketStream));
9815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // For the purpose of the tests using this fixture, it doesn't matter
9825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // whether these methods are called or not.
9835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _, _))
9845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        .Times(AnyNumber());
9855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    EXPECT_CALL(*event_interface_, OnFlowControl(_))
9865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        .Times(AnyNumber());
9875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
9885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)};
9895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
990effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// Fixture for tests which test use of receive quota from the renderer.
991effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochclass WebSocketChannelFlowControlTest
992effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    : public WebSocketChannelEventInterfaceTest {
993effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch protected:
994effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // Tests using this fixture should use CreateChannelAndConnectWithQuota()
995effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // instead of CreateChannelAndConnectSuccessfully().
996effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  void CreateChannelAndConnectWithQuota(int64 quota) {
997effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    CreateChannelAndConnect();
998effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    channel_->SendFlowControl(quota);
999effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    connect_data_.creator.connect_delegate->OnSuccess(stream_.Pass());
1000effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
1001effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
1002effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  virtual void CreateChannelAndConnectSuccesfully() { NOTREACHED(); }
1003effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch};
1004effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
10055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Fixture for tests which test UTF-8 validation of received Text frames using a
10065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// mock WebSocketStream.
10075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)class WebSocketChannelReceiveUtf8Test : public WebSocketChannelStreamTest {
10085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) public:
10095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  virtual void SetUp() {
10105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // For the purpose of the tests using this fixture, it doesn't matter
10115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // whether these methods are called or not.
10125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    EXPECT_CALL(*mock_stream_, GetSubProtocol()).Times(AnyNumber());
10135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    EXPECT_CALL(*mock_stream_, GetExtensions()).Times(AnyNumber());
10145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
10155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)};
10165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1017f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// Simple test that everything that should be passed to the creator function is
1018f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// passed to the creator function.
1019f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)TEST_F(WebSocketChannelTest, EverythingIsPassedToTheCreatorFunction) {
10208bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  connect_data_.socket_url = GURL("ws://example.com/test");
1021a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  connect_data_.origin = url::Origin("http://example.com");
10229ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  connect_data_.requested_subprotocols.push_back("Sinbad");
10239ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
10249ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  CreateChannelAndConnect();
10259ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
1026f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  const ArgumentCopyingWebSocketStreamCreator& actual = connect_data_.creator;
10278bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
10288bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  EXPECT_EQ(&connect_data_.url_request_context, actual.url_request_context);
10298bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
10308bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  EXPECT_EQ(connect_data_.socket_url, actual.socket_url);
10319ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  EXPECT_EQ(connect_data_.requested_subprotocols,
10328bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)            actual.requested_subprotocols);
1033a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  EXPECT_EQ(connect_data_.origin.string(), actual.origin.string());
10349ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch}
10359ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
10365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Verify that calling SendFlowControl before the connection is established does
10375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// not cause a crash.
10385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketChannelTest, SendFlowControlDuringHandshakeOkay) {
10395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CreateChannelAndConnect();
10405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ASSERT_TRUE(channel_);
10415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  channel_->SendFlowControl(65536);
10425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
10435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
10441e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// Any WebSocketEventInterface methods can delete the WebSocketChannel and
10451e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// return CHANNEL_DELETED. The WebSocketChannelDeletingTests are intended to
10461e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// verify that there are no use-after-free bugs when this happens. Problems will
10471e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// probably only be found when running under Address Sanitizer or a similar
10481e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// tool.
10491e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)TEST_F(WebSocketChannelDeletingTest, OnAddChannelResponseFail) {
1050558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  CreateChannelAndConnect();
10511e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  EXPECT_TRUE(channel_);
10525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  connect_data_.creator.connect_delegate->OnFailure("bye");
1053558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  EXPECT_EQ(NULL, channel_.get());
1054558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch}
1055558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
10561e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// Deletion is possible (due to IPC failure) even if the connect succeeds.
10571e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)TEST_F(WebSocketChannelDeletingTest, OnAddChannelResponseSuccess) {
10581e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  CreateChannelAndConnectSuccessfully();
10591e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  EXPECT_EQ(NULL, channel_.get());
10601e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
10611e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
10621e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)TEST_F(WebSocketChannelDeletingTest, OnDataFrameSync) {
10631e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  scoped_ptr<ReadableFakeWebSocketStream> stream(
10641e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      new ReadableFakeWebSocketStream);
10651e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  static const InitFrame frames[] = {
10661e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, NOT_MASKED, "HELLO"}};
10671e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  stream->PrepareReadFrames(ReadableFakeWebSocketStream::SYNC, OK, frames);
10681e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  set_stream(stream.Pass());
10691e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  deleting_ = EVENT_ON_DATA_FRAME;
10701e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
10711e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  CreateChannelAndConnectSuccessfully();
10721e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  EXPECT_EQ(NULL, channel_.get());
10731e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
10741e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
10751e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)TEST_F(WebSocketChannelDeletingTest, OnDataFrameAsync) {
10761e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  scoped_ptr<ReadableFakeWebSocketStream> stream(
10771e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      new ReadableFakeWebSocketStream);
10781e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  static const InitFrame frames[] = {
10791e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, NOT_MASKED, "HELLO"}};
10801e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, frames);
10811e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  set_stream(stream.Pass());
10821e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  deleting_ = EVENT_ON_DATA_FRAME;
10831e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
10841e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  CreateChannelAndConnectSuccessfully();
10851e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  EXPECT_TRUE(channel_);
10861e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  base::MessageLoop::current()->RunUntilIdle();
10871e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  EXPECT_EQ(NULL, channel_.get());
10881e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
10891e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
10901e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)TEST_F(WebSocketChannelDeletingTest, OnFlowControlAfterConnect) {
10911e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  deleting_ = EVENT_ON_FLOW_CONTROL;
10921e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
10931e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  CreateChannelAndConnectSuccessfully();
10941e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  EXPECT_EQ(NULL, channel_.get());
10951e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
10961e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
10971e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)TEST_F(WebSocketChannelDeletingTest, OnFlowControlAfterSend) {
10981e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  set_stream(make_scoped_ptr(new WriteableFakeWebSocketStream));
10991e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // Avoid deleting the channel yet.
11005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  deleting_ = EVENT_ON_FAIL_CHANNEL | EVENT_ON_DROP_CHANNEL;
11011e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  CreateChannelAndConnectSuccessfully();
11021e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  ASSERT_TRUE(channel_);
11031e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  deleting_ = EVENT_ON_FLOW_CONTROL;
11041e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  channel_->SendFrame(true,
11051e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                      WebSocketFrameHeader::kOpCodeText,
11061e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                      std::vector<char>(kDefaultInitialQuota, 'B'));
11071e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  EXPECT_EQ(NULL, channel_.get());
11081e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
11091e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
11101e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)TEST_F(WebSocketChannelDeletingTest, OnClosingHandshakeSync) {
11111e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  scoped_ptr<ReadableFakeWebSocketStream> stream(
11121e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      new ReadableFakeWebSocketStream);
11131e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  static const InitFrame frames[] = {
11141e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose,
11151e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)       NOT_MASKED,  CLOSE_DATA(NORMAL_CLOSURE, "Success")}};
11161e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  stream->PrepareReadFrames(ReadableFakeWebSocketStream::SYNC, OK, frames);
11171e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  set_stream(stream.Pass());
11181e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  deleting_ = EVENT_ON_CLOSING_HANDSHAKE;
11191e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  CreateChannelAndConnectSuccessfully();
11201e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  EXPECT_EQ(NULL, channel_.get());
11211e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
11221e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
11231e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)TEST_F(WebSocketChannelDeletingTest, OnClosingHandshakeAsync) {
11241e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  scoped_ptr<ReadableFakeWebSocketStream> stream(
11251e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      new ReadableFakeWebSocketStream);
11261e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  static const InitFrame frames[] = {
11271e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose,
11281e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)       NOT_MASKED,  CLOSE_DATA(NORMAL_CLOSURE, "Success")}};
11291e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, frames);
11301e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  set_stream(stream.Pass());
11311e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  deleting_ = EVENT_ON_CLOSING_HANDSHAKE;
11321e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  CreateChannelAndConnectSuccessfully();
11331e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  ASSERT_TRUE(channel_);
11341e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  base::MessageLoop::current()->RunUntilIdle();
11351e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  EXPECT_EQ(NULL, channel_.get());
11361e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
11371e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
11381e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)TEST_F(WebSocketChannelDeletingTest, OnDropChannelWriteError) {
11391e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  set_stream(make_scoped_ptr(new UnWriteableFakeWebSocketStream));
11401e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  deleting_ = EVENT_ON_DROP_CHANNEL;
11411e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  CreateChannelAndConnectSuccessfully();
11421e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  ASSERT_TRUE(channel_);
11431e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  channel_->SendFrame(
11441e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      true, WebSocketFrameHeader::kOpCodeText, AsVector("this will fail"));
11451e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  EXPECT_EQ(NULL, channel_.get());
11461e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
11471e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
11481e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)TEST_F(WebSocketChannelDeletingTest, OnDropChannelReadError) {
11491e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  scoped_ptr<ReadableFakeWebSocketStream> stream(
11501e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      new ReadableFakeWebSocketStream);
11511e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  stream->PrepareReadFramesError(ReadableFakeWebSocketStream::ASYNC,
11521e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                                 ERR_FAILED);
11531e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  set_stream(stream.Pass());
11541e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  deleting_ = EVENT_ON_DROP_CHANNEL;
11551e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  CreateChannelAndConnectSuccessfully();
11561e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  ASSERT_TRUE(channel_);
11571e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  base::MessageLoop::current()->RunUntilIdle();
11581e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  EXPECT_EQ(NULL, channel_.get());
11591e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
11601e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
11615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketChannelDeletingTest, OnNotifyStartOpeningHandshakeError) {
11625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_ptr<ReadableFakeWebSocketStream> stream(
11635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      new ReadableFakeWebSocketStream);
11645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  static const InitFrame frames[] = {
11655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, NOT_MASKED, "HELLO"}};
11665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, frames);
11675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  set_stream(stream.Pass());
11685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  deleting_ = EVENT_ON_START_OPENING_HANDSHAKE;
11695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
11705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CreateChannelAndConnectSuccessfully();
11715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ASSERT_TRUE(channel_);
11725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  channel_->OnStartOpeningHandshake(scoped_ptr<WebSocketHandshakeRequestInfo>(
11735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      new WebSocketHandshakeRequestInfo(GURL("http://www.example.com/"),
11745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                        base::Time())));
11755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::MessageLoop::current()->RunUntilIdle();
11765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(NULL, channel_.get());
11775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
11785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
11795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketChannelDeletingTest, OnNotifyFinishOpeningHandshakeError) {
11805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_ptr<ReadableFakeWebSocketStream> stream(
11815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      new ReadableFakeWebSocketStream);
11825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  static const InitFrame frames[] = {
11835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, NOT_MASKED, "HELLO"}};
11845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, frames);
11855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  set_stream(stream.Pass());
11865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  deleting_ = EVENT_ON_FINISH_OPENING_HANDSHAKE;
11875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
11885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CreateChannelAndConnectSuccessfully();
11895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ASSERT_TRUE(channel_);
11905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_refptr<HttpResponseHeaders> response_headers(
11915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      new HttpResponseHeaders(""));
11925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  channel_->OnFinishOpeningHandshake(scoped_ptr<WebSocketHandshakeResponseInfo>(
11935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      new WebSocketHandshakeResponseInfo(GURL("http://www.example.com/"),
11945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                         200,
11955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                         "OK",
11965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                         response_headers,
11975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                         base::Time())));
11985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::MessageLoop::current()->RunUntilIdle();
11995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(NULL, channel_.get());
12005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
12015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
12021e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)TEST_F(WebSocketChannelDeletingTest, FailChannelInSendFrame) {
12031e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  set_stream(make_scoped_ptr(new WriteableFakeWebSocketStream));
12045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  deleting_ = EVENT_ON_FAIL_CHANNEL;
12051e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  CreateChannelAndConnectSuccessfully();
12061e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  ASSERT_TRUE(channel_);
12071e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  channel_->SendFrame(true,
12081e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                      WebSocketFrameHeader::kOpCodeText,
12091e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                      std::vector<char>(kDefaultInitialQuota * 2, 'T'));
12101e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  EXPECT_EQ(NULL, channel_.get());
12111e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
12121e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
12131e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)TEST_F(WebSocketChannelDeletingTest, FailChannelInOnReadDone) {
12141e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  scoped_ptr<ReadableFakeWebSocketStream> stream(
12151e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      new ReadableFakeWebSocketStream);
12161e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  stream->PrepareReadFramesError(ReadableFakeWebSocketStream::ASYNC,
12171e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                                 ERR_WS_PROTOCOL_ERROR);
12181e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  set_stream(stream.Pass());
12195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  deleting_ = EVENT_ON_FAIL_CHANNEL;
12201e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  CreateChannelAndConnectSuccessfully();
12211e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  ASSERT_TRUE(channel_);
12221e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  base::MessageLoop::current()->RunUntilIdle();
12231e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  EXPECT_EQ(NULL, channel_.get());
12241e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
12251e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
12261e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)TEST_F(WebSocketChannelDeletingTest, FailChannelDueToMaskedFrame) {
12271e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  scoped_ptr<ReadableFakeWebSocketStream> stream(
12281e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      new ReadableFakeWebSocketStream);
12291e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  static const InitFrame frames[] = {
12301e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, MASKED, "HELLO"}};
12311e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  stream->PrepareReadFrames(ReadableFakeWebSocketStream::SYNC, OK, frames);
12321e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  set_stream(stream.Pass());
12335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  deleting_ = EVENT_ON_FAIL_CHANNEL;
12341e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
12351e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  CreateChannelAndConnectSuccessfully();
12361e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  EXPECT_EQ(NULL, channel_.get());
12371e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
12381e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
12391e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)TEST_F(WebSocketChannelDeletingTest, FailChannelDueToBadControlFrame) {
12401e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  scoped_ptr<ReadableFakeWebSocketStream> stream(
12411e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      new ReadableFakeWebSocketStream);
12421e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  static const InitFrame frames[] = {
1243a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      {FINAL_FRAME, 0xF, NOT_MASKED, ""}};
12441e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  stream->PrepareReadFrames(ReadableFakeWebSocketStream::SYNC, OK, frames);
12451e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  set_stream(stream.Pass());
12465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  deleting_ = EVENT_ON_FAIL_CHANNEL;
12471e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
12481e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  CreateChannelAndConnectSuccessfully();
12491e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  EXPECT_EQ(NULL, channel_.get());
12501e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
12511e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
1252f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// Version of above test with NULL data.
1253f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)TEST_F(WebSocketChannelDeletingTest, FailChannelDueToBadControlFrameNull) {
1254f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  scoped_ptr<ReadableFakeWebSocketStream> stream(
1255f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      new ReadableFakeWebSocketStream);
1256f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  static const InitFrame frames[] = {
1257a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      {FINAL_FRAME, 0xF, NOT_MASKED, NULL}};
1258f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  stream->PrepareReadFrames(ReadableFakeWebSocketStream::SYNC, OK, frames);
1259f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  set_stream(stream.Pass());
12605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  deleting_ = EVENT_ON_FAIL_CHANNEL;
1261f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
1262f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  CreateChannelAndConnectSuccessfully();
1263f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  EXPECT_EQ(NULL, channel_.get());
1264f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
1265f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
12661e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)TEST_F(WebSocketChannelDeletingTest, FailChannelDueToPongAfterClose) {
12671e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  scoped_ptr<ReadableFakeWebSocketStream> stream(
12681e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      new ReadableFakeWebSocketStream);
12691e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  static const InitFrame frames[] = {
12705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose, NOT_MASKED,
12715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       CLOSE_DATA(NORMAL_CLOSURE, "Success")},
12725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      {FINAL_FRAME, WebSocketFrameHeader::kOpCodePong, NOT_MASKED, ""}};
12731e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  stream->PrepareReadFrames(ReadableFakeWebSocketStream::SYNC, OK, frames);
12741e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  set_stream(stream.Pass());
12755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  deleting_ = EVENT_ON_FAIL_CHANNEL;
12761e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
12771e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  CreateChannelAndConnectSuccessfully();
12781e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  EXPECT_EQ(NULL, channel_.get());
12791e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
12801e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
1281f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)TEST_F(WebSocketChannelDeletingTest, FailChannelDueToPongAfterCloseNull) {
1282f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  scoped_ptr<ReadableFakeWebSocketStream> stream(
1283f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      new ReadableFakeWebSocketStream);
1284f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  static const InitFrame frames[] = {
12855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose, NOT_MASKED,
12865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       CLOSE_DATA(NORMAL_CLOSURE, "Success")},
12875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      {FINAL_FRAME, WebSocketFrameHeader::kOpCodePong, NOT_MASKED, NULL}};
1288f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  stream->PrepareReadFrames(ReadableFakeWebSocketStream::SYNC, OK, frames);
1289f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  set_stream(stream.Pass());
12905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  deleting_ = EVENT_ON_FAIL_CHANNEL;
1291f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
1292f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  CreateChannelAndConnectSuccessfully();
1293f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  EXPECT_EQ(NULL, channel_.get());
1294f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
1295f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
12961e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)TEST_F(WebSocketChannelDeletingTest, FailChannelDueToUnknownOpCode) {
12971e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  scoped_ptr<ReadableFakeWebSocketStream> stream(
12981e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      new ReadableFakeWebSocketStream);
12991e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  static const InitFrame frames[] = {{FINAL_FRAME, 0x7, NOT_MASKED, ""}};
13001e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  stream->PrepareReadFrames(ReadableFakeWebSocketStream::SYNC, OK, frames);
13011e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  set_stream(stream.Pass());
13025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  deleting_ = EVENT_ON_FAIL_CHANNEL;
13031e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
13041e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  CreateChannelAndConnectSuccessfully();
13051e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  EXPECT_EQ(NULL, channel_.get());
13061e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
13071e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
1308f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)TEST_F(WebSocketChannelDeletingTest, FailChannelDueToUnknownOpCodeNull) {
1309f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  scoped_ptr<ReadableFakeWebSocketStream> stream(
1310f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      new ReadableFakeWebSocketStream);
1311f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  static const InitFrame frames[] = {{FINAL_FRAME, 0x7, NOT_MASKED, NULL}};
1312f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  stream->PrepareReadFrames(ReadableFakeWebSocketStream::SYNC, OK, frames);
1313f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  set_stream(stream.Pass());
13145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  deleting_ = EVENT_ON_FAIL_CHANNEL;
13155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
13165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CreateChannelAndConnectSuccessfully();
13175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(NULL, channel_.get());
13185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
13195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
13205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketChannelDeletingTest, FailChannelDueInvalidCloseReason) {
13215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_ptr<ReadableFakeWebSocketStream> stream(
13225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      new ReadableFakeWebSocketStream);
13235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  static const InitFrame frames[] = {
13245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose,
13255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       NOT_MASKED,  CLOSE_DATA(NORMAL_CLOSURE, "\xFF")}};
13265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  stream->PrepareReadFrames(ReadableFakeWebSocketStream::SYNC, OK, frames);
13275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  set_stream(stream.Pass());
13285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  deleting_ = EVENT_ON_FAIL_CHANNEL;
1329f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
1330f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  CreateChannelAndConnectSuccessfully();
1331f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  EXPECT_EQ(NULL, channel_.get());
1332f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
1333f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
13349ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben MurdochTEST_F(WebSocketChannelEventInterfaceTest, ConnectSuccessReported) {
13359ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  // false means success.
13365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, "", ""));
13379ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  // OnFlowControl is always called immediately after connect to provide initial
13389ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  // quota to the renderer.
13399ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  EXPECT_CALL(*event_interface_, OnFlowControl(_));
13409ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
13419ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  CreateChannelAndConnect();
13429ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
1343f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  connect_data_.creator.connect_delegate->OnSuccess(stream_.Pass());
13449ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch}
13459ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
13469ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben MurdochTEST_F(WebSocketChannelEventInterfaceTest, ConnectFailureReported) {
13475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_CALL(*event_interface_, OnFailChannel("hello"));
13489ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
13499ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  CreateChannelAndConnect();
13509ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
13515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  connect_data_.creator.connect_delegate->OnFailure("hello");
13529ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch}
13539ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
1354f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)TEST_F(WebSocketChannelEventInterfaceTest, NonWebSocketSchemeRejected) {
13555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_CALL(*event_interface_, OnAddChannelResponse(true, "", ""));
1356f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  connect_data_.socket_url = GURL("http://www.google.com/");
1357f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  CreateChannelAndConnect();
1358f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
1359f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
13609ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben MurdochTEST_F(WebSocketChannelEventInterfaceTest, ProtocolPassed) {
13615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, "Bob", ""));
13629ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  EXPECT_CALL(*event_interface_, OnFlowControl(_));
13639ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
13649ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  CreateChannelAndConnect();
13659ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
1366f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  connect_data_.creator.connect_delegate->OnSuccess(
13679ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch      scoped_ptr<WebSocketStream>(new FakeWebSocketStream("Bob", "")));
13689ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch}
13699ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
13705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketChannelEventInterfaceTest, ExtensionsPassed) {
13715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_CALL(*event_interface_,
13725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              OnAddChannelResponse(false, "", "extension1, extension2"));
13735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_CALL(*event_interface_, OnFlowControl(_));
13745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
13755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CreateChannelAndConnect();
13765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
13775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  connect_data_.creator.connect_delegate->OnSuccess(scoped_ptr<WebSocketStream>(
13785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      new FakeWebSocketStream("", "extension1, extension2")));
13795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
13805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
13819ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch// The first frames from the server can arrive together with the handshake, in
13829ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch// which case they will be available as soon as ReadFrames() is called the first
13839ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch// time.
13849ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben MurdochTEST_F(WebSocketChannelEventInterfaceTest, DataLeftFromHandshake) {
13859ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  scoped_ptr<ReadableFakeWebSocketStream> stream(
13869ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch      new ReadableFakeWebSocketStream);
13874e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  static const InitFrame frames[] = {
13884e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, NOT_MASKED, "HELLO"}};
13894e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  stream->PrepareReadFrames(ReadableFakeWebSocketStream::SYNC, OK, frames);
13909ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  set_stream(stream.Pass());
13919ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  {
13929ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    InSequence s;
13935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _, _));
13949ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    EXPECT_CALL(*event_interface_, OnFlowControl(_));
13959ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    EXPECT_CALL(
13969ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch        *event_interface_,
13979ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch        OnDataFrame(
13989ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch            true, WebSocketFrameHeader::kOpCodeText, AsVector("HELLO")));
13999ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  }
14009ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
14019ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  CreateChannelAndConnectSuccessfully();
14029ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch}
14039ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
14049ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch// A remote server could accept the handshake, but then immediately send a
14059ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch// Close frame.
14069ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben MurdochTEST_F(WebSocketChannelEventInterfaceTest, CloseAfterHandshake) {
14079ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  scoped_ptr<ReadableFakeWebSocketStream> stream(
14089ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch      new ReadableFakeWebSocketStream);
14094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  static const InitFrame frames[] = {
14104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose,
14114e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)       NOT_MASKED,  CLOSE_DATA(SERVER_ERROR, "Internal Server Error")}};
14124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  stream->PrepareReadFrames(ReadableFakeWebSocketStream::SYNC, OK, frames);
14139ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  stream->PrepareReadFramesError(ReadableFakeWebSocketStream::SYNC,
14149ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch                                 ERR_CONNECTION_CLOSED);
14159ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  set_stream(stream.Pass());
14169ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  {
14179ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    InSequence s;
14185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _, _));
14199ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    EXPECT_CALL(*event_interface_, OnFlowControl(_));
14209ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    EXPECT_CALL(*event_interface_, OnClosingHandshake());
14215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    EXPECT_CALL(
14225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        *event_interface_,
14235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        OnDropChannel(
14245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            true, kWebSocketErrorInternalServerError, "Internal Server Error"));
14259ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  }
14269ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
14279ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  CreateChannelAndConnectSuccessfully();
14289ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch}
14299ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
14309ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch// A remote server could close the connection immediately after sending the
14319ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch// handshake response (most likely a bug in the server).
14329ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben MurdochTEST_F(WebSocketChannelEventInterfaceTest, ConnectionCloseAfterHandshake) {
14339ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  scoped_ptr<ReadableFakeWebSocketStream> stream(
14349ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch      new ReadableFakeWebSocketStream);
14359ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  stream->PrepareReadFramesError(ReadableFakeWebSocketStream::SYNC,
14369ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch                                 ERR_CONNECTION_CLOSED);
14379ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  set_stream(stream.Pass());
14389ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  {
14399ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    InSequence s;
14405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _, _));
14419ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    EXPECT_CALL(*event_interface_, OnFlowControl(_));
14429ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    EXPECT_CALL(*event_interface_,
14435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                OnDropChannel(false, kWebSocketErrorAbnormalClosure, _));
14449ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  }
14459ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
14469ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  CreateChannelAndConnectSuccessfully();
14479ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch}
14489ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
14499ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben MurdochTEST_F(WebSocketChannelEventInterfaceTest, NormalAsyncRead) {
14509ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  scoped_ptr<ReadableFakeWebSocketStream> stream(
14519ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch      new ReadableFakeWebSocketStream);
14524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  static const InitFrame frames[] = {
14534e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, NOT_MASKED, "HELLO"}};
14549ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  // We use this checkpoint object to verify that the callback isn't called
14559ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  // until we expect it to be.
14561e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  Checkpoint checkpoint;
14574e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, frames);
14589ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  set_stream(stream.Pass());
14599ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  {
14609ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    InSequence s;
14615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _, _));
14629ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    EXPECT_CALL(*event_interface_, OnFlowControl(_));
14639ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    EXPECT_CALL(checkpoint, Call(1));
14649ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    EXPECT_CALL(
14659ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch        *event_interface_,
14669ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch        OnDataFrame(
14679ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch            true, WebSocketFrameHeader::kOpCodeText, AsVector("HELLO")));
14689ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    EXPECT_CALL(checkpoint, Call(2));
14699ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  }
14709ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
14719ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  CreateChannelAndConnectSuccessfully();
14729ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  checkpoint.Call(1);
14739ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  base::MessageLoop::current()->RunUntilIdle();
14749ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  checkpoint.Call(2);
14759ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch}
14769ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
14779ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch// Extra data can arrive while a read is being processed, resulting in the next
14789ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch// read completing synchronously.
14799ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben MurdochTEST_F(WebSocketChannelEventInterfaceTest, AsyncThenSyncRead) {
14809ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  scoped_ptr<ReadableFakeWebSocketStream> stream(
14819ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch      new ReadableFakeWebSocketStream);
14824e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  static const InitFrame frames1[] = {
14834e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, NOT_MASKED, "HELLO"}};
14844e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  static const InitFrame frames2[] = {
14854e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, NOT_MASKED, "WORLD"}};
14864e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, frames1);
14874e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  stream->PrepareReadFrames(ReadableFakeWebSocketStream::SYNC, OK, frames2);
14889ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  set_stream(stream.Pass());
14899ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  {
14909ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    InSequence s;
14915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _, _));
14929ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    EXPECT_CALL(*event_interface_, OnFlowControl(_));
14939ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    EXPECT_CALL(
14949ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch        *event_interface_,
14959ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch        OnDataFrame(
14969ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch            true, WebSocketFrameHeader::kOpCodeText, AsVector("HELLO")));
14979ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    EXPECT_CALL(
14989ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch        *event_interface_,
14999ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch        OnDataFrame(
15009ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch            true, WebSocketFrameHeader::kOpCodeText, AsVector("WORLD")));
15019ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  }
15029ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
15039ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  CreateChannelAndConnectSuccessfully();
15049ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  base::MessageLoop::current()->RunUntilIdle();
15059ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch}
15069ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
15074e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// Data frames are delivered the same regardless of how many reads they arrive
15084e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// as.
15094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)TEST_F(WebSocketChannelEventInterfaceTest, FragmentedMessage) {
15109ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  scoped_ptr<ReadableFakeWebSocketStream> stream(
15119ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch      new ReadableFakeWebSocketStream);
15124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Here we have one message which arrived in five frames split across three
15134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // reads. It may have been reframed on arrival, but this class doesn't care
15144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // about that.
15154e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  static const InitFrame frames1[] = {
15164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      {NOT_FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, NOT_MASKED, "THREE"},
15174e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      {NOT_FINAL_FRAME, WebSocketFrameHeader::kOpCodeContinuation,
15184e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)       NOT_MASKED,      " "}};
15194e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  static const InitFrame frames2[] = {
15204e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      {NOT_FINAL_FRAME, WebSocketFrameHeader::kOpCodeContinuation,
15214e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)       NOT_MASKED,      "SMALL"}};
15224e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  static const InitFrame frames3[] = {
15234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      {NOT_FINAL_FRAME, WebSocketFrameHeader::kOpCodeContinuation,
15244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)       NOT_MASKED,      " "},
15254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeContinuation,
15264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)       NOT_MASKED,  "FRAMES"}};
15274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, frames1);
15284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, frames2);
15294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, frames3);
15309ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  set_stream(stream.Pass());
15319ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  {
15329ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    InSequence s;
15335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _, _));
15349ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    EXPECT_CALL(*event_interface_, OnFlowControl(_));
15359ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    EXPECT_CALL(
15369ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch        *event_interface_,
15379ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch        OnDataFrame(
15389ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch            false, WebSocketFrameHeader::kOpCodeText, AsVector("THREE")));
15399ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    EXPECT_CALL(
15409ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch        *event_interface_,
15419ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch        OnDataFrame(
15429ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch            false, WebSocketFrameHeader::kOpCodeContinuation, AsVector(" ")));
15439ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    EXPECT_CALL(*event_interface_,
15449ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch                OnDataFrame(false,
15459ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch                            WebSocketFrameHeader::kOpCodeContinuation,
15469ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch                            AsVector("SMALL")));
15479ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    EXPECT_CALL(
15489ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch        *event_interface_,
15499ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch        OnDataFrame(
15509ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch            false, WebSocketFrameHeader::kOpCodeContinuation, AsVector(" ")));
15519ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    EXPECT_CALL(*event_interface_,
15529ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch                OnDataFrame(true,
15539ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch                            WebSocketFrameHeader::kOpCodeContinuation,
15549ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch                            AsVector("FRAMES")));
15559ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  }
15569ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
15579ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  CreateChannelAndConnectSuccessfully();
15589ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  base::MessageLoop::current()->RunUntilIdle();
15599ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch}
15609ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
1561f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// A message can consist of one frame with NULL payload.
1562f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)TEST_F(WebSocketChannelEventInterfaceTest, NullMessage) {
1563f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  scoped_ptr<ReadableFakeWebSocketStream> stream(
1564f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      new ReadableFakeWebSocketStream);
1565f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  static const InitFrame frames[] = {
1566f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, NOT_MASKED, NULL}};
1567f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  stream->PrepareReadFrames(ReadableFakeWebSocketStream::SYNC, OK, frames);
1568f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  set_stream(stream.Pass());
15695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _, _));
1570f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  EXPECT_CALL(*event_interface_, OnFlowControl(_));
1571f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  EXPECT_CALL(
1572f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      *event_interface_,
1573f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      OnDataFrame(true, WebSocketFrameHeader::kOpCodeText, AsVector("")));
1574f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  CreateChannelAndConnectSuccessfully();
1575f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
1576f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
15779ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch// Connection closed by the remote host without a closing handshake.
15789ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben MurdochTEST_F(WebSocketChannelEventInterfaceTest, AsyncAbnormalClosure) {
15799ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  scoped_ptr<ReadableFakeWebSocketStream> stream(
15809ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch      new ReadableFakeWebSocketStream);
15819ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  stream->PrepareReadFramesError(ReadableFakeWebSocketStream::ASYNC,
15829ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch                                 ERR_CONNECTION_CLOSED);
15839ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  set_stream(stream.Pass());
15849ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  {
15859ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    InSequence s;
15865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _, _));
15879ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    EXPECT_CALL(*event_interface_, OnFlowControl(_));
15889ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    EXPECT_CALL(*event_interface_,
15895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                OnDropChannel(false, kWebSocketErrorAbnormalClosure, _));
15909ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  }
15919ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
15929ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  CreateChannelAndConnectSuccessfully();
15939ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  base::MessageLoop::current()->RunUntilIdle();
15949ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch}
15959ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
15969ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch// A connection reset should produce the same event as an unexpected closure.
15979ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben MurdochTEST_F(WebSocketChannelEventInterfaceTest, ConnectionReset) {
15989ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  scoped_ptr<ReadableFakeWebSocketStream> stream(
15999ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch      new ReadableFakeWebSocketStream);
16009ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  stream->PrepareReadFramesError(ReadableFakeWebSocketStream::ASYNC,
16019ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch                                 ERR_CONNECTION_RESET);
16029ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  set_stream(stream.Pass());
16039ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  {
16049ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    InSequence s;
16055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _, _));
16069ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    EXPECT_CALL(*event_interface_, OnFlowControl(_));
16079ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    EXPECT_CALL(*event_interface_,
16085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                OnDropChannel(false, kWebSocketErrorAbnormalClosure, _));
16099ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  }
16109ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
16119ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  CreateChannelAndConnectSuccessfully();
16129ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  base::MessageLoop::current()->RunUntilIdle();
16139ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch}
16149ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
16159ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch// RFC6455 5.1 "A client MUST close a connection if it detects a masked frame."
16169ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben MurdochTEST_F(WebSocketChannelEventInterfaceTest, MaskedFramesAreRejected) {
16179ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  scoped_ptr<ReadableFakeWebSocketStream> stream(
16189ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch      new ReadableFakeWebSocketStream);
16194e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  static const InitFrame frames[] = {
16204e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, MASKED, "HELLO"}};
16219ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
16224e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, frames);
16239ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  set_stream(stream.Pass());
16249ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  {
16259ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    InSequence s;
16265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _, _));
16279ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    EXPECT_CALL(*event_interface_, OnFlowControl(_));
16285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    EXPECT_CALL(
16295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        *event_interface_,
16305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        OnFailChannel(
16315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            "A server must not mask any frames that it sends to the client."));
16329ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  }
16339ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
16349ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  CreateChannelAndConnectSuccessfully();
16359ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  base::MessageLoop::current()->RunUntilIdle();
16369ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch}
16379ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
16389ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch// RFC6455 5.2 "If an unknown opcode is received, the receiving endpoint MUST
16399ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch// _Fail the WebSocket Connection_."
16409ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben MurdochTEST_F(WebSocketChannelEventInterfaceTest, UnknownOpCodeIsRejected) {
16419ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  scoped_ptr<ReadableFakeWebSocketStream> stream(
16429ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch      new ReadableFakeWebSocketStream);
16434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  static const InitFrame frames[] = {{FINAL_FRAME, 4, NOT_MASKED, "HELLO"}};
16449ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
16454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, frames);
16469ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  set_stream(stream.Pass());
16479ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  {
16489ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    InSequence s;
16495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _, _));
16509ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    EXPECT_CALL(*event_interface_, OnFlowControl(_));
16519ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    EXPECT_CALL(*event_interface_,
16525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                OnFailChannel("Unrecognized frame opcode: 4"));
16539ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  }
16549ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
16559ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  CreateChannelAndConnectSuccessfully();
16569ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  base::MessageLoop::current()->RunUntilIdle();
16579ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch}
16589ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
16599ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch// RFC6455 5.4 "Control frames ... MAY be injected in the middle of a
16609ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch// fragmented message."
16619ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben MurdochTEST_F(WebSocketChannelEventInterfaceTest, ControlFrameInDataMessage) {
16629ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  scoped_ptr<ReadableFakeWebSocketStream> stream(
16639ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch      new ReadableFakeWebSocketStream);
16649ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  // We have one message of type Text split into two frames. In the middle is a
16659ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  // control message of type Pong.
16664e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  static const InitFrame frames1[] = {
16674e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      {NOT_FINAL_FRAME, WebSocketFrameHeader::kOpCodeText,
16684e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)       NOT_MASKED,      "SPLIT "}};
16694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  static const InitFrame frames2[] = {
16704e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      {FINAL_FRAME, WebSocketFrameHeader::kOpCodePong, NOT_MASKED, ""}};
16714e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  static const InitFrame frames3[] = {
16724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeContinuation,
16734e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)       NOT_MASKED,  "MESSAGE"}};
16744e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, frames1);
16754e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, frames2);
16764e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, frames3);
16779ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  set_stream(stream.Pass());
16789ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  {
16799ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    InSequence s;
16805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _, _));
16819ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    EXPECT_CALL(*event_interface_, OnFlowControl(_));
16829ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    EXPECT_CALL(
16839ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch        *event_interface_,
16849ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch        OnDataFrame(
16859ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch            false, WebSocketFrameHeader::kOpCodeText, AsVector("SPLIT ")));
16869ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    EXPECT_CALL(*event_interface_,
16879ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch                OnDataFrame(true,
16889ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch                            WebSocketFrameHeader::kOpCodeContinuation,
16899ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch                            AsVector("MESSAGE")));
16909ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  }
16919ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
16929ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  CreateChannelAndConnectSuccessfully();
16939ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  base::MessageLoop::current()->RunUntilIdle();
16949ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch}
16959ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
1696f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// It seems redundant to repeat the entirety of the above test, so just test a
1697f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// Pong with NULL data.
1698f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)TEST_F(WebSocketChannelEventInterfaceTest, PongWithNullData) {
1699f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  scoped_ptr<ReadableFakeWebSocketStream> stream(
1700f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      new ReadableFakeWebSocketStream);
1701f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  static const InitFrame frames[] = {
1702f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      {FINAL_FRAME, WebSocketFrameHeader::kOpCodePong, NOT_MASKED, NULL}};
1703f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, frames);
1704f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  set_stream(stream.Pass());
17055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _, _));
1706f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  EXPECT_CALL(*event_interface_, OnFlowControl(_));
1707f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
1708f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  CreateChannelAndConnectSuccessfully();
1709f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  base::MessageLoop::current()->RunUntilIdle();
1710f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
1711f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
17124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// If a frame has an invalid header, then the connection is closed and
17134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// subsequent frames must not trigger events.
17144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)TEST_F(WebSocketChannelEventInterfaceTest, FrameAfterInvalidFrame) {
1715558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  scoped_ptr<ReadableFakeWebSocketStream> stream(
1716558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      new ReadableFakeWebSocketStream);
17174e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  static const InitFrame frames[] = {
17184e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      {NOT_FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, MASKED, "HELLO"},
17194e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, NOT_MASKED, " WORLD"}};
1720558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
17214e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, frames);
1722558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  set_stream(stream.Pass());
1723558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  {
1724558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    InSequence s;
17255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _, _));
1726558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    EXPECT_CALL(*event_interface_, OnFlowControl(_));
17275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    EXPECT_CALL(
17285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        *event_interface_,
17295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        OnFailChannel(
17305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            "A server must not mask any frames that it sends to the client."));
1731558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  }
1732558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
1733558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  CreateChannelAndConnectSuccessfully();
1734558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  base::MessageLoop::current()->RunUntilIdle();
1735558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch}
1736558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
17379ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch// If the renderer sends lots of small writes, we don't want to update the quota
17389ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch// for each one.
17399ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben MurdochTEST_F(WebSocketChannelEventInterfaceTest, SmallWriteDoesntUpdateQuota) {
17409ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  set_stream(make_scoped_ptr(new WriteableFakeWebSocketStream));
17419ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  {
17429ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    InSequence s;
17435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _, _));
17449ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    EXPECT_CALL(*event_interface_, OnFlowControl(_));
17459ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  }
17469ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
17479ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  CreateChannelAndConnectSuccessfully();
17489ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  channel_->SendFrame(true, WebSocketFrameHeader::kOpCodeText, AsVector("B"));
17499ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch}
17509ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
17519ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch// If we send enough to go below send_quota_low_water_mask_ we should get our
17529ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch// quota refreshed.
17539ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben MurdochTEST_F(WebSocketChannelEventInterfaceTest, LargeWriteUpdatesQuota) {
17549ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  set_stream(make_scoped_ptr(new WriteableFakeWebSocketStream));
17559ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  // We use this checkpoint object to verify that the quota update comes after
17569ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  // the write.
17571e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  Checkpoint checkpoint;
17589ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  {
17599ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    InSequence s;
17605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _, _));
17619ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    EXPECT_CALL(*event_interface_, OnFlowControl(_));
17629ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    EXPECT_CALL(checkpoint, Call(1));
17639ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    EXPECT_CALL(*event_interface_, OnFlowControl(_));
17649ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    EXPECT_CALL(checkpoint, Call(2));
17659ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  }
17669ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
17679ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  CreateChannelAndConnectSuccessfully();
17689ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  checkpoint.Call(1);
1769558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  channel_->SendFrame(true,
1770558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch                      WebSocketFrameHeader::kOpCodeText,
1771558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch                      std::vector<char>(kDefaultInitialQuota, 'B'));
17729ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  checkpoint.Call(2);
17739ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch}
17749ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
17759ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch// Verify that our quota actually is refreshed when we are told it is.
17769ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben MurdochTEST_F(WebSocketChannelEventInterfaceTest, QuotaReallyIsRefreshed) {
17779ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  set_stream(make_scoped_ptr(new WriteableFakeWebSocketStream));
17781e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  Checkpoint checkpoint;
17799ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  {
17809ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    InSequence s;
17815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _, _));
17829ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    EXPECT_CALL(*event_interface_, OnFlowControl(_));
17839ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    EXPECT_CALL(checkpoint, Call(1));
17849ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    EXPECT_CALL(*event_interface_, OnFlowControl(_));
17859ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    EXPECT_CALL(checkpoint, Call(2));
17869ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    // If quota was not really refreshed, we would get an OnDropChannel()
17879ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    // message.
17889ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    EXPECT_CALL(*event_interface_, OnFlowControl(_));
17899ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    EXPECT_CALL(checkpoint, Call(3));
17909ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  }
17919ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
17929ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  CreateChannelAndConnectSuccessfully();
17939ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  checkpoint.Call(1);
17949ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  channel_->SendFrame(true,
17959ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch                      WebSocketFrameHeader::kOpCodeText,
1796558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch                      std::vector<char>(kDefaultQuotaRefreshTrigger, 'D'));
17979ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  checkpoint.Call(2);
17989ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  // We should have received more quota at this point.
17999ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  channel_->SendFrame(true,
18009ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch                      WebSocketFrameHeader::kOpCodeText,
1801558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch                      std::vector<char>(kDefaultQuotaRefreshTrigger, 'E'));
18029ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  checkpoint.Call(3);
18039ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch}
18049ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
18059ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch// If we send more than the available quota then the connection will be closed
18069ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch// with an error.
18079ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben MurdochTEST_F(WebSocketChannelEventInterfaceTest, WriteOverQuotaIsRejected) {
18089ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  set_stream(make_scoped_ptr(new WriteableFakeWebSocketStream));
18099ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  {
18109ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    InSequence s;
18115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _, _));
1812558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    EXPECT_CALL(*event_interface_, OnFlowControl(kDefaultInitialQuota));
18135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    EXPECT_CALL(*event_interface_, OnFailChannel("Send quota exceeded"));
18149ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  }
18159ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
18169ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  CreateChannelAndConnectSuccessfully();
18179ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  channel_->SendFrame(true,
18189ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch                      WebSocketFrameHeader::kOpCodeText,
1819558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch                      std::vector<char>(kDefaultInitialQuota + 1, 'C'));
18209ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch}
18219ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
18229ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch// If a write fails, the channel is dropped.
18239ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben MurdochTEST_F(WebSocketChannelEventInterfaceTest, FailedWrite) {
18249ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  set_stream(make_scoped_ptr(new UnWriteableFakeWebSocketStream));
18251e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  Checkpoint checkpoint;
18269ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  {
18279ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    InSequence s;
18285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _, _));
18299ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    EXPECT_CALL(*event_interface_, OnFlowControl(_));
18309ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    EXPECT_CALL(checkpoint, Call(1));
18319ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    EXPECT_CALL(*event_interface_,
18325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                OnDropChannel(false, kWebSocketErrorAbnormalClosure, _));
18339ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    EXPECT_CALL(checkpoint, Call(2));
18349ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  }
18359ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
18369ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  CreateChannelAndConnectSuccessfully();
18379ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  checkpoint.Call(1);
18389ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
18399ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  channel_->SendFrame(true, WebSocketFrameHeader::kOpCodeText, AsVector("H"));
18409ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  checkpoint.Call(2);
18419ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch}
18429ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
18439ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch// OnDropChannel() is called exactly once when StartClosingHandshake() is used.
18449ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben MurdochTEST_F(WebSocketChannelEventInterfaceTest, SendCloseDropsChannel) {
18459ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  set_stream(make_scoped_ptr(new EchoeyFakeWebSocketStream));
18469ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  {
18479ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    InSequence s;
18485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _, _));
18499ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    EXPECT_CALL(*event_interface_, OnFlowControl(_));
18509ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    EXPECT_CALL(*event_interface_,
18515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                OnDropChannel(true, kWebSocketNormalClosure, "Fred"));
18529ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  }
18539ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
18549ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  CreateChannelAndConnectSuccessfully();
18559ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
18569ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  channel_->StartClosingHandshake(kWebSocketNormalClosure, "Fred");
18579ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  base::MessageLoop::current()->RunUntilIdle();
18589ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch}
18599ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
18605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// StartClosingHandshake() also works before connection completes, and calls
18615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// OnDropChannel.
18625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketChannelEventInterfaceTest, CloseDuringConnection) {
18635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_CALL(*event_interface_,
18645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              OnDropChannel(false, kWebSocketErrorAbnormalClosure, ""));
18655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
18665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CreateChannelAndConnect();
18675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  channel_->StartClosingHandshake(kWebSocketNormalClosure, "Joe");
18685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
18695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1870558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch// OnDropChannel() is only called once when a write() on the socket triggers a
1871558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch// connection reset.
1872558790d6acca3451cf3a6b497803a5f07d0bec58Ben MurdochTEST_F(WebSocketChannelEventInterfaceTest, OnDropChannelCalledOnce) {
1873558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  set_stream(make_scoped_ptr(new ResetOnWriteFakeWebSocketStream));
18745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _, _));
1875558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  EXPECT_CALL(*event_interface_, OnFlowControl(_));
1876558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
1877558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  EXPECT_CALL(*event_interface_,
18785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              OnDropChannel(false, kWebSocketErrorAbnormalClosure, ""))
1879558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      .Times(1);
1880558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
1881558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  CreateChannelAndConnectSuccessfully();
1882558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
1883558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  channel_->SendFrame(true, WebSocketFrameHeader::kOpCodeText, AsVector("yt?"));
1884558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  base::MessageLoop::current()->RunUntilIdle();
1885558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch}
1886558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
1887558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch// When the remote server sends a Close frame with an empty payload,
1888558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch// WebSocketChannel should report code 1005, kWebSocketErrorNoStatusReceived.
1889558790d6acca3451cf3a6b497803a5f07d0bec58Ben MurdochTEST_F(WebSocketChannelEventInterfaceTest, CloseWithNoPayloadGivesStatus1005) {
1890558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  scoped_ptr<ReadableFakeWebSocketStream> stream(
1891558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      new ReadableFakeWebSocketStream);
18924e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  static const InitFrame frames[] = {
18934e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose, NOT_MASKED, ""}};
18944e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  stream->PrepareReadFrames(ReadableFakeWebSocketStream::SYNC, OK, frames);
1895558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  stream->PrepareReadFramesError(ReadableFakeWebSocketStream::SYNC,
1896558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch                                 ERR_CONNECTION_CLOSED);
1897558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  set_stream(stream.Pass());
18985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _, _));
1899558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  EXPECT_CALL(*event_interface_, OnFlowControl(_));
1900558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  EXPECT_CALL(*event_interface_, OnClosingHandshake());
1901558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  EXPECT_CALL(*event_interface_,
19025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              OnDropChannel(true, kWebSocketErrorNoStatusReceived, _));
1903558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
1904558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  CreateChannelAndConnectSuccessfully();
1905558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch}
1906558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
1907f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// A version of the above test with NULL payload.
1908f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)TEST_F(WebSocketChannelEventInterfaceTest,
1909f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)       CloseWithNullPayloadGivesStatus1005) {
1910f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  scoped_ptr<ReadableFakeWebSocketStream> stream(
1911f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      new ReadableFakeWebSocketStream);
1912f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  static const InitFrame frames[] = {
1913f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose, NOT_MASKED, NULL}};
1914f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  stream->PrepareReadFrames(ReadableFakeWebSocketStream::SYNC, OK, frames);
1915f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  stream->PrepareReadFramesError(ReadableFakeWebSocketStream::SYNC,
1916f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                                 ERR_CONNECTION_CLOSED);
1917f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  set_stream(stream.Pass());
19185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _, _));
1919f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  EXPECT_CALL(*event_interface_, OnFlowControl(_));
1920f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  EXPECT_CALL(*event_interface_, OnClosingHandshake());
1921f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  EXPECT_CALL(*event_interface_,
19225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              OnDropChannel(true, kWebSocketErrorNoStatusReceived, _));
1923f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
1924f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  CreateChannelAndConnectSuccessfully();
1925f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
1926f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
19275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// If ReadFrames() returns ERR_WS_PROTOCOL_ERROR, then the connection must be
19285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// failed.
19294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)TEST_F(WebSocketChannelEventInterfaceTest, SyncProtocolErrorGivesStatus1002) {
19304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  scoped_ptr<ReadableFakeWebSocketStream> stream(
19314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      new ReadableFakeWebSocketStream);
19324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  stream->PrepareReadFramesError(ReadableFakeWebSocketStream::SYNC,
19334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                 ERR_WS_PROTOCOL_ERROR);
19344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  set_stream(stream.Pass());
19355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _, _));
19364e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  EXPECT_CALL(*event_interface_, OnFlowControl(_));
19374e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
19385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_CALL(*event_interface_, OnFailChannel("Invalid frame header"));
19394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
19404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  CreateChannelAndConnectSuccessfully();
19414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
19424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
19434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// Async version of above test.
19444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)TEST_F(WebSocketChannelEventInterfaceTest, AsyncProtocolErrorGivesStatus1002) {
19454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  scoped_ptr<ReadableFakeWebSocketStream> stream(
19464e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      new ReadableFakeWebSocketStream);
19474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  stream->PrepareReadFramesError(ReadableFakeWebSocketStream::ASYNC,
19484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                 ERR_WS_PROTOCOL_ERROR);
19494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  set_stream(stream.Pass());
19505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _, _));
19514e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  EXPECT_CALL(*event_interface_, OnFlowControl(_));
19524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
19535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_CALL(*event_interface_, OnFailChannel("Invalid frame header"));
19545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
19555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CreateChannelAndConnectSuccessfully();
19565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::MessageLoop::current()->RunUntilIdle();
19575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
19585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
19595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketChannelEventInterfaceTest, StartHandshakeRequest) {
19605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  {
19615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    InSequence s;
19625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _, _));
19635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    EXPECT_CALL(*event_interface_, OnFlowControl(_));
19645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    EXPECT_CALL(*event_interface_, OnStartOpeningHandshakeCalled());
19655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
19665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
19675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CreateChannelAndConnectSuccessfully();
19685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
19695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_ptr<WebSocketHandshakeRequestInfo> request_info(
19705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      new WebSocketHandshakeRequestInfo(GURL("ws://www.example.com/"),
19715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                        base::Time()));
19725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  connect_data_.creator.connect_delegate->OnStartOpeningHandshake(
19735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      request_info.Pass());
19745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
19755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::MessageLoop::current()->RunUntilIdle();
19765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
19775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
19785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketChannelEventInterfaceTest, FinishHandshakeRequest) {
19795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  {
19805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    InSequence s;
19815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _, _));
19825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    EXPECT_CALL(*event_interface_, OnFlowControl(_));
19835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    EXPECT_CALL(*event_interface_, OnFinishOpeningHandshakeCalled());
19845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
19854e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
19864e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  CreateChannelAndConnectSuccessfully();
19875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
19885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_refptr<HttpResponseHeaders> response_headers(
19895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      new HttpResponseHeaders(""));
19905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_ptr<WebSocketHandshakeResponseInfo> response_info(
19915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      new WebSocketHandshakeResponseInfo(GURL("ws://www.example.com/"),
19925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                         200,
19935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                         "OK",
19945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                         response_headers,
19955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                         base::Time()));
19965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  connect_data_.creator.connect_delegate->OnFinishOpeningHandshake(
19975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      response_info.Pass());
19985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::MessageLoop::current()->RunUntilIdle();
19995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
20005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
20015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketChannelEventInterfaceTest, FailJustAfterHandshake) {
20025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  {
20035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    InSequence s;
20045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    EXPECT_CALL(*event_interface_, OnStartOpeningHandshakeCalled());
20055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    EXPECT_CALL(*event_interface_, OnFinishOpeningHandshakeCalled());
20065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    EXPECT_CALL(*event_interface_, OnFailChannel("bye"));
20075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
20085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
20095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CreateChannelAndConnect();
20105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
20115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  WebSocketStream::ConnectDelegate* connect_delegate =
20125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      connect_data_.creator.connect_delegate.get();
20135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  GURL url("ws://www.example.com/");
20145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_ptr<WebSocketHandshakeRequestInfo> request_info(
20155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      new WebSocketHandshakeRequestInfo(url, base::Time()));
20165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_refptr<HttpResponseHeaders> response_headers(
20175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      new HttpResponseHeaders(""));
20185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_ptr<WebSocketHandshakeResponseInfo> response_info(
20195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      new WebSocketHandshakeResponseInfo(url,
20205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                         200,
20215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                         "OK",
20225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                         response_headers,
20235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                         base::Time()));
20245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  connect_delegate->OnStartOpeningHandshake(request_info.Pass());
20255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  connect_delegate->OnFinishOpeningHandshake(response_info.Pass());
20265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
20275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  connect_delegate->OnFailure("bye");
20284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  base::MessageLoop::current()->RunUntilIdle();
20294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
20304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
20315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Any frame after close is invalid. This test uses a Text frame. See also
20325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// test "PingAfterCloseIfRejected".
20335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketChannelEventInterfaceTest, DataAfterCloseIsRejected) {
20345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_ptr<ReadableFakeWebSocketStream> stream(
20355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      new ReadableFakeWebSocketStream);
20365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  static const InitFrame frames[] = {
20375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose, NOT_MASKED,
20385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       CLOSE_DATA(NORMAL_CLOSURE, "OK")},
20395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, NOT_MASKED, "Payload"}};
20405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  stream->PrepareReadFrames(ReadableFakeWebSocketStream::SYNC, OK, frames);
20415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  set_stream(stream.Pass());
20425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _, _));
20435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_CALL(*event_interface_, OnFlowControl(_));
20445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
20455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  {
20465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    InSequence s;
20475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    EXPECT_CALL(*event_interface_, OnClosingHandshake());
20485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    EXPECT_CALL(*event_interface_,
20495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                OnFailChannel("Data frame received after close"));
20505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
20515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
20525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CreateChannelAndConnectSuccessfully();
20535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
20545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
20555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// A Close frame with a one-byte payload elicits a specific console error
20565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// message.
20575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketChannelEventInterfaceTest, OneByteClosePayloadMessage) {
20585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_ptr<ReadableFakeWebSocketStream> stream(
20595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      new ReadableFakeWebSocketStream);
20605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  static const InitFrame frames[] = {
20615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose, NOT_MASKED, "\x03"}};
20625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  stream->PrepareReadFrames(ReadableFakeWebSocketStream::SYNC, OK, frames);
20635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  set_stream(stream.Pass());
20645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _, _));
20655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_CALL(*event_interface_, OnFlowControl(_));
20665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_CALL(
20675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      *event_interface_,
20685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      OnFailChannel(
20695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          "Received a broken close frame containing an invalid size body."));
20705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
20715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CreateChannelAndConnectSuccessfully();
20725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
20735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
20745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// A Close frame with a reserved status code also elicits a specific console
20755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// error message.
20765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketChannelEventInterfaceTest, ClosePayloadReservedStatusMessage) {
20775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_ptr<ReadableFakeWebSocketStream> stream(
20785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      new ReadableFakeWebSocketStream);
20795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  static const InitFrame frames[] = {
20805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose,
20815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       NOT_MASKED,  CLOSE_DATA(ABNORMAL_CLOSURE, "Not valid on wire")}};
20825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  stream->PrepareReadFrames(ReadableFakeWebSocketStream::SYNC, OK, frames);
20835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  set_stream(stream.Pass());
20845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _, _));
20855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_CALL(*event_interface_, OnFlowControl(_));
20865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_CALL(
20875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      *event_interface_,
20885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      OnFailChannel(
20895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          "Received a broken close frame containing a reserved status code."));
20905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
20915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CreateChannelAndConnectSuccessfully();
20925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
20935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
20945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// A Close frame with invalid UTF-8 also elicits a specific console error
20955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// message.
20965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketChannelEventInterfaceTest, ClosePayloadInvalidReason) {
20975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_ptr<ReadableFakeWebSocketStream> stream(
20985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      new ReadableFakeWebSocketStream);
20995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  static const InitFrame frames[] = {
21005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose,
21015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       NOT_MASKED,  CLOSE_DATA(NORMAL_CLOSURE, "\xFF")}};
21025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  stream->PrepareReadFrames(ReadableFakeWebSocketStream::SYNC, OK, frames);
21035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  set_stream(stream.Pass());
21045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _, _));
21055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_CALL(*event_interface_, OnFlowControl(_));
21065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_CALL(
21075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      *event_interface_,
21085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      OnFailChannel(
21095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          "Received a broken close frame containing invalid UTF-8."));
21105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
21115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CreateChannelAndConnectSuccessfully();
21125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
21135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2114a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// The reserved bits must all be clear on received frames. Extensions should
2115a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// clear the bits when they are set correctly before passing on the frame.
2116a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)TEST_F(WebSocketChannelEventInterfaceTest, ReservedBitsMustNotBeSet) {
2117a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  scoped_ptr<ReadableFakeWebSocketStream> stream(
2118a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      new ReadableFakeWebSocketStream);
2119a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  static const InitFrame frames[] = {
2120a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText,
2121a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)       NOT_MASKED,  "sakana"}};
2122a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // It is not worth adding support for reserved bits to InitFrame just for this
2123a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // one test, so set the bit manually.
2124a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  ScopedVector<WebSocketFrame> raw_frames = CreateFrameVector(frames);
2125a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  raw_frames[0]->header.reserved1 = true;
2126a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  stream->PrepareRawReadFrames(
2127a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      ReadableFakeWebSocketStream::SYNC, OK, raw_frames.Pass());
2128a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  set_stream(stream.Pass());
2129a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _, _));
2130a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  EXPECT_CALL(*event_interface_, OnFlowControl(_));
2131a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  EXPECT_CALL(*event_interface_,
2132a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)              OnFailChannel(
2133a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                  "One or more reserved bits are on: reserved1 = 1, "
2134a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                  "reserved2 = 0, reserved3 = 0"));
2135a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
2136a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  CreateChannelAndConnectSuccessfully();
2137a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
2138a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
21391e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// The closing handshake times out and sends an OnDropChannel event if no
21401e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// response to the client Close message is received.
21411e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)TEST_F(WebSocketChannelEventInterfaceTest,
21421e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)       ClientInitiatedClosingHandshakeTimesOut) {
21431e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  scoped_ptr<ReadableFakeWebSocketStream> stream(
21441e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      new ReadableFakeWebSocketStream);
21451e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  stream->PrepareReadFramesError(ReadableFakeWebSocketStream::SYNC,
21461e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                                 ERR_IO_PENDING);
21471e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  set_stream(stream.Pass());
21485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _, _));
21491e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  EXPECT_CALL(*event_interface_, OnFlowControl(_));
21501e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // This checkpoint object verifies that the OnDropChannel message comes after
21511e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // the timeout.
21521e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  Checkpoint checkpoint;
21531e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  TestClosure completion;
21541e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  {
21551e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    InSequence s;
21561e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    EXPECT_CALL(checkpoint, Call(1));
21571e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    EXPECT_CALL(*event_interface_,
21585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                OnDropChannel(false, kWebSocketErrorAbnormalClosure, _))
21591e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        .WillOnce(InvokeClosureReturnDeleted(completion.closure()));
21601e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  }
21611e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  CreateChannelAndConnectSuccessfully();
21621e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // OneShotTimer is not very friendly to testing; there is no apparent way to
21631e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // set an expectation on it. Instead the tests need to infer that the timeout
21641e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // was fired by the behaviour of the WebSocketChannel object.
21651e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  channel_->SetClosingHandshakeTimeoutForTesting(
21661e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      TimeDelta::FromMilliseconds(kVeryTinyTimeoutMillis));
21671e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  channel_->StartClosingHandshake(kWebSocketNormalClosure, "");
21681e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  checkpoint.Call(1);
21691e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  completion.WaitForResult();
21701e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
21711e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
21721e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// The closing handshake times out and sends an OnDropChannel event if a Close
21731e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// message is received but the connection isn't closed by the remote host.
21741e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)TEST_F(WebSocketChannelEventInterfaceTest,
21751e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)       ServerInitiatedClosingHandshakeTimesOut) {
21761e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  scoped_ptr<ReadableFakeWebSocketStream> stream(
21771e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      new ReadableFakeWebSocketStream);
21781e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  static const InitFrame frames[] = {
21791e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose,
21801e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)       NOT_MASKED,  CLOSE_DATA(NORMAL_CLOSURE, "OK")}};
21811e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, frames);
21821e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  set_stream(stream.Pass());
21835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _, _));
21841e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  EXPECT_CALL(*event_interface_, OnFlowControl(_));
21851e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  Checkpoint checkpoint;
21861e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  TestClosure completion;
21871e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  {
21881e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    InSequence s;
21891e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    EXPECT_CALL(checkpoint, Call(1));
21901e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    EXPECT_CALL(*event_interface_, OnClosingHandshake());
21911e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    EXPECT_CALL(*event_interface_,
21925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                OnDropChannel(false, kWebSocketErrorAbnormalClosure, _))
21931e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        .WillOnce(InvokeClosureReturnDeleted(completion.closure()));
21941e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  }
21951e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  CreateChannelAndConnectSuccessfully();
21961e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  channel_->SetClosingHandshakeTimeoutForTesting(
21971e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      TimeDelta::FromMilliseconds(kVeryTinyTimeoutMillis));
21981e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  checkpoint.Call(1);
21991e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  completion.WaitForResult();
22001e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
22011e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
2202effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// The renderer should provide us with some quota immediately, and then
2203effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// WebSocketChannel calls ReadFrames as soon as the stream is available.
2204effb81e5f8246d0db0270817048dc992db66e9fbBen MurdochTEST_F(WebSocketChannelStreamTest, FlowControlEarly) {
2205effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  Checkpoint checkpoint;
2206effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  EXPECT_CALL(*mock_stream_, GetSubProtocol()).Times(AnyNumber());
2207effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  EXPECT_CALL(*mock_stream_, GetExtensions()).Times(AnyNumber());
2208effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  {
2209effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    InSequence s;
2210effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    EXPECT_CALL(checkpoint, Call(1));
2211effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    EXPECT_CALL(*mock_stream_, ReadFrames(_, _))
2212effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        .WillOnce(Return(ERR_IO_PENDING));
2213effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    EXPECT_CALL(checkpoint, Call(2));
2214effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
2215effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
2216effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  set_stream(mock_stream_.Pass());
2217effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  CreateChannelAndConnect();
2218effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  channel_->SendFlowControl(kPlentyOfQuota);
2219effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  checkpoint.Call(1);
2220effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  connect_data_.creator.connect_delegate->OnSuccess(stream_.Pass());
2221effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  checkpoint.Call(2);
2222effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
2223effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
2224effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// If for some reason the connect succeeds before the renderer sends us quota,
2225effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// we shouldn't call ReadFrames() immediately.
2226effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// TODO(ricea): Actually we should call ReadFrames() with a small limit so we
2227effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// can still handle control frames. This should be done once we have any API to
2228effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// expose quota to the lower levels.
2229effb81e5f8246d0db0270817048dc992db66e9fbBen MurdochTEST_F(WebSocketChannelStreamTest, FlowControlLate) {
2230effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  Checkpoint checkpoint;
2231effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  EXPECT_CALL(*mock_stream_, GetSubProtocol()).Times(AnyNumber());
2232effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  EXPECT_CALL(*mock_stream_, GetExtensions()).Times(AnyNumber());
2233effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  {
2234effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    InSequence s;
2235effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    EXPECT_CALL(checkpoint, Call(1));
2236effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    EXPECT_CALL(*mock_stream_, ReadFrames(_, _))
2237effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        .WillOnce(Return(ERR_IO_PENDING));
2238effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    EXPECT_CALL(checkpoint, Call(2));
2239effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
2240effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
2241effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  set_stream(mock_stream_.Pass());
2242effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  CreateChannelAndConnect();
2243effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  connect_data_.creator.connect_delegate->OnSuccess(stream_.Pass());
2244effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  checkpoint.Call(1);
2245effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  channel_->SendFlowControl(kPlentyOfQuota);
2246effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  checkpoint.Call(2);
2247effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
2248effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
2249effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// We should stop calling ReadFrames() when all quota is used.
2250effb81e5f8246d0db0270817048dc992db66e9fbBen MurdochTEST_F(WebSocketChannelStreamTest, FlowControlStopsReadFrames) {
2251effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  static const InitFrame frames[] = {
2252effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, NOT_MASKED, "FOUR"}};
2253effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
2254effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  EXPECT_CALL(*mock_stream_, GetSubProtocol()).Times(AnyNumber());
2255effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  EXPECT_CALL(*mock_stream_, GetExtensions()).Times(AnyNumber());
2256effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  EXPECT_CALL(*mock_stream_, ReadFrames(_, _))
2257effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      .WillOnce(ReturnFrames(&frames));
2258effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
2259effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  set_stream(mock_stream_.Pass());
2260effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  CreateChannelAndConnect();
2261effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  channel_->SendFlowControl(4);
2262effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  connect_data_.creator.connect_delegate->OnSuccess(stream_.Pass());
2263effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
2264effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
2265effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// Providing extra quota causes ReadFrames() to be called again.
2266effb81e5f8246d0db0270817048dc992db66e9fbBen MurdochTEST_F(WebSocketChannelStreamTest, FlowControlStartsWithMoreQuota) {
2267effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  static const InitFrame frames[] = {
2268effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, NOT_MASKED, "FOUR"}};
2269effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  Checkpoint checkpoint;
2270effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
2271effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  EXPECT_CALL(*mock_stream_, GetSubProtocol()).Times(AnyNumber());
2272effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  EXPECT_CALL(*mock_stream_, GetExtensions()).Times(AnyNumber());
2273effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  {
2274effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    InSequence s;
2275effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    EXPECT_CALL(*mock_stream_, ReadFrames(_, _))
2276effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        .WillOnce(ReturnFrames(&frames));
2277effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    EXPECT_CALL(checkpoint, Call(1));
2278effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    EXPECT_CALL(*mock_stream_, ReadFrames(_, _))
2279effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        .WillOnce(Return(ERR_IO_PENDING));
2280effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
2281effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
2282effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  set_stream(mock_stream_.Pass());
2283effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  CreateChannelAndConnect();
2284effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  channel_->SendFlowControl(4);
2285effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  connect_data_.creator.connect_delegate->OnSuccess(stream_.Pass());
2286effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  checkpoint.Call(1);
2287effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  channel_->SendFlowControl(4);
2288effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
2289effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
2290effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// ReadFrames() isn't called again until all pending data has been passed to
2291effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// the renderer.
2292effb81e5f8246d0db0270817048dc992db66e9fbBen MurdochTEST_F(WebSocketChannelStreamTest, ReadFramesNotCalledUntilQuotaAvailable) {
2293effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  static const InitFrame frames[] = {
2294effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, NOT_MASKED, "FOUR"}};
2295effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  Checkpoint checkpoint;
2296effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
2297effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  EXPECT_CALL(*mock_stream_, GetSubProtocol()).Times(AnyNumber());
2298effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  EXPECT_CALL(*mock_stream_, GetExtensions()).Times(AnyNumber());
2299effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  {
2300effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    InSequence s;
2301effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    EXPECT_CALL(*mock_stream_, ReadFrames(_, _))
2302effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        .WillOnce(ReturnFrames(&frames));
2303effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    EXPECT_CALL(checkpoint, Call(1));
2304effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    EXPECT_CALL(checkpoint, Call(2));
2305effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    EXPECT_CALL(*mock_stream_, ReadFrames(_, _))
2306effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        .WillOnce(Return(ERR_IO_PENDING));
2307effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
2308effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
2309effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  set_stream(mock_stream_.Pass());
2310effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  CreateChannelAndConnect();
2311effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  channel_->SendFlowControl(2);
2312effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  connect_data_.creator.connect_delegate->OnSuccess(stream_.Pass());
2313effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  checkpoint.Call(1);
2314effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  channel_->SendFlowControl(2);
2315effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  checkpoint.Call(2);
2316effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  channel_->SendFlowControl(2);
2317effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
2318effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
2319effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// A message that needs to be split into frames to fit within quota should
2320effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// maintain correct semantics.
2321effb81e5f8246d0db0270817048dc992db66e9fbBen MurdochTEST_F(WebSocketChannelFlowControlTest, SingleFrameMessageSplitSync) {
2322effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  scoped_ptr<ReadableFakeWebSocketStream> stream(
2323effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      new ReadableFakeWebSocketStream);
2324effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  static const InitFrame frames[] = {
2325effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, NOT_MASKED, "FOUR"}};
2326effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  stream->PrepareReadFrames(ReadableFakeWebSocketStream::SYNC, OK, frames);
2327effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  set_stream(stream.Pass());
2328effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  {
2329effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    InSequence s;
2330effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _, _));
2331effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    EXPECT_CALL(*event_interface_, OnFlowControl(_));
2332effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    EXPECT_CALL(
2333effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        *event_interface_,
2334effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        OnDataFrame(false, WebSocketFrameHeader::kOpCodeText, AsVector("FO")));
2335effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    EXPECT_CALL(
2336effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        *event_interface_,
2337effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        OnDataFrame(
2338effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch            false, WebSocketFrameHeader::kOpCodeContinuation, AsVector("U")));
2339effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    EXPECT_CALL(
2340effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        *event_interface_,
2341effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        OnDataFrame(
2342effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch            true, WebSocketFrameHeader::kOpCodeContinuation, AsVector("R")));
2343effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
2344effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
2345effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  CreateChannelAndConnectWithQuota(2);
2346effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  channel_->SendFlowControl(1);
2347effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  channel_->SendFlowControl(1);
2348effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
2349effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
2350effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// The code path for async messages is slightly different, so test it
2351effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// separately.
2352effb81e5f8246d0db0270817048dc992db66e9fbBen MurdochTEST_F(WebSocketChannelFlowControlTest, SingleFrameMessageSplitAsync) {
2353effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  scoped_ptr<ReadableFakeWebSocketStream> stream(
2354effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      new ReadableFakeWebSocketStream);
2355effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  static const InitFrame frames[] = {
2356effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, NOT_MASKED, "FOUR"}};
2357effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, frames);
2358effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  set_stream(stream.Pass());
2359effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  Checkpoint checkpoint;
2360effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  {
2361effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    InSequence s;
2362effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _, _));
2363effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    EXPECT_CALL(*event_interface_, OnFlowControl(_));
2364effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    EXPECT_CALL(checkpoint, Call(1));
2365effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    EXPECT_CALL(
2366effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        *event_interface_,
2367effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        OnDataFrame(false, WebSocketFrameHeader::kOpCodeText, AsVector("FO")));
2368effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    EXPECT_CALL(checkpoint, Call(2));
2369effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    EXPECT_CALL(
2370effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        *event_interface_,
2371effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        OnDataFrame(
2372effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch            false, WebSocketFrameHeader::kOpCodeContinuation, AsVector("U")));
2373effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    EXPECT_CALL(checkpoint, Call(3));
2374effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    EXPECT_CALL(
2375effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        *event_interface_,
2376effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        OnDataFrame(
2377effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch            true, WebSocketFrameHeader::kOpCodeContinuation, AsVector("R")));
2378effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
2379effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
2380effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  CreateChannelAndConnectWithQuota(2);
2381effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  checkpoint.Call(1);
2382effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  base::MessageLoop::current()->RunUntilIdle();
2383effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  checkpoint.Call(2);
2384effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  channel_->SendFlowControl(1);
2385effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  checkpoint.Call(3);
2386effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  channel_->SendFlowControl(1);
2387effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
2388effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
2389effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// A message split into multiple frames which is further split due to quota
2390effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// restrictions should stil be correct.
2391effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// TODO(ricea): The message ends up split into more frames than are strictly
2392effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// necessary. The complexity/performance tradeoffs here need further
2393effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// examination.
2394effb81e5f8246d0db0270817048dc992db66e9fbBen MurdochTEST_F(WebSocketChannelFlowControlTest, MultipleFrameSplit) {
2395effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  scoped_ptr<ReadableFakeWebSocketStream> stream(
2396effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      new ReadableFakeWebSocketStream);
2397effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  static const InitFrame frames[] = {
2398effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      {NOT_FINAL_FRAME, WebSocketFrameHeader::kOpCodeText,
2399effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch       NOT_MASKED,      "FIRST FRAME IS 25 BYTES. "},
2400effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      {NOT_FINAL_FRAME, WebSocketFrameHeader::kOpCodeContinuation,
2401effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch       NOT_MASKED,      "SECOND FRAME IS 26 BYTES. "},
2402effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      {FINAL_FRAME,     WebSocketFrameHeader::kOpCodeContinuation,
2403effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch       NOT_MASKED,      "FINAL FRAME IS 24 BYTES."}};
2404effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  stream->PrepareReadFrames(ReadableFakeWebSocketStream::SYNC, OK, frames);
2405effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  set_stream(stream.Pass());
2406effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  {
2407effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    InSequence s;
2408effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _, _));
2409effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    EXPECT_CALL(*event_interface_, OnFlowControl(_));
2410effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    EXPECT_CALL(*event_interface_,
2411effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                OnDataFrame(false,
2412effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                            WebSocketFrameHeader::kOpCodeText,
2413effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                            AsVector("FIRST FRAME IS")));
2414effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    EXPECT_CALL(*event_interface_,
2415effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                OnDataFrame(false,
2416effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                            WebSocketFrameHeader::kOpCodeContinuation,
2417effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                            AsVector(" 25 BYTES. ")));
2418effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    EXPECT_CALL(*event_interface_,
2419effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                OnDataFrame(false,
2420effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                            WebSocketFrameHeader::kOpCodeContinuation,
2421effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                            AsVector("SECOND FRAME IS 26 BYTES. ")));
2422effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    EXPECT_CALL(*event_interface_,
2423effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                OnDataFrame(false,
2424effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                            WebSocketFrameHeader::kOpCodeContinuation,
2425effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                            AsVector("FINAL ")));
2426effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    EXPECT_CALL(*event_interface_,
2427effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                OnDataFrame(true,
2428effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                            WebSocketFrameHeader::kOpCodeContinuation,
2429effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                            AsVector("FRAME IS 24 BYTES.")));
2430effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
2431effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  CreateChannelAndConnectWithQuota(14);
2432effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  channel_->SendFlowControl(43);
2433effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  channel_->SendFlowControl(32);
2434effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
2435effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
2436effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// An empty message handled when we are out of quota must not be delivered
2437effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// out-of-order with respect to other messages.
2438effb81e5f8246d0db0270817048dc992db66e9fbBen MurdochTEST_F(WebSocketChannelFlowControlTest, EmptyMessageNoQuota) {
2439effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  scoped_ptr<ReadableFakeWebSocketStream> stream(
2440effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      new ReadableFakeWebSocketStream);
2441effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  static const InitFrame frames[] = {
2442effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText,
2443effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch       NOT_MASKED,  "FIRST MESSAGE"},
2444effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText,
24455c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu       NOT_MASKED,  NULL},
2446effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText,
2447effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch       NOT_MASKED,  "THIRD MESSAGE"}};
2448effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  stream->PrepareReadFrames(ReadableFakeWebSocketStream::SYNC, OK, frames);
2449effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  set_stream(stream.Pass());
2450effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  {
2451effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    InSequence s;
2452effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _, _));
2453effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    EXPECT_CALL(*event_interface_, OnFlowControl(_));
2454effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    EXPECT_CALL(*event_interface_,
2455effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                OnDataFrame(false,
2456effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                            WebSocketFrameHeader::kOpCodeText,
2457effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                            AsVector("FIRST ")));
2458effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    EXPECT_CALL(*event_interface_,
2459effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                OnDataFrame(true,
2460effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                            WebSocketFrameHeader::kOpCodeContinuation,
2461effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                            AsVector("MESSAGE")));
2462effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    EXPECT_CALL(*event_interface_,
2463effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                OnDataFrame(true,
2464effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                            WebSocketFrameHeader::kOpCodeText,
2465effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                            AsVector("")));
2466effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    EXPECT_CALL(*event_interface_,
2467effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                OnDataFrame(true,
2468effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                            WebSocketFrameHeader::kOpCodeText,
2469effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                            AsVector("THIRD MESSAGE")));
2470effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
2471effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
2472effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  CreateChannelAndConnectWithQuota(6);
2473effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  channel_->SendFlowControl(128);
2474effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
2475effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
24769ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch// RFC6455 5.1 "a client MUST mask all frames that it sends to the server".
24779ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch// WebSocketChannel actually only sets the mask bit in the header, it doesn't
24789ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch// perform masking itself (not all transports actually use masking).
24799ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben MurdochTEST_F(WebSocketChannelStreamTest, SentFramesAreMasked) {
24804e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  static const InitFrame expected[] = {
24814e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText,
24824e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)       MASKED,      "NEEDS MASKING"}};
24839ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  EXPECT_CALL(*mock_stream_, GetSubProtocol()).Times(AnyNumber());
24845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_CALL(*mock_stream_, GetExtensions()).Times(AnyNumber());
24859ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  EXPECT_CALL(*mock_stream_, ReadFrames(_, _)).WillOnce(Return(ERR_IO_PENDING));
24864e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  EXPECT_CALL(*mock_stream_, WriteFrames(EqualsFrames(expected), _))
2487558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      .WillOnce(Return(OK));
24889ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
24899ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  CreateChannelAndConnectSuccessfully();
24909ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  channel_->SendFrame(
24919ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch      true, WebSocketFrameHeader::kOpCodeText, AsVector("NEEDS MASKING"));
24929ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch}
24939ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
2494558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch// RFC6455 5.5.1 "The application MUST NOT send any more data frames after
2495558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch// sending a Close frame."
2496558790d6acca3451cf3a6b497803a5f07d0bec58Ben MurdochTEST_F(WebSocketChannelStreamTest, NothingIsSentAfterClose) {
24974e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  static const InitFrame expected[] = {
24984e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose,
24994e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)       MASKED,      CLOSE_DATA(NORMAL_CLOSURE, "Success")}};
2500558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  EXPECT_CALL(*mock_stream_, GetSubProtocol()).Times(AnyNumber());
25015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_CALL(*mock_stream_, GetExtensions()).Times(AnyNumber());
2502558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  EXPECT_CALL(*mock_stream_, ReadFrames(_, _)).WillOnce(Return(ERR_IO_PENDING));
25034e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  EXPECT_CALL(*mock_stream_, WriteFrames(EqualsFrames(expected), _))
2504558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      .WillOnce(Return(OK));
2505558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
2506558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  CreateChannelAndConnectSuccessfully();
2507558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  channel_->StartClosingHandshake(1000, "Success");
2508558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  channel_->SendFrame(
2509558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      true, WebSocketFrameHeader::kOpCodeText, AsVector("SHOULD  BE IGNORED"));
2510558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch}
2511558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
2512558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch// RFC6455 5.5.1 "If an endpoint receives a Close frame and did not previously
2513558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch// send a Close frame, the endpoint MUST send a Close frame in response."
2514558790d6acca3451cf3a6b497803a5f07d0bec58Ben MurdochTEST_F(WebSocketChannelStreamTest, CloseIsEchoedBack) {
25154e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  static const InitFrame frames[] = {
25164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose,
25174e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)       NOT_MASKED,  CLOSE_DATA(NORMAL_CLOSURE, "Close")}};
25184e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  static const InitFrame expected[] = {
25194e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose,
25204e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)       MASKED,      CLOSE_DATA(NORMAL_CLOSURE, "Close")}};
2521558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  EXPECT_CALL(*mock_stream_, GetSubProtocol()).Times(AnyNumber());
25225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_CALL(*mock_stream_, GetExtensions()).Times(AnyNumber());
2523558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  EXPECT_CALL(*mock_stream_, ReadFrames(_, _))
25244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      .WillOnce(ReturnFrames(&frames))
2525558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      .WillRepeatedly(Return(ERR_IO_PENDING));
25264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  EXPECT_CALL(*mock_stream_, WriteFrames(EqualsFrames(expected), _))
2527558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      .WillOnce(Return(OK));
2528558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
2529558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  CreateChannelAndConnectSuccessfully();
2530558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch}
2531558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
2532558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch// The converse of the above case; after sending a Close frame, we should not
2533558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch// send another one.
2534558790d6acca3451cf3a6b497803a5f07d0bec58Ben MurdochTEST_F(WebSocketChannelStreamTest, CloseOnlySentOnce) {
25354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  static const InitFrame expected[] = {
25364e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose,
25374e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)       MASKED,      CLOSE_DATA(NORMAL_CLOSURE, "Close")}};
25384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  static const InitFrame frames_init[] = {
25394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose,
25404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)       NOT_MASKED,  CLOSE_DATA(NORMAL_CLOSURE, "Close")}};
2541558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
2542558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  // We store the parameters that were passed to ReadFrames() so that we can
2543558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  // call them explicitly later.
2544558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  CompletionCallback read_callback;
25454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  ScopedVector<WebSocketFrame>* frames = NULL;
2546558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
25475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // These are not interesting.
25485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_CALL(*mock_stream_, GetSubProtocol()).Times(AnyNumber());
25495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_CALL(*mock_stream_, GetExtensions()).Times(AnyNumber());
25505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2551558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  // Use a checkpoint to make the ordering of events clearer.
25521e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  Checkpoint checkpoint;
2553558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  {
2554558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    InSequence s;
2555558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    EXPECT_CALL(*mock_stream_, ReadFrames(_, _))
25564e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        .WillOnce(DoAll(SaveArg<0>(&frames),
2557558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch                        SaveArg<1>(&read_callback),
2558558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch                        Return(ERR_IO_PENDING)));
2559558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    EXPECT_CALL(checkpoint, Call(1));
25604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    EXPECT_CALL(*mock_stream_, WriteFrames(EqualsFrames(expected), _))
2561558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch        .WillOnce(Return(OK));
2562558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    EXPECT_CALL(checkpoint, Call(2));
2563558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    EXPECT_CALL(*mock_stream_, ReadFrames(_, _))
2564558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch        .WillOnce(Return(ERR_IO_PENDING));
2565558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    EXPECT_CALL(checkpoint, Call(3));
2566558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    // WriteFrames() must not be called again. GoogleMock will ensure that the
2567558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    // test fails if it is.
2568558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  }
2569558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
2570558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  CreateChannelAndConnectSuccessfully();
2571558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  checkpoint.Call(1);
2572558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  channel_->StartClosingHandshake(kWebSocketNormalClosure, "Close");
2573558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  checkpoint.Call(2);
2574558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
25754e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  *frames = CreateFrameVector(frames_init);
2576558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  read_callback.Run(OK);
2577558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  checkpoint.Call(3);
2578558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch}
2579558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
25801e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// Invalid close status codes should not be sent on the network.
25811e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)TEST_F(WebSocketChannelStreamTest, InvalidCloseStatusCodeNotSent) {
25821e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  static const InitFrame expected[] = {
25831e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose,
25845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       MASKED,      CLOSE_DATA(SERVER_ERROR, "")}};
25851e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
25861e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  EXPECT_CALL(*mock_stream_, GetSubProtocol()).Times(AnyNumber());
25875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_CALL(*mock_stream_, GetExtensions()).Times(AnyNumber());
25881e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  EXPECT_CALL(*mock_stream_, ReadFrames(_, _))
25891e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      .WillOnce(Return(ERR_IO_PENDING));
25901e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
25911e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  EXPECT_CALL(*mock_stream_, WriteFrames(EqualsFrames(expected), _));
25921e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
25931e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  CreateChannelAndConnectSuccessfully();
25941e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  channel_->StartClosingHandshake(999, "");
25951e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
25961e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
25971e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// A Close frame with a reason longer than 123 bytes cannot be sent on the
25981e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// network.
25991e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)TEST_F(WebSocketChannelStreamTest, LongCloseReasonNotSent) {
26001e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  static const InitFrame expected[] = {
26011e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose,
26025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       MASKED,      CLOSE_DATA(SERVER_ERROR, "")}};
26031e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
26041e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  EXPECT_CALL(*mock_stream_, GetSubProtocol()).Times(AnyNumber());
26055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_CALL(*mock_stream_, GetExtensions()).Times(AnyNumber());
26061e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  EXPECT_CALL(*mock_stream_, ReadFrames(_, _))
26071e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      .WillOnce(Return(ERR_IO_PENDING));
26081e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
26091e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  EXPECT_CALL(*mock_stream_, WriteFrames(EqualsFrames(expected), _));
26101e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
26111e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  CreateChannelAndConnectSuccessfully();
26121e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  channel_->StartClosingHandshake(1000, std::string(124, 'A'));
26131e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
26141e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
2615558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch// We generate code 1005, kWebSocketErrorNoStatusReceived, when there is no
2616558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch// status in the Close message from the other side. Code 1005 is not allowed to
2617558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch// appear on the wire, so we should not echo it back. See test
2618558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch// CloseWithNoPayloadGivesStatus1005, above, for confirmation that code 1005 is
2619558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch// correctly generated internally.
2620558790d6acca3451cf3a6b497803a5f07d0bec58Ben MurdochTEST_F(WebSocketChannelStreamTest, Code1005IsNotEchoed) {
26214e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  static const InitFrame frames[] = {
26224e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose, NOT_MASKED, ""}};
26234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  static const InitFrame expected[] = {
26244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose, MASKED, ""}};
2625558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  EXPECT_CALL(*mock_stream_, GetSubProtocol()).Times(AnyNumber());
26265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_CALL(*mock_stream_, GetExtensions()).Times(AnyNumber());
2627558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  EXPECT_CALL(*mock_stream_, ReadFrames(_, _))
26284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      .WillOnce(ReturnFrames(&frames))
2629558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      .WillRepeatedly(Return(ERR_IO_PENDING));
26304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  EXPECT_CALL(*mock_stream_, WriteFrames(EqualsFrames(expected), _))
2631558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      .WillOnce(Return(OK));
2632558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
2633558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  CreateChannelAndConnectSuccessfully();
2634558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch}
2635558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
2636f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)TEST_F(WebSocketChannelStreamTest, Code1005IsNotEchoedNull) {
2637f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  static const InitFrame frames[] = {
2638f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose, NOT_MASKED, NULL}};
2639f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  static const InitFrame expected[] = {
2640f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose, MASKED, ""}};
2641f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  EXPECT_CALL(*mock_stream_, GetSubProtocol()).Times(AnyNumber());
26425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_CALL(*mock_stream_, GetExtensions()).Times(AnyNumber());
26435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_CALL(*mock_stream_, ReadFrames(_, _))
26445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      .WillOnce(ReturnFrames(&frames))
26455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      .WillRepeatedly(Return(ERR_IO_PENDING));
26465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_CALL(*mock_stream_, WriteFrames(EqualsFrames(expected), _))
26475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      .WillOnce(Return(OK));
26485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
26495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CreateChannelAndConnectSuccessfully();
26505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
26515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
26525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Receiving an invalid UTF-8 payload in a Close frame causes us to fail the
26535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// connection.
26545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketChannelStreamTest, CloseFrameInvalidUtf8) {
26555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  static const InitFrame frames[] = {
26565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose,
26575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       NOT_MASKED, CLOSE_DATA(NORMAL_CLOSURE, "\xFF")}};
26585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  static const InitFrame expected[] = {
26595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose,
26605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       MASKED, CLOSE_DATA(PROTOCOL_ERROR, "Invalid UTF-8 in Close frame")}};
26615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
26625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_CALL(*mock_stream_, GetSubProtocol()).Times(AnyNumber());
26635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_CALL(*mock_stream_, GetExtensions()).Times(AnyNumber());
2664f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  EXPECT_CALL(*mock_stream_, ReadFrames(_, _))
2665f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      .WillOnce(ReturnFrames(&frames))
2666f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      .WillRepeatedly(Return(ERR_IO_PENDING));
2667f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  EXPECT_CALL(*mock_stream_, WriteFrames(EqualsFrames(expected), _))
2668f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      .WillOnce(Return(OK));
26695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_CALL(*mock_stream_, Close());
2670f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
2671f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  CreateChannelAndConnectSuccessfully();
2672f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
2673f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
2674558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch// RFC6455 5.5.2 "Upon receipt of a Ping frame, an endpoint MUST send a Pong
2675558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch// frame in response"
2676558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch// 5.5.3 "A Pong frame sent in response to a Ping frame must have identical
2677558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch// "Application data" as found in the message body of the Ping frame being
2678558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch// replied to."
2679558790d6acca3451cf3a6b497803a5f07d0bec58Ben MurdochTEST_F(WebSocketChannelStreamTest, PingRepliedWithPong) {
26804e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  static const InitFrame frames[] = {
26814e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      {FINAL_FRAME, WebSocketFrameHeader::kOpCodePing,
26824e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)       NOT_MASKED,  "Application data"}};
26834e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  static const InitFrame expected[] = {
26844e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      {FINAL_FRAME, WebSocketFrameHeader::kOpCodePong,
26854e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)       MASKED,      "Application data"}};
2686558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  EXPECT_CALL(*mock_stream_, GetSubProtocol()).Times(AnyNumber());
26875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_CALL(*mock_stream_, GetExtensions()).Times(AnyNumber());
2688558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  EXPECT_CALL(*mock_stream_, ReadFrames(_, _))
26894e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      .WillOnce(ReturnFrames(&frames))
2690558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      .WillRepeatedly(Return(ERR_IO_PENDING));
26914e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  EXPECT_CALL(*mock_stream_, WriteFrames(EqualsFrames(expected), _))
2692558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      .WillOnce(Return(OK));
2693558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
2694558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  CreateChannelAndConnectSuccessfully();
2695558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch}
2696558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
26975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// A ping with a NULL payload should be responded to with a Pong with a NULL
2698f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// payload.
26995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketChannelStreamTest, NullPingRepliedWithNullPong) {
2700f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  static const InitFrame frames[] = {
2701f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      {FINAL_FRAME, WebSocketFrameHeader::kOpCodePing, NOT_MASKED, NULL}};
2702f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  static const InitFrame expected[] = {
27035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      {FINAL_FRAME, WebSocketFrameHeader::kOpCodePong, MASKED, NULL}};
2704f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  EXPECT_CALL(*mock_stream_, GetSubProtocol()).Times(AnyNumber());
27055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_CALL(*mock_stream_, GetExtensions()).Times(AnyNumber());
2706f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  EXPECT_CALL(*mock_stream_, ReadFrames(_, _))
2707f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      .WillOnce(ReturnFrames(&frames))
2708f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      .WillRepeatedly(Return(ERR_IO_PENDING));
2709f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  EXPECT_CALL(*mock_stream_, WriteFrames(EqualsFrames(expected), _))
2710f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      .WillOnce(Return(OK));
2711f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
2712f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  CreateChannelAndConnectSuccessfully();
2713f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
2714f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
2715558790d6acca3451cf3a6b497803a5f07d0bec58Ben MurdochTEST_F(WebSocketChannelStreamTest, PongInTheMiddleOfDataMessage) {
27164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  static const InitFrame frames[] = {
27174e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      {FINAL_FRAME, WebSocketFrameHeader::kOpCodePing,
27184e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)       NOT_MASKED,  "Application data"}};
27194e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  static const InitFrame expected1[] = {
27204e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      {NOT_FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, MASKED, "Hello "}};
27214e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  static const InitFrame expected2[] = {
27224e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      {FINAL_FRAME, WebSocketFrameHeader::kOpCodePong,
27234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)       MASKED,      "Application data"}};
27244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  static const InitFrame expected3[] = {
27254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeContinuation,
27264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)       MASKED,      "World"}};
27274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  ScopedVector<WebSocketFrame>* read_frames;
2728558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  CompletionCallback read_callback;
2729558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  EXPECT_CALL(*mock_stream_, GetSubProtocol()).Times(AnyNumber());
27305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_CALL(*mock_stream_, GetExtensions()).Times(AnyNumber());
2731558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  EXPECT_CALL(*mock_stream_, ReadFrames(_, _))
27324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      .WillOnce(DoAll(SaveArg<0>(&read_frames),
2733558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch                      SaveArg<1>(&read_callback),
2734558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch                      Return(ERR_IO_PENDING)))
2735558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      .WillRepeatedly(Return(ERR_IO_PENDING));
2736558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  {
2737558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    InSequence s;
2738558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
27394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    EXPECT_CALL(*mock_stream_, WriteFrames(EqualsFrames(expected1), _))
2740558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch        .WillOnce(Return(OK));
27414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    EXPECT_CALL(*mock_stream_, WriteFrames(EqualsFrames(expected2), _))
2742558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch        .WillOnce(Return(OK));
27434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    EXPECT_CALL(*mock_stream_, WriteFrames(EqualsFrames(expected3), _))
2744558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch        .WillOnce(Return(OK));
2745558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  }
2746558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
2747558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  CreateChannelAndConnectSuccessfully();
2748558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  channel_->SendFrame(
2749558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      false, WebSocketFrameHeader::kOpCodeText, AsVector("Hello "));
27504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  *read_frames = CreateFrameVector(frames);
2751558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  read_callback.Run(OK);
2752558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  channel_->SendFrame(
2753558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      true, WebSocketFrameHeader::kOpCodeContinuation, AsVector("World"));
2754558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch}
2755558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
2756558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch// WriteFrames() may not be called until the previous write has completed.
2757558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch// WebSocketChannel must buffer writes that happen in the meantime.
2758558790d6acca3451cf3a6b497803a5f07d0bec58Ben MurdochTEST_F(WebSocketChannelStreamTest, WriteFramesOneAtATime) {
27594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  static const InitFrame expected1[] = {
27604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      {NOT_FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, MASKED, "Hello "}};
27614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  static const InitFrame expected2[] = {
27624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, MASKED, "World"}};
2763558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  CompletionCallback write_callback;
27641e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  Checkpoint checkpoint;
2765558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
2766558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  EXPECT_CALL(*mock_stream_, GetSubProtocol()).Times(AnyNumber());
27675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_CALL(*mock_stream_, GetExtensions()).Times(AnyNumber());
2768558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  EXPECT_CALL(*mock_stream_, ReadFrames(_, _)).WillOnce(Return(ERR_IO_PENDING));
2769558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  {
2770558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    InSequence s;
2771558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    EXPECT_CALL(checkpoint, Call(1));
27724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    EXPECT_CALL(*mock_stream_, WriteFrames(EqualsFrames(expected1), _))
2773558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch        .WillOnce(DoAll(SaveArg<1>(&write_callback), Return(ERR_IO_PENDING)));
2774558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    EXPECT_CALL(checkpoint, Call(2));
27754e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    EXPECT_CALL(*mock_stream_, WriteFrames(EqualsFrames(expected2), _))
2776558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch        .WillOnce(Return(ERR_IO_PENDING));
2777558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    EXPECT_CALL(checkpoint, Call(3));
2778558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  }
2779558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
2780558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  CreateChannelAndConnectSuccessfully();
2781558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  checkpoint.Call(1);
2782558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  channel_->SendFrame(
2783558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      false, WebSocketFrameHeader::kOpCodeText, AsVector("Hello "));
2784558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  channel_->SendFrame(
2785558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      true, WebSocketFrameHeader::kOpCodeText, AsVector("World"));
2786558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  checkpoint.Call(2);
2787558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  write_callback.Run(OK);
2788558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  checkpoint.Call(3);
2789558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch}
2790558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
2791558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch// WebSocketChannel must buffer frames while it is waiting for a write to
2792558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch// complete, and then send them in a single batch. The batching behaviour is
2793558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch// important to get good throughput in the "many small messages" case.
2794558790d6acca3451cf3a6b497803a5f07d0bec58Ben MurdochTEST_F(WebSocketChannelStreamTest, WaitingMessagesAreBatched) {
2795558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  static const char input_letters[] = "Hello";
27964e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  static const InitFrame expected1[] = {
27974e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, MASKED, "H"}};
27984e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  static const InitFrame expected2[] = {
27994e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, MASKED, "e"},
28004e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, MASKED, "l"},
28014e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, MASKED, "l"},
28024e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, MASKED, "o"}};
2803558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  CompletionCallback write_callback;
2804558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
2805558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  EXPECT_CALL(*mock_stream_, GetSubProtocol()).Times(AnyNumber());
28065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_CALL(*mock_stream_, GetExtensions()).Times(AnyNumber());
2807558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  EXPECT_CALL(*mock_stream_, ReadFrames(_, _)).WillOnce(Return(ERR_IO_PENDING));
2808558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  {
2809558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    InSequence s;
28104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    EXPECT_CALL(*mock_stream_, WriteFrames(EqualsFrames(expected1), _))
2811558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch        .WillOnce(DoAll(SaveArg<1>(&write_callback), Return(ERR_IO_PENDING)));
28124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    EXPECT_CALL(*mock_stream_, WriteFrames(EqualsFrames(expected2), _))
2813558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch        .WillOnce(Return(ERR_IO_PENDING));
2814558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  }
2815558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
2816558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  CreateChannelAndConnectSuccessfully();
2817558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  for (size_t i = 0; i < strlen(input_letters); ++i) {
2818558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    channel_->SendFrame(true,
2819558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch                        WebSocketFrameHeader::kOpCodeText,
2820558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch                        std::vector<char>(1, input_letters[i]));
2821558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  }
2822558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  write_callback.Run(OK);
2823558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch}
2824558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
2825effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// When the renderer sends more on a channel than it has quota for, we send the
2826effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// remote server a kWebSocketErrorGoingAway error code.
2827effb81e5f8246d0db0270817048dc992db66e9fbBen MurdochTEST_F(WebSocketChannelStreamTest, SendGoingAwayOnRendererQuotaExceeded) {
28284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  static const InitFrame expected[] = {
28294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose,
28305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       MASKED,      CLOSE_DATA(GOING_AWAY, "")}};
2831558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  EXPECT_CALL(*mock_stream_, GetSubProtocol()).Times(AnyNumber());
28325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_CALL(*mock_stream_, GetExtensions()).Times(AnyNumber());
2833558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  EXPECT_CALL(*mock_stream_, ReadFrames(_, _)).WillOnce(Return(ERR_IO_PENDING));
28344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  EXPECT_CALL(*mock_stream_, WriteFrames(EqualsFrames(expected), _))
2835558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      .WillOnce(Return(OK));
2836558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  EXPECT_CALL(*mock_stream_, Close());
2837558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
2838558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  CreateChannelAndConnectSuccessfully();
2839558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  channel_->SendFrame(true,
2840558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch                      WebSocketFrameHeader::kOpCodeText,
2841558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch                      std::vector<char>(kDefaultInitialQuota + 1, 'C'));
2842558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch}
2843558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
2844558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch// For convenience, most of these tests use Text frames. However, the WebSocket
2845558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch// protocol also has Binary frames and those need to be 8-bit clean. For the
2846558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch// sake of completeness, this test verifies that they are.
2847558790d6acca3451cf3a6b497803a5f07d0bec58Ben MurdochTEST_F(WebSocketChannelStreamTest, WrittenBinaryFramesAre8BitClean) {
28484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  ScopedVector<WebSocketFrame>* frames = NULL;
2849558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
2850558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  EXPECT_CALL(*mock_stream_, GetSubProtocol()).Times(AnyNumber());
28515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_CALL(*mock_stream_, GetExtensions()).Times(AnyNumber());
2852558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  EXPECT_CALL(*mock_stream_, ReadFrames(_, _)).WillOnce(Return(ERR_IO_PENDING));
2853558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  EXPECT_CALL(*mock_stream_, WriteFrames(_, _))
28544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      .WillOnce(DoAll(SaveArg<0>(&frames), Return(ERR_IO_PENDING)));
2855558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
2856558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  CreateChannelAndConnectSuccessfully();
2857558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  channel_->SendFrame(
2858558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      true,
2859558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      WebSocketFrameHeader::kOpCodeBinary,
2860558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      std::vector<char>(kBinaryBlob, kBinaryBlob + kBinaryBlobSize));
28614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  ASSERT_TRUE(frames != NULL);
28624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  ASSERT_EQ(1U, frames->size());
28634e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  const WebSocketFrame* out_frame = (*frames)[0];
28644e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  EXPECT_EQ(kBinaryBlobSize, out_frame->header.payload_length);
28651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  ASSERT_TRUE(out_frame->data.get());
28664e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  EXPECT_EQ(0, memcmp(kBinaryBlob, out_frame->data->data(), kBinaryBlobSize));
2867558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch}
2868558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
2869558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch// Test the read path for 8-bit cleanliness as well.
2870558790d6acca3451cf3a6b497803a5f07d0bec58Ben MurdochTEST_F(WebSocketChannelEventInterfaceTest, ReadBinaryFramesAre8BitClean) {
28714e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  scoped_ptr<WebSocketFrame> frame(
28724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      new WebSocketFrame(WebSocketFrameHeader::kOpCodeBinary));
28734e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  WebSocketFrameHeader& frame_header = frame->header;
28744e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  frame_header.final = true;
28754e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  frame_header.payload_length = kBinaryBlobSize;
28764e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  frame->data = new IOBuffer(kBinaryBlobSize);
28774e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  memcpy(frame->data->data(), kBinaryBlob, kBinaryBlobSize);
28784e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  ScopedVector<WebSocketFrame> frames;
28794e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  frames.push_back(frame.release());
2880558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  scoped_ptr<ReadableFakeWebSocketStream> stream(
2881558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      new ReadableFakeWebSocketStream);
2882558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  stream->PrepareRawReadFrames(
28834e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      ReadableFakeWebSocketStream::SYNC, OK, frames.Pass());
2884558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  set_stream(stream.Pass());
28855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _, _));
2886558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  EXPECT_CALL(*event_interface_, OnFlowControl(_));
2887558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  EXPECT_CALL(*event_interface_,
2888558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch              OnDataFrame(true,
2889558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch                          WebSocketFrameHeader::kOpCodeBinary,
2890558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch                          std::vector<char>(kBinaryBlob,
2891558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch                                            kBinaryBlob + kBinaryBlobSize)));
2892558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
2893558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  CreateChannelAndConnectSuccessfully();
2894558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch}
2895558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
28965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Invalid UTF-8 is not permitted in Text frames.
28975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketChannelSendUtf8Test, InvalidUtf8Rejected) {
28985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_CALL(
28995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      *event_interface_,
29005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      OnFailChannel("Browser sent a text frame containing invalid UTF-8"));
29015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
29025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CreateChannelAndConnectSuccessfully();
29035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
29045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  channel_->SendFrame(
29055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      true, WebSocketFrameHeader::kOpCodeText, AsVector("\xff"));
29065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
29075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
29085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// A Text message cannot end with a partial UTF-8 character.
29095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketChannelSendUtf8Test, IncompleteCharacterInFinalFrame) {
29105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_CALL(
29115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      *event_interface_,
29125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      OnFailChannel("Browser sent a text frame containing invalid UTF-8"));
29135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
29145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CreateChannelAndConnectSuccessfully();
29155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
29165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  channel_->SendFrame(
29175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      true, WebSocketFrameHeader::kOpCodeText, AsVector("\xc2"));
29185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
29195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
29205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// A non-final Text frame may end with a partial UTF-8 character (compare to
29215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// previous test).
29225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketChannelSendUtf8Test, IncompleteCharacterInNonFinalFrame) {
29235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CreateChannelAndConnectSuccessfully();
29245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
29255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  channel_->SendFrame(
29265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      false, WebSocketFrameHeader::kOpCodeText, AsVector("\xc2"));
29275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
29285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
29295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// UTF-8 parsing context must be retained between frames.
29305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketChannelSendUtf8Test, ValidCharacterSplitBetweenFrames) {
29315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CreateChannelAndConnectSuccessfully();
29325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
29335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  channel_->SendFrame(
29345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      false, WebSocketFrameHeader::kOpCodeText, AsVector("\xf1"));
29355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  channel_->SendFrame(true,
29365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                      WebSocketFrameHeader::kOpCodeContinuation,
29375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                      AsVector("\x80\xa0\xbf"));
29385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
29395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
29405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Similarly, an invalid character should be detected even if split.
29415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketChannelSendUtf8Test, InvalidCharacterSplit) {
29425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_CALL(
29435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      *event_interface_,
29445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      OnFailChannel("Browser sent a text frame containing invalid UTF-8"));
29455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
29465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CreateChannelAndConnectSuccessfully();
29475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
29485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  channel_->SendFrame(
29495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      false, WebSocketFrameHeader::kOpCodeText, AsVector("\xe1"));
29505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  channel_->SendFrame(true,
29515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                      WebSocketFrameHeader::kOpCodeContinuation,
29525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                      AsVector("\x80\xa0\xbf"));
29535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
29545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
29555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// An invalid character must be detected in continuation frames.
29565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketChannelSendUtf8Test, InvalidByteInContinuation) {
29575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_CALL(
29585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      *event_interface_,
29595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      OnFailChannel("Browser sent a text frame containing invalid UTF-8"));
29605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
29615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CreateChannelAndConnectSuccessfully();
29625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
29635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  channel_->SendFrame(
29645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      false, WebSocketFrameHeader::kOpCodeText, AsVector("foo"));
29655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  channel_->SendFrame(
29665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      false, WebSocketFrameHeader::kOpCodeContinuation, AsVector("bar"));
29675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  channel_->SendFrame(
29685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      true, WebSocketFrameHeader::kOpCodeContinuation, AsVector("\xff"));
29695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
29705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
29715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// However, continuation frames of a Binary frame will not be tested for UTF-8
29725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// validity.
29735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketChannelSendUtf8Test, BinaryContinuationNotChecked) {
29745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CreateChannelAndConnectSuccessfully();
29755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
29765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  channel_->SendFrame(
29775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      false, WebSocketFrameHeader::kOpCodeBinary, AsVector("foo"));
29785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  channel_->SendFrame(
29795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      false, WebSocketFrameHeader::kOpCodeContinuation, AsVector("bar"));
29805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  channel_->SendFrame(
29815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      true, WebSocketFrameHeader::kOpCodeContinuation, AsVector("\xff"));
29825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
29835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
29845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Multiple text messages can be validated without the validation state getting
29855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// confused.
29865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketChannelSendUtf8Test, ValidateMultipleTextMessages) {
29875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CreateChannelAndConnectSuccessfully();
29885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
29895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  channel_->SendFrame(true, WebSocketFrameHeader::kOpCodeText, AsVector("foo"));
29905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  channel_->SendFrame(true, WebSocketFrameHeader::kOpCodeText, AsVector("bar"));
29915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
29925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
29935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// UTF-8 validation is enforced on received Text frames.
29945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketChannelEventInterfaceTest, ReceivedInvalidUtf8) {
29955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_ptr<ReadableFakeWebSocketStream> stream(
29965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      new ReadableFakeWebSocketStream);
29975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  static const InitFrame frames[] = {
29985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, NOT_MASKED, "\xff"}};
29995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  stream->PrepareReadFrames(ReadableFakeWebSocketStream::SYNC, OK, frames);
30005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  set_stream(stream.Pass());
30015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
30025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _, _));
30035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_CALL(*event_interface_, OnFlowControl(kDefaultInitialQuota));
30045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_CALL(*event_interface_,
30055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              OnFailChannel("Could not decode a text frame as UTF-8."));
30065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
30075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CreateChannelAndConnectSuccessfully();
30085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::MessageLoop::current()->RunUntilIdle();
30095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
30105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
30115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Invalid UTF-8 is not sent over the network.
30125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketChannelStreamTest, InvalidUtf8TextFrameNotSent) {
30135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  static const InitFrame expected[] = {{FINAL_FRAME,
30145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                        WebSocketFrameHeader::kOpCodeClose,
30155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                        MASKED, CLOSE_DATA(GOING_AWAY, "")}};
30165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_CALL(*mock_stream_, GetSubProtocol()).Times(AnyNumber());
30175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_CALL(*mock_stream_, GetExtensions()).Times(AnyNumber());
30185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_CALL(*mock_stream_, ReadFrames(_, _))
30195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      .WillRepeatedly(Return(ERR_IO_PENDING));
30205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_CALL(*mock_stream_, WriteFrames(EqualsFrames(expected), _))
30215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      .WillOnce(Return(OK));
30225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_CALL(*mock_stream_, Close()).Times(1);
30235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
30245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CreateChannelAndConnectSuccessfully();
30255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
30265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  channel_->SendFrame(
30275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      true, WebSocketFrameHeader::kOpCodeText, AsVector("\xff"));
30285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
30295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
30305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// The rest of the tests for receiving invalid UTF-8 test the communication with
30315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// the server. Since there is only one code path, it would be redundant to
30325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// perform the same tests on the EventInterface as well.
30335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
30345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// If invalid UTF-8 is received in a Text frame, the connection is failed.
30355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketChannelReceiveUtf8Test, InvalidTextFrameRejected) {
30365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  static const InitFrame frames[] = {
30375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, NOT_MASKED, "\xff"}};
30385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  static const InitFrame expected[] = {
30395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose, MASKED,
30405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       CLOSE_DATA(PROTOCOL_ERROR, "Invalid UTF-8 in text frame")}};
30415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  {
30425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    InSequence s;
30435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    EXPECT_CALL(*mock_stream_, ReadFrames(_, _))
30445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        .WillOnce(ReturnFrames(&frames))
30455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        .WillRepeatedly(Return(ERR_IO_PENDING));
30465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    EXPECT_CALL(*mock_stream_, WriteFrames(EqualsFrames(expected), _))
30475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        .WillOnce(Return(OK));
30485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    EXPECT_CALL(*mock_stream_, Close()).Times(1);
30495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
30505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
30515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CreateChannelAndConnectSuccessfully();
30525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
30535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
30545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// A received Text message is not permitted to end with a partial UTF-8
30555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// character.
30565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketChannelReceiveUtf8Test, IncompleteCharacterReceived) {
30575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  static const InitFrame frames[] = {
30585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, NOT_MASKED, "\xc2"}};
30595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  static const InitFrame expected[] = {
30605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose, MASKED,
30615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       CLOSE_DATA(PROTOCOL_ERROR, "Invalid UTF-8 in text frame")}};
30625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_CALL(*mock_stream_, ReadFrames(_, _))
30635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      .WillOnce(ReturnFrames(&frames))
30645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      .WillRepeatedly(Return(ERR_IO_PENDING));
30655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_CALL(*mock_stream_, WriteFrames(EqualsFrames(expected), _))
30665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      .WillOnce(Return(OK));
30675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_CALL(*mock_stream_, Close()).Times(1);
30685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
30695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CreateChannelAndConnectSuccessfully();
30705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
30715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
30725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// However, a non-final Text frame may end with a partial UTF-8 character.
30735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketChannelReceiveUtf8Test, IncompleteCharacterIncompleteMessage) {
30745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  static const InitFrame frames[] = {
30755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      {NOT_FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, NOT_MASKED, "\xc2"}};
30765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_CALL(*mock_stream_, ReadFrames(_, _))
30775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      .WillOnce(ReturnFrames(&frames))
30785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      .WillRepeatedly(Return(ERR_IO_PENDING));
30795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
30805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CreateChannelAndConnectSuccessfully();
30815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
30825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
30835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// However, it will become an error if it is followed by an empty final frame.
30845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketChannelReceiveUtf8Test, TricksyIncompleteCharacter) {
30855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  static const InitFrame frames[] = {
30865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      {NOT_FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, NOT_MASKED, "\xc2"},
30875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeContinuation, NOT_MASKED, ""}};
30885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  static const InitFrame expected[] = {
30895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose, MASKED,
30905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       CLOSE_DATA(PROTOCOL_ERROR, "Invalid UTF-8 in text frame")}};
30915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_CALL(*mock_stream_, ReadFrames(_, _))
30925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      .WillOnce(ReturnFrames(&frames))
30935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      .WillRepeatedly(Return(ERR_IO_PENDING));
30945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_CALL(*mock_stream_, WriteFrames(EqualsFrames(expected), _))
30955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      .WillOnce(Return(OK));
30965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_CALL(*mock_stream_, Close()).Times(1);
30975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
30985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CreateChannelAndConnectSuccessfully();
30995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
31005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
31015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// UTF-8 parsing context must be retained between received frames of the same
31025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// message.
31035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketChannelReceiveUtf8Test, ReceivedParsingContextRetained) {
31045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  static const InitFrame frames[] = {
31055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      {NOT_FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, NOT_MASKED, "\xf1"},
31065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeContinuation,
31075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       NOT_MASKED,  "\x80\xa0\xbf"}};
31085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_CALL(*mock_stream_, ReadFrames(_, _))
31095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      .WillOnce(ReturnFrames(&frames))
31105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      .WillRepeatedly(Return(ERR_IO_PENDING));
31115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
31125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CreateChannelAndConnectSuccessfully();
31135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
31145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
31155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// An invalid character must be detected even if split between frames.
31165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketChannelReceiveUtf8Test, SplitInvalidCharacterReceived) {
31175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  static const InitFrame frames[] = {
31185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      {NOT_FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, NOT_MASKED, "\xe1"},
31195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeContinuation,
31205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       NOT_MASKED,  "\x80\xa0\xbf"}};
31215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  static const InitFrame expected[] = {
31225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose, MASKED,
31235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       CLOSE_DATA(PROTOCOL_ERROR, "Invalid UTF-8 in text frame")}};
31245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_CALL(*mock_stream_, ReadFrames(_, _))
31255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      .WillOnce(ReturnFrames(&frames))
31265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      .WillRepeatedly(Return(ERR_IO_PENDING));
31275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_CALL(*mock_stream_, WriteFrames(EqualsFrames(expected), _))
31285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      .WillOnce(Return(OK));
31295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_CALL(*mock_stream_, Close()).Times(1);
31305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
31315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CreateChannelAndConnectSuccessfully();
31325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
31335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
31345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// An invalid character received in a continuation frame must be detected.
31355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketChannelReceiveUtf8Test, InvalidReceivedIncontinuation) {
31365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  static const InitFrame frames[] = {
31375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      {NOT_FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, NOT_MASKED, "foo"},
31385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      {NOT_FINAL_FRAME, WebSocketFrameHeader::kOpCodeContinuation,
31395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       NOT_MASKED,      "bar"},
31405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      {FINAL_FRAME,     WebSocketFrameHeader::kOpCodeContinuation,
31415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       NOT_MASKED,      "\xff"}};
31425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  static const InitFrame expected[] = {
31435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose, MASKED,
31445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       CLOSE_DATA(PROTOCOL_ERROR, "Invalid UTF-8 in text frame")}};
31455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_CALL(*mock_stream_, ReadFrames(_, _))
31465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      .WillOnce(ReturnFrames(&frames))
31475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      .WillRepeatedly(Return(ERR_IO_PENDING));
31485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_CALL(*mock_stream_, WriteFrames(EqualsFrames(expected), _))
31495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      .WillOnce(Return(OK));
31505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_CALL(*mock_stream_, Close()).Times(1);
31515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
31525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CreateChannelAndConnectSuccessfully();
31535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
31545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
31555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Continuations of binary frames must not be tested for UTF-8 validity.
31565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketChannelReceiveUtf8Test, ReceivedBinaryNotUtf8Tested) {
31575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  static const InitFrame frames[] = {
31585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      {NOT_FINAL_FRAME, WebSocketFrameHeader::kOpCodeBinary, NOT_MASKED, "foo"},
31595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      {NOT_FINAL_FRAME, WebSocketFrameHeader::kOpCodeContinuation,
31605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       NOT_MASKED,      "bar"},
31615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      {FINAL_FRAME,     WebSocketFrameHeader::kOpCodeContinuation,
31625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       NOT_MASKED,      "\xff"}};
31635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_CALL(*mock_stream_, ReadFrames(_, _))
31645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      .WillOnce(ReturnFrames(&frames))
31655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      .WillRepeatedly(Return(ERR_IO_PENDING));
31665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
31675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CreateChannelAndConnectSuccessfully();
31685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
31695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
31705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Multiple Text messages can be validated.
31715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketChannelReceiveUtf8Test, ValidateMultipleReceived) {
31725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  static const InitFrame frames[] = {
31735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, NOT_MASKED, "foo"},
31745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, NOT_MASKED, "bar"}};
31755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_CALL(*mock_stream_, ReadFrames(_, _))
31765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      .WillOnce(ReturnFrames(&frames))
31775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      .WillRepeatedly(Return(ERR_IO_PENDING));
31785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
31795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CreateChannelAndConnectSuccessfully();
31805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
31815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3182a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// A new data message cannot start in the middle of another data message.
3183a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)TEST_F(WebSocketChannelEventInterfaceTest, BogusContinuation) {
3184a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  scoped_ptr<ReadableFakeWebSocketStream> stream(
3185a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      new ReadableFakeWebSocketStream);
3186a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  static const InitFrame frames[] = {
3187a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      {NOT_FINAL_FRAME, WebSocketFrameHeader::kOpCodeBinary,
3188a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)       NOT_MASKED, "frame1"},
3189a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText,
3190a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)       NOT_MASKED, "frame2"}};
3191a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  stream->PrepareReadFrames(ReadableFakeWebSocketStream::SYNC, OK, frames);
3192a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  set_stream(stream.Pass());
3193a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
3194a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _, _));
3195a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  EXPECT_CALL(*event_interface_, OnFlowControl(kDefaultInitialQuota));
3196a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  EXPECT_CALL(
3197a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      *event_interface_,
3198a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      OnDataFrame(
3199a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          false, WebSocketFrameHeader::kOpCodeBinary, AsVector("frame1")));
3200a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  EXPECT_CALL(
3201a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      *event_interface_,
3202a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      OnFailChannel(
3203a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          "Received start of new message but previous message is unfinished."));
3204a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
3205a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  CreateChannelAndConnectSuccessfully();
3206a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
3207a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
3208a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// A new message cannot start with a Continuation frame.
3209a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)TEST_F(WebSocketChannelEventInterfaceTest, MessageStartingWithContinuation) {
3210a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  scoped_ptr<ReadableFakeWebSocketStream> stream(
3211a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      new ReadableFakeWebSocketStream);
3212a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  static const InitFrame frames[] = {
3213a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeContinuation,
3214a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)       NOT_MASKED, "continuation"}};
3215a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  stream->PrepareReadFrames(ReadableFakeWebSocketStream::SYNC, OK, frames);
3216a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  set_stream(stream.Pass());
3217a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
3218a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _, _));
3219a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  EXPECT_CALL(*event_interface_, OnFlowControl(kDefaultInitialQuota));
3220a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  EXPECT_CALL(*event_interface_,
3221a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)              OnFailChannel("Received unexpected continuation frame."));
3222a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
3223a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  CreateChannelAndConnectSuccessfully();
3224a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
3225a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
3226a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// A frame passed to the renderer must be either non-empty or have the final bit
3227a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// set.
3228a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)TEST_F(WebSocketChannelEventInterfaceTest, DataFramesNonEmptyOrFinal) {
3229a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  scoped_ptr<ReadableFakeWebSocketStream> stream(
3230a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      new ReadableFakeWebSocketStream);
3231a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  static const InitFrame frames[] = {
3232a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      {NOT_FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, NOT_MASKED, ""},
3233a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      {NOT_FINAL_FRAME, WebSocketFrameHeader::kOpCodeContinuation,
3234a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)       NOT_MASKED, ""},
3235a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeContinuation, NOT_MASKED, ""}};
3236a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  stream->PrepareReadFrames(ReadableFakeWebSocketStream::SYNC, OK, frames);
3237a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  set_stream(stream.Pass());
3238a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
3239a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _, _));
3240a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  EXPECT_CALL(*event_interface_, OnFlowControl(kDefaultInitialQuota));
3241a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  EXPECT_CALL(
3242a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      *event_interface_,
3243a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      OnDataFrame(true, WebSocketFrameHeader::kOpCodeText, AsVector("")));
3244a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
3245a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  CreateChannelAndConnectSuccessfully();
3246a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
3247a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
324846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)// Calls to OnSSLCertificateError() must be passed through to the event
324946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)// interface with the correct URL attached.
325046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)TEST_F(WebSocketChannelEventInterfaceTest, OnSSLCertificateErrorCalled) {
325146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  const GURL wss_url("wss://example.com/sslerror");
325246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  connect_data_.socket_url = wss_url;
325346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  const SSLInfo ssl_info;
325446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  const bool fatal = true;
325546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  scoped_ptr<WebSocketEventInterface::SSLErrorCallbacks> fake_callbacks(
325646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      new FakeSSLErrorCallbacks);
325746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
325846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  EXPECT_CALL(*event_interface_,
325946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)              OnSSLCertificateErrorCalled(NotNull(), wss_url, _, fatal));
326046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
326146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  CreateChannelAndConnect();
326246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  connect_data_.creator.connect_delegate->OnSSLCertificateError(
326346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      fake_callbacks.Pass(), ssl_info, fatal);
326446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}
326546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
3266558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch// If we receive another frame after Close, it is not valid. It is not
3267558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch// completely clear what behaviour is required from the standard in this case,
3268558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch// but the current implementation fails the connection. Since a Close has
3269558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch// already been sent, this just means closing the connection.
3270558790d6acca3451cf3a6b497803a5f07d0bec58Ben MurdochTEST_F(WebSocketChannelStreamTest, PingAfterCloseIsRejected) {
32714e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  static const InitFrame frames[] = {
32724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose,
32734e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)       NOT_MASKED,  CLOSE_DATA(NORMAL_CLOSURE, "OK")},
32744e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      {FINAL_FRAME, WebSocketFrameHeader::kOpCodePing,
32754e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)       NOT_MASKED,  "Ping body"}};
32764e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  static const InitFrame expected[] = {
32774e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose,
32784e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)       MASKED,      CLOSE_DATA(NORMAL_CLOSURE, "OK")}};
3279558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  EXPECT_CALL(*mock_stream_, GetSubProtocol()).Times(AnyNumber());
32805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_CALL(*mock_stream_, GetExtensions()).Times(AnyNumber());
3281558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  EXPECT_CALL(*mock_stream_, ReadFrames(_, _))
32824e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      .WillOnce(ReturnFrames(&frames))
3283558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      .WillRepeatedly(Return(ERR_IO_PENDING));
3284558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  {
3285558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    // We only need to verify the relative order of WriteFrames() and
3286558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    // Close(). The current implementation calls WriteFrames() for the Close
3287558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    // frame before calling ReadFrames() again, but that is an implementation
3288558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    // detail and better not to consider required behaviour.
3289558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    InSequence s;
32904e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    EXPECT_CALL(*mock_stream_, WriteFrames(EqualsFrames(expected), _))
3291558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch        .WillOnce(Return(OK));
3292558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    EXPECT_CALL(*mock_stream_, Close()).Times(1);
3293558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  }
3294558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
3295558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  CreateChannelAndConnectSuccessfully();
3296558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch}
3297558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
32984e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// A protocol error from the remote server should result in a close frame with
32994e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// status 1002, followed by the connection closing.
33004e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)TEST_F(WebSocketChannelStreamTest, ProtocolError) {
33014e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  static const InitFrame expected[] = {
33024e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose,
33034e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)       MASKED,      CLOSE_DATA(PROTOCOL_ERROR, "WebSocket Protocol Error")}};
33044e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  EXPECT_CALL(*mock_stream_, GetSubProtocol()).Times(AnyNumber());
33055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_CALL(*mock_stream_, GetExtensions()).Times(AnyNumber());
33064e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  EXPECT_CALL(*mock_stream_, ReadFrames(_, _))
33074e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      .WillOnce(Return(ERR_WS_PROTOCOL_ERROR));
33084e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  EXPECT_CALL(*mock_stream_, WriteFrames(EqualsFrames(expected), _))
33094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      .WillOnce(Return(OK));
33104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  EXPECT_CALL(*mock_stream_, Close());
33114e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
33124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  CreateChannelAndConnectSuccessfully();
33134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
33144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
33151e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// Set the closing handshake timeout to a very tiny value before connecting.
33161e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)class WebSocketChannelStreamTimeoutTest : public WebSocketChannelStreamTest {
33171e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) protected:
33181e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  WebSocketChannelStreamTimeoutTest() {}
33191e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
33201e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  virtual void CreateChannelAndConnectSuccessfully() OVERRIDE {
33211e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    set_stream(mock_stream_.Pass());
33221e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    CreateChannelAndConnect();
3323effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    channel_->SendFlowControl(kPlentyOfQuota);
33241e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    channel_->SetClosingHandshakeTimeoutForTesting(
33251e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        TimeDelta::FromMilliseconds(kVeryTinyTimeoutMillis));
3326f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    connect_data_.creator.connect_delegate->OnSuccess(stream_.Pass());
33271e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  }
33281e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)};
33291e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
33301e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// In this case the server initiates the closing handshake with a Close
33311e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// message. WebSocketChannel responds with a matching Close message, and waits
33321e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// for the server to close the TCP/IP connection. The server never closes the
33331e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// connection, so the closing handshake times out and WebSocketChannel closes
33341e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// the connection itself.
33351e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)TEST_F(WebSocketChannelStreamTimeoutTest, ServerInitiatedCloseTimesOut) {
33361e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  static const InitFrame frames[] = {
33371e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose,
33381e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)       NOT_MASKED,  CLOSE_DATA(NORMAL_CLOSURE, "OK")}};
33391e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  static const InitFrame expected[] = {
33401e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose,
33411e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)       MASKED,      CLOSE_DATA(NORMAL_CLOSURE, "OK")}};
33421e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  EXPECT_CALL(*mock_stream_, GetSubProtocol()).Times(AnyNumber());
33435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_CALL(*mock_stream_, GetExtensions()).Times(AnyNumber());
33441e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  EXPECT_CALL(*mock_stream_, ReadFrames(_, _))
33451e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      .WillOnce(ReturnFrames(&frames))
33461e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      .WillRepeatedly(Return(ERR_IO_PENDING));
33471e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  Checkpoint checkpoint;
33481e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  TestClosure completion;
33491e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  {
33501e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    InSequence s;
33511e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    EXPECT_CALL(*mock_stream_, WriteFrames(EqualsFrames(expected), _))
33521e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        .WillOnce(Return(OK));
33531e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    EXPECT_CALL(checkpoint, Call(1));
33541e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    EXPECT_CALL(*mock_stream_, Close())
33551e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        .WillOnce(InvokeClosure(completion.closure()));
33561e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  }
33571e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
33581e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  CreateChannelAndConnectSuccessfully();
33591e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  checkpoint.Call(1);
33601e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  completion.WaitForResult();
33611e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
33621e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
33631e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// In this case the client initiates the closing handshake by sending a Close
33641e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// message. WebSocketChannel waits for a Close message in response from the
33651e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// server. The server never responds to the Close message, so the closing
33661e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// handshake times out and WebSocketChannel closes the connection.
33671e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)TEST_F(WebSocketChannelStreamTimeoutTest, ClientInitiatedCloseTimesOut) {
33681e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  static const InitFrame expected[] = {
33691e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose,
33701e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)       MASKED,      CLOSE_DATA(NORMAL_CLOSURE, "OK")}};
33711e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  EXPECT_CALL(*mock_stream_, GetSubProtocol()).Times(AnyNumber());
33725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_CALL(*mock_stream_, GetExtensions()).Times(AnyNumber());
33731e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  EXPECT_CALL(*mock_stream_, ReadFrames(_, _))
33741e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      .WillRepeatedly(Return(ERR_IO_PENDING));
33751e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  TestClosure completion;
33761e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  {
33771e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    InSequence s;
33781e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    EXPECT_CALL(*mock_stream_, WriteFrames(EqualsFrames(expected), _))
33791e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        .WillOnce(Return(OK));
33801e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    EXPECT_CALL(*mock_stream_, Close())
33811e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        .WillOnce(InvokeClosure(completion.closure()));
33821e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  }
33831e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
33841e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  CreateChannelAndConnectSuccessfully();
33851e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  channel_->StartClosingHandshake(kWebSocketNormalClosure, "OK");
33861e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  completion.WaitForResult();
33871e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
33881e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
33891e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// In this case the client initiates the closing handshake and the server
33901e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// responds with a matching Close message. WebSocketChannel waits for the server
33911e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// to close the TCP/IP connection, but it never does. The closing handshake
33921e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// times out and WebSocketChannel closes the connection.
33931e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)TEST_F(WebSocketChannelStreamTimeoutTest, ConnectionCloseTimesOut) {
33941e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  static const InitFrame expected[] = {
33951e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose,
33961e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)       MASKED,      CLOSE_DATA(NORMAL_CLOSURE, "OK")}};
33971e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  static const InitFrame frames[] = {
33981e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose,
33991e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)       NOT_MASKED,  CLOSE_DATA(NORMAL_CLOSURE, "OK")}};
34001e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  EXPECT_CALL(*mock_stream_, GetSubProtocol()).Times(AnyNumber());
34015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_CALL(*mock_stream_, GetExtensions()).Times(AnyNumber());
34021e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  TestClosure completion;
34031e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  ScopedVector<WebSocketFrame>* read_frames = NULL;
34041e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  CompletionCallback read_callback;
34051e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  {
34061e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    InSequence s;
34071e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    // Copy the arguments to ReadFrames so that the test can call the callback
34081e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    // after it has send the close message.
34091e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    EXPECT_CALL(*mock_stream_, ReadFrames(_, _))
34101e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        .WillOnce(DoAll(SaveArg<0>(&read_frames),
34111e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                        SaveArg<1>(&read_callback),
34121e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                        Return(ERR_IO_PENDING)));
34131e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    // The first real event that happens is the client sending the Close
34141e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    // message.
34151e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    EXPECT_CALL(*mock_stream_, WriteFrames(EqualsFrames(expected), _))
34161e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        .WillOnce(Return(OK));
34171e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    // The |read_frames| callback is called (from this test case) at this
34181e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    // point. ReadFrames is called again by WebSocketChannel, waiting for
34191e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    // ERR_CONNECTION_CLOSED.
34201e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    EXPECT_CALL(*mock_stream_, ReadFrames(_, _))
34211e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        .WillOnce(Return(ERR_IO_PENDING));
34221e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    // The timeout happens and so WebSocketChannel closes the stream.
34231e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    EXPECT_CALL(*mock_stream_, Close())
34241e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        .WillOnce(InvokeClosure(completion.closure()));
34251e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  }
34261e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
34271e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  CreateChannelAndConnectSuccessfully();
34281e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  channel_->StartClosingHandshake(kWebSocketNormalClosure, "OK");
34291e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  ASSERT_TRUE(read_frames);
34301e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // Provide the "Close" message from the server.
34311e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  *read_frames = CreateFrameVector(frames);
34321e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  read_callback.Run(OK);
34331e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  completion.WaitForResult();
34341e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
34351e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
34369ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch}  // namespace
34379ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch}  // namespace net
3438