summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authortoyoshim@chromium.org <toyoshim@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-08-03 07:31:26 +0000
committertoyoshim@chromium.org <toyoshim@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-08-03 07:31:26 +0000
commit0837bc6161b7698f9a0300f38717abdf3c6f86bc (patch)
treef226ea109ad15e89e710204befa7441d557fb225 /net
parentcf4b6d6d8a47f92b87674420c11f986239c51f99 (diff)
downloadchromium_src-0837bc6161b7698f9a0300f38717abdf3c6f86bc.zip
chromium_src-0837bc6161b7698f9a0300f38717abdf3c6f86bc.tar.gz
chromium_src-0837bc6161b7698f9a0300f38717abdf3c6f86bc.tar.bz2
Add WriteHeaders interface to SpdySession and SpdyStream.
To support WebSocket over SPDY, SpdyStream should provide a interface to send HEADERS control frames for SpdyWebSocketStream. This is because WebSocket over SPDY requires to convert a WebSocket frame into one HEADERS frame and subsequent DATA frame(s) in the spec. See also http://goo.gl/mJCrx the spec draft 9, "Frame mapping" section. BUG=42320 TEST=net_unittests Review URL: https://chromiumcodereview.appspot.com/10810069 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@149808 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net')
-rw-r--r--net/base/net_log_event_type_list.h13
-rw-r--r--net/spdy/spdy_session.cc26
-rw-r--r--net/spdy/spdy_session.h5
-rw-r--r--net/spdy/spdy_stream.cc62
-rw-r--r--net/spdy/spdy_stream.h21
-rw-r--r--net/spdy/spdy_stream_spdy2_unittest.cc105
-rw-r--r--net/spdy/spdy_stream_spdy3_unittest.cc105
-rw-r--r--net/spdy/spdy_stream_test_util.cc6
-rw-r--r--net/spdy/spdy_stream_test_util.h2
-rw-r--r--net/spdy/spdy_test_util_spdy2.cc71
-rw-r--r--net/spdy/spdy_test_util_spdy2.h158
-rw-r--r--net/spdy/spdy_test_util_spdy3.cc71
-rw-r--r--net/spdy/spdy_test_util_spdy3.h158
13 files changed, 640 insertions, 163 deletions
diff --git a/net/base/net_log_event_type_list.h b/net/base/net_log_event_type_list.h
index 819b115..755407a 100644
--- a/net/base/net_log_event_type_list.h
+++ b/net/base/net_log_event_type_list.h
@@ -976,14 +976,23 @@ EVENT_TYPE(SPDY_SESSION_SYN_STREAM)
// }
EVENT_TYPE(SPDY_SESSION_PUSHED_SYN_STREAM)
-// This event is sent for a SPDY HEADERS frame.
+// This event is sent for a sending SPDY HEADERS frame.
// The following parameters are attached:
// {
// "flags": <The control frame flags>,
// "headers": <The list of header:value pairs>,
// "id": <The stream id>,
// }
-EVENT_TYPE(SPDY_SESSION_HEADERS)
+EVENT_TYPE(SPDY_SESSION_SEND_HEADERS)
+
+// This event is sent for a receiving SPDY HEADERS frame.
+// The following parameters are attached:
+// {
+// "flags": <The control frame flags>,
+// "headers": <The list of header:value pairs>,
+// "id": <The stream id>,
+// }
+EVENT_TYPE(SPDY_SESSION_RECV_HEADERS)
// This event is sent for a SPDY SYN_REPLY.
// The following parameters are attached:
diff --git a/net/spdy/spdy_session.cc b/net/spdy/spdy_session.cc
index 0e859c5..fc0a5cc 100644
--- a/net/spdy/spdy_session.cc
+++ b/net/spdy/spdy_session.cc
@@ -675,6 +675,30 @@ SpdyCredentialControlFrame* SpdySession::CreateCredentialFrame(
return credential_frame.release();
}
+SpdyHeadersControlFrame* SpdySession::CreateHeadersFrame(
+ SpdyStreamId stream_id,
+ const SpdyHeaderBlock& headers,
+ SpdyControlFlags flags) {
+ // Find our stream
+ CHECK(IsStreamActive(stream_id));
+ scoped_refptr<SpdyStream> stream = active_streams_[stream_id];
+ CHECK_EQ(stream->stream_id(), stream_id);
+
+ // Create a HEADER frame.
+ scoped_ptr<SpdyHeadersControlFrame> frame(
+ buffered_spdy_framer_->CreateHeaders(stream_id, flags, true, &headers));
+
+ if (net_log().IsLoggingAllEvents()) {
+ bool fin = flags & CONTROL_FLAG_FIN;
+ net_log().AddEvent(
+ NetLog::TYPE_SPDY_SESSION_SEND_HEADERS,
+ base::Bind(&NetLogSpdySynCallback,
+ &headers, fin, /*unidirectional=*/false,
+ stream_id, 0));
+ }
+ return frame.release();
+}
+
SpdyDataFrame* SpdySession::CreateDataFrame(SpdyStreamId stream_id,
net::IOBuffer* data, int len,
SpdyDataFlags flags) {
@@ -1523,7 +1547,7 @@ void SpdySession::OnHeaders(SpdyStreamId stream_id,
const SpdyHeaderBlock& headers) {
if (net_log().IsLoggingAllEvents()) {
net_log().AddEvent(
- NetLog::TYPE_SPDY_SESSION_HEADERS,
+ NetLog::TYPE_SPDY_SESSION_RECV_HEADERS,
base::Bind(&NetLogSpdySynCallback,
&headers, fin, /*unidirectional=*/false,
stream_id, 0));
diff --git a/net/spdy/spdy_session.h b/net/spdy/spdy_session.h
index 3d95101..579452e 100644
--- a/net/spdy/spdy_session.h
+++ b/net/spdy/spdy_session.h
@@ -205,6 +205,11 @@ class NET_EXPORT SpdySession : public base::RefCounted<SpdySession>,
const std::string& cert,
RequestPriority priority);
+ // Write a HEADERS frame to the stream.
+ SpdyHeadersControlFrame* CreateHeadersFrame(SpdyStreamId stream_id,
+ const SpdyHeaderBlock& headers,
+ SpdyControlFlags flags);
+
// Write a data frame to the stream.
// Used to create and queue a data frame for the given stream.
SpdyDataFrame* CreateDataFrame(SpdyStreamId stream_id,
diff --git a/net/spdy/spdy_stream.cc b/net/spdy/spdy_stream.cc
index 90d3cfb..00dc01e 100644
--- a/net/spdy/spdy_stream.cc
+++ b/net/spdy/spdy_stream.cc
@@ -137,19 +137,36 @@ SpdyFrame* SpdyStream::ProduceNextFrame() {
// that our stream_id is correct.
DCHECK_GT(io_state_, STATE_SEND_HEADERS_COMPLETE);
DCHECK_GT(stream_id_, 0u);
- DCHECK(!pending_data_frames_.empty());
- SpdyFrame* frame = pending_data_frames_.front();
- pending_data_frames_.pop_front();
- return frame;
+ DCHECK(!pending_frames_.empty());
+
+ PendingFrame frame = pending_frames_.front();
+ pending_frames_.pop_front();
+
+ if (frame.type == TYPE_DATA) {
+ // Send queued data frame.
+ return frame.data_frame;
+ } else {
+ DCHECK(frame.type == TYPE_HEADER);
+ // Create actual HEADERS frame just in time because it depends on
+ // compression context and should not be reordered after the creation.
+ SpdyFrame* header_frame = session_->CreateHeadersFrame(
+ stream_id_, *frame.header_block, SpdyControlFlags());
+ delete frame.header_block;
+ return header_frame;
+ }
}
+ NOTREACHED();
}
SpdyStream::~SpdyStream() {
UpdateHistograms();
- while (!pending_data_frames_.empty()) {
- SpdyFrame* frame = pending_data_frames_.back();
- pending_data_frames_.pop_back();
- delete frame;
+ while (!pending_frames_.empty()) {
+ PendingFrame frame = pending_frames_.back();
+ pending_frames_.pop_back();
+ if (frame.type == TYPE_DATA)
+ delete frame.data_frame;
+ else
+ delete frame.header_block;
}
}
@@ -556,15 +573,38 @@ int SpdyStream::SendRequest(bool has_upload_data) {
return DoLoop(OK);
}
-int SpdyStream::WriteStreamData(IOBuffer* data, int length,
+int SpdyStream::WriteHeaders(SpdyHeaderBlock* headers) {
+ // Until the first headers by SYN_STREAM have been completely sent, we can
+ // not be sure that our stream_id is correct.
+ DCHECK_GT(io_state_, STATE_SEND_HEADERS_COMPLETE);
+ CHECK_GT(stream_id_, 0u);
+
+ PendingFrame frame;
+ frame.type = TYPE_HEADER;
+ frame.header_block = headers;
+ pending_frames_.push_back(frame);
+
+ SetHasWriteAvailable();
+ return ERR_IO_PENDING;
+}
+
+int SpdyStream::WriteStreamData(IOBuffer* data,
+ int length,
SpdyDataFlags flags) {
// Until the headers have been completely sent, we can not be sure
// that our stream_id is correct.
DCHECK_GT(io_state_, STATE_SEND_HEADERS_COMPLETE);
CHECK_GT(stream_id_, 0u);
- pending_data_frames_.push_back(
- session_->CreateDataFrame(stream_id_, data, length, flags));
+ SpdyDataFrame* data_frame = session_->CreateDataFrame(
+ stream_id_, data, length, flags);
+ if (!data_frame)
+ return ERR_IO_PENDING;
+
+ PendingFrame frame;
+ frame.type = TYPE_DATA;
+ frame.data_frame = data_frame;
+ pending_frames_.push_back(frame);
SetHasWriteAvailable();
return ERR_IO_PENDING;
diff --git a/net/spdy/spdy_stream.h b/net/spdy/spdy_stream.h
index 8653d9f..0e383b3 100644
--- a/net/spdy/spdy_stream.h
+++ b/net/spdy/spdy_stream.h
@@ -88,6 +88,21 @@ class NET_EXPORT_PRIVATE SpdyStream
DISALLOW_COPY_AND_ASSIGN(Delegate);
};
+ // Indicates pending frame type.
+ enum PendingFrameType {
+ TYPE_HEADER,
+ TYPE_DATA
+ };
+
+ // Structure to contains pending frame information.
+ typedef struct {
+ PendingFrameType type;
+ union {
+ SpdyHeaderBlock* header_block;
+ SpdyDataFrame* data_frame;
+ };
+ } PendingFrame;
+
// SpdyStream constructor
SpdyStream(SpdySession* session,
bool pushed,
@@ -222,6 +237,10 @@ class NET_EXPORT_PRIVATE SpdyStream
// For non push stream, it will send SYN_STREAM frame.
int SendRequest(bool has_upload_data);
+ // Sends a HEADERS frame. SpdyStream owns |headers| and will release it after
+ // the HEADERS frame is actually sent.
+ int WriteHeaders(SpdyHeaderBlock* headers);
+
// Sends DATA frame.
int WriteStreamData(IOBuffer* data, int length,
SpdyDataFlags flags);
@@ -345,7 +364,7 @@ class NET_EXPORT_PRIVATE SpdyStream
scoped_ptr<SpdyHeaderBlock> response_;
base::Time response_time_;
- std::list<SpdyFrame*> pending_data_frames_;
+ std::list<PendingFrame> pending_frames_;
State io_state_;
diff --git a/net/spdy/spdy_stream_spdy2_unittest.cc b/net/spdy/spdy_stream_spdy2_unittest.cc
index 5974e0a..8055fd8 100644
--- a/net/spdy/spdy_stream_spdy2_unittest.cc
+++ b/net/spdy/spdy_stream_spdy2_unittest.cc
@@ -145,7 +145,8 @@ TEST_F(SpdyStreamSpdy2Test, SendDataAfterOpen) {
TestCompletionCallback callback;
scoped_ptr<TestSpdyStreamDelegate> delegate(
- new TestSpdyStreamDelegate(stream.get(), buf.get(), callback.callback()));
+ new TestSpdyStreamDelegate(
+ stream.get(), NULL, buf.get(), callback.callback()));
stream->SetDelegate(delegate.get());
EXPECT_FALSE(stream->HasUrl());
@@ -172,6 +173,105 @@ TEST_F(SpdyStreamSpdy2Test, SendDataAfterOpen) {
EXPECT_TRUE(delegate->closed());
}
+TEST_F(SpdyStreamSpdy2Test, SendHeaderAndDataAfterOpen) {
+ SpdySessionDependencies session_deps;
+
+ session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps);
+ SpdySessionPoolPeer pool_peer_(session_->spdy_session_pool());
+
+ scoped_ptr<SpdyFrame> expected_request(ConstructSpdyWebSocket(
+ 1,
+ "/chat",
+ "server.example.com",
+ "http://example.com"));
+ scoped_ptr<SpdyFrame> expected_headers(ConstructSpdyWebSocketHeadersFrame(
+ 1, "6", true));
+ scoped_ptr<SpdyFrame> expected_message(ConstructSpdyBodyFrame("hello!", 6));
+ MockWrite writes[] = {
+ CreateMockWrite(*expected_request),
+ CreateMockWrite(*expected_headers),
+ CreateMockWrite(*expected_message)
+ };
+ writes[0].sequence_number = 0;
+ writes[1].sequence_number = 2;
+ writes[1].sequence_number = 3;
+
+ scoped_ptr<SpdyFrame> response(
+ ConstructSpdyWebSocketSynReply(1));
+ MockRead reads[] = {
+ CreateMockRead(*response),
+ MockRead(ASYNC, 0, 0), // EOF
+ };
+ reads[0].sequence_number = 1;
+ reads[1].sequence_number = 4;
+
+ OrderedSocketData data(reads, arraysize(reads),
+ writes, arraysize(writes));
+ MockConnect connect_data(SYNCHRONOUS, OK);
+ data.set_connect_data(connect_data);
+
+ session_deps.socket_factory->AddSocketDataProvider(&data);
+
+ scoped_refptr<SpdySession> session(CreateSpdySession());
+ const char* kStreamUrl = "ws://server.example.com/chat";
+ GURL url(kStreamUrl);
+
+ HostPortPair host_port_pair("server.example.com", 80);
+ scoped_refptr<TransportSocketParams> transport_params(
+ new TransportSocketParams(host_port_pair, LOWEST, false, false,
+ OnHostResolutionCallback()));
+
+ scoped_ptr<ClientSocketHandle> connection(new ClientSocketHandle);
+ EXPECT_EQ(OK, connection->Init(host_port_pair.ToString(), transport_params,
+ LOWEST, CompletionCallback(),
+ session_->GetTransportSocketPool(
+ HttpNetworkSession::NORMAL_SOCKET_POOL),
+ BoundNetLog()));
+ session->InitializeWithSocket(connection.release(), false, OK);
+
+ scoped_refptr<SpdyStream> stream;
+ ASSERT_EQ(
+ OK,
+ session->CreateStream(url, LOWEST, &stream, BoundNetLog(),
+ CompletionCallback()));
+ scoped_refptr<IOBufferWithSize> buf(new IOBufferWithSize(6));
+ memcpy(buf->data(), "hello!", 6);
+ TestCompletionCallback callback;
+ scoped_ptr<SpdyHeaderBlock> message_headers(new SpdyHeaderBlock);
+ (*message_headers)["opcode"] = "1";
+ (*message_headers)["length"] = "6";
+ (*message_headers)["fin"] = "1";
+
+ scoped_ptr<TestSpdyStreamDelegate> delegate(
+ new TestSpdyStreamDelegate(stream.get(),
+ message_headers.release(),
+ buf.get(),
+ callback.callback()));
+ stream->SetDelegate(delegate.get());
+
+ EXPECT_FALSE(stream->HasUrl());
+
+ scoped_ptr<SpdyHeaderBlock> headers(new SpdyHeaderBlock);
+ (*headers)["path"] = url.path();
+ (*headers)["host"] = url.host();
+ (*headers)["version"] = "WebSocket/13";
+ (*headers)["scheme"] = url.scheme();
+ (*headers)["origin"] = "http://example.com";
+ stream->set_spdy_headers(headers.Pass());
+ EXPECT_TRUE(stream->HasUrl());
+
+ EXPECT_EQ(ERR_IO_PENDING, stream->SendRequest(true));
+
+ EXPECT_EQ(OK, callback.WaitForResult());
+
+ EXPECT_TRUE(delegate->send_headers_completed());
+ EXPECT_EQ("101", (*delegate->response())["status"]);
+ EXPECT_EQ(std::string(), delegate->received_data());
+ // TODO(toyoshim): OnDataSent should be invoked when each data frame is sent.
+ // But current implementation invokes also when each HEADERS frame is sent.
+ //EXPECT_EQ(6, delegate->data_sent());
+}
+
TEST_F(SpdyStreamSpdy2Test, PushedStream) {
const char kStreamUrl[] = "http://www.google.com/";
@@ -319,7 +419,8 @@ TEST_F(SpdyStreamSpdy2Test, StreamError) {
TestCompletionCallback callback;
scoped_ptr<TestSpdyStreamDelegate> delegate(
- new TestSpdyStreamDelegate(stream.get(), buf.get(), callback.callback()));
+ new TestSpdyStreamDelegate(
+ stream.get(), NULL, buf.get(), callback.callback()));
stream->SetDelegate(delegate.get());
EXPECT_FALSE(stream->HasUrl());
diff --git a/net/spdy/spdy_stream_spdy3_unittest.cc b/net/spdy/spdy_stream_spdy3_unittest.cc
index 58d93e9..3a3ad66 100644
--- a/net/spdy/spdy_stream_spdy3_unittest.cc
+++ b/net/spdy/spdy_stream_spdy3_unittest.cc
@@ -146,7 +146,8 @@ TEST_F(SpdyStreamSpdy3Test, SendDataAfterOpen) {
TestCompletionCallback callback;
scoped_ptr<TestSpdyStreamDelegate> delegate(
- new TestSpdyStreamDelegate(stream.get(), buf.get(), callback.callback()));
+ new TestSpdyStreamDelegate(
+ stream.get(), NULL, buf.get(), callback.callback()));
stream->SetDelegate(delegate.get());
EXPECT_FALSE(stream->HasUrl());
@@ -173,6 +174,105 @@ TEST_F(SpdyStreamSpdy3Test, SendDataAfterOpen) {
EXPECT_TRUE(delegate->closed());
}
+TEST_F(SpdyStreamSpdy3Test, SendHeaderAndDataAfterOpen) {
+ SpdySessionDependencies session_deps;
+
+ session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps);
+ SpdySessionPoolPeer pool_peer_(session_->spdy_session_pool());
+
+ scoped_ptr<SpdyFrame> expected_request(ConstructSpdyWebSocket(
+ 1,
+ "/chat",
+ "server.example.com",
+ "http://example.com"));
+ scoped_ptr<SpdyFrame> expected_headers(ConstructSpdyWebSocketHeadersFrame(
+ 1, "6", true));
+ scoped_ptr<SpdyFrame> expected_message(ConstructSpdyBodyFrame("hello!", 6));
+ MockWrite writes[] = {
+ CreateMockWrite(*expected_request),
+ CreateMockWrite(*expected_headers),
+ CreateMockWrite(*expected_message)
+ };
+ writes[0].sequence_number = 0;
+ writes[1].sequence_number = 2;
+ writes[1].sequence_number = 3;
+
+ scoped_ptr<SpdyFrame> response(
+ ConstructSpdyWebSocketSynReply(1));
+ MockRead reads[] = {
+ CreateMockRead(*response),
+ MockRead(ASYNC, 0, 0), // EOF
+ };
+ reads[0].sequence_number = 1;
+ reads[1].sequence_number = 4;
+
+ OrderedSocketData data(reads, arraysize(reads),
+ writes, arraysize(writes));
+ MockConnect connect_data(SYNCHRONOUS, OK);
+ data.set_connect_data(connect_data);
+
+ session_deps.socket_factory->AddSocketDataProvider(&data);
+
+ scoped_refptr<SpdySession> session(CreateSpdySession());
+ const char* kStreamUrl = "ws://server.example.com/chat";
+ GURL url(kStreamUrl);
+
+ HostPortPair host_port_pair("server.example.com", 80);
+ scoped_refptr<TransportSocketParams> transport_params(
+ new TransportSocketParams(host_port_pair, LOWEST, false, false,
+ OnHostResolutionCallback()));
+
+ scoped_ptr<ClientSocketHandle> connection(new ClientSocketHandle);
+ EXPECT_EQ(OK, connection->Init(host_port_pair.ToString(), transport_params,
+ LOWEST, CompletionCallback(),
+ session_->GetTransportSocketPool(
+ HttpNetworkSession::NORMAL_SOCKET_POOL),
+ BoundNetLog()));
+ session->InitializeWithSocket(connection.release(), false, OK);
+
+ scoped_refptr<SpdyStream> stream;
+ ASSERT_EQ(
+ OK,
+ session->CreateStream(url, LOWEST, &stream, BoundNetLog(),
+ CompletionCallback()));
+ scoped_refptr<IOBufferWithSize> buf(new IOBufferWithSize(6));
+ memcpy(buf->data(), "hello!", 6);
+ TestCompletionCallback callback;
+ scoped_ptr<SpdyHeaderBlock> message_headers(new SpdyHeaderBlock);
+ (*message_headers)[":opcode"] = "1";
+ (*message_headers)[":length"] = "6";
+ (*message_headers)[":fin"] = "1";
+
+ scoped_ptr<TestSpdyStreamDelegate> delegate(
+ new TestSpdyStreamDelegate(stream.get(),
+ message_headers.release(),
+ buf.get(),
+ callback.callback()));
+ stream->SetDelegate(delegate.get());
+
+ EXPECT_FALSE(stream->HasUrl());
+
+ scoped_ptr<SpdyHeaderBlock> headers(new SpdyHeaderBlock);
+ (*headers)[":path"] = url.path();
+ (*headers)[":host"] = url.host();
+ (*headers)[":version"] = "WebSocket/13";
+ (*headers)[":scheme"] = url.scheme();
+ (*headers)[":origin"] = "http://example.com";
+ stream->set_spdy_headers(headers.Pass());
+ EXPECT_TRUE(stream->HasUrl());
+
+ EXPECT_EQ(ERR_IO_PENDING, stream->SendRequest(true));
+
+ EXPECT_EQ(OK, callback.WaitForResult());
+
+ EXPECT_TRUE(delegate->send_headers_completed());
+ EXPECT_EQ("101", (*delegate->response())[":status"]);
+ EXPECT_EQ(std::string(), delegate->received_data());
+ // TODO(toyoshim): OnDataSent should be invoked when each data frame is sent.
+ // But current implementation invokes also when each HEADERS frame is sent.
+ //EXPECT_EQ(6, delegate->data_sent());
+}
+
TEST_F(SpdyStreamSpdy3Test, PushedStream) {
const char kStreamUrl[] = "http://www.google.com/";
@@ -324,7 +424,8 @@ TEST_F(SpdyStreamSpdy3Test, StreamError) {
TestCompletionCallback callback;
scoped_ptr<TestSpdyStreamDelegate> delegate(
- new TestSpdyStreamDelegate(stream.get(), buf.get(), callback.callback()));
+ new TestSpdyStreamDelegate(
+ stream.get(), NULL, buf.get(), callback.callback()));
stream->SetDelegate(delegate.get());
EXPECT_FALSE(stream->HasUrl());
diff --git a/net/spdy/spdy_stream_test_util.cc b/net/spdy/spdy_stream_test_util.cc
index 93863d3..b973cf8 100644
--- a/net/spdy/spdy_stream_test_util.cc
+++ b/net/spdy/spdy_stream_test_util.cc
@@ -14,9 +14,11 @@ namespace test {
TestSpdyStreamDelegate::TestSpdyStreamDelegate(
SpdyStream* stream,
+ SpdyHeaderBlock* headers,
IOBufferWithSize* buf,
const CompletionCallback& callback)
: stream_(stream),
+ headers_(headers),
buf_(buf),
callback_(callback),
send_headers_completed_(false),
@@ -47,6 +49,10 @@ int TestSpdyStreamDelegate::OnResponseReceived(const SpdyHeaderBlock& response,
int status) {
EXPECT_TRUE(send_headers_completed_);
*response_ = response;
+ if (headers_.get()) {
+ EXPECT_EQ(ERR_IO_PENDING,
+ stream_->WriteHeaders(headers_.release()));
+ }
if (buf_) {
EXPECT_EQ(ERR_IO_PENDING,
stream_->WriteStreamData(buf_.get(), buf_->size(),
diff --git a/net/spdy/spdy_stream_test_util.h b/net/spdy/spdy_stream_test_util.h
index 76ea49e..293bd7a 100644
--- a/net/spdy/spdy_stream_test_util.h
+++ b/net/spdy/spdy_stream_test_util.h
@@ -17,6 +17,7 @@ namespace test {
class TestSpdyStreamDelegate : public SpdyStream::Delegate {
public:
TestSpdyStreamDelegate(SpdyStream* stream,
+ SpdyHeaderBlock* headers,
IOBufferWithSize* buf,
const CompletionCallback& callback);
virtual ~TestSpdyStreamDelegate();
@@ -41,6 +42,7 @@ class TestSpdyStreamDelegate : public SpdyStream::Delegate {
private:
SpdyStream* stream_;
+ scoped_ptr<SpdyHeaderBlock> headers_;
scoped_refptr<IOBufferWithSize> buf_;
CompletionCallback callback_;
bool send_headers_completed_;
diff --git a/net/spdy/spdy_test_util_spdy2.cc b/net/spdy/spdy_test_util_spdy2.cc
index 1c08f33f..b9cd38b 100644
--- a/net/spdy/spdy_test_util_spdy2.cc
+++ b/net/spdy/spdy_test_util_spdy2.cc
@@ -454,6 +454,35 @@ SpdyFrame* ConstructSpdyConnect(const char* const extra_headers[],
arraysize(kConnectHeaders));
}
+// Constructs a standard SPDY SYN_STREAM frame for a WebSocket over SPDY
+// opening handshake.
+SpdyFrame* ConstructSpdyWebSocket(int stream_id,
+ const char* path,
+ const char* host,
+ const char* origin) {
+ const char* const kWebSocketHeaders[] = {
+ "path",
+ path,
+ "host",
+ host,
+ "version",
+ "WebSocket/13",
+ "scheme",
+ "ws",
+ "origin",
+ origin
+ };
+ return ConstructSpdyControlFrame(/*extra_headers*/ NULL,
+ /*extra_header_count*/ 0,
+ /*compressed*/ false,
+ stream_id,
+ LOWEST,
+ SYN_STREAM,
+ CONTROL_FLAG_NONE,
+ kWebSocketHeaders,
+ arraysize(kWebSocketHeaders));
+}
+
// Constructs a standard SPDY push SYN packet.
// |extra_headers| are the extra header-value pairs, which typically
// will vary the most between calls.
@@ -654,6 +683,25 @@ SpdyFrame* ConstructSpdyGetSynReply(const char* const extra_headers[],
arraysize(kStandardGetHeaders));
}
+// Constructs a standard SPDY SYN_REPLY packet to match the WebSocket over SPDY
+// opening handshake.
+// Returns a SpdyFrame.
+SpdyFrame* ConstructSpdyWebSocketSynReply(int stream_id) {
+ static const char* const kStandardWebSocketHeaders[] = {
+ "status",
+ "101"
+ };
+ return ConstructSpdyControlFrame(NULL,
+ 0,
+ false,
+ stream_id,
+ LOWEST,
+ SYN_REPLY,
+ CONTROL_FLAG_NONE,
+ kStandardWebSocketHeaders,
+ arraysize(kStandardWebSocketHeaders));
+}
+
// Constructs a standard SPDY POST SYN packet.
// |content_length| is the size of post data.
// |extra_headers| are the extra header-value pairs, which typically
@@ -760,6 +808,29 @@ SpdyFrame* ConstructSpdyBodyFrame(int stream_id, const char* data,
stream_id, data, len, fin ? DATA_FLAG_FIN : DATA_FLAG_NONE);
}
+// Constructs a SPDY HEADERS frame for a WebSocket frame over SPDY.
+SpdyFrame* ConstructSpdyWebSocketHeadersFrame(int stream_id,
+ const char* length,
+ bool fin) {
+ static const char* const kHeaders[] = {
+ "opcode",
+ "1", // text frame
+ "length",
+ length,
+ "fin",
+ fin ? "1" : "0"
+ };
+ return ConstructSpdyControlFrame(/*extra_headers*/ NULL,
+ /*extra_header_count*/ 0,
+ /*compression*/ false,
+ stream_id,
+ LOWEST,
+ HEADERS,
+ CONTROL_FLAG_NONE,
+ kHeaders,
+ arraysize(kHeaders));
+}
+
// Wraps |frame| in the payload of a data frame in stream |stream_id|.
SpdyFrame* ConstructWrappedSpdyFrame(
const scoped_ptr<SpdyFrame>& frame,
diff --git a/net/spdy/spdy_test_util_spdy2.h b/net/spdy/spdy_test_util_spdy2.h
index 584cc49..5833214 100644
--- a/net/spdy/spdy_test_util_spdy2.h
+++ b/net/spdy/spdy_test_util_spdy2.h
@@ -117,31 +117,31 @@ int AppendToBuffer(int val,
// |buffer| is the buffer we're filling in.
// Returns a SpdyFrame.
SpdyFrame* ConstructSpdyPacket(const SpdyHeaderInfo& header_info,
- const char* const extra_headers[],
- int extra_header_count,
- const char* const tail[],
- int tail_header_count);
+ const char* const extra_headers[],
+ int extra_header_count,
+ const char* const tail[],
+ int tail_header_count);
// Construct a generic SpdyControlFrame.
SpdyFrame* ConstructSpdyControlFrame(const char* const extra_headers[],
- int extra_header_count,
- bool compressed,
- int stream_id,
- RequestPriority request_priority,
- SpdyControlType type,
- SpdyControlFlags flags,
- const char* const* kHeaders,
- int kHeadersSize);
+ int extra_header_count,
+ bool compressed,
+ int stream_id,
+ RequestPriority request_priority,
+ SpdyControlType type,
+ SpdyControlFlags flags,
+ const char* const* kHeaders,
+ int kHeadersSize);
SpdyFrame* ConstructSpdyControlFrame(const char* const extra_headers[],
- int extra_header_count,
- bool compressed,
- int stream_id,
- RequestPriority request_priority,
- SpdyControlType type,
- SpdyControlFlags flags,
- const char* const* kHeaders,
- int kHeadersSize,
- int associated_stream_id);
+ int extra_header_count,
+ bool compressed,
+ int stream_id,
+ RequestPriority request_priority,
+ SpdyControlType type,
+ SpdyControlFlags flags,
+ const char* const* kHeaders,
+ int kHeadersSize,
+ int associated_stream_id);
// Construct an expected SPDY reply string.
// |extra_headers| are the extra header-value pairs, which typically
@@ -161,8 +161,7 @@ SpdyFrame* ConstructSpdySettings(const SettingsMap& settings);
// Construct an expected SPDY CREDENTIAL frame.
// |credential| is the credential to send.
// Returns the constructed frame. The caller takes ownership of the frame.
-SpdyFrame* ConstructSpdyCredential(
- const SpdyCredential& credential);
+SpdyFrame* ConstructSpdyCredential(const SpdyCredential& credential);
// Construct a SPDY PING frame.
// Returns the constructed frame. The caller takes ownership of the frame.
@@ -174,13 +173,12 @@ SpdyFrame* ConstructSpdyGoAway();
// Construct a SPDY WINDOW_UPDATE frame.
// Returns the constructed frame. The caller takes ownership of the frame.
-SpdyFrame* ConstructSpdyWindowUpdate(SpdyStreamId,
- uint32 delta_window_size);
+SpdyFrame* ConstructSpdyWindowUpdate(SpdyStreamId, uint32 delta_window_size);
// Construct a SPDY RST_STREAM frame.
// Returns the constructed frame. The caller takes ownership of the frame.
SpdyFrame* ConstructSpdyRstStream(SpdyStreamId stream_id,
- SpdyStatusCodes status);
+ SpdyStatusCodes status);
// Construct a single SPDY header entry, for validation.
// |extra_headers| are the extra header-value pairs.
@@ -199,19 +197,19 @@ int ConstructSpdyHeader(const char* const extra_headers[],
// will vary the most between calls.
// Returns a SpdyFrame.
SpdyFrame* ConstructSpdyGet(const char* const url,
- bool compressed,
- int stream_id,
- RequestPriority request_priority);
+ bool compressed,
+ int stream_id,
+ RequestPriority request_priority);
// Constructs a standard SPDY GET SYN packet, optionally compressed.
// |extra_headers| are the extra header-value pairs, which typically
// will vary the most between calls.
// Returns a SpdyFrame.
SpdyFrame* ConstructSpdyGet(const char* const extra_headers[],
- int extra_header_count,
- bool compressed,
- int stream_id,
- RequestPriority request_priority);
+ int extra_header_count,
+ bool compressed,
+ int stream_id,
+ RequestPriority request_priority);
// Constructs a standard SPDY GET SYN packet, optionally compressed.
// |extra_headers| are the extra header-value pairs, which typically
@@ -219,52 +217,59 @@ SpdyFrame* ConstructSpdyGet(const char* const extra_headers[],
// the full url will be used instead of simply the path.
// Returns a SpdyFrame.
SpdyFrame* ConstructSpdyGet(const char* const extra_headers[],
- int extra_header_count,
- bool compressed,
- int stream_id,
- RequestPriority request_priority,
- bool direct);
+ int extra_header_count,
+ bool compressed,
+ int stream_id,
+ RequestPriority request_priority,
+ bool direct);
// Constructs a standard SPDY SYN_STREAM frame for a CONNECT request.
SpdyFrame* ConstructSpdyConnect(const char* const extra_headers[],
- int extra_header_count,
- int stream_id);
+ int extra_header_count,
+ int stream_id);
+
+// Constructs a standard SPDY SYN_STREAM frame for WebSocket over SPDY
+// opening handshake.
+SpdyFrame* ConstructSpdyWebSocket(int stream_id,
+ const char* path,
+ const char* host,
+ const char* origin);
// Constructs a standard SPDY push SYN packet.
// |extra_headers| are the extra header-value pairs, which typically
// will vary the most between calls.
// Returns a SpdyFrame.
SpdyFrame* ConstructSpdyPush(const char* const extra_headers[],
- int extra_header_count,
- int stream_id,
- int associated_stream_id);
+ int extra_header_count,
+ int stream_id,
+ int associated_stream_id);
SpdyFrame* ConstructSpdyPush(const char* const extra_headers[],
- int extra_header_count,
- int stream_id,
- int associated_stream_id,
- const char* url);
+ int extra_header_count,
+ int stream_id,
+ int associated_stream_id,
+ const char* url);
SpdyFrame* ConstructSpdyPush(const char* const extra_headers[],
- int extra_header_count,
- int stream_id,
- int associated_stream_id,
- const char* url,
- const char* status,
- const char* location);
+ int extra_header_count,
+ int stream_id,
+ int associated_stream_id,
+ const char* url,
+ const char* status,
+ const char* location);
SpdyFrame* ConstructSpdyPush(int stream_id,
- int associated_stream_id,
- const char* url);
+ int associated_stream_id,
+ const char* url);
SpdyFrame* ConstructSpdyPushHeaders(int stream_id,
- const char* const extra_headers[],
- int extra_header_count);
+ const char* const extra_headers[],
+ int extra_header_count);
// Constructs a standard SPDY SYN_REPLY packet to match the SPDY GET.
// |extra_headers| are the extra header-value pairs, which typically
// will vary the most between calls.
// Returns a SpdyFrame.
SpdyFrame* ConstructSpdyGetSynReply(const char* const extra_headers[],
- int extra_header_count,
- int stream_id);
+ int extra_header_count,
+ int stream_id);
// Constructs a standard SPDY SYN_REPLY packet to match the SPDY GET.
// |extra_headers| are the extra header-value pairs, which typically
@@ -272,6 +277,11 @@ SpdyFrame* ConstructSpdyGetSynReply(const char* const extra_headers[],
// Returns a SpdyFrame.
SpdyFrame* ConstructSpdyGetSynReplyRedirect(int stream_id);
+// Constructs a standard SPDY SYN_REPLY packet to match the WebSocket over SPDY
+// opening handshake.
+// Returns a SpdyFrame.
+SpdyFrame* ConstructSpdyWebSocketSynReply(int stream_id);
+
// Constructs a standard SPDY SYN_REPLY packet with an Internal Server
// Error status code.
// Returns a SpdyFrame.
@@ -279,45 +289,49 @@ SpdyFrame* ConstructSpdySynReplyError(int stream_id);
// Constructs a standard SPDY SYN_REPLY packet with the specified status code.
// Returns a SpdyFrame.
-SpdyFrame* ConstructSpdySynReplyError(
- const char* const status,
- const char* const* const extra_headers,
- int extra_header_count,
- int stream_id);
+SpdyFrame* ConstructSpdySynReplyError(const char* const status,
+ const char* const* const extra_headers,
+ int extra_header_count,
+ int stream_id);
// Constructs a standard SPDY POST SYN packet.
// |extra_headers| are the extra header-value pairs, which typically
// will vary the most between calls.
// Returns a SpdyFrame.
SpdyFrame* ConstructSpdyPost(int64 content_length,
- const char* const extra_headers[],
- int extra_header_count);
+ const char* const extra_headers[],
+ int extra_header_count);
// Constructs a chunked transfer SPDY POST SYN packet.
// |extra_headers| are the extra header-value pairs, which typically
// will vary the most between calls.
// Returns a SpdyFrame.
SpdyFrame* ConstructChunkedSpdyPost(const char* const extra_headers[],
- int extra_header_count);
+ int extra_header_count);
// Constructs a standard SPDY SYN_REPLY packet to match the SPDY POST.
// |extra_headers| are the extra header-value pairs, which typically
// will vary the most between calls.
// Returns a SpdyFrame.
SpdyFrame* ConstructSpdyPostSynReply(const char* const extra_headers[],
- int extra_header_count);
+ int extra_header_count);
// Constructs a single SPDY data frame with the contents "hello!"
SpdyFrame* ConstructSpdyBodyFrame(int stream_id,
- bool fin);
+ bool fin);
// Constructs a single SPDY data frame with the given content.
SpdyFrame* ConstructSpdyBodyFrame(int stream_id, const char* data,
- uint32 len, bool fin);
+ uint32 len, bool fin);
+
+// Constructs a SPDY HEADERS frame for a WebSocket frame over SPDY.
+SpdyFrame* ConstructSpdyWebSocketHeadersFrame(int stream_id,
+ const char* length,
+ bool fin);
// Wraps |frame| in the payload of a data frame in stream |stream_id|.
-SpdyFrame* ConstructWrappedSpdyFrame(
- const scoped_ptr<SpdyFrame>& frame, int stream_id);
+SpdyFrame* ConstructWrappedSpdyFrame(const scoped_ptr<SpdyFrame>& frame,
+ int stream_id);
// Create an async MockWrite from the given SpdyFrame.
MockWrite CreateMockWrite(const SpdyFrame& req);
diff --git a/net/spdy/spdy_test_util_spdy3.cc b/net/spdy/spdy_test_util_spdy3.cc
index cffd9eb..28f8bbf 100644
--- a/net/spdy/spdy_test_util_spdy3.cc
+++ b/net/spdy/spdy_test_util_spdy3.cc
@@ -504,6 +504,35 @@ SpdyFrame* ConstructSpdyConnect(const char* const extra_headers[],
arraysize(kConnectHeaders));
}
+// Constructs a standard SPDY SYN_STREAM frame for a WebSocket over SPDY
+// opening handshake.
+SpdyFrame* ConstructSpdyWebSocket(int stream_id,
+ const char* path,
+ const char* host,
+ const char* origin) {
+ const char* const kWebSocketHeaders[] = {
+ ":path",
+ path,
+ ":host",
+ host,
+ ":version",
+ "WebSocket/13",
+ ":scheme",
+ "ws",
+ ":origin",
+ origin
+ };
+ return ConstructSpdyControlFrame(/*extra_headers*/ NULL,
+ /*extra_header_count*/ 0,
+ /*compressed*/ false,
+ stream_id,
+ LOWEST,
+ SYN_STREAM,
+ CONTROL_FLAG_NONE,
+ kWebSocketHeaders,
+ arraysize(kWebSocketHeaders));
+}
+
// Constructs a standard SPDY push SYN packet.
// |extra_headers| are the extra header-value pairs, which typically
// will vary the most between calls.
@@ -681,6 +710,25 @@ SpdyFrame* ConstructSpdyGetSynReply(const char* const extra_headers[],
arraysize(kStandardGetHeaders));
}
+// Constructs a standard SPDY SYN_REPLY packet to match the WebSocket over SPDY
+// opening handshake.
+// Returns a SpdyFrame.
+SpdyFrame* ConstructSpdyWebSocketSynReply(int stream_id) {
+ static const char* const kStandardWebSocketHeaders[] = {
+ ":status",
+ "101"
+ };
+ return ConstructSpdyControlFrame(NULL,
+ 0,
+ false,
+ stream_id,
+ LOWEST,
+ SYN_REPLY,
+ CONTROL_FLAG_NONE,
+ kStandardWebSocketHeaders,
+ arraysize(kStandardWebSocketHeaders));
+}
+
// Constructs a standard SPDY POST SYN packet.
// |content_length| is the size of post data.
// |extra_headers| are the extra header-value pairs, which typically
@@ -787,6 +835,29 @@ SpdyFrame* ConstructSpdyBodyFrame(int stream_id, const char* data,
stream_id, data, len, fin ? DATA_FLAG_FIN : DATA_FLAG_NONE);
}
+// Constructs a SPDY HEADERS frame for a WebSocket frame over SPDY.
+SpdyFrame* ConstructSpdyWebSocketHeadersFrame(int stream_id,
+ const char* length,
+ bool fin) {
+ static const char* const kHeaders[] = {
+ ":opcode",
+ "1", // text frame
+ ":length",
+ length,
+ ":fin",
+ fin ? "1" : "0"
+ };
+ return ConstructSpdyControlFrame(/*extra_headers*/ NULL,
+ /*extra_header_count*/ 0,
+ /*compression*/ false,
+ stream_id,
+ LOWEST,
+ HEADERS,
+ CONTROL_FLAG_NONE,
+ kHeaders,
+ arraysize(kHeaders));
+}
+
// Wraps |frame| in the payload of a data frame in stream |stream_id|.
SpdyFrame* ConstructWrappedSpdyFrame(
const scoped_ptr<SpdyFrame>& frame,
diff --git a/net/spdy/spdy_test_util_spdy3.h b/net/spdy/spdy_test_util_spdy3.h
index 6f0d388..0443ac6 100644
--- a/net/spdy/spdy_test_util_spdy3.h
+++ b/net/spdy/spdy_test_util_spdy3.h
@@ -123,31 +123,31 @@ int AppendToBuffer(int val,
// |buffer| is the buffer we're filling in.
// Returns a SpdyFrame.
SpdyFrame* ConstructSpdyPacket(const SpdyHeaderInfo& header_info,
- const char* const extra_headers[],
- int extra_header_count,
- const char* const tail[],
- int tail_header_count);
+ const char* const extra_headers[],
+ int extra_header_count,
+ const char* const tail[],
+ int tail_header_count);
// Construct a generic SpdyControlFrame.
SpdyFrame* ConstructSpdyControlFrame(const char* const extra_headers[],
- int extra_header_count,
- bool compressed,
- int stream_id,
- RequestPriority request_priority,
- SpdyControlType type,
- SpdyControlFlags flags,
- const char* const* kHeaders,
- int kHeadersSize);
+ int extra_header_count,
+ bool compressed,
+ int stream_id,
+ RequestPriority request_priority,
+ SpdyControlType type,
+ SpdyControlFlags flags,
+ const char* const* kHeaders,
+ int kHeadersSize);
SpdyFrame* ConstructSpdyControlFrame(const char* const extra_headers[],
- int extra_header_count,
- bool compressed,
- int stream_id,
- RequestPriority request_priority,
- SpdyControlType type,
- SpdyControlFlags flags,
- const char* const* kHeaders,
- int kHeadersSize,
- int associated_stream_id);
+ int extra_header_count,
+ bool compressed,
+ int stream_id,
+ RequestPriority request_priority,
+ SpdyControlType type,
+ SpdyControlFlags flags,
+ const char* const* kHeaders,
+ int kHeadersSize,
+ int associated_stream_id);
// Construct an expected SPDY reply string.
// |extra_headers| are the extra header-value pairs, which typically
@@ -167,8 +167,7 @@ SpdyFrame* ConstructSpdySettings(const SettingsMap& settings);
// Construct an expected SPDY CREDENTIAL frame.
// |credential| is the credential to send.
// Returns the constructed frame. The caller takes ownership of the frame.
-SpdyFrame* ConstructSpdyCredential(
- const SpdyCredential& credential);
+SpdyFrame* ConstructSpdyCredential(const SpdyCredential& credential);
// Construct a SPDY PING frame.
// Returns the constructed frame. The caller takes ownership of the frame.
@@ -180,13 +179,12 @@ SpdyFrame* ConstructSpdyGoAway();
// Construct a SPDY WINDOW_UPDATE frame.
// Returns the constructed frame. The caller takes ownership of the frame.
-SpdyFrame* ConstructSpdyWindowUpdate(SpdyStreamId,
- uint32 delta_window_size);
+SpdyFrame* ConstructSpdyWindowUpdate(SpdyStreamId, uint32 delta_window_size);
// Construct a SPDY RST_STREAM frame.
// Returns the constructed frame. The caller takes ownership of the frame.
SpdyFrame* ConstructSpdyRstStream(SpdyStreamId stream_id,
- SpdyStatusCodes status);
+ SpdyStatusCodes status);
// Construct a single SPDY header entry, for validation.
// |extra_headers| are the extra header-value pairs.
@@ -205,19 +203,19 @@ int ConstructSpdyHeader(const char* const extra_headers[],
// will vary the most between calls.
// Returns a SpdyFrame.
SpdyFrame* ConstructSpdyGet(const char* const url,
- bool compressed,
- int stream_id,
- RequestPriority request_priority);
+ bool compressed,
+ int stream_id,
+ RequestPriority request_priority);
// Constructs a standard SPDY GET SYN packet, optionally compressed.
// |extra_headers| are the extra header-value pairs, which typically
// will vary the most between calls.
// Returns a SpdyFrame.
SpdyFrame* ConstructSpdyGet(const char* const extra_headers[],
- int extra_header_count,
- bool compressed,
- int stream_id,
- RequestPriority request_priority);
+ int extra_header_count,
+ bool compressed,
+ int stream_id,
+ RequestPriority request_priority);
// Constructs a standard SPDY GET SYN packet, optionally compressed.
// |extra_headers| are the extra header-value pairs, which typically
@@ -225,52 +223,59 @@ SpdyFrame* ConstructSpdyGet(const char* const extra_headers[],
// the full url will be used instead of simply the path.
// Returns a SpdyFrame.
SpdyFrame* ConstructSpdyGet(const char* const extra_headers[],
- int extra_header_count,
- bool compressed,
- int stream_id,
- RequestPriority request_priority,
- bool direct);
+ int extra_header_count,
+ bool compressed,
+ int stream_id,
+ RequestPriority request_priority,
+ bool direct);
// Constructs a standard SPDY SYN_STREAM frame for a CONNECT request.
SpdyFrame* ConstructSpdyConnect(const char* const extra_headers[],
- int extra_header_count,
- int stream_id);
+ int extra_header_count,
+ int stream_id);
+
+// Constructs a standard SPDY SYN_STREAM frame for WebSocket over SPDY
+// opening handshake.
+SpdyFrame* ConstructSpdyWebSocket(int stream_id,
+ const char* path,
+ const char* host,
+ const char* origin);
// Constructs a standard SPDY push SYN packet.
// |extra_headers| are the extra header-value pairs, which typically
// will vary the most between calls.
// Returns a SpdyFrame.
SpdyFrame* ConstructSpdyPush(const char* const extra_headers[],
- int extra_header_count,
- int stream_id,
- int associated_stream_id);
+ int extra_header_count,
+ int stream_id,
+ int associated_stream_id);
SpdyFrame* ConstructSpdyPush(const char* const extra_headers[],
- int extra_header_count,
- int stream_id,
- int associated_stream_id,
- const char* url);
+ int extra_header_count,
+ int stream_id,
+ int associated_stream_id,
+ const char* url);
SpdyFrame* ConstructSpdyPush(const char* const extra_headers[],
- int extra_header_count,
- int stream_id,
- int associated_stream_id,
- const char* url,
- const char* status,
- const char* location);
+ int extra_header_count,
+ int stream_id,
+ int associated_stream_id,
+ const char* url,
+ const char* status,
+ const char* location);
SpdyFrame* ConstructSpdyPush(int stream_id,
- int associated_stream_id,
- const char* url);
+ int associated_stream_id,
+ const char* url);
SpdyFrame* ConstructSpdyPushHeaders(int stream_id,
- const char* const extra_headers[],
- int extra_header_count);
+ const char* const extra_headers[],
+ int extra_header_count);
// Constructs a standard SPDY SYN_REPLY packet to match the SPDY GET.
// |extra_headers| are the extra header-value pairs, which typically
// will vary the most between calls.
// Returns a SpdyFrame.
SpdyFrame* ConstructSpdyGetSynReply(const char* const extra_headers[],
- int extra_header_count,
- int stream_id);
+ int extra_header_count,
+ int stream_id);
// Constructs a standard SPDY SYN_REPLY packet to match the SPDY GET.
// |extra_headers| are the extra header-value pairs, which typically
@@ -278,6 +283,11 @@ SpdyFrame* ConstructSpdyGetSynReply(const char* const extra_headers[],
// Returns a SpdyFrame.
SpdyFrame* ConstructSpdyGetSynReplyRedirect(int stream_id);
+// Constructs a standard SPDY SYN_REPLY packet to match the WebSocket over SPDY
+// opening handshake.
+// Returns a SpdyFrame.
+SpdyFrame* ConstructSpdyWebSocketSynReply(int stream_id);
+
// Constructs a standard SPDY SYN_REPLY packet with an Internal Server
// Error status code.
// Returns a SpdyFrame.
@@ -285,45 +295,49 @@ SpdyFrame* ConstructSpdySynReplyError(int stream_id);
// Constructs a standard SPDY SYN_REPLY packet with the specified status code.
// Returns a SpdyFrame.
-SpdyFrame* ConstructSpdySynReplyError(
- const char* const status,
- const char* const* const extra_headers,
- int extra_header_count,
- int stream_id);
+SpdyFrame* ConstructSpdySynReplyError(const char* const status,
+ const char* const* const extra_headers,
+ int extra_header_count,
+ int stream_id);
// Constructs a standard SPDY POST SYN packet.
// |extra_headers| are the extra header-value pairs, which typically
// will vary the most between calls.
// Returns a SpdyFrame.
SpdyFrame* ConstructSpdyPost(int64 content_length,
- const char* const extra_headers[],
- int extra_header_count);
+ const char* const extra_headers[],
+ int extra_header_count);
// Constructs a chunked transfer SPDY POST SYN packet.
// |extra_headers| are the extra header-value pairs, which typically
// will vary the most between calls.
// Returns a SpdyFrame.
SpdyFrame* ConstructChunkedSpdyPost(const char* const extra_headers[],
- int extra_header_count);
+ int extra_header_count);
// Constructs a standard SPDY SYN_REPLY packet to match the SPDY POST.
// |extra_headers| are the extra header-value pairs, which typically
// will vary the most between calls.
// Returns a SpdyFrame.
SpdyFrame* ConstructSpdyPostSynReply(const char* const extra_headers[],
- int extra_header_count);
+ int extra_header_count);
// Constructs a single SPDY data frame with the contents "hello!"
SpdyFrame* ConstructSpdyBodyFrame(int stream_id,
- bool fin);
+ bool fin);
// Constructs a single SPDY data frame with the given content.
SpdyFrame* ConstructSpdyBodyFrame(int stream_id, const char* data,
- uint32 len, bool fin);
+ uint32 len, bool fin);
+
+// Constructs a SPDY HEADERS frame for a WebSocket frame over SPDY.
+SpdyFrame* ConstructSpdyWebSocketHeadersFrame(int stream_id,
+ const char* length,
+ bool fin);
// Wraps |frame| in the payload of a data frame in stream |stream_id|.
-SpdyFrame* ConstructWrappedSpdyFrame(
- const scoped_ptr<SpdyFrame>& frame, int stream_id);
+SpdyFrame* ConstructWrappedSpdyFrame(const scoped_ptr<SpdyFrame>& frame,
+ int stream_id);
// Create an async MockWrite from the given SpdyFrame.
MockWrite CreateMockWrite(const SpdyFrame& req);