blob: a4bd90d9b070dea7839686cffef9e4a5712a6f52 [file] [log] [blame]
[email protected]5af3c572010-07-20 14:16:271// Copyright (c) 2010 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
[email protected]aea80602009-09-18 00:55:083// found in the LICENSE file.
4
[email protected]d8ef27b2010-08-06 17:34:395#include <string>
[email protected]a33cad2b62010-07-30 22:24:396#include <vector>
7
[email protected]9e743cd2010-03-16 07:03:538#include "net/base/net_log_unittest.h"
[email protected]aea80602009-09-18 00:55:089#include "net/http/http_transaction_unittest.h"
[email protected]9be804c82010-06-24 17:59:4610#include "net/spdy/spdy_http_stream.h"
[email protected]bdebd1b2010-08-09 20:18:0811#include "net/spdy/spdy_session.h"
[email protected]2ff8b312010-04-26 22:20:5412#include "net/spdy/spdy_test_util.h"
[email protected]e3ebba0f2010-08-05 17:59:5813#include "net/url_request/url_request_unittest.h"
[email protected]aea80602009-09-18 00:55:0814#include "testing/platform_test.h"
15
16//-----------------------------------------------------------------------------
17
[email protected]d1eda932009-11-04 01:03:1018namespace net {
[email protected]dae22c52010-07-30 02:16:3519
20// This is the expected list of advertised protocols from the browser's NPN
21// list.
22static const char kExpectedNPNString[] = "\x08http/1.1\x06spdy/2";
23
[email protected]9e9e842e2010-07-23 23:09:1524enum SpdyNetworkTransactionTestTypes {
25 SPDYNPN,
26 SPDYNOSSL,
27 SPDYSSL
28};
29class SpdyNetworkTransactionTest
30 : public ::testing::TestWithParam<SpdyNetworkTransactionTestTypes> {
[email protected]34437af82009-11-06 02:28:4931 protected:
[email protected]aea80602009-09-18 00:55:0832 virtual void SetUp() {
[email protected]94d78132010-01-22 00:53:0033 // By default, all tests turn off compression.
34 EnableCompression(false);
[email protected]d3cee19d2010-06-22 18:42:1835 google_get_request_initialized_ = false;
[email protected]310240592010-08-05 21:04:1936 google_post_request_initialized_ = false;
[email protected]aea80602009-09-18 00:55:0837 }
38
39 virtual void TearDown() {
40 // Empty the current queue.
41 MessageLoop::current()->RunAllPending();
[email protected]aea80602009-09-18 00:55:0842 }
43
[email protected]72552f02009-10-28 15:25:0144 struct TransactionHelperResult {
[email protected]aea80602009-09-18 00:55:0845 int rv;
46 std::string status_line;
47 std::string response_data;
[email protected]8b070372009-11-16 22:01:2548 HttpResponseInfo response_info;
[email protected]aea80602009-09-18 00:55:0849 };
50
[email protected]94d78132010-01-22 00:53:0051 void EnableCompression(bool enabled) {
[email protected]955fc2e72010-02-08 20:37:3052 spdy::SpdyFramer::set_enable_compression_default(enabled);
[email protected]94d78132010-01-22 00:53:0053 }
54
[email protected]3caf5542010-07-16 15:19:4755 class StartTransactionCallback;
56 class DeleteSessionCallback;
[email protected]74188f22010-04-09 20:18:5057
[email protected]3caf5542010-07-16 15:19:4758 // A helper class that handles all the initial npn/ssl setup.
59 class NormalSpdyTransactionHelper {
60 public:
61 NormalSpdyTransactionHelper(const HttpRequestInfo& request,
[email protected]9e9e842e2010-07-23 23:09:1562 const BoundNetLog& log,
63 SpdyNetworkTransactionTestTypes test_type)
[email protected]30c942b2010-07-21 16:59:5964 : request_(request),
[email protected]b261d0e2010-08-02 19:13:2465 session_deps_(new SpdySessionDependencies()),
66 session_(SpdySessionDependencies::SpdyCreateSession(
67 session_deps_.get())),
[email protected]9e9e842e2010-07-23 23:09:1568 log_(log),
[email protected]3b7828432010-08-18 18:33:2769 test_type_(test_type),
70 deterministic_(false) {
[email protected]a33cad2b62010-07-30 22:24:3971 switch (test_type_) {
[email protected]9e9e842e2010-07-23 23:09:1572 case SPDYNOSSL:
73 case SPDYSSL:
74 port_ = 80;
75 break;
76 case SPDYNPN:
77 port_ = 443;
78 break;
79 default:
80 NOTREACHED();
81 }
82 }
[email protected]74188f22010-04-09 20:18:5083
[email protected]3b7828432010-08-18 18:33:2784 void SetDeterministic() {
85 session_ = SpdySessionDependencies::SpdyCreateSessionDeterministic(
86 session_deps_.get());
87 deterministic_ = true;
88 }
89
[email protected]3caf5542010-07-16 15:19:4790 void RunPreTestSetup() {
[email protected]b261d0e2010-08-02 19:13:2491 if (!session_deps_.get())
92 session_deps_.reset(new SpdySessionDependencies());
93 if (!session_.get())
94 session_ = SpdySessionDependencies::SpdyCreateSession(
95 session_deps_.get());
[email protected]9e9e842e2010-07-23 23:09:1596 HttpNetworkTransaction::SetUseAlternateProtocols(false);
97 HttpNetworkTransaction::SetUseSSLOverSpdyWithoutNPN(false);
98 HttpNetworkTransaction::SetUseSpdyWithoutNPN(false);
[email protected]a33cad2b62010-07-30 22:24:3999 switch (test_type_) {
[email protected]9e9e842e2010-07-23 23:09:15100 case SPDYNPN:
101 session_->mutable_alternate_protocols()->SetAlternateProtocolFor(
102 HostPortPair("www.google.com", 80), 443,
[email protected]dae22c52010-07-30 02:16:35103 HttpAlternateProtocols::NPN_SPDY_2);
[email protected]9e9e842e2010-07-23 23:09:15104 HttpNetworkTransaction::SetUseAlternateProtocols(true);
[email protected]dae22c52010-07-30 02:16:35105 HttpNetworkTransaction::SetNextProtos(kExpectedNPNString);
[email protected]9e9e842e2010-07-23 23:09:15106 break;
107 case SPDYNOSSL:
108 HttpNetworkTransaction::SetUseSSLOverSpdyWithoutNPN(false);
109 HttpNetworkTransaction::SetUseSpdyWithoutNPN(true);
110 break;
111 case SPDYSSL:
112 HttpNetworkTransaction::SetUseSSLOverSpdyWithoutNPN(true);
113 HttpNetworkTransaction::SetUseSpdyWithoutNPN(true);
114 break;
115 default:
116 NOTREACHED();
[email protected]3caf5542010-07-16 15:19:47117 }
[email protected]aea80602009-09-18 00:55:08118
[email protected]3caf5542010-07-16 15:19:47119 // We're now ready to use SSL-npn SPDY.
120 trans_.reset(new HttpNetworkTransaction(session_));
[email protected]cb54b3b22010-06-03 16:28:55121 }
[email protected]aea80602009-09-18 00:55:08122
[email protected]3caf5542010-07-16 15:19:47123 // Start the transaction, read some data, finish.
124 void RunDefaultTest() {
125 output_.rv = trans_->Start(&request_, &callback, log_);
[email protected]aea80602009-09-18 00:55:08126
[email protected]3caf5542010-07-16 15:19:47127 // We expect an IO Pending or some sort of error.
128 EXPECT_LT(output_.rv, 0);
129 if (output_.rv != ERR_IO_PENDING)
130 return;
[email protected]aea80602009-09-18 00:55:08131
[email protected]3caf5542010-07-16 15:19:47132 output_.rv = callback.WaitForResult();
133 if (output_.rv != OK) {
134 session_->spdy_session_pool()->ClearSessions();
135 return;
136 }
[email protected]ff57bb82009-11-12 06:52:14137
[email protected]3caf5542010-07-16 15:19:47138 // Verify responses.
139 const HttpResponseInfo* response = trans_->GetResponseInfo();
140 ASSERT_TRUE(response != NULL);
141 ASSERT_TRUE(response->headers != NULL);
142 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
143 EXPECT_TRUE(response->was_fetched_via_spdy);
[email protected]a33cad2b62010-07-30 22:24:39144 if (test_type_ == SPDYNPN) {
[email protected]9e9e842e2010-07-23 23:09:15145 EXPECT_TRUE(response->was_npn_negotiated);
146 EXPECT_TRUE(response->was_alternate_protocol_available);
[email protected]a33cad2b62010-07-30 22:24:39147 } else {
[email protected]9e9e842e2010-07-23 23:09:15148 EXPECT_TRUE(!response->was_npn_negotiated);
149 EXPECT_TRUE(!response->was_alternate_protocol_available);
150 }
[email protected]3caf5542010-07-16 15:19:47151 output_.status_line = response->headers->GetStatusLine();
152 output_.response_info = *response; // Make a copy so we can verify.
153 output_.rv = ReadTransaction(trans_.get(), &output_.response_data);
154 EXPECT_EQ(OK, output_.rv);
155 return;
156 }
157
158 // Most tests will want to call this function. In particular, the MockReads
159 // should end with an empty read, and that read needs to be processed to
160 // ensure proper deletion of the spdy_session_pool.
161 void VerifyDataConsumed() {
[email protected]a33cad2b62010-07-30 22:24:39162 for (DataVector::iterator it = data_vector_.begin();
[email protected]3caf5542010-07-16 15:19:47163 it != data_vector_.end(); ++it) {
164 EXPECT_TRUE((*it)->at_read_eof()) << "Read count: "
165 << (*it)->read_count()
166 << " Read index: "
167 << (*it)->read_index();
168 EXPECT_TRUE((*it)->at_write_eof()) << "Write count: "
169 << (*it)->write_count()
170 << " Write index: "
171 << (*it)->write_index();
172 }
173 }
174
175 // Occasionally a test will expect to error out before certain reads are
176 // processed. In that case we want to explicitly ensure that the reads were
177 // not processed.
178 void VerifyDataNotConsumed() {
[email protected]a33cad2b62010-07-30 22:24:39179 for (DataVector::iterator it = data_vector_.begin();
[email protected]3caf5542010-07-16 15:19:47180 it != data_vector_.end(); ++it) {
181 EXPECT_TRUE(!(*it)->at_read_eof()) << "Read count: "
182 << (*it)->read_count()
183 << " Read index: "
184 << (*it)->read_index();
185 EXPECT_TRUE(!(*it)->at_write_eof()) << "Write count: "
186 << (*it)->write_count()
187 << " Write index: "
188 << (*it)->write_index();
[email protected]3caf5542010-07-16 15:19:47189 }
190 }
191
192 void RunToCompletion(StaticSocketDataProvider* data) {
[email protected]3caf5542010-07-16 15:19:47193 RunPreTestSetup();
[email protected]e3ebba0f2010-08-05 17:59:58194 AddData(data);
[email protected]3caf5542010-07-16 15:19:47195 RunDefaultTest();
196 VerifyDataConsumed();
197 }
[email protected]e6b06862010-07-20 16:32:58198
[email protected]3caf5542010-07-16 15:19:47199 void AddData(StaticSocketDataProvider* data) {
[email protected]3b7828432010-08-18 18:33:27200 DCHECK(!deterministic_);
[email protected]3caf5542010-07-16 15:19:47201 data_vector_.push_back(data);
[email protected]9e9e842e2010-07-23 23:09:15202 linked_ptr<SSLSocketDataProvider> ssl_(
203 new SSLSocketDataProvider(true, OK));
[email protected]a33cad2b62010-07-30 22:24:39204 if (test_type_ == SPDYNPN) {
[email protected]9e9e842e2010-07-23 23:09:15205 ssl_->next_proto_status = SSLClientSocket::kNextProtoNegotiated;
[email protected]dae22c52010-07-30 02:16:35206 ssl_->next_proto = "spdy/2";
[email protected]9e9e842e2010-07-23 23:09:15207 ssl_->was_npn_negotiated = true;
208 }
209 ssl_vector_.push_back(ssl_);
[email protected]b261d0e2010-08-02 19:13:24210 if(test_type_ == SPDYNPN || test_type_ == SPDYSSL)
[email protected]3b7828432010-08-18 18:33:27211 session_deps_->socket_factory->AddSSLSocketDataProvider(ssl_.get());
212 session_deps_->socket_factory->AddSocketDataProvider(data);
213 }
214
215 void AddDeterministicData(DeterministicSocketData* data) {
216 DCHECK(deterministic_);
217 data_vector_.push_back(data);
218 linked_ptr<SSLSocketDataProvider> ssl_(
219 new SSLSocketDataProvider(true, OK));
220 if (test_type_ == SPDYNPN) {
221 ssl_->next_proto_status = SSLClientSocket::kNextProtoNegotiated;
222 ssl_->next_proto = "spdy/2";
223 ssl_->was_npn_negotiated = true;
224 }
225 ssl_vector_.push_back(ssl_);
226 if(test_type_ == SPDYNPN || test_type_ == SPDYSSL)
227 session_deps_->deterministic_socket_factory->
228 AddSSLSocketDataProvider(ssl_.get());
229 session_deps_->deterministic_socket_factory->AddSocketDataProvider(data);
[email protected]3caf5542010-07-16 15:19:47230 }
231
[email protected]e6b06862010-07-20 16:32:58232 // This can only be called after RunPreTestSetup. It adds a Data Provider,
233 // but not a corresponding SSL data provider
234 void AddDataNoSSL(StaticSocketDataProvider* data) {
[email protected]3b7828432010-08-18 18:33:27235 DCHECK(!deterministic_);
236 session_deps_->socket_factory->AddSocketDataProvider(data);
237 }
238 void AddDataNoSSL(DeterministicSocketData* data) {
239 DCHECK(deterministic_);
240 session_deps_->deterministic_socket_factory->AddSocketDataProvider(data);
[email protected]e6b06862010-07-20 16:32:58241 }
242
[email protected]a33cad2b62010-07-30 22:24:39243 void SetSession(const scoped_refptr<HttpNetworkSession>& session) {
[email protected]3caf5542010-07-16 15:19:47244 session_ = session;
245 }
246 HttpNetworkTransaction* trans() { return trans_.get(); }
247 void ResetTrans() { trans_.reset(); }
248 TransactionHelperResult& output() { return output_; }
249 HttpRequestInfo& request() { return request_; }
250 scoped_refptr<HttpNetworkSession>& session() { return session_; }
[email protected]b261d0e2010-08-02 19:13:24251 scoped_ptr<SpdySessionDependencies>& session_deps() {
252 return session_deps_;
253 }
[email protected]9e9e842e2010-07-23 23:09:15254 int port() { return port_; }
[email protected]3caf5542010-07-16 15:19:47255
256 private:
257 typedef std::vector<StaticSocketDataProvider*> DataVector;
258 typedef std::vector<linked_ptr<SSLSocketDataProvider> > SSLVector;
259 HttpRequestInfo request_;
[email protected]b261d0e2010-08-02 19:13:24260 scoped_ptr<SpdySessionDependencies> session_deps_;
[email protected]3caf5542010-07-16 15:19:47261 scoped_refptr<HttpNetworkSession> session_;
262 TransactionHelperResult output_;
263 scoped_ptr<StaticSocketDataProvider> first_transaction_;
264 SSLVector ssl_vector_;
265 TestCompletionCallback callback;
266 scoped_ptr<HttpNetworkTransaction> trans_;
267 scoped_ptr<HttpNetworkTransaction> trans_http_;
268 DataVector data_vector_;
269 const BoundNetLog& log_;
[email protected]9e9e842e2010-07-23 23:09:15270 SpdyNetworkTransactionTestTypes test_type_;
271 int port_;
[email protected]3b7828432010-08-18 18:33:27272 bool deterministic_;
[email protected]3caf5542010-07-16 15:19:47273 };
[email protected]aea80602009-09-18 00:55:08274
275 void ConnectStatusHelperWithExpectedStatus(const MockRead& status,
276 int expected_status);
277
278 void ConnectStatusHelper(const MockRead& status);
[email protected]d3cee19d2010-06-22 18:42:18279
[email protected]e3ebba0f2010-08-05 17:59:58280 const HttpRequestInfo& CreateGetPushRequest() {
281 google_get_push_request_.method = "GET";
282 google_get_push_request_.url = GURL("http://www.google.com/foo.dat");
283 google_get_push_request_.load_flags = 0;
284 return google_get_push_request_;
285 }
286
[email protected]d3cee19d2010-06-22 18:42:18287 const HttpRequestInfo& CreateGetRequest() {
288 if (!google_get_request_initialized_) {
289 google_get_request_.method = "GET";
[email protected]310240592010-08-05 21:04:19290 google_get_request_.url = GURL(kDefaultURL);
[email protected]d3cee19d2010-06-22 18:42:18291 google_get_request_.load_flags = 0;
292 google_get_request_initialized_ = true;
293 }
294 return google_get_request_;
295 }
296
[email protected]310240592010-08-05 21:04:19297 const HttpRequestInfo& CreatePostRequest() {
298 if (!google_post_request_initialized_) {
299 google_post_request_.method = "POST";
300 google_post_request_.url = GURL(kDefaultURL);
301 google_post_request_.upload_data = new UploadData();
302 google_post_request_.upload_data->AppendBytes(kUploadData,
303 kUploadDataSize);
304 google_post_request_initialized_ = true;
305 }
306 return google_post_request_;
307 }
308
[email protected]e3ebba0f2010-08-05 17:59:58309 class RunServerPushTestCallback : public CallbackRunner< Tuple1<int> > {
310 public:
311 RunServerPushTestCallback(scoped_refptr<net::IOBufferWithSize> buffer,
312 std::string& result, bool& need_read_callback)
313 : buffer_(buffer), result_(result),
314 need_read_callback_(need_read_callback) {}
315
316 virtual void RunWithParams(const Tuple1<int>& params) {
317 // Indicates some type of error.
318 if(params.a <= 0)
319 return;
320
321 std::string temp(buffer_->data(), params.a);
322 result_.append(temp);
323 need_read_callback_ = true;
324 }
325
326 private:
327 scoped_refptr<net::IOBufferWithSize> buffer_;
328 std::string& result_;
329 bool need_read_callback_;
330 };
331
332 void RunServerPushTest(MockWrite writes[], int writes_length,
333 MockRead reads[], int reads_length,
334 HttpResponseInfo* response,
335 HttpResponseInfo* response2,
336 std::string& expected) {
337 scoped_refptr<OrderedSocketData> data(
338 new OrderedSocketData(reads, reads_length,
339 writes, writes_length));
340 NormalSpdyTransactionHelper helper(CreateGetRequest(),
341 BoundNetLog(), GetParam());
342
343 helper.RunPreTestSetup();
344 helper.AddData(data.get());
345
346 HttpNetworkTransaction* trans = helper.trans();
347
348 // Start the transaction with basic parameters.
349 TestCompletionCallback callback;
350 int rv = trans->Start(&CreateGetRequest(), &callback, BoundNetLog());
351 EXPECT_EQ(ERR_IO_PENDING, rv);
352 rv = callback.WaitForResult();
353
354 // Request the pushed path.
355 const int kSize = 3000;
356 scoped_refptr<net::IOBufferWithSize> buf = new net::IOBufferWithSize(kSize);
357 scoped_ptr<HttpNetworkTransaction> trans2(
358 new HttpNetworkTransaction(helper.session()));
359 rv = trans2->Start(&CreateGetPushRequest(), &callback, BoundNetLog());
360 EXPECT_EQ(ERR_IO_PENDING, rv);
361 MessageLoop::current()->RunAllPending();
362
363 // The data for the pushed path may be coming in more than 1 packet. Compile
364 // the results into a single string.
365 std::string result;
366 bool need_read_callback = true;
367 RunServerPushTestCallback callback2(buf, result, need_read_callback);
368 while(!data->at_read_eof())
369 {
370 if(need_read_callback) {
371 while((rv = trans2->Read(buf, kSize, &callback2)) > 0) {
372 std::string result1(buf->data(),rv);
373 result.append(result1);
374 }
375 need_read_callback = false;
376 }
377 else
378 data->CompleteRead();
379 MessageLoop::current()->RunAllPending();
380 }
381
382 // Verify that we consumed all test data.
383 EXPECT_TRUE(data->at_read_eof());
384 EXPECT_TRUE(data->at_write_eof());
385
386 // Verify that the received push data is same as the expected push data.
387 EXPECT_EQ(result.compare(expected),0) << "Received data: "
388 << result
389 << "||||| Expected data: "
390 << expected;
391
392 // Verify the SYN_REPLY.
393 // Copy the response info, because trans goes away.
394 *response = *trans->GetResponseInfo();
395 *response2 = *trans2->GetResponseInfo();
396 }
397
[email protected]d3cee19d2010-06-22 18:42:18398 private:
399 bool google_get_request_initialized_;
[email protected]310240592010-08-05 21:04:19400 bool google_post_request_initialized_;
[email protected]d3cee19d2010-06-22 18:42:18401 HttpRequestInfo google_get_request_;
[email protected]310240592010-08-05 21:04:19402 HttpRequestInfo google_post_request_;
[email protected]e3ebba0f2010-08-05 17:59:58403 HttpRequestInfo google_get_push_request_;
[email protected]aea80602009-09-18 00:55:08404};
405
406//-----------------------------------------------------------------------------
[email protected]9e9e842e2010-07-23 23:09:15407// All tests are run with three different connection types: SPDY after NPN
408// negotiation, SPDY without SSL, and SPDY with SSL.
409INSTANTIATE_TEST_CASE_P(SpdyNetworkingTest,
410 SpdyNetworkTransactionTest,
[email protected]e3ebba0f2010-08-05 17:59:58411 ::testing::Values(SPDYNOSSL, SPDYSSL, SPDYNPN));
[email protected]9e9e842e2010-07-23 23:09:15412
[email protected]aea80602009-09-18 00:55:08413
[email protected]3caf5542010-07-16 15:19:47414// Verify HttpNetworkTransaction constructor.
[email protected]9e9e842e2010-07-23 23:09:15415TEST_P(SpdyNetworkTransactionTest, Constructor) {
[email protected]30c942b2010-07-21 16:59:59416 SpdySessionDependencies session_deps;
[email protected]34437af82009-11-06 02:28:49417 scoped_refptr<HttpNetworkSession> session =
[email protected]30c942b2010-07-21 16:59:59418 SpdySessionDependencies::SpdyCreateSession(&session_deps);
[email protected]3caf5542010-07-16 15:19:47419 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session));
[email protected]aea80602009-09-18 00:55:08420}
421
[email protected]9e9e842e2010-07-23 23:09:15422TEST_P(SpdyNetworkTransactionTest, Get) {
[email protected]75f30cc22010-06-28 21:41:38423 // Construct the request.
[email protected]2bd93022010-07-17 00:58:44424 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST));
[email protected]e7f75092010-07-01 22:39:13425 MockWrite writes[] = { CreateMockWrite(*req) };
[email protected]72552f02009-10-28 15:25:01426
[email protected]2bd93022010-07-17 00:58:44427 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1));
428 scoped_ptr<spdy::SpdyFrame> body(ConstructSpdyBodyFrame(1, true));
[email protected]72552f02009-10-28 15:25:01429 MockRead reads[] = {
[email protected]e7f75092010-07-01 22:39:13430 CreateMockRead(*resp),
431 CreateMockRead(*body),
[email protected]72552f02009-10-28 15:25:01432 MockRead(true, 0, 0) // EOF
433 };
434
[email protected]bf2491a92009-11-29 16:39:48435 scoped_refptr<DelayedSocketData> data(
[email protected]31a2bfe2010-02-09 08:03:39436 new DelayedSocketData(1, reads, arraysize(reads),
437 writes, arraysize(writes)));
[email protected]3caf5542010-07-16 15:19:47438 NormalSpdyTransactionHelper helper(CreateGetRequest(),
[email protected]9e9e842e2010-07-23 23:09:15439 BoundNetLog(), GetParam());
[email protected]3caf5542010-07-16 15:19:47440 helper.RunToCompletion(data.get());
441 TransactionHelperResult out = helper.output();
[email protected]72552f02009-10-28 15:25:01442 EXPECT_EQ(OK, out.rv);
443 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
444 EXPECT_EQ("hello!", out.response_data);
445}
446
[email protected]c9c6f5c2010-07-31 01:30:03447TEST_P(SpdyNetworkTransactionTest, GetAtEachPriority) {
448 for (RequestPriority p = HIGHEST; p < NUM_PRIORITIES;
449 p = RequestPriority(p+1)) {
450 // Construct the request.
451 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, p));
452 MockWrite writes[] = { CreateMockWrite(*req) };
453
454 const int spdy_prio = reinterpret_cast<spdy::SpdySynStreamControlFrame*>(
455 req.get())->priority();
456 // this repeats the RequestPriority-->SpdyPriority mapping from
457 // SpdyFramer::ConvertRequestPriorityToSpdyPriority to make
458 // sure it's being done right.
459 switch(p) {
460 case HIGHEST:
461 EXPECT_EQ(0, spdy_prio);
462 break;
463 case MEDIUM:
464 EXPECT_EQ(1, spdy_prio);
465 break;
466 case LOW:
467 case LOWEST:
468 EXPECT_EQ(2, spdy_prio);
469 break;
470 case IDLE:
471 EXPECT_EQ(3, spdy_prio);
472 break;
473 default:
474 FAIL();
475 }
476
477 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1));
478 scoped_ptr<spdy::SpdyFrame> body(ConstructSpdyBodyFrame(1, true));
479 MockRead reads[] = {
480 CreateMockRead(*resp),
481 CreateMockRead(*body),
482 MockRead(true, 0, 0) // EOF
483 };
484
485 scoped_refptr<DelayedSocketData> data(
486 new DelayedSocketData(1, reads, arraysize(reads),
487 writes, arraysize(writes)));
488 HttpRequestInfo http_req = CreateGetRequest();
489 http_req.priority = p;
490
491 NormalSpdyTransactionHelper helper(http_req, BoundNetLog(), GetParam());
492 helper.RunToCompletion(data.get());
493 TransactionHelperResult out = helper.output();
494 EXPECT_EQ(OK, out.rv);
495 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
496 EXPECT_EQ("hello!", out.response_data);
497 }
498}
499
[email protected]2bd93022010-07-17 00:58:44500// Start three gets simultaniously; making sure that multiplexed
501// streams work properly.
502
503// This can't use the TransactionHelper method, since it only
504// handles a single transaction, and finishes them as soon
505// as it launches them.
506
507// TODO(gavinp): create a working generalized TransactionHelper that
508// can allow multiple streams in flight.
509
[email protected]9e9e842e2010-07-23 23:09:15510TEST_P(SpdyNetworkTransactionTest, ThreeGets) {
[email protected]2bd93022010-07-17 00:58:44511 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST));
512 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1));
513 scoped_ptr<spdy::SpdyFrame> body(ConstructSpdyBodyFrame(1, false));
514 scoped_ptr<spdy::SpdyFrame> fbody(ConstructSpdyBodyFrame(1, true));
515
516 scoped_ptr<spdy::SpdyFrame> req2(ConstructSpdyGet(NULL, 0, false, 3, LOWEST));
517 scoped_ptr<spdy::SpdyFrame> resp2(ConstructSpdyGetSynReply(NULL, 0, 3));
518 scoped_ptr<spdy::SpdyFrame> body2(ConstructSpdyBodyFrame(3, false));
519 scoped_ptr<spdy::SpdyFrame> fbody2(ConstructSpdyBodyFrame(3, true));
520
521 scoped_ptr<spdy::SpdyFrame> req3(ConstructSpdyGet(NULL, 0, false, 5, LOWEST));
522 scoped_ptr<spdy::SpdyFrame> resp3(ConstructSpdyGetSynReply(NULL, 0, 5));
523 scoped_ptr<spdy::SpdyFrame> body3(ConstructSpdyBodyFrame(5, false));
524 scoped_ptr<spdy::SpdyFrame> fbody3(ConstructSpdyBodyFrame(5, true));
525
526 MockWrite writes[] = { CreateMockWrite(*req),
527 CreateMockWrite(*req2),
528 CreateMockWrite(*req3),
529 };
530 MockRead reads[] = {
531 CreateMockRead(*resp, 1),
532 CreateMockRead(*body),
533 CreateMockRead(*resp2, 4),
534 CreateMockRead(*body2),
535 CreateMockRead(*resp3, 7),
536 CreateMockRead(*body3),
537
538 CreateMockRead(*fbody),
539 CreateMockRead(*fbody2),
540 CreateMockRead(*fbody3),
541
542 MockRead(true, 0, 0), // EOF
543 };
[email protected]2bd93022010-07-17 00:58:44544 scoped_refptr<OrderedSocketData> data(
545 new OrderedSocketData(reads, arraysize(reads),
546 writes, arraysize(writes)));
[email protected]bdebd1b2010-08-09 20:18:08547 scoped_refptr<OrderedSocketData> data_placeholder(
548 new OrderedSocketData(NULL, 0, NULL, 0));
[email protected]2bd93022010-07-17 00:58:44549
550 BoundNetLog log;
551 TransactionHelperResult out;
[email protected]bdebd1b2010-08-09 20:18:08552 NormalSpdyTransactionHelper helper(CreateGetRequest(),
553 BoundNetLog(), GetParam());
554 helper.RunPreTestSetup();
555 helper.AddData(data.get());
556 // We require placeholder data because three get requests are sent out, so
557 // there needs to be three sets of SSL connection data.
558 helper.AddData(data_placeholder.get());
559 helper.AddData(data_placeholder.get());
560 scoped_ptr<HttpNetworkTransaction> trans1(
561 new HttpNetworkTransaction(helper.session()));
562 scoped_ptr<HttpNetworkTransaction> trans2(
563 new HttpNetworkTransaction(helper.session()));
564 scoped_ptr<HttpNetworkTransaction> trans3(
565 new HttpNetworkTransaction(helper.session()));
[email protected]2bd93022010-07-17 00:58:44566
[email protected]bdebd1b2010-08-09 20:18:08567 TestCompletionCallback callback1;
568 TestCompletionCallback callback2;
569 TestCompletionCallback callback3;
[email protected]2bd93022010-07-17 00:58:44570
[email protected]bdebd1b2010-08-09 20:18:08571 HttpRequestInfo httpreq1 = CreateGetRequest();
572 HttpRequestInfo httpreq2 = CreateGetRequest();
573 HttpRequestInfo httpreq3 = CreateGetRequest();
[email protected]2bd93022010-07-17 00:58:44574
[email protected]bdebd1b2010-08-09 20:18:08575 out.rv = trans1->Start(&httpreq1, &callback1, log);
576 ASSERT_EQ(ERR_IO_PENDING, out.rv);
577 out.rv = trans2->Start(&httpreq2, &callback2, log);
578 ASSERT_EQ(ERR_IO_PENDING, out.rv);
579 out.rv = trans3->Start(&httpreq3, &callback3, log);
580 ASSERT_EQ(ERR_IO_PENDING, out.rv);
[email protected]2bd93022010-07-17 00:58:44581
[email protected]bdebd1b2010-08-09 20:18:08582 out.rv = callback1.WaitForResult();
583 ASSERT_EQ(OK, out.rv);
584 out.rv = callback3.WaitForResult();
585 ASSERT_EQ(OK, out.rv);
[email protected]2bd93022010-07-17 00:58:44586
[email protected]bdebd1b2010-08-09 20:18:08587 const HttpResponseInfo* response1 = trans1->GetResponseInfo();
588 EXPECT_TRUE(response1->headers != NULL);
589 EXPECT_TRUE(response1->was_fetched_via_spdy);
590 out.status_line = response1->headers->GetStatusLine();
591 out.response_info = *response1;
[email protected]2bd93022010-07-17 00:58:44592
[email protected]bdebd1b2010-08-09 20:18:08593 trans2->GetResponseInfo();
[email protected]2bd93022010-07-17 00:58:44594
[email protected]bdebd1b2010-08-09 20:18:08595 out.rv = ReadTransaction(trans1.get(), &out.response_data);
596 helper.VerifyDataConsumed();
[email protected]2bd93022010-07-17 00:58:44597 EXPECT_EQ(OK, out.rv);
598
[email protected]2bd93022010-07-17 00:58:44599 EXPECT_EQ(OK, out.rv);
600 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
601 EXPECT_EQ("hello!hello!", out.response_data);
602}
603
[email protected]2bd93022010-07-17 00:58:44604// Similar to ThreeGets above, however this test adds a SETTINGS
605// frame. The SETTINGS frame is read during the IO loop waiting on
606// the first transaction completion, and sets a maximum concurrent
607// stream limit of 1. This means that our IO loop exists after the
608// second transaction completes, so we can assert on read_index().
[email protected]9e9e842e2010-07-23 23:09:15609TEST_P(SpdyNetworkTransactionTest, ThreeGetsWithMaxConcurrent) {
[email protected]2bd93022010-07-17 00:58:44610 // Construct the request.
611 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST));
612 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1));
613 scoped_ptr<spdy::SpdyFrame> body(ConstructSpdyBodyFrame(1, false));
614 scoped_ptr<spdy::SpdyFrame> fbody(ConstructSpdyBodyFrame(1, true));
615
616 scoped_ptr<spdy::SpdyFrame> req2(ConstructSpdyGet(NULL, 0, false, 3, LOWEST));
617 scoped_ptr<spdy::SpdyFrame> resp2(ConstructSpdyGetSynReply(NULL, 0, 3));
618 scoped_ptr<spdy::SpdyFrame> body2(ConstructSpdyBodyFrame(3, false));
619 scoped_ptr<spdy::SpdyFrame> fbody2(ConstructSpdyBodyFrame(3, true));
620
621 scoped_ptr<spdy::SpdyFrame> req3(ConstructSpdyGet(NULL, 0, false, 5, LOWEST));
622 scoped_ptr<spdy::SpdyFrame> resp3(ConstructSpdyGetSynReply(NULL, 0, 5));
623 scoped_ptr<spdy::SpdyFrame> body3(ConstructSpdyBodyFrame(5, false));
624 scoped_ptr<spdy::SpdyFrame> fbody3(ConstructSpdyBodyFrame(5, true));
625
626 spdy::SpdySettings settings;
627 spdy::SettingsFlagsAndId id(0);
628 id.set_id(spdy::SETTINGS_MAX_CONCURRENT_STREAMS);
629 const size_t max_concurrent_streams = 1;
630
631 settings.push_back(spdy::SpdySetting(id, max_concurrent_streams));
632 scoped_ptr<spdy::SpdyFrame> settings_frame(ConstructSpdySettings(settings));
633
634 MockWrite writes[] = { CreateMockWrite(*req),
635 CreateMockWrite(*req2),
636 CreateMockWrite(*req3),
637 };
638 MockRead reads[] = {
[email protected]bdebd1b2010-08-09 20:18:08639 CreateMockRead(*settings_frame, 1),
[email protected]2bd93022010-07-17 00:58:44640 CreateMockRead(*resp),
641 CreateMockRead(*body),
642 CreateMockRead(*fbody),
[email protected]bdebd1b2010-08-09 20:18:08643 CreateMockRead(*resp2, 7),
[email protected]2bd93022010-07-17 00:58:44644 CreateMockRead(*body2),
645 CreateMockRead(*fbody2),
[email protected]bdebd1b2010-08-09 20:18:08646 CreateMockRead(*resp3, 12),
[email protected]2bd93022010-07-17 00:58:44647 CreateMockRead(*body3),
648 CreateMockRead(*fbody3),
649
650 MockRead(true, 0, 0), // EOF
651 };
652
653 scoped_refptr<OrderedSocketData> data(
654 new OrderedSocketData(reads, arraysize(reads),
655 writes, arraysize(writes)));
[email protected]bdebd1b2010-08-09 20:18:08656 scoped_refptr<OrderedSocketData> data_placeholder(
657 new OrderedSocketData(NULL, 0, NULL, 0));
[email protected]2bd93022010-07-17 00:58:44658
659 BoundNetLog log;
660 TransactionHelperResult out;
661 {
[email protected]bdebd1b2010-08-09 20:18:08662 NormalSpdyTransactionHelper helper(CreateGetRequest(),
663 BoundNetLog(), GetParam());
664 helper.RunPreTestSetup();
665 helper.AddData(data.get());
666 // We require placeholder data because three get requests are sent out, so
667 // there needs to be three sets of SSL connection data.
668 helper.AddData(data_placeholder.get());
669 helper.AddData(data_placeholder.get());
670 scoped_ptr<HttpNetworkTransaction> trans1(
671 new HttpNetworkTransaction(helper.session()));
672 scoped_ptr<HttpNetworkTransaction> trans2(
673 new HttpNetworkTransaction(helper.session()));
674 scoped_ptr<HttpNetworkTransaction> trans3(
675 new HttpNetworkTransaction(helper.session()));
[email protected]2bd93022010-07-17 00:58:44676
677 TestCompletionCallback callback1;
678 TestCompletionCallback callback2;
679 TestCompletionCallback callback3;
680
681 HttpRequestInfo httpreq1 = CreateGetRequest();
682 HttpRequestInfo httpreq2 = CreateGetRequest();
683 HttpRequestInfo httpreq3 = CreateGetRequest();
684
685 out.rv = trans1->Start(&httpreq1, &callback1, log);
686 ASSERT_EQ(out.rv, ERR_IO_PENDING);
687 // run transaction 1 through quickly to force a read of our SETTINGS
688 // frame
689 out.rv = callback1.WaitForResult();
[email protected]bdebd1b2010-08-09 20:18:08690 ASSERT_EQ(OK, out.rv);
[email protected]2bd93022010-07-17 00:58:44691
692 out.rv = trans2->Start(&httpreq2, &callback2, log);
693 ASSERT_EQ(out.rv, ERR_IO_PENDING);
694 out.rv = trans3->Start(&httpreq3, &callback3, log);
695 ASSERT_EQ(out.rv, ERR_IO_PENDING);
696 out.rv = callback2.WaitForResult();
697 ASSERT_EQ(OK, out.rv);
698 EXPECT_EQ(7U, data->read_index()); // i.e. the third trans was queued
699
700 out.rv = callback3.WaitForResult();
701 ASSERT_EQ(OK, out.rv);
702
703 const HttpResponseInfo* response1 = trans1->GetResponseInfo();
[email protected]bdebd1b2010-08-09 20:18:08704 ASSERT_TRUE(response1 != NULL);
[email protected]2bd93022010-07-17 00:58:44705 EXPECT_TRUE(response1->headers != NULL);
706 EXPECT_TRUE(response1->was_fetched_via_spdy);
707 out.status_line = response1->headers->GetStatusLine();
708 out.response_info = *response1;
709 out.rv = ReadTransaction(trans1.get(), &out.response_data);
710 EXPECT_EQ(OK, out.rv);
711 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
712 EXPECT_EQ("hello!hello!", out.response_data);
713
714 const HttpResponseInfo* response2 = trans2->GetResponseInfo();
715 out.status_line = response2->headers->GetStatusLine();
716 out.response_info = *response2;
717 out.rv = ReadTransaction(trans2.get(), &out.response_data);
718 EXPECT_EQ(OK, out.rv);
719 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
720 EXPECT_EQ("hello!hello!", out.response_data);
721
722 const HttpResponseInfo* response3 = trans3->GetResponseInfo();
723 out.status_line = response3->headers->GetStatusLine();
724 out.response_info = *response3;
725 out.rv = ReadTransaction(trans3.get(), &out.response_data);
726 EXPECT_EQ(OK, out.rv);
727 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
728 EXPECT_EQ("hello!hello!", out.response_data);
[email protected]bdebd1b2010-08-09 20:18:08729 helper.VerifyDataConsumed();
[email protected]2bd93022010-07-17 00:58:44730 }
731 EXPECT_EQ(OK, out.rv);
[email protected]2bd93022010-07-17 00:58:44732}
733
734// Similar to ThreeGetsWithMaxConcurrent above, however this test adds
735// a fourth transaction. The third and fourth transactions have
736// different data ("hello!" vs "hello!hello!") and because of the
737// user specified priority, we expect to see them inverted in
738// the response from the server.
[email protected]9e9e842e2010-07-23 23:09:15739TEST_P(SpdyNetworkTransactionTest, FourGetsWithMaxConcurrentPriority) {
[email protected]2bd93022010-07-17 00:58:44740 // Construct the request.
741 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST));
742 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1));
743 scoped_ptr<spdy::SpdyFrame> body(ConstructSpdyBodyFrame(1, false));
744 scoped_ptr<spdy::SpdyFrame> fbody(ConstructSpdyBodyFrame(1, true));
745
746 scoped_ptr<spdy::SpdyFrame> req2(ConstructSpdyGet(NULL, 0, false, 3, LOWEST));
747 scoped_ptr<spdy::SpdyFrame> resp2(ConstructSpdyGetSynReply(NULL, 0, 3));
748 scoped_ptr<spdy::SpdyFrame> body2(ConstructSpdyBodyFrame(3, false));
749 scoped_ptr<spdy::SpdyFrame> fbody2(ConstructSpdyBodyFrame(3, true));
750
751 scoped_ptr<spdy::SpdyFrame> req4(
752 ConstructSpdyGet(NULL, 0, false, 5, HIGHEST));
753 scoped_ptr<spdy::SpdyFrame> resp4(ConstructSpdyGetSynReply(NULL, 0, 5));
754 scoped_ptr<spdy::SpdyFrame> fbody4(ConstructSpdyBodyFrame(5, true));
755
756 scoped_ptr<spdy::SpdyFrame> req3(ConstructSpdyGet(NULL, 0, false, 7, LOWEST));
757 scoped_ptr<spdy::SpdyFrame> resp3(ConstructSpdyGetSynReply(NULL, 0, 7));
758 scoped_ptr<spdy::SpdyFrame> body3(ConstructSpdyBodyFrame(7, false));
759 scoped_ptr<spdy::SpdyFrame> fbody3(ConstructSpdyBodyFrame(7, true));
760
761
762 spdy::SpdySettings settings;
763 spdy::SettingsFlagsAndId id(0);
764 id.set_id(spdy::SETTINGS_MAX_CONCURRENT_STREAMS);
765 const size_t max_concurrent_streams = 1;
766
767 settings.push_back(spdy::SpdySetting(id, max_concurrent_streams));
768 scoped_ptr<spdy::SpdyFrame> settings_frame(ConstructSpdySettings(settings));
769
770 MockWrite writes[] = { CreateMockWrite(*req),
[email protected]bdebd1b2010-08-09 20:18:08771 CreateMockWrite(*req2),
772 CreateMockWrite(*req4),
773 CreateMockWrite(*req3),
[email protected]2bd93022010-07-17 00:58:44774 };
775 MockRead reads[] = {
[email protected]bdebd1b2010-08-09 20:18:08776 CreateMockRead(*settings_frame, 1),
[email protected]2bd93022010-07-17 00:58:44777 CreateMockRead(*resp),
778 CreateMockRead(*body),
779 CreateMockRead(*fbody),
[email protected]bdebd1b2010-08-09 20:18:08780 CreateMockRead(*resp2, 7),
[email protected]2bd93022010-07-17 00:58:44781 CreateMockRead(*body2),
782 CreateMockRead(*fbody2),
[email protected]bdebd1b2010-08-09 20:18:08783 CreateMockRead(*resp4, 13),
[email protected]2bd93022010-07-17 00:58:44784 CreateMockRead(*fbody4),
[email protected]bdebd1b2010-08-09 20:18:08785 CreateMockRead(*resp3, 16),
[email protected]2bd93022010-07-17 00:58:44786 CreateMockRead(*body3),
787 CreateMockRead(*fbody3),
788
789 MockRead(true, 0, 0), // EOF
790 };
791
792 scoped_refptr<OrderedSocketData> data(
793 new OrderedSocketData(reads, arraysize(reads),
[email protected]bdebd1b2010-08-09 20:18:08794 writes, arraysize(writes)));
795 scoped_refptr<OrderedSocketData> data_placeholder(
796 new OrderedSocketData(NULL, 0, NULL, 0));
[email protected]2bd93022010-07-17 00:58:44797
798 BoundNetLog log;
799 TransactionHelperResult out;
[email protected]bdebd1b2010-08-09 20:18:08800 NormalSpdyTransactionHelper helper(CreateGetRequest(),
801 BoundNetLog(), GetParam());
802 helper.RunPreTestSetup();
803 helper.AddData(data.get());
804 // We require placeholder data because four get requests are sent out, so
805 // there needs to be four sets of SSL connection data.
806 helper.AddData(data_placeholder.get());
807 helper.AddData(data_placeholder.get());
808 helper.AddData(data_placeholder.get());
809 scoped_ptr<HttpNetworkTransaction> trans1(
810 new HttpNetworkTransaction(helper.session()));
811 scoped_ptr<HttpNetworkTransaction> trans2(
812 new HttpNetworkTransaction(helper.session()));
813 scoped_ptr<HttpNetworkTransaction> trans3(
814 new HttpNetworkTransaction(helper.session()));
815 scoped_ptr<HttpNetworkTransaction> trans4(
816 new HttpNetworkTransaction(helper.session()));
[email protected]2bd93022010-07-17 00:58:44817
[email protected]bdebd1b2010-08-09 20:18:08818 TestCompletionCallback callback1;
819 TestCompletionCallback callback2;
820 TestCompletionCallback callback3;
821 TestCompletionCallback callback4;
[email protected]2bd93022010-07-17 00:58:44822
[email protected]bdebd1b2010-08-09 20:18:08823 HttpRequestInfo httpreq1 = CreateGetRequest();
824 HttpRequestInfo httpreq2 = CreateGetRequest();
825 HttpRequestInfo httpreq3 = CreateGetRequest();
826 HttpRequestInfo httpreq4 = CreateGetRequest();
827 httpreq4.priority = HIGHEST;
[email protected]2bd93022010-07-17 00:58:44828
[email protected]bdebd1b2010-08-09 20:18:08829 out.rv = trans1->Start(&httpreq1, &callback1, log);
830 ASSERT_EQ(ERR_IO_PENDING, out.rv);
831 // run transaction 1 through quickly to force a read of our SETTINGS
832 // frame
833 out.rv = callback1.WaitForResult();
834 ASSERT_EQ(OK, out.rv);
[email protected]2bd93022010-07-17 00:58:44835
[email protected]bdebd1b2010-08-09 20:18:08836 out.rv = trans2->Start(&httpreq2, &callback2, log);
837 ASSERT_EQ(ERR_IO_PENDING, out.rv);
838 out.rv = trans3->Start(&httpreq3, &callback3, log);
839 ASSERT_EQ(ERR_IO_PENDING, out.rv);
840 out.rv = trans4->Start(&httpreq4, &callback4, log);
841 ASSERT_EQ(ERR_IO_PENDING, out.rv);
[email protected]2bd93022010-07-17 00:58:44842
[email protected]bdebd1b2010-08-09 20:18:08843 out.rv = callback2.WaitForResult();
844 ASSERT_EQ(OK, out.rv);
845 EXPECT_EQ(data->read_index(), 7U); // i.e. the third & fourth trans queued
[email protected]2bd93022010-07-17 00:58:44846
[email protected]bdebd1b2010-08-09 20:18:08847 out.rv = callback3.WaitForResult();
848 ASSERT_EQ(OK, out.rv);
[email protected]2bd93022010-07-17 00:58:44849
[email protected]bdebd1b2010-08-09 20:18:08850 const HttpResponseInfo* response1 = trans1->GetResponseInfo();
851 EXPECT_TRUE(response1->headers != NULL);
852 EXPECT_TRUE(response1->was_fetched_via_spdy);
853 out.status_line = response1->headers->GetStatusLine();
854 out.response_info = *response1;
855 out.rv = ReadTransaction(trans1.get(), &out.response_data);
856 EXPECT_EQ(OK, out.rv);
857 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
858 EXPECT_EQ("hello!hello!", out.response_data);
[email protected]2bd93022010-07-17 00:58:44859
[email protected]bdebd1b2010-08-09 20:18:08860 const HttpResponseInfo* response2 = trans2->GetResponseInfo();
861 out.status_line = response2->headers->GetStatusLine();
862 out.response_info = *response2;
863 out.rv = ReadTransaction(trans2.get(), &out.response_data);
864 EXPECT_EQ(OK, out.rv);
865 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
866 EXPECT_EQ("hello!hello!", out.response_data);
[email protected]2bd93022010-07-17 00:58:44867
[email protected]bdebd1b2010-08-09 20:18:08868 // notice: response3 gets two hellos, response4 gets one
869 // hello, so we know dequeuing priority was respected.
870 const HttpResponseInfo* response3 = trans3->GetResponseInfo();
871 out.status_line = response3->headers->GetStatusLine();
872 out.response_info = *response3;
873 out.rv = ReadTransaction(trans3.get(), &out.response_data);
874 EXPECT_EQ(OK, out.rv);
875 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
876 EXPECT_EQ("hello!hello!", out.response_data);
[email protected]2bd93022010-07-17 00:58:44877
[email protected]bdebd1b2010-08-09 20:18:08878 out.rv = callback4.WaitForResult();
879 EXPECT_EQ(OK, out.rv);
880 const HttpResponseInfo* response4 = trans4->GetResponseInfo();
881 out.status_line = response4->headers->GetStatusLine();
882 out.response_info = *response4;
883 out.rv = ReadTransaction(trans4.get(), &out.response_data);
884 EXPECT_EQ(OK, out.rv);
885 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
886 EXPECT_EQ("hello!", out.response_data);
887 helper.VerifyDataConsumed();
[email protected]2bd93022010-07-17 00:58:44888 EXPECT_EQ(OK, out.rv);
889
[email protected]2bd93022010-07-17 00:58:44890}
891
892// Similar to ThreeGetsMaxConcurrrent above, however, this test
893// deletes a session in the middle of the transaction to insure
894// that we properly remove pendingcreatestream objects from
895// the spdy_session
[email protected]9e9e842e2010-07-23 23:09:15896TEST_P(SpdyNetworkTransactionTest, ThreeGetsWithMaxConcurrentDelete) {
[email protected]2bd93022010-07-17 00:58:44897 // Construct the request.
898 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST));
899 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1));
900 scoped_ptr<spdy::SpdyFrame> body(ConstructSpdyBodyFrame(1, false));
901 scoped_ptr<spdy::SpdyFrame> fbody(ConstructSpdyBodyFrame(1, true));
902
903 scoped_ptr<spdy::SpdyFrame> req2(ConstructSpdyGet(NULL, 0, false, 3, LOWEST));
904 scoped_ptr<spdy::SpdyFrame> resp2(ConstructSpdyGetSynReply(NULL, 0, 3));
905 scoped_ptr<spdy::SpdyFrame> body2(ConstructSpdyBodyFrame(3, false));
906 scoped_ptr<spdy::SpdyFrame> fbody2(ConstructSpdyBodyFrame(3, true));
907
908 scoped_ptr<spdy::SpdyFrame> req3(ConstructSpdyGet(NULL, 0, false, 5, LOWEST));
909 scoped_ptr<spdy::SpdyFrame> resp3(ConstructSpdyGetSynReply(NULL, 0, 5));
910 scoped_ptr<spdy::SpdyFrame> body3(ConstructSpdyBodyFrame(5, false));
911 scoped_ptr<spdy::SpdyFrame> fbody3(ConstructSpdyBodyFrame(5, true));
912
913 spdy::SpdySettings settings;
914 spdy::SettingsFlagsAndId id(0);
915 id.set_id(spdy::SETTINGS_MAX_CONCURRENT_STREAMS);
916 const size_t max_concurrent_streams = 1;
917
918 settings.push_back(spdy::SpdySetting(id, max_concurrent_streams));
919 scoped_ptr<spdy::SpdyFrame> settings_frame(ConstructSpdySettings(settings));
920
921 MockWrite writes[] = { CreateMockWrite(*req),
[email protected]bdebd1b2010-08-09 20:18:08922 CreateMockWrite(*req2),
[email protected]2bd93022010-07-17 00:58:44923 };
924 MockRead reads[] = {
[email protected]bdebd1b2010-08-09 20:18:08925 CreateMockRead(*settings_frame, 1),
[email protected]2bd93022010-07-17 00:58:44926 CreateMockRead(*resp),
927 CreateMockRead(*body),
928 CreateMockRead(*fbody),
[email protected]bdebd1b2010-08-09 20:18:08929 CreateMockRead(*resp2, 7),
[email protected]2bd93022010-07-17 00:58:44930 CreateMockRead(*body2),
931 CreateMockRead(*fbody2),
932 MockRead(true, 0, 0), // EOF
933 };
934
935 scoped_refptr<OrderedSocketData> data(
936 new OrderedSocketData(reads, arraysize(reads),
[email protected]bdebd1b2010-08-09 20:18:08937 writes, arraysize(writes)));
938 scoped_refptr<OrderedSocketData> data_placeholder(
939 new OrderedSocketData(NULL, 0, NULL, 0));
[email protected]2bd93022010-07-17 00:58:44940
941 BoundNetLog log;
942 TransactionHelperResult out;
[email protected]bdebd1b2010-08-09 20:18:08943 NormalSpdyTransactionHelper helper(CreateGetRequest(),
944 BoundNetLog(), GetParam());
945 helper.RunPreTestSetup();
946 helper.AddData(data.get());
947 // We require placeholder data because three get requests are sent out, so
948 // there needs to be three sets of SSL connection data.
949 helper.AddData(data_placeholder.get());
950 helper.AddData(data_placeholder.get());
951 scoped_ptr<HttpNetworkTransaction> trans1(
952 new HttpNetworkTransaction(helper.session()));
953 scoped_ptr<HttpNetworkTransaction> trans2(
954 new HttpNetworkTransaction(helper.session()));
955 scoped_ptr<HttpNetworkTransaction> trans3(
956 new HttpNetworkTransaction(helper.session()));
[email protected]2bd93022010-07-17 00:58:44957
[email protected]bdebd1b2010-08-09 20:18:08958 TestCompletionCallback callback1;
959 TestCompletionCallback callback2;
960 TestCompletionCallback callback3;
[email protected]2bd93022010-07-17 00:58:44961
[email protected]bdebd1b2010-08-09 20:18:08962 HttpRequestInfo httpreq1 = CreateGetRequest();
963 HttpRequestInfo httpreq2 = CreateGetRequest();
964 HttpRequestInfo httpreq3 = CreateGetRequest();
[email protected]2bd93022010-07-17 00:58:44965
[email protected]bdebd1b2010-08-09 20:18:08966 out.rv = trans1->Start(&httpreq1, &callback1, log);
967 ASSERT_EQ(out.rv, ERR_IO_PENDING);
968 // run transaction 1 through quickly to force a read of our SETTINGS
969 // frame
970 out.rv = callback1.WaitForResult();
971 ASSERT_EQ(OK, out.rv);
[email protected]2bd93022010-07-17 00:58:44972
[email protected]bdebd1b2010-08-09 20:18:08973 out.rv = trans2->Start(&httpreq2, &callback2, log);
974 ASSERT_EQ(out.rv, ERR_IO_PENDING);
975 out.rv = trans3->Start(&httpreq3, &callback3, log);
976 delete trans3.release();
977 ASSERT_EQ(out.rv, ERR_IO_PENDING);
978 out.rv = callback2.WaitForResult();
979 ASSERT_EQ(OK, out.rv);
[email protected]2bd93022010-07-17 00:58:44980
[email protected]bdebd1b2010-08-09 20:18:08981 EXPECT_EQ(8U, data->read_index());
[email protected]2bd93022010-07-17 00:58:44982
[email protected]bdebd1b2010-08-09 20:18:08983 const HttpResponseInfo* response1 = trans1->GetResponseInfo();
984 ASSERT_TRUE(response1 != NULL);
985 EXPECT_TRUE(response1->headers != NULL);
986 EXPECT_TRUE(response1->was_fetched_via_spdy);
987 out.status_line = response1->headers->GetStatusLine();
988 out.response_info = *response1;
989 out.rv = ReadTransaction(trans1.get(), &out.response_data);
990 EXPECT_EQ(OK, out.rv);
991 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
992 EXPECT_EQ("hello!hello!", out.response_data);
[email protected]2bd93022010-07-17 00:58:44993
[email protected]bdebd1b2010-08-09 20:18:08994 const HttpResponseInfo* response2 = trans2->GetResponseInfo();
995 ASSERT_TRUE(response2 != NULL);
996 out.status_line = response2->headers->GetStatusLine();
997 out.response_info = *response2;
998 out.rv = ReadTransaction(trans2.get(), &out.response_data);
999 EXPECT_EQ(OK, out.rv);
1000 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
1001 EXPECT_EQ("hello!hello!", out.response_data);
1002 helper.VerifyDataConsumed();
[email protected]2bd93022010-07-17 00:58:441003 EXPECT_EQ(OK, out.rv);
1004
[email protected]2bd93022010-07-17 00:58:441005}
1006
[email protected]d8ef27b2010-08-06 17:34:391007// Test that a simple PUT request works.
1008TEST_P(SpdyNetworkTransactionTest, Put) {
1009 // Setup the request
1010 HttpRequestInfo request;
1011 request.method = "PUT";
1012 request.url = GURL("http://www.google.com/");
1013
1014 const SpdyHeaderInfo kSynStartHeader = {
1015 spdy::SYN_STREAM, // Kind = Syn
1016 1, // Stream ID
1017 0, // Associated stream ID
1018 net::ConvertRequestPriorityToSpdyPriority(LOWEST), // Priority
1019 spdy::CONTROL_FLAG_FIN, // Control Flags
1020 false, // Compressed
1021 spdy::INVALID, // Status
1022 NULL, // Data
1023 0, // Length
1024 spdy::DATA_FLAG_NONE // Data Flags
1025 };
1026 const char* const kPutHeaders[] = {
1027 "method", "PUT",
1028 "url", "/",
1029 "host", "www.google.com",
1030 "scheme", "http",
1031 "version", "HTTP/1.1",
1032 "content-length", "0"
1033 };
1034 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyPacket(kSynStartHeader, NULL, 0,
1035 kPutHeaders, arraysize(kPutHeaders)/2));
1036 MockWrite writes[] = {
1037 CreateMockWrite(*req)
1038 };
1039
1040 scoped_ptr<spdy::SpdyFrame> body(ConstructSpdyBodyFrame(1, true));
1041 const SpdyHeaderInfo kSynReplyHeader = {
1042 spdy::SYN_REPLY, // Kind = SynReply
1043 1, // Stream ID
1044 0, // Associated stream ID
1045 net::ConvertRequestPriorityToSpdyPriority(LOWEST), // Priority
1046 spdy::CONTROL_FLAG_NONE, // Control Flags
1047 false, // Compressed
1048 spdy::INVALID, // Status
1049 NULL, // Data
1050 0, // Length
1051 spdy::DATA_FLAG_NONE // Data Flags
1052 };
1053 static const char* const kStandardGetHeaders[] = {
1054 "status", "200",
1055 "version", "HTTP/1.1"
1056 "content-length", "1234"
1057 };
1058 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyPacket(kSynReplyHeader,
1059 NULL, 0, kStandardGetHeaders, arraysize(kStandardGetHeaders)/2));
1060 MockRead reads[] = {
1061 CreateMockRead(*resp),
1062 CreateMockRead(*body),
1063 MockRead(true, 0, 0) // EOF
1064 };
1065
1066 scoped_refptr<DelayedSocketData> data(
1067 new DelayedSocketData(1, reads, arraysize(reads),
1068 writes, arraysize(writes)));
1069 NormalSpdyTransactionHelper helper(request,
1070 BoundNetLog(), GetParam());
1071 helper.RunToCompletion(data.get());
1072 TransactionHelperResult out = helper.output();
1073
1074 EXPECT_EQ(OK, out.rv);
1075 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
1076}
1077
1078// Test that a simple HEAD request works.
1079TEST_P(SpdyNetworkTransactionTest, Head) {
1080 // Setup the request
1081 HttpRequestInfo request;
1082 request.method = "HEAD";
1083 request.url = GURL("http://www.google.com/");
1084
1085 const SpdyHeaderInfo kSynStartHeader = {
1086 spdy::SYN_STREAM, // Kind = Syn
1087 1, // Stream ID
1088 0, // Associated stream ID
1089 net::ConvertRequestPriorityToSpdyPriority(LOWEST), // Priority
1090 spdy::CONTROL_FLAG_FIN, // Control Flags
1091 false, // Compressed
1092 spdy::INVALID, // Status
1093 NULL, // Data
1094 0, // Length
1095 spdy::DATA_FLAG_NONE // Data Flags
1096 };
1097 const char* const kHeadHeaders[] = {
1098 "method", "HEAD",
1099 "url", "/",
1100 "host", "www.google.com",
1101 "scheme", "http",
1102 "version", "HTTP/1.1",
1103 "content-length", "0"
1104 };
1105 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyPacket(kSynStartHeader, NULL, 0,
1106 kHeadHeaders, arraysize(kHeadHeaders)/2));
1107 MockWrite writes[] = {
1108 CreateMockWrite(*req)
1109 };
1110
1111 scoped_ptr<spdy::SpdyFrame> body(ConstructSpdyBodyFrame(1, true));
1112 const SpdyHeaderInfo kSynReplyHeader = {
1113 spdy::SYN_REPLY, // Kind = SynReply
1114 1, // Stream ID
1115 0, // Associated stream ID
1116 net::ConvertRequestPriorityToSpdyPriority(LOWEST), // Priority
1117 spdy::CONTROL_FLAG_NONE, // Control Flags
1118 false, // Compressed
1119 spdy::INVALID, // Status
1120 NULL, // Data
1121 0, // Length
1122 spdy::DATA_FLAG_NONE // Data Flags
1123 };
1124 static const char* const kStandardGetHeaders[] = {
1125 "status", "200",
1126 "version", "HTTP/1.1"
1127 "content-length", "1234"
1128 };
1129 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyPacket(kSynReplyHeader,
1130 NULL, 0, kStandardGetHeaders, arraysize(kStandardGetHeaders)/2));
1131 MockRead reads[] = {
1132 CreateMockRead(*resp),
1133 CreateMockRead(*body),
1134 MockRead(true, 0, 0) // EOF
1135 };
1136
1137 scoped_refptr<DelayedSocketData> data(
1138 new DelayedSocketData(1, reads, arraysize(reads),
1139 writes, arraysize(writes)));
1140 NormalSpdyTransactionHelper helper(request,
1141 BoundNetLog(), GetParam());
1142 helper.RunToCompletion(data.get());
1143 TransactionHelperResult out = helper.output();
1144
1145 EXPECT_EQ(OK, out.rv);
1146 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
1147}
1148
[email protected]72552f02009-10-28 15:25:011149// Test that a simple POST works.
[email protected]9e9e842e2010-07-23 23:09:151150TEST_P(SpdyNetworkTransactionTest, Post) {
[email protected]310240592010-08-05 21:04:191151 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyPost(kUploadDataSize, NULL, 0));
[email protected]2bd93022010-07-17 00:58:441152 scoped_ptr<spdy::SpdyFrame> body(ConstructSpdyBodyFrame(1, true));
[email protected]ff57bb82009-11-12 06:52:141153 MockWrite writes[] = {
[email protected]e7f75092010-07-01 22:39:131154 CreateMockWrite(*req),
1155 CreateMockWrite(*body), // POST upload frame
[email protected]ff57bb82009-11-12 06:52:141156 };
[email protected]72552f02009-10-28 15:25:011157
[email protected]a4aeaf42010-06-30 19:57:281158 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyPostSynReply(NULL, 0));
[email protected]ff57bb82009-11-12 06:52:141159 MockRead reads[] = {
[email protected]e7f75092010-07-01 22:39:131160 CreateMockRead(*resp),
1161 CreateMockRead(*body),
[email protected]72552f02009-10-28 15:25:011162 MockRead(true, 0, 0) // EOF
[email protected]aea80602009-09-18 00:55:081163 };
1164
[email protected]bf2491a92009-11-29 16:39:481165 scoped_refptr<DelayedSocketData> data(
[email protected]31a2bfe2010-02-09 08:03:391166 new DelayedSocketData(2, reads, arraysize(reads),
1167 writes, arraysize(writes)));
[email protected]310240592010-08-05 21:04:191168 NormalSpdyTransactionHelper helper(CreatePostRequest(),
[email protected]9e9e842e2010-07-23 23:09:151169 BoundNetLog(), GetParam());
[email protected]3caf5542010-07-16 15:19:471170 helper.RunToCompletion(data.get());
1171 TransactionHelperResult out = helper.output();
[email protected]aea80602009-09-18 00:55:081172 EXPECT_EQ(OK, out.rv);
1173 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
1174 EXPECT_EQ("hello!", out.response_data);
1175}
1176
[email protected]a33cad2b62010-07-30 22:24:391177// Test that a POST without any post data works.
1178TEST_P(SpdyNetworkTransactionTest, NullPost) {
1179 // Setup the request
1180 HttpRequestInfo request;
1181 request.method = "POST";
1182 request.url = GURL("http://www.google.com/");
1183 // Create an empty UploadData.
1184 request.upload_data = NULL;
1185
1186 // When request.upload_data is NULL for post, content-length is
1187 // expected to be 0.
1188 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyPost(0, NULL, 0));
1189 // Set the FIN bit since there will be no body.
1190 req->set_flags(spdy::CONTROL_FLAG_FIN);
1191 MockWrite writes[] = {
1192 CreateMockWrite(*req),
1193 };
1194
1195 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyPostSynReply(NULL, 0));
1196 scoped_ptr<spdy::SpdyFrame> body(ConstructSpdyBodyFrame(1, true));
1197 MockRead reads[] = {
1198 CreateMockRead(*resp),
1199 CreateMockRead(*body),
1200 MockRead(true, 0, 0) // EOF
1201 };
1202
1203 scoped_refptr<DelayedSocketData> data(
1204 new DelayedSocketData(1, reads, arraysize(reads),
1205 writes, arraysize(writes)));
1206
1207 NormalSpdyTransactionHelper helper(request,
1208 BoundNetLog(), GetParam());
1209 helper.RunToCompletion(data.get());
1210 TransactionHelperResult out = helper.output();
1211 EXPECT_EQ(OK, out.rv);
1212 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
1213 EXPECT_EQ("hello!", out.response_data);
1214}
1215
[email protected]edd3b0a52009-11-24 18:56:361216// Test that a simple POST works.
[email protected]9e9e842e2010-07-23 23:09:151217TEST_P(SpdyNetworkTransactionTest, EmptyPost) {
[email protected]edd3b0a52009-11-24 18:56:361218 // Setup the request
1219 HttpRequestInfo request;
1220 request.method = "POST";
1221 request.url = GURL("http://www.google.com/");
1222 // Create an empty UploadData.
1223 request.upload_data = new UploadData();
1224
[email protected]a33cad2b62010-07-30 22:24:391225 // Http POST Content-Length is using UploadDataStream::size().
1226 // It is the same as request.upload_data->GetContentLength().
[email protected]219ba8cb2010-07-31 04:51:461227 scoped_ptr<UploadDataStream> stream(UploadDataStream::Create(
1228 request.upload_data, NULL));
1229 ASSERT_EQ(request.upload_data->GetContentLength(), stream->size());
[email protected]a33cad2b62010-07-30 22:24:391230
1231 scoped_ptr<spdy::SpdyFrame>
1232 req(ConstructSpdyPost(request.upload_data->GetContentLength(), NULL, 0));
[email protected]a4aeaf42010-06-30 19:57:281233 // Set the FIN bit since there will be no body.
1234 req->set_flags(spdy::CONTROL_FLAG_FIN);
[email protected]edd3b0a52009-11-24 18:56:361235 MockWrite writes[] = {
[email protected]e7f75092010-07-01 22:39:131236 CreateMockWrite(*req),
[email protected]edd3b0a52009-11-24 18:56:361237 };
1238
[email protected]a4aeaf42010-06-30 19:57:281239 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyPostSynReply(NULL, 0));
[email protected]2bd93022010-07-17 00:58:441240 scoped_ptr<spdy::SpdyFrame> body(ConstructSpdyBodyFrame(1, true));
[email protected]edd3b0a52009-11-24 18:56:361241 MockRead reads[] = {
[email protected]e7f75092010-07-01 22:39:131242 CreateMockRead(*resp),
1243 CreateMockRead(*body),
[email protected]edd3b0a52009-11-24 18:56:361244 MockRead(true, 0, 0) // EOF
1245 };
1246
[email protected]bf2491a92009-11-29 16:39:481247 scoped_refptr<DelayedSocketData> data(
[email protected]3f662f12010-03-25 19:56:121248 new DelayedSocketData(1, reads, arraysize(reads),
1249 writes, arraysize(writes)));
[email protected]bf2491a92009-11-29 16:39:481250
[email protected]3caf5542010-07-16 15:19:471251 NormalSpdyTransactionHelper helper(request,
[email protected]9e9e842e2010-07-23 23:09:151252 BoundNetLog(), GetParam());
[email protected]3caf5542010-07-16 15:19:471253 helper.RunToCompletion(data.get());
1254 TransactionHelperResult out = helper.output();
[email protected]edd3b0a52009-11-24 18:56:361255 EXPECT_EQ(OK, out.rv);
1256 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
1257 EXPECT_EQ("hello!", out.response_data);
1258}
1259
[email protected]a5566f9702010-05-05 22:25:431260// While we're doing a post, the server sends back a SYN_REPLY.
[email protected]9e9e842e2010-07-23 23:09:151261TEST_P(SpdyNetworkTransactionTest, PostWithEarlySynReply) {
[email protected]a4aeaf42010-06-30 19:57:281262 static const char upload[] = { "hello!" };
[email protected]a5566f9702010-05-05 22:25:431263
1264 // Setup the request
1265 HttpRequestInfo request;
1266 request.method = "POST";
1267 request.url = GURL("http://www.google.com/");
1268 request.upload_data = new UploadData();
1269 request.upload_data->AppendBytes(upload, sizeof(upload));
1270
[email protected]a33cad2b62010-07-30 22:24:391271 // Http POST Content-Length is using UploadDataStream::size().
1272 // It is the same as request.upload_data->GetContentLength().
[email protected]219ba8cb2010-07-31 04:51:461273 scoped_ptr<UploadDataStream> stream(UploadDataStream::Create(
1274 request.upload_data, NULL));
1275 ASSERT_EQ(request.upload_data->GetContentLength(), stream->size());
[email protected]a33cad2b62010-07-30 22:24:391276
1277 scoped_ptr<spdy::SpdyFrame>
1278 req(ConstructSpdyPost(request.upload_data->GetContentLength(), NULL, 0));
[email protected]2bd93022010-07-17 00:58:441279 scoped_ptr<spdy::SpdyFrame> body(ConstructSpdyBodyFrame(1, true));
[email protected]58cebf8f2010-07-31 19:20:161280 MockWrite writes[] = {
[email protected]e7f75092010-07-01 22:39:131281 CreateMockWrite(*req.get(), 2),
[email protected]a5566f9702010-05-05 22:25:431282 };
1283
[email protected]a4aeaf42010-06-30 19:57:281284 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyPostSynReply(NULL, 0));
[email protected]a5566f9702010-05-05 22:25:431285 MockRead reads[] = {
[email protected]e7f75092010-07-01 22:39:131286 CreateMockRead(*resp.get(), 2),
1287 CreateMockRead(*body.get(), 3),
[email protected]a5566f9702010-05-05 22:25:431288 MockRead(false, 0, 0) // EOF
1289 };
1290
1291 scoped_refptr<DelayedSocketData> data(
1292 new DelayedSocketData(0, reads, arraysize(reads),
1293 writes, arraysize(writes)));
[email protected]3caf5542010-07-16 15:19:471294 NormalSpdyTransactionHelper helper(request,
[email protected]9e9e842e2010-07-23 23:09:151295 BoundNetLog(), GetParam());
[email protected]3caf5542010-07-16 15:19:471296 helper.RunPreTestSetup();
[email protected]e3ebba0f2010-08-05 17:59:581297 helper.AddData(data.get());
[email protected]3caf5542010-07-16 15:19:471298 helper.RunDefaultTest();
[email protected]310240592010-08-05 21:04:191299 helper.VerifyDataConsumed();
1300
[email protected]3caf5542010-07-16 15:19:471301 TransactionHelperResult out = helper.output();
[email protected]a5566f9702010-05-05 22:25:431302 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, out.rv);
1303}
1304
[email protected]f9a26d72010-08-03 18:07:131305// The client upon cancellation tries to send a RST_STREAM frame. The mock
1306// socket causes the TCP write to return zero. This test checks that the client
1307// tries to queue up the RST_STREAM frame again.
[email protected]3b7828432010-08-18 18:33:271308TEST_P(SpdyNetworkTransactionTest, SocketWriteReturnsZero) {
[email protected]f9a26d72010-08-03 18:07:131309 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST));
1310 scoped_ptr<spdy::SpdyFrame> rst(
1311 ConstructSpdyRstStream(1, spdy::CANCEL));
1312 MockWrite writes[] = {
[email protected]3b7828432010-08-18 18:33:271313 CreateMockWrite(*req.get(), 0, false),
1314 MockWrite(false, 0, 0, 2),
1315 CreateMockWrite(*rst.get(), 3, false),
[email protected]f9a26d72010-08-03 18:07:131316 };
1317
1318 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1));
1319 MockRead reads[] = {
[email protected]3b7828432010-08-18 18:33:271320 CreateMockRead(*resp.get(), 1, false),
1321 MockRead(false, 0, 0, 4) // EOF
[email protected]f9a26d72010-08-03 18:07:131322 };
1323
[email protected]3b7828432010-08-18 18:33:271324 scoped_refptr<DeterministicSocketData> data(
1325 new DeterministicSocketData(reads, arraysize(reads),
[email protected]f9a26d72010-08-03 18:07:131326 writes, arraysize(writes)));
1327 NormalSpdyTransactionHelper helper(CreateGetRequest(),
1328 BoundNetLog(), GetParam());
[email protected]3b7828432010-08-18 18:33:271329 helper.SetDeterministic();
[email protected]f9a26d72010-08-03 18:07:131330 helper.RunPreTestSetup();
[email protected]3b7828432010-08-18 18:33:271331 helper.AddDeterministicData(data.get());
[email protected]f9a26d72010-08-03 18:07:131332 HttpNetworkTransaction* trans = helper.trans();
1333
1334 TestCompletionCallback callback;
1335 int rv = trans->Start(&CreateGetRequest(), &callback, BoundNetLog());
1336 EXPECT_EQ(ERR_IO_PENDING, rv);
[email protected]3b7828432010-08-18 18:33:271337
1338 data->SetStop(2);
1339 data->Run();
[email protected]f9a26d72010-08-03 18:07:131340 helper.ResetTrans();
[email protected]3b7828432010-08-18 18:33:271341 data->SetStop(20);
1342 data->Run();
1343
[email protected]f9a26d72010-08-03 18:07:131344 helper.VerifyDataConsumed();
1345}
1346
[email protected]93300672009-10-24 13:22:511347// Test that the transaction doesn't crash when we don't have a reply.
[email protected]9e9e842e2010-07-23 23:09:151348TEST_P(SpdyNetworkTransactionTest, ResponseWithoutSynReply) {
[email protected]2bd93022010-07-17 00:58:441349 scoped_ptr<spdy::SpdyFrame> body(ConstructSpdyBodyFrame(1, true));
[email protected]ff57bb82009-11-12 06:52:141350 MockRead reads[] = {
[email protected]e7f75092010-07-01 22:39:131351 CreateMockRead(*body),
[email protected]72552f02009-10-28 15:25:011352 MockRead(true, 0, 0) // EOF
[email protected]93300672009-10-24 13:22:511353 };
1354
[email protected]bf2491a92009-11-29 16:39:481355 scoped_refptr<DelayedSocketData> data(
[email protected]31a2bfe2010-02-09 08:03:391356 new DelayedSocketData(1, reads, arraysize(reads), NULL, 0));
[email protected]3caf5542010-07-16 15:19:471357 NormalSpdyTransactionHelper helper(CreateGetRequest(),
[email protected]9e9e842e2010-07-23 23:09:151358 BoundNetLog(), GetParam());
[email protected]3caf5542010-07-16 15:19:471359 helper.RunToCompletion(data.get());
1360 TransactionHelperResult out = helper.output();
[email protected]93300672009-10-24 13:22:511361 EXPECT_EQ(ERR_SYN_REPLY_NOT_RECEIVED, out.rv);
1362}
1363
[email protected]d30022352010-06-24 19:17:581364// Test that the transaction doesn't crash when we get two replies on the same
1365// stream ID. See http://crbug.com/45639.
[email protected]9e9e842e2010-07-23 23:09:151366TEST_P(SpdyNetworkTransactionTest, ResponseWithTwoSynReplies) {
[email protected]2bd93022010-07-17 00:58:441367 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST));
[email protected]e7f75092010-07-01 22:39:131368 MockWrite writes[] = { CreateMockWrite(*req) };
[email protected]d30022352010-06-24 19:17:581369
[email protected]2bd93022010-07-17 00:58:441370 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1));
1371 scoped_ptr<spdy::SpdyFrame> body(ConstructSpdyBodyFrame(1, true));
[email protected]d30022352010-06-24 19:17:581372 MockRead reads[] = {
[email protected]e7f75092010-07-01 22:39:131373 CreateMockRead(*resp),
1374 CreateMockRead(*resp),
1375 CreateMockRead(*body),
[email protected]d30022352010-06-24 19:17:581376 MockRead(true, 0, 0) // EOF
1377 };
1378
[email protected]d30022352010-06-24 19:17:581379 scoped_refptr<DelayedSocketData> data(
1380 new DelayedSocketData(1, reads, arraysize(reads),
1381 writes, arraysize(writes)));
[email protected]d30022352010-06-24 19:17:581382
[email protected]3caf5542010-07-16 15:19:471383 NormalSpdyTransactionHelper helper(CreateGetRequest(),
[email protected]9e9e842e2010-07-23 23:09:151384 BoundNetLog(), GetParam());
[email protected]3caf5542010-07-16 15:19:471385 helper.RunPreTestSetup();
[email protected]e3ebba0f2010-08-05 17:59:581386 helper.AddData(data.get());
[email protected]3caf5542010-07-16 15:19:471387
1388 HttpNetworkTransaction* trans = helper.trans();
[email protected]d30022352010-06-24 19:17:581389
1390 TestCompletionCallback callback;
[email protected]3caf5542010-07-16 15:19:471391 int rv = trans->Start(&helper.request(), &callback, BoundNetLog());
[email protected]d30022352010-06-24 19:17:581392 EXPECT_EQ(ERR_IO_PENDING, rv);
1393 rv = callback.WaitForResult();
1394 EXPECT_EQ(OK, rv);
1395
1396 const HttpResponseInfo* response = trans->GetResponseInfo();
[email protected]a5c493b92010-08-06 23:04:291397 ASSERT_TRUE(response != NULL);
[email protected]d30022352010-06-24 19:17:581398 EXPECT_TRUE(response->headers != NULL);
1399 EXPECT_TRUE(response->was_fetched_via_spdy);
1400 std::string response_data;
[email protected]3caf5542010-07-16 15:19:471401 rv = ReadTransaction(trans, &response_data);
[email protected]d30022352010-06-24 19:17:581402 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, rv);
[email protected]3caf5542010-07-16 15:19:471403
1404 helper.VerifyDataConsumed();
[email protected]d30022352010-06-24 19:17:581405}
1406
[email protected]7349c6b12010-07-22 02:29:161407// Test that sent data frames and received WINDOW_UPDATE frames change
1408// the send_window_size_ correctly.
[email protected]6abf5372010-08-17 15:44:251409
1410// WINDOW_UPDATE is different than most other frames in that it can arrive
1411// while the client is still sending the request body. In order to enforce
1412// this scenario, we feed a couple of dummy frames and give a delay of 0 to
1413// socket data provider, so that initial read that is done as soon as the
1414// stream is created, succeeds and schedules another read. This way reads
1415// and writes are interleaved; after doing a full frame write, SpdyStream
1416// will break out of DoLoop and will read and process a WINDOW_UPDATE.
1417// Once our WINDOW_UPDATE is read, we cannot send SYN_REPLY right away
1418// since request has not been completely written, therefore we feed
1419// enough number of WINDOW_UPDATEs to finish the first read and cause a
1420// write, leading to a complete write of request body; after that we send
1421// a reply with a body, to cause a graceful shutdown.
1422
1423// TODO(agayev): develop a socket data provider where both, reads and
1424// writes are ordered so that writing tests like these are easy, right now
1425// we are working around the limitations as described above and it's not
1426// deterministic, tests may fail under specific circumstances.
1427TEST_P(SpdyNetworkTransactionTest, WindowUpdateReceived) {
[email protected]7349c6b12010-07-22 02:29:161428 SpdySession::SetFlowControl(true);
[email protected]5af3c572010-07-20 14:16:271429
[email protected]6abf5372010-08-17 15:44:251430 static int kFrameCount = 2;
1431 scoped_ptr<std::string> content(
1432 new std::string(kMaxSpdyFrameChunkSize, 'a'));
1433 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyPost(
1434 kMaxSpdyFrameChunkSize * kFrameCount, NULL, 0));
1435 scoped_ptr<spdy::SpdyFrame> body(
1436 ConstructSpdyBodyFrame(1, content->c_str(), content->size(), false));
1437 scoped_ptr<spdy::SpdyFrame> body_end(
1438 ConstructSpdyBodyFrame(1, content->c_str(), content->size(), true));
1439
[email protected]5af3c572010-07-20 14:16:271440 MockWrite writes[] = {
1441 CreateMockWrite(*req),
1442 CreateMockWrite(*body),
[email protected]6abf5372010-08-17 15:44:251443 CreateMockWrite(*body_end),
[email protected]5af3c572010-07-20 14:16:271444 };
1445
[email protected]5af3c572010-07-20 14:16:271446 static const int kDeltaWindowSize = 0xff;
[email protected]6abf5372010-08-17 15:44:251447 static const int kDeltaCount = 4;
[email protected]5af3c572010-07-20 14:16:271448 scoped_ptr<spdy::SpdyFrame> window_update(
1449 ConstructSpdyWindowUpdate(1, kDeltaWindowSize));
[email protected]6abf5372010-08-17 15:44:251450 scoped_ptr<spdy::SpdyFrame> window_update_dummy(
1451 ConstructSpdyWindowUpdate(2, kDeltaWindowSize));
1452 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyPostSynReply(NULL, 0));
[email protected]5af3c572010-07-20 14:16:271453 MockRead reads[] = {
[email protected]6abf5372010-08-17 15:44:251454 CreateMockRead(*window_update_dummy),
1455 CreateMockRead(*window_update_dummy),
1456 CreateMockRead(*window_update), // Four updates, therefore window
1457 CreateMockRead(*window_update), // size should increase by
1458 CreateMockRead(*window_update), // kDeltaWindowSize * 4
[email protected]5af3c572010-07-20 14:16:271459 CreateMockRead(*window_update),
[email protected]6abf5372010-08-17 15:44:251460 CreateMockRead(*resp),
1461 CreateMockRead(*body_end),
[email protected]5af3c572010-07-20 14:16:271462 MockRead(true, 0, 0) // EOF
1463 };
1464
1465 scoped_refptr<DelayedSocketData> data(
[email protected]6abf5372010-08-17 15:44:251466 new DelayedSocketData(0, reads, arraysize(reads),
[email protected]5af3c572010-07-20 14:16:271467 writes, arraysize(writes)));
[email protected]5af3c572010-07-20 14:16:271468
[email protected]6abf5372010-08-17 15:44:251469 // Setup the request
1470 HttpRequestInfo request;
1471 request.method = "POST";
1472 request.url = GURL(kDefaultURL);
1473 request.upload_data = new UploadData();
1474 for (int i = 0; i < kFrameCount; ++i)
1475 request.upload_data->AppendBytes(content->c_str(), content->size());
1476
1477 NormalSpdyTransactionHelper helper(request, BoundNetLog(), GetParam());
[email protected]310240592010-08-05 21:04:191478 helper.AddData(data.get());
1479 helper.RunPreTestSetup();
1480
1481 HttpNetworkTransaction* trans = helper.trans();
[email protected]5af3c572010-07-20 14:16:271482
1483 TestCompletionCallback callback;
[email protected]310240592010-08-05 21:04:191484 int rv = trans->Start(&helper.request(), &callback, BoundNetLog());
[email protected]5af3c572010-07-20 14:16:271485
1486 EXPECT_EQ(ERR_IO_PENDING, rv);
1487 rv = callback.WaitForResult();
1488 EXPECT_EQ(OK, rv);
1489
[email protected]6abf5372010-08-17 15:44:251490 SpdyHttpStream* stream =
1491 static_cast<SpdyHttpStream*>(trans->stream_.get());
1492 ASSERT_TRUE(stream != NULL);
1493 ASSERT_TRUE(stream->stream() != NULL);
1494 EXPECT_EQ(spdy::kInitialWindowSize +
1495 kDeltaWindowSize * kDeltaCount -
1496 kMaxSpdyFrameChunkSize * kFrameCount,
1497 stream->stream()->send_window_size());
[email protected]310240592010-08-05 21:04:191498 helper.VerifyDataConsumed();
[email protected]7349c6b12010-07-22 02:29:161499 SpdySession::SetFlowControl(false);
[email protected]5af3c572010-07-20 14:16:271500}
1501
[email protected]6abf5372010-08-17 15:44:251502// Test that WINDOW_UPDATE frame causing overflow is handled correctly. We
1503// use the same trick as in the above test to enforce our scenario.
[email protected]9e9e842e2010-07-23 23:09:151504TEST_P(SpdyNetworkTransactionTest, WindowUpdateOverflow) {
[email protected]7349c6b12010-07-22 02:29:161505 SpdySession::SetFlowControl(true);
[email protected]5af3c572010-07-20 14:16:271506
[email protected]310240592010-08-05 21:04:191507 // number of full frames we hope to write (but will not, used to
1508 // set content-length header correctly)
1509 static int kFrameCount = 3;
[email protected]5af3c572010-07-20 14:16:271510
[email protected]310240592010-08-05 21:04:191511 scoped_ptr<std::string> content(
1512 new std::string(kMaxSpdyFrameChunkSize, 'a'));
[email protected]310240592010-08-05 21:04:191513 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyPost(
1514 kMaxSpdyFrameChunkSize * kFrameCount, NULL, 0));
[email protected]310240592010-08-05 21:04:191515 scoped_ptr<spdy::SpdyFrame> body(
1516 ConstructSpdyBodyFrame(1, content->c_str(), content->size(), false));
[email protected]5af3c572010-07-20 14:16:271517 scoped_ptr<spdy::SpdyFrame> rst(
1518 ConstructSpdyRstStream(1, spdy::FLOW_CONTROL_ERROR));
[email protected]310240592010-08-05 21:04:191519
1520 // We're not going to write a data frame with FIN, we'll receive a bad
1521 // WINDOW_UPDATE while sending a request and will send a RST_STREAM frame.
[email protected]5af3c572010-07-20 14:16:271522 MockWrite writes[] = {
1523 CreateMockWrite(*req),
1524 CreateMockWrite(*body),
1525 CreateMockWrite(*rst),
1526 };
1527
[email protected]a33cad2b62010-07-30 22:24:391528 static const int kDeltaWindowSize = 0x7fffffff; // cause an overflow
[email protected]5af3c572010-07-20 14:16:271529 scoped_ptr<spdy::SpdyFrame> window_update(
1530 ConstructSpdyWindowUpdate(1, kDeltaWindowSize));
[email protected]310240592010-08-05 21:04:191531 scoped_ptr<spdy::SpdyFrame> window_update2(
1532 ConstructSpdyWindowUpdate(2, kDeltaWindowSize));
[email protected]5af3c572010-07-20 14:16:271533 scoped_ptr<spdy::SpdyFrame> reply(ConstructSpdyPostSynReply(NULL, 0));
[email protected]310240592010-08-05 21:04:191534
[email protected]5af3c572010-07-20 14:16:271535 MockRead reads[] = {
[email protected]310240592010-08-05 21:04:191536 CreateMockRead(*window_update2),
1537 CreateMockRead(*window_update2),
[email protected]5af3c572010-07-20 14:16:271538 CreateMockRead(*window_update),
[email protected]310240592010-08-05 21:04:191539 CreateMockRead(*window_update),
1540 CreateMockRead(*window_update),
[email protected]5af3c572010-07-20 14:16:271541 MockRead(true, 0, 0) // EOF
1542 };
1543
1544 scoped_refptr<DelayedSocketData> data(
[email protected]310240592010-08-05 21:04:191545 new DelayedSocketData(0, reads, arraysize(reads),
[email protected]5af3c572010-07-20 14:16:271546 writes, arraysize(writes)));
[email protected]5af3c572010-07-20 14:16:271547
[email protected]310240592010-08-05 21:04:191548 // Setup the request
1549 HttpRequestInfo request;
1550 request.method = "POST";
1551 request.url = GURL("http://www.google.com/");
1552 request.upload_data = new UploadData();
1553 for (int i = 0; i < kFrameCount; ++i)
1554 request.upload_data->AppendBytes(content->c_str(), content->size());
1555
1556 NormalSpdyTransactionHelper helper(request,
1557 BoundNetLog(), GetParam());
1558 helper.AddData(data.get());
1559 helper.RunPreTestSetup();
1560
1561 HttpNetworkTransaction* trans = helper.trans();
[email protected]5af3c572010-07-20 14:16:271562
1563 TestCompletionCallback callback;
[email protected]310240592010-08-05 21:04:191564 int rv = trans->Start(&helper.request(), &callback, BoundNetLog());
[email protected]5af3c572010-07-20 14:16:271565
1566 EXPECT_EQ(ERR_IO_PENDING, rv);
1567 rv = callback.WaitForResult();
1568 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, rv);
1569
[email protected]310240592010-08-05 21:04:191570 ASSERT_TRUE(helper.session() != NULL);
1571 ASSERT_TRUE(helper.session()->spdy_session_pool() != NULL);
1572 helper.session()->spdy_session_pool()->ClearSessions();
1573 helper.VerifyDataConsumed();
[email protected]5af3c572010-07-20 14:16:271574
[email protected]310240592010-08-05 21:04:191575 SpdySession::SetFlowControl(false);
1576}
1577
1578// Test that after hitting a send window size of 0, the write process
1579// stalls and upon receiving WINDOW_UPDATE frame write resumes.
[email protected]6abf5372010-08-17 15:44:251580
[email protected]310240592010-08-05 21:04:191581// This test constructs a POST request followed by enough data frames
1582// containing 'a' that would make the window size 0, followed by another
1583// data frame containing default content (which is "hello!") and this frame
1584// also contains a FIN flag. DelayedSocketData is used to enforce all
1585// writes go through before a read could happen. However, the last frame
1586// ("hello!") is not supposed to go through since by the time its turn
1587// arrives, window size is 0. At this point MessageLoop::Run() called via
1588// callback would block. Therefore we call MessageLoop::RunAllPending()
1589// which returns after performing all possible writes. We use DCHECKS to
1590// ensure that last data frame is still there and stream has stalled.
1591// After that, next read is artifically enforced, which causes a
1592// WINDOW_UPDATE to be read and I/O process resumes.
1593TEST_P(SpdyNetworkTransactionTest, FlowControlStallResume) {
1594 SpdySession::SetFlowControl(true);
1595
1596 // Number of frames we need to send to zero out the window size: data
1597 // frames plus SYN_STREAM plus the last data frame; also we need another
1598 // data frame that we will send once the WINDOW_UPDATE is received,
1599 // therefore +3.
1600 size_t nwrites = spdy::kInitialWindowSize / kMaxSpdyFrameChunkSize + 3;
1601
1602 // Calculate last frame's size; 0 size data frame is legal.
1603 size_t last_frame_size = spdy::kInitialWindowSize % kMaxSpdyFrameChunkSize;
1604
1605 // Construct content for a data frame of maximum size.
1606 scoped_ptr<std::string> content(
1607 new std::string(kMaxSpdyFrameChunkSize, 'a'));
1608
1609 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyPost(
1610 spdy::kInitialWindowSize + kUploadDataSize, NULL, 0));
1611
1612 // Full frames.
1613 scoped_ptr<spdy::SpdyFrame> body1(
1614 ConstructSpdyBodyFrame(1, content->c_str(), content->size(), false));
1615
1616 // Last frame to zero out the window size.
1617 scoped_ptr<spdy::SpdyFrame> body2(
1618 ConstructSpdyBodyFrame(1, content->c_str(), last_frame_size, false));
1619
1620 // Data frame to be sent once WINDOW_UPDATE frame is received.
1621 scoped_ptr<spdy::SpdyFrame> body3(ConstructSpdyBodyFrame(1, true));
1622
1623 // Fill in mock writes.
1624 scoped_array<MockWrite> writes(new MockWrite[nwrites]);
1625 size_t i = 0;
1626 writes[i] = CreateMockWrite(*req);
1627 for (i = 1; i < nwrites-2; i++)
1628 writes[i] = CreateMockWrite(*body1);
1629 writes[i++] = CreateMockWrite(*body2);
1630 writes[i] = CreateMockWrite(*body3);
1631
[email protected]6abf5372010-08-17 15:44:251632 // Construct read frame, give enough space to upload the rest of the
[email protected]310240592010-08-05 21:04:191633 // data.
1634 scoped_ptr<spdy::SpdyFrame> window_update(
1635 ConstructSpdyWindowUpdate(1, kUploadDataSize));
1636 scoped_ptr<spdy::SpdyFrame> reply(ConstructSpdyPostSynReply(NULL, 0));
1637 MockRead reads[] = {
1638 CreateMockRead(*window_update),
1639 CreateMockRead(*window_update),
1640 CreateMockRead(*reply),
1641 CreateMockRead(*body2),
1642 CreateMockRead(*body3),
1643 MockRead(true, 0, 0) // EOF
1644 };
1645
1646 // Force all writes to happen before any read, last write will not
1647 // actually queue a frame, due to window size being 0.
1648 scoped_refptr<DelayedSocketData> data(
1649 new DelayedSocketData(nwrites, reads, arraysize(reads),
1650 writes.get(), nwrites));
1651
1652 HttpRequestInfo request;
1653 request.method = "POST";
1654 request.url = GURL("http://www.google.com/");
1655 request.upload_data = new UploadData();
1656 scoped_ptr<std::string> upload_data(
1657 new std::string(spdy::kInitialWindowSize, 'a'));
1658 upload_data->append(kUploadData, kUploadDataSize);
1659 request.upload_data->AppendBytes(upload_data->c_str(), upload_data->size());
1660 NormalSpdyTransactionHelper helper(request,
1661 BoundNetLog(), GetParam());
1662 helper.AddData(data.get());
1663 helper.RunPreTestSetup();
1664
1665 HttpNetworkTransaction* trans = helper.trans();
1666
1667 TestCompletionCallback callback;
1668 int rv = trans->Start(&helper.request(), &callback, BoundNetLog());
1669 EXPECT_EQ(ERR_IO_PENDING, rv);
1670
1671 MessageLoop::current()->RunAllPending(); // Write as much as we can.
[email protected]6abf5372010-08-17 15:44:251672
1673 SpdyHttpStream* stream =
1674 static_cast<SpdyHttpStream*>(trans->stream_.get());
1675 ASSERT_TRUE(stream != NULL);
1676 ASSERT_TRUE(stream->stream() != NULL);
1677 EXPECT_EQ(0, stream->stream()->send_window_size());
1678 EXPECT_FALSE(stream->request_body_stream_->eof());
[email protected]310240592010-08-05 21:04:191679
1680 data->ForceNextRead(); // Read in WINDOW_UPDATE frame.
1681 rv = callback.WaitForResult();
1682 helper.VerifyDataConsumed();
[email protected]7349c6b12010-07-22 02:29:161683
1684 SpdySession::SetFlowControl(false);
[email protected]5af3c572010-07-20 14:16:271685}
1686
[email protected]9e9e842e2010-07-23 23:09:151687TEST_P(SpdyNetworkTransactionTest, CancelledTransaction) {
[email protected]75f30cc22010-06-28 21:41:381688 // Construct the request.
[email protected]2bd93022010-07-17 00:58:441689 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST));
[email protected]34437af82009-11-06 02:28:491690 MockWrite writes[] = {
[email protected]e7f75092010-07-01 22:39:131691 CreateMockWrite(*req),
[email protected]34437af82009-11-06 02:28:491692 };
1693
[email protected]2bd93022010-07-17 00:58:441694 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1));
[email protected]34437af82009-11-06 02:28:491695 MockRead reads[] = {
[email protected]e7f75092010-07-01 22:39:131696 CreateMockRead(*resp),
[email protected]34437af82009-11-06 02:28:491697 // This following read isn't used by the test, except during the
[email protected]955fc2e72010-02-08 20:37:301698 // RunAllPending() call at the end since the SpdySession survives the
[email protected]3caf5542010-07-16 15:19:471699 // HttpNetworkTransaction and still tries to continue Read()'ing. Any
[email protected]34437af82009-11-06 02:28:491700 // MockRead will do here.
1701 MockRead(true, 0, 0) // EOF
1702 };
1703
[email protected]31a2bfe2010-02-09 08:03:391704 StaticSocketDataProvider data(reads, arraysize(reads),
1705 writes, arraysize(writes));
[email protected]3caf5542010-07-16 15:19:471706
1707 NormalSpdyTransactionHelper helper(CreateGetRequest(),
[email protected]9e9e842e2010-07-23 23:09:151708 BoundNetLog(), GetParam());
[email protected]3caf5542010-07-16 15:19:471709 helper.RunPreTestSetup();
[email protected]e3ebba0f2010-08-05 17:59:581710 helper.AddData(&data);
[email protected]3caf5542010-07-16 15:19:471711 HttpNetworkTransaction* trans = helper.trans();
[email protected]34437af82009-11-06 02:28:491712
1713 TestCompletionCallback callback;
[email protected]d3cee19d2010-06-22 18:42:181714 int rv = trans->Start(&CreateGetRequest(), &callback, BoundNetLog());
[email protected]34437af82009-11-06 02:28:491715 EXPECT_EQ(ERR_IO_PENDING, rv);
[email protected]3caf5542010-07-16 15:19:471716 helper.ResetTrans(); // Cancel the transaction.
[email protected]34437af82009-11-06 02:28:491717
[email protected]30c942b2010-07-21 16:59:591718 // Flush the MessageLoop while the SpdySessionDependencies (in particular, the
[email protected]34437af82009-11-06 02:28:491719 // MockClientSocketFactory) are still alive.
1720 MessageLoop::current()->RunAllPending();
[email protected]3caf5542010-07-16 15:19:471721 helper.VerifyDataNotConsumed();
[email protected]34437af82009-11-06 02:28:491722}
[email protected]72552f02009-10-28 15:25:011723
[email protected]6c6ea172010-07-27 20:04:031724// Verify that the client sends a Rst Frame upon cancelling the stream.
[email protected]3b7828432010-08-18 18:33:271725TEST_P(SpdyNetworkTransactionTest, CancelledTransactionSendRst) {
[email protected]6c6ea172010-07-27 20:04:031726 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST));
1727 scoped_ptr<spdy::SpdyFrame> rst(
1728 ConstructSpdyRstStream(1, spdy::CANCEL));
1729 MockWrite writes[] = {
[email protected]3b7828432010-08-18 18:33:271730 CreateMockWrite(*req, 0, false),
1731 CreateMockWrite(*rst, 2, false),
[email protected]6c6ea172010-07-27 20:04:031732 };
1733
1734 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1));
1735 MockRead reads[] = {
[email protected]3b7828432010-08-18 18:33:271736 CreateMockRead(*resp, 1, false),
1737 MockRead(false, 0, 0, 3) // EOF
[email protected]6c6ea172010-07-27 20:04:031738 };
1739
[email protected]3b7828432010-08-18 18:33:271740 scoped_refptr<DeterministicSocketData> data(
1741 new DeterministicSocketData(reads, arraysize(reads),
[email protected]6c6ea172010-07-27 20:04:031742 writes, arraysize(writes)));
1743
1744 NormalSpdyTransactionHelper helper(CreateGetRequest(),
1745 BoundNetLog(),
1746 GetParam());
[email protected]3b7828432010-08-18 18:33:271747 helper.SetDeterministic();
[email protected]6c6ea172010-07-27 20:04:031748 helper.RunPreTestSetup();
[email protected]3b7828432010-08-18 18:33:271749 helper.AddDeterministicData(data.get());
[email protected]6c6ea172010-07-27 20:04:031750 HttpNetworkTransaction* trans = helper.trans();
1751
1752 TestCompletionCallback callback;
1753
1754 int rv = trans->Start(&CreateGetRequest(), &callback, BoundNetLog());
1755 EXPECT_EQ(ERR_IO_PENDING, rv);
[email protected]6c6ea172010-07-27 20:04:031756
[email protected]3b7828432010-08-18 18:33:271757 data->SetStop(2);
1758 data->Run();
1759 helper.ResetTrans();
1760 data->SetStop(20);
1761 data->Run();
1762
[email protected]6c6ea172010-07-27 20:04:031763 helper.VerifyDataConsumed();
1764}
1765
[email protected]3caf5542010-07-16 15:19:471766class SpdyNetworkTransactionTest::StartTransactionCallback
1767 : public CallbackRunner< Tuple1<int> > {
[email protected]b278eb72010-07-09 20:17:001768 public:
1769 explicit StartTransactionCallback(
[email protected]3caf5542010-07-16 15:19:471770 scoped_refptr<HttpNetworkSession>& session,
1771 NormalSpdyTransactionHelper& helper)
1772 : session_(session), helper_(helper) {}
[email protected]b278eb72010-07-09 20:17:001773
1774 // We try to start another transaction, which should succeed.
1775 virtual void RunWithParams(const Tuple1<int>& params) {
[email protected]3caf5542010-07-16 15:19:471776 scoped_ptr<HttpNetworkTransaction> trans(
1777 new HttpNetworkTransaction(session_));
[email protected]b278eb72010-07-09 20:17:001778 TestCompletionCallback callback;
1779 HttpRequestInfo request;
1780 request.method = "GET";
1781 request.url = GURL("http://www.google.com/");
1782 request.load_flags = 0;
1783 int rv = trans->Start(&request, &callback, BoundNetLog());
1784 EXPECT_EQ(ERR_IO_PENDING, rv);
[email protected]3caf5542010-07-16 15:19:471785 rv = callback.WaitForResult();
[email protected]b278eb72010-07-09 20:17:001786 }
1787
1788 private:
[email protected]3caf5542010-07-16 15:19:471789 scoped_refptr<HttpNetworkSession>& session_;
1790 NormalSpdyTransactionHelper& helper_;
[email protected]b278eb72010-07-09 20:17:001791};
1792
1793// Verify that the client can correctly deal with the user callback attempting
1794// to start another transaction on a session that is closing down. See
1795// http://crbug.com/47455
[email protected]9e9e842e2010-07-23 23:09:151796TEST_P(SpdyNetworkTransactionTest, StartTransactionOnReadCallback) {
[email protected]2bd93022010-07-17 00:58:441797 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST));
[email protected]b278eb72010-07-09 20:17:001798 MockWrite writes[] = { CreateMockWrite(*req) };
1799 MockWrite writes2[] = { CreateMockWrite(*req) };
1800
1801 // The indicated length of this packet is longer than its actual length. When
1802 // the session receives an empty packet after this one, it shuts down the
1803 // session, and calls the read callback with the incomplete data.
1804 const uint8 kGetBodyFrame2[] = {
1805 0x00, 0x00, 0x00, 0x01,
1806 0x01, 0x00, 0x00, 0x07,
1807 'h', 'e', 'l', 'l', 'o', '!',
1808 };
1809
[email protected]2bd93022010-07-17 00:58:441810 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1));
[email protected]b278eb72010-07-09 20:17:001811 MockRead reads[] = {
1812 CreateMockRead(*resp, 2),
1813 MockRead(true, ERR_IO_PENDING, 3), // Force a pause
1814 MockRead(true, reinterpret_cast<const char*>(kGetBodyFrame2),
1815 arraysize(kGetBodyFrame2), 4),
[email protected]3caf5542010-07-16 15:19:471816 MockRead(true, ERR_IO_PENDING, 5), // Force a pause
1817 MockRead(true, 0, 0, 6), // EOF
[email protected]b278eb72010-07-09 20:17:001818 };
1819 MockRead reads2[] = {
1820 CreateMockRead(*resp, 2),
1821 MockRead(true, 0, 0, 3), // EOF
1822 };
1823
[email protected]b278eb72010-07-09 20:17:001824 scoped_refptr<OrderedSocketData> data(
1825 new OrderedSocketData(reads, arraysize(reads),
1826 writes, arraysize(writes)));
[email protected]3caf5542010-07-16 15:19:471827 scoped_refptr<DelayedSocketData> data2(
1828 new DelayedSocketData(0, reads2, arraysize(reads2),
[email protected]b278eb72010-07-09 20:17:001829 writes2, arraysize(writes2)));
[email protected]3caf5542010-07-16 15:19:471830
1831 NormalSpdyTransactionHelper helper(CreateGetRequest(),
[email protected]9e9e842e2010-07-23 23:09:151832 BoundNetLog(), GetParam());
[email protected]e3ebba0f2010-08-05 17:59:581833 helper.RunPreTestSetup();
[email protected]3caf5542010-07-16 15:19:471834 helper.AddData(data.get());
1835 helper.AddData(data2.get());
[email protected]3caf5542010-07-16 15:19:471836 HttpNetworkTransaction* trans = helper.trans();
[email protected]b278eb72010-07-09 20:17:001837
1838 // Start the transaction with basic parameters.
1839 TestCompletionCallback callback;
[email protected]3caf5542010-07-16 15:19:471840 int rv = trans->Start(&helper.request(), &callback, BoundNetLog());
[email protected]b278eb72010-07-09 20:17:001841 EXPECT_EQ(ERR_IO_PENDING, rv);
1842 rv = callback.WaitForResult();
1843
[email protected]3caf5542010-07-16 15:19:471844 StartTransactionCallback callback2(helper.session(), helper);
[email protected]b278eb72010-07-09 20:17:001845 const int kSize = 3000;
1846 scoped_refptr<net::IOBuffer> buf = new net::IOBuffer(kSize);
1847 rv = trans->Read(buf, kSize, &callback2);
[email protected]3caf5542010-07-16 15:19:471848 // This forces an err_IO_pending, which sets the callback.
[email protected]b278eb72010-07-09 20:17:001849 data->CompleteRead();
[email protected]3caf5542010-07-16 15:19:471850 // This finishes the read.
1851 data->CompleteRead();
1852 helper.VerifyDataConsumed();
[email protected]b278eb72010-07-09 20:17:001853}
1854
[email protected]3caf5542010-07-16 15:19:471855class SpdyNetworkTransactionTest::DeleteSessionCallback
1856 : public CallbackRunner< Tuple1<int> > {
[email protected]9be804c82010-06-24 17:59:461857 public:
[email protected]3caf5542010-07-16 15:19:471858 explicit DeleteSessionCallback(NormalSpdyTransactionHelper& helper) :
1859 helper_(helper) {}
[email protected]9be804c82010-06-24 17:59:461860
[email protected]b278eb72010-07-09 20:17:001861 // We kill the transaction, which deletes the session and stream.
[email protected]9be804c82010-06-24 17:59:461862 virtual void RunWithParams(const Tuple1<int>& params) {
[email protected]3caf5542010-07-16 15:19:471863 helper_.ResetTrans();
[email protected]9be804c82010-06-24 17:59:461864 }
1865
1866 private:
[email protected]3caf5542010-07-16 15:19:471867 NormalSpdyTransactionHelper& helper_;
[email protected]9be804c82010-06-24 17:59:461868};
1869
1870// Verify that the client can correctly deal with the user callback deleting the
1871// transaction. Failures will usually be valgrind errors. See
1872// http://crbug.com/46925
[email protected]9e9e842e2010-07-23 23:09:151873TEST_P(SpdyNetworkTransactionTest, DeleteSessionOnReadCallback) {
[email protected]2bd93022010-07-17 00:58:441874 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST));
[email protected]e7f75092010-07-01 22:39:131875 MockWrite writes[] = { CreateMockWrite(*req) };
[email protected]9be804c82010-06-24 17:59:461876
[email protected]2bd93022010-07-17 00:58:441877 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1));
1878 scoped_ptr<spdy::SpdyFrame> body(ConstructSpdyBodyFrame(1, true));
[email protected]9be804c82010-06-24 17:59:461879 MockRead reads[] = {
[email protected]e7f75092010-07-01 22:39:131880 CreateMockRead(*resp.get(), 2),
[email protected]9be804c82010-06-24 17:59:461881 MockRead(true, ERR_IO_PENDING, 3), // Force a pause
[email protected]e7f75092010-07-01 22:39:131882 CreateMockRead(*body.get(), 4),
[email protected]9be804c82010-06-24 17:59:461883 MockRead(true, 0, 0, 5), // EOF
1884 };
1885
[email protected]9be804c82010-06-24 17:59:461886 scoped_refptr<OrderedSocketData> data(
1887 new OrderedSocketData(reads, arraysize(reads),
1888 writes, arraysize(writes)));
[email protected]3caf5542010-07-16 15:19:471889
1890 NormalSpdyTransactionHelper helper(CreateGetRequest(),
[email protected]9e9e842e2010-07-23 23:09:151891 BoundNetLog(), GetParam());
[email protected]3caf5542010-07-16 15:19:471892 helper.RunPreTestSetup();
[email protected]e3ebba0f2010-08-05 17:59:581893 helper.AddData(data.get());
[email protected]3caf5542010-07-16 15:19:471894 HttpNetworkTransaction* trans = helper.trans();
[email protected]9be804c82010-06-24 17:59:461895
1896 // Start the transaction with basic parameters.
1897 TestCompletionCallback callback;
[email protected]3caf5542010-07-16 15:19:471898 int rv = trans->Start(&helper.request(), &callback, BoundNetLog());
[email protected]9be804c82010-06-24 17:59:461899 EXPECT_EQ(ERR_IO_PENDING, rv);
1900 rv = callback.WaitForResult();
1901
1902 // Setup a user callback which will delete the session, and clear out the
1903 // memory holding the stream object. Note that the callback deletes trans.
[email protected]3caf5542010-07-16 15:19:471904 DeleteSessionCallback callback2(helper);
[email protected]9be804c82010-06-24 17:59:461905 const int kSize = 3000;
1906 scoped_refptr<net::IOBuffer> buf = new net::IOBuffer(kSize);
1907 rv = trans->Read(buf, kSize, &callback2);
1908 ASSERT_EQ(ERR_IO_PENDING, rv);
1909 data->CompleteRead();
1910
1911 // Finish running rest of tasks.
1912 MessageLoop::current()->RunAllPending();
[email protected]3caf5542010-07-16 15:19:471913 helper.VerifyDataConsumed();
[email protected]9be804c82010-06-24 17:59:461914}
1915
[email protected]e3ebba0f2010-08-05 17:59:581916// Send a spdy request to www.google.com that gets redirected to www.foo.com.
1917TEST_P(SpdyNetworkTransactionTest, RedirectGetRequest) {
1918 // These are headers which the URLRequest tacks on.
1919 const char* const kExtraHeaders[] = {
1920 "accept-charset",
1921 "",
1922 "accept-encoding",
1923 "gzip,deflate",
1924 "accept-language",
1925 "",
1926 };
1927 const SpdyHeaderInfo kSynStartHeader = make_spdy_header(spdy::SYN_STREAM);
1928 const char* const kStandardGetHeaders[] = {
1929 "host",
1930 "www.google.com",
1931 "method",
1932 "GET",
1933 "scheme",
1934 "http",
1935 "url",
1936 "/",
1937 "user-agent",
1938 "",
1939 "version",
1940 "HTTP/1.1"
1941 };
1942 const char* const kStandardGetHeaders2[] = {
1943 "host",
1944 "www.foo.com",
1945 "method",
1946 "GET",
1947 "scheme",
1948 "http",
1949 "url",
1950 "/index.php",
1951 "user-agent",
1952 "",
1953 "version",
1954 "HTTP/1.1"
1955 };
1956
1957 // Setup writes/reads to www.google.com
1958 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyPacket(
1959 kSynStartHeader, kExtraHeaders, arraysize(kExtraHeaders)/2,
1960 kStandardGetHeaders, arraysize(kStandardGetHeaders)/2));
1961 scoped_ptr<spdy::SpdyFrame> req2(ConstructSpdyPacket(
1962 kSynStartHeader, kExtraHeaders, arraysize(kExtraHeaders)/2,
1963 kStandardGetHeaders2, arraysize(kStandardGetHeaders2)/2));
1964 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReplyRedirect(1));
1965 MockWrite writes[] = {
1966 CreateMockWrite(*req, 1),
1967 };
1968 MockRead reads[] = {
1969 CreateMockRead(*resp, 2),
1970 MockRead(true, 0, 0, 3) // EOF
1971 };
1972
1973 // Setup writes/reads to www.foo.com
1974 scoped_ptr<spdy::SpdyFrame> resp2(ConstructSpdyGetSynReply(NULL, 0, 1));
1975 scoped_ptr<spdy::SpdyFrame> body2(ConstructSpdyBodyFrame(1, true));
1976 MockWrite writes2[] = {
1977 CreateMockWrite(*req2, 1),
1978 };
1979 MockRead reads2[] = {
1980 CreateMockRead(*resp2, 2),
1981 CreateMockRead(*body2, 3),
1982 MockRead(true, 0, 0, 4) // EOF
1983 };
1984 scoped_refptr<OrderedSocketData> data(
1985 new OrderedSocketData(reads, arraysize(reads),
1986 writes, arraysize(writes)));
1987 scoped_refptr<OrderedSocketData> data2(
1988 new OrderedSocketData(reads2, arraysize(reads2),
1989 writes2, arraysize(writes2)));
1990
1991 // TODO(erikchen): Make test support SPDYSSL, SPDYNPN
1992 HttpNetworkTransaction::SetUseSSLOverSpdyWithoutNPN(false);
1993 HttpNetworkTransaction::SetUseSpdyWithoutNPN(true);
1994 TestDelegate d;
1995 {
1996 URLRequest r(GURL("http://www.google.com/"), &d);
1997 SpdyURLRequestContext* spdy_url_request_context =
1998 new SpdyURLRequestContext();
1999 r.set_context(spdy_url_request_context);
2000 spdy_url_request_context->socket_factory().
2001 AddSocketDataProvider(data.get());
2002 spdy_url_request_context->socket_factory().
2003 AddSocketDataProvider(data2.get());
2004
2005 d.set_quit_on_redirect(true);
2006 r.Start();
2007 MessageLoop::current()->Run();
2008
2009 EXPECT_EQ(1, d.received_redirect_count());
2010
2011 r.FollowDeferredRedirect();
2012 MessageLoop::current()->Run();
2013 EXPECT_EQ(1, d.response_started_count());
2014 EXPECT_FALSE(d.received_data_before_response());
2015 EXPECT_EQ(URLRequestStatus::SUCCESS, r.status().status());
2016 std::string contents("hello!");
2017 EXPECT_EQ(contents, d.data_received());
2018 }
2019 EXPECT_TRUE(data->at_read_eof());
2020 EXPECT_TRUE(data->at_write_eof());
2021 EXPECT_TRUE(data2->at_read_eof());
2022 EXPECT_TRUE(data2->at_write_eof());
2023}
2024
2025// Send a spdy request to www.google.com. Get a pushed stream that redirects to
2026// www.foo.com.
2027TEST_P(SpdyNetworkTransactionTest, RedirectServerPush) {
2028 // These are headers which the URLRequest tacks on.
2029 const char* const kExtraHeaders[] = {
2030 "accept-charset",
2031 "",
2032 "accept-encoding",
2033 "gzip,deflate",
2034 "accept-language",
2035 "",
2036 };
2037 const SpdyHeaderInfo kSynStartHeader = make_spdy_header(spdy::SYN_STREAM);
2038 const char* const kStandardGetHeaders[] = {
2039 "host",
2040 "www.google.com",
2041 "method",
2042 "GET",
2043 "scheme",
2044 "http",
2045 "url",
2046 "/",
2047 "user-agent",
2048 "",
2049 "version",
2050 "HTTP/1.1"
2051 };
2052 const char* const kStandardGetHeaders2[] = {
2053 "host",
2054 "www.foo.com",
2055 "method",
2056 "GET",
2057 "scheme",
2058 "http",
2059 "url",
2060 "/index.php",
2061 "user-agent",
2062 "",
2063 "version",
2064 "HTTP/1.1"
2065 };
2066
2067 // Setup writes/reads to www.google.com
2068 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyPacket(
2069 kSynStartHeader, kExtraHeaders, arraysize(kExtraHeaders)/2,
2070 kStandardGetHeaders, arraysize(kStandardGetHeaders)/2));
2071 scoped_ptr<spdy::SpdyFrame> req2(ConstructSpdyPacket(
2072 kSynStartHeader, kExtraHeaders, arraysize(kExtraHeaders)/2,
2073 kStandardGetHeaders2, arraysize(kStandardGetHeaders2)/2));
2074 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1));
2075 scoped_ptr<spdy::SpdyFrame> rep(ConstructSpdyPush(NULL, 0, 2, 1, "/foo.dat",
2076 "301 Moved Permanently", "http://www.foo.com/index.php",
2077 "http://www.foo.com/index.php"));
2078 scoped_ptr<spdy::SpdyFrame> body(ConstructSpdyBodyFrame(1, true));
2079 scoped_ptr<spdy::SpdyFrame> res(
2080 ConstructSpdyRstStream(2, spdy::CANCEL));
2081 MockWrite writes[] = {
2082 CreateMockWrite(*req, 1),
2083 CreateMockWrite(*res, 6),
2084 };
2085 MockRead reads[] = {
2086 CreateMockRead(*resp, 2),
2087 CreateMockRead(*rep, 3),
2088 CreateMockRead(*body, 4),
2089 MockRead(true, ERR_IO_PENDING, 5), // Force a pause
2090 MockRead(true, 0, 0, 7) // EOF
2091 };
2092
2093 // Setup writes/reads to www.foo.com
2094 scoped_ptr<spdy::SpdyFrame> resp2(ConstructSpdyGetSynReply(NULL, 0, 1));
2095 scoped_ptr<spdy::SpdyFrame> body2(ConstructSpdyBodyFrame(1, true));
2096 MockWrite writes2[] = {
2097 CreateMockWrite(*req2, 1),
2098 };
2099 MockRead reads2[] = {
2100 CreateMockRead(*resp2, 2),
2101 CreateMockRead(*body2, 3),
2102 MockRead(true, 0, 0, 5) // EOF
2103 };
2104 scoped_refptr<OrderedSocketData> data(
2105 new OrderedSocketData(reads, arraysize(reads),
2106 writes, arraysize(writes)));
2107 scoped_refptr<OrderedSocketData> data2(
2108 new OrderedSocketData(reads2, arraysize(reads2),
2109 writes2, arraysize(writes2)));
2110
2111 // TODO(erikchen): Make test support SPDYSSL, SPDYNPN
2112 HttpNetworkTransaction::SetUseSSLOverSpdyWithoutNPN(false);
2113 HttpNetworkTransaction::SetUseSpdyWithoutNPN(true);
2114 TestDelegate d;
2115 TestDelegate d2;
2116 {
2117 URLRequest r(GURL("http://www.google.com/"), &d);
2118 SpdyURLRequestContext* spdy_url_request_context =
2119 new SpdyURLRequestContext();
2120 r.set_context(spdy_url_request_context);
2121 spdy_url_request_context->socket_factory().
2122 AddSocketDataProvider(data.get());
2123
2124 r.Start();
2125 MessageLoop::current()->Run();
2126
2127 EXPECT_EQ(0, d.received_redirect_count());
2128 std::string contents("hello!");
2129 EXPECT_EQ(contents, d.data_received());
2130
2131 URLRequest r2(GURL("http://www.google.com/foo.dat"), &d2);
2132 r2.set_context(spdy_url_request_context);
2133 spdy_url_request_context->socket_factory().
2134 AddSocketDataProvider(data2.get());
2135
2136 d2.set_quit_on_redirect(true);
2137 r2.Start();
2138 MessageLoop::current()->Run();
2139 EXPECT_EQ(1, d2.received_redirect_count());
2140
2141 r2.FollowDeferredRedirect();
2142 MessageLoop::current()->Run();
2143 EXPECT_EQ(1, d2.response_started_count());
2144 EXPECT_FALSE(d2.received_data_before_response());
2145 EXPECT_EQ(URLRequestStatus::SUCCESS, r2.status().status());
2146 std::string contents2("hello!");
2147 EXPECT_EQ(contents2, d2.data_received());
2148 }
2149 data->CompleteRead();
2150 data2->CompleteRead();
2151 EXPECT_TRUE(data->at_read_eof());
2152 EXPECT_TRUE(data->at_write_eof());
2153 EXPECT_TRUE(data2->at_read_eof());
2154 EXPECT_TRUE(data2->at_write_eof());
2155}
2156
2157TEST_P(SpdyNetworkTransactionTest, ServerPushSingleDataFrame) {
2158 static const unsigned char kPushBodyFrame[] = {
2159 0x00, 0x00, 0x00, 0x02, // header, ID
2160 0x01, 0x00, 0x00, 0x05, // FIN, length
2161 'h', 'e', 'l', 'l', 'o', // "hello"
2162 };
2163
2164 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST));
2165 MockWrite writes[] = {
2166 CreateMockWrite(*req, 1),
2167 };
2168
2169 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1));
2170 scoped_ptr<spdy::SpdyFrame> rep(ConstructSpdyPush(NULL, 0, 2, 1, "/foo.dat"));
2171 MockRead reads[] = {
2172 CreateMockRead(*resp, 2),
2173 CreateMockRead(*rep, 3),
2174 MockRead(true, reinterpret_cast<const char*>(kPushBodyFrame),
2175 arraysize(kPushBodyFrame), 4),
2176 MockRead(true, ERR_IO_PENDING, 5), // Force a pause
2177 MockRead(true, 0, 0, 6) // EOF
2178 };
2179
2180 HttpResponseInfo response;
2181 HttpResponseInfo response2;
2182 std::string expected_push_result("hello");
2183 RunServerPushTest(writes, arraysize(writes), reads, arraysize(reads),
2184 &response, &response2, expected_push_result);
2185
2186 // Verify the SYN_REPLY.
2187 EXPECT_TRUE(response.headers != NULL);
2188 EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine());
2189
2190 // Verify the pushed stream.
2191 EXPECT_TRUE(response2.headers != NULL);
2192 EXPECT_EQ("HTTP/1.1 200 OK", response2.headers->GetStatusLine());
2193}
2194
2195TEST_P(SpdyNetworkTransactionTest, ServerPushMultipleDataFrame) {
2196 static const unsigned char kPushBodyFrame1[] = {
2197 0x00, 0x00, 0x00, 0x02, // header, ID
2198 0x01, 0x00, 0x00, 0x1E, // FIN, length
2199 'h', 'e', 'l', 'l', 'o', // "hello"
2200 };
2201 static const char kPushBodyFrame2[] = " my darling";
2202 static const char kPushBodyFrame3[] = " hello";
2203 static const char kPushBodyFrame4[] = " my baby";
2204
2205 scoped_ptr<spdy::SpdyFrame> req(
2206 ConstructSpdyGet(NULL, 0, false, 1, LOWEST));
2207 MockWrite writes[] = {
2208 CreateMockWrite(*req, 1),
2209 };
2210
2211 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1));
2212 scoped_ptr<spdy::SpdyFrame> rep(ConstructSpdyPush(NULL, 0, 2, 1, "/foo.dat"));
2213 MockRead reads[] = {
2214 CreateMockRead(*resp, 2),
2215 CreateMockRead(*rep, 3),
2216 MockRead(true, reinterpret_cast<const char*>(kPushBodyFrame1),
2217 arraysize(kPushBodyFrame1), 4),
2218 MockRead(true, reinterpret_cast<const char*>(kPushBodyFrame2),
2219 arraysize(kPushBodyFrame2) - 1, 5),
2220 MockRead(true, reinterpret_cast<const char*>(kPushBodyFrame3),
2221 arraysize(kPushBodyFrame3) - 1, 6),
2222 MockRead(true, reinterpret_cast<const char*>(kPushBodyFrame4),
2223 arraysize(kPushBodyFrame4) - 1, 7),
2224 MockRead(true, ERR_IO_PENDING, 8), // Force a pause
2225 MockRead(true, 0, 0, 9) // EOF
2226 };
2227
2228 HttpResponseInfo response;
2229 HttpResponseInfo response2;
2230 std::string expected_push_result("hello my darling hello my baby");
2231 RunServerPushTest(writes, arraysize(writes), reads, arraysize(reads),
2232 &response, &response2, expected_push_result);
2233
2234 // Verify the SYN_REPLY.
2235 EXPECT_TRUE(response.headers != NULL);
2236 EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine());
2237
2238 // Verify the pushed stream.
2239 EXPECT_TRUE(response2.headers != NULL);
2240 EXPECT_EQ("HTTP/1.1 200 OK", response2.headers->GetStatusLine());
2241}
2242
2243TEST_P(SpdyNetworkTransactionTest, ServerPushMultipleDataFrameInterrupted) {
2244 static const unsigned char kPushBodyFrame1[] = {
2245 0x00, 0x00, 0x00, 0x02, // header, ID
2246 0x01, 0x00, 0x00, 0x1E, // FIN, length
2247 'h', 'e', 'l', 'l', 'o', // "hello"
2248 };
2249 static const char kPushBodyFrame2[] = " my darling";
2250 static const char kPushBodyFrame3[] = " hello";
2251 static const char kPushBodyFrame4[] = " my baby";
2252
2253 scoped_ptr<spdy::SpdyFrame> req(
2254 ConstructSpdyGet(NULL, 0, false, 1, LOWEST));
2255 MockWrite writes[] = {
2256 CreateMockWrite(*req, 1),
2257 };
2258
2259 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1));
2260 scoped_ptr<spdy::SpdyFrame> rep(ConstructSpdyPush(NULL, 0, 2, 1, "/foo.dat"));
2261 MockRead reads[] = {
2262 CreateMockRead(*resp, 2),
2263 CreateMockRead(*rep, 3),
2264 MockRead(true, reinterpret_cast<const char*>(kPushBodyFrame1),
2265 arraysize(kPushBodyFrame1), 4),
2266 MockRead(true, reinterpret_cast<const char*>(kPushBodyFrame2),
2267 arraysize(kPushBodyFrame2) - 1, 5),
2268 MockRead(true, ERR_IO_PENDING, 6), // Force a pause
2269 MockRead(true, reinterpret_cast<const char*>(kPushBodyFrame3),
2270 arraysize(kPushBodyFrame3) - 1, 7),
2271 MockRead(true, reinterpret_cast<const char*>(kPushBodyFrame4),
2272 arraysize(kPushBodyFrame4) - 1, 8),
2273 MockRead(true, 0, 0, 9) // EOF
2274 };
2275
2276 HttpResponseInfo response;
2277 HttpResponseInfo response2;
2278 std::string expected_push_result("hello my darling hello my baby");
2279 RunServerPushTest(writes, arraysize(writes), reads, arraysize(reads),
2280 &response, &response2, expected_push_result);
2281
2282 // Verify the SYN_REPLY.
2283 EXPECT_TRUE(response.headers != NULL);
2284 EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine());
2285
2286 // Verify the pushed stream.
2287 EXPECT_TRUE(response2.headers != NULL);
2288 EXPECT_EQ("HTTP/1.1 200 OK", response2.headers->GetStatusLine());
2289}
2290
2291TEST_P(SpdyNetworkTransactionTest, ServerPushInvalidAssociatedStreamID0) {
2292 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST));
2293 scoped_ptr<spdy::SpdyFrame> res(
2294 ConstructSpdyRstStream(2, spdy::INVALID_STREAM));
2295 MockWrite writes[] = {
2296 CreateMockWrite(*req, 1),
2297 CreateMockWrite(*res, 4),
2298 };
2299
2300 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1));
2301 scoped_ptr<spdy::SpdyFrame> rep(ConstructSpdyPush(NULL, 0, 2, 0, "/foo.dat"));
2302 MockRead reads[] = {
2303 CreateMockRead(*resp, 2),
2304 CreateMockRead(*rep, 3),
2305 MockRead(true, 0, 0, 5) // EOF
2306 };
2307
2308 scoped_refptr<OrderedSocketData> data(
2309 new OrderedSocketData(reads, arraysize(reads),
2310 writes, arraysize(writes)));
2311 NormalSpdyTransactionHelper helper(CreateGetRequest(),
2312 BoundNetLog(), GetParam());
2313
2314 helper.RunPreTestSetup();
2315 helper.AddData(data.get());
2316
2317 HttpNetworkTransaction* trans = helper.trans();
2318
2319 // Start the transaction with basic parameters.
2320 TestCompletionCallback callback;
2321 int rv = trans->Start(&CreateGetRequest(), &callback, BoundNetLog());
2322 EXPECT_EQ(ERR_IO_PENDING, rv);
2323 rv = callback.WaitForResult();
2324 data->CompleteRead();
2325 EXPECT_EQ(OK, rv);
2326
2327 // Verify that we consumed all test data.
2328 EXPECT_TRUE(data->at_read_eof()) << "Read count: "
2329 << data->read_count()
2330 << " Read index: "
2331 << data->read_index();
2332 EXPECT_TRUE(data->at_write_eof()) << "Write count: "
2333 << data->write_count()
2334 << " Write index: "
2335 << data->write_index();
2336
2337 // Verify the SYN_REPLY.
2338 HttpResponseInfo response = *trans->GetResponseInfo();
2339 EXPECT_TRUE(response.headers != NULL);
2340 EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine());
2341}
2342
2343TEST_P(SpdyNetworkTransactionTest, ServerPushInvalidAssociatedStreamID9) {
2344 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST));
2345 scoped_ptr<spdy::SpdyFrame> res(
2346 ConstructSpdyRstStream(2, spdy::INVALID_ASSOCIATED_STREAM));
2347 MockWrite writes[] = {
2348 CreateMockWrite(*req, 1),
2349 CreateMockWrite(*res, 4),
2350 };
2351
2352 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1));
2353 scoped_ptr<spdy::SpdyFrame> rep(ConstructSpdyPush(NULL, 0, 2, 9, "/foo.dat"));
2354 MockRead reads[] = {
2355 CreateMockRead(*resp, 2),
2356 CreateMockRead(*rep, 3),
2357 MockRead(true, 0, 0, 5) // EOF
2358 };
2359
2360 scoped_refptr<OrderedSocketData> data(
2361 new OrderedSocketData(reads, arraysize(reads),
2362 writes, arraysize(writes)));
2363 NormalSpdyTransactionHelper helper(CreateGetRequest(),
2364 BoundNetLog(), GetParam());
2365
2366 helper.RunPreTestSetup();
2367 helper.AddData(data.get());
2368
2369 HttpNetworkTransaction* trans = helper.trans();
2370
2371 // Start the transaction with basic parameters.
2372 TestCompletionCallback callback;
2373 int rv = trans->Start(&CreateGetRequest(), &callback, BoundNetLog());
2374 EXPECT_EQ(ERR_IO_PENDING, rv);
2375 rv = callback.WaitForResult();
2376 data->CompleteRead();
2377 EXPECT_EQ(OK, rv);
2378
2379 // Verify that we consumed all test data.
2380 EXPECT_TRUE(data->at_read_eof()) << "Read count: "
2381 << data->read_count()
2382 << " Read index: "
2383 << data->read_index();
2384 EXPECT_TRUE(data->at_write_eof()) << "Write count: "
2385 << data->write_count()
2386 << " Write index: "
2387 << data->write_index();
2388
2389 // Verify the SYN_REPLY.
2390 HttpResponseInfo response = *trans->GetResponseInfo();
2391 EXPECT_TRUE(response.headers != NULL);
2392 EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine());
2393}
2394
2395TEST_P(SpdyNetworkTransactionTest, ServerPushNoURL) {
2396 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST));
2397 scoped_ptr<spdy::SpdyFrame> res(
2398 ConstructSpdyRstStream(2, spdy::PROTOCOL_ERROR));
2399 MockWrite writes[] = {
2400 CreateMockWrite(*req, 1),
2401 CreateMockWrite(*res, 4),
2402 };
2403
2404 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1));
2405 scoped_ptr<spdy::SpdyFrame> rep(ConstructSpdyPush(NULL, 0, 2, 1));
2406 MockRead reads[] = {
2407 CreateMockRead(*resp, 2),
2408 CreateMockRead(*rep, 3),
2409 MockRead(true, 0, 0, 5) // EOF
2410 };
2411
2412 scoped_refptr<OrderedSocketData> data(
2413 new OrderedSocketData(reads, arraysize(reads),
2414 writes, arraysize(writes)));
2415 NormalSpdyTransactionHelper helper(CreateGetRequest(),
2416 BoundNetLog(), GetParam());
2417
2418 helper.RunPreTestSetup();
2419 helper.AddData(data.get());
2420
2421 HttpNetworkTransaction* trans = helper.trans();
2422
2423 // Start the transaction with basic parameters.
2424 TestCompletionCallback callback;
2425 int rv = trans->Start(&CreateGetRequest(), &callback, BoundNetLog());
2426 EXPECT_EQ(ERR_IO_PENDING, rv);
2427 rv = callback.WaitForResult();
2428 data->CompleteRead();
2429 EXPECT_EQ(OK, rv);
2430 // Verify that we consumed all test data.
2431 EXPECT_TRUE(data->at_read_eof()) << "Read count: "
2432 << data->read_count()
2433 << " Read index: "
2434 << data->read_index();
2435 EXPECT_TRUE(data->at_write_eof()) << "Write count: "
2436 << data->write_count()
2437 << " Write index: "
2438 << data->write_index();
2439
2440 // Verify the SYN_REPLY.
2441 HttpResponseInfo response = *trans->GetResponseInfo();
2442 EXPECT_TRUE(response.headers != NULL);
2443 EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine());
2444}
2445
[email protected]8b070372009-11-16 22:01:252446// Verify that various SynReply headers parse correctly through the
2447// HTTP layer.
[email protected]9e9e842e2010-07-23 23:09:152448TEST_P(SpdyNetworkTransactionTest, SynReplyHeaders) {
[email protected]e7f75092010-07-01 22:39:132449 struct SynReplyHeadersTests {
2450 int num_headers;
2451 const char* extra_headers[5];
[email protected]8b070372009-11-16 22:01:252452 const char* expected_headers;
2453 } test_cases[] = {
[email protected]e7f75092010-07-01 22:39:132454 // This uses a multi-valued cookie header.
2455 { 2,
2456 { "cookie", "val1",
2457 "cookie", "val2", // will get appended separated by NULL
2458 NULL
2459 },
[email protected]8b070372009-11-16 22:01:252460 "cookie: val1\n"
2461 "cookie: val2\n"
[email protected]e7f75092010-07-01 22:39:132462 "hello: bye\n"
[email protected]8b070372009-11-16 22:01:252463 "status: 200\n"
2464 "url: /index.php\n"
2465 "version: HTTP/1.1\n"
2466 },
[email protected]e7f75092010-07-01 22:39:132467 // This is the minimalist set of headers.
2468 { 0,
2469 { NULL },
2470 "hello: bye\n"
[email protected]8b070372009-11-16 22:01:252471 "status: 200\n"
2472 "url: /index.php\n"
2473 "version: HTTP/1.1\n"
2474 },
[email protected]e7f75092010-07-01 22:39:132475 // Headers with a comma separated list.
2476 { 1,
2477 { "cookie", "val1,val2",
2478 NULL
2479 },
[email protected]8b070372009-11-16 22:01:252480 "cookie: val1,val2\n"
[email protected]e7f75092010-07-01 22:39:132481 "hello: bye\n"
[email protected]8b070372009-11-16 22:01:252482 "status: 200\n"
2483 "url: /index.php\n"
2484 "version: HTTP/1.1\n"
2485 }
2486 };
2487
2488 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) {
[email protected]2bd93022010-07-17 00:58:442489 scoped_ptr<spdy::SpdyFrame> req(
2490 ConstructSpdyGet(NULL, 0, false, 1, LOWEST));
[email protected]e7f75092010-07-01 22:39:132491 MockWrite writes[] = { CreateMockWrite(*req) };
[email protected]8b070372009-11-16 22:01:252492
[email protected]e7f75092010-07-01 22:39:132493 scoped_ptr<spdy::SpdyFrame> resp(
2494 ConstructSpdyGetSynReply(test_cases[i].extra_headers,
[email protected]2bd93022010-07-17 00:58:442495 test_cases[i].num_headers,
2496 1));
2497 scoped_ptr<spdy::SpdyFrame> body(ConstructSpdyBodyFrame(1, true));
[email protected]8b070372009-11-16 22:01:252498 MockRead reads[] = {
[email protected]e7f75092010-07-01 22:39:132499 CreateMockRead(*resp),
2500 CreateMockRead(*body),
[email protected]8b070372009-11-16 22:01:252501 MockRead(true, 0, 0) // EOF
2502 };
2503
[email protected]bf2491a92009-11-29 16:39:482504 scoped_refptr<DelayedSocketData> data(
[email protected]31a2bfe2010-02-09 08:03:392505 new DelayedSocketData(1, reads, arraysize(reads),
2506 writes, arraysize(writes)));
[email protected]3caf5542010-07-16 15:19:472507 NormalSpdyTransactionHelper helper(CreateGetRequest(),
[email protected]9e9e842e2010-07-23 23:09:152508 BoundNetLog(), GetParam());
[email protected]3caf5542010-07-16 15:19:472509 helper.RunToCompletion(data.get());
2510 TransactionHelperResult out = helper.output();
2511
[email protected]8b070372009-11-16 22:01:252512 EXPECT_EQ(OK, out.rv);
2513 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
2514 EXPECT_EQ("hello!", out.response_data);
2515
2516 scoped_refptr<HttpResponseHeaders> headers = out.response_info.headers;
2517 EXPECT_TRUE(headers.get() != NULL);
2518 void* iter = NULL;
2519 std::string name, value, lines;
2520 while (headers->EnumerateHeaderLines(&iter, &name, &value)) {
2521 lines.append(name);
2522 lines.append(": ");
2523 lines.append(value);
2524 lines.append("\n");
2525 }
2526 EXPECT_EQ(std::string(test_cases[i].expected_headers), lines);
2527 }
2528}
2529
[email protected]3f662f12010-03-25 19:56:122530// Verify that various SynReply headers parse vary fields correctly
2531// through the HTTP layer, and the response matches the request.
[email protected]9e9e842e2010-07-23 23:09:152532TEST_P(SpdyNetworkTransactionTest, SynReplyHeadersVary) {
[email protected]3f662f12010-03-25 19:56:122533 static const SpdyHeaderInfo syn_reply_info = {
2534 spdy::SYN_REPLY, // Syn Reply
2535 1, // Stream ID
2536 0, // Associated Stream ID
[email protected]c9c6f5c2010-07-31 01:30:032537 net::ConvertRequestPriorityToSpdyPriority(LOWEST),
2538 // Priority
[email protected]3f662f12010-03-25 19:56:122539 spdy::CONTROL_FLAG_NONE, // Control Flags
2540 false, // Compressed
[email protected]75f30cc22010-06-28 21:41:382541 spdy::INVALID, // Status
[email protected]3f662f12010-03-25 19:56:122542 NULL, // Data
2543 0, // Data Length
2544 spdy::DATA_FLAG_NONE // Data Flags
2545 };
2546 // Modify the following data to change/add test cases:
2547 struct SynReplyTests {
2548 const SpdyHeaderInfo* syn_reply;
2549 bool vary_matches;
2550 int num_headers[2];
2551 const char* extra_headers[2][16];
2552 } test_cases[] = {
2553 // Test the case of a multi-valued cookie. When the value is delimited
2554 // with NUL characters, it needs to be unfolded into multiple headers.
2555 {
2556 &syn_reply_info,
2557 true,
[email protected]8c76ae22010-04-20 22:15:432558 { 1, 4 },
2559 { { "cookie", "val1,val2",
[email protected]3f662f12010-03-25 19:56:122560 NULL
2561 },
2562 { "vary", "cookie",
2563 "status", "200",
2564 "url", "/index.php",
2565 "version", "HTTP/1.1",
2566 NULL
2567 }
2568 }
2569 }, { // Multiple vary fields.
2570 &syn_reply_info,
2571 true,
2572 { 2, 5 },
2573 { { "friend", "barney",
2574 "enemy", "snaggletooth",
2575 NULL
2576 },
2577 { "vary", "friend",
2578 "vary", "enemy",
2579 "status", "200",
2580 "url", "/index.php",
2581 "version", "HTTP/1.1",
2582 NULL
2583 }
2584 }
2585 }, { // Test a '*' vary field.
2586 &syn_reply_info,
2587 false,
2588 { 1, 4 },
2589 { { "cookie", "val1,val2",
2590 NULL
2591 },
2592 { "vary", "*",
2593 "status", "200",
2594 "url", "/index.php",
2595 "version", "HTTP/1.1",
2596 NULL
2597 }
2598 }
2599 }, { // Multiple comma-separated vary fields.
2600 &syn_reply_info,
2601 true,
2602 { 2, 4 },
2603 { { "friend", "barney",
2604 "enemy", "snaggletooth",
2605 NULL
2606 },
2607 { "vary", "friend,enemy",
2608 "status", "200",
2609 "url", "/index.php",
2610 "version", "HTTP/1.1",
2611 NULL
2612 }
2613 }
2614 }
2615 };
2616
2617 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) {
[email protected]3f662f12010-03-25 19:56:122618 // Construct the request.
2619 scoped_ptr<spdy::SpdyFrame> frame_req(
2620 ConstructSpdyGet(test_cases[i].extra_headers[0],
[email protected]2bd93022010-07-17 00:58:442621 test_cases[i].num_headers[0],
2622 false, 1, LOWEST));
[email protected]3f662f12010-03-25 19:56:122623
2624 MockWrite writes[] = {
[email protected]e7f75092010-07-01 22:39:132625 CreateMockWrite(*frame_req),
[email protected]3f662f12010-03-25 19:56:122626 };
2627
2628 // Construct the reply.
2629 scoped_ptr<spdy::SpdyFrame> frame_reply(
[email protected]a4aeaf42010-06-30 19:57:282630 ConstructSpdyPacket(*test_cases[i].syn_reply,
[email protected]3f662f12010-03-25 19:56:122631 test_cases[i].extra_headers[1],
2632 test_cases[i].num_headers[1],
2633 NULL,
2634 0));
2635
[email protected]2bd93022010-07-17 00:58:442636 scoped_ptr<spdy::SpdyFrame> body(ConstructSpdyBodyFrame(1, true));
[email protected]3f662f12010-03-25 19:56:122637 MockRead reads[] = {
[email protected]e7f75092010-07-01 22:39:132638 CreateMockRead(*frame_reply),
2639 CreateMockRead(*body),
[email protected]3f662f12010-03-25 19:56:122640 MockRead(true, 0, 0) // EOF
2641 };
2642
[email protected]3f662f12010-03-25 19:56:122643 // Attach the headers to the request.
[email protected]8c76ae22010-04-20 22:15:432644 int header_count = test_cases[i].num_headers[0];
[email protected]3f662f12010-03-25 19:56:122645
[email protected]d3cee19d2010-06-22 18:42:182646 HttpRequestInfo request = CreateGetRequest();
[email protected]8c76ae22010-04-20 22:15:432647 for (int ct = 0; ct < header_count; ct++) {
2648 const char* header_key = test_cases[i].extra_headers[0][ct * 2];
2649 const char* header_value = test_cases[i].extra_headers[0][ct * 2 + 1];
2650 request.extra_headers.SetHeader(header_key, header_value);
[email protected]3f662f12010-03-25 19:56:122651 }
2652
2653 scoped_refptr<DelayedSocketData> data(
2654 new DelayedSocketData(1, reads, arraysize(reads),
2655 writes, arraysize(writes)));
[email protected]3caf5542010-07-16 15:19:472656 NormalSpdyTransactionHelper helper(request,
[email protected]9e9e842e2010-07-23 23:09:152657 BoundNetLog(), GetParam());
[email protected]3caf5542010-07-16 15:19:472658 helper.RunToCompletion(data.get());
2659 TransactionHelperResult out = helper.output();
2660
[email protected]3f662f12010-03-25 19:56:122661 EXPECT_EQ(OK, out.rv) << i;
2662 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line) << i;
2663 EXPECT_EQ("hello!", out.response_data) << i;
2664
2665 // Test the response information.
2666 EXPECT_TRUE(out.response_info.response_time >
2667 out.response_info.request_time) << i;
2668 base::TimeDelta test_delay = out.response_info.response_time -
2669 out.response_info.request_time;
2670 base::TimeDelta min_expected_delay;
2671 min_expected_delay.FromMilliseconds(10);
2672 EXPECT_GT(test_delay.InMillisecondsF(),
2673 min_expected_delay.InMillisecondsF()) << i;
2674 EXPECT_EQ(out.response_info.vary_data.is_valid(),
2675 test_cases[i].vary_matches) << i;
2676
2677 // Check the headers.
2678 scoped_refptr<HttpResponseHeaders> headers = out.response_info.headers;
2679 ASSERT_TRUE(headers.get() != NULL) << i;
2680 void* iter = NULL;
2681 std::string name, value, lines;
2682 while (headers->EnumerateHeaderLines(&iter, &name, &value)) {
2683 lines.append(name);
2684 lines.append(": ");
2685 lines.append(value);
2686 lines.append("\n");
2687 }
2688
2689 // Construct the expected header reply string.
2690 char reply_buffer[256] = "";
[email protected]75f30cc22010-06-28 21:41:382691 ConstructSpdyReplyString(test_cases[i].extra_headers[1],
2692 test_cases[i].num_headers[1],
2693 reply_buffer,
2694 256);
[email protected]3f662f12010-03-25 19:56:122695
2696 EXPECT_EQ(std::string(reply_buffer), lines) << i;
2697 }
2698}
2699
[email protected]dd11b932009-11-30 19:39:482700// Verify that we don't crash on invalid SynReply responses.
[email protected]9e9e842e2010-07-23 23:09:152701TEST_P(SpdyNetworkTransactionTest, InvalidSynReply) {
[email protected]e7f75092010-07-01 22:39:132702 const SpdyHeaderInfo kSynStartHeader = {
2703 spdy::SYN_REPLY, // Kind = SynReply
2704 1, // Stream ID
2705 0, // Associated stream ID
[email protected]c9c6f5c2010-07-31 01:30:032706 net::ConvertRequestPriorityToSpdyPriority(LOWEST),
2707 // Priority
[email protected]e7f75092010-07-01 22:39:132708 spdy::CONTROL_FLAG_NONE, // Control Flags
2709 false, // Compressed
2710 spdy::INVALID, // Status
2711 NULL, // Data
2712 0, // Length
2713 spdy::DATA_FLAG_NONE // Data Flags
[email protected]dd11b932009-11-30 19:39:482714 };
2715
[email protected]e7f75092010-07-01 22:39:132716 struct InvalidSynReplyTests {
2717 int num_headers;
2718 const char* headers[10];
[email protected]dd11b932009-11-30 19:39:482719 } test_cases[] = {
[email protected]e7f75092010-07-01 22:39:132720 // SYN_REPLY missing status header
2721 { 4,
2722 { "cookie", "val1",
2723 "cookie", "val2",
2724 "url", "/index.php",
2725 "version", "HTTP/1.1",
2726 NULL
2727 },
2728 },
2729 // SYN_REPLY missing version header
2730 { 2,
2731 { "status", "200",
2732 "url", "/index.php",
2733 NULL
2734 },
2735 },
[email protected]0d384bb2010-07-14 01:51:122736 // SYN_REPLY with no headers
2737 { 0, { NULL }, },
[email protected]dd11b932009-11-30 19:39:482738 };
2739
2740 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) {
[email protected]2bd93022010-07-17 00:58:442741 scoped_ptr<spdy::SpdyFrame> req(
2742 ConstructSpdyGet(NULL, 0, false, 1, LOWEST));
[email protected]dd11b932009-11-30 19:39:482743 MockWrite writes[] = {
[email protected]e7f75092010-07-01 22:39:132744 CreateMockWrite(*req),
[email protected]dd11b932009-11-30 19:39:482745 };
2746
[email protected]e7f75092010-07-01 22:39:132747 scoped_ptr<spdy::SpdyFrame> resp(
2748 ConstructSpdyPacket(kSynStartHeader,
2749 NULL, 0,
2750 test_cases[i].headers,
2751 test_cases[i].num_headers));
[email protected]2bd93022010-07-17 00:58:442752 scoped_ptr<spdy::SpdyFrame> body(ConstructSpdyBodyFrame(1, true));
[email protected]dd11b932009-11-30 19:39:482753 MockRead reads[] = {
[email protected]e7f75092010-07-01 22:39:132754 CreateMockRead(*resp),
2755 CreateMockRead(*body),
[email protected]dd11b932009-11-30 19:39:482756 MockRead(true, 0, 0) // EOF
2757 };
2758
[email protected]dd11b932009-11-30 19:39:482759 scoped_refptr<DelayedSocketData> data(
[email protected]31a2bfe2010-02-09 08:03:392760 new DelayedSocketData(1, reads, arraysize(reads),
2761 writes, arraysize(writes)));
[email protected]3caf5542010-07-16 15:19:472762 NormalSpdyTransactionHelper helper(CreateGetRequest(),
[email protected]9e9e842e2010-07-23 23:09:152763 BoundNetLog(), GetParam());
[email protected]3caf5542010-07-16 15:19:472764 helper.RunToCompletion(data.get());
2765 TransactionHelperResult out = helper.output();
[email protected]dd11b932009-11-30 19:39:482766 EXPECT_EQ(ERR_INVALID_RESPONSE, out.rv);
2767 }
2768}
2769
[email protected]94d78132010-01-22 00:53:002770// Verify that we don't crash on some corrupt frames.
[email protected]6f0a3f42010-07-08 21:44:442771// TODO(eroman): Renable this test, see http://crbug.com/48588
[email protected]9e9e842e2010-07-23 23:09:152772TEST_P(SpdyNetworkTransactionTest, DISABLED_CorruptFrameSessionError) {
[email protected]e7f75092010-07-01 22:39:132773 // This is the length field with a big number
2774 scoped_ptr<spdy::SpdyFrame> syn_reply_massive_length(
[email protected]2bd93022010-07-17 00:58:442775 ConstructSpdyGetSynReply(NULL, 0, 1));
[email protected]e7f75092010-07-01 22:39:132776 syn_reply_massive_length->set_length(0x111126);
[email protected]94d78132010-01-22 00:53:002777
2778 struct SynReplyTests {
[email protected]e7f75092010-07-01 22:39:132779 const spdy::SpdyFrame* syn_reply;
[email protected]94d78132010-01-22 00:53:002780 } test_cases[] = {
[email protected]e7f75092010-07-01 22:39:132781 { syn_reply_massive_length.get(), },
[email protected]94d78132010-01-22 00:53:002782 };
2783
2784 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) {
[email protected]2bd93022010-07-17 00:58:442785 scoped_ptr<spdy::SpdyFrame> req(
2786 ConstructSpdyGet(NULL, 0, false, 1, LOWEST));
[email protected]94d78132010-01-22 00:53:002787 MockWrite writes[] = {
[email protected]e7f75092010-07-01 22:39:132788 CreateMockWrite(*req),
[email protected]94d78132010-01-22 00:53:002789 MockWrite(true, 0, 0) // EOF
2790 };
2791
[email protected]2bd93022010-07-17 00:58:442792 scoped_ptr<spdy::SpdyFrame> body(ConstructSpdyBodyFrame(1, true));
[email protected]94d78132010-01-22 00:53:002793 MockRead reads[] = {
[email protected]e7f75092010-07-01 22:39:132794 CreateMockRead(*test_cases[i].syn_reply),
2795 CreateMockRead(*body),
[email protected]94d78132010-01-22 00:53:002796 MockRead(true, 0, 0) // EOF
2797 };
2798
[email protected]94d78132010-01-22 00:53:002799 scoped_refptr<DelayedSocketData> data(
[email protected]31a2bfe2010-02-09 08:03:392800 new DelayedSocketData(1, reads, arraysize(reads),
2801 writes, arraysize(writes)));
[email protected]3caf5542010-07-16 15:19:472802 NormalSpdyTransactionHelper helper(CreateGetRequest(),
[email protected]9e9e842e2010-07-23 23:09:152803 BoundNetLog(), GetParam());
[email protected]3caf5542010-07-16 15:19:472804 helper.RunToCompletion(data.get());
2805 TransactionHelperResult out = helper.output();
[email protected]955fc2e72010-02-08 20:37:302806 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, out.rv);
[email protected]94d78132010-01-22 00:53:002807 }
2808}
2809
[email protected]bf2491a92009-11-29 16:39:482810// Test that we shutdown correctly on write errors.
[email protected]9e9e842e2010-07-23 23:09:152811TEST_P(SpdyNetworkTransactionTest, WriteError) {
[email protected]2bd93022010-07-17 00:58:442812 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST));
[email protected]bf2491a92009-11-29 16:39:482813 MockWrite writes[] = {
2814 // We'll write 10 bytes successfully
[email protected]75f30cc22010-06-28 21:41:382815 MockWrite(true, req->data(), 10),
[email protected]bf2491a92009-11-29 16:39:482816 // Followed by ERROR!
2817 MockWrite(true, ERR_FAILED),
[email protected]bf2491a92009-11-29 16:39:482818 };
2819
[email protected]bf2491a92009-11-29 16:39:482820 scoped_refptr<DelayedSocketData> data(
[email protected]3caf5542010-07-16 15:19:472821 new DelayedSocketData(2, NULL, 0,
[email protected]31a2bfe2010-02-09 08:03:392822 writes, arraysize(writes)));
[email protected]3caf5542010-07-16 15:19:472823 NormalSpdyTransactionHelper helper(CreateGetRequest(),
[email protected]9e9e842e2010-07-23 23:09:152824 BoundNetLog(), GetParam());
[email protected]3caf5542010-07-16 15:19:472825 helper.RunToCompletion(data.get());
2826 TransactionHelperResult out = helper.output();
[email protected]bf2491a92009-11-29 16:39:482827 EXPECT_EQ(ERR_FAILED, out.rv);
[email protected]32100cb2009-11-30 18:24:462828 data->Reset();
[email protected]bf2491a92009-11-29 16:39:482829}
2830
2831// Test that partial writes work.
[email protected]9e9e842e2010-07-23 23:09:152832TEST_P(SpdyNetworkTransactionTest, PartialWrite) {
[email protected]bf2491a92009-11-29 16:39:482833 // Chop the SYN_STREAM frame into 5 chunks.
[email protected]2bd93022010-07-17 00:58:442834 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST));
[email protected]bf2491a92009-11-29 16:39:482835 const int kChunks = 5;
[email protected]e7f75092010-07-01 22:39:132836 scoped_array<MockWrite> writes(ChopWriteFrame(*req.get(), kChunks));
[email protected]bf2491a92009-11-29 16:39:482837
[email protected]2bd93022010-07-17 00:58:442838 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1));
2839 scoped_ptr<spdy::SpdyFrame> body(ConstructSpdyBodyFrame(1, true));
[email protected]bf2491a92009-11-29 16:39:482840 MockRead reads[] = {
[email protected]e7f75092010-07-01 22:39:132841 CreateMockRead(*resp),
2842 CreateMockRead(*body),
[email protected]bf2491a92009-11-29 16:39:482843 MockRead(true, 0, 0) // EOF
2844 };
2845
[email protected]bf2491a92009-11-29 16:39:482846 scoped_refptr<DelayedSocketData> data(
[email protected]31a2bfe2010-02-09 08:03:392847 new DelayedSocketData(kChunks, reads, arraysize(reads),
2848 writes.get(), kChunks));
[email protected]3caf5542010-07-16 15:19:472849 NormalSpdyTransactionHelper helper(CreateGetRequest(),
[email protected]9e9e842e2010-07-23 23:09:152850 BoundNetLog(), GetParam());
[email protected]3caf5542010-07-16 15:19:472851 helper.RunToCompletion(data.get());
2852 TransactionHelperResult out = helper.output();
[email protected]bf2491a92009-11-29 16:39:482853 EXPECT_EQ(OK, out.rv);
2854 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
2855 EXPECT_EQ("hello!", out.response_data);
2856}
2857
[email protected]94d78132010-01-22 00:53:002858// In this test, we enable compression, but get a uncompressed SynReply from
2859// the server. Verify that teardown is all clean.
[email protected]9e9e842e2010-07-23 23:09:152860TEST_P(SpdyNetworkTransactionTest, DecompressFailureOnSynReply) {
[email protected]a4aeaf42010-06-30 19:57:282861 // For this test, we turn on the normal compression.
2862 EnableCompression(true);
2863
[email protected]2bd93022010-07-17 00:58:442864 scoped_ptr<spdy::SpdyFrame> compressed(
2865 ConstructSpdyGet(NULL, 0, true, 1, LOWEST));
[email protected]6c6ea172010-07-27 20:04:032866 scoped_ptr<spdy::SpdyFrame> rst(
2867 ConstructSpdyRstStream(1, spdy::PROTOCOL_ERROR));
[email protected]94d78132010-01-22 00:53:002868 MockWrite writes[] = {
[email protected]e7f75092010-07-01 22:39:132869 CreateMockWrite(*compressed),
[email protected]6c6ea172010-07-27 20:04:032870 CreateMockWrite(*rst),
[email protected]94d78132010-01-22 00:53:002871 };
2872
[email protected]2bd93022010-07-17 00:58:442873 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1));
2874 scoped_ptr<spdy::SpdyFrame> body(ConstructSpdyBodyFrame(1, true));
[email protected]94d78132010-01-22 00:53:002875 MockRead reads[] = {
[email protected]e7f75092010-07-01 22:39:132876 CreateMockRead(*resp),
2877 CreateMockRead(*body),
[email protected]58cebf8f2010-07-31 19:20:162878 MockRead(true, 0, 0)
[email protected]94d78132010-01-22 00:53:002879 };
2880
[email protected]94d78132010-01-22 00:53:002881 scoped_refptr<DelayedSocketData> data(
[email protected]31a2bfe2010-02-09 08:03:392882 new DelayedSocketData(1, reads, arraysize(reads),
2883 writes, arraysize(writes)));
[email protected]3caf5542010-07-16 15:19:472884 NormalSpdyTransactionHelper helper(CreateGetRequest(),
[email protected]9e9e842e2010-07-23 23:09:152885 BoundNetLog(), GetParam());
[email protected]3caf5542010-07-16 15:19:472886 helper.RunToCompletion(data.get());
2887 TransactionHelperResult out = helper.output();
[email protected]6c6ea172010-07-27 20:04:032888 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, out.rv);
[email protected]94d78132010-01-22 00:53:002889 data->Reset();
2890
2891 EnableCompression(false);
2892}
2893
[email protected]9e743cd2010-03-16 07:03:532894// Test that the NetLog contains good data for a simple GET request.
[email protected]9e9e842e2010-07-23 23:09:152895TEST_P(SpdyNetworkTransactionTest, NetLog) {
[email protected]2bd93022010-07-17 00:58:442896 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST));
[email protected]e7f75092010-07-01 22:39:132897 MockWrite writes[] = { CreateMockWrite(*req) };
[email protected]dac358042009-12-18 02:07:482898
[email protected]2bd93022010-07-17 00:58:442899 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1));
2900 scoped_ptr<spdy::SpdyFrame> body(ConstructSpdyBodyFrame(1, true));
[email protected]dac358042009-12-18 02:07:482901 MockRead reads[] = {
[email protected]e7f75092010-07-01 22:39:132902 CreateMockRead(*resp),
2903 CreateMockRead(*body),
[email protected]dac358042009-12-18 02:07:482904 MockRead(true, 0, 0) // EOF
2905 };
2906
[email protected]9e743cd2010-03-16 07:03:532907 net::CapturingBoundNetLog log(net::CapturingNetLog::kUnbounded);
[email protected]dac358042009-12-18 02:07:482908
[email protected]dac358042009-12-18 02:07:482909 scoped_refptr<DelayedSocketData> data(
[email protected]31a2bfe2010-02-09 08:03:392910 new DelayedSocketData(1, reads, arraysize(reads),
2911 writes, arraysize(writes)));
[email protected]3caf5542010-07-16 15:19:472912 NormalSpdyTransactionHelper helper(CreateGetRequest(),
[email protected]9e9e842e2010-07-23 23:09:152913 log.bound(), GetParam());
[email protected]3caf5542010-07-16 15:19:472914 helper.RunToCompletion(data.get());
2915 TransactionHelperResult out = helper.output();
[email protected]dac358042009-12-18 02:07:482916 EXPECT_EQ(OK, out.rv);
2917 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
2918 EXPECT_EQ("hello!", out.response_data);
2919
[email protected]9e743cd2010-03-16 07:03:532920 // Check that the NetLog was filled reasonably.
[email protected]3caf5542010-07-16 15:19:472921 // This test is intentionally non-specific about the exact ordering of the
2922 // log; instead we just check to make sure that certain events exist, and that
2923 // they are in the right order.
[email protected]9e743cd2010-03-16 07:03:532924 EXPECT_LT(0u, log.entries().size());
[email protected]dac358042009-12-18 02:07:482925 int pos = 0;
[email protected]9e743cd2010-03-16 07:03:532926 pos = net::ExpectLogContainsSomewhere(log.entries(), 0,
[email protected]351ab642010-08-05 16:55:312927 net::NetLog::TYPE_HTTP_TRANSACTION_SEND_REQUEST,
[email protected]9e743cd2010-03-16 07:03:532928 net::NetLog::PHASE_BEGIN);
2929 pos = net::ExpectLogContainsSomewhere(log.entries(), pos + 1,
[email protected]351ab642010-08-05 16:55:312930 net::NetLog::TYPE_HTTP_TRANSACTION_SEND_REQUEST,
[email protected]9e743cd2010-03-16 07:03:532931 net::NetLog::PHASE_END);
2932 pos = net::ExpectLogContainsSomewhere(log.entries(), pos + 1,
[email protected]351ab642010-08-05 16:55:312933 net::NetLog::TYPE_HTTP_TRANSACTION_READ_HEADERS,
[email protected]9e743cd2010-03-16 07:03:532934 net::NetLog::PHASE_BEGIN);
2935 pos = net::ExpectLogContainsSomewhere(log.entries(), pos + 1,
[email protected]351ab642010-08-05 16:55:312936 net::NetLog::TYPE_HTTP_TRANSACTION_READ_HEADERS,
[email protected]9e743cd2010-03-16 07:03:532937 net::NetLog::PHASE_END);
2938 pos = net::ExpectLogContainsSomewhere(log.entries(), pos + 1,
[email protected]351ab642010-08-05 16:55:312939 net::NetLog::TYPE_HTTP_TRANSACTION_READ_BODY,
[email protected]9e743cd2010-03-16 07:03:532940 net::NetLog::PHASE_BEGIN);
2941 pos = net::ExpectLogContainsSomewhere(log.entries(), pos + 1,
[email protected]351ab642010-08-05 16:55:312942 net::NetLog::TYPE_HTTP_TRANSACTION_READ_BODY,
[email protected]9e743cd2010-03-16 07:03:532943 net::NetLog::PHASE_END);
[email protected]dac358042009-12-18 02:07:482944}
2945
[email protected]79d84222010-02-26 00:01:442946// Since we buffer the IO from the stream to the renderer, this test verifies
2947// that when we read out the maximum amount of data (e.g. we received 50 bytes
2948// on the network, but issued a Read for only 5 of those bytes) that the data
2949// flow still works correctly.
[email protected]9e9e842e2010-07-23 23:09:152950TEST_P(SpdyNetworkTransactionTest, BufferFull) {
[email protected]20d005f2010-07-02 19:55:432951 spdy::SpdyFramer framer;
2952
[email protected]2bd93022010-07-17 00:58:442953 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST));
[email protected]e7f75092010-07-01 22:39:132954 MockWrite writes[] = { CreateMockWrite(*req) };
[email protected]79d84222010-02-26 00:01:442955
[email protected]20d005f2010-07-02 19:55:432956 // 2 data frames in a single read.
2957 scoped_ptr<spdy::SpdyFrame> data_frame_1(
2958 framer.CreateDataFrame(1, "goodby", 6, spdy::DATA_FLAG_NONE));
2959 scoped_ptr<spdy::SpdyFrame> data_frame_2(
2960 framer.CreateDataFrame(1, "e worl", 6, spdy::DATA_FLAG_NONE));
2961 const spdy::SpdyFrame* data_frames[2] = {
2962 data_frame_1.get(),
2963 data_frame_2.get(),
[email protected]79d84222010-02-26 00:01:442964 };
[email protected]20d005f2010-07-02 19:55:432965 char combined_data_frames[100];
2966 int combined_data_frames_len =
2967 CombineFrames(data_frames, arraysize(data_frames),
2968 combined_data_frames, arraysize(combined_data_frames));
2969 scoped_ptr<spdy::SpdyFrame> last_frame(
2970 framer.CreateDataFrame(1, "d", 1, spdy::DATA_FLAG_FIN));
[email protected]79d84222010-02-26 00:01:442971
[email protected]2bd93022010-07-17 00:58:442972 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1));
[email protected]79d84222010-02-26 00:01:442973 MockRead reads[] = {
[email protected]e7f75092010-07-01 22:39:132974 CreateMockRead(*resp),
[email protected]79d84222010-02-26 00:01:442975 MockRead(true, ERR_IO_PENDING), // Force a pause
[email protected]20d005f2010-07-02 19:55:432976 MockRead(true, combined_data_frames, combined_data_frames_len),
[email protected]79d84222010-02-26 00:01:442977 MockRead(true, ERR_IO_PENDING), // Force a pause
[email protected]20d005f2010-07-02 19:55:432978 CreateMockRead(*last_frame),
[email protected]79d84222010-02-26 00:01:442979 MockRead(true, 0, 0) // EOF
2980 };
2981
[email protected]79d84222010-02-26 00:01:442982 scoped_refptr<DelayedSocketData> data(
2983 new DelayedSocketData(1, reads, arraysize(reads),
2984 writes, arraysize(writes)));
2985
[email protected]79d84222010-02-26 00:01:442986
2987 TestCompletionCallback callback;
2988
[email protected]3caf5542010-07-16 15:19:472989 NormalSpdyTransactionHelper helper(CreateGetRequest(),
[email protected]9e9e842e2010-07-23 23:09:152990 BoundNetLog(), GetParam());
[email protected]3caf5542010-07-16 15:19:472991 helper.RunPreTestSetup();
[email protected]e3ebba0f2010-08-05 17:59:582992 helper.AddData(data.get());
[email protected]3caf5542010-07-16 15:19:472993 HttpNetworkTransaction* trans = helper.trans();
[email protected]d3cee19d2010-06-22 18:42:182994 int rv = trans->Start(&CreateGetRequest(), &callback, BoundNetLog());
[email protected]79d84222010-02-26 00:01:442995 EXPECT_EQ(ERR_IO_PENDING, rv);
2996
[email protected]3caf5542010-07-16 15:19:472997 TransactionHelperResult out = helper.output();
[email protected]79d84222010-02-26 00:01:442998 out.rv = callback.WaitForResult();
2999 EXPECT_EQ(out.rv, OK);
3000
3001 const HttpResponseInfo* response = trans->GetResponseInfo();
3002 EXPECT_TRUE(response->headers != NULL);
3003 EXPECT_TRUE(response->was_fetched_via_spdy);
3004 out.status_line = response->headers->GetStatusLine();
3005 out.response_info = *response; // Make a copy so we can verify.
3006
3007 // Read Data
3008 TestCompletionCallback read_callback;
3009
3010 std::string content;
3011 do {
3012 // Read small chunks at a time.
3013 const int kSmallReadSize = 3;
3014 scoped_refptr<net::IOBuffer> buf = new net::IOBuffer(kSmallReadSize);
3015 rv = trans->Read(buf, kSmallReadSize, &read_callback);
3016 if (rv == net::ERR_IO_PENDING) {
3017 data->CompleteRead();
3018 rv = read_callback.WaitForResult();
3019 }
3020 if (rv > 0) {
3021 content.append(buf->data(), rv);
3022 } else if (rv < 0) {
3023 NOTREACHED();
3024 }
3025 } while (rv > 0);
3026
3027 out.response_data.swap(content);
3028
[email protected]30c942b2010-07-21 16:59:593029 // Flush the MessageLoop while the SpdySessionDependencies (in particular, the
[email protected]8918d282010-03-02 00:57:553030 // MockClientSocketFactory) are still alive.
3031 MessageLoop::current()->RunAllPending();
3032
[email protected]79d84222010-02-26 00:01:443033 // Verify that we consumed all test data.
[email protected]3caf5542010-07-16 15:19:473034 helper.VerifyDataConsumed();
[email protected]79d84222010-02-26 00:01:443035
3036 EXPECT_EQ(OK, out.rv);
3037 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
3038 EXPECT_EQ("goodbye world", out.response_data);
3039}
3040
[email protected]9e9e842e2010-07-23 23:09:153041TEST_P(SpdyNetworkTransactionTest, ConnectFailureFallbackToHttp) {
[email protected]e6b06862010-07-20 16:32:583042 MockConnect connects[] = {
3043 MockConnect(true, ERR_NAME_NOT_RESOLVED),
3044 MockConnect(false, ERR_NAME_NOT_RESOLVED),
3045 MockConnect(true, ERR_INTERNET_DISCONNECTED),
3046 MockConnect(false, ERR_INTERNET_DISCONNECTED)
3047 };
3048
3049 for (size_t index = 0; index < arraysize(connects); ++index) {
3050 scoped_ptr<spdy::SpdyFrame> req(
3051 ConstructSpdyGet(NULL, 0, false, 1, LOWEST));
3052 MockWrite writes[] = {
3053 CreateMockWrite(*req),
3054 MockWrite(true, 0, 0) // EOF
3055 };
3056
3057 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1));
3058 scoped_ptr<spdy::SpdyFrame> body(ConstructSpdyBodyFrame(1, true));
3059 MockRead reads[] = {
3060 CreateMockRead(*resp),
3061 CreateMockRead(*body),
3062 MockRead(true, 0, 0) // EOF
3063 };
3064
3065 scoped_refptr<DelayedSocketData> data(
3066 new DelayedSocketData(connects[index], 1, reads, arraysize(reads),
3067 writes, arraysize(writes)));
3068 NormalSpdyTransactionHelper helper(CreateGetRequest(),
[email protected]9e9e842e2010-07-23 23:09:153069 BoundNetLog(), GetParam());
[email protected]e6b06862010-07-20 16:32:583070 helper.RunPreTestSetup();
[email protected]e3ebba0f2010-08-05 17:59:583071 helper.AddData(data.get());
[email protected]e6b06862010-07-20 16:32:583072
3073 // Set up http fallback data.
3074 MockRead http_fallback_data[] = {
3075 MockRead("HTTP/1.1 200 OK\r\n\r\n"),
3076 MockRead("hello world!!!"),
3077 MockRead(true, OK),
3078 };
3079
3080 scoped_ptr<StaticSocketDataProvider> http_fallback(
3081 new StaticSocketDataProvider(http_fallback_data,
3082 arraysize(http_fallback_data),
3083 NULL, 0));
3084 helper.AddDataNoSSL(http_fallback.get());
3085 HttpNetworkTransaction* trans = helper.trans();
3086 TestCompletionCallback callback;
3087
3088 int rv = trans->Start(&helper.request(), &callback, BoundNetLog());
3089 EXPECT_EQ(rv, ERR_IO_PENDING);
3090 rv = callback.WaitForResult();
3091 const HttpResponseInfo* response = trans->GetResponseInfo();
[email protected]9e9e842e2010-07-23 23:09:153092 if (GetParam() == SPDYNOSSL || GetParam() == SPDYSSL) {
3093 ASSERT_TRUE(response == NULL);
3094 return;
3095 }
3096 if (GetParam() != SPDYNPN)
3097 NOTREACHED();
[email protected]e6b06862010-07-20 16:32:583098 ASSERT_TRUE(response != NULL);
3099 ASSERT_TRUE(response->headers != NULL);
3100 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
3101 std::string response_data;
3102 rv = ReadTransaction(trans, &response_data);
3103 EXPECT_EQ(OK, rv);
3104
3105 EXPECT_TRUE(!response->was_fetched_via_spdy);
3106 EXPECT_TRUE(!response->was_npn_negotiated);
3107 EXPECT_TRUE(response->was_alternate_protocol_available);
3108 EXPECT_TRUE(http_fallback->at_read_eof());
3109 EXPECT_EQ(0u, data->read_index());
3110 EXPECT_EQ(0u, data->write_index());
3111 EXPECT_EQ("hello world!!!", response_data);
3112 }
3113}
3114
[email protected]8918d282010-03-02 00:57:553115// Verify that basic buffering works; when multiple data frames arrive
3116// at the same time, ensure that we don't notify a read completion for
3117// each data frame individually.
[email protected]9e9e842e2010-07-23 23:09:153118TEST_P(SpdyNetworkTransactionTest, Buffering) {
[email protected]20d005f2010-07-02 19:55:433119 spdy::SpdyFramer framer;
3120
[email protected]2bd93022010-07-17 00:58:443121 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST));
[email protected]e7f75092010-07-01 22:39:133122 MockWrite writes[] = { CreateMockWrite(*req) };
[email protected]8918d282010-03-02 00:57:553123
3124 // 4 data frames in a single read.
[email protected]20d005f2010-07-02 19:55:433125 scoped_ptr<spdy::SpdyFrame> data_frame(
3126 framer.CreateDataFrame(1, "message", 7, spdy::DATA_FLAG_NONE));
3127 scoped_ptr<spdy::SpdyFrame> data_frame_fin(
3128 framer.CreateDataFrame(1, "message", 7, spdy::DATA_FLAG_FIN));
3129 const spdy::SpdyFrame* data_frames[4] = {
3130 data_frame.get(),
3131 data_frame.get(),
3132 data_frame.get(),
3133 data_frame_fin.get()
[email protected]8918d282010-03-02 00:57:553134 };
[email protected]20d005f2010-07-02 19:55:433135 char combined_data_frames[100];
3136 int combined_data_frames_len =
3137 CombineFrames(data_frames, arraysize(data_frames),
3138 combined_data_frames, arraysize(combined_data_frames));
[email protected]8918d282010-03-02 00:57:553139
[email protected]2bd93022010-07-17 00:58:443140 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1));
[email protected]8918d282010-03-02 00:57:553141 MockRead reads[] = {
[email protected]e7f75092010-07-01 22:39:133142 CreateMockRead(*resp),
[email protected]8918d282010-03-02 00:57:553143 MockRead(true, ERR_IO_PENDING), // Force a pause
[email protected]20d005f2010-07-02 19:55:433144 MockRead(true, combined_data_frames, combined_data_frames_len),
[email protected]8918d282010-03-02 00:57:553145 MockRead(true, 0, 0) // EOF
3146 };
3147
[email protected]8918d282010-03-02 00:57:553148 scoped_refptr<DelayedSocketData> data(
3149 new DelayedSocketData(1, reads, arraysize(reads),
3150 writes, arraysize(writes)));
3151
[email protected]3caf5542010-07-16 15:19:473152 NormalSpdyTransactionHelper helper(CreateGetRequest(),
[email protected]9e9e842e2010-07-23 23:09:153153 BoundNetLog(), GetParam());
[email protected]3caf5542010-07-16 15:19:473154 helper.RunPreTestSetup();
[email protected]e3ebba0f2010-08-05 17:59:583155 helper.AddData(data.get());
[email protected]3caf5542010-07-16 15:19:473156 HttpNetworkTransaction* trans = helper.trans();
[email protected]8918d282010-03-02 00:57:553157
3158 TestCompletionCallback callback;
[email protected]d3cee19d2010-06-22 18:42:183159 int rv = trans->Start(&CreateGetRequest(), &callback, BoundNetLog());
[email protected]8918d282010-03-02 00:57:553160 EXPECT_EQ(ERR_IO_PENDING, rv);
3161
[email protected]3caf5542010-07-16 15:19:473162 TransactionHelperResult out = helper.output();
[email protected]8918d282010-03-02 00:57:553163 out.rv = callback.WaitForResult();
3164 EXPECT_EQ(out.rv, OK);
3165
3166 const HttpResponseInfo* response = trans->GetResponseInfo();
3167 EXPECT_TRUE(response->headers != NULL);
3168 EXPECT_TRUE(response->was_fetched_via_spdy);
3169 out.status_line = response->headers->GetStatusLine();
3170 out.response_info = *response; // Make a copy so we can verify.
3171
3172 // Read Data
3173 TestCompletionCallback read_callback;
3174
3175 std::string content;
3176 int reads_completed = 0;
3177 do {
3178 // Read small chunks at a time.
3179 const int kSmallReadSize = 14;
3180 scoped_refptr<net::IOBuffer> buf = new net::IOBuffer(kSmallReadSize);
3181 rv = trans->Read(buf, kSmallReadSize, &read_callback);
3182 if (rv == net::ERR_IO_PENDING) {
3183 data->CompleteRead();
3184 rv = read_callback.WaitForResult();
3185 }
3186 if (rv > 0) {
3187 EXPECT_EQ(kSmallReadSize, rv);
3188 content.append(buf->data(), rv);
3189 } else if (rv < 0) {
3190 FAIL() << "Unexpected read error: " << rv;
3191 }
3192 reads_completed++;
3193 } while (rv > 0);
3194
3195 EXPECT_EQ(3, reads_completed); // Reads are: 14 bytes, 14 bytes, 0 bytes.
3196
3197 out.response_data.swap(content);
3198
[email protected]30c942b2010-07-21 16:59:593199 // Flush the MessageLoop while the SpdySessionDependencies (in particular, the
[email protected]8918d282010-03-02 00:57:553200 // MockClientSocketFactory) are still alive.
3201 MessageLoop::current()->RunAllPending();
3202
3203 // Verify that we consumed all test data.
[email protected]3caf5542010-07-16 15:19:473204 helper.VerifyDataConsumed();
[email protected]8918d282010-03-02 00:57:553205
3206 EXPECT_EQ(OK, out.rv);
3207 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
3208 EXPECT_EQ("messagemessagemessagemessage", out.response_data);
3209}
3210
3211// Verify the case where we buffer data but read it after it has been buffered.
[email protected]9e9e842e2010-07-23 23:09:153212TEST_P(SpdyNetworkTransactionTest, BufferedAll) {
[email protected]20d005f2010-07-02 19:55:433213 spdy::SpdyFramer framer;
3214
[email protected]2bd93022010-07-17 00:58:443215 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST));
[email protected]e7f75092010-07-01 22:39:133216 MockWrite writes[] = { CreateMockWrite(*req) };
[email protected]8918d282010-03-02 00:57:553217
[email protected]20d005f2010-07-02 19:55:433218 // 5 data frames in a single read.
3219 scoped_ptr<spdy::SpdyFrame> syn_reply(
[email protected]2bd93022010-07-17 00:58:443220 ConstructSpdyGetSynReply(NULL, 0, 1));
[email protected]20d005f2010-07-02 19:55:433221 syn_reply->set_flags(spdy::CONTROL_FLAG_NONE); // turn off FIN bit
3222 scoped_ptr<spdy::SpdyFrame> data_frame(
3223 framer.CreateDataFrame(1, "message", 7, spdy::DATA_FLAG_NONE));
3224 scoped_ptr<spdy::SpdyFrame> data_frame_fin(
3225 framer.CreateDataFrame(1, "message", 7, spdy::DATA_FLAG_FIN));
3226 const spdy::SpdyFrame* frames[5] = {
3227 syn_reply.get(),
3228 data_frame.get(),
3229 data_frame.get(),
3230 data_frame.get(),
3231 data_frame_fin.get()
[email protected]8918d282010-03-02 00:57:553232 };
[email protected]20d005f2010-07-02 19:55:433233 char combined_frames[200];
3234 int combined_frames_len =
3235 CombineFrames(frames, arraysize(frames),
3236 combined_frames, arraysize(combined_frames));
[email protected]8918d282010-03-02 00:57:553237
3238 MockRead reads[] = {
[email protected]20d005f2010-07-02 19:55:433239 MockRead(true, combined_frames, combined_frames_len),
[email protected]8918d282010-03-02 00:57:553240 MockRead(true, 0, 0) // EOF
3241 };
3242
[email protected]8918d282010-03-02 00:57:553243 scoped_refptr<DelayedSocketData> data(
3244 new DelayedSocketData(1, reads, arraysize(reads),
3245 writes, arraysize(writes)));
3246
[email protected]3caf5542010-07-16 15:19:473247 NormalSpdyTransactionHelper helper(CreateGetRequest(),
[email protected]9e9e842e2010-07-23 23:09:153248 BoundNetLog(), GetParam());
[email protected]3caf5542010-07-16 15:19:473249 helper.RunPreTestSetup();
[email protected]e3ebba0f2010-08-05 17:59:583250 helper.AddData(data.get());
[email protected]3caf5542010-07-16 15:19:473251 HttpNetworkTransaction* trans = helper.trans();
[email protected]8918d282010-03-02 00:57:553252
3253 TestCompletionCallback callback;
[email protected]d3cee19d2010-06-22 18:42:183254 int rv = trans->Start(&CreateGetRequest(), &callback, BoundNetLog());
[email protected]8918d282010-03-02 00:57:553255 EXPECT_EQ(ERR_IO_PENDING, rv);
3256
[email protected]3caf5542010-07-16 15:19:473257 TransactionHelperResult out = helper.output();
[email protected]8918d282010-03-02 00:57:553258 out.rv = callback.WaitForResult();
3259 EXPECT_EQ(out.rv, OK);
3260
3261 const HttpResponseInfo* response = trans->GetResponseInfo();
3262 EXPECT_TRUE(response->headers != NULL);
3263 EXPECT_TRUE(response->was_fetched_via_spdy);
3264 out.status_line = response->headers->GetStatusLine();
3265 out.response_info = *response; // Make a copy so we can verify.
3266
3267 // Read Data
3268 TestCompletionCallback read_callback;
3269
3270 std::string content;
3271 int reads_completed = 0;
3272 do {
3273 // Read small chunks at a time.
3274 const int kSmallReadSize = 14;
3275 scoped_refptr<net::IOBuffer> buf = new net::IOBuffer(kSmallReadSize);
3276 rv = trans->Read(buf, kSmallReadSize, &read_callback);
3277 if (rv > 0) {
3278 EXPECT_EQ(kSmallReadSize, rv);
3279 content.append(buf->data(), rv);
3280 } else if (rv < 0) {
3281 FAIL() << "Unexpected read error: " << rv;
3282 }
3283 reads_completed++;
3284 } while (rv > 0);
3285
3286 EXPECT_EQ(3, reads_completed);
3287
3288 out.response_data.swap(content);
3289
[email protected]30c942b2010-07-21 16:59:593290 // Flush the MessageLoop while the SpdySessionDependencies (in particular, the
[email protected]8918d282010-03-02 00:57:553291 // MockClientSocketFactory) are still alive.
3292 MessageLoop::current()->RunAllPending();
3293
3294 // Verify that we consumed all test data.
[email protected]3caf5542010-07-16 15:19:473295 helper.VerifyDataConsumed();
[email protected]8918d282010-03-02 00:57:553296
3297 EXPECT_EQ(OK, out.rv);
3298 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
3299 EXPECT_EQ("messagemessagemessagemessage", out.response_data);
3300}
3301
3302// Verify the case where we buffer data and close the connection.
[email protected]9e9e842e2010-07-23 23:09:153303TEST_P(SpdyNetworkTransactionTest, BufferedClosed) {
[email protected]20d005f2010-07-02 19:55:433304 spdy::SpdyFramer framer;
3305
[email protected]2bd93022010-07-17 00:58:443306 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST));
[email protected]e7f75092010-07-01 22:39:133307 MockWrite writes[] = { CreateMockWrite(*req) };
[email protected]8918d282010-03-02 00:57:553308
3309 // All data frames in a single read.
[email protected]20d005f2010-07-02 19:55:433310 // NOTE: We don't FIN the stream.
3311 scoped_ptr<spdy::SpdyFrame> data_frame(
3312 framer.CreateDataFrame(1, "message", 7, spdy::DATA_FLAG_NONE));
3313 const spdy::SpdyFrame* data_frames[4] = {
3314 data_frame.get(),
3315 data_frame.get(),
3316 data_frame.get(),
3317 data_frame.get()
[email protected]8918d282010-03-02 00:57:553318 };
[email protected]20d005f2010-07-02 19:55:433319 char combined_data_frames[100];
3320 int combined_data_frames_len =
3321 CombineFrames(data_frames, arraysize(data_frames),
3322 combined_data_frames, arraysize(combined_data_frames));
[email protected]2bd93022010-07-17 00:58:443323 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1));
[email protected]8918d282010-03-02 00:57:553324 MockRead reads[] = {
[email protected]e7f75092010-07-01 22:39:133325 CreateMockRead(*resp),
[email protected]8918d282010-03-02 00:57:553326 MockRead(true, ERR_IO_PENDING), // Force a wait
[email protected]20d005f2010-07-02 19:55:433327 MockRead(true, combined_data_frames, combined_data_frames_len),
[email protected]8918d282010-03-02 00:57:553328 MockRead(true, 0, 0) // EOF
3329 };
3330
[email protected]8918d282010-03-02 00:57:553331 scoped_refptr<DelayedSocketData> data(
3332 new DelayedSocketData(1, reads, arraysize(reads),
3333 writes, arraysize(writes)));
3334
[email protected]3caf5542010-07-16 15:19:473335 NormalSpdyTransactionHelper helper(CreateGetRequest(),
[email protected]9e9e842e2010-07-23 23:09:153336 BoundNetLog(), GetParam());
[email protected]3caf5542010-07-16 15:19:473337 helper.RunPreTestSetup();
[email protected]e3ebba0f2010-08-05 17:59:583338 helper.AddData(data.get());
[email protected]3caf5542010-07-16 15:19:473339 HttpNetworkTransaction* trans = helper.trans();
[email protected]8918d282010-03-02 00:57:553340
3341 TestCompletionCallback callback;
3342
[email protected]d3cee19d2010-06-22 18:42:183343 int rv = trans->Start(&CreateGetRequest(), &callback, BoundNetLog());
[email protected]8918d282010-03-02 00:57:553344 EXPECT_EQ(ERR_IO_PENDING, rv);
3345
[email protected]3caf5542010-07-16 15:19:473346 TransactionHelperResult out = helper.output();
[email protected]8918d282010-03-02 00:57:553347 out.rv = callback.WaitForResult();
3348 EXPECT_EQ(out.rv, OK);
3349
3350 const HttpResponseInfo* response = trans->GetResponseInfo();
3351 EXPECT_TRUE(response->headers != NULL);
3352 EXPECT_TRUE(response->was_fetched_via_spdy);
3353 out.status_line = response->headers->GetStatusLine();
3354 out.response_info = *response; // Make a copy so we can verify.
3355
3356 // Read Data
3357 TestCompletionCallback read_callback;
3358
3359 std::string content;
3360 int reads_completed = 0;
3361 do {
3362 // Read small chunks at a time.
3363 const int kSmallReadSize = 14;
3364 scoped_refptr<net::IOBuffer> buf = new net::IOBuffer(kSmallReadSize);
3365 rv = trans->Read(buf, kSmallReadSize, &read_callback);
3366 if (rv == net::ERR_IO_PENDING) {
3367 data->CompleteRead();
3368 rv = read_callback.WaitForResult();
3369 }
3370 if (rv > 0) {
3371 content.append(buf->data(), rv);
3372 } else if (rv < 0) {
3373 // This test intentionally closes the connection, and will get an error.
3374 EXPECT_EQ(ERR_CONNECTION_CLOSED, rv);
3375 break;
3376 }
3377 reads_completed++;
3378 } while (rv > 0);
3379
3380 EXPECT_EQ(0, reads_completed);
3381
3382 out.response_data.swap(content);
3383
[email protected]30c942b2010-07-21 16:59:593384 // Flush the MessageLoop while the SpdySessionDependencies (in particular, the
[email protected]8918d282010-03-02 00:57:553385 // MockClientSocketFactory) are still alive.
3386 MessageLoop::current()->RunAllPending();
3387
3388 // Verify that we consumed all test data.
[email protected]3caf5542010-07-16 15:19:473389 helper.VerifyDataConsumed();
[email protected]8918d282010-03-02 00:57:553390}
3391
[email protected]1ed7b3dc2010-03-04 05:41:453392// Verify the case where we buffer data and cancel the transaction.
[email protected]9e9e842e2010-07-23 23:09:153393TEST_P(SpdyNetworkTransactionTest, BufferedCancelled) {
[email protected]20d005f2010-07-02 19:55:433394 spdy::SpdyFramer framer;
3395
[email protected]2bd93022010-07-17 00:58:443396 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST));
[email protected]e7f75092010-07-01 22:39:133397 MockWrite writes[] = { CreateMockWrite(*req) };
[email protected]1ed7b3dc2010-03-04 05:41:453398
[email protected]20d005f2010-07-02 19:55:433399 // NOTE: We don't FIN the stream.
3400 scoped_ptr<spdy::SpdyFrame> data_frame(
3401 framer.CreateDataFrame(1, "message", 7, spdy::DATA_FLAG_NONE));
[email protected]1ed7b3dc2010-03-04 05:41:453402
[email protected]2bd93022010-07-17 00:58:443403 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1));
[email protected]1ed7b3dc2010-03-04 05:41:453404 MockRead reads[] = {
[email protected]e7f75092010-07-01 22:39:133405 CreateMockRead(*resp),
[email protected]1ed7b3dc2010-03-04 05:41:453406 MockRead(true, ERR_IO_PENDING), // Force a wait
[email protected]20d005f2010-07-02 19:55:433407 CreateMockRead(*data_frame),
[email protected]1ed7b3dc2010-03-04 05:41:453408 MockRead(true, 0, 0) // EOF
3409 };
3410
[email protected]1ed7b3dc2010-03-04 05:41:453411 scoped_refptr<DelayedSocketData> data(
3412 new DelayedSocketData(1, reads, arraysize(reads),
3413 writes, arraysize(writes)));
3414
[email protected]3caf5542010-07-16 15:19:473415 NormalSpdyTransactionHelper helper(CreateGetRequest(),
[email protected]9e9e842e2010-07-23 23:09:153416 BoundNetLog(), GetParam());
[email protected]3caf5542010-07-16 15:19:473417 helper.RunPreTestSetup();
[email protected]e3ebba0f2010-08-05 17:59:583418 helper.AddData(data.get());
[email protected]3caf5542010-07-16 15:19:473419 HttpNetworkTransaction* trans = helper.trans();
[email protected]1ed7b3dc2010-03-04 05:41:453420 TestCompletionCallback callback;
3421
[email protected]d3cee19d2010-06-22 18:42:183422 int rv = trans->Start(&CreateGetRequest(), &callback, BoundNetLog());
[email protected]1ed7b3dc2010-03-04 05:41:453423 EXPECT_EQ(ERR_IO_PENDING, rv);
3424
[email protected]3caf5542010-07-16 15:19:473425 TransactionHelperResult out = helper.output();
[email protected]1ed7b3dc2010-03-04 05:41:453426 out.rv = callback.WaitForResult();
3427 EXPECT_EQ(out.rv, OK);
3428
3429 const HttpResponseInfo* response = trans->GetResponseInfo();
3430 EXPECT_TRUE(response->headers != NULL);
3431 EXPECT_TRUE(response->was_fetched_via_spdy);
3432 out.status_line = response->headers->GetStatusLine();
3433 out.response_info = *response; // Make a copy so we can verify.
3434
3435 // Read Data
3436 TestCompletionCallback read_callback;
3437
3438 do {
3439 const int kReadSize = 256;
3440 scoped_refptr<net::IOBuffer> buf = new net::IOBuffer(kReadSize);
3441 rv = trans->Read(buf, kReadSize, &read_callback);
3442 if (rv == net::ERR_IO_PENDING) {
3443 // Complete the read now, which causes buffering to start.
3444 data->CompleteRead();
3445 // Destroy the transaction, causing the stream to get cancelled
3446 // and orphaning the buffered IO task.
[email protected]3caf5542010-07-16 15:19:473447 helper.ResetTrans();
[email protected]1ed7b3dc2010-03-04 05:41:453448 break;
3449 }
3450 // We shouldn't get here in this test.
3451 FAIL() << "Unexpected read: " << rv;
3452 } while (rv > 0);
3453
3454 // Flush the MessageLoop; this will cause the buffered IO task
3455 // to run for the final time.
3456 MessageLoop::current()->RunAllPending();
[email protected]3caf5542010-07-16 15:19:473457
3458 // Verify that we consumed all test data.
3459 helper.VerifyDataConsumed();
[email protected]1ed7b3dc2010-03-04 05:41:453460}
3461
[email protected]74188f22010-04-09 20:18:503462// Test that if the server requests persistence of settings, that we save
3463// the settings in the SpdySettingsStorage.
[email protected]9e9e842e2010-07-23 23:09:153464TEST_P(SpdyNetworkTransactionTest, SettingsSaved) {
[email protected]74188f22010-04-09 20:18:503465 static const SpdyHeaderInfo kSynReplyInfo = {
3466 spdy::SYN_REPLY, // Syn Reply
3467 1, // Stream ID
3468 0, // Associated Stream ID
[email protected]c9c6f5c2010-07-31 01:30:033469 net::ConvertRequestPriorityToSpdyPriority(LOWEST),
3470 // Priority
[email protected]74188f22010-04-09 20:18:503471 spdy::CONTROL_FLAG_NONE, // Control Flags
3472 false, // Compressed
[email protected]75f30cc22010-06-28 21:41:383473 spdy::INVALID, // Status
[email protected]74188f22010-04-09 20:18:503474 NULL, // Data
3475 0, // Data Length
3476 spdy::DATA_FLAG_NONE // Data Flags
3477 };
3478 static const char* const kExtraHeaders[] = {
3479 "status", "200",
3480 "version", "HTTP/1.1"
3481 };
3482
[email protected]3caf5542010-07-16 15:19:473483 NormalSpdyTransactionHelper helper(CreateGetRequest(),
[email protected]9e9e842e2010-07-23 23:09:153484 BoundNetLog(), GetParam());
[email protected]e3ebba0f2010-08-05 17:59:583485 helper.RunPreTestSetup();
[email protected]74188f22010-04-09 20:18:503486
3487 // Verify that no settings exist initially.
[email protected]9e9e842e2010-07-23 23:09:153488 HostPortPair host_port_pair("www.google.com", helper.port());
[email protected]3caf5542010-07-16 15:19:473489 EXPECT_TRUE(helper.session()->spdy_settings().Get(host_port_pair).empty());
[email protected]74188f22010-04-09 20:18:503490
3491 // Construct the request.
[email protected]2bd93022010-07-17 00:58:443492 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST));
[email protected]e7f75092010-07-01 22:39:133493 MockWrite writes[] = { CreateMockWrite(*req) };
[email protected]74188f22010-04-09 20:18:503494
3495 // Construct the reply.
3496 scoped_ptr<spdy::SpdyFrame> reply(
[email protected]a4aeaf42010-06-30 19:57:283497 ConstructSpdyPacket(kSynReplyInfo,
[email protected]74188f22010-04-09 20:18:503498 kExtraHeaders,
3499 arraysize(kExtraHeaders) / 2,
3500 NULL,
3501 0));
3502
3503 unsigned int kSampleId1 = 0x1;
3504 unsigned int kSampleValue1 = 0x0a0a0a0a;
3505 unsigned int kSampleId2 = 0x2;
3506 unsigned int kSampleValue2 = 0x0b0b0b0b;
3507 unsigned int kSampleId3 = 0xababab;
3508 unsigned int kSampleValue3 = 0x0c0c0c0c;
3509 scoped_ptr<spdy::SpdyFrame> settings_frame;
3510 {
3511 // Construct the SETTINGS frame.
3512 spdy::SpdySettings settings;
3513 spdy::SettingsFlagsAndId setting(0);
3514 // First add a persisted setting
3515 setting.set_flags(spdy::SETTINGS_FLAG_PLEASE_PERSIST);
3516 setting.set_id(kSampleId1);
3517 settings.push_back(std::make_pair(setting, kSampleValue1));
3518 // Next add a non-persisted setting
3519 setting.set_flags(0);
3520 setting.set_id(kSampleId2);
3521 settings.push_back(std::make_pair(setting, kSampleValue2));
3522 // Next add another persisted setting
3523 setting.set_flags(spdy::SETTINGS_FLAG_PLEASE_PERSIST);
3524 setting.set_id(kSampleId3);
3525 settings.push_back(std::make_pair(setting, kSampleValue3));
3526 settings_frame.reset(ConstructSpdySettings(settings));
3527 }
3528
[email protected]2bd93022010-07-17 00:58:443529 scoped_ptr<spdy::SpdyFrame> body(ConstructSpdyBodyFrame(1, true));
[email protected]74188f22010-04-09 20:18:503530 MockRead reads[] = {
[email protected]e7f75092010-07-01 22:39:133531 CreateMockRead(*reply),
3532 CreateMockRead(*body),
3533 CreateMockRead(*settings_frame),
[email protected]74188f22010-04-09 20:18:503534 MockRead(true, 0, 0) // EOF
3535 };
3536
[email protected]74188f22010-04-09 20:18:503537 scoped_refptr<DelayedSocketData> data(
3538 new DelayedSocketData(1, reads, arraysize(reads),
3539 writes, arraysize(writes)));
[email protected]e3ebba0f2010-08-05 17:59:583540 helper.AddData(data.get());
3541 helper.RunDefaultTest();
3542 helper.VerifyDataConsumed();
[email protected]3caf5542010-07-16 15:19:473543 TransactionHelperResult out = helper.output();
[email protected]74188f22010-04-09 20:18:503544 EXPECT_EQ(OK, out.rv);
3545 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
3546 EXPECT_EQ("hello!", out.response_data);
3547
3548 {
3549 // Verify we had two persisted settings.
3550 spdy::SpdySettings saved_settings =
[email protected]3caf5542010-07-16 15:19:473551 helper.session()->spdy_settings().Get(host_port_pair);
[email protected]74188f22010-04-09 20:18:503552 ASSERT_EQ(2u, saved_settings.size());
3553
3554 // Verify the first persisted setting.
3555 spdy::SpdySetting setting = saved_settings.front();
3556 saved_settings.pop_front();
3557 EXPECT_EQ(spdy::SETTINGS_FLAG_PERSISTED, setting.first.flags());
3558 EXPECT_EQ(kSampleId1, setting.first.id());
3559 EXPECT_EQ(kSampleValue1, setting.second);
3560
3561 // Verify the second persisted setting.
3562 setting = saved_settings.front();
3563 saved_settings.pop_front();
3564 EXPECT_EQ(spdy::SETTINGS_FLAG_PERSISTED, setting.first.flags());
3565 EXPECT_EQ(kSampleId3, setting.first.id());
3566 EXPECT_EQ(kSampleValue3, setting.second);
3567 }
3568}
3569
3570// Test that when there are settings saved that they are sent back to the
3571// server upon session establishment.
[email protected]9e9e842e2010-07-23 23:09:153572TEST_P(SpdyNetworkTransactionTest, SettingsPlayback) {
[email protected]74188f22010-04-09 20:18:503573 static const SpdyHeaderInfo kSynReplyInfo = {
3574 spdy::SYN_REPLY, // Syn Reply
3575 1, // Stream ID
3576 0, // Associated Stream ID
[email protected]c9c6f5c2010-07-31 01:30:033577 net::ConvertRequestPriorityToSpdyPriority(LOWEST),
3578 // Priority
[email protected]74188f22010-04-09 20:18:503579 spdy::CONTROL_FLAG_NONE, // Control Flags
3580 false, // Compressed
[email protected]75f30cc22010-06-28 21:41:383581 spdy::INVALID, // Status
[email protected]74188f22010-04-09 20:18:503582 NULL, // Data
3583 0, // Data Length
3584 spdy::DATA_FLAG_NONE // Data Flags
3585 };
3586 static const char* kExtraHeaders[] = {
3587 "status", "200",
3588 "version", "HTTP/1.1"
3589 };
3590
[email protected]3caf5542010-07-16 15:19:473591 NormalSpdyTransactionHelper helper(CreateGetRequest(),
[email protected]9e9e842e2010-07-23 23:09:153592 BoundNetLog(), GetParam());
[email protected]e3ebba0f2010-08-05 17:59:583593 helper.RunPreTestSetup();
[email protected]74188f22010-04-09 20:18:503594
3595 // Verify that no settings exist initially.
[email protected]9e9e842e2010-07-23 23:09:153596 HostPortPair host_port_pair("www.google.com", helper.port());
[email protected]3caf5542010-07-16 15:19:473597 EXPECT_TRUE(helper.session()->spdy_settings().Get(host_port_pair).empty());
[email protected]74188f22010-04-09 20:18:503598
3599 unsigned int kSampleId1 = 0x1;
3600 unsigned int kSampleValue1 = 0x0a0a0a0a;
3601 unsigned int kSampleId2 = 0xababab;
3602 unsigned int kSampleValue2 = 0x0c0c0c0c;
3603 // Manually insert settings into the SpdySettingsStorage here.
3604 {
3605 spdy::SpdySettings settings;
3606 spdy::SettingsFlagsAndId setting(0);
3607 // First add a persisted setting
3608 setting.set_flags(spdy::SETTINGS_FLAG_PLEASE_PERSIST);
3609 setting.set_id(kSampleId1);
3610 settings.push_back(std::make_pair(setting, kSampleValue1));
3611 // Next add another persisted setting
3612 setting.set_flags(spdy::SETTINGS_FLAG_PLEASE_PERSIST);
3613 setting.set_id(kSampleId2);
3614 settings.push_back(std::make_pair(setting, kSampleValue2));
3615
[email protected]3caf5542010-07-16 15:19:473616 helper.session()->mutable_spdy_settings()->Set(host_port_pair, settings);
[email protected]74188f22010-04-09 20:18:503617 }
3618
[email protected]3caf5542010-07-16 15:19:473619 EXPECT_EQ(2u, helper.session()->spdy_settings().Get(host_port_pair).size());
[email protected]74188f22010-04-09 20:18:503620
3621 // Construct the SETTINGS frame.
3622 const spdy::SpdySettings& settings =
[email protected]3caf5542010-07-16 15:19:473623 helper.session()->spdy_settings().Get(host_port_pair);
[email protected]74188f22010-04-09 20:18:503624 scoped_ptr<spdy::SpdyFrame> settings_frame(ConstructSpdySettings(settings));
3625
3626 // Construct the request.
[email protected]2bd93022010-07-17 00:58:443627 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST));
[email protected]74188f22010-04-09 20:18:503628
3629 MockWrite writes[] = {
[email protected]e7f75092010-07-01 22:39:133630 CreateMockWrite(*settings_frame),
3631 CreateMockWrite(*req),
[email protected]74188f22010-04-09 20:18:503632 };
3633
3634 // Construct the reply.
3635 scoped_ptr<spdy::SpdyFrame> reply(
[email protected]a4aeaf42010-06-30 19:57:283636 ConstructSpdyPacket(kSynReplyInfo,
[email protected]74188f22010-04-09 20:18:503637 kExtraHeaders,
3638 arraysize(kExtraHeaders) / 2,
3639 NULL,
3640 0));
3641
[email protected]2bd93022010-07-17 00:58:443642 scoped_ptr<spdy::SpdyFrame> body(ConstructSpdyBodyFrame(1, true));
[email protected]74188f22010-04-09 20:18:503643 MockRead reads[] = {
[email protected]e7f75092010-07-01 22:39:133644 CreateMockRead(*reply),
3645 CreateMockRead(*body),
[email protected]74188f22010-04-09 20:18:503646 MockRead(true, 0, 0) // EOF
3647 };
3648
[email protected]74188f22010-04-09 20:18:503649 scoped_refptr<DelayedSocketData> data(
3650 new DelayedSocketData(2, reads, arraysize(reads),
3651 writes, arraysize(writes)));
[email protected]e3ebba0f2010-08-05 17:59:583652 helper.AddData(data.get());
3653 helper.RunDefaultTest();
3654 helper.VerifyDataConsumed();
[email protected]3caf5542010-07-16 15:19:473655 TransactionHelperResult out = helper.output();
[email protected]74188f22010-04-09 20:18:503656 EXPECT_EQ(OK, out.rv);
3657 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
3658 EXPECT_EQ("hello!", out.response_data);
3659
3660 {
3661 // Verify we had two persisted settings.
3662 spdy::SpdySettings saved_settings =
[email protected]3caf5542010-07-16 15:19:473663 helper.session()->spdy_settings().Get(host_port_pair);
[email protected]74188f22010-04-09 20:18:503664 ASSERT_EQ(2u, saved_settings.size());
3665
3666 // Verify the first persisted setting.
3667 spdy::SpdySetting setting = saved_settings.front();
3668 saved_settings.pop_front();
3669 EXPECT_EQ(spdy::SETTINGS_FLAG_PERSISTED, setting.first.flags());
3670 EXPECT_EQ(kSampleId1, setting.first.id());
3671 EXPECT_EQ(kSampleValue1, setting.second);
3672
3673 // Verify the second persisted setting.
3674 setting = saved_settings.front();
3675 saved_settings.pop_front();
3676 EXPECT_EQ(spdy::SETTINGS_FLAG_PERSISTED, setting.first.flags());
3677 EXPECT_EQ(kSampleId2, setting.first.id());
3678 EXPECT_EQ(kSampleValue2, setting.second);
3679 }
3680}
3681
[email protected]9e9e842e2010-07-23 23:09:153682TEST_P(SpdyNetworkTransactionTest, GoAwayWithActiveStream) {
[email protected]2bd93022010-07-17 00:58:443683 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST));
[email protected]e7f75092010-07-01 22:39:133684 MockWrite writes[] = { CreateMockWrite(*req) };
[email protected]69d717bd2010-04-21 18:43:213685
[email protected]a4aeaf42010-06-30 19:57:283686 scoped_ptr<spdy::SpdyFrame> go_away(ConstructSpdyGoAway());
[email protected]69d717bd2010-04-21 18:43:213687 MockRead reads[] = {
[email protected]e7f75092010-07-01 22:39:133688 CreateMockRead(*go_away),
[email protected]58cebf8f2010-07-31 19:20:163689 MockRead(true, 0, 0), // EOF
3690 };
3691
[email protected]69d717bd2010-04-21 18:43:213692 scoped_refptr<DelayedSocketData> data(
3693 new DelayedSocketData(1, reads, arraysize(reads),
3694 writes, arraysize(writes)));
[email protected]3caf5542010-07-16 15:19:473695 NormalSpdyTransactionHelper helper(CreateGetRequest(),
[email protected]9e9e842e2010-07-23 23:09:153696 BoundNetLog(), GetParam());
[email protected]58cebf8f2010-07-31 19:20:163697 helper.AddData(data);
[email protected]58cebf8f2010-07-31 19:20:163698 helper.RunToCompletion(data.get());
3699 TransactionHelperResult out = helper.output();
[email protected]c9336d22010-08-10 00:04:183700 EXPECT_EQ(ERR_ABORTED, out.rv);
[email protected]69d717bd2010-04-21 18:43:213701}
3702
[email protected]9e9e842e2010-07-23 23:09:153703TEST_P(SpdyNetworkTransactionTest, CloseWithActiveStream) {
[email protected]2bd93022010-07-17 00:58:443704 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST));
[email protected]e7f75092010-07-01 22:39:133705 MockWrite writes[] = { CreateMockWrite(*req) };
[email protected]f5ed21552010-05-04 18:39:543706
[email protected]2bd93022010-07-17 00:58:443707 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1));
[email protected]f5ed21552010-05-04 18:39:543708 MockRead reads[] = {
[email protected]e7f75092010-07-01 22:39:133709 CreateMockRead(*resp),
[email protected]f5ed21552010-05-04 18:39:543710 MockRead(false, 0, 0) // EOF
3711 };
3712
[email protected]f5ed21552010-05-04 18:39:543713 scoped_refptr<DelayedSocketData> data(
3714 new DelayedSocketData(1, reads, arraysize(reads),
3715 writes, arraysize(writes)));
[email protected]f5ed21552010-05-04 18:39:543716 BoundNetLog log;
[email protected]3caf5542010-07-16 15:19:473717 NormalSpdyTransactionHelper helper(CreateGetRequest(),
[email protected]9e9e842e2010-07-23 23:09:153718 log, GetParam());
[email protected]3caf5542010-07-16 15:19:473719 helper.RunPreTestSetup();
[email protected]e3ebba0f2010-08-05 17:59:583720 helper.AddData(data.get());
[email protected]3caf5542010-07-16 15:19:473721 HttpNetworkTransaction* trans = helper.trans();
[email protected]f5ed21552010-05-04 18:39:543722
3723 TestCompletionCallback callback;
[email protected]3caf5542010-07-16 15:19:473724 TransactionHelperResult out;
[email protected]d3cee19d2010-06-22 18:42:183725 out.rv = trans->Start(&CreateGetRequest(), &callback, log);
[email protected]3caf5542010-07-16 15:19:473726
[email protected]f5ed21552010-05-04 18:39:543727 EXPECT_EQ(out.rv, ERR_IO_PENDING);
3728 out.rv = callback.WaitForResult();
3729 EXPECT_EQ(out.rv, OK);
3730
3731 const HttpResponseInfo* response = trans->GetResponseInfo();
3732 EXPECT_TRUE(response->headers != NULL);
3733 EXPECT_TRUE(response->was_fetched_via_spdy);
[email protected]3caf5542010-07-16 15:19:473734 out.rv = ReadTransaction(trans, &out.response_data);
[email protected]f5ed21552010-05-04 18:39:543735 EXPECT_EQ(ERR_CONNECTION_CLOSED, out.rv);
3736
3737 // Verify that we consumed all test data.
[email protected]3caf5542010-07-16 15:19:473738 helper.VerifyDataConsumed();
[email protected]f5ed21552010-05-04 18:39:543739}
[email protected]58cebf8f2010-07-31 19:20:163740
[email protected]b261d0e2010-08-02 19:13:243741// Test to make sure we can correctly connect through a proxy.
3742TEST_P(SpdyNetworkTransactionTest, ProxyConnect) {
3743 NormalSpdyTransactionHelper helper(CreateGetRequest(),
3744 BoundNetLog(), GetParam());
3745 helper.session_deps().reset(new SpdySessionDependencies(
3746 net::SpdyCreateFixedProxyService("myproxy:70")));
3747 helper.session() = SpdySessionDependencies::SpdyCreateSession(
3748 helper.session_deps().get());
3749 helper.RunPreTestSetup();
3750 HttpNetworkTransaction* trans = helper.trans();
3751
3752 const char kConnect443[] = {"CONNECT www.google.com:443 HTTP/1.1\r\n"
3753 "Host: www.google.com\r\n"
3754 "Proxy-Connection: keep-alive\r\n\r\n"};
3755 const char kConnect80[] = {"CONNECT www.google.com:80 HTTP/1.1\r\n"
3756 "Host: www.google.com\r\n"
3757 "Proxy-Connection: keep-alive\r\n\r\n"};
3758 const char kHTTP200[] = {"HTTP/1.1 200 OK\r\n\r\n"};
3759 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST));
3760 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1));
3761 scoped_ptr<spdy::SpdyFrame> body(ConstructSpdyBodyFrame(1, true));
3762
3763 MockWrite writes_SPDYNPN[] = {
3764 MockWrite(false, kConnect443, arraysize(kConnect443) - 1, 0),
3765 CreateMockWrite(*req, 2),
3766 };
3767 MockRead reads_SPDYNPN[] = {
3768 MockRead(false, kHTTP200, arraysize(kHTTP200) - 1, 1),
3769 CreateMockRead(*resp, 3),
3770 CreateMockRead(*body.get(), 4),
3771 MockRead(true, 0, 0, 5),
3772 };
3773
3774 MockWrite writes_SPDYSSL[] = {
3775 MockWrite(false, kConnect80, arraysize(kConnect80) - 1, 0),
3776 CreateMockWrite(*req, 2),
3777 };
3778 MockRead reads_SPDYSSL[] = {
3779 MockRead(false, kHTTP200, arraysize(kHTTP200) - 1, 1),
3780 CreateMockRead(*resp, 3),
3781 CreateMockRead(*body.get(), 4),
3782 MockRead(true, 0, 0, 5),
3783 };
3784
3785 MockWrite writes_SPDYNOSSL[] = {
3786 CreateMockWrite(*req, 0),
3787 };
3788
3789 MockRead reads_SPDYNOSSL[] = {
3790 CreateMockRead(*resp, 1),
3791 CreateMockRead(*body.get(), 2),
3792 MockRead(true, 0, 0, 3),
3793 };
3794
3795 scoped_refptr<OrderedSocketData> data;
3796 switch(GetParam()) {
3797 case SPDYNOSSL:
3798 data = new OrderedSocketData(reads_SPDYNOSSL,
3799 arraysize(reads_SPDYNOSSL),
3800 writes_SPDYNOSSL,
3801 arraysize(writes_SPDYNOSSL));
3802 break;
3803 case SPDYSSL:
3804 data = new OrderedSocketData(reads_SPDYSSL, arraysize(reads_SPDYSSL),
3805 writes_SPDYSSL, arraysize(writes_SPDYSSL));
3806 break;
3807 case SPDYNPN:
3808 data = new OrderedSocketData(reads_SPDYNPN, arraysize(reads_SPDYNPN),
3809 writes_SPDYNPN, arraysize(writes_SPDYNPN));
3810 break;
3811 default:
3812 NOTREACHED();
3813 }
3814
3815 helper.AddData(data.get());
3816 TestCompletionCallback callback;
3817
3818 int rv = trans->Start(&CreateGetRequest(), &callback, BoundNetLog());
3819 EXPECT_EQ(ERR_IO_PENDING, rv);
3820
3821 rv = callback.WaitForResult();
3822 EXPECT_EQ(0, rv);
3823
3824 // Verify the SYN_REPLY.
3825 HttpResponseInfo response = *trans->GetResponseInfo();
3826 EXPECT_TRUE(response.headers != NULL);
3827 EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine());
3828
3829 std::string response_data;
3830 ASSERT_EQ(OK, ReadTransaction(trans, &response_data));
3831 EXPECT_EQ("hello!", response_data);
3832 helper.VerifyDataConsumed();
3833}
3834
3835// Test to make sure we can correctly connect through a proxy to www.google.com,
3836// if there already exists a direct spdy connection to www.google.com. See
3837// http://crbug.com/49874
3838TEST_P(SpdyNetworkTransactionTest, DirectConnectProxyReconnect) {
3839 // When setting up the first transaction, we store the SpdySessionPool so that
3840 // we can use the same pool in the second transaction.
3841 NormalSpdyTransactionHelper helper(CreateGetRequest(),
3842 BoundNetLog(), GetParam());
3843 scoped_refptr<SpdySessionPool> spdy_session_pool =
3844 helper.session_deps()->spdy_session_pool;
3845 helper.RunPreTestSetup();
3846
3847 // Construct and send a simple GET request.
3848 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST));
3849 MockWrite writes[] = {
3850 CreateMockWrite(*req, 1),
3851 };
3852
3853 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1));
3854 scoped_ptr<spdy::SpdyFrame> body(ConstructSpdyBodyFrame(1, true));
3855 MockRead reads[] = {
3856 CreateMockRead(*resp, 2),
3857 CreateMockRead(*body, 3),
3858 MockRead(true, ERR_IO_PENDING, 4), // Force a pause
3859 MockRead(true, 0, 5) // EOF
3860 };
3861 scoped_refptr<OrderedSocketData> data(
3862 new OrderedSocketData(reads, arraysize(reads),
3863 writes, arraysize(writes)));
3864 helper.AddData(data.get());
3865 HttpNetworkTransaction* trans = helper.trans();
3866
3867 TestCompletionCallback callback;
3868 TransactionHelperResult out;
3869 out.rv = trans->Start(&CreateGetRequest(), &callback, BoundNetLog());
3870
3871 EXPECT_EQ(out.rv, ERR_IO_PENDING);
3872 out.rv = callback.WaitForResult();
3873 EXPECT_EQ(out.rv, OK);
3874
3875 const HttpResponseInfo* response = trans->GetResponseInfo();
3876 EXPECT_TRUE(response->headers != NULL);
3877 EXPECT_TRUE(response->was_fetched_via_spdy);
3878 out.rv = ReadTransaction(trans, &out.response_data);
3879 EXPECT_EQ(OK, out.rv);
3880 out.status_line = response->headers->GetStatusLine();
3881 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
3882 EXPECT_EQ("hello!", out.response_data);
3883
3884 // Check that the SpdySession is still in the SpdySessionPool.
3885 HostPortPair host_port_pair("www.google.com", helper.port());
3886 HostPortProxyPair pair(host_port_pair, "DIRECT");
3887 EXPECT_TRUE(spdy_session_pool->HasSession(pair));
3888 HostPortProxyPair nonexistent_pair(host_port_pair, "PROXY www.foo.com");
3889 EXPECT_FALSE(spdy_session_pool->HasSession(nonexistent_pair));
3890
3891 // Set up data for the proxy connection.
3892 const char kConnect443[] = {"CONNECT www.google.com:443 HTTP/1.1\r\n"
3893 "Host: www.google.com\r\n"
3894 "Proxy-Connection: keep-alive\r\n\r\n"};
3895 const char kConnect80[] = {"CONNECT www.google.com:80 HTTP/1.1\r\n"
3896 "Host: www.google.com\r\n"
3897 "Proxy-Connection: keep-alive\r\n\r\n"};
3898 const char kHTTP200[] = {"HTTP/1.1 200 OK\r\n\r\n"};
3899 scoped_ptr<spdy::SpdyFrame> req2(ConstructSpdyGet(
3900 "http://www.google.com/foo.dat", false, 1, LOWEST));
3901 scoped_ptr<spdy::SpdyFrame> resp2(ConstructSpdyGetSynReply(NULL, 0, 1));
3902 scoped_ptr<spdy::SpdyFrame> body2(ConstructSpdyBodyFrame(1, true));
3903
3904 MockWrite writes_SPDYNPN[] = {
3905 MockWrite(false, kConnect443, arraysize(kConnect443) - 1, 0),
3906 CreateMockWrite(*req2, 2),
3907 };
3908 MockRead reads_SPDYNPN[] = {
3909 MockRead(false, kHTTP200, arraysize(kHTTP200) - 1, 1),
3910 CreateMockRead(*resp2, 3),
3911 CreateMockRead(*body2, 4),
3912 MockRead(true, 0, 5) // EOF
3913 };
3914
3915 MockWrite writes_SPDYNOSSL[] = {
3916 CreateMockWrite(*req2, 0),
3917 };
3918 MockRead reads_SPDYNOSSL[] = {
3919 CreateMockRead(*resp2, 1),
3920 CreateMockRead(*body2, 2),
3921 MockRead(true, 0, 3) // EOF
3922 };
3923
3924 MockWrite writes_SPDYSSL[] = {
3925 MockWrite(false, kConnect80, arraysize(kConnect80) - 1, 0),
3926 CreateMockWrite(*req2, 2),
3927 };
3928 MockRead reads_SPDYSSL[] = {
3929 MockRead(false, kHTTP200, arraysize(kHTTP200) - 1, 1),
3930 CreateMockRead(*resp2, 3),
3931 CreateMockRead(*body2, 4),
3932 MockRead(true, 0, 0, 5),
3933 };
3934
3935 scoped_refptr<OrderedSocketData> data_proxy;
3936 switch(GetParam()) {
3937 case SPDYNPN:
3938 data_proxy = new OrderedSocketData(reads_SPDYNPN,
3939 arraysize(reads_SPDYNPN),
3940 writes_SPDYNPN,
3941 arraysize(writes_SPDYNPN));
3942 break;
3943 case SPDYNOSSL:
3944 data_proxy = new OrderedSocketData(reads_SPDYNOSSL,
3945 arraysize(reads_SPDYNOSSL),
3946 writes_SPDYNOSSL,
3947 arraysize(writes_SPDYNOSSL));
3948 break;
3949 case SPDYSSL:
3950 data_proxy = new OrderedSocketData(reads_SPDYSSL,
3951 arraysize(reads_SPDYSSL),
3952 writes_SPDYSSL,
3953 arraysize(writes_SPDYSSL));
3954 break;
3955 default:
3956 NOTREACHED();
3957 }
3958
3959 // Create another request to www.google.com, but this time through a proxy.
3960 HttpRequestInfo request_proxy;
3961 request_proxy.method = "GET";
3962 request_proxy.url = GURL("http://www.google.com/foo.dat");
3963 request_proxy.load_flags = 0;
3964 scoped_ptr<SpdySessionDependencies> ssd_proxy(
3965 new SpdySessionDependencies(net::SpdyCreateFixedProxyService(
3966 "myproxy:70")));
3967 // Ensure that this transaction uses the same SpdySessionPool.
3968 ssd_proxy->spdy_session_pool = spdy_session_pool;
3969 scoped_refptr<HttpNetworkSession> session_proxy =
3970 SpdySessionDependencies::SpdyCreateSession(ssd_proxy.get());
3971 NormalSpdyTransactionHelper helper_proxy(request_proxy,
3972 BoundNetLog(), GetParam());
3973 helper_proxy.session_deps().swap(ssd_proxy);
3974 helper_proxy.session() = session_proxy;
3975 helper_proxy.RunPreTestSetup();
3976 helper_proxy.AddData(data_proxy.get());
3977
3978 HttpNetworkTransaction* trans_proxy = helper_proxy.trans();
3979 TestCompletionCallback callback_proxy;
3980 int rv = trans_proxy->Start(&request_proxy, &callback_proxy, BoundNetLog());
3981 EXPECT_EQ(ERR_IO_PENDING, rv);
3982 rv = callback_proxy.WaitForResult();
3983 EXPECT_EQ(0, rv);
3984
3985 HttpResponseInfo response_proxy = *trans_proxy->GetResponseInfo();
3986 EXPECT_TRUE(response_proxy.headers != NULL);
3987 EXPECT_EQ("HTTP/1.1 200 OK", response_proxy.headers->GetStatusLine());
3988
3989 std::string response_data;
3990 ASSERT_EQ(OK, ReadTransaction(trans_proxy, &response_data));
3991 EXPECT_EQ("hello!", response_data);
3992
3993 data->CompleteRead();
3994 helper_proxy.VerifyDataConsumed();
3995}
3996
[email protected]58cebf8f2010-07-31 19:20:163997// When we get a TCP-level RST, we need to retry a HttpNetworkTransaction
3998// on a new connection, if the connection was previously known to be good.
3999// This can happen when a server reboots without saying goodbye, or when
4000// we're behind a NAT that masked the RST.
4001TEST_P(SpdyNetworkTransactionTest, VerifyRetryOnConnectionReset) {
4002 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1));
4003 scoped_ptr<spdy::SpdyFrame> body(ConstructSpdyBodyFrame(1, true));
4004 MockRead reads[] = {
4005 CreateMockRead(*resp),
4006 CreateMockRead(*body),
4007 MockRead(true, ERR_IO_PENDING),
4008 MockRead(true, ERR_CONNECTION_RESET),
4009 };
4010
4011 MockRead reads2[] = {
4012 CreateMockRead(*resp),
4013 CreateMockRead(*body),
4014 MockRead(true, 0, 0) // EOF
4015 };
4016
4017 // This test has a couple of variants.
4018 enum {
4019 // Induce the RST while waiting for our transaction to send.
4020 VARIANT_RST_DURING_SEND_COMPLETION,
4021 // Induce the RST while waiting for our transaction to read.
4022 // In this case, the send completed - everything copied into the SNDBUF.
4023 VARIANT_RST_DURING_READ_COMPLETION
4024 };
4025
4026 for (int variant = VARIANT_RST_DURING_SEND_COMPLETION;
4027 variant <= VARIANT_RST_DURING_READ_COMPLETION;
4028 ++variant) {
4029 scoped_refptr<DelayedSocketData> data1(
4030 new DelayedSocketData(1, reads, arraysize(reads),
4031 NULL, 0));
4032
4033 scoped_refptr<DelayedSocketData> data2(
4034 new DelayedSocketData(1, reads2, arraysize(reads2),
4035 NULL, 0));
4036
4037 NormalSpdyTransactionHelper helper(CreateGetRequest(),
4038 BoundNetLog(), GetParam());
4039 helper.AddData(data1.get());
4040 helper.AddData(data2.get());
4041 helper.RunPreTestSetup();
4042
4043 for (int i = 0; i < 2; ++i) {
4044 scoped_ptr<HttpNetworkTransaction> trans(
4045 new HttpNetworkTransaction(helper.session()));
4046
4047 TestCompletionCallback callback;
4048 int rv = trans->Start(&helper.request(), &callback, BoundNetLog());
4049 EXPECT_EQ(ERR_IO_PENDING, rv);
4050 // On the second transaction, we trigger the RST.
4051 if (i == 1) {
4052 if (variant == VARIANT_RST_DURING_READ_COMPLETION) {
4053 // Writes to the socket complete asynchronously on SPDY by running
4054 // through the message loop. Complete the write here.
4055 MessageLoop::current()->RunAllPending();
4056 }
4057
4058 // Now schedule the ERR_CONNECTION_RESET.
4059 EXPECT_EQ(3u, data1->read_index());
4060 data1->CompleteRead();
4061 EXPECT_EQ(4u, data1->read_index());
4062 }
4063 rv = callback.WaitForResult();
4064 EXPECT_EQ(OK, rv);
4065
4066 const HttpResponseInfo* response = trans->GetResponseInfo();
[email protected]351ab642010-08-05 16:55:314067 ASSERT_TRUE(response != NULL);
[email protected]58cebf8f2010-07-31 19:20:164068 EXPECT_TRUE(response->headers != NULL);
4069 EXPECT_TRUE(response->was_fetched_via_spdy);
4070 std::string response_data;
4071 rv = ReadTransaction(trans.get(), &response_data);
4072 EXPECT_EQ(OK, rv);
4073 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
4074 EXPECT_EQ("hello!", response_data);
4075 }
4076
4077 helper.VerifyDataConsumed();
4078 }
4079}
[email protected]aea80602009-09-18 00:55:084080} // namespace net