blob: 98c77358008b0c613d4456bc7871e1a0cded36b3 [file] [log] [blame]
[email protected]a1595312012-01-22 03:25:041// Copyright (c) 2012 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]34a4dea2013-03-13 00:42:305#include "base/basictypes.h"
[email protected]3b63f8f42011-03-28 01:54:156#include "base/memory/ref_counted.h"
[email protected]34a4dea2013-03-13 00:42:307#include "base/memory/scoped_ptr.h"
[email protected]d2de7da2013-05-22 07:49:568#include "base/memory/weak_ptr.h"
[email protected]d069c11a2013-04-13 00:01:559#include "base/strings/string_piece.h"
[email protected]5a76b812011-12-21 20:52:0010#include "net/base/completion_callback.h"
[email protected]d245c342012-02-23 20:49:1511#include "net/base/net_log_unittest.h"
[email protected]1bbabc82013-03-25 21:11:0212#include "net/base/request_priority.h"
[email protected]bb88e1d32013-05-03 23:11:0713#include "net/socket/next_proto.h"
[email protected]f54c85792012-03-08 19:06:4114#include "net/spdy/buffered_spdy_framer.h"
[email protected]9e1bdd32011-02-03 21:48:3415#include "net/spdy/spdy_http_utils.h"
[email protected]34a4dea2013-03-13 00:42:3016#include "net/spdy/spdy_protocol.h"
[email protected]4f386422010-07-20 04:19:4917#include "net/spdy/spdy_session.h"
[email protected]d069c11a2013-04-13 00:01:5518#include "net/spdy/spdy_stream.h"
[email protected]39d13d942012-07-19 16:48:2019#include "net/spdy/spdy_stream_test_util.h"
[email protected]e3861ca2013-03-02 01:00:4520#include "net/spdy/spdy_test_util_common.h"
[email protected]448d4ca52012-03-04 04:12:2321#include "net/spdy/spdy_test_util_spdy3.h"
[email protected]5e248dc2012-08-21 02:27:3222#include "net/spdy/spdy_websocket_test_util_spdy3.h"
[email protected]4f386422010-07-20 04:19:4923#include "testing/gtest/include/gtest/gtest.h"
24
[email protected]448d4ca52012-03-04 04:12:2325using namespace net::test_spdy3;
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]448d4ca52012-03-04 04:12:2340class SpdyStreamSpdy3Test : public testing::Test {
[email protected]4f386422010-07-20 04:19:4941 protected:
[email protected]d2de7da2013-05-22 07:49:5642 // A function that takes a SpdyStream and the number of bytes which
43 // will unstall the next frame completely.
44 typedef base::Callback<void(const base::WeakPtr<SpdyStream>&, int32)>
45 UnstallFunction;
46
[email protected]bb88e1d32013-05-03 23:11:0747 SpdyStreamSpdy3Test()
[email protected]a4a67772013-05-08 22:56:0748 : spdy_util_(kProtoSPDY3),
49 host_port_pair_("www.google.com", 80),
[email protected]bb88e1d32013-05-03 23:11:0750 session_deps_(kProtoSPDY3) {}
[email protected]4f386422010-07-20 04:19:4951
52 scoped_refptr<SpdySession> CreateSpdySession() {
[email protected]e6d017652013-05-17 18:01:4053 SpdySessionKey key(host_port_pair_, ProxyServer::Direct(),
54 kPrivacyModeDisabled);
[email protected]4f386422010-07-20 04:19:4955 scoped_refptr<SpdySession> session(
[email protected]e6d017652013-05-17 18:01:4056 session_->spdy_session_pool()->Get(key, BoundNetLog()));
[email protected]4f386422010-07-20 04:19:4957 return session;
58 }
59
[email protected]34a4dea2013-03-13 00:42:3060 void InitializeSpdySession(const scoped_refptr<SpdySession>& session,
61 const HostPortPair& host_port_pair) {
62 scoped_refptr<TransportSocketParams> transport_params(
63 new TransportSocketParams(host_port_pair, LOWEST, false, false,
64 OnHostResolutionCallback()));
65
66 scoped_ptr<ClientSocketHandle> connection(new ClientSocketHandle);
67 EXPECT_EQ(OK, connection->Init(host_port_pair.ToString(), transport_params,
68 LOWEST, CompletionCallback(),
69 session_->GetTransportSocketPool(
70 HttpNetworkSession::NORMAL_SOCKET_POOL),
71 BoundNetLog()));
72 session->InitializeWithSocket(connection.release(), false, OK);
73 }
74
[email protected]4f386422010-07-20 04:19:4975 virtual void TearDown() {
[email protected]2da659e2013-05-23 20:51:3476 base::MessageLoop::current()->RunUntilIdle();
[email protected]4f386422010-07-20 04:19:4977 }
78
[email protected]d2de7da2013-05-22 07:49:5679 void RunResumeAfterUnstallRequestResponseTest(
80 const UnstallFunction& unstall_function);
81
82 void RunResumeAfterUnstallBidirectionalTest(
83 const UnstallFunction& unstall_function);
84
[email protected]a4a67772013-05-08 22:56:0785 SpdyTestUtil spdy_util_;
[email protected]34a4dea2013-03-13 00:42:3086 HostPortPair host_port_pair_;
87 SpdySessionDependencies session_deps_;
[email protected]4f386422010-07-20 04:19:4988 scoped_refptr<HttpNetworkSession> session_;
89};
90
[email protected]448d4ca52012-03-04 04:12:2391TEST_F(SpdyStreamSpdy3Test, SendDataAfterOpen) {
[email protected]cbdd73162013-03-18 23:27:3392 GURL url(kStreamUrl);
[email protected]34a4dea2013-03-13 00:42:3093 session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_);
[email protected]4f386422010-07-20 04:19:4994
[email protected]cbdd73162013-03-18 23:27:3395 scoped_ptr<SpdyFrame> req(
96 ConstructSpdyPost(kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0));
97 scoped_ptr<SpdyFrame> msg(
98 ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false));
[email protected]4f386422010-07-20 04:19:4999 MockWrite writes[] = {
100 CreateMockWrite(*req),
101 CreateMockWrite(*msg),
102 };
103 writes[0].sequence_number = 0;
104 writes[1].sequence_number = 2;
105
[email protected]ff98d7f02012-03-22 21:44:19106 scoped_ptr<SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1));
[email protected]cbdd73162013-03-18 23:27:33107 scoped_ptr<SpdyFrame> echo(
108 ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false));
[email protected]4f386422010-07-20 04:19:49109 MockRead reads[] = {
110 CreateMockRead(*resp),
111 CreateMockRead(*echo),
[email protected]8ddf8322012-02-23 18:08:06112 MockRead(ASYNC, 0, 0), // EOF
[email protected]4f386422010-07-20 04:19:49113 };
114 reads[0].sequence_number = 1;
115 reads[1].sequence_number = 3;
116 reads[2].sequence_number = 4;
117
[email protected]dd54bd82012-07-19 23:44:57118 OrderedSocketData data(reads, arraysize(reads),
119 writes, arraysize(writes));
[email protected]d973e99a2012-02-17 21:02:36120 MockConnect connect_data(SYNCHRONOUS, OK);
[email protected]dd54bd82012-07-19 23:44:57121 data.set_connect_data(connect_data);
[email protected]4f386422010-07-20 04:19:49122
[email protected]34a4dea2013-03-13 00:42:30123 session_deps_.socket_factory->AddSocketDataProvider(&data);
[email protected]4f386422010-07-20 04:19:49124
125 scoped_refptr<SpdySession> session(CreateSpdySession());
[email protected]4f386422010-07-20 04:19:49126
[email protected]34a4dea2013-03-13 00:42:30127 InitializeSpdySession(session, host_port_pair_);
[email protected]e3861ca2013-03-02 01:00:45128
[email protected]d26ff352013-05-13 08:48:28129 base::WeakPtr<SpdyStream> stream =
[email protected]e3861ca2013-03-02 01:00:45130 CreateStreamSynchronously(session, url, LOWEST, BoundNetLog());
131 ASSERT_TRUE(stream.get() != NULL);
[email protected]4f386422010-07-20 04:19:49132
[email protected]194cfcf2013-05-23 21:44:44133 StreamDelegateSendImmediate delegate(stream, kPostBodyStringPiece);
[email protected]34a4dea2013-03-13 00:42:30134 stream->SetDelegate(&delegate);
[email protected]4f386422010-07-20 04:19:49135
[email protected]a7a265ef2010-12-08 18:05:57136 EXPECT_FALSE(stream->HasUrl());
137
[email protected]ee7c40d12013-05-24 21:13:10138 scoped_ptr<SpdyHeaderBlock> headers(
[email protected]a4a67772013-05-08 22:56:07139 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
[email protected]528b3452013-05-25 01:28:54140 EXPECT_EQ(ERR_IO_PENDING,
141 stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
[email protected]a7a265ef2010-12-08 18:05:57142 EXPECT_TRUE(stream->HasUrl());
143 EXPECT_EQ(kStreamUrl, stream->GetUrl().spec());
[email protected]4f386422010-07-20 04:19:49144
[email protected]34a4dea2013-03-13 00:42:30145 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
[email protected]4f386422010-07-20 04:19:49146
[email protected]34a4dea2013-03-13 00:42:30147 EXPECT_TRUE(delegate.send_headers_completed());
148 EXPECT_EQ("200", delegate.GetResponseHeaderValue(":status"));
149 EXPECT_EQ("HTTP/1.1", delegate.GetResponseHeaderValue(":version"));
[email protected]09a8d9172013-04-17 19:23:49150 EXPECT_EQ(std::string(kPostBody, kPostBodyLength),
151 delegate.TakeReceivedData());
[email protected]aa19cfc2013-05-23 16:41:38152 EXPECT_TRUE(data.at_write_eof());
[email protected]4f386422010-07-20 04:19:49153}
154
[email protected]448d4ca52012-03-04 04:12:23155TEST_F(SpdyStreamSpdy3Test, PushedStream) {
[email protected]34a4dea2013-03-13 00:42:30156 session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_);
[email protected]a7a265ef2010-12-08 18:05:57157 scoped_refptr<SpdySession> spdy_session(CreateSpdySession());
[email protected]0e861e92012-03-15 18:42:19158
159 MockRead reads[] = {
160 MockRead(ASYNC, 0, 0), // EOF
161 };
162
[email protected]dd54bd82012-07-19 23:44:57163 OrderedSocketData data(reads, arraysize(reads), NULL, 0);
[email protected]0e861e92012-03-15 18:42:19164 MockConnect connect_data(SYNCHRONOUS, OK);
[email protected]dd54bd82012-07-19 23:44:57165 data.set_connect_data(connect_data);
[email protected]0e861e92012-03-15 18:42:19166
[email protected]34a4dea2013-03-13 00:42:30167 session_deps_.socket_factory->AddSocketDataProvider(&data);
[email protected]0e861e92012-03-15 18:42:19168
[email protected]34a4dea2013-03-13 00:42:30169 InitializeSpdySession(spdy_session, host_port_pair_);
[email protected]a7a265ef2010-12-08 18:05:57170 BoundNetLog net_log;
171
172 // Conjure up a stream.
[email protected]1c12c062013-05-14 23:13:48173 SpdyStream stream(spdy_session,
174 std::string(),
175 DEFAULT_PRIORITY,
176 kSpdyStreamInitialWindowSize,
177 kSpdyStreamInitialWindowSize,
178 true,
179 net_log);
180 stream.set_stream_id(2);
181 EXPECT_FALSE(stream.response_received());
182 EXPECT_FALSE(stream.HasUrl());
[email protected]a7a265ef2010-12-08 18:05:57183
184 // Set a couple of headers.
[email protected]ff98d7f02012-03-22 21:44:19185 SpdyHeaderBlock response;
[email protected]0e861e92012-03-15 18:42:19186 GURL url(kStreamUrl);
187 response[":host"] = url.host();
188 response[":scheme"] = url.scheme();
189 response[":path"] = url.path();
[email protected]1c12c062013-05-14 23:13:48190 stream.OnResponseReceived(response);
[email protected]a7a265ef2010-12-08 18:05:57191
192 // Send some basic headers.
[email protected]ff98d7f02012-03-22 21:44:19193 SpdyHeaderBlock headers;
[email protected]d42dedd02012-04-03 19:42:06194 response[":status"] = "200";
195 response[":version"] = "OK";
[email protected]1c12c062013-05-14 23:13:48196 stream.OnHeaders(headers);
[email protected]a7a265ef2010-12-08 18:05:57197
[email protected]1c12c062013-05-14 23:13:48198 stream.set_response_received();
199 EXPECT_TRUE(stream.response_received());
200 EXPECT_TRUE(stream.HasUrl());
201 EXPECT_EQ(kStreamUrl, stream.GetUrl().spec());
[email protected]a7a265ef2010-12-08 18:05:57202}
203
[email protected]448d4ca52012-03-04 04:12:23204TEST_F(SpdyStreamSpdy3Test, StreamError) {
[email protected]cbdd73162013-03-18 23:27:33205 GURL url(kStreamUrl);
206
[email protected]34a4dea2013-03-13 00:42:30207 session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_);
[email protected]d245c342012-02-23 20:49:15208
[email protected]cbdd73162013-03-18 23:27:33209 scoped_ptr<SpdyFrame> req(
210 ConstructSpdyPost(kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0));
211 scoped_ptr<SpdyFrame> msg(
212 ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false));
[email protected]d245c342012-02-23 20:49:15213 MockWrite writes[] = {
214 CreateMockWrite(*req),
215 CreateMockWrite(*msg),
216 };
217 writes[0].sequence_number = 0;
218 writes[1].sequence_number = 2;
219
[email protected]ff98d7f02012-03-22 21:44:19220 scoped_ptr<SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1));
[email protected]cbdd73162013-03-18 23:27:33221 scoped_ptr<SpdyFrame> echo(
222 ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false));
[email protected]d245c342012-02-23 20:49:15223 MockRead reads[] = {
224 CreateMockRead(*resp),
225 CreateMockRead(*echo),
226 MockRead(ASYNC, 0, 0), // EOF
227 };
228 reads[0].sequence_number = 1;
229 reads[1].sequence_number = 3;
230 reads[2].sequence_number = 4;
231
[email protected]333bdf62012-06-08 22:57:29232 CapturingBoundNetLog log;
[email protected]d245c342012-02-23 20:49:15233
[email protected]dd54bd82012-07-19 23:44:57234 OrderedSocketData data(reads, arraysize(reads),
235 writes, arraysize(writes));
[email protected]d245c342012-02-23 20:49:15236 MockConnect connect_data(SYNCHRONOUS, OK);
[email protected]dd54bd82012-07-19 23:44:57237 data.set_connect_data(connect_data);
[email protected]d245c342012-02-23 20:49:15238
[email protected]34a4dea2013-03-13 00:42:30239 session_deps_.socket_factory->AddSocketDataProvider(&data);
[email protected]d245c342012-02-23 20:49:15240
241 scoped_refptr<SpdySession> session(CreateSpdySession());
[email protected]d245c342012-02-23 20:49:15242
[email protected]34a4dea2013-03-13 00:42:30243 InitializeSpdySession(session, host_port_pair_);
[email protected]d245c342012-02-23 20:49:15244
[email protected]d26ff352013-05-13 08:48:28245 base::WeakPtr<SpdyStream> stream =
[email protected]e3861ca2013-03-02 01:00:45246 CreateStreamSynchronously(session, url, LOWEST, log.bound());
247 ASSERT_TRUE(stream.get() != NULL);
[email protected]d245c342012-02-23 20:49:15248
[email protected]194cfcf2013-05-23 21:44:44249 StreamDelegateSendImmediate delegate(stream, kPostBodyStringPiece);
[email protected]34a4dea2013-03-13 00:42:30250 stream->SetDelegate(&delegate);
[email protected]d245c342012-02-23 20:49:15251
252 EXPECT_FALSE(stream->HasUrl());
253
[email protected]ee7c40d12013-05-24 21:13:10254 scoped_ptr<SpdyHeaderBlock> headers(
[email protected]a4a67772013-05-08 22:56:07255 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
[email protected]528b3452013-05-25 01:28:54256 EXPECT_EQ(ERR_IO_PENDING,
257 stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
[email protected]d245c342012-02-23 20:49:15258 EXPECT_TRUE(stream->HasUrl());
259 EXPECT_EQ(kStreamUrl, stream->GetUrl().spec());
260
[email protected]34a4dea2013-03-13 00:42:30261 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
[email protected]218f4b62012-07-20 20:12:41262
[email protected]d26ff352013-05-13 08:48:28263 const SpdyStreamId stream_id = delegate.stream_id();
[email protected]c92f4b4542012-07-26 23:53:21264
[email protected]34a4dea2013-03-13 00:42:30265 EXPECT_TRUE(delegate.send_headers_completed());
266 EXPECT_EQ("200", delegate.GetResponseHeaderValue(":status"));
267 EXPECT_EQ("HTTP/1.1", delegate.GetResponseHeaderValue(":version"));
[email protected]09a8d9172013-04-17 19:23:49268 EXPECT_EQ(std::string(kPostBody, kPostBodyLength),
269 delegate.TakeReceivedData());
[email protected]aa19cfc2013-05-23 16:41:38270 EXPECT_TRUE(data.at_write_eof());
[email protected]d245c342012-02-23 20:49:15271
272 // Check that the NetLog was filled reasonably.
[email protected]f3da152d2012-06-02 01:00:57273 net::CapturingNetLog::CapturedEntryList entries;
[email protected]d245c342012-02-23 20:49:15274 log.GetEntries(&entries);
275 EXPECT_LT(0u, entries.size());
276
277 // Check that we logged SPDY_STREAM_ERROR correctly.
278 int pos = net::ExpectLogContainsSomewhere(
279 entries, 0,
280 net::NetLog::TYPE_SPDY_STREAM_ERROR,
281 net::NetLog::PHASE_NONE);
282
[email protected]f3da152d2012-06-02 01:00:57283 int stream_id2;
284 ASSERT_TRUE(entries[pos].GetIntegerValue("stream_id", &stream_id2));
285 EXPECT_EQ(static_cast<int>(stream_id), stream_id2);
[email protected]d245c342012-02-23 20:49:15286}
[email protected]a7a265ef2010-12-08 18:05:57287
[email protected]aa19cfc2013-05-23 16:41:38288// Make sure that large blocks of data are properly split up into
289// frame-sized chunks for a request/response (i.e., an HTTP-like)
290// stream.
291TEST_F(SpdyStreamSpdy3Test, SendLargeDataAfterOpenRequestResponse) {
292 GURL url(kStreamUrl);
293
294 session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_);
295
296 scoped_ptr<SpdyFrame> req(
297 ConstructSpdyPost(kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0));
298 std::string chunk_data(kMaxSpdyFrameChunkSize, 'x');
299 scoped_ptr<SpdyFrame> chunk(
300 ConstructSpdyBodyFrame(
301 1, chunk_data.data(), chunk_data.length(), false));
[email protected]528b3452013-05-25 01:28:54302 scoped_ptr<SpdyFrame> last_chunk(
303 ConstructSpdyBodyFrame(
304 1, chunk_data.data(), chunk_data.length(), true));
[email protected]aa19cfc2013-05-23 16:41:38305 MockWrite writes[] = {
306 CreateMockWrite(*req, 0),
307 CreateMockWrite(*chunk, 1),
308 CreateMockWrite(*chunk, 2),
[email protected]528b3452013-05-25 01:28:54309 CreateMockWrite(*last_chunk, 3),
[email protected]aa19cfc2013-05-23 16:41:38310 };
311
312 scoped_ptr<SpdyFrame> resp(ConstructSpdyPostSynReply(NULL, 0));
313 MockRead reads[] = {
314 CreateMockRead(*resp, 4),
315 MockRead(ASYNC, 0, 0, 5), // EOF
316 };
317
318 OrderedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
319 MockConnect connect_data(SYNCHRONOUS, OK);
320 data.set_connect_data(connect_data);
321
322 session_deps_.socket_factory->AddSocketDataProvider(&data);
323
324 scoped_refptr<SpdySession> session(CreateSpdySession());
325
326 InitializeSpdySession(session, host_port_pair_);
327
328 base::WeakPtr<SpdyStream> stream =
329 CreateStreamSynchronously(session, url, LOWEST, BoundNetLog());
330 ASSERT_TRUE(stream.get() != NULL);
331
332 std::string body_data(3 * kMaxSpdyFrameChunkSize, 'x');
333 StreamDelegateWithBody delegate(stream, body_data);
334 stream->SetDelegate(&delegate);
335
336 EXPECT_FALSE(stream->HasUrl());
337
[email protected]ee7c40d12013-05-24 21:13:10338 scoped_ptr<SpdyHeaderBlock> headers(
[email protected]aa19cfc2013-05-23 16:41:38339 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
[email protected]528b3452013-05-25 01:28:54340 EXPECT_EQ(ERR_IO_PENDING,
341 stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
[email protected]aa19cfc2013-05-23 16:41:38342 EXPECT_TRUE(stream->HasUrl());
343 EXPECT_EQ(kStreamUrl, stream->GetUrl().spec());
344
[email protected]aa19cfc2013-05-23 16:41:38345 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
346
347 EXPECT_TRUE(delegate.send_headers_completed());
348 EXPECT_EQ("200", delegate.GetResponseHeaderValue(":status"));
349 EXPECT_EQ("HTTP/1.1", delegate.GetResponseHeaderValue(":version"));
350 EXPECT_EQ(std::string(), delegate.TakeReceivedData());
351 EXPECT_TRUE(data.at_write_eof());
352}
353
354// Make sure that large blocks of data are properly split up into
355// frame-sized chunks for a bidirectional (i.e., non-HTTP-like)
356// stream.
357TEST_F(SpdyStreamSpdy3Test, SendLargeDataAfterOpenBidirectional) {
358 GURL url(kStreamUrl);
359
360 session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_);
361
362 scoped_ptr<SpdyFrame> req(
363 ConstructSpdyPost(kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0));
364 std::string chunk_data(kMaxSpdyFrameChunkSize, 'x');
365 scoped_ptr<SpdyFrame> chunk(
366 ConstructSpdyBodyFrame(
367 1, chunk_data.data(), chunk_data.length(), false));
368 MockWrite writes[] = {
369 CreateMockWrite(*req, 0),
370 CreateMockWrite(*chunk, 2),
371 CreateMockWrite(*chunk, 3),
372 CreateMockWrite(*chunk, 4),
373 };
374
375 scoped_ptr<SpdyFrame> resp(ConstructSpdyPostSynReply(NULL, 0));
376 MockRead reads[] = {
377 CreateMockRead(*resp, 1),
378 MockRead(ASYNC, 0, 0, 5), // EOF
379 };
380
381 OrderedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
382 MockConnect connect_data(SYNCHRONOUS, OK);
383 data.set_connect_data(connect_data);
384
385 session_deps_.socket_factory->AddSocketDataProvider(&data);
386
387 scoped_refptr<SpdySession> session(CreateSpdySession());
388
389 InitializeSpdySession(session, host_port_pair_);
390
391 base::WeakPtr<SpdyStream> stream =
392 CreateStreamSynchronously(session, url, LOWEST, BoundNetLog());
393 ASSERT_TRUE(stream.get() != NULL);
394
395 std::string body_data(3 * kMaxSpdyFrameChunkSize, 'x');
[email protected]194cfcf2013-05-23 21:44:44396 StreamDelegateSendImmediate delegate(stream, body_data);
[email protected]aa19cfc2013-05-23 16:41:38397 stream->SetDelegate(&delegate);
398
399 EXPECT_FALSE(stream->HasUrl());
400
[email protected]ee7c40d12013-05-24 21:13:10401 scoped_ptr<SpdyHeaderBlock> headers(
[email protected]aa19cfc2013-05-23 16:41:38402 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
[email protected]528b3452013-05-25 01:28:54403 EXPECT_EQ(ERR_IO_PENDING,
404 stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
[email protected]aa19cfc2013-05-23 16:41:38405 EXPECT_TRUE(stream->HasUrl());
406 EXPECT_EQ(kStreamUrl, stream->GetUrl().spec());
407
[email protected]aa19cfc2013-05-23 16:41:38408 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
409
410 EXPECT_TRUE(delegate.send_headers_completed());
411 EXPECT_EQ("200", delegate.GetResponseHeaderValue(":status"));
412 EXPECT_EQ("HTTP/1.1", delegate.GetResponseHeaderValue(":version"));
413 EXPECT_EQ(std::string(), delegate.TakeReceivedData());
414 EXPECT_TRUE(data.at_write_eof());
415}
416
[email protected]1e5ebd82013-02-20 20:07:24417// Call IncreaseSendWindowSize on a stream with a large enough delta
418// to overflow an int32. The SpdyStream should handle that case
419// gracefully.
420TEST_F(SpdyStreamSpdy3Test, IncreaseSendWindowSizeOverflow) {
[email protected]1c12c062013-05-14 23:13:48421 session_ =
422 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
[email protected]1e5ebd82013-02-20 20:07:24423
424 MockRead reads[] = {
[email protected]1c12c062013-05-14 23:13:48425 MockRead(ASYNC, 0, 2), // EOF
[email protected]1e5ebd82013-02-20 20:07:24426 };
427
[email protected]1c12c062013-05-14 23:13:48428 scoped_ptr<SpdyFrame> req(
429 ConstructSpdyPost(kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0));
[email protected]1e5ebd82013-02-20 20:07:24430 // Triggered by the overflowing call to IncreaseSendWindowSize
431 // below.
432 scoped_ptr<SpdyFrame> rst(
[email protected]c10b20852013-05-15 21:29:20433 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_FLOW_CONTROL_ERROR));
[email protected]1e5ebd82013-02-20 20:07:24434 MockWrite writes[] = {
[email protected]1c12c062013-05-14 23:13:48435 CreateMockWrite(*req, 0),
436 CreateMockWrite(*rst, 1),
[email protected]1e5ebd82013-02-20 20:07:24437 };
[email protected]1e5ebd82013-02-20 20:07:24438
439 CapturingBoundNetLog log;
440
[email protected]1c12c062013-05-14 23:13:48441 DeterministicSocketData data(
442 reads, arraysize(reads), writes, arraysize(writes));
[email protected]1e5ebd82013-02-20 20:07:24443 MockConnect connect_data(SYNCHRONOUS, OK);
444 data.set_connect_data(connect_data);
445
[email protected]1c12c062013-05-14 23:13:48446 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
[email protected]1e5ebd82013-02-20 20:07:24447
448 scoped_refptr<SpdySession> session(CreateSpdySession());
[email protected]1e5ebd82013-02-20 20:07:24449 GURL url(kStreamUrl);
450
[email protected]34a4dea2013-03-13 00:42:30451 InitializeSpdySession(session, host_port_pair_);
[email protected]1e5ebd82013-02-20 20:07:24452
[email protected]d26ff352013-05-13 08:48:28453 base::WeakPtr<SpdyStream> stream =
[email protected]e3861ca2013-03-02 01:00:45454 CreateStreamSynchronously(session, url, LOWEST, log.bound());
455 ASSERT_TRUE(stream.get() != NULL);
[email protected]194cfcf2013-05-23 21:44:44456 StreamDelegateSendImmediate delegate(stream, kPostBodyStringPiece);
[email protected]1c6b12a2013-03-21 00:59:11457 stream->SetDelegate(&delegate);
[email protected]1e5ebd82013-02-20 20:07:24458
[email protected]ee7c40d12013-05-24 21:13:10459 scoped_ptr<SpdyHeaderBlock> headers(
[email protected]1c12c062013-05-14 23:13:48460 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
[email protected]528b3452013-05-25 01:28:54461 EXPECT_EQ(ERR_IO_PENDING,
462 stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
[email protected]1c12c062013-05-14 23:13:48463 EXPECT_TRUE(stream->HasUrl());
464 EXPECT_EQ(kStreamUrl, stream->GetUrl().spec());
465
[email protected]1c12c062013-05-14 23:13:48466 data.RunFor(1);
[email protected]1e5ebd82013-02-20 20:07:24467
468 int32 old_send_window_size = stream->send_window_size();
469 ASSERT_GT(old_send_window_size, 0);
470 int32 delta_window_size = kint32max - old_send_window_size + 1;
471 stream->IncreaseSendWindowSize(delta_window_size);
[email protected]1c12c062013-05-14 23:13:48472 EXPECT_EQ(NULL, stream.get());
[email protected]1e5ebd82013-02-20 20:07:24473
[email protected]1c12c062013-05-14 23:13:48474 data.RunFor(2);
475
476 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, delegate.WaitForClose());
[email protected]1e5ebd82013-02-20 20:07:24477}
478
[email protected]d2de7da2013-05-22 07:49:56479// Functions used with
480// RunResumeAfterUnstall{RequestResponse,Bidirectional}Test().
481
482void StallStream(const base::WeakPtr<SpdyStream>& stream) {
483 // Reduce the send window size to 0 to stall.
484 while (stream->send_window_size() > 0) {
485 stream->DecreaseSendWindowSize(
486 std::min(kMaxSpdyFrameChunkSize, stream->send_window_size()));
487 }
488}
489
490void IncreaseStreamSendWindowSize(const base::WeakPtr<SpdyStream>& stream,
491 int32 delta_window_size) {
492 EXPECT_TRUE(stream->send_stalled_by_flow_control());
493 stream->IncreaseSendWindowSize(delta_window_size);
494 EXPECT_FALSE(stream->send_stalled_by_flow_control());
495}
496
497void AdjustStreamSendWindowSize(const base::WeakPtr<SpdyStream>& stream,
498 int32 delta_window_size) {
499 // Make sure that negative adjustments are handled properly.
500 EXPECT_TRUE(stream->send_stalled_by_flow_control());
501 stream->AdjustSendWindowSize(-delta_window_size);
502 EXPECT_TRUE(stream->send_stalled_by_flow_control());
503 stream->AdjustSendWindowSize(+delta_window_size);
504 EXPECT_TRUE(stream->send_stalled_by_flow_control());
505 stream->AdjustSendWindowSize(+delta_window_size);
506 EXPECT_FALSE(stream->send_stalled_by_flow_control());
507}
508
509// Given an unstall function, runs a test to make sure that a
510// request/response (i.e., an HTTP-like) stream resumes after a stall
511// and unstall.
512void SpdyStreamSpdy3Test::RunResumeAfterUnstallRequestResponseTest(
513 const UnstallFunction& unstall_function) {
[email protected]34a4dea2013-03-13 00:42:30514 GURL url(kStreamUrl);
515
[email protected]34a4dea2013-03-13 00:42:30516 session_ =
517 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
518
[email protected]cbdd73162013-03-18 23:27:33519 scoped_ptr<SpdyFrame> req(
520 ConstructSpdyPost(kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0));
[email protected]d2de7da2013-05-22 07:49:56521 scoped_ptr<SpdyFrame> body(
[email protected]528b3452013-05-25 01:28:54522 ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, true));
[email protected]34a4dea2013-03-13 00:42:30523 MockWrite writes[] = {
524 CreateMockWrite(*req, 0),
[email protected]d2de7da2013-05-22 07:49:56525 CreateMockWrite(*body, 1),
[email protected]34a4dea2013-03-13 00:42:30526 };
527
528 scoped_ptr<SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1));
[email protected]34a4dea2013-03-13 00:42:30529 MockRead reads[] = {
[email protected]d2de7da2013-05-22 07:49:56530 CreateMockRead(*resp, 2),
531 MockRead(ASYNC, 0, 0, 3), // EOF
[email protected]34a4dea2013-03-13 00:42:30532 };
533
534 DeterministicSocketData data(reads, arraysize(reads),
535 writes, arraysize(writes));
536 MockConnect connect_data(SYNCHRONOUS, OK);
537 data.set_connect_data(connect_data);
538
539 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
540
541 scoped_refptr<SpdySession> session(CreateSpdySession());
[email protected]34a4dea2013-03-13 00:42:30542
543 InitializeSpdySession(session, host_port_pair_);
544
[email protected]d26ff352013-05-13 08:48:28545 base::WeakPtr<SpdyStream> stream =
[email protected]34a4dea2013-03-13 00:42:30546 CreateStreamSynchronously(session, url, LOWEST, BoundNetLog());
547 ASSERT_TRUE(stream.get() != NULL);
[email protected]34a4dea2013-03-13 00:42:30548
[email protected]d26ff352013-05-13 08:48:28549 StreamDelegateWithBody delegate(stream, kPostBodyStringPiece);
[email protected]34a4dea2013-03-13 00:42:30550 stream->SetDelegate(&delegate);
551
552 EXPECT_FALSE(stream->HasUrl());
[email protected]1c6b12a2013-03-21 00:59:11553 EXPECT_FALSE(stream->send_stalled_by_flow_control());
[email protected]34a4dea2013-03-13 00:42:30554
[email protected]ee7c40d12013-05-24 21:13:10555 scoped_ptr<SpdyHeaderBlock> headers(
556 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
[email protected]528b3452013-05-25 01:28:54557 EXPECT_EQ(ERR_IO_PENDING,
558 stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
[email protected]ee7c40d12013-05-24 21:13:10559 EXPECT_TRUE(stream->HasUrl());
560 EXPECT_EQ(kStreamUrl, stream->GetUrl().spec());
[email protected]34a4dea2013-03-13 00:42:30561
[email protected]d2de7da2013-05-22 07:49:56562 StallStream(stream);
563
564 data.RunFor(1);
[email protected]34a4dea2013-03-13 00:42:30565
[email protected]1c6b12a2013-03-21 00:59:11566 EXPECT_TRUE(stream->send_stalled_by_flow_control());
[email protected]34a4dea2013-03-13 00:42:30567
[email protected]d2de7da2013-05-22 07:49:56568 unstall_function.Run(stream, kPostBodyLength);
[email protected]34a4dea2013-03-13 00:42:30569
[email protected]1c6b12a2013-03-21 00:59:11570 EXPECT_FALSE(stream->send_stalled_by_flow_control());
[email protected]34a4dea2013-03-13 00:42:30571
572 data.RunFor(3);
573
574 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
575
576 EXPECT_TRUE(delegate.send_headers_completed());
577 EXPECT_EQ("200", delegate.GetResponseHeaderValue(":status"));
578 EXPECT_EQ("HTTP/1.1", delegate.GetResponseHeaderValue(":version"));
[email protected]d2de7da2013-05-22 07:49:56579 EXPECT_EQ(std::string(), delegate.TakeReceivedData());
[email protected]aa19cfc2013-05-23 16:41:38580 EXPECT_TRUE(data.at_write_eof());
[email protected]cbdd73162013-03-18 23:27:33581}
582
[email protected]d2de7da2013-05-22 07:49:56583TEST_F(SpdyStreamSpdy3Test, ResumeAfterSendWindowSizeIncreaseRequestResponse) {
584 RunResumeAfterUnstallRequestResponseTest(
585 base::Bind(&IncreaseStreamSendWindowSize));
586}
587
588TEST_F(SpdyStreamSpdy3Test, ResumeAfterSendWindowSizeAdjustRequestResponse) {
589 RunResumeAfterUnstallRequestResponseTest(
590 base::Bind(&AdjustStreamSendWindowSize));
591}
592
593// Given an unstall function, runs a test to make sure that a
[email protected]63c8cb02013-05-22 22:34:04594// bidirectional (i.e., non-HTTP-like) stream resumes after a stall
595// and unstall.
[email protected]d2de7da2013-05-22 07:49:56596void SpdyStreamSpdy3Test::RunResumeAfterUnstallBidirectionalTest(
597 const UnstallFunction& unstall_function) {
[email protected]cbdd73162013-03-18 23:27:33598 GURL url(kStreamUrl);
599
600 session_ =
601 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
602
603 scoped_ptr<SpdyFrame> req(
604 ConstructSpdyPost(kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0));
605 scoped_ptr<SpdyFrame> msg(
606 ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false));
607 MockWrite writes[] = {
608 CreateMockWrite(*req, 0),
609 CreateMockWrite(*msg, 2),
610 };
611
612 scoped_ptr<SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1));
613 scoped_ptr<SpdyFrame> echo(
614 ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false));
615 MockRead reads[] = {
616 CreateMockRead(*resp, 1),
617 CreateMockRead(*echo, 3),
618 MockRead(ASYNC, 0, 0, 4), // EOF
619 };
620
621 DeterministicSocketData data(reads, arraysize(reads),
622 writes, arraysize(writes));
623 MockConnect connect_data(SYNCHRONOUS, OK);
624 data.set_connect_data(connect_data);
625
626 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
627
628 scoped_refptr<SpdySession> session(CreateSpdySession());
629
630 InitializeSpdySession(session, host_port_pair_);
631
[email protected]d26ff352013-05-13 08:48:28632 base::WeakPtr<SpdyStream> stream =
[email protected]cbdd73162013-03-18 23:27:33633 CreateStreamSynchronously(session, url, LOWEST, BoundNetLog());
634 ASSERT_TRUE(stream.get() != NULL);
[email protected]cbdd73162013-03-18 23:27:33635
[email protected]194cfcf2013-05-23 21:44:44636 StreamDelegateSendImmediate delegate(stream, kPostBodyStringPiece);
[email protected]cbdd73162013-03-18 23:27:33637 stream->SetDelegate(&delegate);
638
639 EXPECT_FALSE(stream->HasUrl());
640
[email protected]ee7c40d12013-05-24 21:13:10641 scoped_ptr<SpdyHeaderBlock> headers(
[email protected]a4a67772013-05-08 22:56:07642 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
[email protected]528b3452013-05-25 01:28:54643 EXPECT_EQ(ERR_IO_PENDING,
644 stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
[email protected]cbdd73162013-03-18 23:27:33645 EXPECT_TRUE(stream->HasUrl());
646 EXPECT_EQ(kStreamUrl, stream->GetUrl().spec());
647
[email protected]d2de7da2013-05-22 07:49:56648 data.RunFor(1);
[email protected]cbdd73162013-03-18 23:27:33649
[email protected]1c6b12a2013-03-21 00:59:11650 EXPECT_FALSE(stream->send_stalled_by_flow_control());
[email protected]cbdd73162013-03-18 23:27:33651
[email protected]d2de7da2013-05-22 07:49:56652 StallStream(stream);
[email protected]cbdd73162013-03-18 23:27:33653
[email protected]d2de7da2013-05-22 07:49:56654 data.RunFor(1);
[email protected]cbdd73162013-03-18 23:27:33655
[email protected]1c6b12a2013-03-21 00:59:11656 EXPECT_TRUE(stream->send_stalled_by_flow_control());
[email protected]cbdd73162013-03-18 23:27:33657
[email protected]d2de7da2013-05-22 07:49:56658 unstall_function.Run(stream, kPostBodyLength);
[email protected]cbdd73162013-03-18 23:27:33659
[email protected]1c6b12a2013-03-21 00:59:11660 EXPECT_FALSE(stream->send_stalled_by_flow_control());
[email protected]cbdd73162013-03-18 23:27:33661
662 data.RunFor(3);
663
664 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
665
666 EXPECT_TRUE(delegate.send_headers_completed());
667 EXPECT_EQ("200", delegate.GetResponseHeaderValue(":status"));
668 EXPECT_EQ("HTTP/1.1", delegate.GetResponseHeaderValue(":version"));
[email protected]09a8d9172013-04-17 19:23:49669 EXPECT_EQ(std::string(kPostBody, kPostBodyLength),
670 delegate.TakeReceivedData());
[email protected]aa19cfc2013-05-23 16:41:38671 EXPECT_TRUE(data.at_write_eof());
[email protected]d2de7da2013-05-22 07:49:56672}
673
[email protected]aa19cfc2013-05-23 16:41:38674TEST_F(SpdyStreamSpdy3Test, ResumeAfterSendWindowSizeIncreaseBidirectional) {
[email protected]d2de7da2013-05-22 07:49:56675 RunResumeAfterUnstallBidirectionalTest(
676 base::Bind(&IncreaseStreamSendWindowSize));
677}
678
[email protected]aa19cfc2013-05-23 16:41:38679TEST_F(SpdyStreamSpdy3Test, ResumeAfterSendWindowSizeAdjustBidirectional) {
[email protected]d2de7da2013-05-22 07:49:56680 RunResumeAfterUnstallBidirectionalTest(
681 base::Bind(&AdjustStreamSendWindowSize));
[email protected]34a4dea2013-03-13 00:42:30682}
683
684} // namespace
685
[email protected]39d13d942012-07-19 16:48:20686} // namespace test
687
[email protected]4f386422010-07-20 04:19:49688} // namespace net