blob: d7bd627143f377a90c851f2f9f868941c4c0538e [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]cbdd73162013-03-18 23:27:33138 stream->set_spdy_headers(
[email protected]a4a67772013-05-08 22:56:07139 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
[email protected]a7a265ef2010-12-08 18:05:57140 EXPECT_TRUE(stream->HasUrl());
141 EXPECT_EQ(kStreamUrl, stream->GetUrl().spec());
[email protected]4f386422010-07-20 04:19:49142
[email protected]a5c493b92010-08-06 23:04:29143 EXPECT_EQ(ERR_IO_PENDING, stream->SendRequest(true));
[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]cbdd73162013-03-18 23:27:33254 stream->set_spdy_headers(
[email protected]a4a67772013-05-08 22:56:07255 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
[email protected]d245c342012-02-23 20:49:15256 EXPECT_TRUE(stream->HasUrl());
257 EXPECT_EQ(kStreamUrl, stream->GetUrl().spec());
258
259 EXPECT_EQ(ERR_IO_PENDING, stream->SendRequest(true));
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));
302 MockWrite writes[] = {
303 CreateMockWrite(*req, 0),
304 CreateMockWrite(*chunk, 1),
305 CreateMockWrite(*chunk, 2),
306 CreateMockWrite(*chunk, 3),
307 };
308
309 scoped_ptr<SpdyFrame> resp(ConstructSpdyPostSynReply(NULL, 0));
310 MockRead reads[] = {
311 CreateMockRead(*resp, 4),
312 MockRead(ASYNC, 0, 0, 5), // EOF
313 };
314
315 OrderedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
316 MockConnect connect_data(SYNCHRONOUS, OK);
317 data.set_connect_data(connect_data);
318
319 session_deps_.socket_factory->AddSocketDataProvider(&data);
320
321 scoped_refptr<SpdySession> session(CreateSpdySession());
322
323 InitializeSpdySession(session, host_port_pair_);
324
325 base::WeakPtr<SpdyStream> stream =
326 CreateStreamSynchronously(session, url, LOWEST, BoundNetLog());
327 ASSERT_TRUE(stream.get() != NULL);
328
329 std::string body_data(3 * kMaxSpdyFrameChunkSize, 'x');
330 StreamDelegateWithBody delegate(stream, body_data);
331 stream->SetDelegate(&delegate);
332
333 EXPECT_FALSE(stream->HasUrl());
334
335 stream->set_spdy_headers(
336 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
337 EXPECT_TRUE(stream->HasUrl());
338 EXPECT_EQ(kStreamUrl, stream->GetUrl().spec());
339
340 EXPECT_EQ(ERR_IO_PENDING, stream->SendRequest(true));
341
342 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
343
344 EXPECT_TRUE(delegate.send_headers_completed());
345 EXPECT_EQ("200", delegate.GetResponseHeaderValue(":status"));
346 EXPECT_EQ("HTTP/1.1", delegate.GetResponseHeaderValue(":version"));
347 EXPECT_EQ(std::string(), delegate.TakeReceivedData());
348 EXPECT_TRUE(data.at_write_eof());
349}
350
351// Make sure that large blocks of data are properly split up into
352// frame-sized chunks for a bidirectional (i.e., non-HTTP-like)
353// stream.
354TEST_F(SpdyStreamSpdy3Test, SendLargeDataAfterOpenBidirectional) {
355 GURL url(kStreamUrl);
356
357 session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_);
358
359 scoped_ptr<SpdyFrame> req(
360 ConstructSpdyPost(kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0));
361 std::string chunk_data(kMaxSpdyFrameChunkSize, 'x');
362 scoped_ptr<SpdyFrame> chunk(
363 ConstructSpdyBodyFrame(
364 1, chunk_data.data(), chunk_data.length(), false));
365 MockWrite writes[] = {
366 CreateMockWrite(*req, 0),
367 CreateMockWrite(*chunk, 2),
368 CreateMockWrite(*chunk, 3),
369 CreateMockWrite(*chunk, 4),
370 };
371
372 scoped_ptr<SpdyFrame> resp(ConstructSpdyPostSynReply(NULL, 0));
373 MockRead reads[] = {
374 CreateMockRead(*resp, 1),
375 MockRead(ASYNC, 0, 0, 5), // EOF
376 };
377
378 OrderedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
379 MockConnect connect_data(SYNCHRONOUS, OK);
380 data.set_connect_data(connect_data);
381
382 session_deps_.socket_factory->AddSocketDataProvider(&data);
383
384 scoped_refptr<SpdySession> session(CreateSpdySession());
385
386 InitializeSpdySession(session, host_port_pair_);
387
388 base::WeakPtr<SpdyStream> stream =
389 CreateStreamSynchronously(session, url, LOWEST, BoundNetLog());
390 ASSERT_TRUE(stream.get() != NULL);
391
392 std::string body_data(3 * kMaxSpdyFrameChunkSize, 'x');
[email protected]194cfcf2013-05-23 21:44:44393 StreamDelegateSendImmediate delegate(stream, body_data);
[email protected]aa19cfc2013-05-23 16:41:38394 stream->SetDelegate(&delegate);
395
396 EXPECT_FALSE(stream->HasUrl());
397
398 stream->set_spdy_headers(
399 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
400 EXPECT_TRUE(stream->HasUrl());
401 EXPECT_EQ(kStreamUrl, stream->GetUrl().spec());
402
403 EXPECT_EQ(ERR_IO_PENDING, stream->SendRequest(true));
404
405 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
406
407 EXPECT_TRUE(delegate.send_headers_completed());
408 EXPECT_EQ("200", delegate.GetResponseHeaderValue(":status"));
409 EXPECT_EQ("HTTP/1.1", delegate.GetResponseHeaderValue(":version"));
410 EXPECT_EQ(std::string(), delegate.TakeReceivedData());
411 EXPECT_TRUE(data.at_write_eof());
412}
413
[email protected]1e5ebd82013-02-20 20:07:24414// Call IncreaseSendWindowSize on a stream with a large enough delta
415// to overflow an int32. The SpdyStream should handle that case
416// gracefully.
417TEST_F(SpdyStreamSpdy3Test, IncreaseSendWindowSizeOverflow) {
[email protected]1c12c062013-05-14 23:13:48418 session_ =
419 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
[email protected]1e5ebd82013-02-20 20:07:24420
421 MockRead reads[] = {
[email protected]1c12c062013-05-14 23:13:48422 MockRead(ASYNC, 0, 2), // EOF
[email protected]1e5ebd82013-02-20 20:07:24423 };
424
[email protected]1c12c062013-05-14 23:13:48425 scoped_ptr<SpdyFrame> req(
426 ConstructSpdyPost(kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0));
[email protected]1e5ebd82013-02-20 20:07:24427 // Triggered by the overflowing call to IncreaseSendWindowSize
428 // below.
429 scoped_ptr<SpdyFrame> rst(
[email protected]c10b20852013-05-15 21:29:20430 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_FLOW_CONTROL_ERROR));
[email protected]1e5ebd82013-02-20 20:07:24431 MockWrite writes[] = {
[email protected]1c12c062013-05-14 23:13:48432 CreateMockWrite(*req, 0),
433 CreateMockWrite(*rst, 1),
[email protected]1e5ebd82013-02-20 20:07:24434 };
[email protected]1e5ebd82013-02-20 20:07:24435
436 CapturingBoundNetLog log;
437
[email protected]1c12c062013-05-14 23:13:48438 DeterministicSocketData data(
439 reads, arraysize(reads), writes, arraysize(writes));
[email protected]1e5ebd82013-02-20 20:07:24440 MockConnect connect_data(SYNCHRONOUS, OK);
441 data.set_connect_data(connect_data);
442
[email protected]1c12c062013-05-14 23:13:48443 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
[email protected]1e5ebd82013-02-20 20:07:24444
445 scoped_refptr<SpdySession> session(CreateSpdySession());
[email protected]1e5ebd82013-02-20 20:07:24446 GURL url(kStreamUrl);
447
[email protected]34a4dea2013-03-13 00:42:30448 InitializeSpdySession(session, host_port_pair_);
[email protected]1e5ebd82013-02-20 20:07:24449
[email protected]d26ff352013-05-13 08:48:28450 base::WeakPtr<SpdyStream> stream =
[email protected]e3861ca2013-03-02 01:00:45451 CreateStreamSynchronously(session, url, LOWEST, log.bound());
452 ASSERT_TRUE(stream.get() != NULL);
[email protected]194cfcf2013-05-23 21:44:44453 StreamDelegateSendImmediate delegate(stream, kPostBodyStringPiece);
[email protected]1c6b12a2013-03-21 00:59:11454 stream->SetDelegate(&delegate);
[email protected]1e5ebd82013-02-20 20:07:24455
[email protected]1c12c062013-05-14 23:13:48456 stream->set_spdy_headers(
457 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
458 EXPECT_TRUE(stream->HasUrl());
459 EXPECT_EQ(kStreamUrl, stream->GetUrl().spec());
460
461 EXPECT_EQ(ERR_IO_PENDING, stream->SendRequest(true));
462
463 data.RunFor(1);
[email protected]1e5ebd82013-02-20 20:07:24464
465 int32 old_send_window_size = stream->send_window_size();
466 ASSERT_GT(old_send_window_size, 0);
467 int32 delta_window_size = kint32max - old_send_window_size + 1;
468 stream->IncreaseSendWindowSize(delta_window_size);
[email protected]1c12c062013-05-14 23:13:48469 EXPECT_EQ(NULL, stream.get());
[email protected]1e5ebd82013-02-20 20:07:24470
[email protected]1c12c062013-05-14 23:13:48471 data.RunFor(2);
472
473 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, delegate.WaitForClose());
[email protected]1e5ebd82013-02-20 20:07:24474}
475
[email protected]d2de7da2013-05-22 07:49:56476// Functions used with
477// RunResumeAfterUnstall{RequestResponse,Bidirectional}Test().
478
479void StallStream(const base::WeakPtr<SpdyStream>& stream) {
480 // Reduce the send window size to 0 to stall.
481 while (stream->send_window_size() > 0) {
482 stream->DecreaseSendWindowSize(
483 std::min(kMaxSpdyFrameChunkSize, stream->send_window_size()));
484 }
485}
486
487void IncreaseStreamSendWindowSize(const base::WeakPtr<SpdyStream>& stream,
488 int32 delta_window_size) {
489 EXPECT_TRUE(stream->send_stalled_by_flow_control());
490 stream->IncreaseSendWindowSize(delta_window_size);
491 EXPECT_FALSE(stream->send_stalled_by_flow_control());
492}
493
494void AdjustStreamSendWindowSize(const base::WeakPtr<SpdyStream>& stream,
495 int32 delta_window_size) {
496 // Make sure that negative adjustments are handled properly.
497 EXPECT_TRUE(stream->send_stalled_by_flow_control());
498 stream->AdjustSendWindowSize(-delta_window_size);
499 EXPECT_TRUE(stream->send_stalled_by_flow_control());
500 stream->AdjustSendWindowSize(+delta_window_size);
501 EXPECT_TRUE(stream->send_stalled_by_flow_control());
502 stream->AdjustSendWindowSize(+delta_window_size);
503 EXPECT_FALSE(stream->send_stalled_by_flow_control());
504}
505
506// Given an unstall function, runs a test to make sure that a
507// request/response (i.e., an HTTP-like) stream resumes after a stall
508// and unstall.
509void SpdyStreamSpdy3Test::RunResumeAfterUnstallRequestResponseTest(
510 const UnstallFunction& unstall_function) {
[email protected]34a4dea2013-03-13 00:42:30511 GURL url(kStreamUrl);
512
[email protected]34a4dea2013-03-13 00:42:30513 session_ =
514 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
515
[email protected]cbdd73162013-03-18 23:27:33516 scoped_ptr<SpdyFrame> req(
517 ConstructSpdyPost(kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0));
[email protected]d2de7da2013-05-22 07:49:56518 scoped_ptr<SpdyFrame> body(
[email protected]cbdd73162013-03-18 23:27:33519 ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false));
[email protected]34a4dea2013-03-13 00:42:30520 MockWrite writes[] = {
521 CreateMockWrite(*req, 0),
[email protected]d2de7da2013-05-22 07:49:56522 CreateMockWrite(*body, 1),
[email protected]34a4dea2013-03-13 00:42:30523 };
524
525 scoped_ptr<SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1));
[email protected]34a4dea2013-03-13 00:42:30526 MockRead reads[] = {
[email protected]d2de7da2013-05-22 07:49:56527 CreateMockRead(*resp, 2),
528 MockRead(ASYNC, 0, 0, 3), // EOF
[email protected]34a4dea2013-03-13 00:42:30529 };
530
531 DeterministicSocketData data(reads, arraysize(reads),
532 writes, arraysize(writes));
533 MockConnect connect_data(SYNCHRONOUS, OK);
534 data.set_connect_data(connect_data);
535
536 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
537
538 scoped_refptr<SpdySession> session(CreateSpdySession());
[email protected]34a4dea2013-03-13 00:42:30539
540 InitializeSpdySession(session, host_port_pair_);
541
[email protected]d26ff352013-05-13 08:48:28542 base::WeakPtr<SpdyStream> stream =
[email protected]34a4dea2013-03-13 00:42:30543 CreateStreamSynchronously(session, url, LOWEST, BoundNetLog());
544 ASSERT_TRUE(stream.get() != NULL);
[email protected]34a4dea2013-03-13 00:42:30545
[email protected]d26ff352013-05-13 08:48:28546 StreamDelegateWithBody delegate(stream, kPostBodyStringPiece);
[email protected]34a4dea2013-03-13 00:42:30547 stream->SetDelegate(&delegate);
548
549 EXPECT_FALSE(stream->HasUrl());
550
[email protected]cbdd73162013-03-18 23:27:33551 stream->set_spdy_headers(
[email protected]a4a67772013-05-08 22:56:07552 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
[email protected]34a4dea2013-03-13 00:42:30553 EXPECT_TRUE(stream->HasUrl());
554 EXPECT_EQ(kStreamUrl, stream->GetUrl().spec());
555
[email protected]1c6b12a2013-03-21 00:59:11556 EXPECT_FALSE(stream->send_stalled_by_flow_control());
[email protected]34a4dea2013-03-13 00:42:30557
[email protected]d2de7da2013-05-22 07:49:56558 EXPECT_EQ(ERR_IO_PENDING, stream->SendRequest(true));
[email protected]34a4dea2013-03-13 00:42:30559
[email protected]d2de7da2013-05-22 07:49:56560 StallStream(stream);
561
562 data.RunFor(1);
[email protected]34a4dea2013-03-13 00:42:30563
[email protected]1c6b12a2013-03-21 00:59:11564 EXPECT_TRUE(stream->send_stalled_by_flow_control());
[email protected]34a4dea2013-03-13 00:42:30565
[email protected]d2de7da2013-05-22 07:49:56566 unstall_function.Run(stream, kPostBodyLength);
[email protected]34a4dea2013-03-13 00:42:30567
[email protected]1c6b12a2013-03-21 00:59:11568 EXPECT_FALSE(stream->send_stalled_by_flow_control());
[email protected]34a4dea2013-03-13 00:42:30569
570 data.RunFor(3);
571
572 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
573
574 EXPECT_TRUE(delegate.send_headers_completed());
575 EXPECT_EQ("200", delegate.GetResponseHeaderValue(":status"));
576 EXPECT_EQ("HTTP/1.1", delegate.GetResponseHeaderValue(":version"));
[email protected]d2de7da2013-05-22 07:49:56577 EXPECT_EQ(std::string(), delegate.TakeReceivedData());
[email protected]aa19cfc2013-05-23 16:41:38578 EXPECT_TRUE(data.at_write_eof());
[email protected]cbdd73162013-03-18 23:27:33579}
580
[email protected]d2de7da2013-05-22 07:49:56581TEST_F(SpdyStreamSpdy3Test, ResumeAfterSendWindowSizeIncreaseRequestResponse) {
582 RunResumeAfterUnstallRequestResponseTest(
583 base::Bind(&IncreaseStreamSendWindowSize));
584}
585
586TEST_F(SpdyStreamSpdy3Test, ResumeAfterSendWindowSizeAdjustRequestResponse) {
587 RunResumeAfterUnstallRequestResponseTest(
588 base::Bind(&AdjustStreamSendWindowSize));
589}
590
591// Given an unstall function, runs a test to make sure that a
[email protected]63c8cb02013-05-22 22:34:04592// bidirectional (i.e., non-HTTP-like) stream resumes after a stall
593// and unstall.
[email protected]d2de7da2013-05-22 07:49:56594void SpdyStreamSpdy3Test::RunResumeAfterUnstallBidirectionalTest(
595 const UnstallFunction& unstall_function) {
[email protected]cbdd73162013-03-18 23:27:33596 GURL url(kStreamUrl);
597
598 session_ =
599 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
600
601 scoped_ptr<SpdyFrame> req(
602 ConstructSpdyPost(kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0));
603 scoped_ptr<SpdyFrame> msg(
604 ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false));
605 MockWrite writes[] = {
606 CreateMockWrite(*req, 0),
607 CreateMockWrite(*msg, 2),
608 };
609
610 scoped_ptr<SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1));
611 scoped_ptr<SpdyFrame> echo(
612 ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false));
613 MockRead reads[] = {
614 CreateMockRead(*resp, 1),
615 CreateMockRead(*echo, 3),
616 MockRead(ASYNC, 0, 0, 4), // EOF
617 };
618
619 DeterministicSocketData data(reads, arraysize(reads),
620 writes, arraysize(writes));
621 MockConnect connect_data(SYNCHRONOUS, OK);
622 data.set_connect_data(connect_data);
623
624 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
625
626 scoped_refptr<SpdySession> session(CreateSpdySession());
627
628 InitializeSpdySession(session, host_port_pair_);
629
[email protected]d26ff352013-05-13 08:48:28630 base::WeakPtr<SpdyStream> stream =
[email protected]cbdd73162013-03-18 23:27:33631 CreateStreamSynchronously(session, url, LOWEST, BoundNetLog());
632 ASSERT_TRUE(stream.get() != NULL);
[email protected]cbdd73162013-03-18 23:27:33633
[email protected]194cfcf2013-05-23 21:44:44634 StreamDelegateSendImmediate delegate(stream, kPostBodyStringPiece);
[email protected]cbdd73162013-03-18 23:27:33635 stream->SetDelegate(&delegate);
636
637 EXPECT_FALSE(stream->HasUrl());
638
639 stream->set_spdy_headers(
[email protected]a4a67772013-05-08 22:56:07640 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
[email protected]cbdd73162013-03-18 23:27:33641 EXPECT_TRUE(stream->HasUrl());
642 EXPECT_EQ(kStreamUrl, stream->GetUrl().spec());
643
644 EXPECT_EQ(ERR_IO_PENDING, stream->SendRequest(true));
645
[email protected]d2de7da2013-05-22 07:49:56646 data.RunFor(1);
[email protected]cbdd73162013-03-18 23:27:33647
[email protected]1c6b12a2013-03-21 00:59:11648 EXPECT_FALSE(stream->send_stalled_by_flow_control());
[email protected]cbdd73162013-03-18 23:27:33649
[email protected]d2de7da2013-05-22 07:49:56650 StallStream(stream);
[email protected]cbdd73162013-03-18 23:27:33651
[email protected]d2de7da2013-05-22 07:49:56652 data.RunFor(1);
[email protected]cbdd73162013-03-18 23:27:33653
[email protected]1c6b12a2013-03-21 00:59:11654 EXPECT_TRUE(stream->send_stalled_by_flow_control());
[email protected]cbdd73162013-03-18 23:27:33655
[email protected]d2de7da2013-05-22 07:49:56656 unstall_function.Run(stream, kPostBodyLength);
[email protected]cbdd73162013-03-18 23:27:33657
[email protected]1c6b12a2013-03-21 00:59:11658 EXPECT_FALSE(stream->send_stalled_by_flow_control());
[email protected]cbdd73162013-03-18 23:27:33659
660 data.RunFor(3);
661
662 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
663
664 EXPECT_TRUE(delegate.send_headers_completed());
665 EXPECT_EQ("200", delegate.GetResponseHeaderValue(":status"));
666 EXPECT_EQ("HTTP/1.1", delegate.GetResponseHeaderValue(":version"));
[email protected]09a8d9172013-04-17 19:23:49667 EXPECT_EQ(std::string(kPostBody, kPostBodyLength),
668 delegate.TakeReceivedData());
[email protected]aa19cfc2013-05-23 16:41:38669 EXPECT_TRUE(data.at_write_eof());
[email protected]d2de7da2013-05-22 07:49:56670}
671
[email protected]aa19cfc2013-05-23 16:41:38672TEST_F(SpdyStreamSpdy3Test, ResumeAfterSendWindowSizeIncreaseBidirectional) {
[email protected]d2de7da2013-05-22 07:49:56673 RunResumeAfterUnstallBidirectionalTest(
674 base::Bind(&IncreaseStreamSendWindowSize));
675}
676
[email protected]aa19cfc2013-05-23 16:41:38677TEST_F(SpdyStreamSpdy3Test, ResumeAfterSendWindowSizeAdjustBidirectional) {
[email protected]d2de7da2013-05-22 07:49:56678 RunResumeAfterUnstallBidirectionalTest(
679 base::Bind(&AdjustStreamSendWindowSize));
[email protected]34a4dea2013-03-13 00:42:30680}
681
682} // namespace
683
[email protected]39d13d942012-07-19 16:48:20684} // namespace test
685
[email protected]4f386422010-07-20 04:19:49686} // namespace net