blob: c27ad2ebc1c028e74b6adc69120b9439d789c0a6 [file] [log] [blame]
[email protected]3d587372013-06-01 04:31:451// Copyright 2013 The Chromium Authors. All rights reserved.
[email protected]4f386422010-07-20 04:19:492// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
[email protected]3d587372013-06-01 04:31:455#include <cstddef>
6#include <string>
7#include <vector>
8
[email protected]3b63f8f42011-03-28 01:54:159#include "base/memory/ref_counted.h"
[email protected]34a4dea2013-03-13 00:42:3010#include "base/memory/scoped_ptr.h"
[email protected]3d587372013-06-01 04:31:4511#include "base/stl_util.h"
[email protected]d069c11a2013-04-13 00:01:5512#include "base/strings/string_piece.h"
[email protected]5a76b812011-12-21 20:52:0013#include "net/base/completion_callback.h"
[email protected]d245c342012-02-23 20:49:1514#include "net/base/net_log_unittest.h"
[email protected]1bbabc82013-03-25 21:11:0215#include "net/base/request_priority.h"
[email protected]bb88e1d32013-05-03 23:11:0716#include "net/socket/next_proto.h"
[email protected]6fe2e992013-06-12 03:38:4317#include "net/socket/socket_test_util.h"
[email protected]f54c85792012-03-08 19:06:4118#include "net/spdy/buffered_spdy_framer.h"
[email protected]9e1bdd32011-02-03 21:48:3419#include "net/spdy/spdy_http_utils.h"
[email protected]34a4dea2013-03-13 00:42:3020#include "net/spdy/spdy_protocol.h"
[email protected]4f386422010-07-20 04:19:4921#include "net/spdy/spdy_session.h"
[email protected]d069c11a2013-04-13 00:01:5522#include "net/spdy/spdy_stream.h"
[email protected]39d13d942012-07-19 16:48:2023#include "net/spdy/spdy_stream_test_util.h"
[email protected]e3861ca2013-03-02 01:00:4524#include "net/spdy/spdy_test_util_common.h"
[email protected]4f386422010-07-20 04:19:4925#include "testing/gtest/include/gtest/gtest.h"
26
[email protected]4f386422010-07-20 04:19:4927// TODO(ukai): factor out common part with spdy_http_stream_unittest.cc
[email protected]b9ec6882011-07-01 07:40:2628//
29namespace net {
[email protected]4f386422010-07-20 04:19:4930
[email protected]34a4dea2013-03-13 00:42:3031namespace test {
32
[email protected]4f386422010-07-20 04:19:4933namespace {
34
[email protected]cbdd73162013-03-18 23:27:3335const char kStreamUrl[] = "http://www.google.com/";
36const char kPostBody[] = "\0hello!\xff";
37const size_t kPostBodyLength = arraysize(kPostBody);
[email protected]1c6b12a2013-03-21 00:59:1138const base::StringPiece kPostBodyStringPiece(kPostBody, kPostBodyLength);
[email protected]39d13d942012-07-19 16:48:2039
[email protected]3d587372013-06-01 04:31:4540class SpdyStreamTest : public ::testing::Test,
41 public ::testing::WithParamInterface<NextProto> {
[email protected]4f386422010-07-20 04:19:4942 protected:
[email protected]d2de7da2013-05-22 07:49:5643 // A function that takes a SpdyStream and the number of bytes which
44 // will unstall the next frame completely.
45 typedef base::Callback<void(const base::WeakPtr<SpdyStream>&, int32)>
46 UnstallFunction;
47
[email protected]3d587372013-06-01 04:31:4548 SpdyStreamTest()
49 : spdy_util_(GetParam()),
[email protected]a4a67772013-05-08 22:56:0750 host_port_pair_("www.google.com", 80),
[email protected]3d587372013-06-01 04:31:4551 session_deps_(GetParam()),
52 offset_(0) {}
[email protected]4f386422010-07-20 04:19:4953
54 scoped_refptr<SpdySession> CreateSpdySession() {
[email protected]e6d017652013-05-17 18:01:4055 SpdySessionKey key(host_port_pair_, ProxyServer::Direct(),
56 kPrivacyModeDisabled);
[email protected]4f386422010-07-20 04:19:4957 scoped_refptr<SpdySession> session(
[email protected]e6d017652013-05-17 18:01:4058 session_->spdy_session_pool()->Get(key, BoundNetLog()));
[email protected]4f386422010-07-20 04:19:4959 return session;
60 }
61
[email protected]34a4dea2013-03-13 00:42:3062 void InitializeSpdySession(const scoped_refptr<SpdySession>& session,
63 const HostPortPair& host_port_pair) {
64 scoped_refptr<TransportSocketParams> transport_params(
65 new TransportSocketParams(host_port_pair, LOWEST, false, false,
66 OnHostResolutionCallback()));
67
68 scoped_ptr<ClientSocketHandle> connection(new ClientSocketHandle);
[email protected]3d587372013-06-01 04:31:4569 EXPECT_EQ(OK, connection->Init(host_port_pair_.ToString(), transport_params,
[email protected]34a4dea2013-03-13 00:42:3070 LOWEST, CompletionCallback(),
71 session_->GetTransportSocketPool(
72 HttpNetworkSession::NORMAL_SOCKET_POOL),
73 BoundNetLog()));
74 session->InitializeWithSocket(connection.release(), false, OK);
75 }
76
[email protected]4f386422010-07-20 04:19:4977 virtual void TearDown() {
[email protected]2da659e2013-05-23 20:51:3478 base::MessageLoop::current()->RunUntilIdle();
[email protected]4f386422010-07-20 04:19:4979 }
80
[email protected]d2de7da2013-05-22 07:49:5681 void RunResumeAfterUnstallRequestResponseTest(
82 const UnstallFunction& unstall_function);
83
84 void RunResumeAfterUnstallBidirectionalTest(
85 const UnstallFunction& unstall_function);
86
[email protected]3d587372013-06-01 04:31:4587 // Add{Read,Write}() populates lists that are eventually passed to a
88 // SocketData class. |frame| must live for the whole test.
89
90 void AddRead(const SpdyFrame& frame) {
91 reads_.push_back(CreateMockRead(frame, offset_++));
92 }
93
94 void AddWrite(const SpdyFrame& frame) {
95 writes_.push_back(CreateMockWrite(frame, offset_++));
96 }
97
98 void AddReadEOF() {
99 reads_.push_back(MockRead(ASYNC, 0, offset_++));
100 }
101
102 MockRead* GetReads() {
103 return vector_as_array(&reads_);
104 }
105
106 size_t GetNumReads() const {
107 return reads_.size();
108 }
109
110 MockWrite* GetWrites() {
111 return vector_as_array(&writes_);
112 }
113
114 int GetNumWrites() const {
115 return writes_.size();
116 }
117
[email protected]a4a67772013-05-08 22:56:07118 SpdyTestUtil spdy_util_;
[email protected]34a4dea2013-03-13 00:42:30119 HostPortPair host_port_pair_;
120 SpdySessionDependencies session_deps_;
[email protected]4f386422010-07-20 04:19:49121 scoped_refptr<HttpNetworkSession> session_;
[email protected]3d587372013-06-01 04:31:45122
123 private:
124 // Used by Add{Read,Write}() above.
125 std::vector<MockWrite> writes_;
126 std::vector<MockRead> reads_;
127 int offset_;
[email protected]4f386422010-07-20 04:19:49128};
129
[email protected]3d587372013-06-01 04:31:45130INSTANTIATE_TEST_CASE_P(
131 NextProto,
132 SpdyStreamTest,
[email protected]162deb82013-06-11 21:23:34133 testing::Values(kProtoSPDY2, kProtoSPDY3, kProtoSPDY31, kProtoSPDY4a2));
[email protected]3d587372013-06-01 04:31:45134
135TEST_P(SpdyStreamTest, SendDataAfterOpen) {
[email protected]cbdd73162013-03-18 23:27:33136 GURL url(kStreamUrl);
[email protected]3d587372013-06-01 04:31:45137
[email protected]34a4dea2013-03-13 00:42:30138 session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_);
[email protected]4f386422010-07-20 04:19:49139
[email protected]3d587372013-06-01 04:31:45140 scoped_ptr<SpdyFrame> initial_window_update(
141 spdy_util_.ConstructSpdyWindowUpdate(
142 kSessionFlowControlStreamId,
143 kDefaultInitialRecvWindowSize - kSpdySessionInitialWindowSize));
144 if (spdy_util_.protocol() >= kProtoSPDY31)
145 AddWrite(*initial_window_update);
146
[email protected]cbdd73162013-03-18 23:27:33147 scoped_ptr<SpdyFrame> req(
[email protected]3d587372013-06-01 04:31:45148 spdy_util_.ConstructSpdyPost(
149 kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0));
150 AddWrite(*req);
151
152 scoped_ptr<SpdyFrame> resp(
153 spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
154 AddRead(*resp);
155
[email protected]cbdd73162013-03-18 23:27:33156 scoped_ptr<SpdyFrame> msg(
[email protected]3d587372013-06-01 04:31:45157 spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false));
158 AddWrite(*msg);
[email protected]4f386422010-07-20 04:19:49159
[email protected]cbdd73162013-03-18 23:27:33160 scoped_ptr<SpdyFrame> echo(
[email protected]3d587372013-06-01 04:31:45161 spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false));
162 AddRead(*echo);
[email protected]4f386422010-07-20 04:19:49163
[email protected]3d587372013-06-01 04:31:45164 AddReadEOF();
165
166 OrderedSocketData data(GetReads(), GetNumReads(),
167 GetWrites(), GetNumWrites());
[email protected]d973e99a2012-02-17 21:02:36168 MockConnect connect_data(SYNCHRONOUS, OK);
[email protected]dd54bd82012-07-19 23:44:57169 data.set_connect_data(connect_data);
[email protected]4f386422010-07-20 04:19:49170
[email protected]34a4dea2013-03-13 00:42:30171 session_deps_.socket_factory->AddSocketDataProvider(&data);
[email protected]4f386422010-07-20 04:19:49172
173 scoped_refptr<SpdySession> session(CreateSpdySession());
[email protected]4f386422010-07-20 04:19:49174
[email protected]34a4dea2013-03-13 00:42:30175 InitializeSpdySession(session, host_port_pair_);
[email protected]e3861ca2013-03-02 01:00:45176
[email protected]d26ff352013-05-13 08:48:28177 base::WeakPtr<SpdyStream> stream =
[email protected]fb73cd672013-05-27 12:53:08178 CreateStreamSynchronously(
179 SPDY_BIDIRECTIONAL_STREAM, session, url, LOWEST, BoundNetLog());
[email protected]e3861ca2013-03-02 01:00:45180 ASSERT_TRUE(stream.get() != NULL);
[email protected]4f386422010-07-20 04:19:49181
[email protected]194cfcf2013-05-23 21:44:44182 StreamDelegateSendImmediate delegate(stream, kPostBodyStringPiece);
[email protected]34a4dea2013-03-13 00:42:30183 stream->SetDelegate(&delegate);
[email protected]4f386422010-07-20 04:19:49184
[email protected]a7a265ef2010-12-08 18:05:57185 EXPECT_FALSE(stream->HasUrl());
186
[email protected]ee7c40d12013-05-24 21:13:10187 scoped_ptr<SpdyHeaderBlock> headers(
[email protected]a4a67772013-05-08 22:56:07188 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
[email protected]528b3452013-05-25 01:28:54189 EXPECT_EQ(ERR_IO_PENDING,
190 stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
[email protected]a7a265ef2010-12-08 18:05:57191 EXPECT_TRUE(stream->HasUrl());
192 EXPECT_EQ(kStreamUrl, stream->GetUrl().spec());
[email protected]4f386422010-07-20 04:19:49193
[email protected]34a4dea2013-03-13 00:42:30194 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
[email protected]4f386422010-07-20 04:19:49195
[email protected]34a4dea2013-03-13 00:42:30196 EXPECT_TRUE(delegate.send_headers_completed());
[email protected]3d587372013-06-01 04:31:45197 EXPECT_EQ("200", delegate.GetResponseHeaderValue(spdy_util_.GetStatusKey()));
198 EXPECT_EQ("HTTP/1.1",
199 delegate.GetResponseHeaderValue(spdy_util_.GetVersionKey()));
[email protected]09a8d9172013-04-17 19:23:49200 EXPECT_EQ(std::string(kPostBody, kPostBodyLength),
201 delegate.TakeReceivedData());
[email protected]aa19cfc2013-05-23 16:41:38202 EXPECT_TRUE(data.at_write_eof());
[email protected]4f386422010-07-20 04:19:49203}
204
[email protected]3d587372013-06-01 04:31:45205TEST_P(SpdyStreamTest, PushedStream) {
[email protected]34a4dea2013-03-13 00:42:30206 session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_);
[email protected]a7a265ef2010-12-08 18:05:57207 scoped_refptr<SpdySession> spdy_session(CreateSpdySession());
[email protected]0e861e92012-03-15 18:42:19208
[email protected]6d116e1a2013-06-24 07:42:15209 scoped_ptr<SpdyFrame> initial_window_update(
210 spdy_util_.ConstructSpdyWindowUpdate(
211 kSessionFlowControlStreamId,
212 kDefaultInitialRecvWindowSize - kSpdySessionInitialWindowSize));
213 if (spdy_util_.protocol() >= kProtoSPDY31)
214 AddWrite(*initial_window_update);
[email protected]0e861e92012-03-15 18:42:19215
[email protected]6d116e1a2013-06-24 07:42:15216 AddReadEOF();
217
218 OrderedSocketData data(GetReads(), GetNumReads(),
219 GetWrites(), GetNumWrites());
[email protected]0e861e92012-03-15 18:42:19220 MockConnect connect_data(SYNCHRONOUS, OK);
[email protected]dd54bd82012-07-19 23:44:57221 data.set_connect_data(connect_data);
[email protected]0e861e92012-03-15 18:42:19222
[email protected]34a4dea2013-03-13 00:42:30223 session_deps_.socket_factory->AddSocketDataProvider(&data);
[email protected]0e861e92012-03-15 18:42:19224
[email protected]34a4dea2013-03-13 00:42:30225 InitializeSpdySession(spdy_session, host_port_pair_);
[email protected]a7a265ef2010-12-08 18:05:57226 BoundNetLog net_log;
227
228 // Conjure up a stream.
[email protected]fb73cd672013-05-27 12:53:08229 SpdyStream stream(SPDY_PUSH_STREAM,
[email protected]90499482013-06-01 00:39:50230 spdy_session.get(),
[email protected]1c12c062013-05-14 23:13:48231 std::string(),
232 DEFAULT_PRIORITY,
233 kSpdyStreamInitialWindowSize,
234 kSpdyStreamInitialWindowSize,
[email protected]1c12c062013-05-14 23:13:48235 net_log);
236 stream.set_stream_id(2);
[email protected]1c12c062013-05-14 23:13:48237 EXPECT_FALSE(stream.HasUrl());
[email protected]a7a265ef2010-12-08 18:05:57238
239 // Set a couple of headers.
[email protected]ff98d7f02012-03-22 21:44:19240 SpdyHeaderBlock response;
[email protected]3d587372013-06-01 04:31:45241 spdy_util_.AddUrlToHeaderBlock(kStreamUrl, &response);
[email protected]6d116e1a2013-06-24 07:42:15242 stream.OnInitialResponseHeadersReceived(
243 response, base::Time::Now(), base::TimeTicks::Now());
[email protected]a7a265ef2010-12-08 18:05:57244
245 // Send some basic headers.
[email protected]ff98d7f02012-03-22 21:44:19246 SpdyHeaderBlock headers;
[email protected]6d116e1a2013-06-24 07:42:15247 headers[spdy_util_.GetStatusKey()] = "200";
248 headers[spdy_util_.GetVersionKey()] = "OK";
249 stream.OnAdditionalResponseHeadersReceived(headers);
[email protected]a7a265ef2010-12-08 18:05:57250
[email protected]1c12c062013-05-14 23:13:48251 EXPECT_TRUE(stream.HasUrl());
252 EXPECT_EQ(kStreamUrl, stream.GetUrl().spec());
[email protected]3d587372013-06-01 04:31:45253
[email protected]6d116e1a2013-06-24 07:42:15254 StreamDelegateDoNothing delegate(stream.GetWeakPtr());
255 stream.SetDelegate(&delegate);
256
257 base::MessageLoop::current()->RunUntilIdle();
258
259 EXPECT_EQ("200", delegate.GetResponseHeaderValue(spdy_util_.GetStatusKey()));
260
[email protected]3d587372013-06-01 04:31:45261 spdy_session->CloseSessionOnError(
262 ERR_CONNECTION_CLOSED, true, "Closing session");
[email protected]a7a265ef2010-12-08 18:05:57263}
264
[email protected]3d587372013-06-01 04:31:45265TEST_P(SpdyStreamTest, StreamError) {
[email protected]cbdd73162013-03-18 23:27:33266 GURL url(kStreamUrl);
267
[email protected]34a4dea2013-03-13 00:42:30268 session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_);
[email protected]d245c342012-02-23 20:49:15269
[email protected]3d587372013-06-01 04:31:45270 scoped_ptr<SpdyFrame> initial_window_update(
271 spdy_util_.ConstructSpdyWindowUpdate(
272 kSessionFlowControlStreamId,
273 kDefaultInitialRecvWindowSize - kSpdySessionInitialWindowSize));
274 if (spdy_util_.protocol() >= kProtoSPDY31)
275 AddWrite(*initial_window_update);
[email protected]d245c342012-02-23 20:49:15276
[email protected]3d587372013-06-01 04:31:45277 scoped_ptr<SpdyFrame> req(
278 spdy_util_.ConstructSpdyPost(
279 kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0));
280 AddWrite(*req);
281
282 scoped_ptr<SpdyFrame> resp(
283 spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
284 AddRead(*resp);
285
286 scoped_ptr<SpdyFrame> msg(
287 spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false));
288 AddWrite(*msg);
289
[email protected]cbdd73162013-03-18 23:27:33290 scoped_ptr<SpdyFrame> echo(
[email protected]3d587372013-06-01 04:31:45291 spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false));
292 AddRead(*echo);
293
294 AddReadEOF();
[email protected]d245c342012-02-23 20:49:15295
[email protected]333bdf62012-06-08 22:57:29296 CapturingBoundNetLog log;
[email protected]d245c342012-02-23 20:49:15297
[email protected]3d587372013-06-01 04:31:45298 OrderedSocketData data(GetReads(), GetNumReads(),
299 GetWrites(), GetNumWrites());
[email protected]d245c342012-02-23 20:49:15300 MockConnect connect_data(SYNCHRONOUS, OK);
[email protected]dd54bd82012-07-19 23:44:57301 data.set_connect_data(connect_data);
[email protected]d245c342012-02-23 20:49:15302
[email protected]34a4dea2013-03-13 00:42:30303 session_deps_.socket_factory->AddSocketDataProvider(&data);
[email protected]d245c342012-02-23 20:49:15304
305 scoped_refptr<SpdySession> session(CreateSpdySession());
[email protected]d245c342012-02-23 20:49:15306
[email protected]34a4dea2013-03-13 00:42:30307 InitializeSpdySession(session, host_port_pair_);
[email protected]d245c342012-02-23 20:49:15308
[email protected]d26ff352013-05-13 08:48:28309 base::WeakPtr<SpdyStream> stream =
[email protected]fb73cd672013-05-27 12:53:08310 CreateStreamSynchronously(
311 SPDY_BIDIRECTIONAL_STREAM, session, url, LOWEST, log.bound());
[email protected]e3861ca2013-03-02 01:00:45312 ASSERT_TRUE(stream.get() != NULL);
[email protected]d245c342012-02-23 20:49:15313
[email protected]194cfcf2013-05-23 21:44:44314 StreamDelegateSendImmediate delegate(stream, kPostBodyStringPiece);
[email protected]34a4dea2013-03-13 00:42:30315 stream->SetDelegate(&delegate);
[email protected]d245c342012-02-23 20:49:15316
317 EXPECT_FALSE(stream->HasUrl());
318
[email protected]ee7c40d12013-05-24 21:13:10319 scoped_ptr<SpdyHeaderBlock> headers(
[email protected]a4a67772013-05-08 22:56:07320 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
[email protected]528b3452013-05-25 01:28:54321 EXPECT_EQ(ERR_IO_PENDING,
322 stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
[email protected]d245c342012-02-23 20:49:15323 EXPECT_TRUE(stream->HasUrl());
324 EXPECT_EQ(kStreamUrl, stream->GetUrl().spec());
325
[email protected]34a4dea2013-03-13 00:42:30326 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
[email protected]218f4b62012-07-20 20:12:41327
[email protected]d26ff352013-05-13 08:48:28328 const SpdyStreamId stream_id = delegate.stream_id();
[email protected]c92f4b4542012-07-26 23:53:21329
[email protected]34a4dea2013-03-13 00:42:30330 EXPECT_TRUE(delegate.send_headers_completed());
[email protected]3d587372013-06-01 04:31:45331 EXPECT_EQ("200", delegate.GetResponseHeaderValue(spdy_util_.GetStatusKey()));
332 EXPECT_EQ("HTTP/1.1",
333 delegate.GetResponseHeaderValue(spdy_util_.GetVersionKey()));
[email protected]09a8d9172013-04-17 19:23:49334 EXPECT_EQ(std::string(kPostBody, kPostBodyLength),
335 delegate.TakeReceivedData());
[email protected]aa19cfc2013-05-23 16:41:38336 EXPECT_TRUE(data.at_write_eof());
[email protected]d245c342012-02-23 20:49:15337
338 // Check that the NetLog was filled reasonably.
[email protected]f3da152d2012-06-02 01:00:57339 net::CapturingNetLog::CapturedEntryList entries;
[email protected]d245c342012-02-23 20:49:15340 log.GetEntries(&entries);
341 EXPECT_LT(0u, entries.size());
342
343 // Check that we logged SPDY_STREAM_ERROR correctly.
344 int pos = net::ExpectLogContainsSomewhere(
345 entries, 0,
346 net::NetLog::TYPE_SPDY_STREAM_ERROR,
347 net::NetLog::PHASE_NONE);
348
[email protected]f3da152d2012-06-02 01:00:57349 int stream_id2;
350 ASSERT_TRUE(entries[pos].GetIntegerValue("stream_id", &stream_id2));
351 EXPECT_EQ(static_cast<int>(stream_id), stream_id2);
[email protected]d245c342012-02-23 20:49:15352}
[email protected]a7a265ef2010-12-08 18:05:57353
[email protected]aa19cfc2013-05-23 16:41:38354// Make sure that large blocks of data are properly split up into
355// frame-sized chunks for a request/response (i.e., an HTTP-like)
356// stream.
[email protected]3d587372013-06-01 04:31:45357TEST_P(SpdyStreamTest, SendLargeDataAfterOpenRequestResponse) {
[email protected]aa19cfc2013-05-23 16:41:38358 GURL url(kStreamUrl);
359
360 session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_);
361
[email protected]3d587372013-06-01 04:31:45362 scoped_ptr<SpdyFrame> initial_window_update(
363 spdy_util_.ConstructSpdyWindowUpdate(
364 kSessionFlowControlStreamId,
365 kDefaultInitialRecvWindowSize - kSpdySessionInitialWindowSize));
366 if (spdy_util_.protocol() >= kProtoSPDY31)
367 AddWrite(*initial_window_update);
368
[email protected]aa19cfc2013-05-23 16:41:38369 scoped_ptr<SpdyFrame> req(
[email protected]3d587372013-06-01 04:31:45370 spdy_util_.ConstructSpdyPost(
371 kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0));
372 AddWrite(*req);
373
[email protected]aa19cfc2013-05-23 16:41:38374 std::string chunk_data(kMaxSpdyFrameChunkSize, 'x');
375 scoped_ptr<SpdyFrame> chunk(
[email protected]3d587372013-06-01 04:31:45376 spdy_util_.ConstructSpdyBodyFrame(
[email protected]aa19cfc2013-05-23 16:41:38377 1, chunk_data.data(), chunk_data.length(), false));
[email protected]3d587372013-06-01 04:31:45378 AddWrite(*chunk);
379 AddWrite(*chunk);
380
[email protected]528b3452013-05-25 01:28:54381 scoped_ptr<SpdyFrame> last_chunk(
[email protected]3d587372013-06-01 04:31:45382 spdy_util_.ConstructSpdyBodyFrame(
[email protected]528b3452013-05-25 01:28:54383 1, chunk_data.data(), chunk_data.length(), true));
[email protected]3d587372013-06-01 04:31:45384 AddWrite(*last_chunk);
[email protected]aa19cfc2013-05-23 16:41:38385
[email protected]3d587372013-06-01 04:31:45386 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
387 AddRead(*resp);
[email protected]aa19cfc2013-05-23 16:41:38388
[email protected]3d587372013-06-01 04:31:45389 AddReadEOF();
390
391 OrderedSocketData data(GetReads(), GetNumReads(),
392 GetWrites(), GetNumWrites());
[email protected]aa19cfc2013-05-23 16:41:38393 MockConnect connect_data(SYNCHRONOUS, OK);
394 data.set_connect_data(connect_data);
395
396 session_deps_.socket_factory->AddSocketDataProvider(&data);
397
398 scoped_refptr<SpdySession> session(CreateSpdySession());
399
400 InitializeSpdySession(session, host_port_pair_);
401
402 base::WeakPtr<SpdyStream> stream =
[email protected]fb73cd672013-05-27 12:53:08403 CreateStreamSynchronously(
404 SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog());
[email protected]aa19cfc2013-05-23 16:41:38405 ASSERT_TRUE(stream.get() != NULL);
406
407 std::string body_data(3 * kMaxSpdyFrameChunkSize, 'x');
408 StreamDelegateWithBody delegate(stream, body_data);
409 stream->SetDelegate(&delegate);
410
411 EXPECT_FALSE(stream->HasUrl());
412
[email protected]ee7c40d12013-05-24 21:13:10413 scoped_ptr<SpdyHeaderBlock> headers(
[email protected]aa19cfc2013-05-23 16:41:38414 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
[email protected]528b3452013-05-25 01:28:54415 EXPECT_EQ(ERR_IO_PENDING,
416 stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
[email protected]aa19cfc2013-05-23 16:41:38417 EXPECT_TRUE(stream->HasUrl());
418 EXPECT_EQ(kStreamUrl, stream->GetUrl().spec());
419
[email protected]aa19cfc2013-05-23 16:41:38420 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
421
422 EXPECT_TRUE(delegate.send_headers_completed());
[email protected]3d587372013-06-01 04:31:45423 EXPECT_EQ("200", delegate.GetResponseHeaderValue(spdy_util_.GetStatusKey()));
424 EXPECT_EQ("HTTP/1.1",
425 delegate.GetResponseHeaderValue(spdy_util_.GetVersionKey()));
[email protected]aa19cfc2013-05-23 16:41:38426 EXPECT_EQ(std::string(), delegate.TakeReceivedData());
427 EXPECT_TRUE(data.at_write_eof());
428}
429
430// Make sure that large blocks of data are properly split up into
431// frame-sized chunks for a bidirectional (i.e., non-HTTP-like)
432// stream.
[email protected]3d587372013-06-01 04:31:45433TEST_P(SpdyStreamTest, SendLargeDataAfterOpenBidirectional) {
[email protected]aa19cfc2013-05-23 16:41:38434 GURL url(kStreamUrl);
435
436 session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_);
437
[email protected]3d587372013-06-01 04:31:45438 scoped_ptr<SpdyFrame> initial_window_update(
439 spdy_util_.ConstructSpdyWindowUpdate(
440 kSessionFlowControlStreamId,
441 kDefaultInitialRecvWindowSize - kSpdySessionInitialWindowSize));
442 if (spdy_util_.protocol() >= kProtoSPDY31)
443 AddWrite(*initial_window_update);
444
[email protected]aa19cfc2013-05-23 16:41:38445 scoped_ptr<SpdyFrame> req(
[email protected]3d587372013-06-01 04:31:45446 spdy_util_.ConstructSpdyPost(
447 kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0));
448 AddWrite(*req);
449
450 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
451 AddRead(*resp);
452
[email protected]aa19cfc2013-05-23 16:41:38453 std::string chunk_data(kMaxSpdyFrameChunkSize, 'x');
454 scoped_ptr<SpdyFrame> chunk(
[email protected]3d587372013-06-01 04:31:45455 spdy_util_.ConstructSpdyBodyFrame(
[email protected]aa19cfc2013-05-23 16:41:38456 1, chunk_data.data(), chunk_data.length(), false));
[email protected]3d587372013-06-01 04:31:45457 AddWrite(*chunk);
458 AddWrite(*chunk);
459 AddWrite(*chunk);
[email protected]aa19cfc2013-05-23 16:41:38460
[email protected]3d587372013-06-01 04:31:45461 AddReadEOF();
[email protected]aa19cfc2013-05-23 16:41:38462
[email protected]3d587372013-06-01 04:31:45463 OrderedSocketData data(GetReads(), GetNumReads(),
464 GetWrites(), GetNumWrites());
[email protected]aa19cfc2013-05-23 16:41:38465 MockConnect connect_data(SYNCHRONOUS, OK);
466 data.set_connect_data(connect_data);
467
468 session_deps_.socket_factory->AddSocketDataProvider(&data);
469
470 scoped_refptr<SpdySession> session(CreateSpdySession());
471
472 InitializeSpdySession(session, host_port_pair_);
473
474 base::WeakPtr<SpdyStream> stream =
[email protected]fb73cd672013-05-27 12:53:08475 CreateStreamSynchronously(
476 SPDY_BIDIRECTIONAL_STREAM, session, url, LOWEST, BoundNetLog());
[email protected]aa19cfc2013-05-23 16:41:38477 ASSERT_TRUE(stream.get() != NULL);
478
479 std::string body_data(3 * kMaxSpdyFrameChunkSize, 'x');
[email protected]194cfcf2013-05-23 21:44:44480 StreamDelegateSendImmediate delegate(stream, body_data);
[email protected]aa19cfc2013-05-23 16:41:38481 stream->SetDelegate(&delegate);
482
483 EXPECT_FALSE(stream->HasUrl());
484
[email protected]ee7c40d12013-05-24 21:13:10485 scoped_ptr<SpdyHeaderBlock> headers(
[email protected]aa19cfc2013-05-23 16:41:38486 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
[email protected]528b3452013-05-25 01:28:54487 EXPECT_EQ(ERR_IO_PENDING,
488 stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
[email protected]aa19cfc2013-05-23 16:41:38489 EXPECT_TRUE(stream->HasUrl());
490 EXPECT_EQ(kStreamUrl, stream->GetUrl().spec());
491
[email protected]aa19cfc2013-05-23 16:41:38492 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
493
494 EXPECT_TRUE(delegate.send_headers_completed());
[email protected]3d587372013-06-01 04:31:45495 EXPECT_EQ("200", delegate.GetResponseHeaderValue(spdy_util_.GetStatusKey()));
496 EXPECT_EQ("HTTP/1.1",
497 delegate.GetResponseHeaderValue(spdy_util_.GetVersionKey()));
[email protected]aa19cfc2013-05-23 16:41:38498 EXPECT_EQ(std::string(), delegate.TakeReceivedData());
499 EXPECT_TRUE(data.at_write_eof());
500}
501
[email protected]6d116e1a2013-06-24 07:42:15502// Receiving a header with uppercase ASCII should result in a protocol
503// error.
504TEST_P(SpdyStreamTest, UpperCaseHeaders) {
505 GURL url(kStreamUrl);
506
507 session_ =
508 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
509
510 scoped_ptr<SpdyFrame> initial_window_update(
511 spdy_util_.ConstructSpdyWindowUpdate(
512 kSessionFlowControlStreamId,
513 kDefaultInitialRecvWindowSize - kSpdySessionInitialWindowSize));
514 if (spdy_util_.protocol() >= kProtoSPDY31)
515 AddWrite(*initial_window_update);
516
517 scoped_ptr<SpdyFrame> syn(
518 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
519 AddWrite(*syn);
520
521 const char* const kExtraHeaders[] = {"X-UpperCase", "yes"};
522 scoped_ptr<SpdyFrame>
523 reply(spdy_util_.ConstructSpdyGetSynReply(kExtraHeaders, 1, 1));
524 AddRead(*reply);
525
526 scoped_ptr<SpdyFrame> rst(
527 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR));
528 AddWrite(*rst);
529
530 AddReadEOF();
531
532 DeterministicSocketData data(GetReads(), GetNumReads(),
533 GetWrites(), GetNumWrites());
534 MockConnect connect_data(SYNCHRONOUS, OK);
535 data.set_connect_data(connect_data);
536
537 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
538
539 scoped_refptr<SpdySession> session(CreateSpdySession());
540
541 InitializeSpdySession(session, host_port_pair_);
542
543 base::WeakPtr<SpdyStream> stream =
544 CreateStreamSynchronously(
545 SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog());
546 ASSERT_TRUE(stream.get() != NULL);
547
548 StreamDelegateDoNothing delegate(stream);
549 stream->SetDelegate(&delegate);
550
551 EXPECT_FALSE(stream->HasUrl());
552
553 scoped_ptr<SpdyHeaderBlock> headers(
554 spdy_util_.ConstructGetHeaderBlock(kStreamUrl));
555 EXPECT_EQ(ERR_IO_PENDING,
556 stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND));
557 EXPECT_TRUE(stream->HasUrl());
558 EXPECT_EQ(kStreamUrl, stream->GetUrl().spec());
559
560 // For the initial window update.
561 if (spdy_util_.protocol() >= kProtoSPDY31)
562 data.RunFor(1);
563
564 data.RunFor(4);
565
566 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, delegate.WaitForClose());
567}
568
569// Receiving a header with uppercase ASCII should result in a protocol
570// error even for a push stream.
571TEST_P(SpdyStreamTest, UpperCaseHeadersOnPush) {
572 GURL url(kStreamUrl);
573
574 session_ =
575 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
576
577 scoped_ptr<SpdyFrame> initial_window_update(
578 spdy_util_.ConstructSpdyWindowUpdate(
579 kSessionFlowControlStreamId,
580 kDefaultInitialRecvWindowSize - kSpdySessionInitialWindowSize));
581 if (spdy_util_.protocol() >= kProtoSPDY31)
582 AddWrite(*initial_window_update);
583
584 scoped_ptr<SpdyFrame> syn(
585 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
586 AddWrite(*syn);
587
588 scoped_ptr<SpdyFrame>
589 reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
590 AddRead(*reply);
591
592 const char* const extra_headers[] = {"X-UpperCase", "yes"};
593 scoped_ptr<SpdyFrame>
594 push(spdy_util_.ConstructSpdyPush(extra_headers, 1, 2, 1, kStreamUrl));
595 AddRead(*push);
596
597 scoped_ptr<SpdyFrame> rst(
598 spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR));
599 AddWrite(*rst);
600
601 AddReadEOF();
602
603 DeterministicSocketData data(GetReads(), GetNumReads(),
604 GetWrites(), GetNumWrites());
605 MockConnect connect_data(SYNCHRONOUS, OK);
606 data.set_connect_data(connect_data);
607
608 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
609
610 scoped_refptr<SpdySession> session(CreateSpdySession());
611
612 InitializeSpdySession(session, host_port_pair_);
613
614 base::WeakPtr<SpdyStream> stream =
615 CreateStreamSynchronously(
616 SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog());
617 ASSERT_TRUE(stream.get() != NULL);
618
619 StreamDelegateDoNothing delegate(stream);
620 stream->SetDelegate(&delegate);
621
622 EXPECT_FALSE(stream->HasUrl());
623
624 scoped_ptr<SpdyHeaderBlock> headers(
625 spdy_util_.ConstructGetHeaderBlock(kStreamUrl));
626 EXPECT_EQ(ERR_IO_PENDING,
627 stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND));
628 EXPECT_TRUE(stream->HasUrl());
629 EXPECT_EQ(kStreamUrl, stream->GetUrl().spec());
630
631 // For the initial window update.
632 if (spdy_util_.protocol() >= kProtoSPDY31)
633 data.RunFor(1);
634
635 data.RunFor(4);
636
637 base::WeakPtr<SpdyStream> push_stream;
638 EXPECT_EQ(OK, session->GetPushStream(url, &push_stream, BoundNetLog()));
639 EXPECT_FALSE(push_stream);
640
641 data.RunFor(1);
642
643 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
644}
645
646// Receiving a header with uppercase ASCII in a HEADERS frame should
647// result in a protocol error.
648TEST_P(SpdyStreamTest, UpperCaseHeadersInHeadersFrame) {
649 GURL url(kStreamUrl);
650
651 session_ =
652 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
653
654 scoped_ptr<SpdyFrame> initial_window_update(
655 spdy_util_.ConstructSpdyWindowUpdate(
656 kSessionFlowControlStreamId,
657 kDefaultInitialRecvWindowSize - kSpdySessionInitialWindowSize));
658 if (spdy_util_.protocol() >= kProtoSPDY31)
659 AddWrite(*initial_window_update);
660
661 scoped_ptr<SpdyFrame> syn(
662 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
663 AddWrite(*syn);
664
665 scoped_ptr<SpdyFrame>
666 reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
667 AddRead(*reply);
668
669 scoped_ptr<SpdyFrame>
670 push(spdy_util_.ConstructSpdyPush(NULL, 0, 2, 1, kStreamUrl));
671 AddRead(*push);
672
673 scoped_ptr<SpdyHeaderBlock> late_headers(new SpdyHeaderBlock());
674 (*late_headers)["X-UpperCase"] = "yes";
675 scoped_ptr<SpdyFrame> headers_frame(
676 spdy_util_.ConstructSpdyControlFrame(late_headers.Pass(),
677 false,
678 2,
679 LOWEST,
680 HEADERS,
681 CONTROL_FLAG_NONE,
682 0));
683 AddRead(*headers_frame);
684
685 scoped_ptr<SpdyFrame> rst(
686 spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR));
687 AddWrite(*rst);
688
689 AddReadEOF();
690
691 DeterministicSocketData data(GetReads(), GetNumReads(),
692 GetWrites(), GetNumWrites());
693 MockConnect connect_data(SYNCHRONOUS, OK);
694 data.set_connect_data(connect_data);
695
696 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
697
698 scoped_refptr<SpdySession> session(CreateSpdySession());
699
700 InitializeSpdySession(session, host_port_pair_);
701
702 base::WeakPtr<SpdyStream> stream =
703 CreateStreamSynchronously(
704 SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog());
705 ASSERT_TRUE(stream.get() != NULL);
706
707 StreamDelegateDoNothing delegate(stream);
708 stream->SetDelegate(&delegate);
709
710 EXPECT_FALSE(stream->HasUrl());
711
712 scoped_ptr<SpdyHeaderBlock> headers(
713 spdy_util_.ConstructGetHeaderBlock(kStreamUrl));
714 EXPECT_EQ(ERR_IO_PENDING,
715 stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND));
716 EXPECT_TRUE(stream->HasUrl());
717 EXPECT_EQ(kStreamUrl, stream->GetUrl().spec());
718
719 // For the initial window update.
720 if (spdy_util_.protocol() >= kProtoSPDY31)
721 data.RunFor(1);
722
723 data.RunFor(3);
724
725 base::WeakPtr<SpdyStream> push_stream;
726 EXPECT_EQ(OK, session->GetPushStream(url, &push_stream, BoundNetLog()));
727 EXPECT_TRUE(push_stream);
728
729 data.RunFor(1);
730
731 EXPECT_EQ(OK, session->GetPushStream(url, &push_stream, BoundNetLog()));
732 EXPECT_FALSE(push_stream);
733
734 data.RunFor(2);
735
736 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
737}
738
739// Receiving a duplicate header in a HEADERS frame should result in a
740// protocol error.
741TEST_P(SpdyStreamTest, DuplicateHeaders) {
742 GURL url(kStreamUrl);
743
744 session_ =
745 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
746
747 scoped_ptr<SpdyFrame> initial_window_update(
748 spdy_util_.ConstructSpdyWindowUpdate(
749 kSessionFlowControlStreamId,
750 kDefaultInitialRecvWindowSize - kSpdySessionInitialWindowSize));
751 if (spdy_util_.protocol() >= kProtoSPDY31)
752 AddWrite(*initial_window_update);
753
754 scoped_ptr<SpdyFrame> syn(
755 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
756 AddWrite(*syn);
757
758 scoped_ptr<SpdyFrame>
759 reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
760 AddRead(*reply);
761
762 scoped_ptr<SpdyFrame>
763 push(spdy_util_.ConstructSpdyPush(NULL, 0, 2, 1, kStreamUrl));
764 AddRead(*push);
765
766 scoped_ptr<SpdyHeaderBlock> late_headers(new SpdyHeaderBlock());
767 (*late_headers)[spdy_util_.GetStatusKey()] = "500 Server Error";
768 scoped_ptr<SpdyFrame> headers_frame(
769 spdy_util_.ConstructSpdyControlFrame(late_headers.Pass(),
770 false,
771 2,
772 LOWEST,
773 HEADERS,
774 CONTROL_FLAG_NONE,
775 0));
776 AddRead(*headers_frame);
777
778 scoped_ptr<SpdyFrame> rst(
779 spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR));
780 AddWrite(*rst);
781
782 AddReadEOF();
783
784 DeterministicSocketData data(GetReads(), GetNumReads(),
785 GetWrites(), GetNumWrites());
786 MockConnect connect_data(SYNCHRONOUS, OK);
787 data.set_connect_data(connect_data);
788
789 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
790
791 scoped_refptr<SpdySession> session(CreateSpdySession());
792
793 InitializeSpdySession(session, host_port_pair_);
794
795 base::WeakPtr<SpdyStream> stream =
796 CreateStreamSynchronously(
797 SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog());
798 ASSERT_TRUE(stream.get() != NULL);
799
800 StreamDelegateDoNothing delegate(stream);
801 stream->SetDelegate(&delegate);
802
803 EXPECT_FALSE(stream->HasUrl());
804
805 scoped_ptr<SpdyHeaderBlock> headers(
806 spdy_util_.ConstructGetHeaderBlock(kStreamUrl));
807 EXPECT_EQ(ERR_IO_PENDING,
808 stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND));
809 EXPECT_TRUE(stream->HasUrl());
810 EXPECT_EQ(kStreamUrl, stream->GetUrl().spec());
811
812 // For the initial window update.
813 if (spdy_util_.protocol() >= kProtoSPDY31)
814 data.RunFor(1);
815
816 data.RunFor(3);
817
818 base::WeakPtr<SpdyStream> push_stream;
819 EXPECT_EQ(OK, session->GetPushStream(url, &push_stream, BoundNetLog()));
820 EXPECT_TRUE(push_stream);
821
822 data.RunFor(1);
823
824 EXPECT_EQ(OK, session->GetPushStream(url, &push_stream, BoundNetLog()));
825 EXPECT_FALSE(push_stream);
826
827 data.RunFor(2);
828
829 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
830}
831
[email protected]3d587372013-06-01 04:31:45832// The tests below are only for SPDY/3 and above.
833
[email protected]1e5ebd82013-02-20 20:07:24834// Call IncreaseSendWindowSize on a stream with a large enough delta
835// to overflow an int32. The SpdyStream should handle that case
836// gracefully.
[email protected]3d587372013-06-01 04:31:45837TEST_P(SpdyStreamTest, IncreaseSendWindowSizeOverflow) {
838 if (spdy_util_.protocol() < kProtoSPDY3)
839 return;
840
[email protected]1c12c062013-05-14 23:13:48841 session_ =
842 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
[email protected]1e5ebd82013-02-20 20:07:24843
[email protected]3d587372013-06-01 04:31:45844 scoped_ptr<SpdyFrame> initial_window_update(
845 spdy_util_.ConstructSpdyWindowUpdate(
846 kSessionFlowControlStreamId,
847 kDefaultInitialRecvWindowSize - kSpdySessionInitialWindowSize));
848 if (spdy_util_.protocol() >= kProtoSPDY31)
849 AddWrite(*initial_window_update);
[email protected]1e5ebd82013-02-20 20:07:24850
[email protected]1c12c062013-05-14 23:13:48851 scoped_ptr<SpdyFrame> req(
[email protected]3d587372013-06-01 04:31:45852 spdy_util_.ConstructSpdyPost(
853 kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0));
854 AddWrite(*req);
855
[email protected]1e5ebd82013-02-20 20:07:24856 // Triggered by the overflowing call to IncreaseSendWindowSize
857 // below.
858 scoped_ptr<SpdyFrame> rst(
[email protected]c10b20852013-05-15 21:29:20859 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_FLOW_CONTROL_ERROR));
[email protected]3d587372013-06-01 04:31:45860 AddWrite(*rst);
861
862 AddReadEOF();
[email protected]1e5ebd82013-02-20 20:07:24863
864 CapturingBoundNetLog log;
865
[email protected]3d587372013-06-01 04:31:45866 DeterministicSocketData data(GetReads(), GetNumReads(),
867 GetWrites(), GetNumWrites());
[email protected]1e5ebd82013-02-20 20:07:24868 MockConnect connect_data(SYNCHRONOUS, OK);
869 data.set_connect_data(connect_data);
870
[email protected]1c12c062013-05-14 23:13:48871 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
[email protected]1e5ebd82013-02-20 20:07:24872
873 scoped_refptr<SpdySession> session(CreateSpdySession());
[email protected]1e5ebd82013-02-20 20:07:24874 GURL url(kStreamUrl);
875
[email protected]34a4dea2013-03-13 00:42:30876 InitializeSpdySession(session, host_port_pair_);
[email protected]1e5ebd82013-02-20 20:07:24877
[email protected]d26ff352013-05-13 08:48:28878 base::WeakPtr<SpdyStream> stream =
[email protected]fb73cd672013-05-27 12:53:08879 CreateStreamSynchronously(
880 SPDY_BIDIRECTIONAL_STREAM, session, url, LOWEST, log.bound());
[email protected]e3861ca2013-03-02 01:00:45881 ASSERT_TRUE(stream.get() != NULL);
[email protected]194cfcf2013-05-23 21:44:44882 StreamDelegateSendImmediate delegate(stream, kPostBodyStringPiece);
[email protected]1c6b12a2013-03-21 00:59:11883 stream->SetDelegate(&delegate);
[email protected]1e5ebd82013-02-20 20:07:24884
[email protected]ee7c40d12013-05-24 21:13:10885 scoped_ptr<SpdyHeaderBlock> headers(
[email protected]1c12c062013-05-14 23:13:48886 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
[email protected]528b3452013-05-25 01:28:54887 EXPECT_EQ(ERR_IO_PENDING,
888 stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
[email protected]1c12c062013-05-14 23:13:48889 EXPECT_TRUE(stream->HasUrl());
890 EXPECT_EQ(kStreamUrl, stream->GetUrl().spec());
891
[email protected]3d587372013-06-01 04:31:45892 // For the initial window update.
893 if (spdy_util_.protocol() >= kProtoSPDY31)
894 data.RunFor(1);
895
[email protected]1c12c062013-05-14 23:13:48896 data.RunFor(1);
[email protected]1e5ebd82013-02-20 20:07:24897
898 int32 old_send_window_size = stream->send_window_size();
899 ASSERT_GT(old_send_window_size, 0);
900 int32 delta_window_size = kint32max - old_send_window_size + 1;
901 stream->IncreaseSendWindowSize(delta_window_size);
[email protected]1c12c062013-05-14 23:13:48902 EXPECT_EQ(NULL, stream.get());
[email protected]1e5ebd82013-02-20 20:07:24903
[email protected]1c12c062013-05-14 23:13:48904 data.RunFor(2);
905
906 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, delegate.WaitForClose());
[email protected]1e5ebd82013-02-20 20:07:24907}
908
[email protected]d2de7da2013-05-22 07:49:56909// Functions used with
910// RunResumeAfterUnstall{RequestResponse,Bidirectional}Test().
911
912void StallStream(const base::WeakPtr<SpdyStream>& stream) {
913 // Reduce the send window size to 0 to stall.
914 while (stream->send_window_size() > 0) {
915 stream->DecreaseSendWindowSize(
916 std::min(kMaxSpdyFrameChunkSize, stream->send_window_size()));
917 }
918}
919
920void IncreaseStreamSendWindowSize(const base::WeakPtr<SpdyStream>& stream,
921 int32 delta_window_size) {
922 EXPECT_TRUE(stream->send_stalled_by_flow_control());
923 stream->IncreaseSendWindowSize(delta_window_size);
924 EXPECT_FALSE(stream->send_stalled_by_flow_control());
925}
926
927void AdjustStreamSendWindowSize(const base::WeakPtr<SpdyStream>& stream,
928 int32 delta_window_size) {
929 // Make sure that negative adjustments are handled properly.
930 EXPECT_TRUE(stream->send_stalled_by_flow_control());
931 stream->AdjustSendWindowSize(-delta_window_size);
932 EXPECT_TRUE(stream->send_stalled_by_flow_control());
933 stream->AdjustSendWindowSize(+delta_window_size);
934 EXPECT_TRUE(stream->send_stalled_by_flow_control());
935 stream->AdjustSendWindowSize(+delta_window_size);
936 EXPECT_FALSE(stream->send_stalled_by_flow_control());
937}
938
939// Given an unstall function, runs a test to make sure that a
940// request/response (i.e., an HTTP-like) stream resumes after a stall
941// and unstall.
[email protected]3d587372013-06-01 04:31:45942void SpdyStreamTest::RunResumeAfterUnstallRequestResponseTest(
[email protected]d2de7da2013-05-22 07:49:56943 const UnstallFunction& unstall_function) {
[email protected]3d587372013-06-01 04:31:45944 if (spdy_util_.protocol() < kProtoSPDY3)
945 return;
946
[email protected]34a4dea2013-03-13 00:42:30947 GURL url(kStreamUrl);
948
[email protected]34a4dea2013-03-13 00:42:30949 session_ =
950 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
951
[email protected]3d587372013-06-01 04:31:45952 scoped_ptr<SpdyFrame> initial_window_update(
953 spdy_util_.ConstructSpdyWindowUpdate(
954 kSessionFlowControlStreamId,
955 kDefaultInitialRecvWindowSize - kSpdySessionInitialWindowSize));
956 if (spdy_util_.protocol() >= kProtoSPDY31)
957 AddWrite(*initial_window_update);
958
[email protected]cbdd73162013-03-18 23:27:33959 scoped_ptr<SpdyFrame> req(
[email protected]3d587372013-06-01 04:31:45960 spdy_util_.ConstructSpdyPost(
961 kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0));
962 AddWrite(*req);
963
[email protected]d2de7da2013-05-22 07:49:56964 scoped_ptr<SpdyFrame> body(
[email protected]3d587372013-06-01 04:31:45965 spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, true));
966 AddWrite(*body);
[email protected]34a4dea2013-03-13 00:42:30967
[email protected]3d587372013-06-01 04:31:45968 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
969 AddRead(*resp);
[email protected]34a4dea2013-03-13 00:42:30970
[email protected]3d587372013-06-01 04:31:45971 AddReadEOF();
972
973 DeterministicSocketData data(GetReads(), GetNumReads(),
974 GetWrites(), GetNumWrites());
[email protected]34a4dea2013-03-13 00:42:30975 MockConnect connect_data(SYNCHRONOUS, OK);
976 data.set_connect_data(connect_data);
977
978 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
979
980 scoped_refptr<SpdySession> session(CreateSpdySession());
[email protected]34a4dea2013-03-13 00:42:30981
982 InitializeSpdySession(session, host_port_pair_);
983
[email protected]d26ff352013-05-13 08:48:28984 base::WeakPtr<SpdyStream> stream =
[email protected]fb73cd672013-05-27 12:53:08985 CreateStreamSynchronously(
986 SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog());
[email protected]34a4dea2013-03-13 00:42:30987 ASSERT_TRUE(stream.get() != NULL);
[email protected]34a4dea2013-03-13 00:42:30988
[email protected]d26ff352013-05-13 08:48:28989 StreamDelegateWithBody delegate(stream, kPostBodyStringPiece);
[email protected]34a4dea2013-03-13 00:42:30990 stream->SetDelegate(&delegate);
991
992 EXPECT_FALSE(stream->HasUrl());
[email protected]1c6b12a2013-03-21 00:59:11993 EXPECT_FALSE(stream->send_stalled_by_flow_control());
[email protected]34a4dea2013-03-13 00:42:30994
[email protected]ee7c40d12013-05-24 21:13:10995 scoped_ptr<SpdyHeaderBlock> headers(
996 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
[email protected]528b3452013-05-25 01:28:54997 EXPECT_EQ(ERR_IO_PENDING,
998 stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
[email protected]ee7c40d12013-05-24 21:13:10999 EXPECT_TRUE(stream->HasUrl());
1000 EXPECT_EQ(kStreamUrl, stream->GetUrl().spec());
[email protected]34a4dea2013-03-13 00:42:301001
[email protected]d2de7da2013-05-22 07:49:561002 StallStream(stream);
1003
[email protected]3d587372013-06-01 04:31:451004 // For the initial window update.
1005 if (spdy_util_.protocol() >= kProtoSPDY31)
1006 data.RunFor(1);
1007
[email protected]d2de7da2013-05-22 07:49:561008 data.RunFor(1);
[email protected]34a4dea2013-03-13 00:42:301009
[email protected]1c6b12a2013-03-21 00:59:111010 EXPECT_TRUE(stream->send_stalled_by_flow_control());
[email protected]34a4dea2013-03-13 00:42:301011
[email protected]d2de7da2013-05-22 07:49:561012 unstall_function.Run(stream, kPostBodyLength);
[email protected]34a4dea2013-03-13 00:42:301013
[email protected]1c6b12a2013-03-21 00:59:111014 EXPECT_FALSE(stream->send_stalled_by_flow_control());
[email protected]34a4dea2013-03-13 00:42:301015
1016 data.RunFor(3);
1017
1018 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
1019
1020 EXPECT_TRUE(delegate.send_headers_completed());
1021 EXPECT_EQ("200", delegate.GetResponseHeaderValue(":status"));
1022 EXPECT_EQ("HTTP/1.1", delegate.GetResponseHeaderValue(":version"));
[email protected]d2de7da2013-05-22 07:49:561023 EXPECT_EQ(std::string(), delegate.TakeReceivedData());
[email protected]aa19cfc2013-05-23 16:41:381024 EXPECT_TRUE(data.at_write_eof());
[email protected]cbdd73162013-03-18 23:27:331025}
1026
[email protected]3d587372013-06-01 04:31:451027TEST_P(SpdyStreamTest, ResumeAfterSendWindowSizeIncreaseRequestResponse) {
[email protected]d2de7da2013-05-22 07:49:561028 RunResumeAfterUnstallRequestResponseTest(
1029 base::Bind(&IncreaseStreamSendWindowSize));
1030}
1031
[email protected]3d587372013-06-01 04:31:451032TEST_P(SpdyStreamTest, ResumeAfterSendWindowSizeAdjustRequestResponse) {
[email protected]d2de7da2013-05-22 07:49:561033 RunResumeAfterUnstallRequestResponseTest(
1034 base::Bind(&AdjustStreamSendWindowSize));
1035}
1036
1037// Given an unstall function, runs a test to make sure that a
[email protected]63c8cb02013-05-22 22:34:041038// bidirectional (i.e., non-HTTP-like) stream resumes after a stall
1039// and unstall.
[email protected]3d587372013-06-01 04:31:451040void SpdyStreamTest::RunResumeAfterUnstallBidirectionalTest(
[email protected]d2de7da2013-05-22 07:49:561041 const UnstallFunction& unstall_function) {
[email protected]3d587372013-06-01 04:31:451042 if (spdy_util_.protocol() < kProtoSPDY3)
1043 return;
1044
[email protected]cbdd73162013-03-18 23:27:331045 GURL url(kStreamUrl);
1046
1047 session_ =
1048 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
1049
[email protected]3d587372013-06-01 04:31:451050 scoped_ptr<SpdyFrame> initial_window_update(
1051 spdy_util_.ConstructSpdyWindowUpdate(
1052 kSessionFlowControlStreamId,
1053 kDefaultInitialRecvWindowSize - kSpdySessionInitialWindowSize));
1054 if (spdy_util_.protocol() >= kProtoSPDY31)
1055 AddWrite(*initial_window_update);
1056
[email protected]cbdd73162013-03-18 23:27:331057 scoped_ptr<SpdyFrame> req(
[email protected]3d587372013-06-01 04:31:451058 spdy_util_.ConstructSpdyPost(
1059 kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0));
1060 AddWrite(*req);
1061
1062 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
1063 AddRead(*resp);
1064
[email protected]cbdd73162013-03-18 23:27:331065 scoped_ptr<SpdyFrame> msg(
[email protected]3d587372013-06-01 04:31:451066 spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false));
1067 AddWrite(*msg);
[email protected]cbdd73162013-03-18 23:27:331068
[email protected]cbdd73162013-03-18 23:27:331069 scoped_ptr<SpdyFrame> echo(
[email protected]3d587372013-06-01 04:31:451070 spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false));
1071 AddRead(*echo);
[email protected]cbdd73162013-03-18 23:27:331072
[email protected]3d587372013-06-01 04:31:451073 AddReadEOF();
1074
1075 DeterministicSocketData data(GetReads(), GetNumReads(),
1076 GetWrites(), GetNumWrites());
[email protected]cbdd73162013-03-18 23:27:331077 MockConnect connect_data(SYNCHRONOUS, OK);
1078 data.set_connect_data(connect_data);
1079
1080 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
1081
1082 scoped_refptr<SpdySession> session(CreateSpdySession());
1083
1084 InitializeSpdySession(session, host_port_pair_);
1085
[email protected]d26ff352013-05-13 08:48:281086 base::WeakPtr<SpdyStream> stream =
[email protected]fb73cd672013-05-27 12:53:081087 CreateStreamSynchronously(
1088 SPDY_BIDIRECTIONAL_STREAM, session, url, LOWEST, BoundNetLog());
[email protected]cbdd73162013-03-18 23:27:331089 ASSERT_TRUE(stream.get() != NULL);
[email protected]cbdd73162013-03-18 23:27:331090
[email protected]194cfcf2013-05-23 21:44:441091 StreamDelegateSendImmediate delegate(stream, kPostBodyStringPiece);
[email protected]cbdd73162013-03-18 23:27:331092 stream->SetDelegate(&delegate);
1093
1094 EXPECT_FALSE(stream->HasUrl());
1095
[email protected]ee7c40d12013-05-24 21:13:101096 scoped_ptr<SpdyHeaderBlock> headers(
[email protected]a4a67772013-05-08 22:56:071097 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
[email protected]528b3452013-05-25 01:28:541098 EXPECT_EQ(ERR_IO_PENDING,
1099 stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
[email protected]cbdd73162013-03-18 23:27:331100 EXPECT_TRUE(stream->HasUrl());
1101 EXPECT_EQ(kStreamUrl, stream->GetUrl().spec());
1102
[email protected]d2de7da2013-05-22 07:49:561103 data.RunFor(1);
[email protected]cbdd73162013-03-18 23:27:331104
[email protected]1c6b12a2013-03-21 00:59:111105 EXPECT_FALSE(stream->send_stalled_by_flow_control());
[email protected]cbdd73162013-03-18 23:27:331106
[email protected]d2de7da2013-05-22 07:49:561107 StallStream(stream);
[email protected]cbdd73162013-03-18 23:27:331108
[email protected]3d587372013-06-01 04:31:451109 // For the initial window update.
1110 if (spdy_util_.protocol() >= kProtoSPDY31)
1111 data.RunFor(1);
1112
[email protected]d2de7da2013-05-22 07:49:561113 data.RunFor(1);
[email protected]cbdd73162013-03-18 23:27:331114
[email protected]1c6b12a2013-03-21 00:59:111115 EXPECT_TRUE(stream->send_stalled_by_flow_control());
[email protected]cbdd73162013-03-18 23:27:331116
[email protected]d2de7da2013-05-22 07:49:561117 unstall_function.Run(stream, kPostBodyLength);
[email protected]cbdd73162013-03-18 23:27:331118
[email protected]1c6b12a2013-03-21 00:59:111119 EXPECT_FALSE(stream->send_stalled_by_flow_control());
[email protected]cbdd73162013-03-18 23:27:331120
1121 data.RunFor(3);
1122
1123 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
1124
1125 EXPECT_TRUE(delegate.send_headers_completed());
1126 EXPECT_EQ("200", delegate.GetResponseHeaderValue(":status"));
1127 EXPECT_EQ("HTTP/1.1", delegate.GetResponseHeaderValue(":version"));
[email protected]09a8d9172013-04-17 19:23:491128 EXPECT_EQ(std::string(kPostBody, kPostBodyLength),
1129 delegate.TakeReceivedData());
[email protected]aa19cfc2013-05-23 16:41:381130 EXPECT_TRUE(data.at_write_eof());
[email protected]d2de7da2013-05-22 07:49:561131}
1132
[email protected]3d587372013-06-01 04:31:451133TEST_P(SpdyStreamTest, ResumeAfterSendWindowSizeIncreaseBidirectional) {
[email protected]d2de7da2013-05-22 07:49:561134 RunResumeAfterUnstallBidirectionalTest(
1135 base::Bind(&IncreaseStreamSendWindowSize));
1136}
1137
[email protected]3d587372013-06-01 04:31:451138TEST_P(SpdyStreamTest, ResumeAfterSendWindowSizeAdjustBidirectional) {
[email protected]d2de7da2013-05-22 07:49:561139 RunResumeAfterUnstallBidirectionalTest(
1140 base::Bind(&AdjustStreamSendWindowSize));
[email protected]34a4dea2013-03-13 00:42:301141}
1142
1143} // namespace
1144
[email protected]39d13d942012-07-19 16:48:201145} // namespace test
1146
[email protected]4f386422010-07-20 04:19:491147} // namespace net