1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <string>
6 #include <vector>
7
8 #include "base/bind.h"
9 #include "base/bind_helpers.h"
10 #include "base/file_util.h"
11 #include "base/files/scoped_temp_dir.h"
12 #include "base/memory/scoped_vector.h"
13 #include "base/run_loop.h"
14 #include "base/stl_util.h"
15 #include "base/strings/string_piece.h"
16 #include "base/test/test_file_util.h"
17 #include "net/base/auth.h"
18 #include "net/base/net_log_unittest.h"
19 #include "net/base/request_priority.h"
20 #include "net/base/upload_bytes_element_reader.h"
21 #include "net/base/upload_data_stream.h"
22 #include "net/base/upload_file_element_reader.h"
23 #include "net/http/http_network_session_peer.h"
24 #include "net/http/http_network_transaction.h"
25 #include "net/http/http_server_properties.h"
26 #include "net/http/http_transaction_test_util.h"
27 #include "net/socket/client_socket_pool_base.h"
28 #include "net/socket/next_proto.h"
29 #include "net/spdy/buffered_spdy_framer.h"
30 #include "net/spdy/spdy_http_stream.h"
31 #include "net/spdy/spdy_http_utils.h"
32 #include "net/spdy/spdy_session.h"
33 #include "net/spdy/spdy_session_pool.h"
34 #include "net/spdy/spdy_test_util_common.h"
35 #include "net/spdy/spdy_test_utils.h"
36 #include "net/ssl/ssl_connection_status_flags.h"
37 #include "net/url_request/url_request_test_util.h"
38 #include "testing/gmock/include/gmock/gmock.h"
39 #include "testing/platform_test.h"
40
41 //-----------------------------------------------------------------------------
42
43 namespace net {
44
45 namespace {
46
47 using testing::Each;
48 using testing::Eq;
49
50 const char kRequestUrl[] = "http://www.google.com/";
51
52 enum SpdyNetworkTransactionTestSSLType {
53 SPDYNPN,
54 SPDYNOSSL,
55 SPDYSSL,
56 };
57
58 struct SpdyNetworkTransactionTestParams {
SpdyNetworkTransactionTestParamsnet::__anonccc356f50111::SpdyNetworkTransactionTestParams59 SpdyNetworkTransactionTestParams()
60 : protocol(kProtoSPDY3),
61 ssl_type(SPDYNPN) {}
62
SpdyNetworkTransactionTestParamsnet::__anonccc356f50111::SpdyNetworkTransactionTestParams63 SpdyNetworkTransactionTestParams(
64 NextProto protocol,
65 SpdyNetworkTransactionTestSSLType ssl_type)
66 : protocol(protocol),
67 ssl_type(ssl_type) {}
68
69 NextProto protocol;
70 SpdyNetworkTransactionTestSSLType ssl_type;
71 };
72
UpdateSpdySessionDependencies(SpdyNetworkTransactionTestParams test_params,SpdySessionDependencies * session_deps)73 void UpdateSpdySessionDependencies(
74 SpdyNetworkTransactionTestParams test_params,
75 SpdySessionDependencies* session_deps) {
76 switch (test_params.ssl_type) {
77 case SPDYNPN:
78 session_deps->http_server_properties.SetAlternateProtocol(
79 HostPortPair("www.google.com", 80), 443,
80 AlternateProtocolFromNextProto(test_params.protocol));
81 session_deps->use_alternate_protocols = true;
82 session_deps->next_protos = SpdyNextProtos();
83 break;
84 case SPDYNOSSL:
85 session_deps->force_spdy_over_ssl = false;
86 session_deps->force_spdy_always = true;
87 break;
88 case SPDYSSL:
89 session_deps->force_spdy_over_ssl = true;
90 session_deps->force_spdy_always = true;
91 break;
92 default:
93 NOTREACHED();
94 }
95 }
96
CreateSpdySessionDependencies(SpdyNetworkTransactionTestParams test_params)97 SpdySessionDependencies* CreateSpdySessionDependencies(
98 SpdyNetworkTransactionTestParams test_params) {
99 SpdySessionDependencies* session_deps =
100 new SpdySessionDependencies(test_params.protocol);
101 UpdateSpdySessionDependencies(test_params, session_deps);
102 return session_deps;
103 }
104
CreateSpdySessionDependencies(SpdyNetworkTransactionTestParams test_params,ProxyService * proxy_service)105 SpdySessionDependencies* CreateSpdySessionDependencies(
106 SpdyNetworkTransactionTestParams test_params,
107 ProxyService* proxy_service) {
108 SpdySessionDependencies* session_deps =
109 new SpdySessionDependencies(test_params.protocol, proxy_service);
110 UpdateSpdySessionDependencies(test_params, session_deps);
111 return session_deps;
112 }
113
114 } // namespace
115
116 class SpdyNetworkTransactionTest
117 : public ::testing::TestWithParam<SpdyNetworkTransactionTestParams> {
118 protected:
SpdyNetworkTransactionTest()119 SpdyNetworkTransactionTest() : spdy_util_(GetParam().protocol) {
120 LOG(INFO) << __FUNCTION__;
121 }
122
~SpdyNetworkTransactionTest()123 virtual ~SpdyNetworkTransactionTest() {
124 LOG(INFO) << __FUNCTION__;
125 // UploadDataStream posts deletion tasks back to the message loop on
126 // destruction.
127 upload_data_stream_.reset();
128 base::RunLoop().RunUntilIdle();
129 LOG(INFO) << __FUNCTION__;
130 }
131
SetUp()132 virtual void SetUp() {
133 LOG(INFO) << __FUNCTION__;
134 google_get_request_initialized_ = false;
135 google_post_request_initialized_ = false;
136 google_chunked_post_request_initialized_ = false;
137 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
138 LOG(INFO) << __FUNCTION__;
139 }
140
141 struct TransactionHelperResult {
142 int rv;
143 std::string status_line;
144 std::string response_data;
145 HttpResponseInfo response_info;
146 };
147
148 // A helper class that handles all the initial npn/ssl setup.
149 class NormalSpdyTransactionHelper {
150 public:
NormalSpdyTransactionHelper(const HttpRequestInfo & request,RequestPriority priority,const BoundNetLog & log,SpdyNetworkTransactionTestParams test_params,SpdySessionDependencies * session_deps)151 NormalSpdyTransactionHelper(const HttpRequestInfo& request,
152 RequestPriority priority,
153 const BoundNetLog& log,
154 SpdyNetworkTransactionTestParams test_params,
155 SpdySessionDependencies* session_deps)
156 : request_(request),
157 priority_(priority),
158 session_deps_(session_deps == NULL ?
159 CreateSpdySessionDependencies(test_params) :
160 session_deps),
161 session_(SpdySessionDependencies::SpdyCreateSession(
162 session_deps_.get())),
163 log_(log),
164 test_params_(test_params),
165 deterministic_(false),
166 spdy_enabled_(true) {
167 switch (test_params_.ssl_type) {
168 case SPDYNOSSL:
169 case SPDYSSL:
170 port_ = 80;
171 break;
172 case SPDYNPN:
173 port_ = 443;
174 break;
175 default:
176 NOTREACHED();
177 }
178 }
179
~NormalSpdyTransactionHelper()180 ~NormalSpdyTransactionHelper() {
181 // Any test which doesn't close the socket by sending it an EOF will
182 // have a valid session left open, which leaks the entire session pool.
183 // This is just fine - in fact, some of our tests intentionally do this
184 // so that we can check consistency of the SpdySessionPool as the test
185 // finishes. If we had put an EOF on the socket, the SpdySession would
186 // have closed and we wouldn't be able to check the consistency.
187
188 // Forcefully close existing sessions here.
189 session()->spdy_session_pool()->CloseAllSessions();
190 }
191
SetDeterministic()192 void SetDeterministic() {
193 session_ = SpdySessionDependencies::SpdyCreateSessionDeterministic(
194 session_deps_.get());
195 deterministic_ = true;
196 }
197
SetSpdyDisabled()198 void SetSpdyDisabled() {
199 spdy_enabled_ = false;
200 port_ = 80;
201 }
202
RunPreTestSetup()203 void RunPreTestSetup() {
204 LOG(INFO) << __FUNCTION__;
205 if (!session_deps_.get())
206 session_deps_.reset(CreateSpdySessionDependencies(test_params_));
207 if (!session_.get()) {
208 session_ = SpdySessionDependencies::SpdyCreateSession(
209 session_deps_.get());
210 }
211
212 // We're now ready to use SSL-npn SPDY.
213 trans_.reset(new HttpNetworkTransaction(priority_, session_.get()));
214 LOG(INFO) << __FUNCTION__;
215 }
216
217 // Start the transaction, read some data, finish.
RunDefaultTest()218 void RunDefaultTest() {
219 LOG(INFO) << __FUNCTION__;
220 if (!StartDefaultTest())
221 return;
222 FinishDefaultTest();
223 LOG(INFO) << __FUNCTION__;
224 }
225
StartDefaultTest()226 bool StartDefaultTest() {
227 output_.rv = trans_->Start(&request_, callback_.callback(), log_);
228
229 // We expect an IO Pending or some sort of error.
230 EXPECT_LT(output_.rv, 0);
231 return output_.rv == ERR_IO_PENDING;
232 }
233
FinishDefaultTest()234 void FinishDefaultTest() {
235 output_.rv = callback_.WaitForResult();
236 if (output_.rv != OK) {
237 session_->spdy_session_pool()->CloseCurrentSessions(net::ERR_ABORTED);
238 return;
239 }
240
241 // Verify responses.
242 const HttpResponseInfo* response = trans_->GetResponseInfo();
243 ASSERT_TRUE(response != NULL);
244 ASSERT_TRUE(response->headers.get() != NULL);
245 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
246 EXPECT_EQ(spdy_enabled_, response->was_fetched_via_spdy);
247 if (HttpStreamFactory::spdy_enabled()) {
248 EXPECT_EQ(
249 HttpResponseInfo::ConnectionInfoFromNextProto(
250 test_params_.protocol),
251 response->connection_info);
252 } else {
253 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP1,
254 response->connection_info);
255 }
256 if (test_params_.ssl_type == SPDYNPN && spdy_enabled_) {
257 EXPECT_TRUE(response->was_npn_negotiated);
258 } else {
259 EXPECT_TRUE(!response->was_npn_negotiated);
260 }
261 // If SPDY is not enabled, a HTTP request should not be diverted
262 // over a SSL session.
263 if (!spdy_enabled_) {
264 EXPECT_EQ(request_.url.SchemeIs("https"),
265 response->was_npn_negotiated);
266 }
267 EXPECT_EQ("127.0.0.1", response->socket_address.host());
268 EXPECT_EQ(port_, response->socket_address.port());
269 output_.status_line = response->headers->GetStatusLine();
270 output_.response_info = *response; // Make a copy so we can verify.
271 output_.rv = ReadTransaction(trans_.get(), &output_.response_data);
272 }
273
274 // Most tests will want to call this function. In particular, the MockReads
275 // should end with an empty read, and that read needs to be processed to
276 // ensure proper deletion of the spdy_session_pool.
VerifyDataConsumed()277 void VerifyDataConsumed() {
278 for (DataVector::iterator it = data_vector_.begin();
279 it != data_vector_.end(); ++it) {
280 EXPECT_TRUE((*it)->at_read_eof()) << "Read count: "
281 << (*it)->read_count()
282 << " Read index: "
283 << (*it)->read_index();
284 EXPECT_TRUE((*it)->at_write_eof()) << "Write count: "
285 << (*it)->write_count()
286 << " Write index: "
287 << (*it)->write_index();
288 }
289 }
290
291 // Occasionally a test will expect to error out before certain reads are
292 // processed. In that case we want to explicitly ensure that the reads were
293 // not processed.
VerifyDataNotConsumed()294 void VerifyDataNotConsumed() {
295 for (DataVector::iterator it = data_vector_.begin();
296 it != data_vector_.end(); ++it) {
297 EXPECT_TRUE(!(*it)->at_read_eof()) << "Read count: "
298 << (*it)->read_count()
299 << " Read index: "
300 << (*it)->read_index();
301 EXPECT_TRUE(!(*it)->at_write_eof()) << "Write count: "
302 << (*it)->write_count()
303 << " Write index: "
304 << (*it)->write_index();
305 }
306 }
307
RunToCompletion(StaticSocketDataProvider * data)308 void RunToCompletion(StaticSocketDataProvider* data) {
309 RunPreTestSetup();
310 AddData(data);
311 RunDefaultTest();
312 VerifyDataConsumed();
313 }
314
RunToCompletionWithSSLData(StaticSocketDataProvider * data,scoped_ptr<SSLSocketDataProvider> ssl_provider)315 void RunToCompletionWithSSLData(
316 StaticSocketDataProvider* data,
317 scoped_ptr<SSLSocketDataProvider> ssl_provider) {
318 RunPreTestSetup();
319 AddDataWithSSLSocketDataProvider(data, ssl_provider.Pass());
320 RunDefaultTest();
321 VerifyDataConsumed();
322 }
323
AddData(StaticSocketDataProvider * data)324 void AddData(StaticSocketDataProvider* data) {
325 scoped_ptr<SSLSocketDataProvider> ssl_provider(
326 new SSLSocketDataProvider(ASYNC, OK));
327 AddDataWithSSLSocketDataProvider(data, ssl_provider.Pass());
328 }
329
AddDataWithSSLSocketDataProvider(StaticSocketDataProvider * data,scoped_ptr<SSLSocketDataProvider> ssl_provider)330 void AddDataWithSSLSocketDataProvider(
331 StaticSocketDataProvider* data,
332 scoped_ptr<SSLSocketDataProvider> ssl_provider) {
333 DCHECK(!deterministic_);
334 data_vector_.push_back(data);
335 if (test_params_.ssl_type == SPDYNPN)
336 ssl_provider->SetNextProto(test_params_.protocol);
337
338 if (test_params_.ssl_type == SPDYNPN ||
339 test_params_.ssl_type == SPDYSSL) {
340 session_deps_->socket_factory->AddSSLSocketDataProvider(
341 ssl_provider.get());
342 }
343 ssl_vector_.push_back(ssl_provider.release());
344
345 session_deps_->socket_factory->AddSocketDataProvider(data);
346 if (test_params_.ssl_type == SPDYNPN) {
347 MockConnect never_finishing_connect(SYNCHRONOUS, ERR_IO_PENDING);
348 StaticSocketDataProvider* hanging_non_alternate_protocol_socket =
349 new StaticSocketDataProvider(NULL, 0, NULL, 0);
350 hanging_non_alternate_protocol_socket->set_connect_data(
351 never_finishing_connect);
352 session_deps_->socket_factory->AddSocketDataProvider(
353 hanging_non_alternate_protocol_socket);
354 alternate_vector_.push_back(hanging_non_alternate_protocol_socket);
355 }
356 }
357
AddDeterministicData(DeterministicSocketData * data)358 void AddDeterministicData(DeterministicSocketData* data) {
359 DCHECK(deterministic_);
360 data_vector_.push_back(data);
361 SSLSocketDataProvider* ssl_provider =
362 new SSLSocketDataProvider(ASYNC, OK);
363 if (test_params_.ssl_type == SPDYNPN)
364 ssl_provider->SetNextProto(test_params_.protocol);
365
366 ssl_vector_.push_back(ssl_provider);
367 if (test_params_.ssl_type == SPDYNPN ||
368 test_params_.ssl_type == SPDYSSL) {
369 session_deps_->deterministic_socket_factory->
370 AddSSLSocketDataProvider(ssl_provider);
371 }
372 session_deps_->deterministic_socket_factory->AddSocketDataProvider(data);
373 if (test_params_.ssl_type == SPDYNPN) {
374 MockConnect never_finishing_connect(SYNCHRONOUS, ERR_IO_PENDING);
375 DeterministicSocketData* hanging_non_alternate_protocol_socket =
376 new DeterministicSocketData(NULL, 0, NULL, 0);
377 hanging_non_alternate_protocol_socket->set_connect_data(
378 never_finishing_connect);
379 session_deps_->deterministic_socket_factory->AddSocketDataProvider(
380 hanging_non_alternate_protocol_socket);
381 alternate_deterministic_vector_.push_back(
382 hanging_non_alternate_protocol_socket);
383 }
384 }
385
SetSession(const scoped_refptr<HttpNetworkSession> & session)386 void SetSession(const scoped_refptr<HttpNetworkSession>& session) {
387 session_ = session;
388 }
trans()389 HttpNetworkTransaction* trans() { return trans_.get(); }
ResetTrans()390 void ResetTrans() { trans_.reset(); }
output()391 TransactionHelperResult& output() { return output_; }
request() const392 const HttpRequestInfo& request() const { return request_; }
session() const393 const scoped_refptr<HttpNetworkSession>& session() const {
394 return session_;
395 }
session_deps()396 scoped_ptr<SpdySessionDependencies>& session_deps() {
397 return session_deps_;
398 }
port() const399 int port() const { return port_; }
test_params() const400 SpdyNetworkTransactionTestParams test_params() const {
401 return test_params_;
402 }
403
404 private:
405 typedef std::vector<StaticSocketDataProvider*> DataVector;
406 typedef ScopedVector<SSLSocketDataProvider> SSLVector;
407 typedef ScopedVector<StaticSocketDataProvider> AlternateVector;
408 typedef ScopedVector<DeterministicSocketData> AlternateDeterministicVector;
409 HttpRequestInfo request_;
410 RequestPriority priority_;
411 scoped_ptr<SpdySessionDependencies> session_deps_;
412 scoped_refptr<HttpNetworkSession> session_;
413 TransactionHelperResult output_;
414 scoped_ptr<StaticSocketDataProvider> first_transaction_;
415 SSLVector ssl_vector_;
416 TestCompletionCallback callback_;
417 scoped_ptr<HttpNetworkTransaction> trans_;
418 scoped_ptr<HttpNetworkTransaction> trans_http_;
419 DataVector data_vector_;
420 AlternateVector alternate_vector_;
421 AlternateDeterministicVector alternate_deterministic_vector_;
422 const BoundNetLog& log_;
423 SpdyNetworkTransactionTestParams test_params_;
424 int port_;
425 bool deterministic_;
426 bool spdy_enabled_;
427 };
428
429 void ConnectStatusHelperWithExpectedStatus(const MockRead& status,
430 int expected_status);
431
432 void ConnectStatusHelper(const MockRead& status);
433
CreateGetPushRequest()434 const HttpRequestInfo& CreateGetPushRequest() {
435 google_get_push_request_.method = "GET";
436 google_get_push_request_.url = GURL("http://www.google.com/foo.dat");
437 google_get_push_request_.load_flags = 0;
438 return google_get_push_request_;
439 }
440
CreateGetRequest()441 const HttpRequestInfo& CreateGetRequest() {
442 if (!google_get_request_initialized_) {
443 google_get_request_.method = "GET";
444 google_get_request_.url = GURL(kDefaultURL);
445 google_get_request_.load_flags = 0;
446 google_get_request_initialized_ = true;
447 }
448 return google_get_request_;
449 }
450
CreateGetRequestWithUserAgent()451 const HttpRequestInfo& CreateGetRequestWithUserAgent() {
452 if (!google_get_request_initialized_) {
453 google_get_request_.method = "GET";
454 google_get_request_.url = GURL(kDefaultURL);
455 google_get_request_.load_flags = 0;
456 google_get_request_.extra_headers.SetHeader("User-Agent", "Chrome");
457 google_get_request_initialized_ = true;
458 }
459 return google_get_request_;
460 }
461
CreatePostRequest()462 const HttpRequestInfo& CreatePostRequest() {
463 if (!google_post_request_initialized_) {
464 ScopedVector<UploadElementReader> element_readers;
465 element_readers.push_back(
466 new UploadBytesElementReader(kUploadData, kUploadDataSize));
467 upload_data_stream_.reset(
468 new UploadDataStream(element_readers.Pass(), 0));
469
470 google_post_request_.method = "POST";
471 google_post_request_.url = GURL(kDefaultURL);
472 google_post_request_.upload_data_stream = upload_data_stream_.get();
473 google_post_request_initialized_ = true;
474 }
475 return google_post_request_;
476 }
477
CreateFilePostRequest()478 const HttpRequestInfo& CreateFilePostRequest() {
479 if (!google_post_request_initialized_) {
480 base::FilePath file_path;
481 CHECK(base::CreateTemporaryFileInDir(temp_dir_.path(), &file_path));
482 CHECK_EQ(static_cast<int>(kUploadDataSize),
483 base::WriteFile(file_path, kUploadData, kUploadDataSize));
484
485 ScopedVector<UploadElementReader> element_readers;
486 element_readers.push_back(
487 new UploadFileElementReader(base::MessageLoopProxy::current().get(),
488 file_path,
489 0,
490 kUploadDataSize,
491 base::Time()));
492 upload_data_stream_.reset(
493 new UploadDataStream(element_readers.Pass(), 0));
494
495 google_post_request_.method = "POST";
496 google_post_request_.url = GURL(kDefaultURL);
497 google_post_request_.upload_data_stream = upload_data_stream_.get();
498 google_post_request_initialized_ = true;
499 }
500 return google_post_request_;
501 }
502
CreateUnreadableFilePostRequest()503 const HttpRequestInfo& CreateUnreadableFilePostRequest() {
504 if (google_post_request_initialized_)
505 return google_post_request_;
506
507 base::FilePath file_path;
508 CHECK(base::CreateTemporaryFileInDir(temp_dir_.path(), &file_path));
509 CHECK_EQ(static_cast<int>(kUploadDataSize),
510 base::WriteFile(file_path, kUploadData, kUploadDataSize));
511 CHECK(file_util::MakeFileUnreadable(file_path));
512
513 ScopedVector<UploadElementReader> element_readers;
514 element_readers.push_back(
515 new UploadFileElementReader(base::MessageLoopProxy::current().get(),
516 file_path,
517 0,
518 kUploadDataSize,
519 base::Time()));
520 upload_data_stream_.reset(
521 new UploadDataStream(element_readers.Pass(), 0));
522
523 google_post_request_.method = "POST";
524 google_post_request_.url = GURL(kDefaultURL);
525 google_post_request_.upload_data_stream = upload_data_stream_.get();
526 google_post_request_initialized_ = true;
527 return google_post_request_;
528 }
529
CreateComplexPostRequest()530 const HttpRequestInfo& CreateComplexPostRequest() {
531 if (!google_post_request_initialized_) {
532 const int kFileRangeOffset = 1;
533 const int kFileRangeLength = 3;
534 CHECK_LT(kFileRangeOffset + kFileRangeLength, kUploadDataSize);
535
536 base::FilePath file_path;
537 CHECK(base::CreateTemporaryFileInDir(temp_dir_.path(), &file_path));
538 CHECK_EQ(static_cast<int>(kUploadDataSize),
539 base::WriteFile(file_path, kUploadData, kUploadDataSize));
540
541 ScopedVector<UploadElementReader> element_readers;
542 element_readers.push_back(
543 new UploadBytesElementReader(kUploadData, kFileRangeOffset));
544 element_readers.push_back(
545 new UploadFileElementReader(base::MessageLoopProxy::current().get(),
546 file_path,
547 kFileRangeOffset,
548 kFileRangeLength,
549 base::Time()));
550 element_readers.push_back(new UploadBytesElementReader(
551 kUploadData + kFileRangeOffset + kFileRangeLength,
552 kUploadDataSize - (kFileRangeOffset + kFileRangeLength)));
553 upload_data_stream_.reset(
554 new UploadDataStream(element_readers.Pass(), 0));
555
556 google_post_request_.method = "POST";
557 google_post_request_.url = GURL(kDefaultURL);
558 google_post_request_.upload_data_stream = upload_data_stream_.get();
559 google_post_request_initialized_ = true;
560 }
561 return google_post_request_;
562 }
563
CreateChunkedPostRequest()564 const HttpRequestInfo& CreateChunkedPostRequest() {
565 if (!google_chunked_post_request_initialized_) {
566 upload_data_stream_.reset(
567 new UploadDataStream(UploadDataStream::CHUNKED, 0));
568 google_chunked_post_request_.method = "POST";
569 google_chunked_post_request_.url = GURL(kDefaultURL);
570 google_chunked_post_request_.upload_data_stream =
571 upload_data_stream_.get();
572 google_chunked_post_request_initialized_ = true;
573 }
574 return google_chunked_post_request_;
575 }
576
577 // Read the result of a particular transaction, knowing that we've got
578 // multiple transactions in the read pipeline; so as we read, we may have
579 // to skip over data destined for other transactions while we consume
580 // the data for |trans|.
ReadResult(HttpNetworkTransaction * trans,StaticSocketDataProvider * data,std::string * result)581 int ReadResult(HttpNetworkTransaction* trans,
582 StaticSocketDataProvider* data,
583 std::string* result) {
584 const int kSize = 3000;
585
586 int bytes_read = 0;
587 scoped_refptr<net::IOBufferWithSize> buf(new net::IOBufferWithSize(kSize));
588 TestCompletionCallback callback;
589 while (true) {
590 int rv = trans->Read(buf.get(), kSize, callback.callback());
591 if (rv == ERR_IO_PENDING) {
592 // Multiple transactions may be in the data set. Keep pulling off
593 // reads until we complete our callback.
594 while (!callback.have_result()) {
595 data->CompleteRead();
596 base::RunLoop().RunUntilIdle();
597 }
598 rv = callback.WaitForResult();
599 } else if (rv <= 0) {
600 break;
601 }
602 result->append(buf->data(), rv);
603 bytes_read += rv;
604 }
605 return bytes_read;
606 }
607
VerifyStreamsClosed(const NormalSpdyTransactionHelper & helper)608 void VerifyStreamsClosed(const NormalSpdyTransactionHelper& helper) {
609 // This lengthy block is reaching into the pool to dig out the active
610 // session. Once we have the session, we verify that the streams are
611 // all closed and not leaked at this point.
612 const GURL& url = helper.request().url;
613 int port = helper.test_params().ssl_type == SPDYNPN ? 443 : 80;
614 HostPortPair host_port_pair(url.host(), port);
615 SpdySessionKey key(host_port_pair, ProxyServer::Direct(),
616 PRIVACY_MODE_DISABLED);
617 BoundNetLog log;
618 const scoped_refptr<HttpNetworkSession>& session = helper.session();
619 base::WeakPtr<SpdySession> spdy_session =
620 session->spdy_session_pool()->FindAvailableSession(key, log);
621 ASSERT_TRUE(spdy_session != NULL);
622 EXPECT_EQ(0u, spdy_session->num_active_streams());
623 EXPECT_EQ(0u, spdy_session->num_unclaimed_pushed_streams());
624 }
625
RunServerPushTest(OrderedSocketData * data,HttpResponseInfo * response,HttpResponseInfo * push_response,const std::string & expected)626 void RunServerPushTest(OrderedSocketData* data,
627 HttpResponseInfo* response,
628 HttpResponseInfo* push_response,
629 const std::string& expected) {
630 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
631 BoundNetLog(), GetParam(), NULL);
632 helper.RunPreTestSetup();
633 helper.AddData(data);
634
635 HttpNetworkTransaction* trans = helper.trans();
636
637 // Start the transaction with basic parameters.
638 TestCompletionCallback callback;
639 int rv = trans->Start(
640 &CreateGetRequest(), callback.callback(), BoundNetLog());
641 EXPECT_EQ(ERR_IO_PENDING, rv);
642 rv = callback.WaitForResult();
643
644 // Request the pushed path.
645 scoped_ptr<HttpNetworkTransaction> trans2(
646 new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get()));
647 rv = trans2->Start(
648 &CreateGetPushRequest(), callback.callback(), BoundNetLog());
649 EXPECT_EQ(ERR_IO_PENDING, rv);
650 base::RunLoop().RunUntilIdle();
651
652 // The data for the pushed path may be coming in more than 1 frame. Compile
653 // the results into a single string.
654
655 // Read the server push body.
656 std::string result2;
657 ReadResult(trans2.get(), data, &result2);
658 // Read the response body.
659 std::string result;
660 ReadResult(trans, data, &result);
661
662 // Verify that we consumed all test data.
663 EXPECT_TRUE(data->at_read_eof());
664 EXPECT_TRUE(data->at_write_eof());
665
666 // Verify that the received push data is same as the expected push data.
667 EXPECT_EQ(result2.compare(expected), 0) << "Received data: "
668 << result2
669 << "||||| Expected data: "
670 << expected;
671
672 // Verify the SYN_REPLY.
673 // Copy the response info, because trans goes away.
674 *response = *trans->GetResponseInfo();
675 *push_response = *trans2->GetResponseInfo();
676
677 VerifyStreamsClosed(helper);
678 }
679
DeleteSessionCallback(NormalSpdyTransactionHelper * helper,int result)680 static void DeleteSessionCallback(NormalSpdyTransactionHelper* helper,
681 int result) {
682 helper->ResetTrans();
683 }
684
StartTransactionCallback(const scoped_refptr<HttpNetworkSession> & session,int result)685 static void StartTransactionCallback(
686 const scoped_refptr<HttpNetworkSession>& session,
687 int result) {
688 scoped_ptr<HttpNetworkTransaction> trans(
689 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
690 TestCompletionCallback callback;
691 HttpRequestInfo request;
692 request.method = "GET";
693 request.url = GURL("http://www.google.com/");
694 request.load_flags = 0;
695 int rv = trans->Start(&request, callback.callback(), BoundNetLog());
696 EXPECT_EQ(ERR_IO_PENDING, rv);
697 callback.WaitForResult();
698 }
699
700 SpdyTestUtil spdy_util_;
701
702 private:
703 scoped_ptr<UploadDataStream> upload_data_stream_;
704 bool google_get_request_initialized_;
705 bool google_post_request_initialized_;
706 bool google_chunked_post_request_initialized_;
707 HttpRequestInfo google_get_request_;
708 HttpRequestInfo google_post_request_;
709 HttpRequestInfo google_chunked_post_request_;
710 HttpRequestInfo google_get_push_request_;
711 base::ScopedTempDir temp_dir_;
712 };
713
714 //-----------------------------------------------------------------------------
715 // All tests are run with three different connection types: SPDY after NPN
716 // negotiation, SPDY without SSL, and SPDY with SSL.
717 //
718 // TODO(akalin): Use ::testing::Combine() when we are able to use
719 // <tr1/tuple>.
720 INSTANTIATE_TEST_CASE_P(
721 Spdy,
722 SpdyNetworkTransactionTest,
723 ::testing::Values(
724 SpdyNetworkTransactionTestParams(kProtoDeprecatedSPDY2, SPDYNOSSL),
725 SpdyNetworkTransactionTestParams(kProtoDeprecatedSPDY2, SPDYSSL),
726 SpdyNetworkTransactionTestParams(kProtoDeprecatedSPDY2, SPDYNPN),
727 SpdyNetworkTransactionTestParams(kProtoSPDY3, SPDYNOSSL),
728 SpdyNetworkTransactionTestParams(kProtoSPDY3, SPDYSSL),
729 SpdyNetworkTransactionTestParams(kProtoSPDY3, SPDYNPN),
730 SpdyNetworkTransactionTestParams(kProtoSPDY31, SPDYNOSSL),
731 SpdyNetworkTransactionTestParams(kProtoSPDY31, SPDYSSL),
732 SpdyNetworkTransactionTestParams(kProtoSPDY31, SPDYNPN),
733 SpdyNetworkTransactionTestParams(kProtoSPDY4, SPDYNOSSL),
734 SpdyNetworkTransactionTestParams(kProtoSPDY4, SPDYSSL),
735 SpdyNetworkTransactionTestParams(kProtoSPDY4, SPDYNPN)));
736
737 // Verify HttpNetworkTransaction constructor.
TEST_P(SpdyNetworkTransactionTest,Constructor)738 TEST_P(SpdyNetworkTransactionTest, Constructor) {
739 LOG(INFO) << __FUNCTION__;
740 scoped_ptr<SpdySessionDependencies> session_deps(
741 CreateSpdySessionDependencies(GetParam()));
742 LOG(INFO) << __FUNCTION__;
743 scoped_refptr<HttpNetworkSession> session(
744 SpdySessionDependencies::SpdyCreateSession(session_deps.get()));
745 LOG(INFO) << __FUNCTION__;
746 scoped_ptr<HttpTransaction> trans(
747 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
748 LOG(INFO) << __FUNCTION__;
749 }
750
TEST_P(SpdyNetworkTransactionTest,Get)751 TEST_P(SpdyNetworkTransactionTest, Get) {
752 LOG(INFO) << __FUNCTION__;
753 // Construct the request.
754 scoped_ptr<SpdyFrame> req(
755 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
756 MockWrite writes[] = { CreateMockWrite(*req) };
757
758 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
759 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
760 MockRead reads[] = {
761 CreateMockRead(*resp),
762 CreateMockRead(*body),
763 MockRead(ASYNC, 0, 0) // EOF
764 };
765
766 DelayedSocketData data(1, reads, arraysize(reads),
767 writes, arraysize(writes));
768 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
769 BoundNetLog(), GetParam(), NULL);
770 helper.RunToCompletion(&data);
771 TransactionHelperResult out = helper.output();
772 EXPECT_EQ(OK, out.rv);
773 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
774 EXPECT_EQ("hello!", out.response_data);
775 }
776
TEST_P(SpdyNetworkTransactionTest,GetAtEachPriority)777 TEST_P(SpdyNetworkTransactionTest, GetAtEachPriority) {
778 for (RequestPriority p = MINIMUM_PRIORITY; p <= MAXIMUM_PRIORITY;
779 p = RequestPriority(p + 1)) {
780 // Construct the request.
781 scoped_ptr<SpdyFrame> req(
782 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, p, true));
783 MockWrite writes[] = { CreateMockWrite(*req) };
784
785 SpdyPriority spdy_prio = 0;
786 EXPECT_TRUE(GetSpdyPriority(spdy_util_.spdy_version(), *req, &spdy_prio));
787 // this repeats the RequestPriority-->SpdyPriority mapping from
788 // SpdyFramer::ConvertRequestPriorityToSpdyPriority to make
789 // sure it's being done right.
790 if (spdy_util_.spdy_version() < SPDY3) {
791 switch(p) {
792 case HIGHEST:
793 EXPECT_EQ(0, spdy_prio);
794 break;
795 case MEDIUM:
796 EXPECT_EQ(1, spdy_prio);
797 break;
798 case LOW:
799 case LOWEST:
800 EXPECT_EQ(2, spdy_prio);
801 break;
802 case IDLE:
803 EXPECT_EQ(3, spdy_prio);
804 break;
805 default:
806 FAIL();
807 }
808 } else {
809 switch(p) {
810 case HIGHEST:
811 EXPECT_EQ(0, spdy_prio);
812 break;
813 case MEDIUM:
814 EXPECT_EQ(1, spdy_prio);
815 break;
816 case LOW:
817 EXPECT_EQ(2, spdy_prio);
818 break;
819 case LOWEST:
820 EXPECT_EQ(3, spdy_prio);
821 break;
822 case IDLE:
823 EXPECT_EQ(4, spdy_prio);
824 break;
825 default:
826 FAIL();
827 }
828 }
829
830 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
831 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
832 MockRead reads[] = {
833 CreateMockRead(*resp),
834 CreateMockRead(*body),
835 MockRead(ASYNC, 0, 0) // EOF
836 };
837
838 DelayedSocketData data(1, reads, arraysize(reads),
839 writes, arraysize(writes));
840 HttpRequestInfo http_req = CreateGetRequest();
841
842 NormalSpdyTransactionHelper helper(http_req, p, BoundNetLog(),
843 GetParam(), NULL);
844 helper.RunToCompletion(&data);
845 TransactionHelperResult out = helper.output();
846 EXPECT_EQ(OK, out.rv);
847 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
848 EXPECT_EQ("hello!", out.response_data);
849 }
850 }
851
852 // Start three gets simultaniously; making sure that multiplexed
853 // streams work properly.
854
855 // This can't use the TransactionHelper method, since it only
856 // handles a single transaction, and finishes them as soon
857 // as it launches them.
858
859 // TODO(gavinp): create a working generalized TransactionHelper that
860 // can allow multiple streams in flight.
861
TEST_P(SpdyNetworkTransactionTest,ThreeGets)862 TEST_P(SpdyNetworkTransactionTest, ThreeGets) {
863 scoped_ptr<SpdyFrame> req(
864 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
865 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
866 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, false));
867 scoped_ptr<SpdyFrame> fbody(spdy_util_.ConstructSpdyBodyFrame(1, true));
868
869 scoped_ptr<SpdyFrame> req2(
870 spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, LOWEST, true));
871 scoped_ptr<SpdyFrame> resp2(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3));
872 scoped_ptr<SpdyFrame> body2(spdy_util_.ConstructSpdyBodyFrame(3, false));
873 scoped_ptr<SpdyFrame> fbody2(spdy_util_.ConstructSpdyBodyFrame(3, true));
874
875 scoped_ptr<SpdyFrame> req3(
876 spdy_util_.ConstructSpdyGet(NULL, 0, false, 5, LOWEST, true));
877 scoped_ptr<SpdyFrame> resp3(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 5));
878 scoped_ptr<SpdyFrame> body3(spdy_util_.ConstructSpdyBodyFrame(5, false));
879 scoped_ptr<SpdyFrame> fbody3(spdy_util_.ConstructSpdyBodyFrame(5, true));
880
881 MockWrite writes[] = {
882 CreateMockWrite(*req),
883 CreateMockWrite(*req2),
884 CreateMockWrite(*req3),
885 };
886 MockRead reads[] = {
887 CreateMockRead(*resp, 1),
888 CreateMockRead(*body),
889 CreateMockRead(*resp2, 4),
890 CreateMockRead(*body2),
891 CreateMockRead(*resp3, 7),
892 CreateMockRead(*body3),
893
894 CreateMockRead(*fbody),
895 CreateMockRead(*fbody2),
896 CreateMockRead(*fbody3),
897
898 MockRead(ASYNC, 0, 0), // EOF
899 };
900 OrderedSocketData data(reads, arraysize(reads),
901 writes, arraysize(writes));
902 OrderedSocketData data_placeholder(NULL, 0, NULL, 0);
903
904 BoundNetLog log;
905 TransactionHelperResult out;
906 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
907 BoundNetLog(), GetParam(), NULL);
908 helper.RunPreTestSetup();
909 helper.AddData(&data);
910 // We require placeholder data because three get requests are sent out, so
911 // there needs to be three sets of SSL connection data.
912 helper.AddData(&data_placeholder);
913 helper.AddData(&data_placeholder);
914 scoped_ptr<HttpNetworkTransaction> trans1(
915 new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get()));
916 scoped_ptr<HttpNetworkTransaction> trans2(
917 new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get()));
918 scoped_ptr<HttpNetworkTransaction> trans3(
919 new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get()));
920
921 TestCompletionCallback callback1;
922 TestCompletionCallback callback2;
923 TestCompletionCallback callback3;
924
925 HttpRequestInfo httpreq1 = CreateGetRequest();
926 HttpRequestInfo httpreq2 = CreateGetRequest();
927 HttpRequestInfo httpreq3 = CreateGetRequest();
928
929 out.rv = trans1->Start(&httpreq1, callback1.callback(), log);
930 ASSERT_EQ(ERR_IO_PENDING, out.rv);
931 out.rv = trans2->Start(&httpreq2, callback2.callback(), log);
932 ASSERT_EQ(ERR_IO_PENDING, out.rv);
933 out.rv = trans3->Start(&httpreq3, callback3.callback(), log);
934 ASSERT_EQ(ERR_IO_PENDING, out.rv);
935
936 out.rv = callback1.WaitForResult();
937 ASSERT_EQ(OK, out.rv);
938 out.rv = callback3.WaitForResult();
939 ASSERT_EQ(OK, out.rv);
940
941 const HttpResponseInfo* response1 = trans1->GetResponseInfo();
942 EXPECT_TRUE(response1->headers.get() != NULL);
943 EXPECT_TRUE(response1->was_fetched_via_spdy);
944 out.status_line = response1->headers->GetStatusLine();
945 out.response_info = *response1;
946
947 trans2->GetResponseInfo();
948
949 out.rv = ReadTransaction(trans1.get(), &out.response_data);
950 helper.VerifyDataConsumed();
951 EXPECT_EQ(OK, out.rv);
952
953 EXPECT_EQ(OK, out.rv);
954 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
955 EXPECT_EQ("hello!hello!", out.response_data);
956 }
957
TEST_P(SpdyNetworkTransactionTest,TwoGetsLateBinding)958 TEST_P(SpdyNetworkTransactionTest, TwoGetsLateBinding) {
959 scoped_ptr<SpdyFrame> req(
960 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
961 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
962 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, false));
963 scoped_ptr<SpdyFrame> fbody(spdy_util_.ConstructSpdyBodyFrame(1, true));
964
965 scoped_ptr<SpdyFrame> req2(
966 spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, LOWEST, true));
967 scoped_ptr<SpdyFrame> resp2(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3));
968 scoped_ptr<SpdyFrame> body2(spdy_util_.ConstructSpdyBodyFrame(3, false));
969 scoped_ptr<SpdyFrame> fbody2(spdy_util_.ConstructSpdyBodyFrame(3, true));
970
971 MockWrite writes[] = {
972 CreateMockWrite(*req),
973 CreateMockWrite(*req2),
974 };
975 MockRead reads[] = {
976 CreateMockRead(*resp, 1),
977 CreateMockRead(*body),
978 CreateMockRead(*resp2, 4),
979 CreateMockRead(*body2),
980 CreateMockRead(*fbody),
981 CreateMockRead(*fbody2),
982 MockRead(ASYNC, 0, 0), // EOF
983 };
984 OrderedSocketData data(reads, arraysize(reads),
985 writes, arraysize(writes));
986
987 MockConnect never_finishing_connect(SYNCHRONOUS, ERR_IO_PENDING);
988
989 OrderedSocketData data_placeholder(NULL, 0, NULL, 0);
990 data_placeholder.set_connect_data(never_finishing_connect);
991
992 BoundNetLog log;
993 TransactionHelperResult out;
994 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
995 BoundNetLog(), GetParam(), NULL);
996 helper.RunPreTestSetup();
997 helper.AddData(&data);
998 // We require placeholder data because two get requests are sent out, so
999 // there needs to be two sets of SSL connection data.
1000 helper.AddData(&data_placeholder);
1001 scoped_ptr<HttpNetworkTransaction> trans1(
1002 new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get()));
1003 scoped_ptr<HttpNetworkTransaction> trans2(
1004 new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get()));
1005
1006 TestCompletionCallback callback1;
1007 TestCompletionCallback callback2;
1008
1009 HttpRequestInfo httpreq1 = CreateGetRequest();
1010 HttpRequestInfo httpreq2 = CreateGetRequest();
1011
1012 out.rv = trans1->Start(&httpreq1, callback1.callback(), log);
1013 ASSERT_EQ(ERR_IO_PENDING, out.rv);
1014 out.rv = trans2->Start(&httpreq2, callback2.callback(), log);
1015 ASSERT_EQ(ERR_IO_PENDING, out.rv);
1016
1017 out.rv = callback1.WaitForResult();
1018 ASSERT_EQ(OK, out.rv);
1019 out.rv = callback2.WaitForResult();
1020 ASSERT_EQ(OK, out.rv);
1021
1022 const HttpResponseInfo* response1 = trans1->GetResponseInfo();
1023 EXPECT_TRUE(response1->headers.get() != NULL);
1024 EXPECT_TRUE(response1->was_fetched_via_spdy);
1025 out.status_line = response1->headers->GetStatusLine();
1026 out.response_info = *response1;
1027 out.rv = ReadTransaction(trans1.get(), &out.response_data);
1028 EXPECT_EQ(OK, out.rv);
1029 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
1030 EXPECT_EQ("hello!hello!", out.response_data);
1031
1032 const HttpResponseInfo* response2 = trans2->GetResponseInfo();
1033 EXPECT_TRUE(response2->headers.get() != NULL);
1034 EXPECT_TRUE(response2->was_fetched_via_spdy);
1035 out.status_line = response2->headers->GetStatusLine();
1036 out.response_info = *response2;
1037 out.rv = ReadTransaction(trans2.get(), &out.response_data);
1038 EXPECT_EQ(OK, out.rv);
1039 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
1040 EXPECT_EQ("hello!hello!", out.response_data);
1041
1042 helper.VerifyDataConsumed();
1043 }
1044
TEST_P(SpdyNetworkTransactionTest,TwoGetsLateBindingFromPreconnect)1045 TEST_P(SpdyNetworkTransactionTest, TwoGetsLateBindingFromPreconnect) {
1046 scoped_ptr<SpdyFrame> req(
1047 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
1048 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
1049 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, false));
1050 scoped_ptr<SpdyFrame> fbody(spdy_util_.ConstructSpdyBodyFrame(1, true));
1051
1052 scoped_ptr<SpdyFrame> req2(
1053 spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, LOWEST, true));
1054 scoped_ptr<SpdyFrame> resp2(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3));
1055 scoped_ptr<SpdyFrame> body2(spdy_util_.ConstructSpdyBodyFrame(3, false));
1056 scoped_ptr<SpdyFrame> fbody2(spdy_util_.ConstructSpdyBodyFrame(3, true));
1057
1058 MockWrite writes[] = {
1059 CreateMockWrite(*req),
1060 CreateMockWrite(*req2),
1061 };
1062 MockRead reads[] = {
1063 CreateMockRead(*resp, 1),
1064 CreateMockRead(*body),
1065 CreateMockRead(*resp2, 4),
1066 CreateMockRead(*body2),
1067 CreateMockRead(*fbody),
1068 CreateMockRead(*fbody2),
1069 MockRead(ASYNC, 0, 0), // EOF
1070 };
1071 OrderedSocketData preconnect_data(reads, arraysize(reads),
1072 writes, arraysize(writes));
1073
1074 MockConnect never_finishing_connect(ASYNC, ERR_IO_PENDING);
1075
1076 OrderedSocketData data_placeholder(NULL, 0, NULL, 0);
1077 data_placeholder.set_connect_data(never_finishing_connect);
1078
1079 BoundNetLog log;
1080 TransactionHelperResult out;
1081 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
1082 BoundNetLog(), GetParam(), NULL);
1083 helper.RunPreTestSetup();
1084 helper.AddData(&preconnect_data);
1085 // We require placeholder data because 3 connections are attempted (first is
1086 // the preconnect, 2nd and 3rd are the never finished connections.
1087 helper.AddData(&data_placeholder);
1088 helper.AddData(&data_placeholder);
1089
1090 scoped_ptr<HttpNetworkTransaction> trans1(
1091 new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get()));
1092 scoped_ptr<HttpNetworkTransaction> trans2(
1093 new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get()));
1094
1095 TestCompletionCallback callback1;
1096 TestCompletionCallback callback2;
1097
1098 HttpRequestInfo httpreq = CreateGetRequest();
1099
1100 // Preconnect the first.
1101 SSLConfig preconnect_ssl_config;
1102 helper.session()->ssl_config_service()->GetSSLConfig(&preconnect_ssl_config);
1103 HttpStreamFactory* http_stream_factory =
1104 helper.session()->http_stream_factory();
1105 helper.session()->GetNextProtos(&preconnect_ssl_config.next_protos);
1106
1107 http_stream_factory->PreconnectStreams(
1108 1, httpreq, DEFAULT_PRIORITY,
1109 preconnect_ssl_config, preconnect_ssl_config);
1110
1111 out.rv = trans1->Start(&httpreq, callback1.callback(), log);
1112 ASSERT_EQ(ERR_IO_PENDING, out.rv);
1113 out.rv = trans2->Start(&httpreq, callback2.callback(), log);
1114 ASSERT_EQ(ERR_IO_PENDING, out.rv);
1115
1116 out.rv = callback1.WaitForResult();
1117 ASSERT_EQ(OK, out.rv);
1118 out.rv = callback2.WaitForResult();
1119 ASSERT_EQ(OK, out.rv);
1120
1121 const HttpResponseInfo* response1 = trans1->GetResponseInfo();
1122 EXPECT_TRUE(response1->headers.get() != NULL);
1123 EXPECT_TRUE(response1->was_fetched_via_spdy);
1124 out.status_line = response1->headers->GetStatusLine();
1125 out.response_info = *response1;
1126 out.rv = ReadTransaction(trans1.get(), &out.response_data);
1127 EXPECT_EQ(OK, out.rv);
1128 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
1129 EXPECT_EQ("hello!hello!", out.response_data);
1130
1131 const HttpResponseInfo* response2 = trans2->GetResponseInfo();
1132 EXPECT_TRUE(response2->headers.get() != NULL);
1133 EXPECT_TRUE(response2->was_fetched_via_spdy);
1134 out.status_line = response2->headers->GetStatusLine();
1135 out.response_info = *response2;
1136 out.rv = ReadTransaction(trans2.get(), &out.response_data);
1137 EXPECT_EQ(OK, out.rv);
1138 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
1139 EXPECT_EQ("hello!hello!", out.response_data);
1140
1141 helper.VerifyDataConsumed();
1142 }
1143
1144 // Similar to ThreeGets above, however this test adds a SETTINGS
1145 // frame. The SETTINGS frame is read during the IO loop waiting on
1146 // the first transaction completion, and sets a maximum concurrent
1147 // stream limit of 1. This means that our IO loop exists after the
1148 // second transaction completes, so we can assert on read_index().
TEST_P(SpdyNetworkTransactionTest,ThreeGetsWithMaxConcurrent)1149 TEST_P(SpdyNetworkTransactionTest, ThreeGetsWithMaxConcurrent) {
1150 // Construct the request.
1151 scoped_ptr<SpdyFrame> req(
1152 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
1153 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
1154 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, false));
1155 scoped_ptr<SpdyFrame> fbody(spdy_util_.ConstructSpdyBodyFrame(1, true));
1156
1157 scoped_ptr<SpdyFrame> req2(
1158 spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, LOWEST, true));
1159 scoped_ptr<SpdyFrame> resp2(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3));
1160 scoped_ptr<SpdyFrame> body2(spdy_util_.ConstructSpdyBodyFrame(3, false));
1161 scoped_ptr<SpdyFrame> fbody2(spdy_util_.ConstructSpdyBodyFrame(3, true));
1162
1163 scoped_ptr<SpdyFrame> req3(
1164 spdy_util_.ConstructSpdyGet(NULL, 0, false, 5, LOWEST, true));
1165 scoped_ptr<SpdyFrame> resp3(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 5));
1166 scoped_ptr<SpdyFrame> body3(spdy_util_.ConstructSpdyBodyFrame(5, false));
1167 scoped_ptr<SpdyFrame> fbody3(spdy_util_.ConstructSpdyBodyFrame(5, true));
1168
1169 SettingsMap settings;
1170 const uint32 max_concurrent_streams = 1;
1171 settings[SETTINGS_MAX_CONCURRENT_STREAMS] =
1172 SettingsFlagsAndValue(SETTINGS_FLAG_NONE, max_concurrent_streams);
1173 scoped_ptr<SpdyFrame> settings_frame(
1174 spdy_util_.ConstructSpdySettings(settings));
1175 scoped_ptr<SpdyFrame> settings_ack(spdy_util_.ConstructSpdySettingsAck());
1176
1177 MockWrite writes[] = {
1178 CreateMockWrite(*req),
1179 CreateMockWrite(*settings_ack, 2),
1180 CreateMockWrite(*req2),
1181 CreateMockWrite(*req3),
1182 };
1183
1184 MockRead reads[] = {
1185 CreateMockRead(*settings_frame, 1),
1186 CreateMockRead(*resp),
1187 CreateMockRead(*body),
1188 CreateMockRead(*fbody),
1189 CreateMockRead(*resp2, 8),
1190 CreateMockRead(*body2),
1191 CreateMockRead(*fbody2),
1192 CreateMockRead(*resp3, 13),
1193 CreateMockRead(*body3),
1194 CreateMockRead(*fbody3),
1195
1196 MockRead(ASYNC, 0, 0), // EOF
1197 };
1198
1199 OrderedSocketData data(reads, arraysize(reads),
1200 writes, arraysize(writes));
1201 OrderedSocketData data_placeholder(NULL, 0, NULL, 0);
1202
1203 BoundNetLog log;
1204 TransactionHelperResult out;
1205 {
1206 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
1207 BoundNetLog(), GetParam(), NULL);
1208 helper.RunPreTestSetup();
1209 helper.AddData(&data);
1210 // We require placeholder data because three get requests are sent out, so
1211 // there needs to be three sets of SSL connection data.
1212 helper.AddData(&data_placeholder);
1213 helper.AddData(&data_placeholder);
1214 scoped_ptr<HttpNetworkTransaction> trans1(
1215 new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get()));
1216 scoped_ptr<HttpNetworkTransaction> trans2(
1217 new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get()));
1218 scoped_ptr<HttpNetworkTransaction> trans3(
1219 new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get()));
1220
1221 TestCompletionCallback callback1;
1222 TestCompletionCallback callback2;
1223 TestCompletionCallback callback3;
1224
1225 HttpRequestInfo httpreq1 = CreateGetRequest();
1226 HttpRequestInfo httpreq2 = CreateGetRequest();
1227 HttpRequestInfo httpreq3 = CreateGetRequest();
1228
1229 out.rv = trans1->Start(&httpreq1, callback1.callback(), log);
1230 ASSERT_EQ(out.rv, ERR_IO_PENDING);
1231 // Run transaction 1 through quickly to force a read of our SETTINGS
1232 // frame.
1233 out.rv = callback1.WaitForResult();
1234 ASSERT_EQ(OK, out.rv);
1235
1236 out.rv = trans2->Start(&httpreq2, callback2.callback(), log);
1237 ASSERT_EQ(out.rv, ERR_IO_PENDING);
1238 out.rv = trans3->Start(&httpreq3, callback3.callback(), log);
1239 ASSERT_EQ(out.rv, ERR_IO_PENDING);
1240 out.rv = callback2.WaitForResult();
1241 ASSERT_EQ(OK, out.rv);
1242 EXPECT_EQ(7U, data.read_index()); // i.e. the third trans was queued
1243
1244 out.rv = callback3.WaitForResult();
1245 ASSERT_EQ(OK, out.rv);
1246
1247 const HttpResponseInfo* response1 = trans1->GetResponseInfo();
1248 ASSERT_TRUE(response1 != NULL);
1249 EXPECT_TRUE(response1->headers.get() != NULL);
1250 EXPECT_TRUE(response1->was_fetched_via_spdy);
1251 out.status_line = response1->headers->GetStatusLine();
1252 out.response_info = *response1;
1253 out.rv = ReadTransaction(trans1.get(), &out.response_data);
1254 EXPECT_EQ(OK, out.rv);
1255 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
1256 EXPECT_EQ("hello!hello!", out.response_data);
1257
1258 const HttpResponseInfo* response2 = trans2->GetResponseInfo();
1259 out.status_line = response2->headers->GetStatusLine();
1260 out.response_info = *response2;
1261 out.rv = ReadTransaction(trans2.get(), &out.response_data);
1262 EXPECT_EQ(OK, out.rv);
1263 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
1264 EXPECT_EQ("hello!hello!", out.response_data);
1265
1266 const HttpResponseInfo* response3 = trans3->GetResponseInfo();
1267 out.status_line = response3->headers->GetStatusLine();
1268 out.response_info = *response3;
1269 out.rv = ReadTransaction(trans3.get(), &out.response_data);
1270 EXPECT_EQ(OK, out.rv);
1271 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
1272 EXPECT_EQ("hello!hello!", out.response_data);
1273
1274 helper.VerifyDataConsumed();
1275 }
1276 EXPECT_EQ(OK, out.rv);
1277 }
1278
1279 // Similar to ThreeGetsWithMaxConcurrent above, however this test adds
1280 // a fourth transaction. The third and fourth transactions have
1281 // different data ("hello!" vs "hello!hello!") and because of the
1282 // user specified priority, we expect to see them inverted in
1283 // the response from the server.
TEST_P(SpdyNetworkTransactionTest,FourGetsWithMaxConcurrentPriority)1284 TEST_P(SpdyNetworkTransactionTest, FourGetsWithMaxConcurrentPriority) {
1285 // Construct the request.
1286 scoped_ptr<SpdyFrame> req(
1287 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
1288 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
1289 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, false));
1290 scoped_ptr<SpdyFrame> fbody(spdy_util_.ConstructSpdyBodyFrame(1, true));
1291
1292 scoped_ptr<SpdyFrame> req2(
1293 spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, LOWEST, true));
1294 scoped_ptr<SpdyFrame> resp2(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3));
1295 scoped_ptr<SpdyFrame> body2(spdy_util_.ConstructSpdyBodyFrame(3, false));
1296 scoped_ptr<SpdyFrame> fbody2(spdy_util_.ConstructSpdyBodyFrame(3, true));
1297
1298 scoped_ptr<SpdyFrame> req4(
1299 spdy_util_.ConstructSpdyGet(NULL, 0, false, 5, HIGHEST, true));
1300 scoped_ptr<SpdyFrame> resp4(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 5));
1301 scoped_ptr<SpdyFrame> fbody4(spdy_util_.ConstructSpdyBodyFrame(5, true));
1302
1303 scoped_ptr<SpdyFrame> req3(
1304 spdy_util_.ConstructSpdyGet(NULL, 0, false, 7, LOWEST, true));
1305 scoped_ptr<SpdyFrame> resp3(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 7));
1306 scoped_ptr<SpdyFrame> body3(spdy_util_.ConstructSpdyBodyFrame(7, false));
1307 scoped_ptr<SpdyFrame> fbody3(spdy_util_.ConstructSpdyBodyFrame(7, true));
1308
1309 SettingsMap settings;
1310 const uint32 max_concurrent_streams = 1;
1311 settings[SETTINGS_MAX_CONCURRENT_STREAMS] =
1312 SettingsFlagsAndValue(SETTINGS_FLAG_NONE, max_concurrent_streams);
1313 scoped_ptr<SpdyFrame> settings_frame(
1314 spdy_util_.ConstructSpdySettings(settings));
1315 scoped_ptr<SpdyFrame> settings_ack(spdy_util_.ConstructSpdySettingsAck());
1316
1317 MockWrite writes[] = { CreateMockWrite(*req),
1318 CreateMockWrite(*settings_ack, 2),
1319 CreateMockWrite(*req2),
1320 CreateMockWrite(*req4),
1321 CreateMockWrite(*req3),
1322 };
1323 MockRead reads[] = {
1324 CreateMockRead(*settings_frame, 1),
1325 CreateMockRead(*resp),
1326 CreateMockRead(*body),
1327 CreateMockRead(*fbody),
1328 CreateMockRead(*resp2, 8),
1329 CreateMockRead(*body2),
1330 CreateMockRead(*fbody2),
1331 CreateMockRead(*resp4, 14),
1332 CreateMockRead(*fbody4),
1333 CreateMockRead(*resp3, 17),
1334 CreateMockRead(*body3),
1335 CreateMockRead(*fbody3),
1336
1337 MockRead(ASYNC, 0, 0), // EOF
1338 };
1339
1340 OrderedSocketData data(reads, arraysize(reads),
1341 writes, arraysize(writes));
1342 OrderedSocketData data_placeholder(NULL, 0, NULL, 0);
1343
1344 BoundNetLog log;
1345 TransactionHelperResult out;
1346 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
1347 BoundNetLog(), GetParam(), NULL);
1348 helper.RunPreTestSetup();
1349 helper.AddData(&data);
1350 // We require placeholder data because four get requests are sent out, so
1351 // there needs to be four sets of SSL connection data.
1352 helper.AddData(&data_placeholder);
1353 helper.AddData(&data_placeholder);
1354 helper.AddData(&data_placeholder);
1355 scoped_ptr<HttpNetworkTransaction> trans1(
1356 new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get()));
1357 scoped_ptr<HttpNetworkTransaction> trans2(
1358 new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get()));
1359 scoped_ptr<HttpNetworkTransaction> trans3(
1360 new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get()));
1361 scoped_ptr<HttpNetworkTransaction> trans4(
1362 new HttpNetworkTransaction(HIGHEST, helper.session().get()));
1363
1364 TestCompletionCallback callback1;
1365 TestCompletionCallback callback2;
1366 TestCompletionCallback callback3;
1367 TestCompletionCallback callback4;
1368
1369 HttpRequestInfo httpreq1 = CreateGetRequest();
1370 HttpRequestInfo httpreq2 = CreateGetRequest();
1371 HttpRequestInfo httpreq3 = CreateGetRequest();
1372 HttpRequestInfo httpreq4 = CreateGetRequest();
1373
1374 out.rv = trans1->Start(&httpreq1, callback1.callback(), log);
1375 ASSERT_EQ(ERR_IO_PENDING, out.rv);
1376 // Run transaction 1 through quickly to force a read of our SETTINGS frame.
1377 out.rv = callback1.WaitForResult();
1378 ASSERT_EQ(OK, out.rv);
1379
1380 out.rv = trans2->Start(&httpreq2, callback2.callback(), log);
1381 ASSERT_EQ(ERR_IO_PENDING, out.rv);
1382 out.rv = trans3->Start(&httpreq3, callback3.callback(), log);
1383 ASSERT_EQ(ERR_IO_PENDING, out.rv);
1384 out.rv = trans4->Start(&httpreq4, callback4.callback(), log);
1385 ASSERT_EQ(ERR_IO_PENDING, out.rv);
1386
1387 out.rv = callback2.WaitForResult();
1388 ASSERT_EQ(OK, out.rv);
1389 EXPECT_EQ(data.read_index(), 7U); // i.e. the third & fourth trans queued
1390
1391 out.rv = callback3.WaitForResult();
1392 ASSERT_EQ(OK, out.rv);
1393
1394 const HttpResponseInfo* response1 = trans1->GetResponseInfo();
1395 EXPECT_TRUE(response1->headers.get() != NULL);
1396 EXPECT_TRUE(response1->was_fetched_via_spdy);
1397 out.status_line = response1->headers->GetStatusLine();
1398 out.response_info = *response1;
1399 out.rv = ReadTransaction(trans1.get(), &out.response_data);
1400 EXPECT_EQ(OK, out.rv);
1401 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
1402 EXPECT_EQ("hello!hello!", out.response_data);
1403
1404 const HttpResponseInfo* response2 = trans2->GetResponseInfo();
1405 out.status_line = response2->headers->GetStatusLine();
1406 out.response_info = *response2;
1407 out.rv = ReadTransaction(trans2.get(), &out.response_data);
1408 EXPECT_EQ(OK, out.rv);
1409 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
1410 EXPECT_EQ("hello!hello!", out.response_data);
1411
1412 // notice: response3 gets two hellos, response4 gets one
1413 // hello, so we know dequeuing priority was respected.
1414 const HttpResponseInfo* response3 = trans3->GetResponseInfo();
1415 out.status_line = response3->headers->GetStatusLine();
1416 out.response_info = *response3;
1417 out.rv = ReadTransaction(trans3.get(), &out.response_data);
1418 EXPECT_EQ(OK, out.rv);
1419 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
1420 EXPECT_EQ("hello!hello!", out.response_data);
1421
1422 out.rv = callback4.WaitForResult();
1423 EXPECT_EQ(OK, out.rv);
1424 const HttpResponseInfo* response4 = trans4->GetResponseInfo();
1425 out.status_line = response4->headers->GetStatusLine();
1426 out.response_info = *response4;
1427 out.rv = ReadTransaction(trans4.get(), &out.response_data);
1428 EXPECT_EQ(OK, out.rv);
1429 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
1430 EXPECT_EQ("hello!", out.response_data);
1431 helper.VerifyDataConsumed();
1432 EXPECT_EQ(OK, out.rv);
1433 }
1434
1435 // Similar to ThreeGetsMaxConcurrrent above, however, this test
1436 // deletes a session in the middle of the transaction to insure
1437 // that we properly remove pendingcreatestream objects from
1438 // the spdy_session
TEST_P(SpdyNetworkTransactionTest,ThreeGetsWithMaxConcurrentDelete)1439 TEST_P(SpdyNetworkTransactionTest, ThreeGetsWithMaxConcurrentDelete) {
1440 // Construct the request.
1441 scoped_ptr<SpdyFrame> req(
1442 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
1443 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
1444 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, false));
1445 scoped_ptr<SpdyFrame> fbody(spdy_util_.ConstructSpdyBodyFrame(1, true));
1446
1447 scoped_ptr<SpdyFrame> req2(
1448 spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, LOWEST, true));
1449 scoped_ptr<SpdyFrame> resp2(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3));
1450 scoped_ptr<SpdyFrame> body2(spdy_util_.ConstructSpdyBodyFrame(3, false));
1451 scoped_ptr<SpdyFrame> fbody2(spdy_util_.ConstructSpdyBodyFrame(3, true));
1452
1453 SettingsMap settings;
1454 const uint32 max_concurrent_streams = 1;
1455 settings[SETTINGS_MAX_CONCURRENT_STREAMS] =
1456 SettingsFlagsAndValue(SETTINGS_FLAG_NONE, max_concurrent_streams);
1457 scoped_ptr<SpdyFrame> settings_frame(
1458 spdy_util_.ConstructSpdySettings(settings));
1459 scoped_ptr<SpdyFrame> settings_ack(spdy_util_.ConstructSpdySettingsAck());
1460
1461 MockWrite writes[] = {
1462 CreateMockWrite(*req),
1463 CreateMockWrite(*settings_ack, 2),
1464 CreateMockWrite(*req2),
1465 };
1466 MockRead reads[] = {
1467 CreateMockRead(*settings_frame, 1),
1468 CreateMockRead(*resp),
1469 CreateMockRead(*body),
1470 CreateMockRead(*fbody),
1471 CreateMockRead(*resp2, 8),
1472 CreateMockRead(*body2),
1473 CreateMockRead(*fbody2),
1474 MockRead(ASYNC, 0, 0), // EOF
1475 };
1476
1477 OrderedSocketData data(reads, arraysize(reads),
1478 writes, arraysize(writes));
1479 OrderedSocketData data_placeholder(NULL, 0, NULL, 0);
1480
1481 BoundNetLog log;
1482 TransactionHelperResult out;
1483 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
1484 BoundNetLog(), GetParam(), NULL);
1485 helper.RunPreTestSetup();
1486 helper.AddData(&data);
1487 // We require placeholder data because three get requests are sent out, so
1488 // there needs to be three sets of SSL connection data.
1489 helper.AddData(&data_placeholder);
1490 helper.AddData(&data_placeholder);
1491 scoped_ptr<HttpNetworkTransaction> trans1(
1492 new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get()));
1493 scoped_ptr<HttpNetworkTransaction> trans2(
1494 new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get()));
1495 scoped_ptr<HttpNetworkTransaction> trans3(
1496 new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get()));
1497
1498 TestCompletionCallback callback1;
1499 TestCompletionCallback callback2;
1500 TestCompletionCallback callback3;
1501
1502 HttpRequestInfo httpreq1 = CreateGetRequest();
1503 HttpRequestInfo httpreq2 = CreateGetRequest();
1504 HttpRequestInfo httpreq3 = CreateGetRequest();
1505
1506 out.rv = trans1->Start(&httpreq1, callback1.callback(), log);
1507 ASSERT_EQ(out.rv, ERR_IO_PENDING);
1508 // Run transaction 1 through quickly to force a read of our SETTINGS frame.
1509 out.rv = callback1.WaitForResult();
1510 ASSERT_EQ(OK, out.rv);
1511
1512 out.rv = trans2->Start(&httpreq2, callback2.callback(), log);
1513 ASSERT_EQ(out.rv, ERR_IO_PENDING);
1514 out.rv = trans3->Start(&httpreq3, callback3.callback(), log);
1515 delete trans3.release();
1516 ASSERT_EQ(out.rv, ERR_IO_PENDING);
1517 out.rv = callback2.WaitForResult();
1518 ASSERT_EQ(OK, out.rv);
1519
1520 EXPECT_EQ(8U, data.read_index());
1521
1522 const HttpResponseInfo* response1 = trans1->GetResponseInfo();
1523 ASSERT_TRUE(response1 != NULL);
1524 EXPECT_TRUE(response1->headers.get() != NULL);
1525 EXPECT_TRUE(response1->was_fetched_via_spdy);
1526 out.status_line = response1->headers->GetStatusLine();
1527 out.response_info = *response1;
1528 out.rv = ReadTransaction(trans1.get(), &out.response_data);
1529 EXPECT_EQ(OK, out.rv);
1530 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
1531 EXPECT_EQ("hello!hello!", out.response_data);
1532
1533 const HttpResponseInfo* response2 = trans2->GetResponseInfo();
1534 ASSERT_TRUE(response2 != NULL);
1535 out.status_line = response2->headers->GetStatusLine();
1536 out.response_info = *response2;
1537 out.rv = ReadTransaction(trans2.get(), &out.response_data);
1538 EXPECT_EQ(OK, out.rv);
1539 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
1540 EXPECT_EQ("hello!hello!", out.response_data);
1541 helper.VerifyDataConsumed();
1542 EXPECT_EQ(OK, out.rv);
1543 }
1544
1545 namespace {
1546
1547 // The KillerCallback will delete the transaction on error as part of the
1548 // callback.
1549 class KillerCallback : public TestCompletionCallbackBase {
1550 public:
KillerCallback(HttpNetworkTransaction * transaction)1551 explicit KillerCallback(HttpNetworkTransaction* transaction)
1552 : transaction_(transaction),
1553 callback_(base::Bind(&KillerCallback::OnComplete,
1554 base::Unretained(this))) {
1555 }
1556
~KillerCallback()1557 virtual ~KillerCallback() {}
1558
callback() const1559 const CompletionCallback& callback() const { return callback_; }
1560
1561 private:
OnComplete(int result)1562 void OnComplete(int result) {
1563 if (result < 0)
1564 delete transaction_;
1565
1566 SetResult(result);
1567 }
1568
1569 HttpNetworkTransaction* transaction_;
1570 CompletionCallback callback_;
1571 };
1572
1573 } // namespace
1574
1575 // Similar to ThreeGetsMaxConcurrrentDelete above, however, this test
1576 // closes the socket while we have a pending transaction waiting for
1577 // a pending stream creation. http://crbug.com/52901
TEST_P(SpdyNetworkTransactionTest,ThreeGetsWithMaxConcurrentSocketClose)1578 TEST_P(SpdyNetworkTransactionTest, ThreeGetsWithMaxConcurrentSocketClose) {
1579 // Construct the request.
1580 scoped_ptr<SpdyFrame> req(
1581 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
1582 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
1583 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, false));
1584 scoped_ptr<SpdyFrame> fin_body(spdy_util_.ConstructSpdyBodyFrame(1, true));
1585
1586 scoped_ptr<SpdyFrame> req2(
1587 spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, LOWEST, true));
1588 scoped_ptr<SpdyFrame> resp2(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3));
1589
1590 SettingsMap settings;
1591 const uint32 max_concurrent_streams = 1;
1592 settings[SETTINGS_MAX_CONCURRENT_STREAMS] =
1593 SettingsFlagsAndValue(SETTINGS_FLAG_NONE, max_concurrent_streams);
1594 scoped_ptr<SpdyFrame> settings_frame(
1595 spdy_util_.ConstructSpdySettings(settings));
1596 scoped_ptr<SpdyFrame> settings_ack(spdy_util_.ConstructSpdySettingsAck());
1597
1598 MockWrite writes[] = {
1599 CreateMockWrite(*req),
1600 CreateMockWrite(*settings_ack, 2),
1601 CreateMockWrite(*req2),
1602 };
1603 MockRead reads[] = {
1604 CreateMockRead(*settings_frame, 1),
1605 CreateMockRead(*resp),
1606 CreateMockRead(*body),
1607 CreateMockRead(*fin_body),
1608 CreateMockRead(*resp2, 8),
1609 MockRead(ASYNC, ERR_CONNECTION_RESET, 0), // Abort!
1610 };
1611
1612 OrderedSocketData data(reads, arraysize(reads),
1613 writes, arraysize(writes));
1614 OrderedSocketData data_placeholder(NULL, 0, NULL, 0);
1615
1616 BoundNetLog log;
1617 TransactionHelperResult out;
1618 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
1619 BoundNetLog(), GetParam(), NULL);
1620 helper.RunPreTestSetup();
1621 helper.AddData(&data);
1622 // We require placeholder data because three get requests are sent out, so
1623 // there needs to be three sets of SSL connection data.
1624 helper.AddData(&data_placeholder);
1625 helper.AddData(&data_placeholder);
1626 HttpNetworkTransaction trans1(DEFAULT_PRIORITY, helper.session().get());
1627 HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session().get());
1628 HttpNetworkTransaction* trans3(
1629 new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get()));
1630
1631 TestCompletionCallback callback1;
1632 TestCompletionCallback callback2;
1633 KillerCallback callback3(trans3);
1634
1635 HttpRequestInfo httpreq1 = CreateGetRequest();
1636 HttpRequestInfo httpreq2 = CreateGetRequest();
1637 HttpRequestInfo httpreq3 = CreateGetRequest();
1638
1639 out.rv = trans1.Start(&httpreq1, callback1.callback(), log);
1640 ASSERT_EQ(out.rv, ERR_IO_PENDING);
1641 // Run transaction 1 through quickly to force a read of our SETTINGS frame.
1642 out.rv = callback1.WaitForResult();
1643 ASSERT_EQ(OK, out.rv);
1644
1645 out.rv = trans2.Start(&httpreq2, callback2.callback(), log);
1646 ASSERT_EQ(out.rv, ERR_IO_PENDING);
1647 out.rv = trans3->Start(&httpreq3, callback3.callback(), log);
1648 ASSERT_EQ(out.rv, ERR_IO_PENDING);
1649 out.rv = callback3.WaitForResult();
1650 ASSERT_EQ(ERR_ABORTED, out.rv);
1651
1652 EXPECT_EQ(6U, data.read_index());
1653
1654 const HttpResponseInfo* response1 = trans1.GetResponseInfo();
1655 ASSERT_TRUE(response1 != NULL);
1656 EXPECT_TRUE(response1->headers.get() != NULL);
1657 EXPECT_TRUE(response1->was_fetched_via_spdy);
1658 out.status_line = response1->headers->GetStatusLine();
1659 out.response_info = *response1;
1660 out.rv = ReadTransaction(&trans1, &out.response_data);
1661 EXPECT_EQ(OK, out.rv);
1662
1663 const HttpResponseInfo* response2 = trans2.GetResponseInfo();
1664 ASSERT_TRUE(response2 != NULL);
1665 out.status_line = response2->headers->GetStatusLine();
1666 out.response_info = *response2;
1667 out.rv = ReadTransaction(&trans2, &out.response_data);
1668 EXPECT_EQ(ERR_CONNECTION_RESET, out.rv);
1669
1670 helper.VerifyDataConsumed();
1671 }
1672
1673 // Test that a simple PUT request works.
TEST_P(SpdyNetworkTransactionTest,Put)1674 TEST_P(SpdyNetworkTransactionTest, Put) {
1675 // Setup the request
1676 HttpRequestInfo request;
1677 request.method = "PUT";
1678 request.url = GURL("http://www.google.com/");
1679
1680 const SpdyHeaderInfo kSynStartHeader = {
1681 SYN_STREAM, // Kind = Syn
1682 1, // Stream ID
1683 0, // Associated stream ID
1684 ConvertRequestPriorityToSpdyPriority(
1685 LOWEST, spdy_util_.spdy_version()),
1686 kSpdyCredentialSlotUnused,
1687 CONTROL_FLAG_FIN, // Control Flags
1688 false, // Compressed
1689 RST_STREAM_INVALID, // Status
1690 NULL, // Data
1691 0, // Length
1692 DATA_FLAG_NONE // Data Flags
1693 };
1694 scoped_ptr<SpdyHeaderBlock> put_headers(
1695 spdy_util_.ConstructPutHeaderBlock("http://www.google.com", 0));
1696 scoped_ptr<SpdyFrame> req(spdy_util_.ConstructSpdyFrame(
1697 kSynStartHeader, put_headers.Pass()));
1698 MockWrite writes[] = {
1699 CreateMockWrite(*req),
1700 };
1701
1702 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
1703 const SpdyHeaderInfo kSynReplyHeader = {
1704 SYN_REPLY, // Kind = SynReply
1705 1, // Stream ID
1706 0, // Associated stream ID
1707 ConvertRequestPriorityToSpdyPriority(
1708 LOWEST, spdy_util_.spdy_version()),
1709 kSpdyCredentialSlotUnused,
1710 CONTROL_FLAG_NONE, // Control Flags
1711 false, // Compressed
1712 RST_STREAM_INVALID, // Status
1713 NULL, // Data
1714 0, // Length
1715 DATA_FLAG_NONE // Data Flags
1716 };
1717 scoped_ptr<SpdyHeaderBlock> reply_headers(new SpdyHeaderBlock());
1718 (*reply_headers)[spdy_util_.GetStatusKey()] = "200";
1719 (*reply_headers)[spdy_util_.GetVersionKey()] = "HTTP/1.1";
1720 (*reply_headers)["content-length"] = "1234";
1721 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyFrame(
1722 kSynReplyHeader, reply_headers.Pass()));
1723 MockRead reads[] = {
1724 CreateMockRead(*resp),
1725 CreateMockRead(*body),
1726 MockRead(ASYNC, 0, 0) // EOF
1727 };
1728
1729 DelayedSocketData data(1, reads, arraysize(reads),
1730 writes, arraysize(writes));
1731 NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY,
1732 BoundNetLog(), GetParam(), NULL);
1733 helper.RunToCompletion(&data);
1734 TransactionHelperResult out = helper.output();
1735
1736 EXPECT_EQ(OK, out.rv);
1737 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
1738 }
1739
1740 // Test that a simple HEAD request works.
TEST_P(SpdyNetworkTransactionTest,Head)1741 TEST_P(SpdyNetworkTransactionTest, Head) {
1742 // Setup the request
1743 HttpRequestInfo request;
1744 request.method = "HEAD";
1745 request.url = GURL("http://www.google.com/");
1746
1747 const SpdyHeaderInfo kSynStartHeader = {
1748 SYN_STREAM, // Kind = Syn
1749 1, // Stream ID
1750 0, // Associated stream ID
1751 ConvertRequestPriorityToSpdyPriority(
1752 LOWEST, spdy_util_.spdy_version()),
1753 kSpdyCredentialSlotUnused,
1754 CONTROL_FLAG_FIN, // Control Flags
1755 false, // Compressed
1756 RST_STREAM_INVALID, // Status
1757 NULL, // Data
1758 0, // Length
1759 DATA_FLAG_NONE // Data Flags
1760 };
1761 scoped_ptr<SpdyHeaderBlock> head_headers(
1762 spdy_util_.ConstructHeadHeaderBlock("http://www.google.com", 0));
1763 scoped_ptr<SpdyFrame> req(spdy_util_.ConstructSpdyFrame(
1764 kSynStartHeader, head_headers.Pass()));
1765 MockWrite writes[] = {
1766 CreateMockWrite(*req),
1767 };
1768
1769 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
1770 const SpdyHeaderInfo kSynReplyHeader = {
1771 SYN_REPLY, // Kind = SynReply
1772 1, // Stream ID
1773 0, // Associated stream ID
1774 ConvertRequestPriorityToSpdyPriority(
1775 LOWEST, spdy_util_.spdy_version()),
1776 kSpdyCredentialSlotUnused,
1777 CONTROL_FLAG_NONE, // Control Flags
1778 false, // Compressed
1779 RST_STREAM_INVALID, // Status
1780 NULL, // Data
1781 0, // Length
1782 DATA_FLAG_NONE // Data Flags
1783 };
1784 scoped_ptr<SpdyHeaderBlock> reply_headers(new SpdyHeaderBlock());
1785 (*reply_headers)[spdy_util_.GetStatusKey()] = "200";
1786 (*reply_headers)[spdy_util_.GetVersionKey()] = "HTTP/1.1";
1787 (*reply_headers)["content-length"] = "1234";
1788 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyFrame(
1789 kSynReplyHeader,
1790 reply_headers.Pass()));
1791 MockRead reads[] = {
1792 CreateMockRead(*resp),
1793 CreateMockRead(*body),
1794 MockRead(ASYNC, 0, 0) // EOF
1795 };
1796
1797 DelayedSocketData data(1, reads, arraysize(reads),
1798 writes, arraysize(writes));
1799 NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY,
1800 BoundNetLog(), GetParam(), NULL);
1801 helper.RunToCompletion(&data);
1802 TransactionHelperResult out = helper.output();
1803
1804 EXPECT_EQ(OK, out.rv);
1805 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
1806 }
1807
1808 // Test that a simple POST works.
TEST_P(SpdyNetworkTransactionTest,Post)1809 TEST_P(SpdyNetworkTransactionTest, Post) {
1810 scoped_ptr<SpdyFrame> req(
1811 spdy_util_.ConstructSpdyPost(
1812 kRequestUrl, 1, kUploadDataSize, LOWEST, NULL, 0));
1813 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
1814 MockWrite writes[] = {
1815 CreateMockWrite(*req),
1816 CreateMockWrite(*body), // POST upload frame
1817 };
1818
1819 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
1820 MockRead reads[] = {
1821 CreateMockRead(*resp),
1822 CreateMockRead(*body),
1823 MockRead(ASYNC, 0, 0) // EOF
1824 };
1825
1826 DelayedSocketData data(2, reads, arraysize(reads),
1827 writes, arraysize(writes));
1828 NormalSpdyTransactionHelper helper(CreatePostRequest(), DEFAULT_PRIORITY,
1829 BoundNetLog(), GetParam(), NULL);
1830 helper.RunToCompletion(&data);
1831 TransactionHelperResult out = helper.output();
1832 EXPECT_EQ(OK, out.rv);
1833 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
1834 EXPECT_EQ("hello!", out.response_data);
1835 }
1836
1837 // Test that a POST with a file works.
TEST_P(SpdyNetworkTransactionTest,FilePost)1838 TEST_P(SpdyNetworkTransactionTest, FilePost) {
1839 scoped_ptr<SpdyFrame> req(
1840 spdy_util_.ConstructSpdyPost(
1841 kRequestUrl, 1, kUploadDataSize, LOWEST, NULL, 0));
1842 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
1843 MockWrite writes[] = {
1844 CreateMockWrite(*req),
1845 CreateMockWrite(*body), // POST upload frame
1846 };
1847
1848 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
1849 MockRead reads[] = {
1850 CreateMockRead(*resp),
1851 CreateMockRead(*body),
1852 MockRead(ASYNC, 0, 0) // EOF
1853 };
1854
1855 DelayedSocketData data(2, reads, arraysize(reads),
1856 writes, arraysize(writes));
1857 NormalSpdyTransactionHelper helper(CreateFilePostRequest(), DEFAULT_PRIORITY,
1858 BoundNetLog(), GetParam(), NULL);
1859 helper.RunToCompletion(&data);
1860 TransactionHelperResult out = helper.output();
1861 EXPECT_EQ(OK, out.rv);
1862 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
1863 EXPECT_EQ("hello!", out.response_data);
1864 }
1865
1866 // Test that a POST with a unreadable file fails.
TEST_P(SpdyNetworkTransactionTest,UnreadableFilePost)1867 TEST_P(SpdyNetworkTransactionTest, UnreadableFilePost) {
1868 MockWrite writes[] = {
1869 MockWrite(ASYNC, 0, 0) // EOF
1870 };
1871 MockRead reads[] = {
1872 MockRead(ASYNC, 0, 0) // EOF
1873 };
1874
1875 DelayedSocketData data(1, reads, arraysize(reads), writes, arraysize(writes));
1876 NormalSpdyTransactionHelper helper(CreateUnreadableFilePostRequest(),
1877 DEFAULT_PRIORITY,
1878 BoundNetLog(), GetParam(), NULL);
1879 helper.RunPreTestSetup();
1880 helper.AddData(&data);
1881 helper.RunDefaultTest();
1882
1883 base::RunLoop().RunUntilIdle();
1884 helper.VerifyDataNotConsumed();
1885 EXPECT_EQ(ERR_ACCESS_DENIED, helper.output().rv);
1886 }
1887
1888 // Test that a complex POST works.
TEST_P(SpdyNetworkTransactionTest,ComplexPost)1889 TEST_P(SpdyNetworkTransactionTest, ComplexPost) {
1890 scoped_ptr<SpdyFrame> req(
1891 spdy_util_.ConstructSpdyPost(
1892 kRequestUrl, 1, kUploadDataSize, LOWEST, NULL, 0));
1893 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
1894 MockWrite writes[] = {
1895 CreateMockWrite(*req),
1896 CreateMockWrite(*body), // POST upload frame
1897 };
1898
1899 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
1900 MockRead reads[] = {
1901 CreateMockRead(*resp),
1902 CreateMockRead(*body),
1903 MockRead(ASYNC, 0, 0) // EOF
1904 };
1905
1906 DelayedSocketData data(2, reads, arraysize(reads),
1907 writes, arraysize(writes));
1908 NormalSpdyTransactionHelper helper(CreateComplexPostRequest(),
1909 DEFAULT_PRIORITY,
1910 BoundNetLog(), GetParam(), NULL);
1911 helper.RunToCompletion(&data);
1912 TransactionHelperResult out = helper.output();
1913 EXPECT_EQ(OK, out.rv);
1914 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
1915 EXPECT_EQ("hello!", out.response_data);
1916 }
1917
1918 // Test that a chunked POST works.
TEST_P(SpdyNetworkTransactionTest,ChunkedPost)1919 TEST_P(SpdyNetworkTransactionTest, ChunkedPost) {
1920 scoped_ptr<SpdyFrame> req(spdy_util_.ConstructChunkedSpdyPost(NULL, 0));
1921 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
1922 MockWrite writes[] = {
1923 CreateMockWrite(*req),
1924 CreateMockWrite(*body),
1925 };
1926
1927 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
1928 MockRead reads[] = {
1929 CreateMockRead(*resp),
1930 CreateMockRead(*body),
1931 MockRead(ASYNC, 0, 0) // EOF
1932 };
1933
1934 DelayedSocketData data(2, reads, arraysize(reads),
1935 writes, arraysize(writes));
1936 NormalSpdyTransactionHelper helper(CreateChunkedPostRequest(),
1937 DEFAULT_PRIORITY,
1938 BoundNetLog(), GetParam(), NULL);
1939
1940 // These chunks get merged into a single frame when being sent.
1941 const int kFirstChunkSize = kUploadDataSize/2;
1942 helper.request().upload_data_stream->AppendChunk(
1943 kUploadData, kFirstChunkSize, false);
1944 helper.request().upload_data_stream->AppendChunk(
1945 kUploadData + kFirstChunkSize, kUploadDataSize - kFirstChunkSize, true);
1946
1947 helper.RunToCompletion(&data);
1948 TransactionHelperResult out = helper.output();
1949 EXPECT_EQ(OK, out.rv);
1950 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
1951 EXPECT_EQ(kUploadData, out.response_data);
1952 }
1953
1954 // Test that a chunked POST works with chunks appended after transaction starts.
TEST_P(SpdyNetworkTransactionTest,DelayedChunkedPost)1955 TEST_P(SpdyNetworkTransactionTest, DelayedChunkedPost) {
1956 scoped_ptr<SpdyFrame> req(spdy_util_.ConstructChunkedSpdyPost(NULL, 0));
1957 scoped_ptr<SpdyFrame> chunk1(spdy_util_.ConstructSpdyBodyFrame(1, false));
1958 scoped_ptr<SpdyFrame> chunk2(spdy_util_.ConstructSpdyBodyFrame(1, false));
1959 scoped_ptr<SpdyFrame> chunk3(spdy_util_.ConstructSpdyBodyFrame(1, true));
1960 MockWrite writes[] = {
1961 CreateMockWrite(*req),
1962 CreateMockWrite(*chunk1),
1963 CreateMockWrite(*chunk2),
1964 CreateMockWrite(*chunk3),
1965 };
1966
1967 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
1968 MockRead reads[] = {
1969 CreateMockRead(*resp),
1970 CreateMockRead(*chunk1),
1971 CreateMockRead(*chunk2),
1972 CreateMockRead(*chunk3),
1973 MockRead(ASYNC, 0, 0) // EOF
1974 };
1975
1976 DelayedSocketData data(4, reads, arraysize(reads),
1977 writes, arraysize(writes));
1978 NormalSpdyTransactionHelper helper(CreateChunkedPostRequest(),
1979 DEFAULT_PRIORITY,
1980 BoundNetLog(), GetParam(), NULL);
1981
1982 helper.request().upload_data_stream->AppendChunk(
1983 kUploadData, kUploadDataSize, false);
1984
1985 helper.RunPreTestSetup();
1986 helper.AddData(&data);
1987 ASSERT_TRUE(helper.StartDefaultTest());
1988
1989 base::RunLoop().RunUntilIdle();
1990 helper.request().upload_data_stream->AppendChunk(
1991 kUploadData, kUploadDataSize, false);
1992 base::RunLoop().RunUntilIdle();
1993 helper.request().upload_data_stream->AppendChunk(
1994 kUploadData, kUploadDataSize, true);
1995
1996 helper.FinishDefaultTest();
1997 helper.VerifyDataConsumed();
1998
1999 std::string expected_response;
2000 expected_response += kUploadData;
2001 expected_response += kUploadData;
2002 expected_response += kUploadData;
2003
2004 TransactionHelperResult out = helper.output();
2005 EXPECT_EQ(OK, out.rv);
2006 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
2007 EXPECT_EQ(expected_response, out.response_data);
2008 }
2009
2010 // Test that a POST without any post data works.
TEST_P(SpdyNetworkTransactionTest,NullPost)2011 TEST_P(SpdyNetworkTransactionTest, NullPost) {
2012 BufferedSpdyFramer framer(spdy_util_.spdy_version(), false);
2013 // Setup the request
2014 HttpRequestInfo request;
2015 request.method = "POST";
2016 request.url = GURL(kRequestUrl);
2017 // Create an empty UploadData.
2018 request.upload_data_stream = NULL;
2019
2020 // When request.upload_data_stream is NULL for post, content-length is
2021 // expected to be 0.
2022 SpdySynStreamIR syn_ir(1);
2023 syn_ir.set_name_value_block(
2024 *spdy_util_.ConstructPostHeaderBlock(kRequestUrl, 0));
2025 syn_ir.set_fin(true); // No body.
2026 syn_ir.set_priority(ConvertRequestPriorityToSpdyPriority(
2027 LOWEST, spdy_util_.spdy_version()));
2028 scoped_ptr<SpdyFrame> req(framer.SerializeFrame(syn_ir));
2029
2030 MockWrite writes[] = {
2031 CreateMockWrite(*req),
2032 };
2033
2034 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
2035 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
2036 MockRead reads[] = {
2037 CreateMockRead(*resp),
2038 CreateMockRead(*body),
2039 MockRead(ASYNC, 0, 0) // EOF
2040 };
2041
2042 DelayedSocketData data(1, reads, arraysize(reads),
2043 writes, arraysize(writes));
2044
2045 NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY,
2046 BoundNetLog(), GetParam(), NULL);
2047 helper.RunToCompletion(&data);
2048 TransactionHelperResult out = helper.output();
2049 EXPECT_EQ(OK, out.rv);
2050 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
2051 EXPECT_EQ("hello!", out.response_data);
2052 }
2053
2054 // Test that a simple POST works.
TEST_P(SpdyNetworkTransactionTest,EmptyPost)2055 TEST_P(SpdyNetworkTransactionTest, EmptyPost) {
2056 BufferedSpdyFramer framer(spdy_util_.spdy_version(), false);
2057 // Create an empty UploadDataStream.
2058 ScopedVector<UploadElementReader> element_readers;
2059 UploadDataStream stream(element_readers.Pass(), 0);
2060
2061 // Setup the request
2062 HttpRequestInfo request;
2063 request.method = "POST";
2064 request.url = GURL(kRequestUrl);
2065 request.upload_data_stream = &stream;
2066
2067 const uint64 kContentLength = 0;
2068
2069 SpdySynStreamIR syn_ir(1);
2070 syn_ir.set_name_value_block(
2071 *spdy_util_.ConstructPostHeaderBlock(kRequestUrl, kContentLength));
2072 syn_ir.set_fin(true); // No body.
2073 syn_ir.set_priority(ConvertRequestPriorityToSpdyPriority(
2074 LOWEST, spdy_util_.spdy_version()));
2075 scoped_ptr<SpdyFrame> req(framer.SerializeFrame(syn_ir));
2076
2077 MockWrite writes[] = {
2078 CreateMockWrite(*req),
2079 };
2080
2081 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
2082 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
2083 MockRead reads[] = {
2084 CreateMockRead(*resp),
2085 CreateMockRead(*body),
2086 MockRead(ASYNC, 0, 0) // EOF
2087 };
2088
2089 DelayedSocketData data(1, reads, arraysize(reads), writes, arraysize(writes));
2090
2091 NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY,
2092 BoundNetLog(), GetParam(), NULL);
2093 helper.RunToCompletion(&data);
2094 TransactionHelperResult out = helper.output();
2095 EXPECT_EQ(OK, out.rv);
2096 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
2097 EXPECT_EQ("hello!", out.response_data);
2098 }
2099
2100 // While we're doing a post, the server sends the reply before upload completes.
TEST_P(SpdyNetworkTransactionTest,ResponseBeforePostCompletes)2101 TEST_P(SpdyNetworkTransactionTest, ResponseBeforePostCompletes) {
2102 scoped_ptr<SpdyFrame> req(spdy_util_.ConstructChunkedSpdyPost(NULL, 0));
2103 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
2104 MockWrite writes[] = {
2105 CreateMockWrite(*req, 0),
2106 CreateMockWrite(*body, 3),
2107 };
2108 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
2109 MockRead reads[] = {
2110 CreateMockRead(*resp, 1),
2111 CreateMockRead(*body, 2),
2112 MockRead(ASYNC, 0, 4) // EOF
2113 };
2114
2115 // Write the request headers, and read the complete response
2116 // while still waiting for chunked request data.
2117 DeterministicSocketData data(reads, arraysize(reads),
2118 writes, arraysize(writes));
2119 NormalSpdyTransactionHelper helper(CreateChunkedPostRequest(),
2120 DEFAULT_PRIORITY,
2121 BoundNetLog(), GetParam(), NULL);
2122 helper.SetDeterministic();
2123 helper.RunPreTestSetup();
2124 helper.AddDeterministicData(&data);
2125
2126 ASSERT_TRUE(helper.StartDefaultTest());
2127
2128 // Process the request headers, SYN_REPLY, and response body.
2129 // The request body is still in flight.
2130 data.RunFor(3);
2131
2132 const HttpResponseInfo* response = helper.trans()->GetResponseInfo();
2133 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
2134
2135 // Finish sending the request body.
2136 helper.request().upload_data_stream->AppendChunk(
2137 kUploadData, kUploadDataSize, true);
2138 data.RunFor(2);
2139
2140 std::string response_body;
2141 EXPECT_EQ(OK, ReadTransaction(helper.trans(), &response_body));
2142 EXPECT_EQ(kUploadData, response_body);
2143 helper.VerifyDataConsumed();
2144 }
2145
2146 // The client upon cancellation tries to send a RST_STREAM frame. The mock
2147 // socket causes the TCP write to return zero. This test checks that the client
2148 // tries to queue up the RST_STREAM frame again.
TEST_P(SpdyNetworkTransactionTest,SocketWriteReturnsZero)2149 TEST_P(SpdyNetworkTransactionTest, SocketWriteReturnsZero) {
2150 scoped_ptr<SpdyFrame> req(
2151 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
2152 scoped_ptr<SpdyFrame> rst(
2153 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL));
2154 MockWrite writes[] = {
2155 CreateMockWrite(*req.get(), 0, SYNCHRONOUS),
2156 MockWrite(SYNCHRONOUS, 0, 0, 2),
2157 CreateMockWrite(*rst.get(), 3, SYNCHRONOUS),
2158 };
2159
2160 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
2161 MockRead reads[] = {
2162 CreateMockRead(*resp.get(), 1, ASYNC),
2163 MockRead(ASYNC, 0, 0, 4) // EOF
2164 };
2165
2166 DeterministicSocketData data(reads, arraysize(reads),
2167 writes, arraysize(writes));
2168 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
2169 BoundNetLog(), GetParam(), NULL);
2170 helper.SetDeterministic();
2171 helper.RunPreTestSetup();
2172 helper.AddDeterministicData(&data);
2173 HttpNetworkTransaction* trans = helper.trans();
2174
2175 TestCompletionCallback callback;
2176 int rv = trans->Start(
2177 &CreateGetRequest(), callback.callback(), BoundNetLog());
2178 EXPECT_EQ(ERR_IO_PENDING, rv);
2179
2180 data.SetStop(2);
2181 data.Run();
2182 helper.ResetTrans();
2183 data.SetStop(20);
2184 data.Run();
2185
2186 helper.VerifyDataConsumed();
2187 }
2188
2189 // Test that the transaction doesn't crash when we don't have a reply.
TEST_P(SpdyNetworkTransactionTest,ResponseWithoutSynReply)2190 TEST_P(SpdyNetworkTransactionTest, ResponseWithoutSynReply) {
2191 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
2192 MockRead reads[] = {
2193 CreateMockRead(*body),
2194 MockRead(ASYNC, 0, 0) // EOF
2195 };
2196
2197 DelayedSocketData data(1, reads, arraysize(reads), NULL, 0);
2198 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
2199 BoundNetLog(), GetParam(), NULL);
2200 helper.RunToCompletion(&data);
2201 TransactionHelperResult out = helper.output();
2202 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, out.rv);
2203 }
2204
2205 // Test that the transaction doesn't crash when we get two replies on the same
2206 // stream ID. See http://crbug.com/45639.
TEST_P(SpdyNetworkTransactionTest,ResponseWithTwoSynReplies)2207 TEST_P(SpdyNetworkTransactionTest, ResponseWithTwoSynReplies) {
2208 scoped_ptr<SpdyFrame> req(
2209 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
2210 scoped_ptr<SpdyFrame> rst(
2211 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR));
2212 MockWrite writes[] = {
2213 CreateMockWrite(*req),
2214 CreateMockWrite(*rst),
2215 };
2216
2217 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
2218 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
2219 MockRead reads[] = {
2220 CreateMockRead(*resp),
2221 CreateMockRead(*resp),
2222 CreateMockRead(*body),
2223 MockRead(ASYNC, 0, 0) // EOF
2224 };
2225
2226 DelayedSocketData data(1, reads, arraysize(reads),
2227 writes, arraysize(writes));
2228
2229 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
2230 BoundNetLog(), GetParam(), NULL);
2231 helper.RunPreTestSetup();
2232 helper.AddData(&data);
2233
2234 HttpNetworkTransaction* trans = helper.trans();
2235
2236 TestCompletionCallback callback;
2237 int rv = trans->Start(&helper.request(), callback.callback(), BoundNetLog());
2238 EXPECT_EQ(ERR_IO_PENDING, rv);
2239 rv = callback.WaitForResult();
2240 EXPECT_EQ(OK, rv);
2241
2242 const HttpResponseInfo* response = trans->GetResponseInfo();
2243 ASSERT_TRUE(response != NULL);
2244 EXPECT_TRUE(response->headers.get() != NULL);
2245 EXPECT_TRUE(response->was_fetched_via_spdy);
2246 std::string response_data;
2247 rv = ReadTransaction(trans, &response_data);
2248 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, rv);
2249
2250 helper.VerifyDataConsumed();
2251 }
2252
TEST_P(SpdyNetworkTransactionTest,ResetReplyWithTransferEncoding)2253 TEST_P(SpdyNetworkTransactionTest, ResetReplyWithTransferEncoding) {
2254 // Construct the request.
2255 scoped_ptr<SpdyFrame> req(
2256 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
2257 scoped_ptr<SpdyFrame> rst(
2258 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR));
2259 MockWrite writes[] = {
2260 CreateMockWrite(*req),
2261 CreateMockWrite(*rst),
2262 };
2263
2264 const char* const headers[] = {
2265 "transfer-encoding", "chunked"
2266 };
2267 scoped_ptr<SpdyFrame> resp(
2268 spdy_util_.ConstructSpdyGetSynReply(headers, 1, 1));
2269 scoped_ptr<SpdyFrame> body(
2270 spdy_util_.ConstructSpdyBodyFrame(1, true));
2271 MockRead reads[] = {
2272 CreateMockRead(*resp),
2273 CreateMockRead(*body),
2274 MockRead(ASYNC, 0, 0) // EOF
2275 };
2276
2277 DelayedSocketData data(1, reads, arraysize(reads),
2278 writes, arraysize(writes));
2279 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
2280 BoundNetLog(), GetParam(), NULL);
2281 helper.RunToCompletion(&data);
2282 TransactionHelperResult out = helper.output();
2283 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, out.rv);
2284
2285 helper.session()->spdy_session_pool()->CloseAllSessions();
2286 helper.VerifyDataConsumed();
2287 }
2288
TEST_P(SpdyNetworkTransactionTest,ResetPushWithTransferEncoding)2289 TEST_P(SpdyNetworkTransactionTest, ResetPushWithTransferEncoding) {
2290 // Construct the request.
2291 scoped_ptr<SpdyFrame> req(
2292 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
2293 scoped_ptr<SpdyFrame> rst(
2294 spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR));
2295 MockWrite writes[] = {
2296 CreateMockWrite(*req),
2297 CreateMockWrite(*rst),
2298 };
2299
2300 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
2301 const char* const headers[] = {
2302 "transfer-encoding", "chunked"
2303 };
2304 scoped_ptr<SpdyFrame> push(
2305 spdy_util_.ConstructSpdyPush(headers, arraysize(headers) / 2,
2306 2, 1, "http://www.google.com/1"));
2307 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
2308 MockRead reads[] = {
2309 CreateMockRead(*resp),
2310 CreateMockRead(*push),
2311 CreateMockRead(*body),
2312 MockRead(ASYNC, 0, 0) // EOF
2313 };
2314
2315 DelayedSocketData data(1, reads, arraysize(reads),
2316 writes, arraysize(writes));
2317 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
2318 BoundNetLog(), GetParam(), NULL);
2319 helper.RunToCompletion(&data);
2320 TransactionHelperResult out = helper.output();
2321 EXPECT_EQ(OK, out.rv);
2322 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
2323 EXPECT_EQ("hello!", out.response_data);
2324
2325 helper.session()->spdy_session_pool()->CloseAllSessions();
2326 helper.VerifyDataConsumed();
2327 }
2328
TEST_P(SpdyNetworkTransactionTest,CancelledTransaction)2329 TEST_P(SpdyNetworkTransactionTest, CancelledTransaction) {
2330 // Construct the request.
2331 scoped_ptr<SpdyFrame> req(
2332 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
2333 MockWrite writes[] = {
2334 CreateMockWrite(*req),
2335 };
2336
2337 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
2338 MockRead reads[] = {
2339 CreateMockRead(*resp),
2340 // This following read isn't used by the test, except during the
2341 // RunUntilIdle() call at the end since the SpdySession survives the
2342 // HttpNetworkTransaction and still tries to continue Read()'ing. Any
2343 // MockRead will do here.
2344 MockRead(ASYNC, 0, 0) // EOF
2345 };
2346
2347 StaticSocketDataProvider data(reads, arraysize(reads),
2348 writes, arraysize(writes));
2349
2350 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
2351 BoundNetLog(), GetParam(), NULL);
2352 helper.RunPreTestSetup();
2353 helper.AddData(&data);
2354 HttpNetworkTransaction* trans = helper.trans();
2355
2356 TestCompletionCallback callback;
2357 int rv = trans->Start(
2358 &CreateGetRequest(), callback.callback(), BoundNetLog());
2359 EXPECT_EQ(ERR_IO_PENDING, rv);
2360 helper.ResetTrans(); // Cancel the transaction.
2361
2362 // Flush the MessageLoop while the SpdySessionDependencies (in particular, the
2363 // MockClientSocketFactory) are still alive.
2364 base::RunLoop().RunUntilIdle();
2365 helper.VerifyDataNotConsumed();
2366 }
2367
2368 // Verify that the client sends a Rst Frame upon cancelling the stream.
TEST_P(SpdyNetworkTransactionTest,CancelledTransactionSendRst)2369 TEST_P(SpdyNetworkTransactionTest, CancelledTransactionSendRst) {
2370 scoped_ptr<SpdyFrame> req(
2371 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
2372 scoped_ptr<SpdyFrame> rst(
2373 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL));
2374 MockWrite writes[] = {
2375 CreateMockWrite(*req, 0, SYNCHRONOUS),
2376 CreateMockWrite(*rst, 2, SYNCHRONOUS),
2377 };
2378
2379 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
2380 MockRead reads[] = {
2381 CreateMockRead(*resp, 1, ASYNC),
2382 MockRead(ASYNC, 0, 0, 3) // EOF
2383 };
2384
2385 DeterministicSocketData data(reads, arraysize(reads),
2386 writes, arraysize(writes));
2387
2388 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
2389 BoundNetLog(),
2390 GetParam(), NULL);
2391 helper.SetDeterministic();
2392 helper.RunPreTestSetup();
2393 helper.AddDeterministicData(&data);
2394 HttpNetworkTransaction* trans = helper.trans();
2395
2396 TestCompletionCallback callback;
2397
2398 int rv = trans->Start(
2399 &CreateGetRequest(), callback.callback(), BoundNetLog());
2400 EXPECT_EQ(ERR_IO_PENDING, rv);
2401
2402 data.SetStop(2);
2403 data.Run();
2404 helper.ResetTrans();
2405 data.SetStop(20);
2406 data.Run();
2407
2408 helper.VerifyDataConsumed();
2409 }
2410
2411 // Verify that the client can correctly deal with the user callback attempting
2412 // to start another transaction on a session that is closing down. See
2413 // http://crbug.com/47455
TEST_P(SpdyNetworkTransactionTest,StartTransactionOnReadCallback)2414 TEST_P(SpdyNetworkTransactionTest, StartTransactionOnReadCallback) {
2415 scoped_ptr<SpdyFrame> req(
2416 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
2417 MockWrite writes[] = { CreateMockWrite(*req) };
2418 MockWrite writes2[] = { CreateMockWrite(*req) };
2419
2420 // The indicated length of this frame is longer than its actual length. When
2421 // the session receives an empty frame after this one, it shuts down the
2422 // session, and calls the read callback with the incomplete data.
2423 const uint8 kGetBodyFrame2[] = {
2424 0x00, 0x00, 0x00, 0x01,
2425 0x01, 0x00, 0x00, 0x07,
2426 'h', 'e', 'l', 'l', 'o', '!',
2427 };
2428
2429 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
2430 MockRead reads[] = {
2431 CreateMockRead(*resp, 2),
2432 MockRead(ASYNC, ERR_IO_PENDING, 3), // Force a pause
2433 MockRead(ASYNC, reinterpret_cast<const char*>(kGetBodyFrame2),
2434 arraysize(kGetBodyFrame2), 4),
2435 MockRead(ASYNC, ERR_IO_PENDING, 5), // Force a pause
2436 MockRead(ASYNC, 0, 0, 6), // EOF
2437 };
2438 MockRead reads2[] = {
2439 CreateMockRead(*resp, 2),
2440 MockRead(ASYNC, 0, 0, 3), // EOF
2441 };
2442
2443 OrderedSocketData data(reads, arraysize(reads),
2444 writes, arraysize(writes));
2445 DelayedSocketData data2(1, reads2, arraysize(reads2),
2446 writes2, arraysize(writes2));
2447
2448 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
2449 BoundNetLog(), GetParam(), NULL);
2450 helper.RunPreTestSetup();
2451 helper.AddData(&data);
2452 helper.AddData(&data2);
2453 HttpNetworkTransaction* trans = helper.trans();
2454
2455 // Start the transaction with basic parameters.
2456 TestCompletionCallback callback;
2457 int rv = trans->Start(&helper.request(), callback.callback(), BoundNetLog());
2458 EXPECT_EQ(ERR_IO_PENDING, rv);
2459 rv = callback.WaitForResult();
2460
2461 const int kSize = 3000;
2462 scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(kSize));
2463 rv = trans->Read(
2464 buf.get(),
2465 kSize,
2466 base::Bind(&SpdyNetworkTransactionTest::StartTransactionCallback,
2467 helper.session()));
2468 // This forces an err_IO_pending, which sets the callback.
2469 data.CompleteRead();
2470 // This finishes the read.
2471 data.CompleteRead();
2472 helper.VerifyDataConsumed();
2473 }
2474
2475 // Verify that the client can correctly deal with the user callback deleting the
2476 // transaction. Failures will usually be valgrind errors. See
2477 // http://crbug.com/46925
TEST_P(SpdyNetworkTransactionTest,DeleteSessionOnReadCallback)2478 TEST_P(SpdyNetworkTransactionTest, DeleteSessionOnReadCallback) {
2479 scoped_ptr<SpdyFrame> req(
2480 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
2481 MockWrite writes[] = { CreateMockWrite(*req) };
2482
2483 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
2484 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
2485 MockRead reads[] = {
2486 CreateMockRead(*resp.get(), 2),
2487 MockRead(ASYNC, ERR_IO_PENDING, 3), // Force a pause
2488 CreateMockRead(*body.get(), 4),
2489 MockRead(ASYNC, 0, 0, 5), // EOF
2490 };
2491
2492 OrderedSocketData data(reads, arraysize(reads),
2493 writes, arraysize(writes));
2494
2495 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
2496 BoundNetLog(), GetParam(), NULL);
2497 helper.RunPreTestSetup();
2498 helper.AddData(&data);
2499 HttpNetworkTransaction* trans = helper.trans();
2500
2501 // Start the transaction with basic parameters.
2502 TestCompletionCallback callback;
2503 int rv = trans->Start(&helper.request(), callback.callback(), BoundNetLog());
2504 EXPECT_EQ(ERR_IO_PENDING, rv);
2505 rv = callback.WaitForResult();
2506
2507 // Setup a user callback which will delete the session, and clear out the
2508 // memory holding the stream object. Note that the callback deletes trans.
2509 const int kSize = 3000;
2510 scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(kSize));
2511 rv = trans->Read(
2512 buf.get(),
2513 kSize,
2514 base::Bind(&SpdyNetworkTransactionTest::DeleteSessionCallback,
2515 base::Unretained(&helper)));
2516 ASSERT_EQ(ERR_IO_PENDING, rv);
2517 data.CompleteRead();
2518
2519 // Finish running rest of tasks.
2520 base::RunLoop().RunUntilIdle();
2521 helper.VerifyDataConsumed();
2522 }
2523
2524 // Send a spdy request to www.google.com that gets redirected to www.foo.com.
TEST_P(SpdyNetworkTransactionTest,RedirectGetRequest)2525 TEST_P(SpdyNetworkTransactionTest, RedirectGetRequest) {
2526 const SpdyHeaderInfo kSynStartHeader = spdy_util_.MakeSpdyHeader(SYN_STREAM);
2527 scoped_ptr<SpdyHeaderBlock> headers(
2528 spdy_util_.ConstructGetHeaderBlock("http://www.google.com/"));
2529 (*headers)["user-agent"] = "";
2530 (*headers)["accept-encoding"] = "gzip,deflate";
2531 scoped_ptr<SpdyHeaderBlock> headers2(
2532 spdy_util_.ConstructGetHeaderBlock("http://www.foo.com/index.php"));
2533 (*headers2)["user-agent"] = "";
2534 (*headers2)["accept-encoding"] = "gzip,deflate";
2535
2536 // Setup writes/reads to www.google.com
2537 scoped_ptr<SpdyFrame> req(spdy_util_.ConstructSpdyFrame(
2538 kSynStartHeader, headers.Pass()));
2539 scoped_ptr<SpdyFrame> req2(spdy_util_.ConstructSpdyFrame(
2540 kSynStartHeader, headers2.Pass()));
2541 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReplyRedirect(1));
2542 MockWrite writes[] = {
2543 CreateMockWrite(*req, 1),
2544 };
2545 MockRead reads[] = {
2546 CreateMockRead(*resp, 2),
2547 MockRead(ASYNC, 0, 0, 3) // EOF
2548 };
2549
2550 // Setup writes/reads to www.foo.com
2551 scoped_ptr<SpdyFrame> resp2(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
2552 scoped_ptr<SpdyFrame> body2(spdy_util_.ConstructSpdyBodyFrame(1, true));
2553 MockWrite writes2[] = {
2554 CreateMockWrite(*req2, 1),
2555 };
2556 MockRead reads2[] = {
2557 CreateMockRead(*resp2, 2),
2558 CreateMockRead(*body2, 3),
2559 MockRead(ASYNC, 0, 0, 4) // EOF
2560 };
2561 OrderedSocketData data(reads, arraysize(reads),
2562 writes, arraysize(writes));
2563 OrderedSocketData data2(reads2, arraysize(reads2),
2564 writes2, arraysize(writes2));
2565
2566 // TODO(erikchen): Make test support SPDYSSL, SPDYNPN
2567 TestDelegate d;
2568 {
2569 SpdyURLRequestContext spdy_url_request_context(
2570 GetParam().protocol,
2571 false /* force_spdy_over_ssl*/,
2572 true /* force_spdy_always */);
2573 net::URLRequest r(GURL("http://www.google.com/"),
2574 DEFAULT_PRIORITY,
2575 &d,
2576 &spdy_url_request_context);
2577 spdy_url_request_context.socket_factory().
2578 AddSocketDataProvider(&data);
2579 spdy_url_request_context.socket_factory().
2580 AddSocketDataProvider(&data2);
2581
2582 d.set_quit_on_redirect(true);
2583 r.Start();
2584 base::RunLoop().Run();
2585
2586 EXPECT_EQ(1, d.received_redirect_count());
2587
2588 r.FollowDeferredRedirect();
2589 base::RunLoop().Run();
2590 EXPECT_EQ(1, d.response_started_count());
2591 EXPECT_FALSE(d.received_data_before_response());
2592 EXPECT_EQ(net::URLRequestStatus::SUCCESS, r.status().status());
2593 std::string contents("hello!");
2594 EXPECT_EQ(contents, d.data_received());
2595 }
2596 EXPECT_TRUE(data.at_read_eof());
2597 EXPECT_TRUE(data.at_write_eof());
2598 EXPECT_TRUE(data2.at_read_eof());
2599 EXPECT_TRUE(data2.at_write_eof());
2600 }
2601
2602 // Send a spdy request to www.google.com. Get a pushed stream that redirects to
2603 // www.foo.com.
TEST_P(SpdyNetworkTransactionTest,RedirectServerPush)2604 TEST_P(SpdyNetworkTransactionTest, RedirectServerPush) {
2605 const SpdyHeaderInfo kSynStartHeader = spdy_util_.MakeSpdyHeader(SYN_STREAM);
2606
2607 scoped_ptr<SpdyHeaderBlock> headers(
2608 spdy_util_.ConstructGetHeaderBlock("http://www.google.com/"));
2609 (*headers)["user-agent"] = "";
2610 (*headers)["accept-encoding"] = "gzip,deflate";
2611
2612 // Setup writes/reads to www.google.com
2613 scoped_ptr<SpdyFrame> req(
2614 spdy_util_.ConstructSpdyFrame(kSynStartHeader, headers.Pass()));
2615 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
2616 scoped_ptr<SpdyFrame> rep(
2617 spdy_util_.ConstructSpdyPush(NULL,
2618 0,
2619 2,
2620 1,
2621 "http://www.google.com/foo.dat",
2622 "301 Moved Permanently",
2623 "http://www.foo.com/index.php"));
2624 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
2625 scoped_ptr<SpdyFrame> rst(
2626 spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_CANCEL));
2627 MockWrite writes[] = {
2628 CreateMockWrite(*req, 1),
2629 CreateMockWrite(*rst, 6),
2630 };
2631 MockRead reads[] = {
2632 CreateMockRead(*resp, 2),
2633 CreateMockRead(*rep, 3),
2634 CreateMockRead(*body, 4),
2635 MockRead(ASYNC, ERR_IO_PENDING, 5), // Force a pause
2636 MockRead(ASYNC, 0, 0, 7) // EOF
2637 };
2638
2639 // Setup writes/reads to www.foo.com
2640 scoped_ptr<SpdyHeaderBlock> headers2(
2641 spdy_util_.ConstructGetHeaderBlock("http://www.foo.com/index.php"));
2642 (*headers2)["user-agent"] = "";
2643 (*headers2)["accept-encoding"] = "gzip,deflate";
2644 scoped_ptr<SpdyFrame> req2(
2645 spdy_util_.ConstructSpdyFrame(kSynStartHeader, headers2.Pass()));
2646 scoped_ptr<SpdyFrame> resp2(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
2647 scoped_ptr<SpdyFrame> body2(spdy_util_.ConstructSpdyBodyFrame(1, true));
2648 MockWrite writes2[] = {
2649 CreateMockWrite(*req2, 1),
2650 };
2651 MockRead reads2[] = {
2652 CreateMockRead(*resp2, 2),
2653 CreateMockRead(*body2, 3),
2654 MockRead(ASYNC, 0, 0, 5) // EOF
2655 };
2656 OrderedSocketData data(reads, arraysize(reads),
2657 writes, arraysize(writes));
2658 OrderedSocketData data2(reads2, arraysize(reads2),
2659 writes2, arraysize(writes2));
2660
2661 // TODO(erikchen): Make test support SPDYSSL, SPDYNPN
2662 TestDelegate d;
2663 TestDelegate d2;
2664 SpdyURLRequestContext spdy_url_request_context(
2665 GetParam().protocol,
2666 false /* force_spdy_over_ssl*/,
2667 true /* force_spdy_always */);
2668 {
2669 net::URLRequest r(GURL("http://www.google.com/"),
2670 DEFAULT_PRIORITY,
2671 &d,
2672 &spdy_url_request_context);
2673 spdy_url_request_context.socket_factory().
2674 AddSocketDataProvider(&data);
2675
2676 r.Start();
2677 base::RunLoop().Run();
2678
2679 EXPECT_EQ(0, d.received_redirect_count());
2680 std::string contents("hello!");
2681 EXPECT_EQ(contents, d.data_received());
2682
2683 net::URLRequest r2(GURL("http://www.google.com/foo.dat"),
2684 DEFAULT_PRIORITY,
2685 &d2,
2686 &spdy_url_request_context);
2687 spdy_url_request_context.socket_factory().
2688 AddSocketDataProvider(&data2);
2689
2690 d2.set_quit_on_redirect(true);
2691 r2.Start();
2692 base::RunLoop().Run();
2693 EXPECT_EQ(1, d2.received_redirect_count());
2694
2695 r2.FollowDeferredRedirect();
2696 base::RunLoop().Run();
2697 EXPECT_EQ(1, d2.response_started_count());
2698 EXPECT_FALSE(d2.received_data_before_response());
2699 EXPECT_EQ(net::URLRequestStatus::SUCCESS, r2.status().status());
2700 std::string contents2("hello!");
2701 EXPECT_EQ(contents2, d2.data_received());
2702 }
2703 data.CompleteRead();
2704 data2.CompleteRead();
2705 EXPECT_TRUE(data.at_read_eof());
2706 EXPECT_TRUE(data.at_write_eof());
2707 EXPECT_TRUE(data2.at_read_eof());
2708 EXPECT_TRUE(data2.at_write_eof());
2709 }
2710
TEST_P(SpdyNetworkTransactionTest,ServerPushSingleDataFrame)2711 TEST_P(SpdyNetworkTransactionTest, ServerPushSingleDataFrame) {
2712 scoped_ptr<SpdyFrame> stream1_syn(
2713 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
2714 scoped_ptr<SpdyFrame> stream1_body(
2715 spdy_util_.ConstructSpdyBodyFrame(1, true));
2716 MockWrite writes[] = {
2717 CreateMockWrite(*stream1_syn, 1),
2718 };
2719
2720 scoped_ptr<SpdyFrame>
2721 stream1_reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
2722 scoped_ptr<SpdyFrame>
2723 stream2_syn(spdy_util_.ConstructSpdyPush(NULL,
2724 0,
2725 2,
2726 1,
2727 "http://www.google.com/foo.dat"));
2728 const char kPushedData[] = "pushed";
2729 scoped_ptr<SpdyFrame> stream2_body(
2730 spdy_util_.ConstructSpdyBodyFrame(
2731 2, kPushedData, strlen(kPushedData), true));
2732 MockRead reads[] = {
2733 CreateMockRead(*stream1_reply, 2),
2734 CreateMockRead(*stream2_syn, 3),
2735 CreateMockRead(*stream1_body, 4, SYNCHRONOUS),
2736 CreateMockRead(*stream2_body, 5),
2737 MockRead(ASYNC, ERR_IO_PENDING, 6), // Force a pause
2738 };
2739
2740 HttpResponseInfo response;
2741 HttpResponseInfo response2;
2742 std::string expected_push_result("pushed");
2743 OrderedSocketData data(reads, arraysize(reads),
2744 writes, arraysize(writes));
2745 RunServerPushTest(&data,
2746 &response,
2747 &response2,
2748 expected_push_result);
2749
2750 // Verify the SYN_REPLY.
2751 EXPECT_TRUE(response.headers.get() != NULL);
2752 EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine());
2753
2754 // Verify the pushed stream.
2755 EXPECT_TRUE(response2.headers.get() != NULL);
2756 EXPECT_EQ("HTTP/1.1 200 OK", response2.headers->GetStatusLine());
2757 }
2758
TEST_P(SpdyNetworkTransactionTest,ServerPushBeforeSynReply)2759 TEST_P(SpdyNetworkTransactionTest, ServerPushBeforeSynReply) {
2760 scoped_ptr<SpdyFrame> stream1_syn(
2761 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
2762 scoped_ptr<SpdyFrame> stream1_body(
2763 spdy_util_.ConstructSpdyBodyFrame(1, true));
2764 MockWrite writes[] = {
2765 CreateMockWrite(*stream1_syn, 1),
2766 };
2767
2768 scoped_ptr<SpdyFrame>
2769 stream1_reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
2770 scoped_ptr<SpdyFrame>
2771 stream2_syn(spdy_util_.ConstructSpdyPush(NULL,
2772 0,
2773 2,
2774 1,
2775 "http://www.google.com/foo.dat"));
2776 const char kPushedData[] = "pushed";
2777 scoped_ptr<SpdyFrame> stream2_body(
2778 spdy_util_.ConstructSpdyBodyFrame(
2779 2, kPushedData, strlen(kPushedData), true));
2780 MockRead reads[] = {
2781 CreateMockRead(*stream2_syn, 2),
2782 CreateMockRead(*stream1_reply, 3),
2783 CreateMockRead(*stream1_body, 4, SYNCHRONOUS),
2784 CreateMockRead(*stream2_body, 5),
2785 MockRead(ASYNC, ERR_IO_PENDING, 6), // Force a pause
2786 };
2787
2788 HttpResponseInfo response;
2789 HttpResponseInfo response2;
2790 std::string expected_push_result("pushed");
2791 OrderedSocketData data(reads, arraysize(reads),
2792 writes, arraysize(writes));
2793 RunServerPushTest(&data,
2794 &response,
2795 &response2,
2796 expected_push_result);
2797
2798 // Verify the SYN_REPLY.
2799 EXPECT_TRUE(response.headers.get() != NULL);
2800 EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine());
2801
2802 // Verify the pushed stream.
2803 EXPECT_TRUE(response2.headers.get() != NULL);
2804 EXPECT_EQ("HTTP/1.1 200 OK", response2.headers->GetStatusLine());
2805 }
2806
TEST_P(SpdyNetworkTransactionTest,ServerPushSingleDataFrame2)2807 TEST_P(SpdyNetworkTransactionTest, ServerPushSingleDataFrame2) {
2808 scoped_ptr<SpdyFrame> stream1_syn(
2809 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
2810 MockWrite writes[] = { CreateMockWrite(*stream1_syn, 1), };
2811
2812 scoped_ptr<SpdyFrame>
2813 stream1_reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
2814 scoped_ptr<SpdyFrame>
2815 stream2_syn(spdy_util_.ConstructSpdyPush(NULL,
2816 0,
2817 2,
2818 1,
2819 "http://www.google.com/foo.dat"));
2820 const char kPushedData[] = "pushed";
2821 scoped_ptr<SpdyFrame> stream2_body(
2822 spdy_util_.ConstructSpdyBodyFrame(
2823 2, kPushedData, strlen(kPushedData), true));
2824 scoped_ptr<SpdyFrame>
2825 stream1_body(spdy_util_.ConstructSpdyBodyFrame(1, true));
2826 MockRead reads[] = {
2827 CreateMockRead(*stream1_reply, 2),
2828 CreateMockRead(*stream2_syn, 3),
2829 CreateMockRead(*stream2_body, 4),
2830 CreateMockRead(*stream1_body, 5, SYNCHRONOUS),
2831 MockRead(ASYNC, ERR_IO_PENDING, 6), // Force a pause
2832 };
2833
2834 HttpResponseInfo response;
2835 HttpResponseInfo response2;
2836 std::string expected_push_result("pushed");
2837 OrderedSocketData data(reads, arraysize(reads),
2838 writes, arraysize(writes));
2839 RunServerPushTest(&data,
2840 &response,
2841 &response2,
2842 expected_push_result);
2843
2844 // Verify the SYN_REPLY.
2845 EXPECT_TRUE(response.headers.get() != NULL);
2846 EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine());
2847
2848 // Verify the pushed stream.
2849 EXPECT_TRUE(response2.headers.get() != NULL);
2850 EXPECT_EQ("HTTP/1.1 200 OK", response2.headers->GetStatusLine());
2851 }
2852
TEST_P(SpdyNetworkTransactionTest,ServerPushServerAborted)2853 TEST_P(SpdyNetworkTransactionTest, ServerPushServerAborted) {
2854 scoped_ptr<SpdyFrame> stream1_syn(
2855 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
2856 scoped_ptr<SpdyFrame> stream1_body(
2857 spdy_util_.ConstructSpdyBodyFrame(1, true));
2858 MockWrite writes[] = {
2859 CreateMockWrite(*stream1_syn, 1),
2860 };
2861
2862 scoped_ptr<SpdyFrame>
2863 stream1_reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
2864 scoped_ptr<SpdyFrame>
2865 stream2_syn(spdy_util_.ConstructSpdyPush(NULL,
2866 0,
2867 2,
2868 1,
2869 "http://www.google.com/foo.dat"));
2870 scoped_ptr<SpdyFrame> stream2_rst(
2871 spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR));
2872 MockRead reads[] = {
2873 CreateMockRead(*stream1_reply, 2),
2874 CreateMockRead(*stream2_syn, 3),
2875 CreateMockRead(*stream2_rst, 4),
2876 CreateMockRead(*stream1_body, 5, SYNCHRONOUS),
2877 MockRead(ASYNC, ERR_IO_PENDING, 6), // Force a pause
2878 };
2879
2880 OrderedSocketData data(reads, arraysize(reads),
2881 writes, arraysize(writes));
2882 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
2883 BoundNetLog(), GetParam(), NULL);
2884
2885 helper.RunPreTestSetup();
2886 helper.AddData(&data);
2887
2888 HttpNetworkTransaction* trans = helper.trans();
2889
2890 // Start the transaction with basic parameters.
2891 TestCompletionCallback callback;
2892 int rv = trans->Start(
2893 &CreateGetRequest(), callback.callback(), BoundNetLog());
2894 EXPECT_EQ(ERR_IO_PENDING, rv);
2895 rv = callback.WaitForResult();
2896 EXPECT_EQ(OK, rv);
2897
2898 // Verify that we consumed all test data.
2899 EXPECT_TRUE(data.at_read_eof()) << "Read count: "
2900 << data.read_count()
2901 << " Read index: "
2902 << data.read_index();
2903 EXPECT_TRUE(data.at_write_eof()) << "Write count: "
2904 << data.write_count()
2905 << " Write index: "
2906 << data.write_index();
2907
2908 // Verify the SYN_REPLY.
2909 HttpResponseInfo response = *trans->GetResponseInfo();
2910 EXPECT_TRUE(response.headers.get() != NULL);
2911 EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine());
2912 }
2913
2914 // Verify that we don't leak streams and that we properly send a reset
2915 // if the server pushes the same stream twice.
TEST_P(SpdyNetworkTransactionTest,ServerPushDuplicate)2916 TEST_P(SpdyNetworkTransactionTest, ServerPushDuplicate) {
2917 scoped_ptr<SpdyFrame> stream1_syn(
2918 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
2919 scoped_ptr<SpdyFrame> stream1_body(
2920 spdy_util_.ConstructSpdyBodyFrame(1, true));
2921 scoped_ptr<SpdyFrame> stream3_rst(
2922 spdy_util_.ConstructSpdyRstStream(4, RST_STREAM_PROTOCOL_ERROR));
2923 MockWrite writes[] = {
2924 CreateMockWrite(*stream1_syn, 1),
2925 CreateMockWrite(*stream3_rst, 5),
2926 };
2927
2928 scoped_ptr<SpdyFrame>
2929 stream1_reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
2930 scoped_ptr<SpdyFrame>
2931 stream2_syn(spdy_util_.ConstructSpdyPush(NULL,
2932 0,
2933 2,
2934 1,
2935 "http://www.google.com/foo.dat"));
2936 const char kPushedData[] = "pushed";
2937 scoped_ptr<SpdyFrame> stream2_body(
2938 spdy_util_.ConstructSpdyBodyFrame(
2939 2, kPushedData, strlen(kPushedData), true));
2940 scoped_ptr<SpdyFrame>
2941 stream3_syn(spdy_util_.ConstructSpdyPush(NULL,
2942 0,
2943 4,
2944 1,
2945 "http://www.google.com/foo.dat"));
2946 MockRead reads[] = {
2947 CreateMockRead(*stream1_reply, 2),
2948 CreateMockRead(*stream2_syn, 3),
2949 CreateMockRead(*stream3_syn, 4),
2950 CreateMockRead(*stream1_body, 6, SYNCHRONOUS),
2951 CreateMockRead(*stream2_body, 7),
2952 MockRead(ASYNC, ERR_IO_PENDING, 8), // Force a pause
2953 };
2954
2955 HttpResponseInfo response;
2956 HttpResponseInfo response2;
2957 std::string expected_push_result("pushed");
2958 OrderedSocketData data(reads, arraysize(reads),
2959 writes, arraysize(writes));
2960 RunServerPushTest(&data,
2961 &response,
2962 &response2,
2963 expected_push_result);
2964
2965 // Verify the SYN_REPLY.
2966 EXPECT_TRUE(response.headers.get() != NULL);
2967 EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine());
2968
2969 // Verify the pushed stream.
2970 EXPECT_TRUE(response2.headers.get() != NULL);
2971 EXPECT_EQ("HTTP/1.1 200 OK", response2.headers->GetStatusLine());
2972 }
2973
TEST_P(SpdyNetworkTransactionTest,ServerPushMultipleDataFrame)2974 TEST_P(SpdyNetworkTransactionTest, ServerPushMultipleDataFrame) {
2975 scoped_ptr<SpdyFrame> stream1_syn(
2976 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
2977 scoped_ptr<SpdyFrame> stream1_body(
2978 spdy_util_.ConstructSpdyBodyFrame(1, true));
2979 MockWrite writes[] = {
2980 CreateMockWrite(*stream1_syn, 1),
2981 };
2982
2983 scoped_ptr<SpdyFrame>
2984 stream1_reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
2985 scoped_ptr<SpdyFrame>
2986 stream2_syn(spdy_util_.ConstructSpdyPush(NULL,
2987 0,
2988 2,
2989 1,
2990 "http://www.google.com/foo.dat"));
2991 static const char kPushedData[] = "pushed my darling hello my baby";
2992 scoped_ptr<SpdyFrame> stream2_body_base(
2993 spdy_util_.ConstructSpdyBodyFrame(
2994 2, kPushedData, strlen(kPushedData), true));
2995 const size_t kChunkSize = strlen(kPushedData) / 4;
2996 scoped_ptr<SpdyFrame> stream2_body1(
2997 new SpdyFrame(stream2_body_base->data(), kChunkSize, false));
2998 scoped_ptr<SpdyFrame> stream2_body2(
2999 new SpdyFrame(stream2_body_base->data() + kChunkSize, kChunkSize, false));
3000 scoped_ptr<SpdyFrame> stream2_body3(
3001 new SpdyFrame(stream2_body_base->data() + 2 * kChunkSize,
3002 kChunkSize, false));
3003 scoped_ptr<SpdyFrame> stream2_body4(
3004 new SpdyFrame(stream2_body_base->data() + 3 * kChunkSize,
3005 stream2_body_base->size() - 3 * kChunkSize, false));
3006 MockRead reads[] = {
3007 CreateMockRead(*stream1_reply, 2),
3008 CreateMockRead(*stream2_syn, 3),
3009 CreateMockRead(*stream2_body1, 4),
3010 CreateMockRead(*stream2_body2, 5),
3011 CreateMockRead(*stream2_body3, 6),
3012 CreateMockRead(*stream2_body4, 7),
3013 CreateMockRead(*stream1_body, 8, SYNCHRONOUS),
3014 MockRead(ASYNC, ERR_IO_PENDING, 9), // Force a pause
3015 };
3016
3017 HttpResponseInfo response;
3018 HttpResponseInfo response2;
3019 std::string expected_push_result("pushed my darling hello my baby");
3020 OrderedSocketData data(reads, arraysize(reads),
3021 writes, arraysize(writes));
3022 RunServerPushTest(&data, &response, &response2, kPushedData);
3023
3024 // Verify the SYN_REPLY.
3025 EXPECT_TRUE(response.headers.get() != NULL);
3026 EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine());
3027
3028 // Verify the pushed stream.
3029 EXPECT_TRUE(response2.headers.get() != NULL);
3030 EXPECT_EQ("HTTP/1.1 200 OK", response2.headers->GetStatusLine());
3031 }
3032
TEST_P(SpdyNetworkTransactionTest,ServerPushMultipleDataFrameInterrupted)3033 TEST_P(SpdyNetworkTransactionTest, ServerPushMultipleDataFrameInterrupted) {
3034 scoped_ptr<SpdyFrame> stream1_syn(
3035 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
3036 scoped_ptr<SpdyFrame> stream1_body(
3037 spdy_util_.ConstructSpdyBodyFrame(1, true));
3038 MockWrite writes[] = {
3039 CreateMockWrite(*stream1_syn, 1),
3040 };
3041
3042 scoped_ptr<SpdyFrame>
3043 stream1_reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
3044 scoped_ptr<SpdyFrame>
3045 stream2_syn(spdy_util_.ConstructSpdyPush(NULL,
3046 0,
3047 2,
3048 1,
3049 "http://www.google.com/foo.dat"));
3050 static const char kPushedData[] = "pushed my darling hello my baby";
3051 scoped_ptr<SpdyFrame> stream2_body_base(
3052 spdy_util_.ConstructSpdyBodyFrame(
3053 2, kPushedData, strlen(kPushedData), true));
3054 const size_t kChunkSize = strlen(kPushedData) / 4;
3055 scoped_ptr<SpdyFrame> stream2_body1(
3056 new SpdyFrame(stream2_body_base->data(), kChunkSize, false));
3057 scoped_ptr<SpdyFrame> stream2_body2(
3058 new SpdyFrame(stream2_body_base->data() + kChunkSize, kChunkSize, false));
3059 scoped_ptr<SpdyFrame> stream2_body3(
3060 new SpdyFrame(stream2_body_base->data() + 2 * kChunkSize,
3061 kChunkSize, false));
3062 scoped_ptr<SpdyFrame> stream2_body4(
3063 new SpdyFrame(stream2_body_base->data() + 3 * kChunkSize,
3064 stream2_body_base->size() - 3 * kChunkSize, false));
3065 MockRead reads[] = {
3066 CreateMockRead(*stream1_reply, 2),
3067 CreateMockRead(*stream2_syn, 3),
3068 CreateMockRead(*stream2_body1, 4),
3069 CreateMockRead(*stream2_body2, 5),
3070 MockRead(ASYNC, ERR_IO_PENDING, 6), // Force a pause
3071 CreateMockRead(*stream2_body3, 7),
3072 CreateMockRead(*stream2_body4, 8),
3073 CreateMockRead(*stream1_body.get(), 9, SYNCHRONOUS),
3074 MockRead(ASYNC, ERR_IO_PENDING, 10) // Force a pause.
3075 };
3076
3077 HttpResponseInfo response;
3078 HttpResponseInfo response2;
3079 OrderedSocketData data(reads, arraysize(reads),
3080 writes, arraysize(writes));
3081 RunServerPushTest(&data, &response, &response2, kPushedData);
3082
3083 // Verify the SYN_REPLY.
3084 EXPECT_TRUE(response.headers.get() != NULL);
3085 EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine());
3086
3087 // Verify the pushed stream.
3088 EXPECT_TRUE(response2.headers.get() != NULL);
3089 EXPECT_EQ("HTTP/1.1 200 OK", response2.headers->GetStatusLine());
3090 }
3091
TEST_P(SpdyNetworkTransactionTest,ServerPushInvalidAssociatedStreamID0)3092 TEST_P(SpdyNetworkTransactionTest, ServerPushInvalidAssociatedStreamID0) {
3093 if (spdy_util_.spdy_version() == SPDY4) {
3094 // PUSH_PROMISE with stream id 0 is connection-level error.
3095 // TODO(baranovich): Test session going away.
3096 return;
3097 }
3098
3099 scoped_ptr<SpdyFrame> stream1_syn(
3100 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
3101 scoped_ptr<SpdyFrame> stream1_body(
3102 spdy_util_.ConstructSpdyBodyFrame(1, true));
3103 scoped_ptr<SpdyFrame> stream2_rst(
3104 spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_REFUSED_STREAM));
3105 MockWrite writes[] = {
3106 CreateMockWrite(*stream1_syn, 1),
3107 CreateMockWrite(*stream2_rst, 4),
3108 };
3109
3110 scoped_ptr<SpdyFrame>
3111 stream1_reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
3112 scoped_ptr<SpdyFrame>
3113 stream2_syn(spdy_util_.ConstructSpdyPush(NULL,
3114 0,
3115 2,
3116 0,
3117 "http://www.google.com/foo.dat"));
3118 MockRead reads[] = {
3119 CreateMockRead(*stream1_reply, 2),
3120 CreateMockRead(*stream2_syn, 3),
3121 CreateMockRead(*stream1_body, 4),
3122 MockRead(ASYNC, ERR_IO_PENDING, 5) // Force a pause
3123 };
3124
3125 OrderedSocketData data(reads, arraysize(reads),
3126 writes, arraysize(writes));
3127 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
3128 BoundNetLog(), GetParam(), NULL);
3129
3130 helper.RunPreTestSetup();
3131 helper.AddData(&data);
3132
3133 HttpNetworkTransaction* trans = helper.trans();
3134
3135 // Start the transaction with basic parameters.
3136 TestCompletionCallback callback;
3137 int rv = trans->Start(
3138 &CreateGetRequest(), callback.callback(), BoundNetLog());
3139 EXPECT_EQ(ERR_IO_PENDING, rv);
3140 rv = callback.WaitForResult();
3141 EXPECT_EQ(OK, rv);
3142
3143 // Verify that we consumed all test data.
3144 EXPECT_TRUE(data.at_read_eof()) << "Read count: "
3145 << data.read_count()
3146 << " Read index: "
3147 << data.read_index();
3148 EXPECT_TRUE(data.at_write_eof()) << "Write count: "
3149 << data.write_count()
3150 << " Write index: "
3151 << data.write_index();
3152
3153 // Verify the SYN_REPLY.
3154 HttpResponseInfo response = *trans->GetResponseInfo();
3155 EXPECT_TRUE(response.headers.get() != NULL);
3156 EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine());
3157 }
3158
TEST_P(SpdyNetworkTransactionTest,ServerPushInvalidAssociatedStreamID9)3159 TEST_P(SpdyNetworkTransactionTest, ServerPushInvalidAssociatedStreamID9) {
3160 scoped_ptr<SpdyFrame> stream1_syn(
3161 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
3162 scoped_ptr<SpdyFrame> stream1_body(
3163 spdy_util_.ConstructSpdyBodyFrame(1, true));
3164 scoped_ptr<SpdyFrame> stream2_rst(
3165 spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_INVALID_STREAM));
3166 MockWrite writes[] = {
3167 CreateMockWrite(*stream1_syn, 1),
3168 CreateMockWrite(*stream2_rst, 4),
3169 };
3170
3171 scoped_ptr<SpdyFrame>
3172 stream1_reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
3173 scoped_ptr<SpdyFrame>
3174 stream2_syn(spdy_util_.ConstructSpdyPush(NULL,
3175 0,
3176 2,
3177 9,
3178 "http://www.google.com/foo.dat"));
3179 MockRead reads[] = {
3180 CreateMockRead(*stream1_reply, 2),
3181 CreateMockRead(*stream2_syn, 3),
3182 CreateMockRead(*stream1_body, 4),
3183 MockRead(ASYNC, ERR_IO_PENDING, 5), // Force a pause
3184 };
3185
3186 OrderedSocketData data(reads, arraysize(reads),
3187 writes, arraysize(writes));
3188 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
3189 BoundNetLog(), GetParam(), NULL);
3190
3191 helper.RunPreTestSetup();
3192 helper.AddData(&data);
3193
3194 HttpNetworkTransaction* trans = helper.trans();
3195
3196 // Start the transaction with basic parameters.
3197 TestCompletionCallback callback;
3198 int rv = trans->Start(
3199 &CreateGetRequest(), callback.callback(), BoundNetLog());
3200 EXPECT_EQ(ERR_IO_PENDING, rv);
3201 rv = callback.WaitForResult();
3202 EXPECT_EQ(OK, rv);
3203
3204 // Verify that we consumed all test data.
3205 EXPECT_TRUE(data.at_read_eof()) << "Read count: "
3206 << data.read_count()
3207 << " Read index: "
3208 << data.read_index();
3209 EXPECT_TRUE(data.at_write_eof()) << "Write count: "
3210 << data.write_count()
3211 << " Write index: "
3212 << data.write_index();
3213
3214 // Verify the SYN_REPLY.
3215 HttpResponseInfo response = *trans->GetResponseInfo();
3216 EXPECT_TRUE(response.headers.get() != NULL);
3217 EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine());
3218 }
3219
TEST_P(SpdyNetworkTransactionTest,ServerPushNoURL)3220 TEST_P(SpdyNetworkTransactionTest, ServerPushNoURL) {
3221 scoped_ptr<SpdyFrame> stream1_syn(
3222 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
3223 scoped_ptr<SpdyFrame> stream1_body(
3224 spdy_util_.ConstructSpdyBodyFrame(1, true));
3225 scoped_ptr<SpdyFrame> stream2_rst(
3226 spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR));
3227 MockWrite writes[] = {
3228 CreateMockWrite(*stream1_syn, 1),
3229 CreateMockWrite(*stream2_rst, 4),
3230 };
3231
3232 scoped_ptr<SpdyFrame>
3233 stream1_reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
3234 scoped_ptr<SpdyHeaderBlock> incomplete_headers(new SpdyHeaderBlock());
3235 (*incomplete_headers)["hello"] = "bye";
3236 (*incomplete_headers)[spdy_util_.GetStatusKey()] = "200 OK";
3237 (*incomplete_headers)[spdy_util_.GetVersionKey()] = "HTTP/1.1";
3238 scoped_ptr<SpdyFrame> stream2_syn(spdy_util_.ConstructInitialSpdyPushFrame(
3239 incomplete_headers.Pass(), 2, 1));
3240 MockRead reads[] = {
3241 CreateMockRead(*stream1_reply, 2),
3242 CreateMockRead(*stream2_syn, 3),
3243 CreateMockRead(*stream1_body, 4),
3244 MockRead(ASYNC, ERR_IO_PENDING, 5) // Force a pause
3245 };
3246
3247 OrderedSocketData data(reads, arraysize(reads),
3248 writes, arraysize(writes));
3249 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
3250 BoundNetLog(), GetParam(), NULL);
3251
3252 helper.RunPreTestSetup();
3253 helper.AddData(&data);
3254
3255 HttpNetworkTransaction* trans = helper.trans();
3256
3257 // Start the transaction with basic parameters.
3258 TestCompletionCallback callback;
3259 int rv = trans->Start(
3260 &CreateGetRequest(), callback.callback(), BoundNetLog());
3261 EXPECT_EQ(ERR_IO_PENDING, rv);
3262 rv = callback.WaitForResult();
3263 EXPECT_EQ(OK, rv);
3264 // Verify that we consumed all test data.
3265 EXPECT_TRUE(data.at_read_eof()) << "Read count: "
3266 << data.read_count()
3267 << " Read index: "
3268 << data.read_index();
3269 EXPECT_TRUE(data.at_write_eof()) << "Write count: "
3270 << data.write_count()
3271 << " Write index: "
3272 << data.write_index();
3273
3274 // Verify the SYN_REPLY.
3275 HttpResponseInfo response = *trans->GetResponseInfo();
3276 EXPECT_TRUE(response.headers.get() != NULL);
3277 EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine());
3278 }
3279
3280 // Verify that various SynReply headers parse correctly through the
3281 // HTTP layer.
TEST_P(SpdyNetworkTransactionTest,SynReplyHeaders)3282 TEST_P(SpdyNetworkTransactionTest, SynReplyHeaders) {
3283 struct SynReplyHeadersTests {
3284 int num_headers;
3285 const char* extra_headers[5];
3286 SpdyHeaderBlock expected_headers;
3287 } test_cases[] = {
3288 // This uses a multi-valued cookie header.
3289 { 2,
3290 { "cookie", "val1",
3291 "cookie", "val2", // will get appended separated by NULL
3292 NULL
3293 },
3294 },
3295 // This is the minimalist set of headers.
3296 { 0,
3297 { NULL },
3298 },
3299 // Headers with a comma separated list.
3300 { 1,
3301 { "cookie", "val1,val2",
3302 NULL
3303 },
3304 }
3305 };
3306
3307 test_cases[0].expected_headers["cookie"] = "val1";
3308 test_cases[0].expected_headers["cookie"] += '\0';
3309 test_cases[0].expected_headers["cookie"] += "val2";
3310 test_cases[0].expected_headers["hello"] = "bye";
3311 test_cases[0].expected_headers["status"] = "200";
3312
3313 test_cases[1].expected_headers["hello"] = "bye";
3314 test_cases[1].expected_headers["status"] = "200";
3315
3316 test_cases[2].expected_headers["cookie"] = "val1,val2";
3317 test_cases[2].expected_headers["hello"] = "bye";
3318 test_cases[2].expected_headers["status"] = "200";
3319
3320 if (spdy_util_.spdy_version() < SPDY4) {
3321 // SPDY4/HTTP2 eliminates use of the :version header.
3322 test_cases[0].expected_headers["version"] = "HTTP/1.1";
3323 test_cases[1].expected_headers["version"] = "HTTP/1.1";
3324 test_cases[2].expected_headers["version"] = "HTTP/1.1";
3325 }
3326
3327 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) {
3328 scoped_ptr<SpdyFrame> req(
3329 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
3330 MockWrite writes[] = { CreateMockWrite(*req) };
3331
3332 scoped_ptr<SpdyFrame> resp(
3333 spdy_util_.ConstructSpdyGetSynReply(test_cases[i].extra_headers,
3334 test_cases[i].num_headers,
3335 1));
3336 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
3337 MockRead reads[] = {
3338 CreateMockRead(*resp),
3339 CreateMockRead(*body),
3340 MockRead(ASYNC, 0, 0) // EOF
3341 };
3342
3343 DelayedSocketData data(1, reads, arraysize(reads),
3344 writes, arraysize(writes));
3345 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
3346 BoundNetLog(), GetParam(), NULL);
3347 helper.RunToCompletion(&data);
3348 TransactionHelperResult out = helper.output();
3349
3350 EXPECT_EQ(OK, out.rv);
3351 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
3352 EXPECT_EQ("hello!", out.response_data);
3353
3354 scoped_refptr<HttpResponseHeaders> headers = out.response_info.headers;
3355 EXPECT_TRUE(headers.get() != NULL);
3356 void* iter = NULL;
3357 std::string name, value;
3358 SpdyHeaderBlock header_block;
3359 while (headers->EnumerateHeaderLines(&iter, &name, &value)) {
3360 if (header_block[name].empty()) {
3361 header_block[name] = value;
3362 } else {
3363 header_block[name] += '\0';
3364 header_block[name] += value;
3365 }
3366 }
3367 EXPECT_EQ(test_cases[i].expected_headers, header_block);
3368 }
3369 }
3370
3371 // Verify that various SynReply headers parse vary fields correctly
3372 // through the HTTP layer, and the response matches the request.
TEST_P(SpdyNetworkTransactionTest,SynReplyHeadersVary)3373 TEST_P(SpdyNetworkTransactionTest, SynReplyHeadersVary) {
3374 static const SpdyHeaderInfo syn_reply_info = {
3375 SYN_REPLY, // Syn Reply
3376 1, // Stream ID
3377 0, // Associated Stream ID
3378 ConvertRequestPriorityToSpdyPriority(
3379 LOWEST, spdy_util_.spdy_version()),
3380 kSpdyCredentialSlotUnused,
3381 CONTROL_FLAG_NONE, // Control Flags
3382 false, // Compressed
3383 RST_STREAM_INVALID, // Status
3384 NULL, // Data
3385 0, // Data Length
3386 DATA_FLAG_NONE // Data Flags
3387 };
3388 // Modify the following data to change/add test cases:
3389 struct SynReplyTests {
3390 const SpdyHeaderInfo* syn_reply;
3391 bool vary_matches;
3392 int num_headers[2];
3393 const char* extra_headers[2][16];
3394 } test_cases[] = {
3395 // Test the case of a multi-valued cookie. When the value is delimited
3396 // with NUL characters, it needs to be unfolded into multiple headers.
3397 {
3398 &syn_reply_info,
3399 true,
3400 { 1, 4 },
3401 { { "cookie", "val1,val2",
3402 NULL
3403 },
3404 { "vary", "cookie",
3405 spdy_util_.GetStatusKey(), "200",
3406 spdy_util_.GetPathKey(), "/index.php",
3407 spdy_util_.GetVersionKey(), "HTTP/1.1",
3408 NULL
3409 }
3410 }
3411 }, { // Multiple vary fields.
3412 &syn_reply_info,
3413 true,
3414 { 2, 5 },
3415 { { "friend", "barney",
3416 "enemy", "snaggletooth",
3417 NULL
3418 },
3419 { "vary", "friend",
3420 "vary", "enemy",
3421 spdy_util_.GetStatusKey(), "200",
3422 spdy_util_.GetPathKey(), "/index.php",
3423 spdy_util_.GetVersionKey(), "HTTP/1.1",
3424 NULL
3425 }
3426 }
3427 }, { // Test a '*' vary field.
3428 &syn_reply_info,
3429 false,
3430 { 1, 4 },
3431 { { "cookie", "val1,val2",
3432 NULL
3433 },
3434 { "vary", "*",
3435 spdy_util_.GetStatusKey(), "200",
3436 spdy_util_.GetPathKey(), "/index.php",
3437 spdy_util_.GetVersionKey(), "HTTP/1.1",
3438 NULL
3439 }
3440 }
3441 }, { // Multiple comma-separated vary fields.
3442 &syn_reply_info,
3443 true,
3444 { 2, 4 },
3445 { { "friend", "barney",
3446 "enemy", "snaggletooth",
3447 NULL
3448 },
3449 { "vary", "friend,enemy",
3450 spdy_util_.GetStatusKey(), "200",
3451 spdy_util_.GetPathKey(), "/index.php",
3452 spdy_util_.GetVersionKey(), "HTTP/1.1",
3453 NULL
3454 }
3455 }
3456 }
3457 };
3458
3459 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) {
3460 // Construct the request.
3461 scoped_ptr<SpdyFrame> frame_req(
3462 spdy_util_.ConstructSpdyGet(test_cases[i].extra_headers[0],
3463 test_cases[i].num_headers[0],
3464 false, 1, LOWEST, true));
3465
3466 MockWrite writes[] = {
3467 CreateMockWrite(*frame_req),
3468 };
3469
3470 // Construct the reply.
3471 scoped_ptr<SpdyFrame> frame_reply(
3472 spdy_util_.ConstructSpdyFrame(*test_cases[i].syn_reply,
3473 test_cases[i].extra_headers[1],
3474 test_cases[i].num_headers[1],
3475 NULL,
3476 0));
3477
3478 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
3479 MockRead reads[] = {
3480 CreateMockRead(*frame_reply),
3481 CreateMockRead(*body),
3482 MockRead(ASYNC, 0, 0) // EOF
3483 };
3484
3485 // Attach the headers to the request.
3486 int header_count = test_cases[i].num_headers[0];
3487
3488 HttpRequestInfo request = CreateGetRequest();
3489 for (int ct = 0; ct < header_count; ct++) {
3490 const char* header_key = test_cases[i].extra_headers[0][ct * 2];
3491 const char* header_value = test_cases[i].extra_headers[0][ct * 2 + 1];
3492 request.extra_headers.SetHeader(header_key, header_value);
3493 }
3494
3495 DelayedSocketData data(1, reads, arraysize(reads),
3496 writes, arraysize(writes));
3497 NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY,
3498 BoundNetLog(), GetParam(), NULL);
3499 helper.RunToCompletion(&data);
3500 TransactionHelperResult out = helper.output();
3501
3502 EXPECT_EQ(OK, out.rv) << i;
3503 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line) << i;
3504 EXPECT_EQ("hello!", out.response_data) << i;
3505
3506 // Test the response information.
3507 EXPECT_TRUE(out.response_info.response_time >
3508 out.response_info.request_time) << i;
3509 base::TimeDelta test_delay = out.response_info.response_time -
3510 out.response_info.request_time;
3511 base::TimeDelta min_expected_delay;
3512 min_expected_delay.FromMilliseconds(10);
3513 EXPECT_GT(test_delay.InMillisecondsF(),
3514 min_expected_delay.InMillisecondsF()) << i;
3515 EXPECT_EQ(out.response_info.vary_data.is_valid(),
3516 test_cases[i].vary_matches) << i;
3517
3518 // Check the headers.
3519 scoped_refptr<HttpResponseHeaders> headers = out.response_info.headers;
3520 ASSERT_TRUE(headers.get() != NULL) << i;
3521 void* iter = NULL;
3522 std::string name, value, lines;
3523 while (headers->EnumerateHeaderLines(&iter, &name, &value)) {
3524 lines.append(name);
3525 lines.append(": ");
3526 lines.append(value);
3527 lines.append("\n");
3528 }
3529
3530 // Construct the expected header reply string.
3531 SpdyHeaderBlock reply_headers;
3532 AppendToHeaderBlock(test_cases[i].extra_headers[1],
3533 test_cases[i].num_headers[1],
3534 &reply_headers);
3535 std::string expected_reply =
3536 spdy_util_.ConstructSpdyReplyString(reply_headers);
3537 EXPECT_EQ(expected_reply, lines) << i;
3538 }
3539 }
3540
3541 // Verify that we don't crash on invalid SynReply responses.
TEST_P(SpdyNetworkTransactionTest,InvalidSynReply)3542 TEST_P(SpdyNetworkTransactionTest, InvalidSynReply) {
3543 const SpdyHeaderInfo kSynStartHeader = {
3544 SYN_REPLY, // Kind = SynReply
3545 1, // Stream ID
3546 0, // Associated stream ID
3547 ConvertRequestPriorityToSpdyPriority(
3548 LOWEST, spdy_util_.spdy_version()),
3549 kSpdyCredentialSlotUnused,
3550 CONTROL_FLAG_NONE, // Control Flags
3551 false, // Compressed
3552 RST_STREAM_INVALID, // Status
3553 NULL, // Data
3554 0, // Length
3555 DATA_FLAG_NONE // Data Flags
3556 };
3557
3558 struct InvalidSynReplyTests {
3559 int num_headers;
3560 const char* headers[10];
3561 } test_cases[] = {
3562 // SYN_REPLY missing status header
3563 { 4,
3564 { "cookie", "val1",
3565 "cookie", "val2",
3566 spdy_util_.GetPathKey(), "/index.php",
3567 spdy_util_.GetVersionKey(), "HTTP/1.1",
3568 NULL
3569 },
3570 },
3571 // SYN_REPLY missing version header
3572 { 2,
3573 { "status", "200",
3574 spdy_util_.GetPathKey(), "/index.php",
3575 NULL
3576 },
3577 },
3578 // SYN_REPLY with no headers
3579 { 0, { NULL }, },
3580 };
3581
3582 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) {
3583 scoped_ptr<SpdyFrame> req(
3584 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
3585 scoped_ptr<SpdyFrame> rst(
3586 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR));
3587 MockWrite writes[] = {
3588 CreateMockWrite(*req),
3589 CreateMockWrite(*rst),
3590 };
3591
3592 scoped_ptr<SpdyFrame> resp(
3593 spdy_util_.ConstructSpdyFrame(kSynStartHeader,
3594 NULL, 0,
3595 test_cases[i].headers,
3596 test_cases[i].num_headers));
3597 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
3598 MockRead reads[] = {
3599 CreateMockRead(*resp),
3600 MockRead(ASYNC, 0, 0) // EOF
3601 };
3602
3603 DelayedSocketData data(1, reads, arraysize(reads),
3604 writes, arraysize(writes));
3605 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
3606 BoundNetLog(), GetParam(), NULL);
3607 helper.RunToCompletion(&data);
3608 TransactionHelperResult out = helper.output();
3609 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, out.rv);
3610 }
3611 }
3612
3613 // Verify that we don't crash on some corrupt frames.
3614 // TODO(jgraettinger): SPDY4 and up treats a header decompression failure as a
3615 // connection error. I'd like to backport this behavior to SPDY3 as well.
TEST_P(SpdyNetworkTransactionTest,CorruptFrameSessionError)3616 TEST_P(SpdyNetworkTransactionTest, CorruptFrameSessionError) {
3617 if (spdy_util_.spdy_version() >= SPDY4) {
3618 return;
3619 }
3620 // This is the length field that's too short.
3621 scoped_ptr<SpdyFrame> syn_reply_wrong_length(
3622 spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
3623 BufferedSpdyFramer framer(spdy_util_.spdy_version(), false);
3624 size_t right_size =
3625 (spdy_util_.spdy_version() < SPDY4) ?
3626 syn_reply_wrong_length->size() - framer.GetControlFrameHeaderSize() :
3627 syn_reply_wrong_length->size();
3628 size_t wrong_size = right_size - 4;
3629 test::SetFrameLength(syn_reply_wrong_length.get(),
3630 wrong_size,
3631 spdy_util_.spdy_version());
3632
3633 struct SynReplyTests {
3634 const SpdyFrame* syn_reply;
3635 } test_cases[] = {
3636 { syn_reply_wrong_length.get(), },
3637 };
3638
3639 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) {
3640 scoped_ptr<SpdyFrame> req(
3641 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
3642 scoped_ptr<SpdyFrame> rst(
3643 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR));
3644 MockWrite writes[] = {
3645 CreateMockWrite(*req),
3646 CreateMockWrite(*rst),
3647 };
3648
3649 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
3650 MockRead reads[] = {
3651 MockRead(ASYNC, test_cases[i].syn_reply->data(), wrong_size),
3652 CreateMockRead(*body),
3653 MockRead(ASYNC, 0, 0) // EOF
3654 };
3655
3656 DelayedSocketData data(1, reads, arraysize(reads),
3657 writes, arraysize(writes));
3658 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
3659 BoundNetLog(), GetParam(), NULL);
3660 helper.RunToCompletion(&data);
3661 TransactionHelperResult out = helper.output();
3662 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, out.rv);
3663 }
3664 }
3665
3666 // SPDY4 treats a header decompression failure as a connection-level error.
TEST_P(SpdyNetworkTransactionTest,CorruptFrameSessionErrorSpdy4)3667 TEST_P(SpdyNetworkTransactionTest, CorruptFrameSessionErrorSpdy4) {
3668 if (spdy_util_.spdy_version() < SPDY4) {
3669 return;
3670 }
3671 // This is the length field that's too short.
3672 scoped_ptr<SpdyFrame> syn_reply_wrong_length(
3673 spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
3674 BufferedSpdyFramer framer(spdy_util_.spdy_version(), false);
3675 size_t right_size =
3676 syn_reply_wrong_length->size() - framer.GetControlFrameHeaderSize();
3677 size_t wrong_size = right_size - 4;
3678 test::SetFrameLength(syn_reply_wrong_length.get(),
3679 wrong_size,
3680 spdy_util_.spdy_version());
3681
3682 scoped_ptr<SpdyFrame> req(
3683 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
3684 scoped_ptr<SpdyFrame> goaway(spdy_util_.ConstructSpdyGoAway(
3685 0, GOAWAY_COMPRESSION_ERROR, "Framer error: 5 (DECOMPRESS_FAILURE)."));
3686 MockWrite writes[] = {CreateMockWrite(*req), CreateMockWrite(*goaway)};
3687
3688 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
3689 MockRead reads[] = {
3690 MockRead(ASYNC, syn_reply_wrong_length->data(),
3691 syn_reply_wrong_length->size() - 4),
3692 };
3693
3694 DelayedSocketData data(1, reads, arraysize(reads),
3695 writes, arraysize(writes));
3696 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
3697 BoundNetLog(), GetParam(), NULL);
3698 helper.RunToCompletion(&data);
3699 TransactionHelperResult out = helper.output();
3700 EXPECT_EQ(ERR_SPDY_COMPRESSION_ERROR, out.rv);
3701 }
3702
TEST_P(SpdyNetworkTransactionTest,GoAwayOnDecompressionFailure)3703 TEST_P(SpdyNetworkTransactionTest, GoAwayOnDecompressionFailure) {
3704 if (GetParam().protocol < kProtoSPDY4) {
3705 // Decompression failures are a stream error in SPDY3 and above.
3706 return;
3707 }
3708 scoped_ptr<SpdyFrame> req(
3709 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
3710 scoped_ptr<SpdyFrame> goaway(spdy_util_.ConstructSpdyGoAway(
3711 0, GOAWAY_COMPRESSION_ERROR, "Framer error: 5 (DECOMPRESS_FAILURE)."));
3712 MockWrite writes[] = {CreateMockWrite(*req), CreateMockWrite(*goaway)};
3713
3714 // Read HEADERS with corrupted payload.
3715 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
3716 memset(resp->data() + 12, 0xff, resp->size() - 12);
3717 MockRead reads[] = {CreateMockRead(*resp)};
3718
3719 DelayedSocketData data(1, reads, arraysize(reads), writes, arraysize(writes));
3720 NormalSpdyTransactionHelper helper(
3721 CreateGetRequest(), DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL);
3722 helper.RunToCompletion(&data);
3723 TransactionHelperResult out = helper.output();
3724 EXPECT_EQ(ERR_SPDY_COMPRESSION_ERROR, out.rv);
3725 }
3726
TEST_P(SpdyNetworkTransactionTest,GoAwayOnFrameSizeError)3727 TEST_P(SpdyNetworkTransactionTest, GoAwayOnFrameSizeError) {
3728 scoped_ptr<SpdyFrame> req(
3729 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
3730 scoped_ptr<SpdyFrame> goaway(spdy_util_.ConstructSpdyGoAway(
3731 0, GOAWAY_PROTOCOL_ERROR, "Framer error: 1 (INVALID_CONTROL_FRAME)."));
3732 MockWrite writes[] = {CreateMockWrite(*req), CreateMockWrite(*goaway)};
3733
3734 // Read WINDOW_UPDATE with incorrectly-sized payload.
3735 // TODO(jgraettinger): SpdyFramer signals this as an INVALID_CONTROL_FRAME,
3736 // which is mapped to a protocol error, and not a frame size error.
3737 scoped_ptr<SpdyFrame> bad_window_update(
3738 spdy_util_.ConstructSpdyWindowUpdate(1, 1));
3739 test::SetFrameLength(bad_window_update.get(),
3740 bad_window_update->size() - 1,
3741 spdy_util_.spdy_version());
3742 MockRead reads[] = {CreateMockRead(*bad_window_update)};
3743
3744 DelayedSocketData data(1, reads, arraysize(reads), writes, arraysize(writes));
3745 NormalSpdyTransactionHelper helper(
3746 CreateGetRequest(), DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL);
3747 helper.RunToCompletion(&data);
3748 TransactionHelperResult out = helper.output();
3749 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, out.rv);
3750 }
3751
3752 // Test that we shutdown correctly on write errors.
TEST_P(SpdyNetworkTransactionTest,WriteError)3753 TEST_P(SpdyNetworkTransactionTest, WriteError) {
3754 scoped_ptr<SpdyFrame> req(
3755 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
3756 MockWrite writes[] = {
3757 // We'll write 10 bytes successfully
3758 MockWrite(ASYNC, req->data(), 10, 0),
3759 // Followed by ERROR!
3760 MockWrite(ASYNC, ERR_FAILED, 1),
3761 // Session drains and attempts to write a GOAWAY: Another ERROR!
3762 MockWrite(ASYNC, ERR_FAILED, 2),
3763 };
3764
3765 MockRead reads[] = {
3766 MockRead(ASYNC, 0, 3) // EOF
3767 };
3768
3769 DeterministicSocketData data(reads, arraysize(reads),
3770 writes, arraysize(writes));
3771
3772 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
3773 BoundNetLog(), GetParam(), NULL);
3774 helper.SetDeterministic();
3775 helper.RunPreTestSetup();
3776 helper.AddDeterministicData(&data);
3777 EXPECT_TRUE(helper.StartDefaultTest());
3778 data.RunFor(2);
3779 helper.FinishDefaultTest();
3780 EXPECT_TRUE(data.at_write_eof());
3781 EXPECT_TRUE(!data.at_read_eof());
3782 TransactionHelperResult out = helper.output();
3783 EXPECT_EQ(ERR_FAILED, out.rv);
3784 }
3785
3786 // Test that partial writes work.
TEST_P(SpdyNetworkTransactionTest,PartialWrite)3787 TEST_P(SpdyNetworkTransactionTest, PartialWrite) {
3788 // Chop the SYN_STREAM frame into 5 chunks.
3789 scoped_ptr<SpdyFrame> req(
3790 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
3791 const int kChunks = 5;
3792 scoped_ptr<MockWrite[]> writes(ChopWriteFrame(*req.get(), kChunks));
3793
3794 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
3795 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
3796 MockRead reads[] = {
3797 CreateMockRead(*resp),
3798 CreateMockRead(*body),
3799 MockRead(ASYNC, 0, 0) // EOF
3800 };
3801
3802 DelayedSocketData data(kChunks, reads, arraysize(reads),
3803 writes.get(), kChunks);
3804 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
3805 BoundNetLog(), GetParam(), NULL);
3806 helper.RunToCompletion(&data);
3807 TransactionHelperResult out = helper.output();
3808 EXPECT_EQ(OK, out.rv);
3809 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
3810 EXPECT_EQ("hello!", out.response_data);
3811 }
3812
3813 // In this test, we enable compression, but get a uncompressed SynReply from
3814 // the server. Verify that teardown is all clean.
TEST_P(SpdyNetworkTransactionTest,DecompressFailureOnSynReply)3815 TEST_P(SpdyNetworkTransactionTest, DecompressFailureOnSynReply) {
3816 if (spdy_util_.spdy_version() >= SPDY4) {
3817 // HPACK doesn't use deflate compression.
3818 return;
3819 }
3820 scoped_ptr<SpdyFrame> compressed(
3821 spdy_util_.ConstructSpdyGet(NULL, 0, true, 1, LOWEST, true));
3822 scoped_ptr<SpdyFrame> goaway(spdy_util_.ConstructSpdyGoAway(
3823 0, GOAWAY_COMPRESSION_ERROR, "Framer error: 5 (DECOMPRESS_FAILURE)."));
3824 MockWrite writes[] = {CreateMockWrite(*compressed), CreateMockWrite(*goaway)};
3825
3826 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
3827 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
3828 MockRead reads[] = {
3829 CreateMockRead(*resp),
3830 };
3831
3832 DelayedSocketData data(1, reads, arraysize(reads),
3833 writes, arraysize(writes));
3834 SpdySessionDependencies* session_deps =
3835 CreateSpdySessionDependencies(GetParam());
3836 session_deps->enable_compression = true;
3837 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
3838 BoundNetLog(), GetParam(), session_deps);
3839 helper.RunToCompletion(&data);
3840 TransactionHelperResult out = helper.output();
3841 EXPECT_EQ(ERR_SPDY_COMPRESSION_ERROR, out.rv);
3842 data.Reset();
3843 }
3844
3845 // Test that the NetLog contains good data for a simple GET request.
TEST_P(SpdyNetworkTransactionTest,NetLog)3846 TEST_P(SpdyNetworkTransactionTest, NetLog) {
3847 static const char* const kExtraHeaders[] = {
3848 "user-agent", "Chrome",
3849 };
3850 scoped_ptr<SpdyFrame> req(
3851 spdy_util_.ConstructSpdyGet(kExtraHeaders, 1, false, 1, LOWEST, true));
3852 MockWrite writes[] = { CreateMockWrite(*req) };
3853
3854 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
3855 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
3856 MockRead reads[] = {
3857 CreateMockRead(*resp),
3858 CreateMockRead(*body),
3859 MockRead(ASYNC, 0, 0) // EOF
3860 };
3861
3862 CapturingBoundNetLog log;
3863
3864 DelayedSocketData data(1, reads, arraysize(reads),
3865 writes, arraysize(writes));
3866 NormalSpdyTransactionHelper helper(CreateGetRequestWithUserAgent(),
3867 DEFAULT_PRIORITY,
3868 log.bound(), GetParam(), NULL);
3869 helper.RunToCompletion(&data);
3870 TransactionHelperResult out = helper.output();
3871 EXPECT_EQ(OK, out.rv);
3872 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
3873 EXPECT_EQ("hello!", out.response_data);
3874
3875 // Check that the NetLog was filled reasonably.
3876 // This test is intentionally non-specific about the exact ordering of the
3877 // log; instead we just check to make sure that certain events exist, and that
3878 // they are in the right order.
3879 net::CapturingNetLog::CapturedEntryList entries;
3880 log.GetEntries(&entries);
3881
3882 EXPECT_LT(0u, entries.size());
3883 int pos = 0;
3884 pos = net::ExpectLogContainsSomewhere(entries, 0,
3885 net::NetLog::TYPE_HTTP_TRANSACTION_SEND_REQUEST,
3886 net::NetLog::PHASE_BEGIN);
3887 pos = net::ExpectLogContainsSomewhere(entries, pos + 1,
3888 net::NetLog::TYPE_HTTP_TRANSACTION_SEND_REQUEST,
3889 net::NetLog::PHASE_END);
3890 pos = net::ExpectLogContainsSomewhere(entries, pos + 1,
3891 net::NetLog::TYPE_HTTP_TRANSACTION_READ_HEADERS,
3892 net::NetLog::PHASE_BEGIN);
3893 pos = net::ExpectLogContainsSomewhere(entries, pos + 1,
3894 net::NetLog::TYPE_HTTP_TRANSACTION_READ_HEADERS,
3895 net::NetLog::PHASE_END);
3896 pos = net::ExpectLogContainsSomewhere(entries, pos + 1,
3897 net::NetLog::TYPE_HTTP_TRANSACTION_READ_BODY,
3898 net::NetLog::PHASE_BEGIN);
3899 pos = net::ExpectLogContainsSomewhere(entries, pos + 1,
3900 net::NetLog::TYPE_HTTP_TRANSACTION_READ_BODY,
3901 net::NetLog::PHASE_END);
3902
3903 // Check that we logged all the headers correctly
3904 pos = net::ExpectLogContainsSomewhere(
3905 entries, 0,
3906 net::NetLog::TYPE_SPDY_SESSION_SYN_STREAM,
3907 net::NetLog::PHASE_NONE);
3908
3909 base::ListValue* header_list;
3910 ASSERT_TRUE(entries[pos].params.get());
3911 ASSERT_TRUE(entries[pos].params->GetList("headers", &header_list));
3912
3913 std::vector<std::string> expected;
3914 expected.push_back(std::string(spdy_util_.GetHostKey()) + ": www.google.com");
3915 expected.push_back(std::string(spdy_util_.GetPathKey()) + ": /");
3916 expected.push_back(std::string(spdy_util_.GetSchemeKey()) + ": http");
3917 expected.push_back(std::string(spdy_util_.GetMethodKey()) + ": GET");
3918 expected.push_back("user-agent: Chrome");
3919 if (spdy_util_.spdy_version() < SPDY4) {
3920 // SPDY4/HTTP2 eliminates use of the :version header.
3921 expected.push_back(std::string(spdy_util_.GetVersionKey()) + ": HTTP/1.1");
3922 }
3923 EXPECT_EQ(expected.size(), header_list->GetSize());
3924 for (std::vector<std::string>::const_iterator it = expected.begin();
3925 it != expected.end();
3926 ++it) {
3927 base::StringValue header(*it);
3928 EXPECT_NE(header_list->end(), header_list->Find(header)) <<
3929 "Header not found: " << *it;
3930 }
3931 }
3932
3933 // Since we buffer the IO from the stream to the renderer, this test verifies
3934 // that when we read out the maximum amount of data (e.g. we received 50 bytes
3935 // on the network, but issued a Read for only 5 of those bytes) that the data
3936 // flow still works correctly.
TEST_P(SpdyNetworkTransactionTest,BufferFull)3937 TEST_P(SpdyNetworkTransactionTest, BufferFull) {
3938 BufferedSpdyFramer framer(spdy_util_.spdy_version(), false);
3939
3940 scoped_ptr<SpdyFrame> req(
3941 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
3942 MockWrite writes[] = { CreateMockWrite(*req) };
3943
3944 // 2 data frames in a single read.
3945 scoped_ptr<SpdyFrame> data_frame_1(
3946 framer.CreateDataFrame(1, "goodby", 6, DATA_FLAG_NONE));
3947 scoped_ptr<SpdyFrame> data_frame_2(
3948 framer.CreateDataFrame(1, "e worl", 6, DATA_FLAG_NONE));
3949 const SpdyFrame* data_frames[2] = {
3950 data_frame_1.get(),
3951 data_frame_2.get(),
3952 };
3953 char combined_data_frames[100];
3954 int combined_data_frames_len =
3955 CombineFrames(data_frames, arraysize(data_frames),
3956 combined_data_frames, arraysize(combined_data_frames));
3957 scoped_ptr<SpdyFrame> last_frame(
3958 framer.CreateDataFrame(1, "d", 1, DATA_FLAG_FIN));
3959
3960 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
3961 MockRead reads[] = {
3962 CreateMockRead(*resp),
3963 MockRead(ASYNC, ERR_IO_PENDING), // Force a pause
3964 MockRead(ASYNC, combined_data_frames, combined_data_frames_len),
3965 MockRead(ASYNC, ERR_IO_PENDING), // Force a pause
3966 CreateMockRead(*last_frame),
3967 MockRead(ASYNC, 0, 0) // EOF
3968 };
3969
3970 DelayedSocketData data(1, reads, arraysize(reads),
3971 writes, arraysize(writes));
3972
3973 TestCompletionCallback callback;
3974
3975 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
3976 BoundNetLog(), GetParam(), NULL);
3977 helper.RunPreTestSetup();
3978 helper.AddData(&data);
3979 HttpNetworkTransaction* trans = helper.trans();
3980 int rv = trans->Start(
3981 &CreateGetRequest(), callback.callback(), BoundNetLog());
3982 EXPECT_EQ(ERR_IO_PENDING, rv);
3983
3984 TransactionHelperResult out = helper.output();
3985 out.rv = callback.WaitForResult();
3986 EXPECT_EQ(out.rv, OK);
3987
3988 const HttpResponseInfo* response = trans->GetResponseInfo();
3989 EXPECT_TRUE(response->headers.get() != NULL);
3990 EXPECT_TRUE(response->was_fetched_via_spdy);
3991 out.status_line = response->headers->GetStatusLine();
3992 out.response_info = *response; // Make a copy so we can verify.
3993
3994 // Read Data
3995 TestCompletionCallback read_callback;
3996
3997 std::string content;
3998 do {
3999 // Read small chunks at a time.
4000 const int kSmallReadSize = 3;
4001 scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(kSmallReadSize));
4002 rv = trans->Read(buf.get(), kSmallReadSize, read_callback.callback());
4003 if (rv == net::ERR_IO_PENDING) {
4004 data.CompleteRead();
4005 rv = read_callback.WaitForResult();
4006 }
4007 if (rv > 0) {
4008 content.append(buf->data(), rv);
4009 } else if (rv < 0) {
4010 NOTREACHED();
4011 }
4012 } while (rv > 0);
4013
4014 out.response_data.swap(content);
4015
4016 // Flush the MessageLoop while the SpdySessionDependencies (in particular, the
4017 // MockClientSocketFactory) are still alive.
4018 base::RunLoop().RunUntilIdle();
4019
4020 // Verify that we consumed all test data.
4021 helper.VerifyDataConsumed();
4022
4023 EXPECT_EQ(OK, out.rv);
4024 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
4025 EXPECT_EQ("goodbye world", out.response_data);
4026 }
4027
4028 // Verify that basic buffering works; when multiple data frames arrive
4029 // at the same time, ensure that we don't notify a read completion for
4030 // each data frame individually.
TEST_P(SpdyNetworkTransactionTest,Buffering)4031 TEST_P(SpdyNetworkTransactionTest, Buffering) {
4032 BufferedSpdyFramer framer(spdy_util_.spdy_version(), false);
4033
4034 scoped_ptr<SpdyFrame> req(
4035 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
4036 MockWrite writes[] = { CreateMockWrite(*req) };
4037
4038 // 4 data frames in a single read.
4039 scoped_ptr<SpdyFrame> data_frame(
4040 framer.CreateDataFrame(1, "message", 7, DATA_FLAG_NONE));
4041 scoped_ptr<SpdyFrame> data_frame_fin(
4042 framer.CreateDataFrame(1, "message", 7, DATA_FLAG_FIN));
4043 const SpdyFrame* data_frames[4] = {
4044 data_frame.get(),
4045 data_frame.get(),
4046 data_frame.get(),
4047 data_frame_fin.get()
4048 };
4049 char combined_data_frames[100];
4050 int combined_data_frames_len =
4051 CombineFrames(data_frames, arraysize(data_frames),
4052 combined_data_frames, arraysize(combined_data_frames));
4053
4054 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
4055 MockRead reads[] = {
4056 CreateMockRead(*resp),
4057 MockRead(ASYNC, ERR_IO_PENDING), // Force a pause
4058 MockRead(ASYNC, combined_data_frames, combined_data_frames_len),
4059 MockRead(ASYNC, 0, 0) // EOF
4060 };
4061
4062 DelayedSocketData data(1, reads, arraysize(reads),
4063 writes, arraysize(writes));
4064
4065 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
4066 BoundNetLog(), GetParam(), NULL);
4067 helper.RunPreTestSetup();
4068 helper.AddData(&data);
4069 HttpNetworkTransaction* trans = helper.trans();
4070
4071 TestCompletionCallback callback;
4072 int rv = trans->Start(
4073 &CreateGetRequest(), callback.callback(), BoundNetLog());
4074 EXPECT_EQ(ERR_IO_PENDING, rv);
4075
4076 TransactionHelperResult out = helper.output();
4077 out.rv = callback.WaitForResult();
4078 EXPECT_EQ(out.rv, OK);
4079
4080 const HttpResponseInfo* response = trans->GetResponseInfo();
4081 EXPECT_TRUE(response->headers.get() != NULL);
4082 EXPECT_TRUE(response->was_fetched_via_spdy);
4083 out.status_line = response->headers->GetStatusLine();
4084 out.response_info = *response; // Make a copy so we can verify.
4085
4086 // Read Data
4087 TestCompletionCallback read_callback;
4088
4089 std::string content;
4090 int reads_completed = 0;
4091 do {
4092 // Read small chunks at a time.
4093 const int kSmallReadSize = 14;
4094 scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(kSmallReadSize));
4095 rv = trans->Read(buf.get(), kSmallReadSize, read_callback.callback());
4096 if (rv == net::ERR_IO_PENDING) {
4097 data.CompleteRead();
4098 rv = read_callback.WaitForResult();
4099 }
4100 if (rv > 0) {
4101 EXPECT_EQ(kSmallReadSize, rv);
4102 content.append(buf->data(), rv);
4103 } else if (rv < 0) {
4104 FAIL() << "Unexpected read error: " << rv;
4105 }
4106 reads_completed++;
4107 } while (rv > 0);
4108
4109 EXPECT_EQ(3, reads_completed); // Reads are: 14 bytes, 14 bytes, 0 bytes.
4110
4111 out.response_data.swap(content);
4112
4113 // Flush the MessageLoop while the SpdySessionDependencies (in particular, the
4114 // MockClientSocketFactory) are still alive.
4115 base::RunLoop().RunUntilIdle();
4116
4117 // Verify that we consumed all test data.
4118 helper.VerifyDataConsumed();
4119
4120 EXPECT_EQ(OK, out.rv);
4121 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
4122 EXPECT_EQ("messagemessagemessagemessage", out.response_data);
4123 }
4124
4125 // Verify the case where we buffer data but read it after it has been buffered.
TEST_P(SpdyNetworkTransactionTest,BufferedAll)4126 TEST_P(SpdyNetworkTransactionTest, BufferedAll) {
4127 BufferedSpdyFramer framer(spdy_util_.spdy_version(), false);
4128
4129 scoped_ptr<SpdyFrame> req(
4130 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
4131 MockWrite writes[] = { CreateMockWrite(*req) };
4132
4133 // 5 data frames in a single read.
4134 SpdySynReplyIR reply_ir(1);
4135 reply_ir.SetHeader(spdy_util_.GetStatusKey(), "200");
4136 reply_ir.SetHeader(spdy_util_.GetVersionKey(), "HTTP/1.1");
4137
4138 scoped_ptr<SpdyFrame> syn_reply(framer.SerializeFrame(reply_ir));
4139 scoped_ptr<SpdyFrame> data_frame(
4140 framer.CreateDataFrame(1, "message", 7, DATA_FLAG_NONE));
4141 scoped_ptr<SpdyFrame> data_frame_fin(
4142 framer.CreateDataFrame(1, "message", 7, DATA_FLAG_FIN));
4143 const SpdyFrame* frames[5] = {
4144 syn_reply.get(),
4145 data_frame.get(),
4146 data_frame.get(),
4147 data_frame.get(),
4148 data_frame_fin.get()
4149 };
4150 char combined_frames[200];
4151 int combined_frames_len =
4152 CombineFrames(frames, arraysize(frames),
4153 combined_frames, arraysize(combined_frames));
4154
4155 MockRead reads[] = {
4156 MockRead(ASYNC, combined_frames, combined_frames_len),
4157 MockRead(ASYNC, 0, 0) // EOF
4158 };
4159
4160 DelayedSocketData data(1, reads, arraysize(reads),
4161 writes, arraysize(writes));
4162
4163 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
4164 BoundNetLog(), GetParam(), NULL);
4165 helper.RunPreTestSetup();
4166 helper.AddData(&data);
4167 HttpNetworkTransaction* trans = helper.trans();
4168
4169 TestCompletionCallback callback;
4170 int rv = trans->Start(
4171 &CreateGetRequest(), callback.callback(), BoundNetLog());
4172 EXPECT_EQ(ERR_IO_PENDING, rv);
4173
4174 TransactionHelperResult out = helper.output();
4175 out.rv = callback.WaitForResult();
4176 EXPECT_EQ(out.rv, OK);
4177
4178 const HttpResponseInfo* response = trans->GetResponseInfo();
4179 EXPECT_TRUE(response->headers.get() != NULL);
4180 EXPECT_TRUE(response->was_fetched_via_spdy);
4181 out.status_line = response->headers->GetStatusLine();
4182 out.response_info = *response; // Make a copy so we can verify.
4183
4184 // Read Data
4185 TestCompletionCallback read_callback;
4186
4187 std::string content;
4188 int reads_completed = 0;
4189 do {
4190 // Read small chunks at a time.
4191 const int kSmallReadSize = 14;
4192 scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(kSmallReadSize));
4193 rv = trans->Read(buf.get(), kSmallReadSize, read_callback.callback());
4194 if (rv > 0) {
4195 EXPECT_EQ(kSmallReadSize, rv);
4196 content.append(buf->data(), rv);
4197 } else if (rv < 0) {
4198 FAIL() << "Unexpected read error: " << rv;
4199 }
4200 reads_completed++;
4201 } while (rv > 0);
4202
4203 EXPECT_EQ(3, reads_completed);
4204
4205 out.response_data.swap(content);
4206
4207 // Flush the MessageLoop while the SpdySessionDependencies (in particular, the
4208 // MockClientSocketFactory) are still alive.
4209 base::RunLoop().RunUntilIdle();
4210
4211 // Verify that we consumed all test data.
4212 helper.VerifyDataConsumed();
4213
4214 EXPECT_EQ(OK, out.rv);
4215 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
4216 EXPECT_EQ("messagemessagemessagemessage", out.response_data);
4217 }
4218
4219 // Verify the case where we buffer data and close the connection.
TEST_P(SpdyNetworkTransactionTest,BufferedClosed)4220 TEST_P(SpdyNetworkTransactionTest, BufferedClosed) {
4221 BufferedSpdyFramer framer(spdy_util_.spdy_version(), false);
4222
4223 scoped_ptr<SpdyFrame> req(
4224 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
4225 MockWrite writes[] = { CreateMockWrite(*req) };
4226
4227 // All data frames in a single read.
4228 // NOTE: We don't FIN the stream.
4229 scoped_ptr<SpdyFrame> data_frame(
4230 framer.CreateDataFrame(1, "message", 7, DATA_FLAG_NONE));
4231 const SpdyFrame* data_frames[4] = {
4232 data_frame.get(),
4233 data_frame.get(),
4234 data_frame.get(),
4235 data_frame.get()
4236 };
4237 char combined_data_frames[100];
4238 int combined_data_frames_len =
4239 CombineFrames(data_frames, arraysize(data_frames),
4240 combined_data_frames, arraysize(combined_data_frames));
4241 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
4242 MockRead reads[] = {
4243 CreateMockRead(*resp),
4244 MockRead(ASYNC, ERR_IO_PENDING), // Force a wait
4245 MockRead(ASYNC, combined_data_frames, combined_data_frames_len),
4246 MockRead(ASYNC, 0, 0) // EOF
4247 };
4248
4249 DelayedSocketData data(1, reads, arraysize(reads),
4250 writes, arraysize(writes));
4251
4252 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
4253 BoundNetLog(), GetParam(), NULL);
4254 helper.RunPreTestSetup();
4255 helper.AddData(&data);
4256 HttpNetworkTransaction* trans = helper.trans();
4257
4258 TestCompletionCallback callback;
4259
4260 int rv = trans->Start(
4261 &CreateGetRequest(), callback.callback(), BoundNetLog());
4262 EXPECT_EQ(ERR_IO_PENDING, rv);
4263
4264 TransactionHelperResult out = helper.output();
4265 out.rv = callback.WaitForResult();
4266 EXPECT_EQ(out.rv, OK);
4267
4268 const HttpResponseInfo* response = trans->GetResponseInfo();
4269 EXPECT_TRUE(response->headers.get() != NULL);
4270 EXPECT_TRUE(response->was_fetched_via_spdy);
4271 out.status_line = response->headers->GetStatusLine();
4272 out.response_info = *response; // Make a copy so we can verify.
4273
4274 // Read Data
4275 TestCompletionCallback read_callback;
4276
4277 std::string content;
4278 int reads_completed = 0;
4279 do {
4280 // Read small chunks at a time.
4281 const int kSmallReadSize = 14;
4282 scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(kSmallReadSize));
4283 rv = trans->Read(buf.get(), kSmallReadSize, read_callback.callback());
4284 if (rv == net::ERR_IO_PENDING) {
4285 data.CompleteRead();
4286 rv = read_callback.WaitForResult();
4287 }
4288 if (rv > 0) {
4289 content.append(buf->data(), rv);
4290 } else if (rv < 0) {
4291 // This test intentionally closes the connection, and will get an error.
4292 EXPECT_EQ(ERR_CONNECTION_CLOSED, rv);
4293 break;
4294 }
4295 reads_completed++;
4296 } while (rv > 0);
4297
4298 EXPECT_EQ(0, reads_completed);
4299
4300 out.response_data.swap(content);
4301
4302 // Flush the MessageLoop while the SpdySessionDependencies (in particular, the
4303 // MockClientSocketFactory) are still alive.
4304 base::RunLoop().RunUntilIdle();
4305
4306 // Verify that we consumed all test data.
4307 helper.VerifyDataConsumed();
4308 }
4309
4310 // Verify the case where we buffer data and cancel the transaction.
TEST_P(SpdyNetworkTransactionTest,BufferedCancelled)4311 TEST_P(SpdyNetworkTransactionTest, BufferedCancelled) {
4312 BufferedSpdyFramer framer(spdy_util_.spdy_version(), false);
4313
4314 scoped_ptr<SpdyFrame> req(
4315 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
4316 scoped_ptr<SpdyFrame> rst(
4317 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL));
4318 MockWrite writes[] = {CreateMockWrite(*req), CreateMockWrite(*rst)};
4319
4320 // NOTE: We don't FIN the stream.
4321 scoped_ptr<SpdyFrame> data_frame(
4322 framer.CreateDataFrame(1, "message", 7, DATA_FLAG_NONE));
4323
4324 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
4325 MockRead reads[] = {
4326 CreateMockRead(*resp),
4327 MockRead(ASYNC, ERR_IO_PENDING), // Force a wait
4328 CreateMockRead(*data_frame),
4329 MockRead(ASYNC, 0, 0) // EOF
4330 };
4331
4332 DelayedSocketData data(1, reads, arraysize(reads),
4333 writes, arraysize(writes));
4334
4335 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
4336 BoundNetLog(), GetParam(), NULL);
4337 helper.RunPreTestSetup();
4338 helper.AddData(&data);
4339 HttpNetworkTransaction* trans = helper.trans();
4340 TestCompletionCallback callback;
4341
4342 int rv = trans->Start(
4343 &CreateGetRequest(), callback.callback(), BoundNetLog());
4344 EXPECT_EQ(ERR_IO_PENDING, rv);
4345
4346 TransactionHelperResult out = helper.output();
4347 out.rv = callback.WaitForResult();
4348 EXPECT_EQ(out.rv, OK);
4349
4350 const HttpResponseInfo* response = trans->GetResponseInfo();
4351 EXPECT_TRUE(response->headers.get() != NULL);
4352 EXPECT_TRUE(response->was_fetched_via_spdy);
4353 out.status_line = response->headers->GetStatusLine();
4354 out.response_info = *response; // Make a copy so we can verify.
4355
4356 // Read Data
4357 TestCompletionCallback read_callback;
4358
4359 const int kReadSize = 256;
4360 scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(kReadSize));
4361 rv = trans->Read(buf.get(), kReadSize, read_callback.callback());
4362 ASSERT_EQ(net::ERR_IO_PENDING, rv) << "Unexpected read: " << rv;
4363
4364 // Complete the read now, which causes buffering to start.
4365 data.CompleteRead();
4366 // Destroy the transaction, causing the stream to get cancelled
4367 // and orphaning the buffered IO task.
4368 helper.ResetTrans();
4369
4370 // Flush the MessageLoop; this will cause the buffered IO task
4371 // to run for the final time.
4372 base::RunLoop().RunUntilIdle();
4373
4374 // Verify that we consumed all test data.
4375 helper.VerifyDataConsumed();
4376 }
4377
4378 // Test that if the server requests persistence of settings, that we save
4379 // the settings in the HttpServerProperties.
TEST_P(SpdyNetworkTransactionTest,SettingsSaved)4380 TEST_P(SpdyNetworkTransactionTest, SettingsSaved) {
4381 if (spdy_util_.spdy_version() >= SPDY4) {
4382 // SPDY4 doesn't support flags on individual settings, and
4383 // has no concept of settings persistence.
4384 return;
4385 }
4386 static const SpdyHeaderInfo kSynReplyInfo = {
4387 SYN_REPLY, // Syn Reply
4388 1, // Stream ID
4389 0, // Associated Stream ID
4390 ConvertRequestPriorityToSpdyPriority(
4391 LOWEST, spdy_util_.spdy_version()),
4392 kSpdyCredentialSlotUnused,
4393 CONTROL_FLAG_NONE, // Control Flags
4394 false, // Compressed
4395 RST_STREAM_INVALID, // Status
4396 NULL, // Data
4397 0, // Data Length
4398 DATA_FLAG_NONE // Data Flags
4399 };
4400
4401 BoundNetLog net_log;
4402 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
4403 net_log, GetParam(), NULL);
4404 helper.RunPreTestSetup();
4405
4406 // Verify that no settings exist initially.
4407 HostPortPair host_port_pair("www.google.com", helper.port());
4408 SpdySessionPool* spdy_session_pool = helper.session()->spdy_session_pool();
4409 EXPECT_TRUE(spdy_session_pool->http_server_properties()->GetSpdySettings(
4410 host_port_pair).empty());
4411
4412 // Construct the request.
4413 scoped_ptr<SpdyFrame> req(
4414 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
4415 MockWrite writes[] = { CreateMockWrite(*req) };
4416
4417 // Construct the reply.
4418 scoped_ptr<SpdyHeaderBlock> reply_headers(new SpdyHeaderBlock());
4419 (*reply_headers)[spdy_util_.GetStatusKey()] = "200";
4420 (*reply_headers)[spdy_util_.GetVersionKey()] = "HTTP/1.1";
4421 scoped_ptr<SpdyFrame> reply(
4422 spdy_util_.ConstructSpdyFrame(kSynReplyInfo, reply_headers.Pass()));
4423
4424 const SpdySettingsIds kSampleId1 = SETTINGS_UPLOAD_BANDWIDTH;
4425 unsigned int kSampleValue1 = 0x0a0a0a0a;
4426 const SpdySettingsIds kSampleId2 = SETTINGS_DOWNLOAD_BANDWIDTH;
4427 unsigned int kSampleValue2 = 0x0b0b0b0b;
4428 const SpdySettingsIds kSampleId3 = SETTINGS_ROUND_TRIP_TIME;
4429 unsigned int kSampleValue3 = 0x0c0c0c0c;
4430 scoped_ptr<SpdyFrame> settings_frame;
4431 {
4432 // Construct the SETTINGS frame.
4433 SettingsMap settings;
4434 // First add a persisted setting.
4435 settings[kSampleId1] =
4436 SettingsFlagsAndValue(SETTINGS_FLAG_PLEASE_PERSIST, kSampleValue1);
4437 // Next add a non-persisted setting.
4438 settings[kSampleId2] =
4439 SettingsFlagsAndValue(SETTINGS_FLAG_NONE, kSampleValue2);
4440 // Next add another persisted setting.
4441 settings[kSampleId3] =
4442 SettingsFlagsAndValue(SETTINGS_FLAG_PLEASE_PERSIST, kSampleValue3);
4443 settings_frame.reset(spdy_util_.ConstructSpdySettings(settings));
4444 }
4445
4446 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
4447 MockRead reads[] = {
4448 CreateMockRead(*reply),
4449 CreateMockRead(*body),
4450 CreateMockRead(*settings_frame),
4451 MockRead(ASYNC, 0, 0) // EOF
4452 };
4453
4454 DelayedSocketData data(1, reads, arraysize(reads),
4455 writes, arraysize(writes));
4456 helper.AddData(&data);
4457 helper.RunDefaultTest();
4458 helper.VerifyDataConsumed();
4459 TransactionHelperResult out = helper.output();
4460 EXPECT_EQ(OK, out.rv);
4461 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
4462 EXPECT_EQ("hello!", out.response_data);
4463
4464 {
4465 // Verify we had two persisted settings.
4466 const SettingsMap& settings_map =
4467 spdy_session_pool->http_server_properties()->GetSpdySettings(
4468 host_port_pair);
4469 ASSERT_EQ(2u, settings_map.size());
4470
4471 // Verify the first persisted setting.
4472 SettingsMap::const_iterator it1 = settings_map.find(kSampleId1);
4473 EXPECT_TRUE(it1 != settings_map.end());
4474 SettingsFlagsAndValue flags_and_value1 = it1->second;
4475 EXPECT_EQ(SETTINGS_FLAG_PERSISTED, flags_and_value1.first);
4476 EXPECT_EQ(kSampleValue1, flags_and_value1.second);
4477
4478 // Verify the second persisted setting.
4479 SettingsMap::const_iterator it3 = settings_map.find(kSampleId3);
4480 EXPECT_TRUE(it3 != settings_map.end());
4481 SettingsFlagsAndValue flags_and_value3 = it3->second;
4482 EXPECT_EQ(SETTINGS_FLAG_PERSISTED, flags_and_value3.first);
4483 EXPECT_EQ(kSampleValue3, flags_and_value3.second);
4484 }
4485 }
4486
4487 // Test that when there are settings saved that they are sent back to the
4488 // server upon session establishment.
TEST_P(SpdyNetworkTransactionTest,SettingsPlayback)4489 TEST_P(SpdyNetworkTransactionTest, SettingsPlayback) {
4490 // TODO(jgraettinger): Remove settings persistence mechanisms altogether.
4491 static const SpdyHeaderInfo kSynReplyInfo = {
4492 SYN_REPLY, // Syn Reply
4493 1, // Stream ID
4494 0, // Associated Stream ID
4495 ConvertRequestPriorityToSpdyPriority(
4496 LOWEST, spdy_util_.spdy_version()),
4497 kSpdyCredentialSlotUnused,
4498 CONTROL_FLAG_NONE, // Control Flags
4499 false, // Compressed
4500 RST_STREAM_INVALID, // Status
4501 NULL, // Data
4502 0, // Data Length
4503 DATA_FLAG_NONE // Data Flags
4504 };
4505
4506 BoundNetLog net_log;
4507 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
4508 net_log, GetParam(), NULL);
4509 helper.RunPreTestSetup();
4510
4511 SpdySessionPool* spdy_session_pool = helper.session()->spdy_session_pool();
4512
4513 SpdySessionPoolPeer pool_peer(spdy_session_pool);
4514 pool_peer.SetEnableSendingInitialData(true);
4515
4516 // Verify that no settings exist initially.
4517 HostPortPair host_port_pair("www.google.com", helper.port());
4518 EXPECT_TRUE(spdy_session_pool->http_server_properties()->GetSpdySettings(
4519 host_port_pair).empty());
4520
4521 const SpdySettingsIds kSampleId1 = SETTINGS_MAX_CONCURRENT_STREAMS;
4522 unsigned int kSampleValue1 = 0x0a0a0a0a;
4523 const SpdySettingsIds kSampleId2 = SETTINGS_INITIAL_WINDOW_SIZE;
4524 unsigned int kSampleValue2 = 0x0c0c0c0c;
4525
4526 // First add a persisted setting.
4527 spdy_session_pool->http_server_properties()->SetSpdySetting(
4528 host_port_pair,
4529 kSampleId1,
4530 SETTINGS_FLAG_PLEASE_PERSIST,
4531 kSampleValue1);
4532
4533 // Next add another persisted setting.
4534 spdy_session_pool->http_server_properties()->SetSpdySetting(
4535 host_port_pair,
4536 kSampleId2,
4537 SETTINGS_FLAG_PLEASE_PERSIST,
4538 kSampleValue2);
4539
4540 EXPECT_EQ(2u, spdy_session_pool->http_server_properties()->GetSpdySettings(
4541 host_port_pair).size());
4542
4543 // Construct the initial SETTINGS frame.
4544 SettingsMap initial_settings;
4545 initial_settings[SETTINGS_MAX_CONCURRENT_STREAMS] =
4546 SettingsFlagsAndValue(SETTINGS_FLAG_NONE, kMaxConcurrentPushedStreams);
4547 scoped_ptr<SpdyFrame> initial_settings_frame(
4548 spdy_util_.ConstructSpdySettings(initial_settings));
4549
4550 // Construct the initial window update.
4551 scoped_ptr<SpdyFrame> initial_window_update(
4552 spdy_util_.ConstructSpdyWindowUpdate(
4553 kSessionFlowControlStreamId,
4554 kDefaultInitialRecvWindowSize - kSpdySessionInitialWindowSize));
4555
4556 // Construct the persisted SETTINGS frame.
4557 const SettingsMap& settings =
4558 spdy_session_pool->http_server_properties()->GetSpdySettings(
4559 host_port_pair);
4560 scoped_ptr<SpdyFrame> settings_frame(
4561 spdy_util_.ConstructSpdySettings(settings));
4562
4563 // Construct the request.
4564 scoped_ptr<SpdyFrame> req(
4565 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
4566
4567 std::vector<MockWrite> writes;
4568 if (GetParam().protocol == kProtoSPDY4) {
4569 writes.push_back(
4570 MockWrite(ASYNC,
4571 kHttp2ConnectionHeaderPrefix,
4572 kHttp2ConnectionHeaderPrefixSize));
4573 }
4574 writes.push_back(CreateMockWrite(*initial_settings_frame));
4575 if (GetParam().protocol >= kProtoSPDY31) {
4576 writes.push_back(CreateMockWrite(*initial_window_update));
4577 };
4578 writes.push_back(CreateMockWrite(*settings_frame));
4579 writes.push_back(CreateMockWrite(*req));
4580
4581 // Construct the reply.
4582 scoped_ptr<SpdyHeaderBlock> reply_headers(new SpdyHeaderBlock());
4583 (*reply_headers)[spdy_util_.GetStatusKey()] = "200";
4584 (*reply_headers)[spdy_util_.GetVersionKey()] = "HTTP/1.1";
4585 scoped_ptr<SpdyFrame> reply(
4586 spdy_util_.ConstructSpdyFrame(kSynReplyInfo, reply_headers.Pass()));
4587
4588 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
4589 MockRead reads[] = {
4590 CreateMockRead(*reply),
4591 CreateMockRead(*body),
4592 MockRead(ASYNC, 0, 0) // EOF
4593 };
4594
4595 DelayedSocketData data(2, reads, arraysize(reads),
4596 vector_as_array(&writes), writes.size());
4597 helper.AddData(&data);
4598 helper.RunDefaultTest();
4599 helper.VerifyDataConsumed();
4600 TransactionHelperResult out = helper.output();
4601 EXPECT_EQ(OK, out.rv);
4602 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
4603 EXPECT_EQ("hello!", out.response_data);
4604
4605 {
4606 // Verify we had two persisted settings.
4607 const SettingsMap& settings_map =
4608 spdy_session_pool->http_server_properties()->GetSpdySettings(
4609 host_port_pair);
4610 ASSERT_EQ(2u, settings_map.size());
4611
4612 // Verify the first persisted setting.
4613 SettingsMap::const_iterator it1 = settings_map.find(kSampleId1);
4614 EXPECT_TRUE(it1 != settings_map.end());
4615 SettingsFlagsAndValue flags_and_value1 = it1->second;
4616 EXPECT_EQ(SETTINGS_FLAG_PERSISTED, flags_and_value1.first);
4617 EXPECT_EQ(kSampleValue1, flags_and_value1.second);
4618
4619 // Verify the second persisted setting.
4620 SettingsMap::const_iterator it2 = settings_map.find(kSampleId2);
4621 EXPECT_TRUE(it2 != settings_map.end());
4622 SettingsFlagsAndValue flags_and_value2 = it2->second;
4623 EXPECT_EQ(SETTINGS_FLAG_PERSISTED, flags_and_value2.first);
4624 EXPECT_EQ(kSampleValue2, flags_and_value2.second);
4625 }
4626 }
4627
TEST_P(SpdyNetworkTransactionTest,GoAwayWithActiveStream)4628 TEST_P(SpdyNetworkTransactionTest, GoAwayWithActiveStream) {
4629 scoped_ptr<SpdyFrame> req(
4630 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
4631 MockWrite writes[] = { CreateMockWrite(*req) };
4632
4633 scoped_ptr<SpdyFrame> go_away(spdy_util_.ConstructSpdyGoAway());
4634 MockRead reads[] = {
4635 CreateMockRead(*go_away),
4636 };
4637
4638 DelayedSocketData data(1, reads, arraysize(reads),
4639 writes, arraysize(writes));
4640 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
4641 BoundNetLog(), GetParam(), NULL);
4642 helper.AddData(&data);
4643 helper.RunToCompletion(&data);
4644 TransactionHelperResult out = helper.output();
4645 EXPECT_EQ(ERR_ABORTED, out.rv);
4646 }
4647
TEST_P(SpdyNetworkTransactionTest,CloseWithActiveStream)4648 TEST_P(SpdyNetworkTransactionTest, CloseWithActiveStream) {
4649 scoped_ptr<SpdyFrame> req(
4650 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
4651 MockWrite writes[] = { CreateMockWrite(*req) };
4652
4653 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
4654 MockRead reads[] = {
4655 CreateMockRead(*resp),
4656 MockRead(SYNCHRONOUS, 0, 0) // EOF
4657 };
4658
4659 DelayedSocketData data(1, reads, arraysize(reads),
4660 writes, arraysize(writes));
4661 BoundNetLog log;
4662 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
4663 log, GetParam(), NULL);
4664 helper.RunPreTestSetup();
4665 helper.AddData(&data);
4666 HttpNetworkTransaction* trans = helper.trans();
4667
4668 TestCompletionCallback callback;
4669 TransactionHelperResult out;
4670 out.rv = trans->Start(&CreateGetRequest(), callback.callback(), log);
4671
4672 EXPECT_EQ(out.rv, ERR_IO_PENDING);
4673 out.rv = callback.WaitForResult();
4674 EXPECT_EQ(out.rv, OK);
4675
4676 const HttpResponseInfo* response = trans->GetResponseInfo();
4677 EXPECT_TRUE(response->headers.get() != NULL);
4678 EXPECT_TRUE(response->was_fetched_via_spdy);
4679 out.rv = ReadTransaction(trans, &out.response_data);
4680 EXPECT_EQ(ERR_CONNECTION_CLOSED, out.rv);
4681
4682 // Verify that we consumed all test data.
4683 helper.VerifyDataConsumed();
4684 }
4685
4686 // Test to make sure we can correctly connect through a proxy.
TEST_P(SpdyNetworkTransactionTest,ProxyConnect)4687 TEST_P(SpdyNetworkTransactionTest, ProxyConnect) {
4688 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
4689 BoundNetLog(), GetParam(), NULL);
4690 helper.session_deps().reset(CreateSpdySessionDependencies(
4691 GetParam(),
4692 ProxyService::CreateFixedFromPacResult("PROXY myproxy:70")));
4693 helper.SetSession(make_scoped_refptr(
4694 SpdySessionDependencies::SpdyCreateSession(helper.session_deps().get())));
4695 helper.RunPreTestSetup();
4696 HttpNetworkTransaction* trans = helper.trans();
4697
4698 const char kConnect443[] = {"CONNECT www.google.com:443 HTTP/1.1\r\n"
4699 "Host: www.google.com\r\n"
4700 "Proxy-Connection: keep-alive\r\n\r\n"};
4701 const char kConnect80[] = {"CONNECT www.google.com:80 HTTP/1.1\r\n"
4702 "Host: www.google.com\r\n"
4703 "Proxy-Connection: keep-alive\r\n\r\n"};
4704 const char kHTTP200[] = {"HTTP/1.1 200 OK\r\n\r\n"};
4705 scoped_ptr<SpdyFrame> req(
4706 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
4707 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
4708 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
4709
4710 MockWrite writes_SPDYNPN[] = {
4711 MockWrite(SYNCHRONOUS, kConnect443, arraysize(kConnect443) - 1, 0),
4712 CreateMockWrite(*req, 2),
4713 };
4714 MockRead reads_SPDYNPN[] = {
4715 MockRead(SYNCHRONOUS, kHTTP200, arraysize(kHTTP200) - 1, 1),
4716 CreateMockRead(*resp, 3),
4717 CreateMockRead(*body.get(), 4),
4718 MockRead(ASYNC, 0, 0, 5),
4719 };
4720
4721 MockWrite writes_SPDYSSL[] = {
4722 MockWrite(SYNCHRONOUS, kConnect80, arraysize(kConnect80) - 1, 0),
4723 CreateMockWrite(*req, 2),
4724 };
4725 MockRead reads_SPDYSSL[] = {
4726 MockRead(SYNCHRONOUS, kHTTP200, arraysize(kHTTP200) - 1, 1),
4727 CreateMockRead(*resp, 3),
4728 CreateMockRead(*body.get(), 4),
4729 MockRead(ASYNC, 0, 0, 5),
4730 };
4731
4732 MockWrite writes_SPDYNOSSL[] = {
4733 CreateMockWrite(*req, 0),
4734 };
4735
4736 MockRead reads_SPDYNOSSL[] = {
4737 CreateMockRead(*resp, 1),
4738 CreateMockRead(*body.get(), 2),
4739 MockRead(ASYNC, 0, 0, 3),
4740 };
4741
4742 scoped_ptr<OrderedSocketData> data;
4743 switch(GetParam().ssl_type) {
4744 case SPDYNOSSL:
4745 data.reset(new OrderedSocketData(reads_SPDYNOSSL,
4746 arraysize(reads_SPDYNOSSL),
4747 writes_SPDYNOSSL,
4748 arraysize(writes_SPDYNOSSL)));
4749 break;
4750 case SPDYSSL:
4751 data.reset(new OrderedSocketData(reads_SPDYSSL,
4752 arraysize(reads_SPDYSSL),
4753 writes_SPDYSSL,
4754 arraysize(writes_SPDYSSL)));
4755 break;
4756 case SPDYNPN:
4757 data.reset(new OrderedSocketData(reads_SPDYNPN,
4758 arraysize(reads_SPDYNPN),
4759 writes_SPDYNPN,
4760 arraysize(writes_SPDYNPN)));
4761 break;
4762 default:
4763 NOTREACHED();
4764 }
4765
4766 helper.AddData(data.get());
4767 TestCompletionCallback callback;
4768
4769 int rv = trans->Start(
4770 &CreateGetRequest(), callback.callback(), BoundNetLog());
4771 EXPECT_EQ(ERR_IO_PENDING, rv);
4772
4773 rv = callback.WaitForResult();
4774 EXPECT_EQ(0, rv);
4775
4776 // Verify the SYN_REPLY.
4777 HttpResponseInfo response = *trans->GetResponseInfo();
4778 EXPECT_TRUE(response.headers.get() != NULL);
4779 EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine());
4780
4781 std::string response_data;
4782 ASSERT_EQ(OK, ReadTransaction(trans, &response_data));
4783 EXPECT_EQ("hello!", response_data);
4784 helper.VerifyDataConsumed();
4785 }
4786
4787 // Test to make sure we can correctly connect through a proxy to www.google.com,
4788 // if there already exists a direct spdy connection to www.google.com. See
4789 // http://crbug.com/49874
TEST_P(SpdyNetworkTransactionTest,DirectConnectProxyReconnect)4790 TEST_P(SpdyNetworkTransactionTest, DirectConnectProxyReconnect) {
4791 // When setting up the first transaction, we store the SpdySessionPool so that
4792 // we can use the same pool in the second transaction.
4793 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
4794 BoundNetLog(), GetParam(), NULL);
4795
4796 // Use a proxy service which returns a proxy fallback list from DIRECT to
4797 // myproxy:70. For this test there will be no fallback, so it is equivalent
4798 // to simply DIRECT. The reason for appending the second proxy is to verify
4799 // that the session pool key used does is just "DIRECT".
4800 helper.session_deps().reset(CreateSpdySessionDependencies(
4801 GetParam(),
4802 ProxyService::CreateFixedFromPacResult("DIRECT; PROXY myproxy:70")));
4803 helper.SetSession(make_scoped_refptr(
4804 SpdySessionDependencies::SpdyCreateSession(helper.session_deps().get())));
4805
4806 SpdySessionPool* spdy_session_pool = helper.session()->spdy_session_pool();
4807 helper.RunPreTestSetup();
4808
4809 // Construct and send a simple GET request.
4810 scoped_ptr<SpdyFrame> req(
4811 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
4812 MockWrite writes[] = {
4813 CreateMockWrite(*req, 1),
4814 };
4815
4816 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
4817 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
4818 MockRead reads[] = {
4819 CreateMockRead(*resp, 2),
4820 CreateMockRead(*body, 3),
4821 MockRead(ASYNC, ERR_IO_PENDING, 4), // Force a pause
4822 MockRead(ASYNC, 0, 5) // EOF
4823 };
4824 OrderedSocketData data(reads, arraysize(reads),
4825 writes, arraysize(writes));
4826 helper.AddData(&data);
4827 HttpNetworkTransaction* trans = helper.trans();
4828
4829 TestCompletionCallback callback;
4830 TransactionHelperResult out;
4831 out.rv = trans->Start(
4832 &CreateGetRequest(), callback.callback(), BoundNetLog());
4833
4834 EXPECT_EQ(out.rv, ERR_IO_PENDING);
4835 out.rv = callback.WaitForResult();
4836 EXPECT_EQ(out.rv, OK);
4837
4838 const HttpResponseInfo* response = trans->GetResponseInfo();
4839 EXPECT_TRUE(response->headers.get() != NULL);
4840 EXPECT_TRUE(response->was_fetched_via_spdy);
4841 out.rv = ReadTransaction(trans, &out.response_data);
4842 EXPECT_EQ(OK, out.rv);
4843 out.status_line = response->headers->GetStatusLine();
4844 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
4845 EXPECT_EQ("hello!", out.response_data);
4846
4847 // Check that the SpdySession is still in the SpdySessionPool.
4848 HostPortPair host_port_pair("www.google.com", helper.port());
4849 SpdySessionKey session_pool_key_direct(
4850 host_port_pair, ProxyServer::Direct(), PRIVACY_MODE_DISABLED);
4851 EXPECT_TRUE(HasSpdySession(spdy_session_pool, session_pool_key_direct));
4852 SpdySessionKey session_pool_key_proxy(
4853 host_port_pair,
4854 ProxyServer::FromURI("www.foo.com", ProxyServer::SCHEME_HTTP),
4855 PRIVACY_MODE_DISABLED);
4856 EXPECT_FALSE(HasSpdySession(spdy_session_pool, session_pool_key_proxy));
4857
4858 // Set up data for the proxy connection.
4859 const char kConnect443[] = {"CONNECT www.google.com:443 HTTP/1.1\r\n"
4860 "Host: www.google.com\r\n"
4861 "Proxy-Connection: keep-alive\r\n\r\n"};
4862 const char kConnect80[] = {"CONNECT www.google.com:80 HTTP/1.1\r\n"
4863 "Host: www.google.com\r\n"
4864 "Proxy-Connection: keep-alive\r\n\r\n"};
4865 const char kHTTP200[] = {"HTTP/1.1 200 OK\r\n\r\n"};
4866 scoped_ptr<SpdyFrame> req2(spdy_util_.ConstructSpdyGet(
4867 "http://www.google.com/foo.dat", false, 1, LOWEST));
4868 scoped_ptr<SpdyFrame> resp2(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
4869 scoped_ptr<SpdyFrame> body2(spdy_util_.ConstructSpdyBodyFrame(1, true));
4870
4871 MockWrite writes_SPDYNPN[] = {
4872 MockWrite(SYNCHRONOUS, kConnect443, arraysize(kConnect443) - 1, 0),
4873 CreateMockWrite(*req2, 2),
4874 };
4875 MockRead reads_SPDYNPN[] = {
4876 MockRead(SYNCHRONOUS, kHTTP200, arraysize(kHTTP200) - 1, 1),
4877 CreateMockRead(*resp2, 3),
4878 CreateMockRead(*body2, 4),
4879 MockRead(ASYNC, 0, 5) // EOF
4880 };
4881
4882 MockWrite writes_SPDYNOSSL[] = {
4883 CreateMockWrite(*req2, 0),
4884 };
4885 MockRead reads_SPDYNOSSL[] = {
4886 CreateMockRead(*resp2, 1),
4887 CreateMockRead(*body2, 2),
4888 MockRead(ASYNC, 0, 3) // EOF
4889 };
4890
4891 MockWrite writes_SPDYSSL[] = {
4892 MockWrite(SYNCHRONOUS, kConnect80, arraysize(kConnect80) - 1, 0),
4893 CreateMockWrite(*req2, 2),
4894 };
4895 MockRead reads_SPDYSSL[] = {
4896 MockRead(SYNCHRONOUS, kHTTP200, arraysize(kHTTP200) - 1, 1),
4897 CreateMockRead(*resp2, 3),
4898 CreateMockRead(*body2, 4),
4899 MockRead(ASYNC, 0, 0, 5),
4900 };
4901
4902 scoped_ptr<OrderedSocketData> data_proxy;
4903 switch(GetParam().ssl_type) {
4904 case SPDYNPN:
4905 data_proxy.reset(new OrderedSocketData(reads_SPDYNPN,
4906 arraysize(reads_SPDYNPN),
4907 writes_SPDYNPN,
4908 arraysize(writes_SPDYNPN)));
4909 break;
4910 case SPDYNOSSL:
4911 data_proxy.reset(new OrderedSocketData(reads_SPDYNOSSL,
4912 arraysize(reads_SPDYNOSSL),
4913 writes_SPDYNOSSL,
4914 arraysize(writes_SPDYNOSSL)));
4915 break;
4916 case SPDYSSL:
4917 data_proxy.reset(new OrderedSocketData(reads_SPDYSSL,
4918 arraysize(reads_SPDYSSL),
4919 writes_SPDYSSL,
4920 arraysize(writes_SPDYSSL)));
4921 break;
4922 default:
4923 NOTREACHED();
4924 }
4925
4926 // Create another request to www.google.com, but this time through a proxy.
4927 HttpRequestInfo request_proxy;
4928 request_proxy.method = "GET";
4929 request_proxy.url = GURL("http://www.google.com/foo.dat");
4930 request_proxy.load_flags = 0;
4931 scoped_ptr<SpdySessionDependencies> ssd_proxy(
4932 CreateSpdySessionDependencies(GetParam()));
4933 // Ensure that this transaction uses the same SpdySessionPool.
4934 scoped_refptr<HttpNetworkSession> session_proxy(
4935 SpdySessionDependencies::SpdyCreateSession(ssd_proxy.get()));
4936 NormalSpdyTransactionHelper helper_proxy(request_proxy, DEFAULT_PRIORITY,
4937 BoundNetLog(), GetParam(), NULL);
4938 HttpNetworkSessionPeer session_peer(session_proxy);
4939 scoped_ptr<net::ProxyService> proxy_service(
4940 ProxyService::CreateFixedFromPacResult("PROXY myproxy:70"));
4941 session_peer.SetProxyService(proxy_service.get());
4942 helper_proxy.session_deps().swap(ssd_proxy);
4943 helper_proxy.SetSession(session_proxy);
4944 helper_proxy.RunPreTestSetup();
4945 helper_proxy.AddData(data_proxy.get());
4946
4947 HttpNetworkTransaction* trans_proxy = helper_proxy.trans();
4948 TestCompletionCallback callback_proxy;
4949 int rv = trans_proxy->Start(
4950 &request_proxy, callback_proxy.callback(), BoundNetLog());
4951 EXPECT_EQ(ERR_IO_PENDING, rv);
4952 rv = callback_proxy.WaitForResult();
4953 EXPECT_EQ(0, rv);
4954
4955 HttpResponseInfo response_proxy = *trans_proxy->GetResponseInfo();
4956 EXPECT_TRUE(response_proxy.headers.get() != NULL);
4957 EXPECT_EQ("HTTP/1.1 200 OK", response_proxy.headers->GetStatusLine());
4958
4959 std::string response_data;
4960 ASSERT_EQ(OK, ReadTransaction(trans_proxy, &response_data));
4961 EXPECT_EQ("hello!", response_data);
4962
4963 data.CompleteRead();
4964 helper_proxy.VerifyDataConsumed();
4965 }
4966
4967 // When we get a TCP-level RST, we need to retry a HttpNetworkTransaction
4968 // on a new connection, if the connection was previously known to be good.
4969 // This can happen when a server reboots without saying goodbye, or when
4970 // we're behind a NAT that masked the RST.
TEST_P(SpdyNetworkTransactionTest,VerifyRetryOnConnectionReset)4971 TEST_P(SpdyNetworkTransactionTest, VerifyRetryOnConnectionReset) {
4972 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
4973 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
4974 MockRead reads[] = {
4975 CreateMockRead(*resp),
4976 CreateMockRead(*body),
4977 MockRead(ASYNC, ERR_IO_PENDING),
4978 MockRead(ASYNC, ERR_CONNECTION_RESET),
4979 };
4980
4981 MockRead reads2[] = {
4982 CreateMockRead(*resp),
4983 CreateMockRead(*body),
4984 MockRead(ASYNC, 0, 0) // EOF
4985 };
4986
4987 // This test has a couple of variants.
4988 enum {
4989 // Induce the RST while waiting for our transaction to send.
4990 VARIANT_RST_DURING_SEND_COMPLETION,
4991 // Induce the RST while waiting for our transaction to read.
4992 // In this case, the send completed - everything copied into the SNDBUF.
4993 VARIANT_RST_DURING_READ_COMPLETION
4994 };
4995
4996 for (int variant = VARIANT_RST_DURING_SEND_COMPLETION;
4997 variant <= VARIANT_RST_DURING_READ_COMPLETION;
4998 ++variant) {
4999 DelayedSocketData data1(1, reads, arraysize(reads), NULL, 0);
5000
5001 DelayedSocketData data2(1, reads2, arraysize(reads2), NULL, 0);
5002
5003 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
5004 BoundNetLog(), GetParam(), NULL);
5005 helper.AddData(&data1);
5006 helper.AddData(&data2);
5007 helper.RunPreTestSetup();
5008
5009 for (int i = 0; i < 2; ++i) {
5010 scoped_ptr<HttpNetworkTransaction> trans(
5011 new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get()));
5012
5013 TestCompletionCallback callback;
5014 int rv = trans->Start(
5015 &helper.request(), callback.callback(), BoundNetLog());
5016 EXPECT_EQ(ERR_IO_PENDING, rv);
5017 // On the second transaction, we trigger the RST.
5018 if (i == 1) {
5019 if (variant == VARIANT_RST_DURING_READ_COMPLETION) {
5020 // Writes to the socket complete asynchronously on SPDY by running
5021 // through the message loop. Complete the write here.
5022 base::RunLoop().RunUntilIdle();
5023 }
5024
5025 // Now schedule the ERR_CONNECTION_RESET.
5026 EXPECT_EQ(3u, data1.read_index());
5027 data1.CompleteRead();
5028 EXPECT_EQ(4u, data1.read_index());
5029 }
5030 rv = callback.WaitForResult();
5031 EXPECT_EQ(OK, rv);
5032
5033 const HttpResponseInfo* response = trans->GetResponseInfo();
5034 ASSERT_TRUE(response != NULL);
5035 EXPECT_TRUE(response->headers.get() != NULL);
5036 EXPECT_TRUE(response->was_fetched_via_spdy);
5037 std::string response_data;
5038 rv = ReadTransaction(trans.get(), &response_data);
5039 EXPECT_EQ(OK, rv);
5040 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
5041 EXPECT_EQ("hello!", response_data);
5042 }
5043
5044 helper.VerifyDataConsumed();
5045 }
5046 }
5047
5048 // Test that turning SPDY on and off works properly.
TEST_P(SpdyNetworkTransactionTest,SpdyOnOffToggle)5049 TEST_P(SpdyNetworkTransactionTest, SpdyOnOffToggle) {
5050 HttpStreamFactory::set_spdy_enabled(true);
5051 scoped_ptr<SpdyFrame> req(
5052 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
5053 MockWrite spdy_writes[] = { CreateMockWrite(*req) };
5054
5055 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
5056 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
5057 MockRead spdy_reads[] = {
5058 CreateMockRead(*resp),
5059 CreateMockRead(*body),
5060 MockRead(ASYNC, 0, 0) // EOF
5061 };
5062
5063 DelayedSocketData data(1, spdy_reads, arraysize(spdy_reads),
5064 spdy_writes, arraysize(spdy_writes));
5065 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
5066 BoundNetLog(), GetParam(), NULL);
5067 helper.RunToCompletion(&data);
5068 TransactionHelperResult out = helper.output();
5069 EXPECT_EQ(OK, out.rv);
5070 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
5071 EXPECT_EQ("hello!", out.response_data);
5072
5073 net::HttpStreamFactory::set_spdy_enabled(false);
5074 MockRead http_reads[] = {
5075 MockRead("HTTP/1.1 200 OK\r\n\r\n"),
5076 MockRead("hello from http"),
5077 MockRead(SYNCHRONOUS, OK),
5078 };
5079 DelayedSocketData data2(1, http_reads, arraysize(http_reads), NULL, 0);
5080 NormalSpdyTransactionHelper helper2(CreateGetRequest(), DEFAULT_PRIORITY,
5081 BoundNetLog(), GetParam(), NULL);
5082 helper2.SetSpdyDisabled();
5083 helper2.RunToCompletion(&data2);
5084 TransactionHelperResult out2 = helper2.output();
5085 EXPECT_EQ(OK, out2.rv);
5086 EXPECT_EQ("HTTP/1.1 200 OK", out2.status_line);
5087 EXPECT_EQ("hello from http", out2.response_data);
5088
5089 net::HttpStreamFactory::set_spdy_enabled(true);
5090 }
5091
5092 // Tests that Basic authentication works over SPDY
TEST_P(SpdyNetworkTransactionTest,SpdyBasicAuth)5093 TEST_P(SpdyNetworkTransactionTest, SpdyBasicAuth) {
5094 net::HttpStreamFactory::set_spdy_enabled(true);
5095
5096 // The first request will be a bare GET, the second request will be a
5097 // GET with an Authorization header.
5098 scoped_ptr<SpdyFrame> req_get(
5099 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
5100 const char* const kExtraAuthorizationHeaders[] = {
5101 "authorization", "Basic Zm9vOmJhcg=="
5102 };
5103 scoped_ptr<SpdyFrame> req_get_authorization(
5104 spdy_util_.ConstructSpdyGet(kExtraAuthorizationHeaders,
5105 arraysize(kExtraAuthorizationHeaders) / 2,
5106 false, 3, LOWEST, true));
5107 MockWrite spdy_writes[] = {
5108 CreateMockWrite(*req_get, 1),
5109 CreateMockWrite(*req_get_authorization, 4),
5110 };
5111
5112 // The first response is a 401 authentication challenge, and the second
5113 // response will be a 200 response since the second request includes a valid
5114 // Authorization header.
5115 const char* const kExtraAuthenticationHeaders[] = {
5116 "www-authenticate",
5117 "Basic realm=\"MyRealm\""
5118 };
5119 scoped_ptr<SpdyFrame> resp_authentication(
5120 spdy_util_.ConstructSpdySynReplyError(
5121 "401 Authentication Required",
5122 kExtraAuthenticationHeaders,
5123 arraysize(kExtraAuthenticationHeaders) / 2,
5124 1));
5125 scoped_ptr<SpdyFrame> body_authentication(
5126 spdy_util_.ConstructSpdyBodyFrame(1, true));
5127 scoped_ptr<SpdyFrame> resp_data(
5128 spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3));
5129 scoped_ptr<SpdyFrame> body_data(spdy_util_.ConstructSpdyBodyFrame(3, true));
5130 MockRead spdy_reads[] = {
5131 CreateMockRead(*resp_authentication, 2),
5132 CreateMockRead(*body_authentication, 3),
5133 CreateMockRead(*resp_data, 5),
5134 CreateMockRead(*body_data, 6),
5135 MockRead(ASYNC, 0, 7),
5136 };
5137
5138 OrderedSocketData data(spdy_reads, arraysize(spdy_reads),
5139 spdy_writes, arraysize(spdy_writes));
5140 HttpRequestInfo request(CreateGetRequest());
5141 BoundNetLog net_log;
5142 NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY,
5143 net_log, GetParam(), NULL);
5144
5145 helper.RunPreTestSetup();
5146 helper.AddData(&data);
5147 HttpNetworkTransaction* trans = helper.trans();
5148 TestCompletionCallback callback;
5149 const int rv_start = trans->Start(&request, callback.callback(), net_log);
5150 EXPECT_EQ(ERR_IO_PENDING, rv_start);
5151 const int rv_start_complete = callback.WaitForResult();
5152 EXPECT_EQ(OK, rv_start_complete);
5153
5154 // Make sure the response has an auth challenge.
5155 const HttpResponseInfo* const response_start = trans->GetResponseInfo();
5156 ASSERT_TRUE(response_start != NULL);
5157 ASSERT_TRUE(response_start->headers.get() != NULL);
5158 EXPECT_EQ(401, response_start->headers->response_code());
5159 EXPECT_TRUE(response_start->was_fetched_via_spdy);
5160 AuthChallengeInfo* auth_challenge = response_start->auth_challenge.get();
5161 ASSERT_TRUE(auth_challenge != NULL);
5162 EXPECT_FALSE(auth_challenge->is_proxy);
5163 EXPECT_EQ("basic", auth_challenge->scheme);
5164 EXPECT_EQ("MyRealm", auth_challenge->realm);
5165
5166 // Restart with a username/password.
5167 AuthCredentials credentials(base::ASCIIToUTF16("foo"),
5168 base::ASCIIToUTF16("bar"));
5169 TestCompletionCallback callback_restart;
5170 const int rv_restart = trans->RestartWithAuth(
5171 credentials, callback_restart.callback());
5172 EXPECT_EQ(ERR_IO_PENDING, rv_restart);
5173 const int rv_restart_complete = callback_restart.WaitForResult();
5174 EXPECT_EQ(OK, rv_restart_complete);
5175 // TODO(cbentzel): This is actually the same response object as before, but
5176 // data has changed.
5177 const HttpResponseInfo* const response_restart = trans->GetResponseInfo();
5178 ASSERT_TRUE(response_restart != NULL);
5179 ASSERT_TRUE(response_restart->headers.get() != NULL);
5180 EXPECT_EQ(200, response_restart->headers->response_code());
5181 EXPECT_TRUE(response_restart->auth_challenge.get() == NULL);
5182 }
5183
TEST_P(SpdyNetworkTransactionTest,ServerPushWithHeaders)5184 TEST_P(SpdyNetworkTransactionTest, ServerPushWithHeaders) {
5185 scoped_ptr<SpdyFrame> stream1_syn(
5186 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
5187 scoped_ptr<SpdyFrame> stream1_body(
5188 spdy_util_.ConstructSpdyBodyFrame(1, true));
5189 MockWrite writes[] = {
5190 CreateMockWrite(*stream1_syn, 1),
5191 };
5192
5193 scoped_ptr<SpdyHeaderBlock> initial_headers(new SpdyHeaderBlock());
5194 spdy_util_.AddUrlToHeaderBlock(
5195 "http://www.google.com/foo.dat", initial_headers.get());
5196 scoped_ptr<SpdyFrame> stream2_syn(
5197 spdy_util_.ConstructInitialSpdyPushFrame(initial_headers.Pass(), 2, 1));
5198
5199 scoped_ptr<SpdyHeaderBlock> late_headers(new SpdyHeaderBlock());
5200 (*late_headers)["hello"] = "bye";
5201 (*late_headers)[spdy_util_.GetStatusKey()] = "200";
5202 (*late_headers)[spdy_util_.GetVersionKey()] = "HTTP/1.1";
5203 scoped_ptr<SpdyFrame> stream2_headers(
5204 spdy_util_.ConstructSpdyControlFrame(late_headers.Pass(),
5205 false,
5206 2,
5207 LOWEST,
5208 HEADERS,
5209 CONTROL_FLAG_NONE,
5210 0));
5211
5212 scoped_ptr<SpdyFrame>
5213 stream1_reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
5214 const char kPushedData[] = "pushed";
5215 scoped_ptr<SpdyFrame> stream2_body(
5216 spdy_util_.ConstructSpdyBodyFrame(
5217 2, kPushedData, strlen(kPushedData), true));
5218 MockRead reads[] = {
5219 CreateMockRead(*stream1_reply, 2),
5220 CreateMockRead(*stream2_syn, 3),
5221 CreateMockRead(*stream2_headers, 4),
5222 CreateMockRead(*stream1_body, 5, SYNCHRONOUS),
5223 CreateMockRead(*stream2_body, 5),
5224 MockRead(ASYNC, ERR_IO_PENDING, 7), // Force a pause
5225 };
5226
5227 HttpResponseInfo response;
5228 HttpResponseInfo response2;
5229 std::string expected_push_result("pushed");
5230 OrderedSocketData data(reads, arraysize(reads),
5231 writes, arraysize(writes));
5232 RunServerPushTest(&data,
5233 &response,
5234 &response2,
5235 expected_push_result);
5236
5237 // Verify the SYN_REPLY.
5238 EXPECT_TRUE(response.headers.get() != NULL);
5239 EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine());
5240
5241 // Verify the pushed stream.
5242 EXPECT_TRUE(response2.headers.get() != NULL);
5243 EXPECT_EQ("HTTP/1.1 200 OK", response2.headers->GetStatusLine());
5244 }
5245
TEST_P(SpdyNetworkTransactionTest,ServerPushClaimBeforeHeaders)5246 TEST_P(SpdyNetworkTransactionTest, ServerPushClaimBeforeHeaders) {
5247 // We push a stream and attempt to claim it before the headers come down.
5248 scoped_ptr<SpdyFrame> stream1_syn(
5249 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
5250 scoped_ptr<SpdyFrame> stream1_body(
5251 spdy_util_.ConstructSpdyBodyFrame(1, true));
5252 MockWrite writes[] = {
5253 CreateMockWrite(*stream1_syn, 0, SYNCHRONOUS),
5254 };
5255
5256 scoped_ptr<SpdyHeaderBlock> initial_headers(new SpdyHeaderBlock());
5257 spdy_util_.AddUrlToHeaderBlock(
5258 "http://www.google.com/foo.dat", initial_headers.get());
5259 scoped_ptr<SpdyFrame> stream2_syn(
5260 spdy_util_.ConstructInitialSpdyPushFrame(initial_headers.Pass(), 2, 1));
5261
5262 scoped_ptr<SpdyHeaderBlock> late_headers(new SpdyHeaderBlock());
5263 (*late_headers)["hello"] = "bye";
5264 (*late_headers)[spdy_util_.GetStatusKey()] = "200";
5265 (*late_headers)[spdy_util_.GetVersionKey()] = "HTTP/1.1";
5266 scoped_ptr<SpdyFrame> stream2_headers(
5267 spdy_util_.ConstructSpdyControlFrame(late_headers.Pass(),
5268 false,
5269 2,
5270 LOWEST,
5271 HEADERS,
5272 CONTROL_FLAG_NONE,
5273 0));
5274
5275 scoped_ptr<SpdyFrame>
5276 stream1_reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
5277 const char kPushedData[] = "pushed";
5278 scoped_ptr<SpdyFrame> stream2_body(
5279 spdy_util_.ConstructSpdyBodyFrame(
5280 2, kPushedData, strlen(kPushedData), true));
5281 MockRead reads[] = {
5282 CreateMockRead(*stream1_reply, 1),
5283 CreateMockRead(*stream2_syn, 2),
5284 CreateMockRead(*stream1_body, 3),
5285 CreateMockRead(*stream2_headers, 4),
5286 CreateMockRead(*stream2_body, 5),
5287 MockRead(ASYNC, 0, 6), // EOF
5288 };
5289
5290 HttpResponseInfo response;
5291 HttpResponseInfo response2;
5292 std::string expected_push_result("pushed");
5293 DeterministicSocketData data(reads, arraysize(reads),
5294 writes, arraysize(writes));
5295
5296 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
5297 BoundNetLog(), GetParam(), NULL);
5298 helper.SetDeterministic();
5299 helper.AddDeterministicData(&data);
5300 helper.RunPreTestSetup();
5301
5302 HttpNetworkTransaction* trans = helper.trans();
5303
5304 // Run until we've received the primary SYN_STREAM, the pushed SYN_STREAM,
5305 // and the body of the primary stream, but before we've received the HEADERS
5306 // for the pushed stream.
5307 data.SetStop(3);
5308
5309 // Start the transaction.
5310 TestCompletionCallback callback;
5311 int rv = trans->Start(
5312 &CreateGetRequest(), callback.callback(), BoundNetLog());
5313 EXPECT_EQ(ERR_IO_PENDING, rv);
5314 data.Run();
5315 rv = callback.WaitForResult();
5316 EXPECT_EQ(0, rv);
5317
5318 // Request the pushed path. At this point, we've received the push, but the
5319 // headers are not yet complete.
5320 scoped_ptr<HttpNetworkTransaction> trans2(
5321 new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get()));
5322 rv = trans2->Start(
5323 &CreateGetPushRequest(), callback.callback(), BoundNetLog());
5324 EXPECT_EQ(ERR_IO_PENDING, rv);
5325 data.RunFor(3);
5326 base::RunLoop().RunUntilIdle();
5327
5328 // Read the server push body.
5329 std::string result2;
5330 ReadResult(trans2.get(), &data, &result2);
5331 // Read the response body.
5332 std::string result;
5333 ReadResult(trans, &data, &result);
5334
5335 // Verify that the received push data is same as the expected push data.
5336 EXPECT_EQ(result2.compare(expected_push_result), 0)
5337 << "Received data: "
5338 << result2
5339 << "||||| Expected data: "
5340 << expected_push_result;
5341
5342 // Verify the SYN_REPLY.
5343 // Copy the response info, because trans goes away.
5344 response = *trans->GetResponseInfo();
5345 response2 = *trans2->GetResponseInfo();
5346
5347 VerifyStreamsClosed(helper);
5348
5349 // Verify the SYN_REPLY.
5350 EXPECT_TRUE(response.headers.get() != NULL);
5351 EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine());
5352
5353 // Verify the pushed stream.
5354 EXPECT_TRUE(response2.headers.get() != NULL);
5355 EXPECT_EQ("HTTP/1.1 200 OK", response2.headers->GetStatusLine());
5356
5357 // Read the final EOF (which will close the session)
5358 data.RunFor(1);
5359
5360 // Verify that we consumed all test data.
5361 EXPECT_TRUE(data.at_read_eof());
5362 EXPECT_TRUE(data.at_write_eof());
5363 }
5364
5365 // TODO(baranovich): HTTP 2 does not allow multiple HEADERS frames
TEST_P(SpdyNetworkTransactionTest,ServerPushWithTwoHeaderFrames)5366 TEST_P(SpdyNetworkTransactionTest, ServerPushWithTwoHeaderFrames) {
5367 // We push a stream and attempt to claim it before the headers come down.
5368 scoped_ptr<SpdyFrame> stream1_syn(
5369 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
5370 scoped_ptr<SpdyFrame> stream1_body(
5371 spdy_util_.ConstructSpdyBodyFrame(1, true));
5372 MockWrite writes[] = {
5373 CreateMockWrite(*stream1_syn, 0, SYNCHRONOUS),
5374 };
5375
5376 scoped_ptr<SpdyHeaderBlock> initial_headers(new SpdyHeaderBlock());
5377 if (spdy_util_.spdy_version() < SPDY4) {
5378 // In SPDY4 PUSH_PROMISE headers won't show up in the response headers.
5379 (*initial_headers)["alpha"] = "beta";
5380 }
5381 spdy_util_.AddUrlToHeaderBlock(
5382 "http://www.google.com/foo.dat", initial_headers.get());
5383 scoped_ptr<SpdyFrame> stream2_syn(
5384 spdy_util_.ConstructInitialSpdyPushFrame(initial_headers.Pass(), 2, 1));
5385
5386 scoped_ptr<SpdyHeaderBlock> middle_headers(new SpdyHeaderBlock());
5387 (*middle_headers)["hello"] = "bye";
5388 scoped_ptr<SpdyFrame> stream2_headers1(
5389 spdy_util_.ConstructSpdyControlFrame(middle_headers.Pass(),
5390 false,
5391 2,
5392 LOWEST,
5393 HEADERS,
5394 CONTROL_FLAG_NONE,
5395 0));
5396
5397 scoped_ptr<SpdyHeaderBlock> late_headers(new SpdyHeaderBlock());
5398 (*late_headers)[spdy_util_.GetStatusKey()] = "200";
5399 if (spdy_util_.spdy_version() < SPDY4) {
5400 // SPDY4/HTTP2 eliminates use of the :version header.
5401 (*late_headers)[spdy_util_.GetVersionKey()] = "HTTP/1.1";
5402 }
5403 scoped_ptr<SpdyFrame> stream2_headers2(
5404 spdy_util_.ConstructSpdyControlFrame(late_headers.Pass(),
5405 false,
5406 2,
5407 LOWEST,
5408 HEADERS,
5409 CONTROL_FLAG_NONE,
5410 0));
5411
5412 scoped_ptr<SpdyFrame>
5413 stream1_reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
5414 const char kPushedData[] = "pushed";
5415 scoped_ptr<SpdyFrame> stream2_body(
5416 spdy_util_.ConstructSpdyBodyFrame(
5417 2, kPushedData, strlen(kPushedData), true));
5418 MockRead reads[] = {
5419 CreateMockRead(*stream1_reply, 1),
5420 CreateMockRead(*stream2_syn, 2),
5421 CreateMockRead(*stream1_body, 3),
5422 CreateMockRead(*stream2_headers1, 4),
5423 CreateMockRead(*stream2_headers2, 5),
5424 CreateMockRead(*stream2_body, 6),
5425 MockRead(ASYNC, 0, 7), // EOF
5426 };
5427
5428 HttpResponseInfo response;
5429 HttpResponseInfo response2;
5430 std::string expected_push_result("pushed");
5431 DeterministicSocketData data(reads, arraysize(reads),
5432 writes, arraysize(writes));
5433
5434 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
5435 BoundNetLog(), GetParam(), NULL);
5436 helper.SetDeterministic();
5437 helper.AddDeterministicData(&data);
5438 helper.RunPreTestSetup();
5439
5440 HttpNetworkTransaction* trans = helper.trans();
5441
5442 // Run until we've received the primary SYN_STREAM, the pushed SYN_STREAM,
5443 // the first HEADERS frame, and the body of the primary stream, but before
5444 // we've received the final HEADERS for the pushed stream.
5445 data.SetStop(4);
5446
5447 // Start the transaction.
5448 TestCompletionCallback callback;
5449 int rv = trans->Start(
5450 &CreateGetRequest(), callback.callback(), BoundNetLog());
5451 EXPECT_EQ(ERR_IO_PENDING, rv);
5452 data.Run();
5453 rv = callback.WaitForResult();
5454 EXPECT_EQ(0, rv);
5455
5456 // Request the pushed path. At this point, we've received the push, but the
5457 // headers are not yet complete.
5458 scoped_ptr<HttpNetworkTransaction> trans2(
5459 new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get()));
5460 rv = trans2->Start(
5461 &CreateGetPushRequest(), callback.callback(), BoundNetLog());
5462 EXPECT_EQ(ERR_IO_PENDING, rv);
5463 data.RunFor(3);
5464 base::RunLoop().RunUntilIdle();
5465
5466 // Read the server push body.
5467 std::string result2;
5468 ReadResult(trans2.get(), &data, &result2);
5469 // Read the response body.
5470 std::string result;
5471 ReadResult(trans, &data, &result);
5472
5473 // Verify that the received push data is same as the expected push data.
5474 EXPECT_EQ(expected_push_result, result2);
5475
5476 // Verify the SYN_REPLY.
5477 // Copy the response info, because trans goes away.
5478 response = *trans->GetResponseInfo();
5479 response2 = *trans2->GetResponseInfo();
5480
5481 VerifyStreamsClosed(helper);
5482
5483 // Verify the SYN_REPLY.
5484 EXPECT_TRUE(response.headers.get() != NULL);
5485 EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine());
5486
5487 // Verify the pushed stream.
5488 EXPECT_TRUE(response2.headers.get() != NULL);
5489 EXPECT_EQ("HTTP/1.1 200 OK", response2.headers->GetStatusLine());
5490
5491 // Verify we got all the headers from all header blocks.
5492 if (spdy_util_.spdy_version() < SPDY4)
5493 EXPECT_TRUE(response2.headers->HasHeaderValue("alpha", "beta"));
5494 EXPECT_TRUE(response2.headers->HasHeaderValue("hello", "bye"));
5495 EXPECT_TRUE(response2.headers->HasHeaderValue("status", "200"));
5496
5497 // Read the final EOF (which will close the session)
5498 data.RunFor(1);
5499
5500 // Verify that we consumed all test data.
5501 EXPECT_TRUE(data.at_read_eof());
5502 EXPECT_TRUE(data.at_write_eof());
5503 }
5504
TEST_P(SpdyNetworkTransactionTest,ServerPushWithNoStatusHeaderFrames)5505 TEST_P(SpdyNetworkTransactionTest, ServerPushWithNoStatusHeaderFrames) {
5506 // We push a stream and attempt to claim it before the headers come down.
5507 scoped_ptr<SpdyFrame> stream1_syn(
5508 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
5509 scoped_ptr<SpdyFrame> stream1_body(
5510 spdy_util_.ConstructSpdyBodyFrame(1, true));
5511 MockWrite writes[] = {
5512 CreateMockWrite(*stream1_syn, 0, SYNCHRONOUS),
5513 };
5514
5515 scoped_ptr<SpdyHeaderBlock> initial_headers(new SpdyHeaderBlock());
5516 spdy_util_.AddUrlToHeaderBlock(
5517 "http://www.google.com/foo.dat", initial_headers.get());
5518 scoped_ptr<SpdyFrame> stream2_syn(
5519 spdy_util_.ConstructInitialSpdyPushFrame(initial_headers.Pass(), 2, 1));
5520
5521 scoped_ptr<SpdyHeaderBlock> middle_headers(new SpdyHeaderBlock());
5522 (*middle_headers)["hello"] = "bye";
5523 scoped_ptr<SpdyFrame> stream2_headers1(
5524 spdy_util_.ConstructSpdyControlFrame(middle_headers.Pass(),
5525 false,
5526 2,
5527 LOWEST,
5528 HEADERS,
5529 CONTROL_FLAG_NONE,
5530 0));
5531
5532 scoped_ptr<SpdyFrame>
5533 stream1_reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
5534 const char kPushedData[] = "pushed";
5535 scoped_ptr<SpdyFrame> stream2_body(
5536 spdy_util_.ConstructSpdyBodyFrame(
5537 2, kPushedData, strlen(kPushedData), true));
5538 MockRead reads[] = {
5539 CreateMockRead(*stream1_reply, 1),
5540 CreateMockRead(*stream2_syn, 2),
5541 CreateMockRead(*stream1_body, 3),
5542 CreateMockRead(*stream2_headers1, 4),
5543 CreateMockRead(*stream2_body, 5),
5544 MockRead(ASYNC, 0, 6), // EOF
5545 };
5546
5547 DeterministicSocketData data(reads, arraysize(reads),
5548 writes, arraysize(writes));
5549
5550 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
5551 BoundNetLog(), GetParam(), NULL);
5552 helper.SetDeterministic();
5553 helper.AddDeterministicData(&data);
5554 helper.RunPreTestSetup();
5555
5556 HttpNetworkTransaction* trans = helper.trans();
5557
5558 // Run until we've received the primary SYN_STREAM, the pushed SYN_STREAM,
5559 // the first HEADERS frame, and the body of the primary stream, but before
5560 // we've received the final HEADERS for the pushed stream.
5561 data.SetStop(4);
5562
5563 // Start the transaction.
5564 TestCompletionCallback callback;
5565 int rv = trans->Start(
5566 &CreateGetRequest(), callback.callback(), BoundNetLog());
5567 EXPECT_EQ(ERR_IO_PENDING, rv);
5568 data.Run();
5569 rv = callback.WaitForResult();
5570 EXPECT_EQ(0, rv);
5571
5572 // Request the pushed path. At this point, we've received the push, but the
5573 // headers are not yet complete.
5574 scoped_ptr<HttpNetworkTransaction> trans2(
5575 new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get()));
5576 rv = trans2->Start(
5577 &CreateGetPushRequest(), callback.callback(), BoundNetLog());
5578 EXPECT_EQ(ERR_IO_PENDING, rv);
5579 data.RunFor(2);
5580 base::RunLoop().RunUntilIdle();
5581
5582 // Read the server push body.
5583 std::string result2;
5584 ReadResult(trans2.get(), &data, &result2);
5585 // Read the response body.
5586 std::string result;
5587 ReadResult(trans, &data, &result);
5588 EXPECT_EQ("hello!", result);
5589
5590 // Verify that we haven't received any push data.
5591 EXPECT_EQ("", result2);
5592
5593 // Verify the SYN_REPLY.
5594 // Copy the response info, because trans goes away.
5595 HttpResponseInfo response = *trans->GetResponseInfo();
5596 ASSERT_TRUE(trans2->GetResponseInfo() == NULL);
5597
5598 VerifyStreamsClosed(helper);
5599
5600 // Verify the SYN_REPLY.
5601 EXPECT_TRUE(response.headers.get() != NULL);
5602 EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine());
5603
5604 // Read the final EOF (which will close the session).
5605 data.RunFor(1);
5606
5607 // Verify that we consumed all test data.
5608 EXPECT_TRUE(data.at_read_eof());
5609 EXPECT_TRUE(data.at_write_eof());
5610 }
5611
TEST_P(SpdyNetworkTransactionTest,SynReplyWithHeaders)5612 TEST_P(SpdyNetworkTransactionTest, SynReplyWithHeaders) {
5613 scoped_ptr<SpdyFrame> req(
5614 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
5615 scoped_ptr<SpdyFrame> rst(
5616 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR));
5617 MockWrite writes[] = {
5618 CreateMockWrite(*req),
5619 CreateMockWrite(*rst),
5620 };
5621
5622 scoped_ptr<SpdyHeaderBlock> initial_headers(new SpdyHeaderBlock());
5623 (*initial_headers)[spdy_util_.GetStatusKey()] = "200 OK";
5624 (*initial_headers)[spdy_util_.GetVersionKey()] = "HTTP/1.1";
5625 scoped_ptr<SpdyFrame> stream1_reply(
5626 spdy_util_.ConstructSpdyControlFrame(initial_headers.Pass(),
5627 false,
5628 1,
5629 LOWEST,
5630 SYN_REPLY,
5631 CONTROL_FLAG_NONE,
5632 0));
5633
5634 scoped_ptr<SpdyHeaderBlock> late_headers(new SpdyHeaderBlock());
5635 (*late_headers)["hello"] = "bye";
5636 scoped_ptr<SpdyFrame> stream1_headers(
5637 spdy_util_.ConstructSpdyControlFrame(late_headers.Pass(),
5638 false,
5639 1,
5640 LOWEST,
5641 HEADERS,
5642 CONTROL_FLAG_NONE,
5643 0));
5644 scoped_ptr<SpdyFrame> stream1_body(
5645 spdy_util_.ConstructSpdyBodyFrame(1, true));
5646 MockRead reads[] = {
5647 CreateMockRead(*stream1_reply),
5648 CreateMockRead(*stream1_headers),
5649 CreateMockRead(*stream1_body),
5650 MockRead(ASYNC, 0, 0) // EOF
5651 };
5652
5653 DelayedSocketData data(1, reads, arraysize(reads),
5654 writes, arraysize(writes));
5655 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
5656 BoundNetLog(), GetParam(), NULL);
5657 helper.RunToCompletion(&data);
5658 TransactionHelperResult out = helper.output();
5659 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, out.rv);
5660 }
5661
TEST_P(SpdyNetworkTransactionTest,SynReplyWithLateHeaders)5662 TEST_P(SpdyNetworkTransactionTest, SynReplyWithLateHeaders) {
5663 scoped_ptr<SpdyFrame> req(
5664 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
5665 scoped_ptr<SpdyFrame> rst(
5666 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR));
5667 MockWrite writes[] = {
5668 CreateMockWrite(*req),
5669 CreateMockWrite(*rst),
5670 };
5671
5672 scoped_ptr<SpdyHeaderBlock> initial_headers(new SpdyHeaderBlock());
5673 (*initial_headers)[spdy_util_.GetStatusKey()] = "200 OK";
5674 (*initial_headers)[spdy_util_.GetVersionKey()] = "HTTP/1.1";
5675 scoped_ptr<SpdyFrame> stream1_reply(
5676 spdy_util_.ConstructSpdyControlFrame(initial_headers.Pass(),
5677 false,
5678 1,
5679 LOWEST,
5680 SYN_REPLY,
5681 CONTROL_FLAG_NONE,
5682 0));
5683
5684 scoped_ptr<SpdyHeaderBlock> late_headers(new SpdyHeaderBlock());
5685 (*late_headers)["hello"] = "bye";
5686 scoped_ptr<SpdyFrame> stream1_headers(
5687 spdy_util_.ConstructSpdyControlFrame(late_headers.Pass(),
5688 false,
5689 1,
5690 LOWEST,
5691 HEADERS,
5692 CONTROL_FLAG_NONE,
5693 0));
5694 scoped_ptr<SpdyFrame> stream1_body(
5695 spdy_util_.ConstructSpdyBodyFrame(1, false));
5696 scoped_ptr<SpdyFrame> stream1_body2(
5697 spdy_util_.ConstructSpdyBodyFrame(1, true));
5698 MockRead reads[] = {
5699 CreateMockRead(*stream1_reply),
5700 CreateMockRead(*stream1_body),
5701 CreateMockRead(*stream1_headers),
5702 CreateMockRead(*stream1_body2),
5703 MockRead(ASYNC, 0, 0) // EOF
5704 };
5705
5706 DelayedSocketData data(1, reads, arraysize(reads),
5707 writes, arraysize(writes));
5708 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
5709 BoundNetLog(), GetParam(), NULL);
5710 helper.RunToCompletion(&data);
5711 TransactionHelperResult out = helper.output();
5712 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, out.rv);
5713 }
5714
TEST_P(SpdyNetworkTransactionTest,ServerPushCrossOriginCorrectness)5715 TEST_P(SpdyNetworkTransactionTest, ServerPushCrossOriginCorrectness) {
5716 // In this test we want to verify that we can't accidentally push content
5717 // which can't be pushed by this content server.
5718 // This test assumes that:
5719 // - if we're requesting http://www.foo.com/barbaz
5720 // - the browser has made a connection to "www.foo.com".
5721
5722 // A list of the URL to fetch, followed by the URL being pushed.
5723 static const char* const kTestCases[] = {
5724 "http://www.google.com/foo.html",
5725 "http://www.google.com:81/foo.js", // Bad port
5726
5727 "http://www.google.com/foo.html",
5728 "https://www.google.com/foo.js", // Bad protocol
5729
5730 "http://www.google.com/foo.html",
5731 "ftp://www.google.com/foo.js", // Invalid Protocol
5732
5733 "http://www.google.com/foo.html",
5734 "http://blat.www.google.com/foo.js", // Cross subdomain
5735
5736 "http://www.google.com/foo.html",
5737 "http://www.foo.com/foo.js", // Cross domain
5738 };
5739
5740 for (size_t index = 0; index < arraysize(kTestCases); index += 2) {
5741 const char* url_to_fetch = kTestCases[index];
5742 const char* url_to_push = kTestCases[index + 1];
5743
5744 scoped_ptr<SpdyFrame> stream1_syn(
5745 spdy_util_.ConstructSpdyGet(url_to_fetch, false, 1, LOWEST));
5746 scoped_ptr<SpdyFrame> stream1_body(
5747 spdy_util_.ConstructSpdyBodyFrame(1, true));
5748 scoped_ptr<SpdyFrame> push_rst(
5749 spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_REFUSED_STREAM));
5750 MockWrite writes[] = {
5751 CreateMockWrite(*stream1_syn, 1),
5752 CreateMockWrite(*push_rst, 4),
5753 };
5754
5755 scoped_ptr<SpdyFrame>
5756 stream1_reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
5757 scoped_ptr<SpdyFrame>
5758 stream2_syn(spdy_util_.ConstructSpdyPush(NULL,
5759 0,
5760 2,
5761 1,
5762 url_to_push));
5763 const char kPushedData[] = "pushed";
5764 scoped_ptr<SpdyFrame> stream2_body(
5765 spdy_util_.ConstructSpdyBodyFrame(
5766 2, kPushedData, strlen(kPushedData), true));
5767 scoped_ptr<SpdyFrame> rst(
5768 spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_CANCEL));
5769
5770 MockRead reads[] = {
5771 CreateMockRead(*stream1_reply, 2),
5772 CreateMockRead(*stream2_syn, 3),
5773 CreateMockRead(*stream1_body, 5, SYNCHRONOUS),
5774 CreateMockRead(*stream2_body, 6),
5775 MockRead(ASYNC, ERR_IO_PENDING, 7), // Force a pause
5776 };
5777
5778 HttpResponseInfo response;
5779 OrderedSocketData data(reads, arraysize(reads),
5780 writes, arraysize(writes));
5781
5782 HttpRequestInfo request;
5783 request.method = "GET";
5784 request.url = GURL(url_to_fetch);
5785 request.load_flags = 0;
5786
5787 // Enable cross-origin push. Since we are not using a proxy, this should
5788 // not actually enable cross-origin SPDY push.
5789 scoped_ptr<SpdySessionDependencies> session_deps(
5790 CreateSpdySessionDependencies(GetParam()));
5791 session_deps->trusted_spdy_proxy = "123.45.67.89:8080";
5792 NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY,
5793 BoundNetLog(), GetParam(),
5794 session_deps.release());
5795 helper.RunPreTestSetup();
5796 helper.AddData(&data);
5797
5798 HttpNetworkTransaction* trans = helper.trans();
5799
5800 // Start the transaction with basic parameters.
5801 TestCompletionCallback callback;
5802
5803 int rv = trans->Start(&request, callback.callback(), BoundNetLog());
5804 EXPECT_EQ(ERR_IO_PENDING, rv);
5805 rv = callback.WaitForResult();
5806
5807 // Read the response body.
5808 std::string result;
5809 ReadResult(trans, &data, &result);
5810
5811 // Verify that we consumed all test data.
5812 EXPECT_TRUE(data.at_read_eof());
5813 EXPECT_TRUE(data.at_write_eof());
5814
5815 // Verify the SYN_REPLY.
5816 // Copy the response info, because trans goes away.
5817 response = *trans->GetResponseInfo();
5818
5819 VerifyStreamsClosed(helper);
5820
5821 // Verify the SYN_REPLY.
5822 EXPECT_TRUE(response.headers.get() != NULL);
5823 EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine());
5824 }
5825 }
5826
TEST_P(SpdyNetworkTransactionTest,RetryAfterRefused)5827 TEST_P(SpdyNetworkTransactionTest, RetryAfterRefused) {
5828 // Construct the request.
5829 scoped_ptr<SpdyFrame> req(
5830 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
5831 scoped_ptr<SpdyFrame> req2(
5832 spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, LOWEST, true));
5833 MockWrite writes[] = {
5834 CreateMockWrite(*req, 1),
5835 CreateMockWrite(*req2, 3),
5836 };
5837
5838 scoped_ptr<SpdyFrame> refused(
5839 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_REFUSED_STREAM));
5840 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3));
5841 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(3, true));
5842 MockRead reads[] = {
5843 CreateMockRead(*refused, 2),
5844 CreateMockRead(*resp, 4),
5845 CreateMockRead(*body, 5),
5846 MockRead(ASYNC, 0, 6) // EOF
5847 };
5848
5849 OrderedSocketData data(reads, arraysize(reads),
5850 writes, arraysize(writes));
5851 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
5852 BoundNetLog(), GetParam(), NULL);
5853
5854 helper.RunPreTestSetup();
5855 helper.AddData(&data);
5856
5857 HttpNetworkTransaction* trans = helper.trans();
5858
5859 // Start the transaction with basic parameters.
5860 TestCompletionCallback callback;
5861 int rv = trans->Start(
5862 &CreateGetRequest(), callback.callback(), BoundNetLog());
5863 EXPECT_EQ(ERR_IO_PENDING, rv);
5864 rv = callback.WaitForResult();
5865 EXPECT_EQ(OK, rv);
5866
5867 // Verify that we consumed all test data.
5868 EXPECT_TRUE(data.at_read_eof()) << "Read count: "
5869 << data.read_count()
5870 << " Read index: "
5871 << data.read_index();
5872 EXPECT_TRUE(data.at_write_eof()) << "Write count: "
5873 << data.write_count()
5874 << " Write index: "
5875 << data.write_index();
5876
5877 // Verify the SYN_REPLY.
5878 HttpResponseInfo response = *trans->GetResponseInfo();
5879 EXPECT_TRUE(response.headers.get() != NULL);
5880 EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine());
5881 }
5882
TEST_P(SpdyNetworkTransactionTest,OutOfOrderSynStream)5883 TEST_P(SpdyNetworkTransactionTest, OutOfOrderSynStream) {
5884 // This first request will start to establish the SpdySession.
5885 // Then we will start the second (MEDIUM priority) and then third
5886 // (HIGHEST priority) request in such a way that the third will actually
5887 // start before the second, causing the second to be numbered differently
5888 // than the order they were created.
5889 scoped_ptr<SpdyFrame> req1(
5890 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
5891 scoped_ptr<SpdyFrame> req2(
5892 spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, HIGHEST, true));
5893 scoped_ptr<SpdyFrame> req3(
5894 spdy_util_.ConstructSpdyGet(NULL, 0, false, 5, MEDIUM, true));
5895 MockWrite writes[] = {
5896 CreateMockWrite(*req1, 0),
5897 CreateMockWrite(*req2, 3),
5898 CreateMockWrite(*req3, 4),
5899 };
5900
5901 scoped_ptr<SpdyFrame> resp1(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
5902 scoped_ptr<SpdyFrame> body1(spdy_util_.ConstructSpdyBodyFrame(1, true));
5903 scoped_ptr<SpdyFrame> resp2(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3));
5904 scoped_ptr<SpdyFrame> body2(spdy_util_.ConstructSpdyBodyFrame(3, true));
5905 scoped_ptr<SpdyFrame> resp3(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 5));
5906 scoped_ptr<SpdyFrame> body3(spdy_util_.ConstructSpdyBodyFrame(5, true));
5907 MockRead reads[] = {
5908 CreateMockRead(*resp1, 1),
5909 CreateMockRead(*body1, 2),
5910 CreateMockRead(*resp2, 5),
5911 CreateMockRead(*body2, 6),
5912 CreateMockRead(*resp3, 7),
5913 CreateMockRead(*body3, 8),
5914 MockRead(ASYNC, 0, 9) // EOF
5915 };
5916
5917 DeterministicSocketData data(reads, arraysize(reads),
5918 writes, arraysize(writes));
5919 NormalSpdyTransactionHelper helper(CreateGetRequest(), LOWEST,
5920 BoundNetLog(), GetParam(), NULL);
5921 helper.SetDeterministic();
5922 helper.RunPreTestSetup();
5923 helper.AddDeterministicData(&data);
5924
5925 // Start the first transaction to set up the SpdySession
5926 HttpNetworkTransaction* trans = helper.trans();
5927 TestCompletionCallback callback;
5928 HttpRequestInfo info1 = CreateGetRequest();
5929 int rv = trans->Start(&info1, callback.callback(), BoundNetLog());
5930 EXPECT_EQ(ERR_IO_PENDING, rv);
5931
5932 // Run the message loop, but do not allow the write to complete.
5933 // This leaves the SpdySession with a write pending, which prevents
5934 // SpdySession from attempting subsequent writes until this write completes.
5935 base::RunLoop().RunUntilIdle();
5936
5937 // Now, start both new transactions
5938 HttpRequestInfo info2 = CreateGetRequest();
5939 TestCompletionCallback callback2;
5940 scoped_ptr<HttpNetworkTransaction> trans2(
5941 new HttpNetworkTransaction(MEDIUM, helper.session().get()));
5942 rv = trans2->Start(&info2, callback2.callback(), BoundNetLog());
5943 EXPECT_EQ(ERR_IO_PENDING, rv);
5944 base::RunLoop().RunUntilIdle();
5945
5946 HttpRequestInfo info3 = CreateGetRequest();
5947 TestCompletionCallback callback3;
5948 scoped_ptr<HttpNetworkTransaction> trans3(
5949 new HttpNetworkTransaction(HIGHEST, helper.session().get()));
5950 rv = trans3->Start(&info3, callback3.callback(), BoundNetLog());
5951 EXPECT_EQ(ERR_IO_PENDING, rv);
5952 base::RunLoop().RunUntilIdle();
5953
5954 // We now have two SYN_STREAM frames queued up which will be
5955 // dequeued only once the first write completes, which we
5956 // now allow to happen.
5957 data.RunFor(2);
5958 EXPECT_EQ(OK, callback.WaitForResult());
5959
5960 // And now we can allow everything else to run to completion.
5961 data.SetStop(10);
5962 data.Run();
5963 EXPECT_EQ(OK, callback2.WaitForResult());
5964 EXPECT_EQ(OK, callback3.WaitForResult());
5965
5966 helper.VerifyDataConsumed();
5967 }
5968
5969 // The tests below are only for SPDY/3 and above.
5970
5971 // Test that sent data frames and received WINDOW_UPDATE frames change
5972 // the send_window_size_ correctly.
5973
5974 // WINDOW_UPDATE is different than most other frames in that it can arrive
5975 // while the client is still sending the request body. In order to enforce
5976 // this scenario, we feed a couple of dummy frames and give a delay of 0 to
5977 // socket data provider, so that initial read that is done as soon as the
5978 // stream is created, succeeds and schedules another read. This way reads
5979 // and writes are interleaved; after doing a full frame write, SpdyStream
5980 // will break out of DoLoop and will read and process a WINDOW_UPDATE.
5981 // Once our WINDOW_UPDATE is read, we cannot send SYN_REPLY right away
5982 // since request has not been completely written, therefore we feed
5983 // enough number of WINDOW_UPDATEs to finish the first read and cause a
5984 // write, leading to a complete write of request body; after that we send
5985 // a reply with a body, to cause a graceful shutdown.
5986
5987 // TODO(agayev): develop a socket data provider where both, reads and
5988 // writes are ordered so that writing tests like these are easy and rewrite
5989 // all these tests using it. Right now we are working around the
5990 // limitations as described above and it's not deterministic, tests may
5991 // fail under specific circumstances.
TEST_P(SpdyNetworkTransactionTest,WindowUpdateReceived)5992 TEST_P(SpdyNetworkTransactionTest, WindowUpdateReceived) {
5993 if (GetParam().protocol < kProtoSPDY3)
5994 return;
5995
5996 static int kFrameCount = 2;
5997 scoped_ptr<std::string> content(
5998 new std::string(kMaxSpdyFrameChunkSize, 'a'));
5999 scoped_ptr<SpdyFrame> req(spdy_util_.ConstructSpdyPost(
6000 kRequestUrl, 1, kMaxSpdyFrameChunkSize * kFrameCount, LOWEST, NULL, 0));
6001 scoped_ptr<SpdyFrame> body(
6002 spdy_util_.ConstructSpdyBodyFrame(
6003 1, content->c_str(), content->size(), false));
6004 scoped_ptr<SpdyFrame> body_end(
6005 spdy_util_.ConstructSpdyBodyFrame(
6006 1, content->c_str(), content->size(), true));
6007
6008 MockWrite writes[] = {
6009 CreateMockWrite(*req, 0),
6010 CreateMockWrite(*body, 1),
6011 CreateMockWrite(*body_end, 2),
6012 };
6013
6014 static const int32 kDeltaWindowSize = 0xff;
6015 static const int kDeltaCount = 4;
6016 scoped_ptr<SpdyFrame> window_update(
6017 spdy_util_.ConstructSpdyWindowUpdate(1, kDeltaWindowSize));
6018 scoped_ptr<SpdyFrame> window_update_dummy(
6019 spdy_util_.ConstructSpdyWindowUpdate(2, kDeltaWindowSize));
6020 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
6021 MockRead reads[] = {
6022 CreateMockRead(*window_update_dummy, 3),
6023 CreateMockRead(*window_update_dummy, 4),
6024 CreateMockRead(*window_update_dummy, 5),
6025 CreateMockRead(*window_update, 6), // Four updates, therefore window
6026 CreateMockRead(*window_update, 7), // size should increase by
6027 CreateMockRead(*window_update, 8), // kDeltaWindowSize * 4
6028 CreateMockRead(*window_update, 9),
6029 CreateMockRead(*resp, 10),
6030 CreateMockRead(*body_end, 11),
6031 MockRead(ASYNC, 0, 0, 12) // EOF
6032 };
6033
6034 DeterministicSocketData data(reads, arraysize(reads),
6035 writes, arraysize(writes));
6036
6037 ScopedVector<UploadElementReader> element_readers;
6038 for (int i = 0; i < kFrameCount; ++i) {
6039 element_readers.push_back(
6040 new UploadBytesElementReader(content->c_str(), content->size()));
6041 }
6042 UploadDataStream upload_data_stream(element_readers.Pass(), 0);
6043
6044 // Setup the request
6045 HttpRequestInfo request;
6046 request.method = "POST";
6047 request.url = GURL(kDefaultURL);
6048 request.upload_data_stream = &upload_data_stream;
6049
6050 NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY,
6051 BoundNetLog(), GetParam(), NULL);
6052 helper.SetDeterministic();
6053 helper.AddDeterministicData(&data);
6054 helper.RunPreTestSetup();
6055
6056 HttpNetworkTransaction* trans = helper.trans();
6057
6058 TestCompletionCallback callback;
6059 int rv = trans->Start(&helper.request(), callback.callback(), BoundNetLog());
6060
6061 EXPECT_EQ(ERR_IO_PENDING, rv);
6062
6063 data.RunFor(11);
6064
6065 SpdyHttpStream* stream = static_cast<SpdyHttpStream*>(trans->stream_.get());
6066 ASSERT_TRUE(stream != NULL);
6067 ASSERT_TRUE(stream->stream() != NULL);
6068 EXPECT_EQ(static_cast<int>(kSpdyStreamInitialWindowSize) +
6069 kDeltaWindowSize * kDeltaCount -
6070 kMaxSpdyFrameChunkSize * kFrameCount,
6071 stream->stream()->send_window_size());
6072
6073 data.RunFor(1);
6074
6075 rv = callback.WaitForResult();
6076 EXPECT_EQ(OK, rv);
6077
6078 helper.VerifyDataConsumed();
6079 }
6080
6081 // Test that received data frames and sent WINDOW_UPDATE frames change
6082 // the recv_window_size_ correctly.
TEST_P(SpdyNetworkTransactionTest,WindowUpdateSent)6083 TEST_P(SpdyNetworkTransactionTest, WindowUpdateSent) {
6084 if (GetParam().protocol < kProtoSPDY3)
6085 return;
6086
6087 // Amount of body required to trigger a sent window update.
6088 const size_t kTargetSize = kSpdyStreamInitialWindowSize / 2 + 1;
6089
6090 scoped_ptr<SpdyFrame> req(
6091 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
6092 scoped_ptr<SpdyFrame> session_window_update(
6093 spdy_util_.ConstructSpdyWindowUpdate(0, kTargetSize));
6094 scoped_ptr<SpdyFrame> window_update(
6095 spdy_util_.ConstructSpdyWindowUpdate(1, kTargetSize));
6096
6097 std::vector<MockWrite> writes;
6098 writes.push_back(CreateMockWrite(*req));
6099 if (GetParam().protocol >= kProtoSPDY31)
6100 writes.push_back(CreateMockWrite(*session_window_update));
6101 writes.push_back(CreateMockWrite(*window_update));
6102
6103 std::vector<MockRead> reads;
6104 scoped_ptr<SpdyFrame> resp(
6105 spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
6106 reads.push_back(CreateMockRead(*resp));
6107
6108 ScopedVector<SpdyFrame> body_frames;
6109 const std::string body_data(4096, 'x');
6110 for (size_t remaining = kTargetSize; remaining != 0;) {
6111 size_t frame_size = std::min(remaining, body_data.size());
6112 body_frames.push_back(spdy_util_.ConstructSpdyBodyFrame(
6113 1, body_data.data(), frame_size, false));
6114 reads.push_back(CreateMockRead(*body_frames.back()));
6115 remaining -= frame_size;
6116 }
6117 reads.push_back(MockRead(ASYNC, ERR_IO_PENDING, 0)); // Yield.
6118
6119 DelayedSocketData data(1, vector_as_array(&reads), reads.size(),
6120 vector_as_array(&writes), writes.size());
6121
6122 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
6123 BoundNetLog(), GetParam(), NULL);
6124 helper.AddData(&data);
6125 helper.RunPreTestSetup();
6126 HttpNetworkTransaction* trans = helper.trans();
6127
6128 TestCompletionCallback callback;
6129 int rv = trans->Start(&helper.request(), callback.callback(), BoundNetLog());
6130
6131 EXPECT_EQ(ERR_IO_PENDING, rv);
6132 rv = callback.WaitForResult();
6133 EXPECT_EQ(OK, rv);
6134
6135 SpdyHttpStream* stream =
6136 static_cast<SpdyHttpStream*>(trans->stream_.get());
6137 ASSERT_TRUE(stream != NULL);
6138 ASSERT_TRUE(stream->stream() != NULL);
6139
6140 // All data has been read, but not consumed. The window reflects this.
6141 EXPECT_EQ(static_cast<int>(kSpdyStreamInitialWindowSize - kTargetSize),
6142 stream->stream()->recv_window_size());
6143
6144 const HttpResponseInfo* response = trans->GetResponseInfo();
6145 ASSERT_TRUE(response != NULL);
6146 ASSERT_TRUE(response->headers.get() != NULL);
6147 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
6148 EXPECT_TRUE(response->was_fetched_via_spdy);
6149
6150 // Issue a read which will cause a WINDOW_UPDATE to be sent and window
6151 // size increased to default.
6152 scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(kTargetSize));
6153 EXPECT_EQ(static_cast<int>(kTargetSize),
6154 trans->Read(buf.get(), kTargetSize, CompletionCallback()));
6155 EXPECT_EQ(static_cast<int>(kSpdyStreamInitialWindowSize),
6156 stream->stream()->recv_window_size());
6157 EXPECT_THAT(base::StringPiece(buf->data(), kTargetSize), Each(Eq('x')));
6158
6159 // Allow scheduled WINDOW_UPDATE frames to write.
6160 base::RunLoop().RunUntilIdle();
6161 helper.VerifyDataConsumed();
6162 }
6163
6164 // Test that WINDOW_UPDATE frame causing overflow is handled correctly.
TEST_P(SpdyNetworkTransactionTest,WindowUpdateOverflow)6165 TEST_P(SpdyNetworkTransactionTest, WindowUpdateOverflow) {
6166 if (GetParam().protocol < kProtoSPDY3)
6167 return;
6168
6169 // Number of full frames we hope to write (but will not, used to
6170 // set content-length header correctly)
6171 static int kFrameCount = 3;
6172
6173 scoped_ptr<std::string> content(
6174 new std::string(kMaxSpdyFrameChunkSize, 'a'));
6175 scoped_ptr<SpdyFrame> req(spdy_util_.ConstructSpdyPost(
6176 kRequestUrl, 1, kMaxSpdyFrameChunkSize * kFrameCount, LOWEST, NULL, 0));
6177 scoped_ptr<SpdyFrame> body(
6178 spdy_util_.ConstructSpdyBodyFrame(
6179 1, content->c_str(), content->size(), false));
6180 scoped_ptr<SpdyFrame> rst(
6181 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_FLOW_CONTROL_ERROR));
6182
6183 // We're not going to write a data frame with FIN, we'll receive a bad
6184 // WINDOW_UPDATE while sending a request and will send a RST_STREAM frame.
6185 MockWrite writes[] = {
6186 CreateMockWrite(*req, 0),
6187 CreateMockWrite(*body, 2),
6188 CreateMockWrite(*rst, 3),
6189 };
6190
6191 static const int32 kDeltaWindowSize = 0x7fffffff; // cause an overflow
6192 scoped_ptr<SpdyFrame> window_update(
6193 spdy_util_.ConstructSpdyWindowUpdate(1, kDeltaWindowSize));
6194 MockRead reads[] = {
6195 CreateMockRead(*window_update, 1),
6196 MockRead(ASYNC, 0, 4) // EOF
6197 };
6198
6199 DeterministicSocketData data(reads, arraysize(reads),
6200 writes, arraysize(writes));
6201
6202 ScopedVector<UploadElementReader> element_readers;
6203 for (int i = 0; i < kFrameCount; ++i) {
6204 element_readers.push_back(
6205 new UploadBytesElementReader(content->c_str(), content->size()));
6206 }
6207 UploadDataStream upload_data_stream(element_readers.Pass(), 0);
6208
6209 // Setup the request
6210 HttpRequestInfo request;
6211 request.method = "POST";
6212 request.url = GURL("http://www.google.com/");
6213 request.upload_data_stream = &upload_data_stream;
6214
6215 NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY,
6216 BoundNetLog(), GetParam(), NULL);
6217 helper.SetDeterministic();
6218 helper.RunPreTestSetup();
6219 helper.AddDeterministicData(&data);
6220 HttpNetworkTransaction* trans = helper.trans();
6221
6222 TestCompletionCallback callback;
6223 int rv = trans->Start(&helper.request(), callback.callback(), BoundNetLog());
6224 ASSERT_EQ(ERR_IO_PENDING, rv);
6225
6226 data.RunFor(5);
6227 ASSERT_TRUE(callback.have_result());
6228 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, callback.WaitForResult());
6229 helper.VerifyDataConsumed();
6230 }
6231
6232 // Test that after hitting a send window size of 0, the write process
6233 // stalls and upon receiving WINDOW_UPDATE frame write resumes.
6234
6235 // This test constructs a POST request followed by enough data frames
6236 // containing 'a' that would make the window size 0, followed by another
6237 // data frame containing default content (which is "hello!") and this frame
6238 // also contains a FIN flag. DelayedSocketData is used to enforce all
6239 // writes go through before a read could happen. However, the last frame
6240 // ("hello!") is not supposed to go through since by the time its turn
6241 // arrives, window size is 0. At this point MessageLoop::Run() called via
6242 // callback would block. Therefore we call MessageLoop::RunUntilIdle()
6243 // which returns after performing all possible writes. We use DCHECKS to
6244 // ensure that last data frame is still there and stream has stalled.
6245 // After that, next read is artifically enforced, which causes a
6246 // WINDOW_UPDATE to be read and I/O process resumes.
TEST_P(SpdyNetworkTransactionTest,FlowControlStallResume)6247 TEST_P(SpdyNetworkTransactionTest, FlowControlStallResume) {
6248 if (GetParam().protocol < kProtoSPDY3)
6249 return;
6250
6251 // Number of frames we need to send to zero out the window size: data
6252 // frames plus SYN_STREAM plus the last data frame; also we need another
6253 // data frame that we will send once the WINDOW_UPDATE is received,
6254 // therefore +3.
6255 size_t num_writes = kSpdyStreamInitialWindowSize / kMaxSpdyFrameChunkSize + 3;
6256
6257 // Calculate last frame's size; 0 size data frame is legal.
6258 size_t last_frame_size =
6259 kSpdyStreamInitialWindowSize % kMaxSpdyFrameChunkSize;
6260
6261 // Construct content for a data frame of maximum size.
6262 std::string content(kMaxSpdyFrameChunkSize, 'a');
6263
6264 scoped_ptr<SpdyFrame> req(spdy_util_.ConstructSpdyPost(
6265 kRequestUrl, 1, kSpdyStreamInitialWindowSize + kUploadDataSize,
6266 LOWEST, NULL, 0));
6267
6268 // Full frames.
6269 scoped_ptr<SpdyFrame> body1(
6270 spdy_util_.ConstructSpdyBodyFrame(
6271 1, content.c_str(), content.size(), false));
6272
6273 // Last frame to zero out the window size.
6274 scoped_ptr<SpdyFrame> body2(
6275 spdy_util_.ConstructSpdyBodyFrame(
6276 1, content.c_str(), last_frame_size, false));
6277
6278 // Data frame to be sent once WINDOW_UPDATE frame is received.
6279 scoped_ptr<SpdyFrame> body3(spdy_util_.ConstructSpdyBodyFrame(1, true));
6280
6281 // Fill in mock writes.
6282 scoped_ptr<MockWrite[]> writes(new MockWrite[num_writes]);
6283 size_t i = 0;
6284 writes[i] = CreateMockWrite(*req);
6285 for (i = 1; i < num_writes - 2; i++)
6286 writes[i] = CreateMockWrite(*body1);
6287 writes[i++] = CreateMockWrite(*body2);
6288 writes[i] = CreateMockWrite(*body3);
6289
6290 // Construct read frame, give enough space to upload the rest of the
6291 // data.
6292 scoped_ptr<SpdyFrame> session_window_update(
6293 spdy_util_.ConstructSpdyWindowUpdate(0, kUploadDataSize));
6294 scoped_ptr<SpdyFrame> window_update(
6295 spdy_util_.ConstructSpdyWindowUpdate(1, kUploadDataSize));
6296 scoped_ptr<SpdyFrame> reply(spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
6297 MockRead reads[] = {
6298 CreateMockRead(*session_window_update),
6299 CreateMockRead(*session_window_update),
6300 CreateMockRead(*window_update),
6301 CreateMockRead(*window_update),
6302 CreateMockRead(*reply),
6303 CreateMockRead(*body2),
6304 CreateMockRead(*body3),
6305 MockRead(ASYNC, 0, 0) // EOF
6306 };
6307
6308 // Skip the session window updates unless we're using SPDY/3.1 and
6309 // above.
6310 size_t read_offset = (GetParam().protocol >= kProtoSPDY31) ? 0 : 2;
6311 size_t num_reads = arraysize(reads) - read_offset;
6312
6313 // Force all writes to happen before any read, last write will not
6314 // actually queue a frame, due to window size being 0.
6315 DelayedSocketData data(num_writes, reads + read_offset, num_reads,
6316 writes.get(), num_writes);
6317
6318 ScopedVector<UploadElementReader> element_readers;
6319 std::string upload_data_string(kSpdyStreamInitialWindowSize, 'a');
6320 upload_data_string.append(kUploadData, kUploadDataSize);
6321 element_readers.push_back(new UploadBytesElementReader(
6322 upload_data_string.c_str(), upload_data_string.size()));
6323 UploadDataStream upload_data_stream(element_readers.Pass(), 0);
6324
6325 HttpRequestInfo request;
6326 request.method = "POST";
6327 request.url = GURL("http://www.google.com/");
6328 request.upload_data_stream = &upload_data_stream;
6329 NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY,
6330 BoundNetLog(), GetParam(), NULL);
6331 helper.AddData(&data);
6332 helper.RunPreTestSetup();
6333
6334 HttpNetworkTransaction* trans = helper.trans();
6335
6336 TestCompletionCallback callback;
6337 int rv = trans->Start(&helper.request(), callback.callback(), BoundNetLog());
6338 EXPECT_EQ(ERR_IO_PENDING, rv);
6339
6340 base::RunLoop().RunUntilIdle(); // Write as much as we can.
6341
6342 SpdyHttpStream* stream = static_cast<SpdyHttpStream*>(trans->stream_.get());
6343 ASSERT_TRUE(stream != NULL);
6344 ASSERT_TRUE(stream->stream() != NULL);
6345 EXPECT_EQ(0, stream->stream()->send_window_size());
6346 // All the body data should have been read.
6347 // TODO(satorux): This is because of the weirdness in reading the request
6348 // body in OnSendBodyComplete(). See crbug.com/113107.
6349 EXPECT_TRUE(upload_data_stream.IsEOF());
6350 // But the body is not yet fully sent (kUploadData is not yet sent)
6351 // since we're send-stalled.
6352 EXPECT_TRUE(stream->stream()->send_stalled_by_flow_control());
6353
6354 data.ForceNextRead(); // Read in WINDOW_UPDATE frame.
6355 rv = callback.WaitForResult();
6356 helper.VerifyDataConsumed();
6357 }
6358
6359 // Test we correctly handle the case where the SETTINGS frame results in
6360 // unstalling the send window.
TEST_P(SpdyNetworkTransactionTest,FlowControlStallResumeAfterSettings)6361 TEST_P(SpdyNetworkTransactionTest, FlowControlStallResumeAfterSettings) {
6362 if (GetParam().protocol < kProtoSPDY3)
6363 return;
6364
6365 // Number of frames we need to send to zero out the window size: data
6366 // frames plus SYN_STREAM plus the last data frame; also we need another
6367 // data frame that we will send once the SETTING is received, therefore +3.
6368 size_t num_writes = kSpdyStreamInitialWindowSize / kMaxSpdyFrameChunkSize + 3;
6369
6370 // Calculate last frame's size; 0 size data frame is legal.
6371 size_t last_frame_size =
6372 kSpdyStreamInitialWindowSize % kMaxSpdyFrameChunkSize;
6373
6374 // Construct content for a data frame of maximum size.
6375 std::string content(kMaxSpdyFrameChunkSize, 'a');
6376
6377 scoped_ptr<SpdyFrame> req(spdy_util_.ConstructSpdyPost(
6378 kRequestUrl, 1, kSpdyStreamInitialWindowSize + kUploadDataSize,
6379 LOWEST, NULL, 0));
6380
6381 // Full frames.
6382 scoped_ptr<SpdyFrame> body1(
6383 spdy_util_.ConstructSpdyBodyFrame(
6384 1, content.c_str(), content.size(), false));
6385
6386 // Last frame to zero out the window size.
6387 scoped_ptr<SpdyFrame> body2(
6388 spdy_util_.ConstructSpdyBodyFrame(
6389 1, content.c_str(), last_frame_size, false));
6390
6391 // Data frame to be sent once SETTINGS frame is received.
6392 scoped_ptr<SpdyFrame> body3(spdy_util_.ConstructSpdyBodyFrame(1, true));
6393
6394 // Fill in mock reads/writes.
6395 std::vector<MockRead> reads;
6396 std::vector<MockWrite> writes;
6397 size_t i = 0;
6398 writes.push_back(CreateMockWrite(*req, i++));
6399 while (i < num_writes - 2)
6400 writes.push_back(CreateMockWrite(*body1, i++));
6401 writes.push_back(CreateMockWrite(*body2, i++));
6402
6403 // Construct read frame for SETTINGS that gives enough space to upload the
6404 // rest of the data.
6405 SettingsMap settings;
6406 settings[SETTINGS_INITIAL_WINDOW_SIZE] =
6407 SettingsFlagsAndValue(
6408 SETTINGS_FLAG_NONE, kSpdyStreamInitialWindowSize * 2);
6409 scoped_ptr<SpdyFrame> settings_frame_large(
6410 spdy_util_.ConstructSpdySettings(settings));
6411
6412 reads.push_back(CreateMockRead(*settings_frame_large, i++));
6413
6414 scoped_ptr<SpdyFrame> session_window_update(
6415 spdy_util_.ConstructSpdyWindowUpdate(0, kUploadDataSize));
6416 if (GetParam().protocol >= kProtoSPDY31)
6417 reads.push_back(CreateMockRead(*session_window_update, i++));
6418
6419 scoped_ptr<SpdyFrame> settings_ack(spdy_util_.ConstructSpdySettingsAck());
6420 writes.push_back(CreateMockWrite(*settings_ack, i++));
6421
6422 writes.push_back(CreateMockWrite(*body3, i++));
6423
6424 scoped_ptr<SpdyFrame> reply(spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
6425 reads.push_back(CreateMockRead(*reply, i++));
6426 reads.push_back(CreateMockRead(*body2, i++));
6427 reads.push_back(CreateMockRead(*body3, i++));
6428 reads.push_back(MockRead(ASYNC, 0, i++)); // EOF
6429
6430 // Force all writes to happen before any read, last write will not
6431 // actually queue a frame, due to window size being 0.
6432 DeterministicSocketData data(vector_as_array(&reads), reads.size(),
6433 vector_as_array(&writes), writes.size());
6434
6435 ScopedVector<UploadElementReader> element_readers;
6436 std::string upload_data_string(kSpdyStreamInitialWindowSize, 'a');
6437 upload_data_string.append(kUploadData, kUploadDataSize);
6438 element_readers.push_back(new UploadBytesElementReader(
6439 upload_data_string.c_str(), upload_data_string.size()));
6440 UploadDataStream upload_data_stream(element_readers.Pass(), 0);
6441
6442 HttpRequestInfo request;
6443 request.method = "POST";
6444 request.url = GURL("http://www.google.com/");
6445 request.upload_data_stream = &upload_data_stream;
6446 NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY,
6447 BoundNetLog(), GetParam(), NULL);
6448 helper.SetDeterministic();
6449 helper.RunPreTestSetup();
6450 helper.AddDeterministicData(&data);
6451
6452 HttpNetworkTransaction* trans = helper.trans();
6453
6454 TestCompletionCallback callback;
6455 int rv = trans->Start(&helper.request(), callback.callback(), BoundNetLog());
6456 EXPECT_EQ(ERR_IO_PENDING, rv);
6457
6458 data.RunFor(num_writes - 1); // Write as much as we can.
6459
6460 SpdyHttpStream* stream = static_cast<SpdyHttpStream*>(trans->stream_.get());
6461 ASSERT_TRUE(stream != NULL);
6462 ASSERT_TRUE(stream->stream() != NULL);
6463 EXPECT_EQ(0, stream->stream()->send_window_size());
6464
6465 // All the body data should have been read.
6466 // TODO(satorux): This is because of the weirdness in reading the request
6467 // body in OnSendBodyComplete(). See crbug.com/113107.
6468 EXPECT_TRUE(upload_data_stream.IsEOF());
6469 // But the body is not yet fully sent (kUploadData is not yet sent)
6470 // since we're send-stalled.
6471 EXPECT_TRUE(stream->stream()->send_stalled_by_flow_control());
6472
6473 data.RunFor(7); // Read in SETTINGS frame to unstall.
6474 rv = callback.WaitForResult();
6475 helper.VerifyDataConsumed();
6476 // If stream is NULL, that means it was unstalled and closed.
6477 EXPECT_TRUE(stream->stream() == NULL);
6478 }
6479
6480 // Test we correctly handle the case where the SETTINGS frame results in a
6481 // negative send window size.
TEST_P(SpdyNetworkTransactionTest,FlowControlNegativeSendWindowSize)6482 TEST_P(SpdyNetworkTransactionTest, FlowControlNegativeSendWindowSize) {
6483 if (GetParam().protocol < kProtoSPDY3)
6484 return;
6485
6486 // Number of frames we need to send to zero out the window size: data
6487 // frames plus SYN_STREAM plus the last data frame; also we need another
6488 // data frame that we will send once the SETTING is received, therefore +3.
6489 size_t num_writes = kSpdyStreamInitialWindowSize / kMaxSpdyFrameChunkSize + 3;
6490
6491 // Calculate last frame's size; 0 size data frame is legal.
6492 size_t last_frame_size =
6493 kSpdyStreamInitialWindowSize % kMaxSpdyFrameChunkSize;
6494
6495 // Construct content for a data frame of maximum size.
6496 std::string content(kMaxSpdyFrameChunkSize, 'a');
6497
6498 scoped_ptr<SpdyFrame> req(spdy_util_.ConstructSpdyPost(
6499 kRequestUrl, 1, kSpdyStreamInitialWindowSize + kUploadDataSize,
6500 LOWEST, NULL, 0));
6501
6502 // Full frames.
6503 scoped_ptr<SpdyFrame> body1(
6504 spdy_util_.ConstructSpdyBodyFrame(
6505 1, content.c_str(), content.size(), false));
6506
6507 // Last frame to zero out the window size.
6508 scoped_ptr<SpdyFrame> body2(
6509 spdy_util_.ConstructSpdyBodyFrame(
6510 1, content.c_str(), last_frame_size, false));
6511
6512 // Data frame to be sent once SETTINGS frame is received.
6513 scoped_ptr<SpdyFrame> body3(spdy_util_.ConstructSpdyBodyFrame(1, true));
6514
6515 // Fill in mock reads/writes.
6516 std::vector<MockRead> reads;
6517 std::vector<MockWrite> writes;
6518 size_t i = 0;
6519 writes.push_back(CreateMockWrite(*req, i++));
6520 while (i < num_writes - 2)
6521 writes.push_back(CreateMockWrite(*body1, i++));
6522 writes.push_back(CreateMockWrite(*body2, i++));
6523
6524 // Construct read frame for SETTINGS that makes the send_window_size
6525 // negative.
6526 SettingsMap new_settings;
6527 new_settings[SETTINGS_INITIAL_WINDOW_SIZE] =
6528 SettingsFlagsAndValue(
6529 SETTINGS_FLAG_NONE, kSpdyStreamInitialWindowSize / 2);
6530 scoped_ptr<SpdyFrame> settings_frame_small(
6531 spdy_util_.ConstructSpdySettings(new_settings));
6532 // Construct read frames for WINDOW_UPDATE that makes the send_window_size
6533 // positive.
6534 scoped_ptr<SpdyFrame> session_window_update_init_size(
6535 spdy_util_.ConstructSpdyWindowUpdate(0, kSpdyStreamInitialWindowSize));
6536 scoped_ptr<SpdyFrame> window_update_init_size(
6537 spdy_util_.ConstructSpdyWindowUpdate(1, kSpdyStreamInitialWindowSize));
6538
6539 reads.push_back(CreateMockRead(*settings_frame_small, i++));
6540
6541 if (GetParam().protocol >= kProtoSPDY3)
6542 reads.push_back(CreateMockRead(*session_window_update_init_size, i++));
6543
6544 reads.push_back(CreateMockRead(*window_update_init_size, i++));
6545
6546 scoped_ptr<SpdyFrame> settings_ack(spdy_util_.ConstructSpdySettingsAck());
6547 writes.push_back(CreateMockWrite(*settings_ack, i++));
6548
6549 writes.push_back(CreateMockWrite(*body3, i++));
6550
6551 scoped_ptr<SpdyFrame> reply(spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
6552 reads.push_back(CreateMockRead(*reply, i++));
6553 reads.push_back(CreateMockRead(*body2, i++));
6554 reads.push_back(CreateMockRead(*body3, i++));
6555 reads.push_back(MockRead(ASYNC, 0, i++)); // EOF
6556
6557 // Force all writes to happen before any read, last write will not
6558 // actually queue a frame, due to window size being 0.
6559 DeterministicSocketData data(vector_as_array(&reads), reads.size(),
6560 vector_as_array(&writes), writes.size());
6561
6562 ScopedVector<UploadElementReader> element_readers;
6563 std::string upload_data_string(kSpdyStreamInitialWindowSize, 'a');
6564 upload_data_string.append(kUploadData, kUploadDataSize);
6565 element_readers.push_back(new UploadBytesElementReader(
6566 upload_data_string.c_str(), upload_data_string.size()));
6567 UploadDataStream upload_data_stream(element_readers.Pass(), 0);
6568
6569 HttpRequestInfo request;
6570 request.method = "POST";
6571 request.url = GURL("http://www.google.com/");
6572 request.upload_data_stream = &upload_data_stream;
6573 NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY,
6574 BoundNetLog(), GetParam(), NULL);
6575 helper.SetDeterministic();
6576 helper.RunPreTestSetup();
6577 helper.AddDeterministicData(&data);
6578
6579 HttpNetworkTransaction* trans = helper.trans();
6580
6581 TestCompletionCallback callback;
6582 int rv = trans->Start(&helper.request(), callback.callback(), BoundNetLog());
6583 EXPECT_EQ(ERR_IO_PENDING, rv);
6584
6585 data.RunFor(num_writes - 1); // Write as much as we can.
6586
6587 SpdyHttpStream* stream = static_cast<SpdyHttpStream*>(trans->stream_.get());
6588 ASSERT_TRUE(stream != NULL);
6589 ASSERT_TRUE(stream->stream() != NULL);
6590 EXPECT_EQ(0, stream->stream()->send_window_size());
6591
6592 // All the body data should have been read.
6593 // TODO(satorux): This is because of the weirdness in reading the request
6594 // body in OnSendBodyComplete(). See crbug.com/113107.
6595 EXPECT_TRUE(upload_data_stream.IsEOF());
6596 // But the body is not yet fully sent (kUploadData is not yet sent)
6597 // since we're send-stalled.
6598 EXPECT_TRUE(stream->stream()->send_stalled_by_flow_control());
6599
6600 // Read in WINDOW_UPDATE or SETTINGS frame.
6601 data.RunFor((GetParam().protocol >= kProtoSPDY31) ? 9 : 8);
6602 rv = callback.WaitForResult();
6603 helper.VerifyDataConsumed();
6604 }
6605
6606 class SpdyNetworkTransactionNoTLSUsageCheckTest
6607 : public SpdyNetworkTransactionTest {
6608 protected:
RunNoTLSUsageCheckTest(scoped_ptr<SSLSocketDataProvider> ssl_provider)6609 void RunNoTLSUsageCheckTest(scoped_ptr<SSLSocketDataProvider> ssl_provider) {
6610 // Construct the request.
6611 scoped_ptr<SpdyFrame> req(spdy_util_.ConstructSpdyGet(
6612 "https://www.google.com/", false, 1, LOWEST));
6613 MockWrite writes[] = {CreateMockWrite(*req)};
6614
6615 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
6616 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
6617 MockRead reads[] = {
6618 CreateMockRead(*resp), CreateMockRead(*body),
6619 MockRead(ASYNC, 0, 0) // EOF
6620 };
6621
6622 DelayedSocketData data(
6623 1, reads, arraysize(reads), writes, arraysize(writes));
6624 HttpRequestInfo request;
6625 request.method = "GET";
6626 request.url = GURL("https://www.google.com/");
6627 NormalSpdyTransactionHelper helper(
6628 request, DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL);
6629 helper.RunToCompletionWithSSLData(&data, ssl_provider.Pass());
6630 TransactionHelperResult out = helper.output();
6631 EXPECT_EQ(OK, out.rv);
6632 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
6633 EXPECT_EQ("hello!", out.response_data);
6634 }
6635 };
6636
6637 //-----------------------------------------------------------------------------
6638 // All tests are run with three different connection types: SPDY after NPN
6639 // negotiation, SPDY without SSL, and SPDY with SSL.
6640 //
6641 // TODO(akalin): Use ::testing::Combine() when we are able to use
6642 // <tr1/tuple>.
6643 INSTANTIATE_TEST_CASE_P(
6644 Spdy,
6645 SpdyNetworkTransactionNoTLSUsageCheckTest,
6646 ::testing::Values(SpdyNetworkTransactionTestParams(kProtoDeprecatedSPDY2,
6647 SPDYNPN),
6648 SpdyNetworkTransactionTestParams(kProtoSPDY3, SPDYNPN),
6649 SpdyNetworkTransactionTestParams(kProtoSPDY31, SPDYNPN)));
6650
TEST_P(SpdyNetworkTransactionNoTLSUsageCheckTest,TLSVersionTooOld)6651 TEST_P(SpdyNetworkTransactionNoTLSUsageCheckTest, TLSVersionTooOld) {
6652 scoped_ptr<SSLSocketDataProvider> ssl_provider(
6653 new SSLSocketDataProvider(ASYNC, OK));
6654 SSLConnectionStatusSetVersion(SSL_CONNECTION_VERSION_SSL3,
6655 &ssl_provider->connection_status);
6656
6657 RunNoTLSUsageCheckTest(ssl_provider.Pass());
6658 }
6659
TEST_P(SpdyNetworkTransactionNoTLSUsageCheckTest,TLSCipherSuiteSucky)6660 TEST_P(SpdyNetworkTransactionNoTLSUsageCheckTest, TLSCipherSuiteSucky) {
6661 scoped_ptr<SSLSocketDataProvider> ssl_provider(
6662 new SSLSocketDataProvider(ASYNC, OK));
6663 // Set to TLS_RSA_WITH_NULL_MD5
6664 SSLConnectionStatusSetCipherSuite(0x1, &ssl_provider->connection_status);
6665
6666 RunNoTLSUsageCheckTest(ssl_provider.Pass());
6667 }
6668
6669 class SpdyNetworkTransactionTLSUsageCheckTest
6670 : public SpdyNetworkTransactionTest {
6671 protected:
RunTLSUsageCheckTest(scoped_ptr<SSLSocketDataProvider> ssl_provider)6672 void RunTLSUsageCheckTest(scoped_ptr<SSLSocketDataProvider> ssl_provider) {
6673 scoped_ptr<SpdyFrame> goaway(
6674 spdy_util_.ConstructSpdyGoAway(0, GOAWAY_INADEQUATE_SECURITY, ""));
6675 MockWrite writes[] = {CreateMockWrite(*goaway)};
6676
6677 DelayedSocketData data(1, NULL, 0, writes, arraysize(writes));
6678 HttpRequestInfo request;
6679 request.method = "GET";
6680 request.url = GURL("https://www.google.com/");
6681 NormalSpdyTransactionHelper helper(
6682 request, DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL);
6683 helper.RunToCompletionWithSSLData(&data, ssl_provider.Pass());
6684 TransactionHelperResult out = helper.output();
6685 EXPECT_EQ(ERR_SPDY_INADEQUATE_TRANSPORT_SECURITY, out.rv);
6686 }
6687 };
6688
6689 INSTANTIATE_TEST_CASE_P(
6690 Spdy,
6691 SpdyNetworkTransactionTLSUsageCheckTest,
6692 ::testing::Values(SpdyNetworkTransactionTestParams(kProtoSPDY4, SPDYNPN)));
6693
TEST_P(SpdyNetworkTransactionTLSUsageCheckTest,TLSVersionTooOld)6694 TEST_P(SpdyNetworkTransactionTLSUsageCheckTest, TLSVersionTooOld) {
6695 scoped_ptr<SSLSocketDataProvider> ssl_provider(
6696 new SSLSocketDataProvider(ASYNC, OK));
6697 SSLConnectionStatusSetVersion(SSL_CONNECTION_VERSION_SSL3,
6698 &ssl_provider->connection_status);
6699
6700 RunTLSUsageCheckTest(ssl_provider.Pass());
6701 }
6702
TEST_P(SpdyNetworkTransactionTLSUsageCheckTest,TLSCipherSuiteSucky)6703 TEST_P(SpdyNetworkTransactionTLSUsageCheckTest, TLSCipherSuiteSucky) {
6704 scoped_ptr<SSLSocketDataProvider> ssl_provider(
6705 new SSLSocketDataProvider(ASYNC, OK));
6706 // Set to TLS_RSA_WITH_NULL_MD5
6707 SSLConnectionStatusSetCipherSuite(0x1, &ssl_provider->connection_status);
6708
6709 RunTLSUsageCheckTest(ssl_provider.Pass());
6710 }
6711
6712 } // namespace net
6713