summaryrefslogtreecommitdiffstats
path: root/net/websockets/websocket_channel_test.cc
diff options
context:
space:
mode:
Diffstat (limited to 'net/websockets/websocket_channel_test.cc')
-rw-r--r--net/websockets/websocket_channel_test.cc893
1 files changed, 369 insertions, 524 deletions
diff --git a/net/websockets/websocket_channel_test.cc b/net/websockets/websocket_channel_test.cc
index 25e9cdc..361f69f 100644
--- a/net/websockets/websocket_channel_test.cc
+++ b/net/websockets/websocket_channel_test.cc
@@ -34,40 +34,37 @@
#define CLOSE_DATA(code, string) WEBSOCKET_CLOSE_CODE_AS_STRING_##code string
#define WEBSOCKET_CLOSE_CODE_AS_STRING_NORMAL_CLOSURE "\x03\xe8"
#define WEBSOCKET_CLOSE_CODE_AS_STRING_GOING_AWAY "\x03\xe9"
+#define WEBSOCKET_CLOSE_CODE_AS_STRING_PROTOCOL_ERROR "\x03\xea"
#define WEBSOCKET_CLOSE_CODE_AS_STRING_SERVER_ERROR "\x03\xf3"
namespace net {
-// Printing helpers to allow GoogleMock to print frame chunks. These are
-// explicitly designed to look like the static initialisation format we use in
-// these tests. They have to live in the net namespace in order to be found by
+// Printing helpers to allow GoogleMock to print frames. These are explicitly
+// designed to look like the static initialisation format we use in these
+// tests. They have to live in the net namespace in order to be found by
// GoogleMock; a nested anonymous namespace will not work.
std::ostream& operator<<(std::ostream& os, const WebSocketFrameHeader& header) {
- return os << "{" << (header.final ? "FINAL_FRAME" : "NOT_FINAL_FRAME") << ", "
+ return os << (header.final ? "FINAL_FRAME" : "NOT_FINAL_FRAME") << ", "
<< header.opcode << ", "
- << (header.masked ? "MASKED" : "NOT_MASKED") << ", "
- << header.payload_length << "}";
+ << (header.masked ? "MASKED" : "NOT_MASKED");
}
-std::ostream& operator<<(std::ostream& os, const WebSocketFrameChunk& chunk) {
- os << "{";
- if (chunk.header) {
- os << *chunk.header;
- } else {
- os << "{NO_HEADER}";
+std::ostream& operator<<(std::ostream& os, const WebSocketFrame& frame) {
+ os << "{" << frame.header << ", ";
+ if (frame.data) {
+ return os << "\"" << base::StringPiece(frame.data->data(),
+ frame.header.payload_length)
+ << "\"}";
}
- return os << ", " << (chunk.final_chunk ? "FINAL_CHUNK" : "NOT_FINAL_CHUNK")
- << ", \""
- << base::StringPiece(chunk.data->data(), chunk.data->size())
- << "\"}";
+ return os << "NULL}";
}
std::ostream& operator<<(std::ostream& os,
- const ScopedVector<WebSocketFrameChunk>& vector) {
+ const ScopedVector<WebSocketFrame>& vector) {
os << "{";
bool first = true;
- for (ScopedVector<WebSocketFrameChunk>::const_iterator it = vector.begin();
+ for (ScopedVector<WebSocketFrame>::const_iterator it = vector.begin();
it != vector.end();
++it) {
if (!first) {
@@ -81,7 +78,7 @@ std::ostream& operator<<(std::ostream& os,
}
std::ostream& operator<<(std::ostream& os,
- const ScopedVector<WebSocketFrameChunk>* vector) {
+ const ScopedVector<WebSocketFrame>* vector) {
return os << '&' << *vector;
}
@@ -97,7 +94,7 @@ using ::testing::_;
// A selection of characters that have traditionally been mangled in some
// environment or other, for testing 8-bit cleanliness.
-const char kBinaryBlob[] = {'\n', '\r', // BACKWARDS CRNL
+const char kBinaryBlob[] = {'\n', '\r', // BACKWARDS CRNL
'\0', // nul
'\x7F', // DEL
'\x80', '\xFF', // NOT VALID UTF-8
@@ -170,12 +167,12 @@ class FakeWebSocketStream : public WebSocketStream {
return ERR_IO_PENDING;
}
- virtual int ReadFrames(ScopedVector<WebSocketFrameChunk>* frame_chunks,
+ virtual int ReadFrames(ScopedVector<WebSocketFrame>* frames,
const CompletionCallback& callback) OVERRIDE {
return ERR_IO_PENDING;
}
- virtual int WriteFrames(ScopedVector<WebSocketFrameChunk>* frame_chunks,
+ virtual int WriteFrames(ScopedVector<WebSocketFrame>* frames,
const CompletionCallback& callback) OVERRIDE {
return ERR_IO_PENDING;
}
@@ -198,12 +195,7 @@ class FakeWebSocketStream : public WebSocketStream {
// To make the static initialisers easier to read, we use enums rather than
// bools.
-
-// NO_HEADER means there shouldn't be a header included in the generated
-// WebSocketFrameChunk. The static initialiser always has a header, but we can
-// avoid specifying the rest of the fields.
enum IsFinal {
- NO_HEADER,
NOT_FINAL_FRAME,
FINAL_FRAME
};
@@ -213,54 +205,33 @@ enum IsMasked {
MASKED
};
-enum IsFinalChunk {
- NOT_FINAL_CHUNK,
- FINAL_CHUNK
-};
-
-// This is used to initialise a WebSocketFrameChunk but is statically
-// initialisable.
-struct InitFrameChunk {
- struct FrameHeader {
- IsFinal final;
- // Reserved fields omitted for now. Add them if you need them.
- WebSocketFrameHeader::OpCode opcode;
- IsMasked masked;
- // payload_length is the length of the whole frame. The length of the data
- // members from every chunk in the frame must add up to the payload_length.
- uint64 payload_length;
- };
- FrameHeader header;
-
- // Directly equivalent to WebSocketFrameChunk::final_chunk
- IsFinalChunk final_chunk;
+// This is used to initialise a WebSocketFrame but is statically initialisable.
+struct InitFrame {
+ IsFinal final;
+ // Reserved fields omitted for now. Add them if you need them.
+ WebSocketFrameHeader::OpCode opcode;
+ IsMasked masked;
// Will be used to create the IOBuffer member. Can be NULL for NULL data. Is a
- // nul-terminated string for ease-of-use. This means it is not 8-bit clean,
- // but this is not an issue for test data.
+ // nul-terminated string for ease-of-use. |header.payload_length| is
+ // initialised from |strlen(data)|. This means it is not 8-bit clean, but this
+ // is not an issue for test data.
const char* const data;
};
// For GoogleMock
-std::ostream& operator<<(std::ostream& os, const InitFrameChunk& chunk) {
- os << "{";
- if (chunk.header.final != NO_HEADER) {
- os << "{" << (chunk.header.final == FINAL_FRAME ? "FINAL_FRAME"
- : "NOT_FINAL_FRAME") << ", "
- << chunk.header.opcode << ", "
- << (chunk.header.masked == MASKED ? "MASKED" : "NOT_MASKED") << ", "
- << chunk.header.payload_length << "}";
-
- } else {
- os << "{NO_HEADER}";
+std::ostream& operator<<(std::ostream& os, const InitFrame& frame) {
+ os << "{" << (frame.final == FINAL_FRAME ? "FINAL_FRAME" : "NOT_FINAL_FRAME")
+ << ", " << frame.opcode << ", "
+ << (frame.masked == MASKED ? "MASKED" : "NOT_MASKED") << ", ";
+ if (frame.data) {
+ return os << "\"" << frame.data << "\"}";
}
- return os << ", " << (chunk.final_chunk == FINAL_CHUNK ? "FINAL_CHUNK"
- : "NOT_FINAL_CHUNK")
- << ", \"" << chunk.data << "\"}";
+ return os << "NULL}";
}
template <size_t N>
-std::ostream& operator<<(std::ostream& os, const InitFrameChunk (&chunks)[N]) {
+std::ostream& operator<<(std::ostream& os, const InitFrame (&frames)[N]) {
os << "{";
bool first = true;
for (size_t i = 0; i < N; ++i) {
@@ -269,119 +240,92 @@ std::ostream& operator<<(std::ostream& os, const InitFrameChunk (&chunks)[N]) {
} else {
first = false;
}
- os << chunks[i];
+ os << frames[i];
}
return os << "}";
}
-// Convert a const array of InitFrameChunks to the format used at
+// Convert a const array of InitFrame structs to the format used at
// runtime. Templated on the size of the array to save typing.
template <size_t N>
-ScopedVector<WebSocketFrameChunk> CreateFrameChunkVector(
- const InitFrameChunk (&source_chunks)[N]) {
- ScopedVector<WebSocketFrameChunk> result_chunks;
- result_chunks.reserve(N);
+ScopedVector<WebSocketFrame> CreateFrameVector(
+ const InitFrame (&source_frames)[N]) {
+ ScopedVector<WebSocketFrame> result_frames;
+ result_frames.reserve(N);
for (size_t i = 0; i < N; ++i) {
- scoped_ptr<WebSocketFrameChunk> result_chunk(new WebSocketFrameChunk);
- size_t chunk_length =
- source_chunks[i].data ? strlen(source_chunks[i].data) : 0;
- if (source_chunks[i].header.final != NO_HEADER) {
- const InitFrameChunk::FrameHeader& source_header =
- source_chunks[i].header;
- scoped_ptr<WebSocketFrameHeader> result_header(
- new WebSocketFrameHeader(source_header.opcode));
- result_header->final = (source_header.final == FINAL_FRAME);
- result_header->masked = (source_header.masked == MASKED);
- result_header->payload_length = source_header.payload_length;
- DCHECK(chunk_length <= source_header.payload_length);
- result_chunk->header.swap(result_header);
- }
- result_chunk->final_chunk = (source_chunks[i].final_chunk == FINAL_CHUNK);
- if (source_chunks[i].data) {
- result_chunk->data = new IOBufferWithSize(chunk_length);
- memcpy(result_chunk->data->data(), source_chunks[i].data, chunk_length);
+ const InitFrame& source_frame = source_frames[i];
+ scoped_ptr<WebSocketFrame> result_frame(
+ new WebSocketFrame(source_frame.opcode));
+ size_t frame_length = source_frame.data ? strlen(source_frame.data) : 0;
+ WebSocketFrameHeader& result_header = result_frame->header;
+ result_header.final = (source_frame.final == FINAL_FRAME);
+ result_header.masked = (source_frame.masked == MASKED);
+ result_header.payload_length = frame_length;
+ if (source_frame.data) {
+ result_frame->data = new IOBuffer(frame_length);
+ memcpy(result_frame->data->data(), source_frame.data, frame_length);
}
- result_chunks.push_back(result_chunk.release());
+ result_frames.push_back(result_frame.release());
}
- return result_chunks.Pass();
+ return result_frames.Pass();
}
// A GoogleMock action which can be used to respond to call to ReadFrames with
-// some frames. Use like ReadFrames(_, _).WillOnce(ReturnChunks(&chunks));
-// |chunks| is an array of InitFrameChunks needs to be passed by pointer because
-// otherwise it will be reduced to a pointer and lose the array size
-// information.
-ACTION_P(ReturnChunks, source_chunks) {
- *arg0 = CreateFrameChunkVector(*source_chunks);
+// some frames. Use like ReadFrames(_, _).WillOnce(ReturnFrames(&frames));
+// |frames| is an array of InitFrame. |frames| needs to be passed by pointer
+// because otherwise it will be treated as a pointer and the array size
+// information will be lost.
+ACTION_P(ReturnFrames, source_frames) {
+ *arg0 = CreateFrameVector(*source_frames);
return OK;
}
// The implementation of a GoogleMock matcher which can be used to compare a
-// ScopedVector<WebSocketFrameChunk>* against an expectation defined as an array
-// of InitFrameChunks. Although it is possible to compose built-in GoogleMock
-// matchers to check the contents of a WebSocketFrameChunk, the results are so
+// ScopedVector<WebSocketFrame>* against an expectation defined as an array of
+// InitFrame objects. Although it is possible to compose built-in GoogleMock
+// matchers to check the contents of a WebSocketFrame, the results are so
// unreadable that it is better to use this matcher.
template <size_t N>
-class EqualsChunksMatcher
- : public ::testing::MatcherInterface<ScopedVector<WebSocketFrameChunk>*> {
+class EqualsFramesMatcher
+ : public ::testing::MatcherInterface<ScopedVector<WebSocketFrame>*> {
public:
- EqualsChunksMatcher(const InitFrameChunk (*expect_chunks)[N])
- : expect_chunks_(expect_chunks) {}
+ EqualsFramesMatcher(const InitFrame (*expect_frames)[N])
+ : expect_frames_(expect_frames) {}
- virtual bool MatchAndExplain(ScopedVector<WebSocketFrameChunk>* actual_chunks,
+ virtual bool MatchAndExplain(ScopedVector<WebSocketFrame>* actual_frames,
::testing::MatchResultListener* listener) const {
- if (actual_chunks->size() != N) {
- *listener << "the vector size is " << actual_chunks->size();
+ if (actual_frames->size() != N) {
+ *listener << "the vector size is " << actual_frames->size();
return false;
}
for (size_t i = 0; i < N; ++i) {
- const WebSocketFrameChunk& actual_chunk = *(*actual_chunks)[i];
- const InitFrameChunk& expected_chunk = (*expect_chunks_)[i];
- // Testing that the absence or presence of a header is the same for both.
- if ((!actual_chunk.header) !=
- (expected_chunk.header.final == NO_HEADER)) {
- *listener << "the header is "
- << (actual_chunk.header ? "present" : "absent");
+ const WebSocketFrame& actual_frame = *(*actual_frames)[i];
+ const InitFrame& expected_frame = (*expect_frames_)[i];
+ if (actual_frame.header.final != (expected_frame.final == FINAL_FRAME)) {
+ *listener << "the frame is marked as "
+ << (actual_frame.header.final ? "" : "not ") << "final";
return false;
}
- if (actual_chunk.header) {
- if (actual_chunk.header->final !=
- (expected_chunk.header.final == FINAL_FRAME)) {
- *listener << "the frame is marked as "
- << (actual_chunk.header->final ? "" : "not ") << "final";
- return false;
- }
- if (actual_chunk.header->opcode != expected_chunk.header.opcode) {
- *listener << "the opcode is " << actual_chunk.header->opcode;
- return false;
- }
- if (actual_chunk.header->masked !=
- (expected_chunk.header.masked == MASKED)) {
- *listener << "the frame is "
- << (actual_chunk.header->masked ? "masked" : "not masked");
- return false;
- }
- if (actual_chunk.header->payload_length !=
- expected_chunk.header.payload_length) {
- *listener << "the payload length is "
- << actual_chunk.header->payload_length;
- return false;
- }
+ if (actual_frame.header.opcode != expected_frame.opcode) {
+ *listener << "the opcode is " << actual_frame.header.opcode;
+ return false;
}
- if (actual_chunk.final_chunk !=
- (expected_chunk.final_chunk == FINAL_CHUNK)) {
- *listener << "the chunk is marked as "
- << (actual_chunk.final_chunk ? "" : "not ") << "final";
+ if (actual_frame.header.masked != (expected_frame.masked == MASKED)) {
+ *listener << "the frame is "
+ << (actual_frame.header.masked ? "masked" : "not masked");
return false;
}
- if (actual_chunk.data->size() !=
- base::checked_numeric_cast<int>(strlen(expected_chunk.data))) {
- *listener << "the data size is " << actual_chunk.data->size();
+ const size_t expected_length =
+ expected_frame.data ? strlen(expected_frame.data) : 0;
+ if (actual_frame.header.payload_length != expected_length) {
+ *listener << "the payload length is "
+ << actual_frame.header.payload_length;
return false;
}
- if (memcmp(actual_chunk.data->data(),
- expected_chunk.data,
- actual_chunk.data->size()) != 0) {
+ if (expected_length != 0 &&
+ memcmp(actual_frame.data->data(),
+ expected_frame.data,
+ actual_frame.header.payload_length) != 0) {
*listener << "the data content differs";
return false;
}
@@ -390,23 +334,23 @@ class EqualsChunksMatcher
}
virtual void DescribeTo(std::ostream* os) const {
- *os << "matches " << *expect_chunks_;
+ *os << "matches " << *expect_frames_;
}
virtual void DescribeNegationTo(std::ostream* os) const {
- *os << "does not match " << *expect_chunks_;
+ *os << "does not match " << *expect_frames_;
}
private:
- const InitFrameChunk (*expect_chunks_)[N];
+ const InitFrame (*expect_frames_)[N];
};
-// The definition of EqualsChunks GoogleMock matcher. Unlike the ReturnChunks
+// The definition of EqualsFrames GoogleMock matcher. Unlike the ReturnFrames
// action, this can take the array by reference.
template <size_t N>
-::testing::Matcher<ScopedVector<WebSocketFrameChunk>*> EqualsChunks(
- const InitFrameChunk (&chunks)[N]) {
- return ::testing::MakeMatcher(new EqualsChunksMatcher<N>(&chunks));
+::testing::Matcher<ScopedVector<WebSocketFrame>*> EqualsFrames(
+ const InitFrame (&frames)[N]) {
+ return ::testing::MakeMatcher(new EqualsFramesMatcher<N>(&frames));
}
// A FakeWebSocketStream whose ReadFrames() function returns data.
@@ -427,39 +371,38 @@ class ReadableFakeWebSocketStream : public FakeWebSocketStream {
CHECK(!read_frames_pending_);
}
- // Prepares a fake responses. Fake responses will be returned from
- // ReadFrames() in the same order they were prepared with PrepareReadFrames()
- // and PrepareReadFramesError(). If |async| is ASYNC, then ReadFrames() will
+ // Prepares a fake response. Fake responses will be returned from ReadFrames()
+ // in the same order they were prepared with PrepareReadFrames() and
+ // PrepareReadFramesError(). If |async| is ASYNC, then ReadFrames() will
// return ERR_IO_PENDING and the callback will be scheduled to run on the
// message loop. This requires the test case to run the message loop. If
// |async| is SYNC, the response will be returned synchronously. |error| is
// returned directly from ReadFrames() in the synchronous case, or passed to
- // the callback in the asynchronous case. |chunks| will be converted to a
- // ScopedVector<WebSocketFrameChunks> and copied to the pointer that was
- // passed to ReadFrames().
+ // the callback in the asynchronous case. |frames| will be converted to a
+ // ScopedVector<WebSocketFrame> and copied to the pointer that was passed to
+ // ReadFrames().
template <size_t N>
void PrepareReadFrames(IsSync async,
int error,
- const InitFrameChunk (&chunks)[N]) {
- responses_.push_back(
- new Response(async, error, CreateFrameChunkVector(chunks)));
+ const InitFrame (&frames)[N]) {
+ responses_.push_back(new Response(async, error, CreateFrameVector(frames)));
}
// An alternate version of PrepareReadFrames for when we need to construct
// the frames manually.
void PrepareRawReadFrames(IsSync async,
int error,
- ScopedVector<WebSocketFrameChunk> chunks) {
- responses_.push_back(new Response(async, error, chunks.Pass()));
+ ScopedVector<WebSocketFrame> frames) {
+ responses_.push_back(new Response(async, error, frames.Pass()));
}
// Prepares a fake error response (ie. there is no data).
void PrepareReadFramesError(IsSync async, int error) {
responses_.push_back(
- new Response(async, error, ScopedVector<WebSocketFrameChunk>()));
+ new Response(async, error, ScopedVector<WebSocketFrame>()));
}
- virtual int ReadFrames(ScopedVector<WebSocketFrameChunk>* frame_chunks,
+ virtual int ReadFrames(ScopedVector<WebSocketFrame>* frames,
const CompletionCallback& callback) OVERRIDE {
CHECK(!read_frames_pending_);
if (index_ >= responses_.size())
@@ -470,34 +413,34 @@ class ReadableFakeWebSocketStream : public FakeWebSocketStream {
FROM_HERE,
base::Bind(&ReadableFakeWebSocketStream::DoCallback,
base::Unretained(this),
- frame_chunks,
+ frames,
callback));
return ERR_IO_PENDING;
} else {
- frame_chunks->swap(responses_[index_]->chunks);
+ frames->swap(responses_[index_]->frames);
return responses_[index_++]->error;
}
}
private:
- void DoCallback(ScopedVector<WebSocketFrameChunk>* frame_chunks,
+ void DoCallback(ScopedVector<WebSocketFrame>* frames,
const CompletionCallback& callback) {
read_frames_pending_ = false;
- frame_chunks->swap(responses_[index_]->chunks);
+ frames->swap(responses_[index_]->frames);
callback.Run(responses_[index_++]->error);
return;
}
struct Response {
- Response(IsSync async, int error, ScopedVector<WebSocketFrameChunk> chunks)
- : async(async), error(error), chunks(chunks.Pass()) {}
+ Response(IsSync async, int error, ScopedVector<WebSocketFrame> frames)
+ : async(async), error(error), frames(frames.Pass()) {}
IsSync async;
int error;
- ScopedVector<WebSocketFrameChunk> chunks;
+ ScopedVector<WebSocketFrame> frames;
private:
- // Bad things will happen if we attempt to copy or assign "chunks".
+ // Bad things will happen if we attempt to copy or assign |frames|.
DISALLOW_COPY_AND_ASSIGN(Response);
};
ScopedVector<Response> responses_;
@@ -516,7 +459,7 @@ class ReadableFakeWebSocketStream : public FakeWebSocketStream {
// synchronously.
class WriteableFakeWebSocketStream : public FakeWebSocketStream {
public:
- virtual int WriteFrames(ScopedVector<WebSocketFrameChunk>* frame_chunks,
+ virtual int WriteFrames(ScopedVector<WebSocketFrame>* frames,
const CompletionCallback& callback) OVERRIDE {
return OK;
}
@@ -525,7 +468,7 @@ class WriteableFakeWebSocketStream : public FakeWebSocketStream {
// A FakeWebSocketStream where writes always fail.
class UnWriteableFakeWebSocketStream : public FakeWebSocketStream {
public:
- virtual int WriteFrames(ScopedVector<WebSocketFrameChunk>* frame_chunks,
+ virtual int WriteFrames(ScopedVector<WebSocketFrame>* frames,
const CompletionCallback& callback) OVERRIDE {
return ERR_CONNECTION_RESET;
}
@@ -539,23 +482,22 @@ class UnWriteableFakeWebSocketStream : public FakeWebSocketStream {
// otherwise the ReadFrames() callback will never be called.
class EchoeyFakeWebSocketStream : public FakeWebSocketStream {
public:
- EchoeyFakeWebSocketStream() : read_frame_chunks_(NULL), done_(false) {}
+ EchoeyFakeWebSocketStream() : read_frames_(NULL), done_(false) {}
- virtual int WriteFrames(ScopedVector<WebSocketFrameChunk>* frame_chunks,
+ virtual int WriteFrames(ScopedVector<WebSocketFrame>* frames,
const CompletionCallback& callback) OVERRIDE {
// Users of WebSocketStream will not expect the ReadFrames() callback to be
// called from within WriteFrames(), so post it to the message loop instead.
- stored_frame_chunks_.insert(
- stored_frame_chunks_.end(), frame_chunks->begin(), frame_chunks->end());
- frame_chunks->weak_clear();
+ stored_frames_.insert(stored_frames_.end(), frames->begin(), frames->end());
+ frames->weak_clear();
PostCallback();
return OK;
}
- virtual int ReadFrames(ScopedVector<WebSocketFrameChunk>* frame_chunks,
+ virtual int ReadFrames(ScopedVector<WebSocketFrame>* frames,
const CompletionCallback& callback) OVERRIDE {
read_callback_ = callback;
- read_frame_chunks_ = frame_chunks;
+ read_frames_ = frames;
if (done_)
PostCallback();
return ERR_IO_PENDING;
@@ -572,36 +514,34 @@ class EchoeyFakeWebSocketStream : public FakeWebSocketStream {
void DoCallback() {
if (done_) {
read_callback_.Run(ERR_CONNECTION_CLOSED);
- } else if (!stored_frame_chunks_.empty()) {
- done_ = MoveFrameChunks(read_frame_chunks_);
- read_frame_chunks_ = NULL;
+ } else if (!stored_frames_.empty()) {
+ done_ = MoveFrames(read_frames_);
+ read_frames_ = NULL;
read_callback_.Run(OK);
}
}
- // Copy the chunks stored in stored_frame_chunks_ to |out|, while clearing the
+ // Copy the frames stored in stored_frames_ to |out|, while clearing the
// "masked" header bit. Returns true if a Close Frame was seen, false
// otherwise.
- bool MoveFrameChunks(ScopedVector<WebSocketFrameChunk>* out) {
+ bool MoveFrames(ScopedVector<WebSocketFrame>* out) {
bool seen_close = false;
- *out = stored_frame_chunks_.Pass();
- for (ScopedVector<WebSocketFrameChunk>::iterator it = out->begin();
+ *out = stored_frames_.Pass();
+ for (ScopedVector<WebSocketFrame>::iterator it = out->begin();
it != out->end();
++it) {
- WebSocketFrameHeader* header = (*it)->header.get();
- if (header) {
- header->masked = false;
- if (header->opcode == WebSocketFrameHeader::kOpCodeClose)
- seen_close = true;
- }
+ WebSocketFrameHeader& header = (*it)->header;
+ header.masked = false;
+ if (header.opcode == WebSocketFrameHeader::kOpCodeClose)
+ seen_close = true;
}
return seen_close;
}
- ScopedVector<WebSocketFrameChunk> stored_frame_chunks_;
+ ScopedVector<WebSocketFrame> stored_frames_;
CompletionCallback read_callback_;
// Owned by the caller of ReadFrames().
- ScopedVector<WebSocketFrameChunk>* read_frame_chunks_;
+ ScopedVector<WebSocketFrame>* read_frames_;
// True if we should close the connection.
bool done_;
};
@@ -612,7 +552,7 @@ class EchoeyFakeWebSocketStream : public FakeWebSocketStream {
// run the message loop.
class ResetOnWriteFakeWebSocketStream : public FakeWebSocketStream {
public:
- virtual int WriteFrames(ScopedVector<WebSocketFrameChunk>* frame_chunks,
+ virtual int WriteFrames(ScopedVector<WebSocketFrame>* frames,
const CompletionCallback& callback) OVERRIDE {
base::MessageLoop::current()->PostTask(
FROM_HERE, base::Bind(callback, ERR_CONNECTION_RESET));
@@ -621,7 +561,7 @@ class ResetOnWriteFakeWebSocketStream : public FakeWebSocketStream {
return ERR_IO_PENDING;
}
- virtual int ReadFrames(ScopedVector<WebSocketFrameChunk>* frame_chunks,
+ virtual int ReadFrames(ScopedVector<WebSocketFrame>* frames,
const CompletionCallback& callback) OVERRIDE {
read_callback_ = callback;
return ERR_IO_PENDING;
@@ -636,10 +576,10 @@ class ResetOnWriteFakeWebSocketStream : public FakeWebSocketStream {
class MockWebSocketStream : public WebSocketStream {
public:
MOCK_METHOD2(ReadFrames,
- int(ScopedVector<WebSocketFrameChunk>* frame_chunks,
+ int(ScopedVector<WebSocketFrame>* frames,
const CompletionCallback& callback));
MOCK_METHOD2(WriteFrames,
- int(ScopedVector<WebSocketFrameChunk>* frame_chunks,
+ int(ScopedVector<WebSocketFrame>* frames,
const CompletionCallback& callback));
MOCK_METHOD0(Close, void());
MOCK_CONST_METHOD0(GetSubProtocol, std::string());
@@ -846,8 +786,8 @@ TEST_F(WebSocketChannelTest, EverythingIsPassedToTheFactoryFunction) {
// AddressSanitizer.
TEST_F(WebSocketChannelDeletingTest, DeletingFromOnAddChannelResponseWorks) {
CreateChannelAndConnect();
- connect_data_.factory.connect_delegate
- ->OnFailure(kWebSocketErrorNoStatusReceived);
+ connect_data_.factory.connect_delegate->OnFailure(
+ kWebSocketErrorNoStatusReceived);
EXPECT_EQ(NULL, channel_.get());
}
@@ -869,8 +809,8 @@ TEST_F(WebSocketChannelEventInterfaceTest, ConnectFailureReported) {
CreateChannelAndConnect();
- connect_data_.factory.connect_delegate
- ->OnFailure(kWebSocketErrorNoStatusReceived);
+ connect_data_.factory.connect_delegate->OnFailure(
+ kWebSocketErrorNoStatusReceived);
}
TEST_F(WebSocketChannelEventInterfaceTest, ProtocolPassed) {
@@ -889,10 +829,9 @@ TEST_F(WebSocketChannelEventInterfaceTest, ProtocolPassed) {
TEST_F(WebSocketChannelEventInterfaceTest, DataLeftFromHandshake) {
scoped_ptr<ReadableFakeWebSocketStream> stream(
new ReadableFakeWebSocketStream);
- static const InitFrameChunk chunks[] = {
- {{FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, NOT_MASKED, 5},
- FINAL_CHUNK, "HELLO"}};
- stream->PrepareReadFrames(ReadableFakeWebSocketStream::SYNC, OK, chunks);
+ static const InitFrame frames[] = {
+ {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, NOT_MASKED, "HELLO"}};
+ stream->PrepareReadFrames(ReadableFakeWebSocketStream::SYNC, OK, frames);
set_stream(stream.Pass());
{
InSequence s;
@@ -912,10 +851,10 @@ TEST_F(WebSocketChannelEventInterfaceTest, DataLeftFromHandshake) {
TEST_F(WebSocketChannelEventInterfaceTest, CloseAfterHandshake) {
scoped_ptr<ReadableFakeWebSocketStream> stream(
new ReadableFakeWebSocketStream);
- static const InitFrameChunk chunks[] = {
- {{FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose, NOT_MASKED, 23},
- FINAL_CHUNK, CLOSE_DATA(SERVER_ERROR, "Internal Server Error")}};
- stream->PrepareReadFrames(ReadableFakeWebSocketStream::SYNC, OK, chunks);
+ static const InitFrame frames[] = {
+ {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose,
+ NOT_MASKED, CLOSE_DATA(SERVER_ERROR, "Internal Server Error")}};
+ stream->PrepareReadFrames(ReadableFakeWebSocketStream::SYNC, OK, frames);
stream->PrepareReadFramesError(ReadableFakeWebSocketStream::SYNC,
ERR_CONNECTION_CLOSED);
set_stream(stream.Pass());
@@ -954,13 +893,12 @@ TEST_F(WebSocketChannelEventInterfaceTest, ConnectionCloseAfterHandshake) {
TEST_F(WebSocketChannelEventInterfaceTest, NormalAsyncRead) {
scoped_ptr<ReadableFakeWebSocketStream> stream(
new ReadableFakeWebSocketStream);
- static const InitFrameChunk chunks[] = {
- {{FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, NOT_MASKED, 5},
- FINAL_CHUNK, "HELLO"}};
+ static const InitFrame frames[] = {
+ {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, NOT_MASKED, "HELLO"}};
// We use this checkpoint object to verify that the callback isn't called
// until we expect it to be.
MockFunction<void(int)> checkpoint;
- stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, chunks);
+ stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, frames);
set_stream(stream.Pass());
{
InSequence s;
@@ -985,14 +923,12 @@ TEST_F(WebSocketChannelEventInterfaceTest, NormalAsyncRead) {
TEST_F(WebSocketChannelEventInterfaceTest, AsyncThenSyncRead) {
scoped_ptr<ReadableFakeWebSocketStream> stream(
new ReadableFakeWebSocketStream);
- static const InitFrameChunk chunks1[] = {
- {{FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, NOT_MASKED, 5},
- FINAL_CHUNK, "HELLO"}};
- static const InitFrameChunk chunks2[] = {
- {{FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, NOT_MASKED, 5},
- FINAL_CHUNK, "WORLD"}};
- stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, chunks1);
- stream->PrepareReadFrames(ReadableFakeWebSocketStream::SYNC, OK, chunks2);
+ static const InitFrame frames1[] = {
+ {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, NOT_MASKED, "HELLO"}};
+ static const InitFrame frames2[] = {
+ {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, NOT_MASKED, "WORLD"}};
+ stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, frames1);
+ stream->PrepareReadFrames(ReadableFakeWebSocketStream::SYNC, OK, frames2);
set_stream(stream.Pass());
{
InSequence s;
@@ -1012,31 +948,29 @@ TEST_F(WebSocketChannelEventInterfaceTest, AsyncThenSyncRead) {
base::MessageLoop::current()->RunUntilIdle();
}
-// Data frames that arrive in fragments are turned into individual frames
-TEST_F(WebSocketChannelEventInterfaceTest, FragmentedFrames) {
+// Data frames are delivered the same regardless of how many reads they arrive
+// as.
+TEST_F(WebSocketChannelEventInterfaceTest, FragmentedMessage) {
scoped_ptr<ReadableFakeWebSocketStream> stream(
new ReadableFakeWebSocketStream);
- // Here we have one message split into 3 frames which arrive in 3 chunks. The
- // first frame is entirely in the first chunk, the second frame is split
- // across all the chunks, and the final frame is entirely in the final
- // chunk. The frame fragments are converted to separate frames so that they
- // can be delivered immediatedly. So the EventInterface should see a Text
- // message with 5 frames.
- static const InitFrameChunk chunks1[] = {
- {{NOT_FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, NOT_MASKED, 5},
- FINAL_CHUNK, "THREE"},
- {{NOT_FINAL_FRAME, WebSocketFrameHeader::kOpCodeContinuation, NOT_MASKED,
- 7},
- NOT_FINAL_CHUNK, " "}};
- static const InitFrameChunk chunks2[] = {
- {{NO_HEADER}, NOT_FINAL_CHUNK, "SMALL"}};
- static const InitFrameChunk chunks3[] = {
- {{NO_HEADER}, FINAL_CHUNK, " "},
- {{FINAL_FRAME, WebSocketFrameHeader::kOpCodeContinuation, NOT_MASKED, 6},
- FINAL_CHUNK, "FRAMES"}};
- stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, chunks1);
- stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, chunks2);
- stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, chunks3);
+ // Here we have one message which arrived in five frames split across three
+ // reads. It may have been reframed on arrival, but this class doesn't care
+ // about that.
+ static const InitFrame frames1[] = {
+ {NOT_FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, NOT_MASKED, "THREE"},
+ {NOT_FINAL_FRAME, WebSocketFrameHeader::kOpCodeContinuation,
+ NOT_MASKED, " "}};
+ static const InitFrame frames2[] = {
+ {NOT_FINAL_FRAME, WebSocketFrameHeader::kOpCodeContinuation,
+ NOT_MASKED, "SMALL"}};
+ static const InitFrame frames3[] = {
+ {NOT_FINAL_FRAME, WebSocketFrameHeader::kOpCodeContinuation,
+ NOT_MASKED, " "},
+ {FINAL_FRAME, WebSocketFrameHeader::kOpCodeContinuation,
+ NOT_MASKED, "FRAMES"}};
+ stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, frames1);
+ stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, frames2);
+ stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, frames3);
set_stream(stream.Pass());
{
InSequence s;
@@ -1068,112 +1002,16 @@ TEST_F(WebSocketChannelEventInterfaceTest, FragmentedFrames) {
base::MessageLoop::current()->RunUntilIdle();
}
-// In the case when a single-frame message because fragmented, it must be
-// correctly transformed to multiple frames.
-TEST_F(WebSocketChannelEventInterfaceTest, MessageFragmentation) {
- scoped_ptr<ReadableFakeWebSocketStream> stream(
- new ReadableFakeWebSocketStream);
- // A single-frame Text message arrives in three chunks. This should be
- // delivered as three frames.
- static const InitFrameChunk chunks1[] = {
- {{FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, NOT_MASKED, 12},
- NOT_FINAL_CHUNK, "TIME"}};
- static const InitFrameChunk chunks2[] = {
- {{NO_HEADER}, NOT_FINAL_CHUNK, " FOR "}};
- static const InitFrameChunk chunks3[] = {{{NO_HEADER}, FINAL_CHUNK, "TEA"}};
- stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, chunks1);
- stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, chunks2);
- stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, chunks3);
- set_stream(stream.Pass());
- {
- InSequence s;
- EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _));
- EXPECT_CALL(*event_interface_, OnFlowControl(_));
- EXPECT_CALL(
- *event_interface_,
- OnDataFrame(
- false, WebSocketFrameHeader::kOpCodeText, AsVector("TIME")));
- EXPECT_CALL(*event_interface_,
- OnDataFrame(false,
- WebSocketFrameHeader::kOpCodeContinuation,
- AsVector(" FOR ")));
- EXPECT_CALL(
- *event_interface_,
- OnDataFrame(
- true, WebSocketFrameHeader::kOpCodeContinuation, AsVector("TEA")));
- }
-
- CreateChannelAndConnectSuccessfully();
- base::MessageLoop::current()->RunUntilIdle();
-}
-
-// If a control message is fragmented, it must be re-assembled before being
-// delivered. A control message can only be fragmented at the network level; it
-// is not permitted to be split into multiple frames.
-TEST_F(WebSocketChannelEventInterfaceTest, FragmentedControlMessage) {
- scoped_ptr<ReadableFakeWebSocketStream> stream(
- new ReadableFakeWebSocketStream);
- static const InitFrameChunk chunks1[] = {
- {{FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose, NOT_MASKED, 7},
- NOT_FINAL_CHUNK, CLOSE_DATA(NORMAL_CLOSURE, "")}};
- static const InitFrameChunk chunks2[] = {
- {{NO_HEADER}, NOT_FINAL_CHUNK, "Clo"}};
- static const InitFrameChunk chunks3[] = {{{NO_HEADER}, FINAL_CHUNK, "se"}};
- stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, chunks1);
- stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, chunks2);
- stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, chunks3);
- stream->PrepareReadFramesError(ReadableFakeWebSocketStream::ASYNC,
- ERR_CONNECTION_CLOSED);
- set_stream(stream.Pass());
- {
- InSequence s;
- EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _));
- EXPECT_CALL(*event_interface_, OnFlowControl(_));
- EXPECT_CALL(*event_interface_, OnClosingHandshake());
- EXPECT_CALL(*event_interface_,
- OnDropChannel(kWebSocketNormalClosure, "Close"));
- }
-
- CreateChannelAndConnectSuccessfully();
- base::MessageLoop::current()->RunUntilIdle();
-}
-
-// The payload of a control frame is not permitted to exceed 125 bytes. RFC6455
-// 5.5 "All control frames MUST have a payload length of 125 bytes or less"
-TEST_F(WebSocketChannelEventInterfaceTest, OversizeControlMessageIsRejected) {
- scoped_ptr<ReadableFakeWebSocketStream> stream(
- new ReadableFakeWebSocketStream);
- static const size_t kPayloadLen = 126;
- char payload[kPayloadLen + 1]; // allow space for trailing NUL
- std::fill(payload, payload + kPayloadLen, 'A');
- payload[kPayloadLen] = '\0';
- // Not static because "payload" is constructed at runtime.
- const InitFrameChunk chunks[] = {
- {{FINAL_FRAME, WebSocketFrameHeader::kOpCodePing, NOT_MASKED,
- kPayloadLen},
- FINAL_CHUNK, payload}};
- stream->PrepareReadFrames(ReadableFakeWebSocketStream::SYNC, OK, chunks);
- set_stream(stream.Pass());
-
- EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _));
- EXPECT_CALL(*event_interface_, OnFlowControl(_));
- EXPECT_CALL(*event_interface_,
- OnDropChannel(kWebSocketErrorProtocolError, _));
-
- CreateChannelAndConnectSuccessfully();
-}
-
// A control frame is not permitted to be split into multiple frames. RFC6455
// 5.5 "All control frames ... MUST NOT be fragmented."
TEST_F(WebSocketChannelEventInterfaceTest, MultiFrameControlMessageIsRejected) {
scoped_ptr<ReadableFakeWebSocketStream> stream(
new ReadableFakeWebSocketStream);
- static const InitFrameChunk chunks[] = {
- {{NOT_FINAL_FRAME, WebSocketFrameHeader::kOpCodePing, NOT_MASKED, 2},
- FINAL_CHUNK, "Pi"},
- {{FINAL_FRAME, WebSocketFrameHeader::kOpCodeContinuation, NOT_MASKED, 2},
- FINAL_CHUNK, "ng"}};
- stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, chunks);
+ static const InitFrame frames[] = {
+ {NOT_FINAL_FRAME, WebSocketFrameHeader::kOpCodePing, NOT_MASKED, "Pi"},
+ {FINAL_FRAME, WebSocketFrameHeader::kOpCodeContinuation,
+ NOT_MASKED, "ng"}};
+ stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, frames);
set_stream(stream.Pass());
{
InSequence s;
@@ -1225,39 +1063,14 @@ TEST_F(WebSocketChannelEventInterfaceTest, ConnectionReset) {
base::MessageLoop::current()->RunUntilIdle();
}
-// Connection closed in the middle of a Close message (server bug, etc.)
-TEST_F(WebSocketChannelEventInterfaceTest, ConnectionClosedInMessage) {
- scoped_ptr<ReadableFakeWebSocketStream> stream(
- new ReadableFakeWebSocketStream);
- static const InitFrameChunk chunks[] = {
- {{FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose, NOT_MASKED, 7},
- NOT_FINAL_CHUNK, CLOSE_DATA(NORMAL_CLOSURE, "")}};
-
- stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, chunks);
- stream->PrepareReadFramesError(ReadableFakeWebSocketStream::ASYNC,
- ERR_CONNECTION_CLOSED);
- set_stream(stream.Pass());
- {
- InSequence s;
- EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _));
- EXPECT_CALL(*event_interface_, OnFlowControl(_));
- EXPECT_CALL(*event_interface_,
- OnDropChannel(kWebSocketErrorAbnormalClosure, _));
- }
-
- CreateChannelAndConnectSuccessfully();
- base::MessageLoop::current()->RunUntilIdle();
-}
-
// RFC6455 5.1 "A client MUST close a connection if it detects a masked frame."
TEST_F(WebSocketChannelEventInterfaceTest, MaskedFramesAreRejected) {
scoped_ptr<ReadableFakeWebSocketStream> stream(
new ReadableFakeWebSocketStream);
- static const InitFrameChunk chunks[] = {
- {{FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, MASKED, 5}, FINAL_CHUNK,
- "HELLO"}};
+ static const InitFrame frames[] = {
+ {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, MASKED, "HELLO"}};
- stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, chunks);
+ stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, frames);
set_stream(stream.Pass());
{
InSequence s;
@@ -1276,10 +1089,9 @@ TEST_F(WebSocketChannelEventInterfaceTest, MaskedFramesAreRejected) {
TEST_F(WebSocketChannelEventInterfaceTest, UnknownOpCodeIsRejected) {
scoped_ptr<ReadableFakeWebSocketStream> stream(
new ReadableFakeWebSocketStream);
- static const InitFrameChunk chunks[] = {
- {{FINAL_FRAME, 4, NOT_MASKED, 5}, FINAL_CHUNK, "HELLO"}};
+ static const InitFrame frames[] = {{FINAL_FRAME, 4, NOT_MASKED, "HELLO"}};
- stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, chunks);
+ stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, frames);
set_stream(stream.Pass());
{
InSequence s;
@@ -1300,18 +1112,17 @@ TEST_F(WebSocketChannelEventInterfaceTest, ControlFrameInDataMessage) {
new ReadableFakeWebSocketStream);
// We have one message of type Text split into two frames. In the middle is a
// control message of type Pong.
- static const InitFrameChunk chunks1[] = {
- {{NOT_FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, NOT_MASKED, 6},
- FINAL_CHUNK, "SPLIT "}};
- static const InitFrameChunk chunks2[] = {
- {{FINAL_FRAME, WebSocketFrameHeader::kOpCodePong, NOT_MASKED, 0},
- FINAL_CHUNK, ""}};
- static const InitFrameChunk chunks3[] = {
- {{FINAL_FRAME, WebSocketFrameHeader::kOpCodeContinuation, NOT_MASKED, 7},
- FINAL_CHUNK, "MESSAGE"}};
- stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, chunks1);
- stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, chunks2);
- stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, chunks3);
+ static const InitFrame frames1[] = {
+ {NOT_FINAL_FRAME, WebSocketFrameHeader::kOpCodeText,
+ NOT_MASKED, "SPLIT "}};
+ static const InitFrame frames2[] = {
+ {FINAL_FRAME, WebSocketFrameHeader::kOpCodePong, NOT_MASKED, ""}};
+ static const InitFrame frames3[] = {
+ {FINAL_FRAME, WebSocketFrameHeader::kOpCodeContinuation,
+ NOT_MASKED, "MESSAGE"}};
+ stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, frames1);
+ stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, frames2);
+ stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, frames3);
set_stream(stream.Pass());
{
InSequence s;
@@ -1331,17 +1142,16 @@ TEST_F(WebSocketChannelEventInterfaceTest, ControlFrameInDataMessage) {
base::MessageLoop::current()->RunUntilIdle();
}
-// If a chunk has an invalid header, then the connection is closed and
-// subsequent chunks must not trigger events.
-TEST_F(WebSocketChannelEventInterfaceTest, HeaderlessChunkAfterInvalidChunk) {
+// If a frame has an invalid header, then the connection is closed and
+// subsequent frames must not trigger events.
+TEST_F(WebSocketChannelEventInterfaceTest, FrameAfterInvalidFrame) {
scoped_ptr<ReadableFakeWebSocketStream> stream(
new ReadableFakeWebSocketStream);
- static const InitFrameChunk chunks[] = {
- {{FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, MASKED, 11},
- NOT_FINAL_CHUNK, "HELLO"},
- {{NO_HEADER}, FINAL_CHUNK, " WORLD"}};
+ static const InitFrame frames[] = {
+ {NOT_FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, MASKED, "HELLO"},
+ {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, NOT_MASKED, " WORLD"}};
- stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, chunks);
+ stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, frames);
set_stream(stream.Pass());
{
InSequence s;
@@ -1501,10 +1311,9 @@ TEST_F(WebSocketChannelEventInterfaceTest, OnDropChannelCalledOnce) {
TEST_F(WebSocketChannelEventInterfaceTest, CloseWithNoPayloadGivesStatus1005) {
scoped_ptr<ReadableFakeWebSocketStream> stream(
new ReadableFakeWebSocketStream);
- static const InitFrameChunk chunks[] = {
- {{FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose, NOT_MASKED, 0},
- FINAL_CHUNK, ""}};
- stream->PrepareReadFrames(ReadableFakeWebSocketStream::SYNC, OK, chunks);
+ static const InitFrame frames[] = {
+ {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose, NOT_MASKED, ""}};
+ stream->PrepareReadFrames(ReadableFakeWebSocketStream::SYNC, OK, frames);
stream->PrepareReadFramesError(ReadableFakeWebSocketStream::SYNC,
ERR_CONNECTION_CLOSED);
set_stream(stream.Pass());
@@ -1517,16 +1326,50 @@ TEST_F(WebSocketChannelEventInterfaceTest, CloseWithNoPayloadGivesStatus1005) {
CreateChannelAndConnectSuccessfully();
}
+// If ReadFrames() returns ERR_WS_PROTOCOL_ERROR, then
+// kWebSocketErrorProtocolError must be sent to the renderer.
+TEST_F(WebSocketChannelEventInterfaceTest, SyncProtocolErrorGivesStatus1002) {
+ scoped_ptr<ReadableFakeWebSocketStream> stream(
+ new ReadableFakeWebSocketStream);
+ stream->PrepareReadFramesError(ReadableFakeWebSocketStream::SYNC,
+ ERR_WS_PROTOCOL_ERROR);
+ set_stream(stream.Pass());
+ EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _));
+ EXPECT_CALL(*event_interface_, OnFlowControl(_));
+
+ EXPECT_CALL(*event_interface_,
+ OnDropChannel(kWebSocketErrorProtocolError, _));
+
+ CreateChannelAndConnectSuccessfully();
+}
+
+// Async version of above test.
+TEST_F(WebSocketChannelEventInterfaceTest, AsyncProtocolErrorGivesStatus1002) {
+ scoped_ptr<ReadableFakeWebSocketStream> stream(
+ new ReadableFakeWebSocketStream);
+ stream->PrepareReadFramesError(ReadableFakeWebSocketStream::ASYNC,
+ ERR_WS_PROTOCOL_ERROR);
+ set_stream(stream.Pass());
+ EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _));
+ EXPECT_CALL(*event_interface_, OnFlowControl(_));
+
+ EXPECT_CALL(*event_interface_,
+ OnDropChannel(kWebSocketErrorProtocolError, _));
+
+ CreateChannelAndConnectSuccessfully();
+ base::MessageLoop::current()->RunUntilIdle();
+}
+
// RFC6455 5.1 "a client MUST mask all frames that it sends to the server".
// WebSocketChannel actually only sets the mask bit in the header, it doesn't
// perform masking itself (not all transports actually use masking).
TEST_F(WebSocketChannelStreamTest, SentFramesAreMasked) {
- static const InitFrameChunk expected[] = {
- {{FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, MASKED, 13},
- FINAL_CHUNK, "NEEDS MASKING"}};
+ static const InitFrame expected[] = {
+ {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText,
+ MASKED, "NEEDS MASKING"}};
EXPECT_CALL(*mock_stream_, GetSubProtocol()).Times(AnyNumber());
EXPECT_CALL(*mock_stream_, ReadFrames(_, _)).WillOnce(Return(ERR_IO_PENDING));
- EXPECT_CALL(*mock_stream_, WriteFrames(EqualsChunks(expected), _))
+ EXPECT_CALL(*mock_stream_, WriteFrames(EqualsFrames(expected), _))
.WillOnce(Return(OK));
CreateChannelAndConnectSuccessfully();
@@ -1537,12 +1380,12 @@ TEST_F(WebSocketChannelStreamTest, SentFramesAreMasked) {
// RFC6455 5.5.1 "The application MUST NOT send any more data frames after
// sending a Close frame."
TEST_F(WebSocketChannelStreamTest, NothingIsSentAfterClose) {
- static const InitFrameChunk expected[] = {
- {{FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose, MASKED, 9},
- FINAL_CHUNK, CLOSE_DATA(NORMAL_CLOSURE, "Success")}};
+ static const InitFrame expected[] = {
+ {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose,
+ MASKED, CLOSE_DATA(NORMAL_CLOSURE, "Success")}};
EXPECT_CALL(*mock_stream_, GetSubProtocol()).Times(AnyNumber());
EXPECT_CALL(*mock_stream_, ReadFrames(_, _)).WillOnce(Return(ERR_IO_PENDING));
- EXPECT_CALL(*mock_stream_, WriteFrames(EqualsChunks(expected), _))
+ EXPECT_CALL(*mock_stream_, WriteFrames(EqualsFrames(expected), _))
.WillOnce(Return(OK));
CreateChannelAndConnectSuccessfully();
@@ -1554,17 +1397,17 @@ TEST_F(WebSocketChannelStreamTest, NothingIsSentAfterClose) {
// RFC6455 5.5.1 "If an endpoint receives a Close frame and did not previously
// send a Close frame, the endpoint MUST send a Close frame in response."
TEST_F(WebSocketChannelStreamTest, CloseIsEchoedBack) {
- static const InitFrameChunk chunks[] = {
- {{FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose, NOT_MASKED, 7},
- FINAL_CHUNK, CLOSE_DATA(NORMAL_CLOSURE, "Close")}};
- static const InitFrameChunk expected[] = {
- {{FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose, MASKED, 7},
- FINAL_CHUNK, CLOSE_DATA(NORMAL_CLOSURE, "Close")}};
+ static const InitFrame frames[] = {
+ {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose,
+ NOT_MASKED, CLOSE_DATA(NORMAL_CLOSURE, "Close")}};
+ static const InitFrame expected[] = {
+ {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose,
+ MASKED, CLOSE_DATA(NORMAL_CLOSURE, "Close")}};
EXPECT_CALL(*mock_stream_, GetSubProtocol()).Times(AnyNumber());
EXPECT_CALL(*mock_stream_, ReadFrames(_, _))
- .WillOnce(ReturnChunks(&chunks))
+ .WillOnce(ReturnFrames(&frames))
.WillRepeatedly(Return(ERR_IO_PENDING));
- EXPECT_CALL(*mock_stream_, WriteFrames(EqualsChunks(expected), _))
+ EXPECT_CALL(*mock_stream_, WriteFrames(EqualsFrames(expected), _))
.WillOnce(Return(OK));
CreateChannelAndConnectSuccessfully();
@@ -1573,17 +1416,17 @@ TEST_F(WebSocketChannelStreamTest, CloseIsEchoedBack) {
// The converse of the above case; after sending a Close frame, we should not
// send another one.
TEST_F(WebSocketChannelStreamTest, CloseOnlySentOnce) {
- static const InitFrameChunk expected[] = {
- {{FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose, MASKED, 7},
- FINAL_CHUNK, CLOSE_DATA(NORMAL_CLOSURE, "Close")}};
- static const InitFrameChunk chunks[] = {
- {{FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose, NOT_MASKED, 7},
- FINAL_CHUNK, CLOSE_DATA(NORMAL_CLOSURE, "Close")}};
+ static const InitFrame expected[] = {
+ {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose,
+ MASKED, CLOSE_DATA(NORMAL_CLOSURE, "Close")}};
+ static const InitFrame frames_init[] = {
+ {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose,
+ NOT_MASKED, CLOSE_DATA(NORMAL_CLOSURE, "Close")}};
// We store the parameters that were passed to ReadFrames() so that we can
// call them explicitly later.
CompletionCallback read_callback;
- ScopedVector<WebSocketFrameChunk>* frame_chunks = NULL;
+ ScopedVector<WebSocketFrame>* frames = NULL;
// Use a checkpoint to make the ordering of events clearer.
MockFunction<void(int)> checkpoint;
@@ -1591,11 +1434,11 @@ TEST_F(WebSocketChannelStreamTest, CloseOnlySentOnce) {
InSequence s;
EXPECT_CALL(*mock_stream_, GetSubProtocol()).Times(AnyNumber());
EXPECT_CALL(*mock_stream_, ReadFrames(_, _))
- .WillOnce(DoAll(SaveArg<0>(&frame_chunks),
+ .WillOnce(DoAll(SaveArg<0>(&frames),
SaveArg<1>(&read_callback),
Return(ERR_IO_PENDING)));
EXPECT_CALL(checkpoint, Call(1));
- EXPECT_CALL(*mock_stream_, WriteFrames(EqualsChunks(expected), _))
+ EXPECT_CALL(*mock_stream_, WriteFrames(EqualsFrames(expected), _))
.WillOnce(Return(OK));
EXPECT_CALL(checkpoint, Call(2));
EXPECT_CALL(*mock_stream_, ReadFrames(_, _))
@@ -1610,7 +1453,7 @@ TEST_F(WebSocketChannelStreamTest, CloseOnlySentOnce) {
channel_->StartClosingHandshake(kWebSocketNormalClosure, "Close");
checkpoint.Call(2);
- *frame_chunks = CreateFrameChunkVector(chunks);
+ *frames = CreateFrameVector(frames_init);
read_callback.Run(OK);
checkpoint.Call(3);
}
@@ -1621,17 +1464,15 @@ TEST_F(WebSocketChannelStreamTest, CloseOnlySentOnce) {
// CloseWithNoPayloadGivesStatus1005, above, for confirmation that code 1005 is
// correctly generated internally.
TEST_F(WebSocketChannelStreamTest, Code1005IsNotEchoed) {
- static const InitFrameChunk chunks[] = {
- {{FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose, NOT_MASKED, 0},
- FINAL_CHUNK, ""}};
- static const InitFrameChunk expected[] = {
- {{FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose, MASKED, 0},
- FINAL_CHUNK, ""}};
+ static const InitFrame frames[] = {
+ {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose, NOT_MASKED, ""}};
+ static const InitFrame expected[] = {
+ {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose, MASKED, ""}};
EXPECT_CALL(*mock_stream_, GetSubProtocol()).Times(AnyNumber());
EXPECT_CALL(*mock_stream_, ReadFrames(_, _))
- .WillOnce(ReturnChunks(&chunks))
+ .WillOnce(ReturnFrames(&frames))
.WillRepeatedly(Return(ERR_IO_PENDING));
- EXPECT_CALL(*mock_stream_, WriteFrames(EqualsChunks(expected), _))
+ EXPECT_CALL(*mock_stream_, WriteFrames(EqualsFrames(expected), _))
.WillOnce(Return(OK));
CreateChannelAndConnectSuccessfully();
@@ -1643,58 +1484,57 @@ TEST_F(WebSocketChannelStreamTest, Code1005IsNotEchoed) {
// "Application data" as found in the message body of the Ping frame being
// replied to."
TEST_F(WebSocketChannelStreamTest, PingRepliedWithPong) {
- static const InitFrameChunk chunks[] = {
- {{FINAL_FRAME, WebSocketFrameHeader::kOpCodePing, NOT_MASKED, 16},
- FINAL_CHUNK, "Application data"}};
- static const InitFrameChunk expected[] = {
- {{FINAL_FRAME, WebSocketFrameHeader::kOpCodePong, MASKED, 16},
- FINAL_CHUNK, "Application data"}};
+ static const InitFrame frames[] = {
+ {FINAL_FRAME, WebSocketFrameHeader::kOpCodePing,
+ NOT_MASKED, "Application data"}};
+ static const InitFrame expected[] = {
+ {FINAL_FRAME, WebSocketFrameHeader::kOpCodePong,
+ MASKED, "Application data"}};
EXPECT_CALL(*mock_stream_, GetSubProtocol()).Times(AnyNumber());
EXPECT_CALL(*mock_stream_, ReadFrames(_, _))
- .WillOnce(ReturnChunks(&chunks))
+ .WillOnce(ReturnFrames(&frames))
.WillRepeatedly(Return(ERR_IO_PENDING));
- EXPECT_CALL(*mock_stream_, WriteFrames(EqualsChunks(expected), _))
+ EXPECT_CALL(*mock_stream_, WriteFrames(EqualsFrames(expected), _))
.WillOnce(Return(OK));
CreateChannelAndConnectSuccessfully();
}
TEST_F(WebSocketChannelStreamTest, PongInTheMiddleOfDataMessage) {
- static const InitFrameChunk chunks[] = {
- {{FINAL_FRAME, WebSocketFrameHeader::kOpCodePing, NOT_MASKED, 16},
- FINAL_CHUNK, "Application data"}};
- static const InitFrameChunk expected1[] = {
- {{NOT_FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, MASKED, 6},
- FINAL_CHUNK, "Hello "}};
- static const InitFrameChunk expected2[] = {
- {{FINAL_FRAME, WebSocketFrameHeader::kOpCodePong, MASKED, 16},
- FINAL_CHUNK, "Application data"}};
- static const InitFrameChunk expected3[] = {
- {{FINAL_FRAME, WebSocketFrameHeader::kOpCodeContinuation, MASKED, 5},
- FINAL_CHUNK, "World"}};
- ScopedVector<WebSocketFrameChunk>* read_chunks;
+ static const InitFrame frames[] = {
+ {FINAL_FRAME, WebSocketFrameHeader::kOpCodePing,
+ NOT_MASKED, "Application data"}};
+ static const InitFrame expected1[] = {
+ {NOT_FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, MASKED, "Hello "}};
+ static const InitFrame expected2[] = {
+ {FINAL_FRAME, WebSocketFrameHeader::kOpCodePong,
+ MASKED, "Application data"}};
+ static const InitFrame expected3[] = {
+ {FINAL_FRAME, WebSocketFrameHeader::kOpCodeContinuation,
+ MASKED, "World"}};
+ ScopedVector<WebSocketFrame>* read_frames;
CompletionCallback read_callback;
EXPECT_CALL(*mock_stream_, GetSubProtocol()).Times(AnyNumber());
EXPECT_CALL(*mock_stream_, ReadFrames(_, _))
- .WillOnce(DoAll(SaveArg<0>(&read_chunks),
+ .WillOnce(DoAll(SaveArg<0>(&read_frames),
SaveArg<1>(&read_callback),
Return(ERR_IO_PENDING)))
.WillRepeatedly(Return(ERR_IO_PENDING));
{
InSequence s;
- EXPECT_CALL(*mock_stream_, WriteFrames(EqualsChunks(expected1), _))
+ EXPECT_CALL(*mock_stream_, WriteFrames(EqualsFrames(expected1), _))
.WillOnce(Return(OK));
- EXPECT_CALL(*mock_stream_, WriteFrames(EqualsChunks(expected2), _))
+ EXPECT_CALL(*mock_stream_, WriteFrames(EqualsFrames(expected2), _))
.WillOnce(Return(OK));
- EXPECT_CALL(*mock_stream_, WriteFrames(EqualsChunks(expected3), _))
+ EXPECT_CALL(*mock_stream_, WriteFrames(EqualsFrames(expected3), _))
.WillOnce(Return(OK));
}
CreateChannelAndConnectSuccessfully();
channel_->SendFrame(
false, WebSocketFrameHeader::kOpCodeText, AsVector("Hello "));
- *read_chunks = CreateFrameChunkVector(chunks);
+ *read_frames = CreateFrameVector(frames);
read_callback.Run(OK);
channel_->SendFrame(
true, WebSocketFrameHeader::kOpCodeContinuation, AsVector("World"));
@@ -1703,12 +1543,10 @@ TEST_F(WebSocketChannelStreamTest, PongInTheMiddleOfDataMessage) {
// WriteFrames() may not be called until the previous write has completed.
// WebSocketChannel must buffer writes that happen in the meantime.
TEST_F(WebSocketChannelStreamTest, WriteFramesOneAtATime) {
- static const InitFrameChunk expected1[] = {
- {{NOT_FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, MASKED, 6},
- FINAL_CHUNK, "Hello "}};
- static const InitFrameChunk expected2[] = {
- {{FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, MASKED, 5}, FINAL_CHUNK,
- "World"}};
+ static const InitFrame expected1[] = {
+ {NOT_FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, MASKED, "Hello "}};
+ static const InitFrame expected2[] = {
+ {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, MASKED, "World"}};
CompletionCallback write_callback;
MockFunction<void(int)> checkpoint;
@@ -1717,10 +1555,10 @@ TEST_F(WebSocketChannelStreamTest, WriteFramesOneAtATime) {
{
InSequence s;
EXPECT_CALL(checkpoint, Call(1));
- EXPECT_CALL(*mock_stream_, WriteFrames(EqualsChunks(expected1), _))
+ EXPECT_CALL(*mock_stream_, WriteFrames(EqualsFrames(expected1), _))
.WillOnce(DoAll(SaveArg<1>(&write_callback), Return(ERR_IO_PENDING)));
EXPECT_CALL(checkpoint, Call(2));
- EXPECT_CALL(*mock_stream_, WriteFrames(EqualsChunks(expected2), _))
+ EXPECT_CALL(*mock_stream_, WriteFrames(EqualsFrames(expected2), _))
.WillOnce(Return(ERR_IO_PENDING));
EXPECT_CALL(checkpoint, Call(3));
}
@@ -1741,27 +1579,22 @@ TEST_F(WebSocketChannelStreamTest, WriteFramesOneAtATime) {
// important to get good throughput in the "many small messages" case.
TEST_F(WebSocketChannelStreamTest, WaitingMessagesAreBatched) {
static const char input_letters[] = "Hello";
- static const InitFrameChunk expected1[] = {
- {{FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, MASKED, 1}, FINAL_CHUNK,
- "H"}};
- static const InitFrameChunk expected2[] = {
- {{FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, MASKED, 1}, FINAL_CHUNK,
- "e"},
- {{FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, MASKED, 1}, FINAL_CHUNK,
- "l"},
- {{FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, MASKED, 1}, FINAL_CHUNK,
- "l"},
- {{FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, MASKED, 1}, FINAL_CHUNK,
- "o"}};
+ static const InitFrame expected1[] = {
+ {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, MASKED, "H"}};
+ static const InitFrame expected2[] = {
+ {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, MASKED, "e"},
+ {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, MASKED, "l"},
+ {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, MASKED, "l"},
+ {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, MASKED, "o"}};
CompletionCallback write_callback;
EXPECT_CALL(*mock_stream_, GetSubProtocol()).Times(AnyNumber());
EXPECT_CALL(*mock_stream_, ReadFrames(_, _)).WillOnce(Return(ERR_IO_PENDING));
{
InSequence s;
- EXPECT_CALL(*mock_stream_, WriteFrames(EqualsChunks(expected1), _))
+ EXPECT_CALL(*mock_stream_, WriteFrames(EqualsFrames(expected1), _))
.WillOnce(DoAll(SaveArg<1>(&write_callback), Return(ERR_IO_PENDING)));
- EXPECT_CALL(*mock_stream_, WriteFrames(EqualsChunks(expected2), _))
+ EXPECT_CALL(*mock_stream_, WriteFrames(EqualsFrames(expected2), _))
.WillOnce(Return(ERR_IO_PENDING));
}
@@ -1781,12 +1614,12 @@ TEST_F(WebSocketChannelStreamTest, WaitingMessagesAreBatched) {
// even be using a different extension which uses that code to mean something
// else.
TEST_F(WebSocketChannelStreamTest, MuxErrorIsNotSentToStream) {
- static const InitFrameChunk expected[] = {
- {{FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose, MASKED, 16},
- FINAL_CHUNK, CLOSE_DATA(GOING_AWAY, "Internal Error")}};
+ static const InitFrame expected[] = {
+ {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose,
+ MASKED, CLOSE_DATA(GOING_AWAY, "Internal Error")}};
EXPECT_CALL(*mock_stream_, GetSubProtocol()).Times(AnyNumber());
EXPECT_CALL(*mock_stream_, ReadFrames(_, _)).WillOnce(Return(ERR_IO_PENDING));
- EXPECT_CALL(*mock_stream_, WriteFrames(EqualsChunks(expected), _))
+ EXPECT_CALL(*mock_stream_, WriteFrames(EqualsFrames(expected), _))
.WillOnce(Return(OK));
EXPECT_CALL(*mock_stream_, Close());
@@ -1800,45 +1633,41 @@ TEST_F(WebSocketChannelStreamTest, MuxErrorIsNotSentToStream) {
// protocol also has Binary frames and those need to be 8-bit clean. For the
// sake of completeness, this test verifies that they are.
TEST_F(WebSocketChannelStreamTest, WrittenBinaryFramesAre8BitClean) {
- ScopedVector<WebSocketFrameChunk>* frame_chunks = NULL;
+ ScopedVector<WebSocketFrame>* frames = NULL;
EXPECT_CALL(*mock_stream_, GetSubProtocol()).Times(AnyNumber());
EXPECT_CALL(*mock_stream_, ReadFrames(_, _)).WillOnce(Return(ERR_IO_PENDING));
EXPECT_CALL(*mock_stream_, WriteFrames(_, _))
- .WillOnce(DoAll(SaveArg<0>(&frame_chunks), Return(ERR_IO_PENDING)));
+ .WillOnce(DoAll(SaveArg<0>(&frames), Return(ERR_IO_PENDING)));
CreateChannelAndConnectSuccessfully();
channel_->SendFrame(
true,
WebSocketFrameHeader::kOpCodeBinary,
std::vector<char>(kBinaryBlob, kBinaryBlob + kBinaryBlobSize));
- ASSERT_TRUE(frame_chunks != NULL);
- ASSERT_EQ(1U, frame_chunks->size());
- const WebSocketFrameChunk* out_chunk = (*frame_chunks)[0];
- ASSERT_TRUE(out_chunk->header);
- EXPECT_EQ(kBinaryBlobSize, out_chunk->header->payload_length);
- ASSERT_TRUE(out_chunk->data);
- EXPECT_EQ(kBinaryBlobSize, static_cast<size_t>(out_chunk->data->size()));
- EXPECT_EQ(0, memcmp(kBinaryBlob, out_chunk->data->data(), kBinaryBlobSize));
+ ASSERT_TRUE(frames != NULL);
+ ASSERT_EQ(1U, frames->size());
+ const WebSocketFrame* out_frame = (*frames)[0];
+ EXPECT_EQ(kBinaryBlobSize, out_frame->header.payload_length);
+ ASSERT_TRUE(out_frame->data);
+ EXPECT_EQ(0, memcmp(kBinaryBlob, out_frame->data->data(), kBinaryBlobSize));
}
// Test the read path for 8-bit cleanliness as well.
TEST_F(WebSocketChannelEventInterfaceTest, ReadBinaryFramesAre8BitClean) {
- scoped_ptr<WebSocketFrameHeader> frame_header(
- new WebSocketFrameHeader(WebSocketFrameHeader::kOpCodeBinary));
- frame_header->final = true;
- frame_header->payload_length = kBinaryBlobSize;
- scoped_ptr<WebSocketFrameChunk> frame_chunk(new WebSocketFrameChunk);
- frame_chunk->header = frame_header.Pass();
- frame_chunk->final_chunk = true;
- frame_chunk->data = new IOBufferWithSize(kBinaryBlobSize);
- memcpy(frame_chunk->data->data(), kBinaryBlob, kBinaryBlobSize);
- ScopedVector<WebSocketFrameChunk> chunks;
- chunks.push_back(frame_chunk.release());
+ scoped_ptr<WebSocketFrame> frame(
+ new WebSocketFrame(WebSocketFrameHeader::kOpCodeBinary));
+ WebSocketFrameHeader& frame_header = frame->header;
+ frame_header.final = true;
+ frame_header.payload_length = kBinaryBlobSize;
+ frame->data = new IOBuffer(kBinaryBlobSize);
+ memcpy(frame->data->data(), kBinaryBlob, kBinaryBlobSize);
+ ScopedVector<WebSocketFrame> frames;
+ frames.push_back(frame.release());
scoped_ptr<ReadableFakeWebSocketStream> stream(
new ReadableFakeWebSocketStream);
stream->PrepareRawReadFrames(
- ReadableFakeWebSocketStream::SYNC, OK, chunks.Pass());
+ ReadableFakeWebSocketStream::SYNC, OK, frames.Pass());
set_stream(stream.Pass());
EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _));
EXPECT_CALL(*event_interface_, OnFlowControl(_));
@@ -1856,17 +1685,17 @@ TEST_F(WebSocketChannelEventInterfaceTest, ReadBinaryFramesAre8BitClean) {
// but the current implementation fails the connection. Since a Close has
// already been sent, this just means closing the connection.
TEST_F(WebSocketChannelStreamTest, PingAfterCloseIsRejected) {
- static const InitFrameChunk chunks[] = {
- {{FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose, NOT_MASKED, 4},
- FINAL_CHUNK, CLOSE_DATA(NORMAL_CLOSURE, "OK")},
- {{FINAL_FRAME, WebSocketFrameHeader::kOpCodePing, NOT_MASKED, 9},
- FINAL_CHUNK, "Ping body"}};
- static const InitFrameChunk expected[] = {
- {{FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose, MASKED, 4},
- FINAL_CHUNK, CLOSE_DATA(NORMAL_CLOSURE, "OK")}};
+ static const InitFrame frames[] = {
+ {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose,
+ NOT_MASKED, CLOSE_DATA(NORMAL_CLOSURE, "OK")},
+ {FINAL_FRAME, WebSocketFrameHeader::kOpCodePing,
+ NOT_MASKED, "Ping body"}};
+ static const InitFrame expected[] = {
+ {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose,
+ MASKED, CLOSE_DATA(NORMAL_CLOSURE, "OK")}};
EXPECT_CALL(*mock_stream_, GetSubProtocol()).Times(AnyNumber());
EXPECT_CALL(*mock_stream_, ReadFrames(_, _))
- .WillOnce(ReturnChunks(&chunks))
+ .WillOnce(ReturnFrames(&frames))
.WillRepeatedly(Return(ERR_IO_PENDING));
{
// We only need to verify the relative order of WriteFrames() and
@@ -1874,7 +1703,7 @@ TEST_F(WebSocketChannelStreamTest, PingAfterCloseIsRejected) {
// frame before calling ReadFrames() again, but that is an implementation
// detail and better not to consider required behaviour.
InSequence s;
- EXPECT_CALL(*mock_stream_, WriteFrames(EqualsChunks(expected), _))
+ EXPECT_CALL(*mock_stream_, WriteFrames(EqualsFrames(expected), _))
.WillOnce(Return(OK));
EXPECT_CALL(*mock_stream_, Close()).Times(1);
}
@@ -1882,5 +1711,21 @@ TEST_F(WebSocketChannelStreamTest, PingAfterCloseIsRejected) {
CreateChannelAndConnectSuccessfully();
}
+// A protocol error from the remote server should result in a close frame with
+// status 1002, followed by the connection closing.
+TEST_F(WebSocketChannelStreamTest, ProtocolError) {
+ static const InitFrame expected[] = {
+ {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose,
+ MASKED, CLOSE_DATA(PROTOCOL_ERROR, "WebSocket Protocol Error")}};
+ EXPECT_CALL(*mock_stream_, GetSubProtocol()).Times(AnyNumber());
+ EXPECT_CALL(*mock_stream_, ReadFrames(_, _))
+ .WillOnce(Return(ERR_WS_PROTOCOL_ERROR));
+ EXPECT_CALL(*mock_stream_, WriteFrames(EqualsFrames(expected), _))
+ .WillOnce(Return(OK));
+ EXPECT_CALL(*mock_stream_, Close());
+
+ CreateChannelAndConnectSuccessfully();
+}
+
} // namespace
} // namespace net