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.
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/test/test_file_util.h"
16 #include "net/base/auth.h"
17 #include "net/base/net_log_unittest.h"
18 #include "net/base/request_priority.h"
19 #include "net/base/upload_bytes_element_reader.h"
20 #include "net/base/upload_data_stream.h"
21 #include "net/base/upload_file_element_reader.h"
22 #include "net/http/http_network_session_peer.h"
23 #include "net/http/http_network_transaction.h"
24 #include "net/http/http_server_properties.h"
25 #include "net/http/http_transaction_unittest.h"
26 #include "net/socket/client_socket_pool_base.h"
27 #include "net/socket/next_proto.h"
28 #include "net/spdy/buffered_spdy_framer.h"
29 #include "net/spdy/spdy_http_stream.h"
30 #include "net/spdy/spdy_http_utils.h"
31 #include "net/spdy/spdy_session.h"
32 #include "net/spdy/spdy_session_pool.h"
33 #include "net/spdy/spdy_test_util_common.h"
34 #include "net/spdy/spdy_test_utils.h"
35 #include "net/url_request/url_request_test_util.h"
36 #include "testing/platform_test.h"
38 //-----------------------------------------------------------------------------
43 const char kRequestUrl[] = "http://www.google.com/";
45 enum SpdyNetworkTransactionTestSSLType {
51 struct SpdyNetworkTransactionTestParams {
52 SpdyNetworkTransactionTestParams()
53 : protocol(kProtoSPDY3),
56 SpdyNetworkTransactionTestParams(
58 SpdyNetworkTransactionTestSSLType ssl_type)
63 SpdyNetworkTransactionTestSSLType ssl_type;
66 SpdySessionDependencies* CreateSpdySessionDependencies(
67 SpdyNetworkTransactionTestParams test_params) {
68 return new SpdySessionDependencies(test_params.protocol);
71 SpdySessionDependencies* CreateSpdySessionDependencies(
72 SpdyNetworkTransactionTestParams test_params,
73 ProxyService* proxy_service) {
74 return new SpdySessionDependencies(test_params.protocol, proxy_service);
79 class SpdyNetworkTransactionTest
80 : public ::testing::TestWithParam<SpdyNetworkTransactionTestParams> {
82 SpdyNetworkTransactionTest() : spdy_util_(GetParam().protocol) {
83 LOG(INFO) << __FUNCTION__;
86 virtual ~SpdyNetworkTransactionTest() {
87 LOG(INFO) << __FUNCTION__;
88 // UploadDataStream posts deletion tasks back to the message loop on
90 upload_data_stream_.reset();
91 base::RunLoop().RunUntilIdle();
92 LOG(INFO) << __FUNCTION__;
95 virtual void SetUp() {
96 LOG(INFO) << __FUNCTION__;
97 google_get_request_initialized_ = false;
98 google_post_request_initialized_ = false;
99 google_chunked_post_request_initialized_ = false;
100 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
101 LOG(INFO) << __FUNCTION__;
104 struct TransactionHelperResult {
106 std::string status_line;
107 std::string response_data;
108 HttpResponseInfo response_info;
111 // A helper class that handles all the initial npn/ssl setup.
112 class NormalSpdyTransactionHelper {
114 NormalSpdyTransactionHelper(const HttpRequestInfo& request,
115 RequestPriority priority,
116 const BoundNetLog& log,
117 SpdyNetworkTransactionTestParams test_params,
118 SpdySessionDependencies* session_deps)
121 session_deps_(session_deps == NULL ?
122 CreateSpdySessionDependencies(test_params) :
124 session_(SpdySessionDependencies::SpdyCreateSession(
125 session_deps_.get())),
127 test_params_(test_params),
128 deterministic_(false),
129 spdy_enabled_(true) {
130 switch (test_params_.ssl_type) {
143 ~NormalSpdyTransactionHelper() {
144 // Any test which doesn't close the socket by sending it an EOF will
145 // have a valid session left open, which leaks the entire session pool.
146 // This is just fine - in fact, some of our tests intentionally do this
147 // so that we can check consistency of the SpdySessionPool as the test
148 // finishes. If we had put an EOF on the socket, the SpdySession would
149 // have closed and we wouldn't be able to check the consistency.
151 // Forcefully close existing sessions here.
152 session()->spdy_session_pool()->CloseAllSessions();
155 void SetDeterministic() {
156 session_ = SpdySessionDependencies::SpdyCreateSessionDeterministic(
157 session_deps_.get());
158 deterministic_ = true;
161 void SetSpdyDisabled() {
162 spdy_enabled_ = false;
166 void RunPreTestSetup() {
167 LOG(INFO) << __FUNCTION__;
168 if (!session_deps_.get())
169 session_deps_.reset(CreateSpdySessionDependencies(test_params_));
171 session_ = SpdySessionDependencies::SpdyCreateSession(
172 session_deps_.get());
173 HttpStreamFactory::set_use_alternate_protocols(false);
174 HttpStreamFactory::set_force_spdy_over_ssl(false);
175 HttpStreamFactory::set_force_spdy_always(false);
177 std::vector<NextProto> next_protos = SpdyNextProtos();
179 switch (test_params_.ssl_type) {
181 session_->http_server_properties()->SetAlternateProtocol(
182 HostPortPair("www.google.com", 80), 443,
183 AlternateProtocolFromNextProto(test_params_.protocol));
184 HttpStreamFactory::set_use_alternate_protocols(true);
185 HttpStreamFactory::SetNextProtos(next_protos);
188 HttpStreamFactory::set_force_spdy_over_ssl(false);
189 HttpStreamFactory::set_force_spdy_always(true);
192 HttpStreamFactory::set_force_spdy_over_ssl(true);
193 HttpStreamFactory::set_force_spdy_always(true);
199 // We're now ready to use SSL-npn SPDY.
200 trans_.reset(new HttpNetworkTransaction(priority_, session_.get()));
201 LOG(INFO) << __FUNCTION__;
204 // Start the transaction, read some data, finish.
205 void RunDefaultTest() {
206 LOG(INFO) << __FUNCTION__;
207 if (!StartDefaultTest())
210 LOG(INFO) << __FUNCTION__;
213 bool StartDefaultTest() {
214 output_.rv = trans_->Start(&request_, callback.callback(), log_);
216 // We expect an IO Pending or some sort of error.
217 EXPECT_LT(output_.rv, 0);
218 return output_.rv == ERR_IO_PENDING;
221 void FinishDefaultTest() {
222 output_.rv = callback.WaitForResult();
223 if (output_.rv != OK) {
224 session_->spdy_session_pool()->CloseCurrentSessions(net::ERR_ABORTED);
229 const HttpResponseInfo* response = trans_->GetResponseInfo();
230 ASSERT_TRUE(response != NULL);
231 ASSERT_TRUE(response->headers.get() != NULL);
232 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
233 EXPECT_EQ(spdy_enabled_, response->was_fetched_via_spdy);
234 if (HttpStreamFactory::spdy_enabled()) {
236 HttpResponseInfo::ConnectionInfoFromNextProto(
237 test_params_.protocol),
238 response->connection_info);
240 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP1,
241 response->connection_info);
243 if (test_params_.ssl_type == SPDYNPN && spdy_enabled_) {
244 EXPECT_TRUE(response->was_npn_negotiated);
246 EXPECT_TRUE(!response->was_npn_negotiated);
248 // If SPDY is not enabled, a HTTP request should not be diverted
249 // over a SSL session.
250 if (!spdy_enabled_) {
251 EXPECT_EQ(request_.url.SchemeIs("https"),
252 response->was_npn_negotiated);
254 EXPECT_EQ("127.0.0.1", response->socket_address.host());
255 EXPECT_EQ(port_, response->socket_address.port());
256 output_.status_line = response->headers->GetStatusLine();
257 output_.response_info = *response; // Make a copy so we can verify.
258 output_.rv = ReadTransaction(trans_.get(), &output_.response_data);
261 // Most tests will want to call this function. In particular, the MockReads
262 // should end with an empty read, and that read needs to be processed to
263 // ensure proper deletion of the spdy_session_pool.
264 void VerifyDataConsumed() {
265 for (DataVector::iterator it = data_vector_.begin();
266 it != data_vector_.end(); ++it) {
267 EXPECT_TRUE((*it)->at_read_eof()) << "Read count: "
268 << (*it)->read_count()
270 << (*it)->read_index();
271 EXPECT_TRUE((*it)->at_write_eof()) << "Write count: "
272 << (*it)->write_count()
274 << (*it)->write_index();
278 // Occasionally a test will expect to error out before certain reads are
279 // processed. In that case we want to explicitly ensure that the reads were
281 void VerifyDataNotConsumed() {
282 for (DataVector::iterator it = data_vector_.begin();
283 it != data_vector_.end(); ++it) {
284 EXPECT_TRUE(!(*it)->at_read_eof()) << "Read count: "
285 << (*it)->read_count()
287 << (*it)->read_index();
288 EXPECT_TRUE(!(*it)->at_write_eof()) << "Write count: "
289 << (*it)->write_count()
291 << (*it)->write_index();
295 void RunToCompletion(StaticSocketDataProvider* data) {
299 VerifyDataConsumed();
302 void AddData(StaticSocketDataProvider* data) {
303 DCHECK(!deterministic_);
304 data_vector_.push_back(data);
305 SSLSocketDataProvider* ssl_provider =
306 new SSLSocketDataProvider(ASYNC, OK);
307 if (test_params_.ssl_type == SPDYNPN)
308 ssl_provider->SetNextProto(test_params_.protocol);
310 ssl_vector_.push_back(ssl_provider);
311 if (test_params_.ssl_type == SPDYNPN || test_params_.ssl_type == SPDYSSL)
312 session_deps_->socket_factory->AddSSLSocketDataProvider(ssl_provider);
314 session_deps_->socket_factory->AddSocketDataProvider(data);
315 if (test_params_.ssl_type == SPDYNPN) {
316 MockConnect never_finishing_connect(SYNCHRONOUS, ERR_IO_PENDING);
317 StaticSocketDataProvider* hanging_non_alternate_protocol_socket =
318 new StaticSocketDataProvider(NULL, 0, NULL, 0);
319 hanging_non_alternate_protocol_socket->set_connect_data(
320 never_finishing_connect);
321 session_deps_->socket_factory->AddSocketDataProvider(
322 hanging_non_alternate_protocol_socket);
323 alternate_vector_.push_back(hanging_non_alternate_protocol_socket);
327 void AddDeterministicData(DeterministicSocketData* data) {
328 DCHECK(deterministic_);
329 data_vector_.push_back(data);
330 SSLSocketDataProvider* ssl_provider =
331 new SSLSocketDataProvider(ASYNC, OK);
332 if (test_params_.ssl_type == SPDYNPN)
333 ssl_provider->SetNextProto(test_params_.protocol);
335 ssl_vector_.push_back(ssl_provider);
336 if (test_params_.ssl_type == SPDYNPN ||
337 test_params_.ssl_type == SPDYSSL) {
338 session_deps_->deterministic_socket_factory->
339 AddSSLSocketDataProvider(ssl_provider);
341 session_deps_->deterministic_socket_factory->AddSocketDataProvider(data);
342 if (test_params_.ssl_type == SPDYNPN) {
343 MockConnect never_finishing_connect(SYNCHRONOUS, ERR_IO_PENDING);
344 DeterministicSocketData* hanging_non_alternate_protocol_socket =
345 new DeterministicSocketData(NULL, 0, NULL, 0);
346 hanging_non_alternate_protocol_socket->set_connect_data(
347 never_finishing_connect);
348 session_deps_->deterministic_socket_factory->AddSocketDataProvider(
349 hanging_non_alternate_protocol_socket);
350 alternate_deterministic_vector_.push_back(
351 hanging_non_alternate_protocol_socket);
355 void SetSession(const scoped_refptr<HttpNetworkSession>& session) {
358 HttpNetworkTransaction* trans() { return trans_.get(); }
359 void ResetTrans() { trans_.reset(); }
360 TransactionHelperResult& output() { return output_; }
361 const HttpRequestInfo& request() const { return request_; }
362 const scoped_refptr<HttpNetworkSession>& session() const {
365 scoped_ptr<SpdySessionDependencies>& session_deps() {
366 return session_deps_;
368 int port() const { return port_; }
369 SpdyNetworkTransactionTestParams test_params() const {
374 typedef std::vector<StaticSocketDataProvider*> DataVector;
375 typedef ScopedVector<SSLSocketDataProvider> SSLVector;
376 typedef ScopedVector<StaticSocketDataProvider> AlternateVector;
377 typedef ScopedVector<DeterministicSocketData> AlternateDeterministicVector;
378 HttpRequestInfo request_;
379 RequestPriority priority_;
380 scoped_ptr<SpdySessionDependencies> session_deps_;
381 scoped_refptr<HttpNetworkSession> session_;
382 TransactionHelperResult output_;
383 scoped_ptr<StaticSocketDataProvider> first_transaction_;
384 SSLVector ssl_vector_;
385 TestCompletionCallback callback;
386 scoped_ptr<HttpNetworkTransaction> trans_;
387 scoped_ptr<HttpNetworkTransaction> trans_http_;
388 DataVector data_vector_;
389 AlternateVector alternate_vector_;
390 AlternateDeterministicVector alternate_deterministic_vector_;
391 const BoundNetLog& log_;
392 SpdyNetworkTransactionTestParams test_params_;
398 void ConnectStatusHelperWithExpectedStatus(const MockRead& status,
399 int expected_status);
401 void ConnectStatusHelper(const MockRead& status);
403 const HttpRequestInfo& CreateGetPushRequest() {
404 google_get_push_request_.method = "GET";
405 google_get_push_request_.url = GURL("http://www.google.com/foo.dat");
406 google_get_push_request_.load_flags = 0;
407 return google_get_push_request_;
410 const HttpRequestInfo& CreateGetRequest() {
411 if (!google_get_request_initialized_) {
412 google_get_request_.method = "GET";
413 google_get_request_.url = GURL(kDefaultURL);
414 google_get_request_.load_flags = 0;
415 google_get_request_initialized_ = true;
417 return google_get_request_;
420 const HttpRequestInfo& CreateGetRequestWithUserAgent() {
421 if (!google_get_request_initialized_) {
422 google_get_request_.method = "GET";
423 google_get_request_.url = GURL(kDefaultURL);
424 google_get_request_.load_flags = 0;
425 google_get_request_.extra_headers.SetHeader("User-Agent", "Chrome");
426 google_get_request_initialized_ = true;
428 return google_get_request_;
431 const HttpRequestInfo& CreatePostRequest() {
432 if (!google_post_request_initialized_) {
433 ScopedVector<UploadElementReader> element_readers;
434 element_readers.push_back(
435 new UploadBytesElementReader(kUploadData, kUploadDataSize));
436 upload_data_stream_.reset(
437 new UploadDataStream(element_readers.Pass(), 0));
439 google_post_request_.method = "POST";
440 google_post_request_.url = GURL(kDefaultURL);
441 google_post_request_.upload_data_stream = upload_data_stream_.get();
442 google_post_request_initialized_ = true;
444 return google_post_request_;
447 const HttpRequestInfo& CreateFilePostRequest() {
448 if (!google_post_request_initialized_) {
449 base::FilePath file_path;
450 CHECK(base::CreateTemporaryFileInDir(temp_dir_.path(), &file_path));
451 CHECK_EQ(static_cast<int>(kUploadDataSize),
452 file_util::WriteFile(file_path, kUploadData, kUploadDataSize));
454 ScopedVector<UploadElementReader> element_readers;
455 element_readers.push_back(
456 new UploadFileElementReader(base::MessageLoopProxy::current().get(),
461 upload_data_stream_.reset(
462 new UploadDataStream(element_readers.Pass(), 0));
464 google_post_request_.method = "POST";
465 google_post_request_.url = GURL(kDefaultURL);
466 google_post_request_.upload_data_stream = upload_data_stream_.get();
467 google_post_request_initialized_ = true;
469 return google_post_request_;
472 const HttpRequestInfo& CreateUnreadableFilePostRequest() {
473 if (google_post_request_initialized_)
474 return google_post_request_;
476 base::FilePath file_path;
477 CHECK(base::CreateTemporaryFileInDir(temp_dir_.path(), &file_path));
478 CHECK_EQ(static_cast<int>(kUploadDataSize),
479 file_util::WriteFile(file_path, kUploadData, kUploadDataSize));
480 CHECK(file_util::MakeFileUnreadable(file_path));
482 ScopedVector<UploadElementReader> element_readers;
483 element_readers.push_back(
484 new UploadFileElementReader(base::MessageLoopProxy::current().get(),
489 upload_data_stream_.reset(
490 new UploadDataStream(element_readers.Pass(), 0));
492 google_post_request_.method = "POST";
493 google_post_request_.url = GURL(kDefaultURL);
494 google_post_request_.upload_data_stream = upload_data_stream_.get();
495 google_post_request_initialized_ = true;
496 return google_post_request_;
499 const HttpRequestInfo& CreateComplexPostRequest() {
500 if (!google_post_request_initialized_) {
501 const int kFileRangeOffset = 1;
502 const int kFileRangeLength = 3;
503 CHECK_LT(kFileRangeOffset + kFileRangeLength, kUploadDataSize);
505 base::FilePath file_path;
506 CHECK(base::CreateTemporaryFileInDir(temp_dir_.path(), &file_path));
507 CHECK_EQ(static_cast<int>(kUploadDataSize),
508 file_util::WriteFile(file_path, kUploadData, kUploadDataSize));
510 ScopedVector<UploadElementReader> element_readers;
511 element_readers.push_back(
512 new UploadBytesElementReader(kUploadData, kFileRangeOffset));
513 element_readers.push_back(
514 new UploadFileElementReader(base::MessageLoopProxy::current().get(),
519 element_readers.push_back(new UploadBytesElementReader(
520 kUploadData + kFileRangeOffset + kFileRangeLength,
521 kUploadDataSize - (kFileRangeOffset + kFileRangeLength)));
522 upload_data_stream_.reset(
523 new UploadDataStream(element_readers.Pass(), 0));
525 google_post_request_.method = "POST";
526 google_post_request_.url = GURL(kDefaultURL);
527 google_post_request_.upload_data_stream = upload_data_stream_.get();
528 google_post_request_initialized_ = true;
530 return google_post_request_;
533 const HttpRequestInfo& CreateChunkedPostRequest() {
534 if (!google_chunked_post_request_initialized_) {
535 upload_data_stream_.reset(
536 new UploadDataStream(UploadDataStream::CHUNKED, 0));
537 google_chunked_post_request_.method = "POST";
538 google_chunked_post_request_.url = GURL(kDefaultURL);
539 google_chunked_post_request_.upload_data_stream =
540 upload_data_stream_.get();
541 google_chunked_post_request_initialized_ = true;
543 return google_chunked_post_request_;
546 // Read the result of a particular transaction, knowing that we've got
547 // multiple transactions in the read pipeline; so as we read, we may have
548 // to skip over data destined for other transactions while we consume
549 // the data for |trans|.
550 int ReadResult(HttpNetworkTransaction* trans,
551 StaticSocketDataProvider* data,
552 std::string* result) {
553 const int kSize = 3000;
556 scoped_refptr<net::IOBufferWithSize> buf(new net::IOBufferWithSize(kSize));
557 TestCompletionCallback callback;
559 int rv = trans->Read(buf.get(), kSize, callback.callback());
560 if (rv == ERR_IO_PENDING) {
561 // Multiple transactions may be in the data set. Keep pulling off
562 // reads until we complete our callback.
563 while (!callback.have_result()) {
564 data->CompleteRead();
565 base::RunLoop().RunUntilIdle();
567 rv = callback.WaitForResult();
568 } else if (rv <= 0) {
571 result->append(buf->data(), rv);
577 void VerifyStreamsClosed(const NormalSpdyTransactionHelper& helper) {
578 // This lengthy block is reaching into the pool to dig out the active
579 // session. Once we have the session, we verify that the streams are
580 // all closed and not leaked at this point.
581 const GURL& url = helper.request().url;
582 int port = helper.test_params().ssl_type == SPDYNPN ? 443 : 80;
583 HostPortPair host_port_pair(url.host(), port);
584 SpdySessionKey key(host_port_pair, ProxyServer::Direct(),
585 kPrivacyModeDisabled);
587 const scoped_refptr<HttpNetworkSession>& session = helper.session();
588 base::WeakPtr<SpdySession> spdy_session =
589 session->spdy_session_pool()->FindAvailableSession(key, log);
590 ASSERT_TRUE(spdy_session != NULL);
591 EXPECT_EQ(0u, spdy_session->num_active_streams());
592 EXPECT_EQ(0u, spdy_session->num_unclaimed_pushed_streams());
595 void RunServerPushTest(OrderedSocketData* data,
596 HttpResponseInfo* response,
597 HttpResponseInfo* push_response,
598 const std::string& expected) {
599 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
600 BoundNetLog(), GetParam(), NULL);
601 helper.RunPreTestSetup();
602 helper.AddData(data);
604 HttpNetworkTransaction* trans = helper.trans();
606 // Start the transaction with basic parameters.
607 TestCompletionCallback callback;
608 int rv = trans->Start(
609 &CreateGetRequest(), callback.callback(), BoundNetLog());
610 EXPECT_EQ(ERR_IO_PENDING, rv);
611 rv = callback.WaitForResult();
613 // Request the pushed path.
614 scoped_ptr<HttpNetworkTransaction> trans2(
615 new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get()));
617 &CreateGetPushRequest(), callback.callback(), BoundNetLog());
618 EXPECT_EQ(ERR_IO_PENDING, rv);
619 base::RunLoop().RunUntilIdle();
621 // The data for the pushed path may be coming in more than 1 frame. Compile
622 // the results into a single string.
624 // Read the server push body.
626 ReadResult(trans2.get(), data, &result2);
627 // Read the response body.
629 ReadResult(trans, data, &result);
631 // Verify that we consumed all test data.
632 EXPECT_TRUE(data->at_read_eof());
633 EXPECT_TRUE(data->at_write_eof());
635 // Verify that the received push data is same as the expected push data.
636 EXPECT_EQ(result2.compare(expected), 0) << "Received data: "
638 << "||||| Expected data: "
641 // Verify the SYN_REPLY.
642 // Copy the response info, because trans goes away.
643 *response = *trans->GetResponseInfo();
644 *push_response = *trans2->GetResponseInfo();
646 VerifyStreamsClosed(helper);
649 static void DeleteSessionCallback(NormalSpdyTransactionHelper* helper,
651 helper->ResetTrans();
654 static void StartTransactionCallback(
655 const scoped_refptr<HttpNetworkSession>& session,
657 scoped_ptr<HttpNetworkTransaction> trans(
658 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
659 TestCompletionCallback callback;
660 HttpRequestInfo request;
661 request.method = "GET";
662 request.url = GURL("http://www.google.com/");
663 request.load_flags = 0;
664 int rv = trans->Start(&request, callback.callback(), BoundNetLog());
665 EXPECT_EQ(ERR_IO_PENDING, rv);
666 callback.WaitForResult();
669 SpdyTestUtil spdy_util_;
672 scoped_ptr<UploadDataStream> upload_data_stream_;
673 bool google_get_request_initialized_;
674 bool google_post_request_initialized_;
675 bool google_chunked_post_request_initialized_;
676 HttpRequestInfo google_get_request_;
677 HttpRequestInfo google_post_request_;
678 HttpRequestInfo google_chunked_post_request_;
679 HttpRequestInfo google_get_push_request_;
680 base::ScopedTempDir temp_dir_;
683 //-----------------------------------------------------------------------------
684 // All tests are run with three different connection types: SPDY after NPN
685 // negotiation, SPDY without SSL, and SPDY with SSL.
687 // TODO(akalin): Use ::testing::Combine() when we are able to use
689 INSTANTIATE_TEST_CASE_P(
691 SpdyNetworkTransactionTest,
693 SpdyNetworkTransactionTestParams(kProtoDeprecatedSPDY2, SPDYNOSSL),
694 SpdyNetworkTransactionTestParams(kProtoDeprecatedSPDY2, SPDYSSL),
695 SpdyNetworkTransactionTestParams(kProtoDeprecatedSPDY2, SPDYNPN),
696 SpdyNetworkTransactionTestParams(kProtoSPDY3, SPDYNOSSL),
697 SpdyNetworkTransactionTestParams(kProtoSPDY3, SPDYSSL),
698 SpdyNetworkTransactionTestParams(kProtoSPDY3, SPDYNPN),
699 SpdyNetworkTransactionTestParams(kProtoSPDY31, SPDYNOSSL),
700 SpdyNetworkTransactionTestParams(kProtoSPDY31, SPDYSSL),
701 SpdyNetworkTransactionTestParams(kProtoSPDY31, SPDYNPN),
702 SpdyNetworkTransactionTestParams(kProtoSPDY4a2, SPDYNOSSL),
703 SpdyNetworkTransactionTestParams(kProtoSPDY4a2, SPDYSSL),
704 SpdyNetworkTransactionTestParams(kProtoSPDY4a2, SPDYNPN),
705 SpdyNetworkTransactionTestParams(kProtoHTTP2Draft04, SPDYNOSSL),
706 SpdyNetworkTransactionTestParams(kProtoHTTP2Draft04, SPDYSSL),
707 SpdyNetworkTransactionTestParams(kProtoHTTP2Draft04, SPDYNPN)));
709 // Verify HttpNetworkTransaction constructor.
710 TEST_P(SpdyNetworkTransactionTest, Constructor) {
711 LOG(INFO) << __FUNCTION__;
712 scoped_ptr<SpdySessionDependencies> session_deps(
713 CreateSpdySessionDependencies(GetParam()));
714 LOG(INFO) << __FUNCTION__;
715 scoped_refptr<HttpNetworkSession> session(
716 SpdySessionDependencies::SpdyCreateSession(session_deps.get()));
717 LOG(INFO) << __FUNCTION__;
718 scoped_ptr<HttpTransaction> trans(
719 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
720 LOG(INFO) << __FUNCTION__;
723 TEST_P(SpdyNetworkTransactionTest, Get) {
724 LOG(INFO) << __FUNCTION__;
725 // Construct the request.
726 scoped_ptr<SpdyFrame> req(
727 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
728 MockWrite writes[] = { CreateMockWrite(*req) };
730 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
731 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
733 CreateMockRead(*resp),
734 CreateMockRead(*body),
735 MockRead(ASYNC, 0, 0) // EOF
738 DelayedSocketData data(1, reads, arraysize(reads),
739 writes, arraysize(writes));
740 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
741 BoundNetLog(), GetParam(), NULL);
742 helper.RunToCompletion(&data);
743 TransactionHelperResult out = helper.output();
744 EXPECT_EQ(OK, out.rv);
745 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
746 EXPECT_EQ("hello!", out.response_data);
749 TEST_P(SpdyNetworkTransactionTest, GetAtEachPriority) {
750 for (RequestPriority p = MINIMUM_PRIORITY; p <= MAXIMUM_PRIORITY;
751 p = RequestPriority(p + 1)) {
752 // Construct the request.
753 scoped_ptr<SpdyFrame> req(
754 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, p, true));
755 MockWrite writes[] = { CreateMockWrite(*req) };
757 SpdyPriority spdy_prio = 0;
758 EXPECT_TRUE(GetSpdyPriority(spdy_util_.spdy_version(), *req, &spdy_prio));
759 // this repeats the RequestPriority-->SpdyPriority mapping from
760 // SpdyFramer::ConvertRequestPriorityToSpdyPriority to make
761 // sure it's being done right.
762 if (spdy_util_.spdy_version() < SPDY3) {
765 EXPECT_EQ(0, spdy_prio);
768 EXPECT_EQ(1, spdy_prio);
772 EXPECT_EQ(2, spdy_prio);
775 EXPECT_EQ(3, spdy_prio);
783 EXPECT_EQ(0, spdy_prio);
786 EXPECT_EQ(1, spdy_prio);
789 EXPECT_EQ(2, spdy_prio);
792 EXPECT_EQ(3, spdy_prio);
795 EXPECT_EQ(4, spdy_prio);
802 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
803 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
805 CreateMockRead(*resp),
806 CreateMockRead(*body),
807 MockRead(ASYNC, 0, 0) // EOF
810 DelayedSocketData data(1, reads, arraysize(reads),
811 writes, arraysize(writes));
812 HttpRequestInfo http_req = CreateGetRequest();
814 NormalSpdyTransactionHelper helper(http_req, p, BoundNetLog(),
816 helper.RunToCompletion(&data);
817 TransactionHelperResult out = helper.output();
818 EXPECT_EQ(OK, out.rv);
819 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
820 EXPECT_EQ("hello!", out.response_data);
824 // Start three gets simultaniously; making sure that multiplexed
825 // streams work properly.
827 // This can't use the TransactionHelper method, since it only
828 // handles a single transaction, and finishes them as soon
829 // as it launches them.
831 // TODO(gavinp): create a working generalized TransactionHelper that
832 // can allow multiple streams in flight.
834 TEST_P(SpdyNetworkTransactionTest, ThreeGets) {
835 scoped_ptr<SpdyFrame> req(
836 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
837 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
838 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, false));
839 scoped_ptr<SpdyFrame> fbody(spdy_util_.ConstructSpdyBodyFrame(1, true));
841 scoped_ptr<SpdyFrame> req2(
842 spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, LOWEST, true));
843 scoped_ptr<SpdyFrame> resp2(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3));
844 scoped_ptr<SpdyFrame> body2(spdy_util_.ConstructSpdyBodyFrame(3, false));
845 scoped_ptr<SpdyFrame> fbody2(spdy_util_.ConstructSpdyBodyFrame(3, true));
847 scoped_ptr<SpdyFrame> req3(
848 spdy_util_.ConstructSpdyGet(NULL, 0, false, 5, LOWEST, true));
849 scoped_ptr<SpdyFrame> resp3(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 5));
850 scoped_ptr<SpdyFrame> body3(spdy_util_.ConstructSpdyBodyFrame(5, false));
851 scoped_ptr<SpdyFrame> fbody3(spdy_util_.ConstructSpdyBodyFrame(5, true));
853 MockWrite writes[] = {
854 CreateMockWrite(*req),
855 CreateMockWrite(*req2),
856 CreateMockWrite(*req3),
859 CreateMockRead(*resp, 1),
860 CreateMockRead(*body),
861 CreateMockRead(*resp2, 4),
862 CreateMockRead(*body2),
863 CreateMockRead(*resp3, 7),
864 CreateMockRead(*body3),
866 CreateMockRead(*fbody),
867 CreateMockRead(*fbody2),
868 CreateMockRead(*fbody3),
870 MockRead(ASYNC, 0, 0), // EOF
872 OrderedSocketData data(reads, arraysize(reads),
873 writes, arraysize(writes));
874 OrderedSocketData data_placeholder(NULL, 0, NULL, 0);
877 TransactionHelperResult out;
878 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
879 BoundNetLog(), GetParam(), NULL);
880 helper.RunPreTestSetup();
881 helper.AddData(&data);
882 // We require placeholder data because three get requests are sent out, so
883 // there needs to be three sets of SSL connection data.
884 helper.AddData(&data_placeholder);
885 helper.AddData(&data_placeholder);
886 scoped_ptr<HttpNetworkTransaction> trans1(
887 new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get()));
888 scoped_ptr<HttpNetworkTransaction> trans2(
889 new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get()));
890 scoped_ptr<HttpNetworkTransaction> trans3(
891 new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get()));
893 TestCompletionCallback callback1;
894 TestCompletionCallback callback2;
895 TestCompletionCallback callback3;
897 HttpRequestInfo httpreq1 = CreateGetRequest();
898 HttpRequestInfo httpreq2 = CreateGetRequest();
899 HttpRequestInfo httpreq3 = CreateGetRequest();
901 out.rv = trans1->Start(&httpreq1, callback1.callback(), log);
902 ASSERT_EQ(ERR_IO_PENDING, out.rv);
903 out.rv = trans2->Start(&httpreq2, callback2.callback(), log);
904 ASSERT_EQ(ERR_IO_PENDING, out.rv);
905 out.rv = trans3->Start(&httpreq3, callback3.callback(), log);
906 ASSERT_EQ(ERR_IO_PENDING, out.rv);
908 out.rv = callback1.WaitForResult();
909 ASSERT_EQ(OK, out.rv);
910 out.rv = callback3.WaitForResult();
911 ASSERT_EQ(OK, out.rv);
913 const HttpResponseInfo* response1 = trans1->GetResponseInfo();
914 EXPECT_TRUE(response1->headers.get() != NULL);
915 EXPECT_TRUE(response1->was_fetched_via_spdy);
916 out.status_line = response1->headers->GetStatusLine();
917 out.response_info = *response1;
919 trans2->GetResponseInfo();
921 out.rv = ReadTransaction(trans1.get(), &out.response_data);
922 helper.VerifyDataConsumed();
923 EXPECT_EQ(OK, out.rv);
925 EXPECT_EQ(OK, out.rv);
926 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
927 EXPECT_EQ("hello!hello!", out.response_data);
930 TEST_P(SpdyNetworkTransactionTest, TwoGetsLateBinding) {
931 scoped_ptr<SpdyFrame> req(
932 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
933 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
934 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, false));
935 scoped_ptr<SpdyFrame> fbody(spdy_util_.ConstructSpdyBodyFrame(1, true));
937 scoped_ptr<SpdyFrame> req2(
938 spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, LOWEST, true));
939 scoped_ptr<SpdyFrame> resp2(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3));
940 scoped_ptr<SpdyFrame> body2(spdy_util_.ConstructSpdyBodyFrame(3, false));
941 scoped_ptr<SpdyFrame> fbody2(spdy_util_.ConstructSpdyBodyFrame(3, true));
943 MockWrite writes[] = {
944 CreateMockWrite(*req),
945 CreateMockWrite(*req2),
948 CreateMockRead(*resp, 1),
949 CreateMockRead(*body),
950 CreateMockRead(*resp2, 4),
951 CreateMockRead(*body2),
952 CreateMockRead(*fbody),
953 CreateMockRead(*fbody2),
954 MockRead(ASYNC, 0, 0), // EOF
956 OrderedSocketData data(reads, arraysize(reads),
957 writes, arraysize(writes));
959 MockConnect never_finishing_connect(SYNCHRONOUS, ERR_IO_PENDING);
961 OrderedSocketData data_placeholder(NULL, 0, NULL, 0);
962 data_placeholder.set_connect_data(never_finishing_connect);
965 TransactionHelperResult out;
966 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
967 BoundNetLog(), GetParam(), NULL);
968 helper.RunPreTestSetup();
969 helper.AddData(&data);
970 // We require placeholder data because two get requests are sent out, so
971 // there needs to be two sets of SSL connection data.
972 helper.AddData(&data_placeholder);
973 scoped_ptr<HttpNetworkTransaction> trans1(
974 new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get()));
975 scoped_ptr<HttpNetworkTransaction> trans2(
976 new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get()));
978 TestCompletionCallback callback1;
979 TestCompletionCallback callback2;
981 HttpRequestInfo httpreq1 = CreateGetRequest();
982 HttpRequestInfo httpreq2 = CreateGetRequest();
984 out.rv = trans1->Start(&httpreq1, callback1.callback(), log);
985 ASSERT_EQ(ERR_IO_PENDING, out.rv);
986 out.rv = trans2->Start(&httpreq2, callback2.callback(), log);
987 ASSERT_EQ(ERR_IO_PENDING, out.rv);
989 out.rv = callback1.WaitForResult();
990 ASSERT_EQ(OK, out.rv);
991 out.rv = callback2.WaitForResult();
992 ASSERT_EQ(OK, out.rv);
994 const HttpResponseInfo* response1 = trans1->GetResponseInfo();
995 EXPECT_TRUE(response1->headers.get() != NULL);
996 EXPECT_TRUE(response1->was_fetched_via_spdy);
997 out.status_line = response1->headers->GetStatusLine();
998 out.response_info = *response1;
999 out.rv = ReadTransaction(trans1.get(), &out.response_data);
1000 EXPECT_EQ(OK, out.rv);
1001 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
1002 EXPECT_EQ("hello!hello!", out.response_data);
1004 const HttpResponseInfo* response2 = trans2->GetResponseInfo();
1005 EXPECT_TRUE(response2->headers.get() != NULL);
1006 EXPECT_TRUE(response2->was_fetched_via_spdy);
1007 out.status_line = response2->headers->GetStatusLine();
1008 out.response_info = *response2;
1009 out.rv = ReadTransaction(trans2.get(), &out.response_data);
1010 EXPECT_EQ(OK, out.rv);
1011 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
1012 EXPECT_EQ("hello!hello!", out.response_data);
1014 helper.VerifyDataConsumed();
1017 TEST_P(SpdyNetworkTransactionTest, TwoGetsLateBindingFromPreconnect) {
1018 scoped_ptr<SpdyFrame> req(
1019 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
1020 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
1021 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, false));
1022 scoped_ptr<SpdyFrame> fbody(spdy_util_.ConstructSpdyBodyFrame(1, true));
1024 scoped_ptr<SpdyFrame> req2(
1025 spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, LOWEST, true));
1026 scoped_ptr<SpdyFrame> resp2(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3));
1027 scoped_ptr<SpdyFrame> body2(spdy_util_.ConstructSpdyBodyFrame(3, false));
1028 scoped_ptr<SpdyFrame> fbody2(spdy_util_.ConstructSpdyBodyFrame(3, true));
1030 MockWrite writes[] = {
1031 CreateMockWrite(*req),
1032 CreateMockWrite(*req2),
1034 MockRead reads[] = {
1035 CreateMockRead(*resp, 1),
1036 CreateMockRead(*body),
1037 CreateMockRead(*resp2, 4),
1038 CreateMockRead(*body2),
1039 CreateMockRead(*fbody),
1040 CreateMockRead(*fbody2),
1041 MockRead(ASYNC, 0, 0), // EOF
1043 OrderedSocketData preconnect_data(reads, arraysize(reads),
1044 writes, arraysize(writes));
1046 MockConnect never_finishing_connect(ASYNC, ERR_IO_PENDING);
1048 OrderedSocketData data_placeholder(NULL, 0, NULL, 0);
1049 data_placeholder.set_connect_data(never_finishing_connect);
1052 TransactionHelperResult out;
1053 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
1054 BoundNetLog(), GetParam(), NULL);
1055 helper.RunPreTestSetup();
1056 helper.AddData(&preconnect_data);
1057 // We require placeholder data because 3 connections are attempted (first is
1058 // the preconnect, 2nd and 3rd are the never finished connections.
1059 helper.AddData(&data_placeholder);
1060 helper.AddData(&data_placeholder);
1062 scoped_ptr<HttpNetworkTransaction> trans1(
1063 new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get()));
1064 scoped_ptr<HttpNetworkTransaction> trans2(
1065 new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get()));
1067 TestCompletionCallback callback1;
1068 TestCompletionCallback callback2;
1070 HttpRequestInfo httpreq = CreateGetRequest();
1072 // Preconnect the first.
1073 SSLConfig preconnect_ssl_config;
1074 helper.session()->ssl_config_service()->GetSSLConfig(&preconnect_ssl_config);
1075 HttpStreamFactory* http_stream_factory =
1076 helper.session()->http_stream_factory();
1077 if (http_stream_factory->has_next_protos()) {
1078 preconnect_ssl_config.next_protos = http_stream_factory->next_protos();
1081 http_stream_factory->PreconnectStreams(
1082 1, httpreq, DEFAULT_PRIORITY,
1083 preconnect_ssl_config, preconnect_ssl_config);
1085 out.rv = trans1->Start(&httpreq, callback1.callback(), log);
1086 ASSERT_EQ(ERR_IO_PENDING, out.rv);
1087 out.rv = trans2->Start(&httpreq, callback2.callback(), log);
1088 ASSERT_EQ(ERR_IO_PENDING, out.rv);
1090 out.rv = callback1.WaitForResult();
1091 ASSERT_EQ(OK, out.rv);
1092 out.rv = callback2.WaitForResult();
1093 ASSERT_EQ(OK, out.rv);
1095 const HttpResponseInfo* response1 = trans1->GetResponseInfo();
1096 EXPECT_TRUE(response1->headers.get() != NULL);
1097 EXPECT_TRUE(response1->was_fetched_via_spdy);
1098 out.status_line = response1->headers->GetStatusLine();
1099 out.response_info = *response1;
1100 out.rv = ReadTransaction(trans1.get(), &out.response_data);
1101 EXPECT_EQ(OK, out.rv);
1102 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
1103 EXPECT_EQ("hello!hello!", out.response_data);
1105 const HttpResponseInfo* response2 = trans2->GetResponseInfo();
1106 EXPECT_TRUE(response2->headers.get() != NULL);
1107 EXPECT_TRUE(response2->was_fetched_via_spdy);
1108 out.status_line = response2->headers->GetStatusLine();
1109 out.response_info = *response2;
1110 out.rv = ReadTransaction(trans2.get(), &out.response_data);
1111 EXPECT_EQ(OK, out.rv);
1112 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
1113 EXPECT_EQ("hello!hello!", out.response_data);
1115 helper.VerifyDataConsumed();
1118 // Similar to ThreeGets above, however this test adds a SETTINGS
1119 // frame. The SETTINGS frame is read during the IO loop waiting on
1120 // the first transaction completion, and sets a maximum concurrent
1121 // stream limit of 1. This means that our IO loop exists after the
1122 // second transaction completes, so we can assert on read_index().
1123 TEST_P(SpdyNetworkTransactionTest, ThreeGetsWithMaxConcurrent) {
1124 // Construct the request.
1125 scoped_ptr<SpdyFrame> req(
1126 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
1127 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
1128 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, false));
1129 scoped_ptr<SpdyFrame> fbody(spdy_util_.ConstructSpdyBodyFrame(1, true));
1131 scoped_ptr<SpdyFrame> req2(
1132 spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, LOWEST, true));
1133 scoped_ptr<SpdyFrame> resp2(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3));
1134 scoped_ptr<SpdyFrame> body2(spdy_util_.ConstructSpdyBodyFrame(3, false));
1135 scoped_ptr<SpdyFrame> fbody2(spdy_util_.ConstructSpdyBodyFrame(3, true));
1137 scoped_ptr<SpdyFrame> req3(
1138 spdy_util_.ConstructSpdyGet(NULL, 0, false, 5, LOWEST, true));
1139 scoped_ptr<SpdyFrame> resp3(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 5));
1140 scoped_ptr<SpdyFrame> body3(spdy_util_.ConstructSpdyBodyFrame(5, false));
1141 scoped_ptr<SpdyFrame> fbody3(spdy_util_.ConstructSpdyBodyFrame(5, true));
1143 SettingsMap settings;
1144 const uint32 max_concurrent_streams = 1;
1145 settings[SETTINGS_MAX_CONCURRENT_STREAMS] =
1146 SettingsFlagsAndValue(SETTINGS_FLAG_NONE, max_concurrent_streams);
1147 scoped_ptr<SpdyFrame> settings_frame(
1148 spdy_util_.ConstructSpdySettings(settings));
1150 MockWrite writes[] = {
1151 CreateMockWrite(*req),
1152 CreateMockWrite(*req2),
1153 CreateMockWrite(*req3),
1156 MockRead reads[] = {
1157 CreateMockRead(*settings_frame, 1),
1158 CreateMockRead(*resp),
1159 CreateMockRead(*body),
1160 CreateMockRead(*fbody),
1161 CreateMockRead(*resp2, 7),
1162 CreateMockRead(*body2),
1163 CreateMockRead(*fbody2),
1164 CreateMockRead(*resp3, 12),
1165 CreateMockRead(*body3),
1166 CreateMockRead(*fbody3),
1168 MockRead(ASYNC, 0, 0), // EOF
1171 OrderedSocketData data(reads, arraysize(reads),
1172 writes, arraysize(writes));
1173 OrderedSocketData data_placeholder(NULL, 0, NULL, 0);
1176 TransactionHelperResult out;
1178 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
1179 BoundNetLog(), GetParam(), NULL);
1180 helper.RunPreTestSetup();
1181 helper.AddData(&data);
1182 // We require placeholder data because three get requests are sent out, so
1183 // there needs to be three sets of SSL connection data.
1184 helper.AddData(&data_placeholder);
1185 helper.AddData(&data_placeholder);
1186 scoped_ptr<HttpNetworkTransaction> trans1(
1187 new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get()));
1188 scoped_ptr<HttpNetworkTransaction> trans2(
1189 new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get()));
1190 scoped_ptr<HttpNetworkTransaction> trans3(
1191 new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get()));
1193 TestCompletionCallback callback1;
1194 TestCompletionCallback callback2;
1195 TestCompletionCallback callback3;
1197 HttpRequestInfo httpreq1 = CreateGetRequest();
1198 HttpRequestInfo httpreq2 = CreateGetRequest();
1199 HttpRequestInfo httpreq3 = CreateGetRequest();
1201 out.rv = trans1->Start(&httpreq1, callback1.callback(), log);
1202 ASSERT_EQ(out.rv, ERR_IO_PENDING);
1203 // Run transaction 1 through quickly to force a read of our SETTINGS
1205 out.rv = callback1.WaitForResult();
1206 ASSERT_EQ(OK, out.rv);
1208 out.rv = trans2->Start(&httpreq2, callback2.callback(), log);
1209 ASSERT_EQ(out.rv, ERR_IO_PENDING);
1210 out.rv = trans3->Start(&httpreq3, callback3.callback(), log);
1211 ASSERT_EQ(out.rv, ERR_IO_PENDING);
1212 out.rv = callback2.WaitForResult();
1213 ASSERT_EQ(OK, out.rv);
1214 EXPECT_EQ(7U, data.read_index()); // i.e. the third trans was queued
1216 out.rv = callback3.WaitForResult();
1217 ASSERT_EQ(OK, out.rv);
1219 const HttpResponseInfo* response1 = trans1->GetResponseInfo();
1220 ASSERT_TRUE(response1 != NULL);
1221 EXPECT_TRUE(response1->headers.get() != NULL);
1222 EXPECT_TRUE(response1->was_fetched_via_spdy);
1223 out.status_line = response1->headers->GetStatusLine();
1224 out.response_info = *response1;
1225 out.rv = ReadTransaction(trans1.get(), &out.response_data);
1226 EXPECT_EQ(OK, out.rv);
1227 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
1228 EXPECT_EQ("hello!hello!", out.response_data);
1230 const HttpResponseInfo* response2 = trans2->GetResponseInfo();
1231 out.status_line = response2->headers->GetStatusLine();
1232 out.response_info = *response2;
1233 out.rv = ReadTransaction(trans2.get(), &out.response_data);
1234 EXPECT_EQ(OK, out.rv);
1235 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
1236 EXPECT_EQ("hello!hello!", out.response_data);
1238 const HttpResponseInfo* response3 = trans3->GetResponseInfo();
1239 out.status_line = response3->headers->GetStatusLine();
1240 out.response_info = *response3;
1241 out.rv = ReadTransaction(trans3.get(), &out.response_data);
1242 EXPECT_EQ(OK, out.rv);
1243 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
1244 EXPECT_EQ("hello!hello!", out.response_data);
1246 helper.VerifyDataConsumed();
1248 EXPECT_EQ(OK, out.rv);
1251 // Similar to ThreeGetsWithMaxConcurrent above, however this test adds
1252 // a fourth transaction. The third and fourth transactions have
1253 // different data ("hello!" vs "hello!hello!") and because of the
1254 // user specified priority, we expect to see them inverted in
1255 // the response from the server.
1256 TEST_P(SpdyNetworkTransactionTest, FourGetsWithMaxConcurrentPriority) {
1257 // Construct the request.
1258 scoped_ptr<SpdyFrame> req(
1259 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
1260 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
1261 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, false));
1262 scoped_ptr<SpdyFrame> fbody(spdy_util_.ConstructSpdyBodyFrame(1, true));
1264 scoped_ptr<SpdyFrame> req2(
1265 spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, LOWEST, true));
1266 scoped_ptr<SpdyFrame> resp2(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3));
1267 scoped_ptr<SpdyFrame> body2(spdy_util_.ConstructSpdyBodyFrame(3, false));
1268 scoped_ptr<SpdyFrame> fbody2(spdy_util_.ConstructSpdyBodyFrame(3, true));
1270 scoped_ptr<SpdyFrame> req4(
1271 spdy_util_.ConstructSpdyGet(NULL, 0, false, 5, HIGHEST, true));
1272 scoped_ptr<SpdyFrame> resp4(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 5));
1273 scoped_ptr<SpdyFrame> fbody4(spdy_util_.ConstructSpdyBodyFrame(5, true));
1275 scoped_ptr<SpdyFrame> req3(
1276 spdy_util_.ConstructSpdyGet(NULL, 0, false, 7, LOWEST, true));
1277 scoped_ptr<SpdyFrame> resp3(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 7));
1278 scoped_ptr<SpdyFrame> body3(spdy_util_.ConstructSpdyBodyFrame(7, false));
1279 scoped_ptr<SpdyFrame> fbody3(spdy_util_.ConstructSpdyBodyFrame(7, true));
1281 SettingsMap settings;
1282 const uint32 max_concurrent_streams = 1;
1283 settings[SETTINGS_MAX_CONCURRENT_STREAMS] =
1284 SettingsFlagsAndValue(SETTINGS_FLAG_NONE, max_concurrent_streams);
1285 scoped_ptr<SpdyFrame> settings_frame(
1286 spdy_util_.ConstructSpdySettings(settings));
1288 MockWrite writes[] = { CreateMockWrite(*req),
1289 CreateMockWrite(*req2),
1290 CreateMockWrite(*req4),
1291 CreateMockWrite(*req3),
1293 MockRead reads[] = {
1294 CreateMockRead(*settings_frame, 1),
1295 CreateMockRead(*resp),
1296 CreateMockRead(*body),
1297 CreateMockRead(*fbody),
1298 CreateMockRead(*resp2, 7),
1299 CreateMockRead(*body2),
1300 CreateMockRead(*fbody2),
1301 CreateMockRead(*resp4, 13),
1302 CreateMockRead(*fbody4),
1303 CreateMockRead(*resp3, 16),
1304 CreateMockRead(*body3),
1305 CreateMockRead(*fbody3),
1307 MockRead(ASYNC, 0, 0), // EOF
1310 OrderedSocketData data(reads, arraysize(reads),
1311 writes, arraysize(writes));
1312 OrderedSocketData data_placeholder(NULL, 0, NULL, 0);
1315 TransactionHelperResult out;
1316 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
1317 BoundNetLog(), GetParam(), NULL);
1318 helper.RunPreTestSetup();
1319 helper.AddData(&data);
1320 // We require placeholder data because four get requests are sent out, so
1321 // there needs to be four sets of SSL connection data.
1322 helper.AddData(&data_placeholder);
1323 helper.AddData(&data_placeholder);
1324 helper.AddData(&data_placeholder);
1325 scoped_ptr<HttpNetworkTransaction> trans1(
1326 new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get()));
1327 scoped_ptr<HttpNetworkTransaction> trans2(
1328 new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get()));
1329 scoped_ptr<HttpNetworkTransaction> trans3(
1330 new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get()));
1331 scoped_ptr<HttpNetworkTransaction> trans4(
1332 new HttpNetworkTransaction(HIGHEST, helper.session().get()));
1334 TestCompletionCallback callback1;
1335 TestCompletionCallback callback2;
1336 TestCompletionCallback callback3;
1337 TestCompletionCallback callback4;
1339 HttpRequestInfo httpreq1 = CreateGetRequest();
1340 HttpRequestInfo httpreq2 = CreateGetRequest();
1341 HttpRequestInfo httpreq3 = CreateGetRequest();
1342 HttpRequestInfo httpreq4 = CreateGetRequest();
1344 out.rv = trans1->Start(&httpreq1, callback1.callback(), log);
1345 ASSERT_EQ(ERR_IO_PENDING, out.rv);
1346 // Run transaction 1 through quickly to force a read of our SETTINGS frame.
1347 out.rv = callback1.WaitForResult();
1348 ASSERT_EQ(OK, out.rv);
1350 out.rv = trans2->Start(&httpreq2, callback2.callback(), log);
1351 ASSERT_EQ(ERR_IO_PENDING, out.rv);
1352 out.rv = trans3->Start(&httpreq3, callback3.callback(), log);
1353 ASSERT_EQ(ERR_IO_PENDING, out.rv);
1354 out.rv = trans4->Start(&httpreq4, callback4.callback(), log);
1355 ASSERT_EQ(ERR_IO_PENDING, out.rv);
1357 out.rv = callback2.WaitForResult();
1358 ASSERT_EQ(OK, out.rv);
1359 EXPECT_EQ(data.read_index(), 7U); // i.e. the third & fourth trans queued
1361 out.rv = callback3.WaitForResult();
1362 ASSERT_EQ(OK, out.rv);
1364 const HttpResponseInfo* response1 = trans1->GetResponseInfo();
1365 EXPECT_TRUE(response1->headers.get() != NULL);
1366 EXPECT_TRUE(response1->was_fetched_via_spdy);
1367 out.status_line = response1->headers->GetStatusLine();
1368 out.response_info = *response1;
1369 out.rv = ReadTransaction(trans1.get(), &out.response_data);
1370 EXPECT_EQ(OK, out.rv);
1371 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
1372 EXPECT_EQ("hello!hello!", out.response_data);
1374 const HttpResponseInfo* response2 = trans2->GetResponseInfo();
1375 out.status_line = response2->headers->GetStatusLine();
1376 out.response_info = *response2;
1377 out.rv = ReadTransaction(trans2.get(), &out.response_data);
1378 EXPECT_EQ(OK, out.rv);
1379 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
1380 EXPECT_EQ("hello!hello!", out.response_data);
1382 // notice: response3 gets two hellos, response4 gets one
1383 // hello, so we know dequeuing priority was respected.
1384 const HttpResponseInfo* response3 = trans3->GetResponseInfo();
1385 out.status_line = response3->headers->GetStatusLine();
1386 out.response_info = *response3;
1387 out.rv = ReadTransaction(trans3.get(), &out.response_data);
1388 EXPECT_EQ(OK, out.rv);
1389 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
1390 EXPECT_EQ("hello!hello!", out.response_data);
1392 out.rv = callback4.WaitForResult();
1393 EXPECT_EQ(OK, out.rv);
1394 const HttpResponseInfo* response4 = trans4->GetResponseInfo();
1395 out.status_line = response4->headers->GetStatusLine();
1396 out.response_info = *response4;
1397 out.rv = ReadTransaction(trans4.get(), &out.response_data);
1398 EXPECT_EQ(OK, out.rv);
1399 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
1400 EXPECT_EQ("hello!", out.response_data);
1401 helper.VerifyDataConsumed();
1402 EXPECT_EQ(OK, out.rv);
1405 // Similar to ThreeGetsMaxConcurrrent above, however, this test
1406 // deletes a session in the middle of the transaction to insure
1407 // that we properly remove pendingcreatestream objects from
1409 TEST_P(SpdyNetworkTransactionTest, ThreeGetsWithMaxConcurrentDelete) {
1410 // Construct the request.
1411 scoped_ptr<SpdyFrame> req(
1412 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
1413 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
1414 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, false));
1415 scoped_ptr<SpdyFrame> fbody(spdy_util_.ConstructSpdyBodyFrame(1, true));
1417 scoped_ptr<SpdyFrame> req2(
1418 spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, LOWEST, true));
1419 scoped_ptr<SpdyFrame> resp2(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3));
1420 scoped_ptr<SpdyFrame> body2(spdy_util_.ConstructSpdyBodyFrame(3, false));
1421 scoped_ptr<SpdyFrame> fbody2(spdy_util_.ConstructSpdyBodyFrame(3, true));
1423 SettingsMap settings;
1424 const uint32 max_concurrent_streams = 1;
1425 settings[SETTINGS_MAX_CONCURRENT_STREAMS] =
1426 SettingsFlagsAndValue(SETTINGS_FLAG_NONE, max_concurrent_streams);
1427 scoped_ptr<SpdyFrame> settings_frame(
1428 spdy_util_.ConstructSpdySettings(settings));
1430 MockWrite writes[] = { CreateMockWrite(*req),
1431 CreateMockWrite(*req2),
1433 MockRead reads[] = {
1434 CreateMockRead(*settings_frame, 1),
1435 CreateMockRead(*resp),
1436 CreateMockRead(*body),
1437 CreateMockRead(*fbody),
1438 CreateMockRead(*resp2, 7),
1439 CreateMockRead(*body2),
1440 CreateMockRead(*fbody2),
1441 MockRead(ASYNC, 0, 0), // EOF
1444 OrderedSocketData data(reads, arraysize(reads),
1445 writes, arraysize(writes));
1446 OrderedSocketData data_placeholder(NULL, 0, NULL, 0);
1449 TransactionHelperResult out;
1450 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
1451 BoundNetLog(), GetParam(), NULL);
1452 helper.RunPreTestSetup();
1453 helper.AddData(&data);
1454 // We require placeholder data because three get requests are sent out, so
1455 // there needs to be three sets of SSL connection data.
1456 helper.AddData(&data_placeholder);
1457 helper.AddData(&data_placeholder);
1458 scoped_ptr<HttpNetworkTransaction> trans1(
1459 new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get()));
1460 scoped_ptr<HttpNetworkTransaction> trans2(
1461 new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get()));
1462 scoped_ptr<HttpNetworkTransaction> trans3(
1463 new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get()));
1465 TestCompletionCallback callback1;
1466 TestCompletionCallback callback2;
1467 TestCompletionCallback callback3;
1469 HttpRequestInfo httpreq1 = CreateGetRequest();
1470 HttpRequestInfo httpreq2 = CreateGetRequest();
1471 HttpRequestInfo httpreq3 = CreateGetRequest();
1473 out.rv = trans1->Start(&httpreq1, callback1.callback(), log);
1474 ASSERT_EQ(out.rv, ERR_IO_PENDING);
1475 // Run transaction 1 through quickly to force a read of our SETTINGS frame.
1476 out.rv = callback1.WaitForResult();
1477 ASSERT_EQ(OK, out.rv);
1479 out.rv = trans2->Start(&httpreq2, callback2.callback(), log);
1480 ASSERT_EQ(out.rv, ERR_IO_PENDING);
1481 out.rv = trans3->Start(&httpreq3, callback3.callback(), log);
1482 delete trans3.release();
1483 ASSERT_EQ(out.rv, ERR_IO_PENDING);
1484 out.rv = callback2.WaitForResult();
1485 ASSERT_EQ(OK, out.rv);
1487 EXPECT_EQ(8U, data.read_index());
1489 const HttpResponseInfo* response1 = trans1->GetResponseInfo();
1490 ASSERT_TRUE(response1 != NULL);
1491 EXPECT_TRUE(response1->headers.get() != NULL);
1492 EXPECT_TRUE(response1->was_fetched_via_spdy);
1493 out.status_line = response1->headers->GetStatusLine();
1494 out.response_info = *response1;
1495 out.rv = ReadTransaction(trans1.get(), &out.response_data);
1496 EXPECT_EQ(OK, out.rv);
1497 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
1498 EXPECT_EQ("hello!hello!", out.response_data);
1500 const HttpResponseInfo* response2 = trans2->GetResponseInfo();
1501 ASSERT_TRUE(response2 != NULL);
1502 out.status_line = response2->headers->GetStatusLine();
1503 out.response_info = *response2;
1504 out.rv = ReadTransaction(trans2.get(), &out.response_data);
1505 EXPECT_EQ(OK, out.rv);
1506 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
1507 EXPECT_EQ("hello!hello!", out.response_data);
1508 helper.VerifyDataConsumed();
1509 EXPECT_EQ(OK, out.rv);
1514 // The KillerCallback will delete the transaction on error as part of the
1516 class KillerCallback : public TestCompletionCallbackBase {
1518 explicit KillerCallback(HttpNetworkTransaction* transaction)
1519 : transaction_(transaction),
1520 callback_(base::Bind(&KillerCallback::OnComplete,
1521 base::Unretained(this))) {
1524 virtual ~KillerCallback() {}
1526 const CompletionCallback& callback() const { return callback_; }
1529 void OnComplete(int result) {
1531 delete transaction_;
1536 HttpNetworkTransaction* transaction_;
1537 CompletionCallback callback_;
1542 // Similar to ThreeGetsMaxConcurrrentDelete above, however, this test
1543 // closes the socket while we have a pending transaction waiting for
1544 // a pending stream creation. http://crbug.com/52901
1545 TEST_P(SpdyNetworkTransactionTest, ThreeGetsWithMaxConcurrentSocketClose) {
1546 // Construct the request.
1547 scoped_ptr<SpdyFrame> req(
1548 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
1549 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
1550 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, false));
1551 scoped_ptr<SpdyFrame> fin_body(spdy_util_.ConstructSpdyBodyFrame(1, true));
1553 scoped_ptr<SpdyFrame> req2(
1554 spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, LOWEST, true));
1555 scoped_ptr<SpdyFrame> resp2(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3));
1557 SettingsMap settings;
1558 const uint32 max_concurrent_streams = 1;
1559 settings[SETTINGS_MAX_CONCURRENT_STREAMS] =
1560 SettingsFlagsAndValue(SETTINGS_FLAG_NONE, max_concurrent_streams);
1561 scoped_ptr<SpdyFrame> settings_frame(
1562 spdy_util_.ConstructSpdySettings(settings));
1564 MockWrite writes[] = { CreateMockWrite(*req),
1565 CreateMockWrite(*req2),
1567 MockRead reads[] = {
1568 CreateMockRead(*settings_frame, 1),
1569 CreateMockRead(*resp),
1570 CreateMockRead(*body),
1571 CreateMockRead(*fin_body),
1572 CreateMockRead(*resp2, 7),
1573 MockRead(ASYNC, ERR_CONNECTION_RESET, 0), // Abort!
1576 OrderedSocketData data(reads, arraysize(reads),
1577 writes, arraysize(writes));
1578 OrderedSocketData data_placeholder(NULL, 0, NULL, 0);
1581 TransactionHelperResult out;
1582 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
1583 BoundNetLog(), GetParam(), NULL);
1584 helper.RunPreTestSetup();
1585 helper.AddData(&data);
1586 // We require placeholder data because three get requests are sent out, so
1587 // there needs to be three sets of SSL connection data.
1588 helper.AddData(&data_placeholder);
1589 helper.AddData(&data_placeholder);
1590 HttpNetworkTransaction trans1(DEFAULT_PRIORITY, helper.session().get());
1591 HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session().get());
1592 HttpNetworkTransaction* trans3(
1593 new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get()));
1595 TestCompletionCallback callback1;
1596 TestCompletionCallback callback2;
1597 KillerCallback callback3(trans3);
1599 HttpRequestInfo httpreq1 = CreateGetRequest();
1600 HttpRequestInfo httpreq2 = CreateGetRequest();
1601 HttpRequestInfo httpreq3 = CreateGetRequest();
1603 out.rv = trans1.Start(&httpreq1, callback1.callback(), log);
1604 ASSERT_EQ(out.rv, ERR_IO_PENDING);
1605 // Run transaction 1 through quickly to force a read of our SETTINGS frame.
1606 out.rv = callback1.WaitForResult();
1607 ASSERT_EQ(OK, out.rv);
1609 out.rv = trans2.Start(&httpreq2, callback2.callback(), log);
1610 ASSERT_EQ(out.rv, ERR_IO_PENDING);
1611 out.rv = trans3->Start(&httpreq3, callback3.callback(), log);
1612 ASSERT_EQ(out.rv, ERR_IO_PENDING);
1613 out.rv = callback3.WaitForResult();
1614 ASSERT_EQ(ERR_ABORTED, out.rv);
1616 EXPECT_EQ(6U, data.read_index());
1618 const HttpResponseInfo* response1 = trans1.GetResponseInfo();
1619 ASSERT_TRUE(response1 != NULL);
1620 EXPECT_TRUE(response1->headers.get() != NULL);
1621 EXPECT_TRUE(response1->was_fetched_via_spdy);
1622 out.status_line = response1->headers->GetStatusLine();
1623 out.response_info = *response1;
1624 out.rv = ReadTransaction(&trans1, &out.response_data);
1625 EXPECT_EQ(OK, out.rv);
1627 const HttpResponseInfo* response2 = trans2.GetResponseInfo();
1628 ASSERT_TRUE(response2 != NULL);
1629 out.status_line = response2->headers->GetStatusLine();
1630 out.response_info = *response2;
1631 out.rv = ReadTransaction(&trans2, &out.response_data);
1632 EXPECT_EQ(ERR_CONNECTION_RESET, out.rv);
1634 helper.VerifyDataConsumed();
1637 // Test that a simple PUT request works.
1638 TEST_P(SpdyNetworkTransactionTest, Put) {
1639 // Setup the request
1640 HttpRequestInfo request;
1641 request.method = "PUT";
1642 request.url = GURL("http://www.google.com/");
1644 const SpdyHeaderInfo kSynStartHeader = {
1645 SYN_STREAM, // Kind = Syn
1647 0, // Associated stream ID
1648 ConvertRequestPriorityToSpdyPriority(
1649 LOWEST, spdy_util_.spdy_version()),
1650 kSpdyCredentialSlotUnused,
1651 CONTROL_FLAG_FIN, // Control Flags
1652 false, // Compressed
1653 RST_STREAM_INVALID, // Status
1656 DATA_FLAG_NONE // Data Flags
1658 scoped_ptr<SpdyHeaderBlock> put_headers(
1659 spdy_util_.ConstructPutHeaderBlock("http://www.google.com", 0));
1660 scoped_ptr<SpdyFrame> req(spdy_util_.ConstructSpdyFrame(
1661 kSynStartHeader, put_headers.Pass()));
1662 MockWrite writes[] = {
1663 CreateMockWrite(*req),
1666 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
1667 const SpdyHeaderInfo kSynReplyHeader = {
1668 SYN_REPLY, // Kind = SynReply
1670 0, // Associated stream ID
1671 ConvertRequestPriorityToSpdyPriority(
1672 LOWEST, spdy_util_.spdy_version()),
1673 kSpdyCredentialSlotUnused,
1674 CONTROL_FLAG_NONE, // Control Flags
1675 false, // Compressed
1676 RST_STREAM_INVALID, // Status
1679 DATA_FLAG_NONE // Data Flags
1681 scoped_ptr<SpdyHeaderBlock> reply_headers(new SpdyHeaderBlock());
1682 (*reply_headers)[spdy_util_.GetStatusKey()] = "200";
1683 (*reply_headers)[spdy_util_.GetVersionKey()] = "HTTP/1.1";
1684 (*reply_headers)["content-length"] = "1234";
1685 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyFrame(
1686 kSynReplyHeader, reply_headers.Pass()));
1687 MockRead reads[] = {
1688 CreateMockRead(*resp),
1689 CreateMockRead(*body),
1690 MockRead(ASYNC, 0, 0) // EOF
1693 DelayedSocketData data(1, reads, arraysize(reads),
1694 writes, arraysize(writes));
1695 NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY,
1696 BoundNetLog(), GetParam(), NULL);
1697 helper.RunToCompletion(&data);
1698 TransactionHelperResult out = helper.output();
1700 EXPECT_EQ(OK, out.rv);
1701 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
1704 // Test that a simple HEAD request works.
1705 TEST_P(SpdyNetworkTransactionTest, Head) {
1706 // Setup the request
1707 HttpRequestInfo request;
1708 request.method = "HEAD";
1709 request.url = GURL("http://www.google.com/");
1711 const SpdyHeaderInfo kSynStartHeader = {
1712 SYN_STREAM, // Kind = Syn
1714 0, // Associated stream ID
1715 ConvertRequestPriorityToSpdyPriority(
1716 LOWEST, spdy_util_.spdy_version()),
1717 kSpdyCredentialSlotUnused,
1718 CONTROL_FLAG_FIN, // Control Flags
1719 false, // Compressed
1720 RST_STREAM_INVALID, // Status
1723 DATA_FLAG_NONE // Data Flags
1725 scoped_ptr<SpdyHeaderBlock> head_headers(
1726 spdy_util_.ConstructHeadHeaderBlock("http://www.google.com", 0));
1727 scoped_ptr<SpdyFrame> req(spdy_util_.ConstructSpdyFrame(
1728 kSynStartHeader, head_headers.Pass()));
1729 MockWrite writes[] = {
1730 CreateMockWrite(*req),
1733 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
1734 const SpdyHeaderInfo kSynReplyHeader = {
1735 SYN_REPLY, // Kind = SynReply
1737 0, // Associated stream ID
1738 ConvertRequestPriorityToSpdyPriority(
1739 LOWEST, spdy_util_.spdy_version()),
1740 kSpdyCredentialSlotUnused,
1741 CONTROL_FLAG_NONE, // Control Flags
1742 false, // Compressed
1743 RST_STREAM_INVALID, // Status
1746 DATA_FLAG_NONE // Data Flags
1748 scoped_ptr<SpdyHeaderBlock> reply_headers(new SpdyHeaderBlock());
1749 (*reply_headers)[spdy_util_.GetStatusKey()] = "200";
1750 (*reply_headers)[spdy_util_.GetVersionKey()] = "HTTP/1.1";
1751 (*reply_headers)["content-length"] = "1234";
1752 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyFrame(
1754 reply_headers.Pass()));
1755 MockRead reads[] = {
1756 CreateMockRead(*resp),
1757 CreateMockRead(*body),
1758 MockRead(ASYNC, 0, 0) // EOF
1761 DelayedSocketData data(1, reads, arraysize(reads),
1762 writes, arraysize(writes));
1763 NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY,
1764 BoundNetLog(), GetParam(), NULL);
1765 helper.RunToCompletion(&data);
1766 TransactionHelperResult out = helper.output();
1768 EXPECT_EQ(OK, out.rv);
1769 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
1772 // Test that a simple POST works.
1773 TEST_P(SpdyNetworkTransactionTest, Post) {
1774 scoped_ptr<SpdyFrame> req(
1775 spdy_util_.ConstructSpdyPost(
1776 kRequestUrl, 1, kUploadDataSize, LOWEST, NULL, 0));
1777 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
1778 MockWrite writes[] = {
1779 CreateMockWrite(*req),
1780 CreateMockWrite(*body), // POST upload frame
1783 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
1784 MockRead reads[] = {
1785 CreateMockRead(*resp),
1786 CreateMockRead(*body),
1787 MockRead(ASYNC, 0, 0) // EOF
1790 DelayedSocketData data(2, reads, arraysize(reads),
1791 writes, arraysize(writes));
1792 NormalSpdyTransactionHelper helper(CreatePostRequest(), DEFAULT_PRIORITY,
1793 BoundNetLog(), GetParam(), NULL);
1794 helper.RunToCompletion(&data);
1795 TransactionHelperResult out = helper.output();
1796 EXPECT_EQ(OK, out.rv);
1797 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
1798 EXPECT_EQ("hello!", out.response_data);
1801 // Test that a POST with a file works.
1802 TEST_P(SpdyNetworkTransactionTest, FilePost) {
1803 scoped_ptr<SpdyFrame> req(
1804 spdy_util_.ConstructSpdyPost(
1805 kRequestUrl, 1, kUploadDataSize, LOWEST, NULL, 0));
1806 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
1807 MockWrite writes[] = {
1808 CreateMockWrite(*req),
1809 CreateMockWrite(*body), // POST upload frame
1812 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
1813 MockRead reads[] = {
1814 CreateMockRead(*resp),
1815 CreateMockRead(*body),
1816 MockRead(ASYNC, 0, 0) // EOF
1819 DelayedSocketData data(2, reads, arraysize(reads),
1820 writes, arraysize(writes));
1821 NormalSpdyTransactionHelper helper(CreateFilePostRequest(), DEFAULT_PRIORITY,
1822 BoundNetLog(), GetParam(), NULL);
1823 helper.RunToCompletion(&data);
1824 TransactionHelperResult out = helper.output();
1825 EXPECT_EQ(OK, out.rv);
1826 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
1827 EXPECT_EQ("hello!", out.response_data);
1830 // Test that a POST with a unreadable file fails.
1831 TEST_P(SpdyNetworkTransactionTest, UnreadableFilePost) {
1832 MockWrite writes[] = {
1833 MockWrite(ASYNC, 0, 0) // EOF
1835 MockRead reads[] = {
1836 MockRead(ASYNC, 0, 0) // EOF
1839 DelayedSocketData data(1, reads, arraysize(reads), writes, arraysize(writes));
1840 NormalSpdyTransactionHelper helper(CreateUnreadableFilePostRequest(),
1842 BoundNetLog(), GetParam(), NULL);
1843 helper.RunPreTestSetup();
1844 helper.AddData(&data);
1845 helper.RunDefaultTest();
1847 base::RunLoop().RunUntilIdle();
1848 helper.VerifyDataNotConsumed();
1849 EXPECT_EQ(ERR_ACCESS_DENIED, helper.output().rv);
1852 // Test that a complex POST works.
1853 TEST_P(SpdyNetworkTransactionTest, ComplexPost) {
1854 scoped_ptr<SpdyFrame> req(
1855 spdy_util_.ConstructSpdyPost(
1856 kRequestUrl, 1, kUploadDataSize, LOWEST, NULL, 0));
1857 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
1858 MockWrite writes[] = {
1859 CreateMockWrite(*req),
1860 CreateMockWrite(*body), // POST upload frame
1863 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
1864 MockRead reads[] = {
1865 CreateMockRead(*resp),
1866 CreateMockRead(*body),
1867 MockRead(ASYNC, 0, 0) // EOF
1870 DelayedSocketData data(2, reads, arraysize(reads),
1871 writes, arraysize(writes));
1872 NormalSpdyTransactionHelper helper(CreateComplexPostRequest(),
1874 BoundNetLog(), GetParam(), NULL);
1875 helper.RunToCompletion(&data);
1876 TransactionHelperResult out = helper.output();
1877 EXPECT_EQ(OK, out.rv);
1878 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
1879 EXPECT_EQ("hello!", out.response_data);
1882 // Test that a chunked POST works.
1883 TEST_P(SpdyNetworkTransactionTest, ChunkedPost) {
1884 scoped_ptr<SpdyFrame> req(spdy_util_.ConstructChunkedSpdyPost(NULL, 0));
1885 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
1886 MockWrite writes[] = {
1887 CreateMockWrite(*req),
1888 CreateMockWrite(*body),
1891 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
1892 MockRead reads[] = {
1893 CreateMockRead(*resp),
1894 CreateMockRead(*body),
1895 MockRead(ASYNC, 0, 0) // EOF
1898 DelayedSocketData data(2, reads, arraysize(reads),
1899 writes, arraysize(writes));
1900 NormalSpdyTransactionHelper helper(CreateChunkedPostRequest(),
1902 BoundNetLog(), GetParam(), NULL);
1904 // These chunks get merged into a single frame when being sent.
1905 const int kFirstChunkSize = kUploadDataSize/2;
1906 helper.request().upload_data_stream->AppendChunk(
1907 kUploadData, kFirstChunkSize, false);
1908 helper.request().upload_data_stream->AppendChunk(
1909 kUploadData + kFirstChunkSize, kUploadDataSize - kFirstChunkSize, true);
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(kUploadData, out.response_data);
1918 // Test that a chunked POST works with chunks appended after transaction starts.
1919 TEST_P(SpdyNetworkTransactionTest, DelayedChunkedPost) {
1920 scoped_ptr<SpdyFrame> req(spdy_util_.ConstructChunkedSpdyPost(NULL, 0));
1921 scoped_ptr<SpdyFrame> chunk1(spdy_util_.ConstructSpdyBodyFrame(1, false));
1922 scoped_ptr<SpdyFrame> chunk2(spdy_util_.ConstructSpdyBodyFrame(1, false));
1923 scoped_ptr<SpdyFrame> chunk3(spdy_util_.ConstructSpdyBodyFrame(1, true));
1924 MockWrite writes[] = {
1925 CreateMockWrite(*req),
1926 CreateMockWrite(*chunk1),
1927 CreateMockWrite(*chunk2),
1928 CreateMockWrite(*chunk3),
1931 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
1932 MockRead reads[] = {
1933 CreateMockRead(*resp),
1934 CreateMockRead(*chunk1),
1935 CreateMockRead(*chunk2),
1936 CreateMockRead(*chunk3),
1937 MockRead(ASYNC, 0, 0) // EOF
1940 DelayedSocketData data(4, reads, arraysize(reads),
1941 writes, arraysize(writes));
1942 NormalSpdyTransactionHelper helper(CreateChunkedPostRequest(),
1944 BoundNetLog(), GetParam(), NULL);
1946 helper.request().upload_data_stream->AppendChunk(
1947 kUploadData, kUploadDataSize, false);
1949 helper.RunPreTestSetup();
1950 helper.AddData(&data);
1951 ASSERT_TRUE(helper.StartDefaultTest());
1953 base::RunLoop().RunUntilIdle();
1954 helper.request().upload_data_stream->AppendChunk(
1955 kUploadData, kUploadDataSize, false);
1956 base::RunLoop().RunUntilIdle();
1957 helper.request().upload_data_stream->AppendChunk(
1958 kUploadData, kUploadDataSize, true);
1960 helper.FinishDefaultTest();
1961 helper.VerifyDataConsumed();
1963 std::string expected_response;
1964 expected_response += kUploadData;
1965 expected_response += kUploadData;
1966 expected_response += kUploadData;
1968 TransactionHelperResult out = helper.output();
1969 EXPECT_EQ(OK, out.rv);
1970 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
1971 EXPECT_EQ(expected_response, out.response_data);
1974 // Test that a POST without any post data works.
1975 TEST_P(SpdyNetworkTransactionTest, NullPost) {
1976 // Setup the request
1977 HttpRequestInfo request;
1978 request.method = "POST";
1979 request.url = GURL(kRequestUrl);
1980 // Create an empty UploadData.
1981 request.upload_data_stream = NULL;
1983 // When request.upload_data_stream is NULL for post, content-length is
1984 // expected to be 0.
1985 scoped_ptr<SpdyFrame> req(
1986 spdy_util_.ConstructSpdyPost(kRequestUrl, 1, 0, LOWEST, NULL, 0));
1987 // Set the FIN bit since there will be no body.
1988 int flags = CONTROL_FLAG_FIN;
1989 if (spdy_util_.spdy_version() >= SPDY4) {
1990 flags |= HEADERS_FLAG_PRIORITY;
1992 test::SetFrameFlags(req.get(), flags, spdy_util_.spdy_version());
1993 MockWrite writes[] = {
1994 CreateMockWrite(*req),
1997 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
1998 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
1999 MockRead reads[] = {
2000 CreateMockRead(*resp),
2001 CreateMockRead(*body),
2002 MockRead(ASYNC, 0, 0) // EOF
2005 DelayedSocketData data(1, reads, arraysize(reads),
2006 writes, arraysize(writes));
2008 NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY,
2009 BoundNetLog(), GetParam(), NULL);
2010 helper.RunToCompletion(&data);
2011 TransactionHelperResult out = helper.output();
2012 EXPECT_EQ(OK, out.rv);
2013 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
2014 EXPECT_EQ("hello!", out.response_data);
2017 // Test that a simple POST works.
2018 TEST_P(SpdyNetworkTransactionTest, EmptyPost) {
2019 // Create an empty UploadDataStream.
2020 ScopedVector<UploadElementReader> element_readers;
2021 UploadDataStream stream(element_readers.Pass(), 0);
2023 // Setup the request
2024 HttpRequestInfo request;
2025 request.method = "POST";
2026 request.url = GURL(kRequestUrl);
2027 request.upload_data_stream = &stream;
2029 const uint64 kContentLength = 0;
2030 scoped_ptr<SpdyFrame> req(
2031 spdy_util_.ConstructSpdyPost(
2032 kRequestUrl, 1, kContentLength, LOWEST, NULL, 0));
2033 // Set the FIN bit since there will be no body.
2034 int flags = CONTROL_FLAG_FIN;
2035 if (spdy_util_.spdy_version() >= SPDY4) {
2036 flags |= HEADERS_FLAG_PRIORITY;
2038 test::SetFrameFlags(req.get(), flags, spdy_util_.spdy_version());
2039 MockWrite writes[] = {
2040 CreateMockWrite(*req),
2043 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
2044 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
2045 MockRead reads[] = {
2046 CreateMockRead(*resp),
2047 CreateMockRead(*body),
2048 MockRead(ASYNC, 0, 0) // EOF
2051 DelayedSocketData data(1, reads, arraysize(reads), writes, arraysize(writes));
2053 NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY,
2054 BoundNetLog(), GetParam(), NULL);
2055 helper.RunToCompletion(&data);
2056 TransactionHelperResult out = helper.output();
2057 EXPECT_EQ(OK, out.rv);
2058 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
2059 EXPECT_EQ("hello!", out.response_data);
2062 // While we're doing a post, the server sends the reply before upload completes.
2063 TEST_P(SpdyNetworkTransactionTest, ResponseBeforePostCompletes) {
2064 scoped_ptr<SpdyFrame> req(spdy_util_.ConstructChunkedSpdyPost(NULL, 0));
2065 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
2066 MockWrite writes[] = {
2067 CreateMockWrite(*req, 0),
2068 CreateMockWrite(*body, 3),
2070 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
2071 MockRead reads[] = {
2072 CreateMockRead(*resp, 1),
2073 CreateMockRead(*body, 2),
2074 MockRead(ASYNC, 0, 4) // EOF
2077 // Write the request headers, and read the complete response
2078 // while still waiting for chunked request data.
2079 DeterministicSocketData data(reads, arraysize(reads),
2080 writes, arraysize(writes));
2081 NormalSpdyTransactionHelper helper(CreateChunkedPostRequest(),
2083 BoundNetLog(), GetParam(), NULL);
2084 helper.SetDeterministic();
2085 helper.RunPreTestSetup();
2086 helper.AddDeterministicData(&data);
2088 ASSERT_TRUE(helper.StartDefaultTest());
2090 // Process the request headers, SYN_REPLY, and response body.
2091 // The request body is still in flight.
2094 const HttpResponseInfo* response = helper.trans()->GetResponseInfo();
2095 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
2097 // Finish sending the request body.
2098 helper.request().upload_data_stream->AppendChunk(
2099 kUploadData, kUploadDataSize, true);
2102 std::string response_body;
2103 EXPECT_EQ(OK, ReadTransaction(helper.trans(), &response_body));
2104 EXPECT_EQ(kUploadData, response_body);
2105 helper.VerifyDataConsumed();
2108 // The client upon cancellation tries to send a RST_STREAM frame. The mock
2109 // socket causes the TCP write to return zero. This test checks that the client
2110 // tries to queue up the RST_STREAM frame again.
2111 TEST_P(SpdyNetworkTransactionTest, SocketWriteReturnsZero) {
2112 scoped_ptr<SpdyFrame> req(
2113 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
2114 scoped_ptr<SpdyFrame> rst(
2115 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL));
2116 MockWrite writes[] = {
2117 CreateMockWrite(*req.get(), 0, SYNCHRONOUS),
2118 MockWrite(SYNCHRONOUS, 0, 0, 2),
2119 CreateMockWrite(*rst.get(), 3, SYNCHRONOUS),
2122 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
2123 MockRead reads[] = {
2124 CreateMockRead(*resp.get(), 1, ASYNC),
2125 MockRead(ASYNC, 0, 0, 4) // EOF
2128 DeterministicSocketData data(reads, arraysize(reads),
2129 writes, arraysize(writes));
2130 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
2131 BoundNetLog(), GetParam(), NULL);
2132 helper.SetDeterministic();
2133 helper.RunPreTestSetup();
2134 helper.AddDeterministicData(&data);
2135 HttpNetworkTransaction* trans = helper.trans();
2137 TestCompletionCallback callback;
2138 int rv = trans->Start(
2139 &CreateGetRequest(), callback.callback(), BoundNetLog());
2140 EXPECT_EQ(ERR_IO_PENDING, rv);
2144 helper.ResetTrans();
2148 helper.VerifyDataConsumed();
2151 // Test that the transaction doesn't crash when we don't have a reply.
2152 TEST_P(SpdyNetworkTransactionTest, ResponseWithoutSynReply) {
2153 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
2154 MockRead reads[] = {
2155 CreateMockRead(*body),
2156 MockRead(ASYNC, 0, 0) // EOF
2159 DelayedSocketData data(1, reads, arraysize(reads), NULL, 0);
2160 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
2161 BoundNetLog(), GetParam(), NULL);
2162 helper.RunToCompletion(&data);
2163 TransactionHelperResult out = helper.output();
2164 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, out.rv);
2167 // Test that the transaction doesn't crash when we get two replies on the same
2168 // stream ID. See http://crbug.com/45639.
2169 TEST_P(SpdyNetworkTransactionTest, ResponseWithTwoSynReplies) {
2170 scoped_ptr<SpdyFrame> req(
2171 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
2172 scoped_ptr<SpdyFrame> rst(
2173 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR));
2174 MockWrite writes[] = {
2175 CreateMockWrite(*req),
2176 CreateMockWrite(*rst),
2179 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
2180 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
2181 MockRead reads[] = {
2182 CreateMockRead(*resp),
2183 CreateMockRead(*resp),
2184 CreateMockRead(*body),
2185 MockRead(ASYNC, 0, 0) // EOF
2188 DelayedSocketData data(1, reads, arraysize(reads),
2189 writes, arraysize(writes));
2191 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
2192 BoundNetLog(), GetParam(), NULL);
2193 helper.RunPreTestSetup();
2194 helper.AddData(&data);
2196 HttpNetworkTransaction* trans = helper.trans();
2198 TestCompletionCallback callback;
2199 int rv = trans->Start(&helper.request(), callback.callback(), BoundNetLog());
2200 EXPECT_EQ(ERR_IO_PENDING, rv);
2201 rv = callback.WaitForResult();
2204 const HttpResponseInfo* response = trans->GetResponseInfo();
2205 ASSERT_TRUE(response != NULL);
2206 EXPECT_TRUE(response->headers.get() != NULL);
2207 EXPECT_TRUE(response->was_fetched_via_spdy);
2208 std::string response_data;
2209 rv = ReadTransaction(trans, &response_data);
2210 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, rv);
2212 helper.VerifyDataConsumed();
2215 TEST_P(SpdyNetworkTransactionTest, ResetReplyWithTransferEncoding) {
2216 // Construct the request.
2217 scoped_ptr<SpdyFrame> req(
2218 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
2219 scoped_ptr<SpdyFrame> rst(
2220 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR));
2221 MockWrite writes[] = {
2222 CreateMockWrite(*req),
2223 CreateMockWrite(*rst),
2226 const char* const headers[] = {
2227 "transfer-encoding", "chunked"
2229 scoped_ptr<SpdyFrame> resp(
2230 spdy_util_.ConstructSpdyGetSynReply(headers, 1, 1));
2231 scoped_ptr<SpdyFrame> body(
2232 spdy_util_.ConstructSpdyBodyFrame(1, true));
2233 MockRead reads[] = {
2234 CreateMockRead(*resp),
2235 CreateMockRead(*body),
2236 MockRead(ASYNC, 0, 0) // EOF
2239 DelayedSocketData data(1, reads, arraysize(reads),
2240 writes, arraysize(writes));
2241 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
2242 BoundNetLog(), GetParam(), NULL);
2243 helper.RunToCompletion(&data);
2244 TransactionHelperResult out = helper.output();
2245 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, out.rv);
2247 helper.session()->spdy_session_pool()->CloseAllSessions();
2248 helper.VerifyDataConsumed();
2251 TEST_P(SpdyNetworkTransactionTest, ResetPushWithTransferEncoding) {
2252 // Construct the request.
2253 scoped_ptr<SpdyFrame> req(
2254 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
2255 scoped_ptr<SpdyFrame> rst(
2256 spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR));
2257 MockWrite writes[] = {
2258 CreateMockWrite(*req),
2259 CreateMockWrite(*rst),
2262 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
2263 const char* const headers[] = {
2264 "transfer-encoding", "chunked"
2266 scoped_ptr<SpdyFrame> push(
2267 spdy_util_.ConstructSpdyPush(headers, arraysize(headers) / 2,
2268 2, 1, "http://www.google.com/1"));
2269 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
2270 MockRead reads[] = {
2271 CreateMockRead(*resp),
2272 CreateMockRead(*push),
2273 CreateMockRead(*body),
2274 MockRead(ASYNC, 0, 0) // EOF
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(OK, out.rv);
2284 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
2285 EXPECT_EQ("hello!", out.response_data);
2287 helper.session()->spdy_session_pool()->CloseAllSessions();
2288 helper.VerifyDataConsumed();
2291 TEST_P(SpdyNetworkTransactionTest, CancelledTransaction) {
2292 // Construct the request.
2293 scoped_ptr<SpdyFrame> req(
2294 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
2295 MockWrite writes[] = {
2296 CreateMockWrite(*req),
2299 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
2300 MockRead reads[] = {
2301 CreateMockRead(*resp),
2302 // This following read isn't used by the test, except during the
2303 // RunUntilIdle() call at the end since the SpdySession survives the
2304 // HttpNetworkTransaction and still tries to continue Read()'ing. Any
2305 // MockRead will do here.
2306 MockRead(ASYNC, 0, 0) // EOF
2309 StaticSocketDataProvider data(reads, arraysize(reads),
2310 writes, arraysize(writes));
2312 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
2313 BoundNetLog(), GetParam(), NULL);
2314 helper.RunPreTestSetup();
2315 helper.AddData(&data);
2316 HttpNetworkTransaction* trans = helper.trans();
2318 TestCompletionCallback callback;
2319 int rv = trans->Start(
2320 &CreateGetRequest(), callback.callback(), BoundNetLog());
2321 EXPECT_EQ(ERR_IO_PENDING, rv);
2322 helper.ResetTrans(); // Cancel the transaction.
2324 // Flush the MessageLoop while the SpdySessionDependencies (in particular, the
2325 // MockClientSocketFactory) are still alive.
2326 base::RunLoop().RunUntilIdle();
2327 helper.VerifyDataNotConsumed();
2330 // Verify that the client sends a Rst Frame upon cancelling the stream.
2331 TEST_P(SpdyNetworkTransactionTest, CancelledTransactionSendRst) {
2332 scoped_ptr<SpdyFrame> req(
2333 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
2334 scoped_ptr<SpdyFrame> rst(
2335 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL));
2336 MockWrite writes[] = {
2337 CreateMockWrite(*req, 0, SYNCHRONOUS),
2338 CreateMockWrite(*rst, 2, SYNCHRONOUS),
2341 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
2342 MockRead reads[] = {
2343 CreateMockRead(*resp, 1, ASYNC),
2344 MockRead(ASYNC, 0, 0, 3) // EOF
2347 DeterministicSocketData data(reads, arraysize(reads),
2348 writes, arraysize(writes));
2350 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
2353 helper.SetDeterministic();
2354 helper.RunPreTestSetup();
2355 helper.AddDeterministicData(&data);
2356 HttpNetworkTransaction* trans = helper.trans();
2358 TestCompletionCallback callback;
2360 int rv = trans->Start(
2361 &CreateGetRequest(), callback.callback(), BoundNetLog());
2362 EXPECT_EQ(ERR_IO_PENDING, rv);
2366 helper.ResetTrans();
2370 helper.VerifyDataConsumed();
2373 // Verify that the client can correctly deal with the user callback attempting
2374 // to start another transaction on a session that is closing down. See
2375 // http://crbug.com/47455
2376 TEST_P(SpdyNetworkTransactionTest, StartTransactionOnReadCallback) {
2377 scoped_ptr<SpdyFrame> req(
2378 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
2379 MockWrite writes[] = { CreateMockWrite(*req) };
2380 MockWrite writes2[] = { CreateMockWrite(*req) };
2382 // The indicated length of this frame is longer than its actual length. When
2383 // the session receives an empty frame after this one, it shuts down the
2384 // session, and calls the read callback with the incomplete data.
2385 const uint8 kGetBodyFrame2[] = {
2386 0x00, 0x00, 0x00, 0x01,
2387 0x01, 0x00, 0x00, 0x07,
2388 'h', 'e', 'l', 'l', 'o', '!',
2391 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
2392 MockRead reads[] = {
2393 CreateMockRead(*resp, 2),
2394 MockRead(ASYNC, ERR_IO_PENDING, 3), // Force a pause
2395 MockRead(ASYNC, reinterpret_cast<const char*>(kGetBodyFrame2),
2396 arraysize(kGetBodyFrame2), 4),
2397 MockRead(ASYNC, ERR_IO_PENDING, 5), // Force a pause
2398 MockRead(ASYNC, 0, 0, 6), // EOF
2400 MockRead reads2[] = {
2401 CreateMockRead(*resp, 2),
2402 MockRead(ASYNC, 0, 0, 3), // EOF
2405 OrderedSocketData data(reads, arraysize(reads),
2406 writes, arraysize(writes));
2407 DelayedSocketData data2(1, reads2, arraysize(reads2),
2408 writes2, arraysize(writes2));
2410 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
2411 BoundNetLog(), GetParam(), NULL);
2412 helper.RunPreTestSetup();
2413 helper.AddData(&data);
2414 helper.AddData(&data2);
2415 HttpNetworkTransaction* trans = helper.trans();
2417 // Start the transaction with basic parameters.
2418 TestCompletionCallback callback;
2419 int rv = trans->Start(&helper.request(), callback.callback(), BoundNetLog());
2420 EXPECT_EQ(ERR_IO_PENDING, rv);
2421 rv = callback.WaitForResult();
2423 const int kSize = 3000;
2424 scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(kSize));
2428 base::Bind(&SpdyNetworkTransactionTest::StartTransactionCallback,
2430 // This forces an err_IO_pending, which sets the callback.
2431 data.CompleteRead();
2432 // This finishes the read.
2433 data.CompleteRead();
2434 helper.VerifyDataConsumed();
2437 // Verify that the client can correctly deal with the user callback deleting the
2438 // transaction. Failures will usually be valgrind errors. See
2439 // http://crbug.com/46925
2440 TEST_P(SpdyNetworkTransactionTest, DeleteSessionOnReadCallback) {
2441 scoped_ptr<SpdyFrame> req(
2442 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
2443 MockWrite writes[] = { CreateMockWrite(*req) };
2445 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
2446 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
2447 MockRead reads[] = {
2448 CreateMockRead(*resp.get(), 2),
2449 MockRead(ASYNC, ERR_IO_PENDING, 3), // Force a pause
2450 CreateMockRead(*body.get(), 4),
2451 MockRead(ASYNC, 0, 0, 5), // EOF
2454 OrderedSocketData data(reads, arraysize(reads),
2455 writes, arraysize(writes));
2457 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
2458 BoundNetLog(), GetParam(), NULL);
2459 helper.RunPreTestSetup();
2460 helper.AddData(&data);
2461 HttpNetworkTransaction* trans = helper.trans();
2463 // Start the transaction with basic parameters.
2464 TestCompletionCallback callback;
2465 int rv = trans->Start(&helper.request(), callback.callback(), BoundNetLog());
2466 EXPECT_EQ(ERR_IO_PENDING, rv);
2467 rv = callback.WaitForResult();
2469 // Setup a user callback which will delete the session, and clear out the
2470 // memory holding the stream object. Note that the callback deletes trans.
2471 const int kSize = 3000;
2472 scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(kSize));
2476 base::Bind(&SpdyNetworkTransactionTest::DeleteSessionCallback,
2477 base::Unretained(&helper)));
2478 ASSERT_EQ(ERR_IO_PENDING, rv);
2479 data.CompleteRead();
2481 // Finish running rest of tasks.
2482 base::RunLoop().RunUntilIdle();
2483 helper.VerifyDataConsumed();
2486 // Send a spdy request to www.google.com that gets redirected to www.foo.com.
2487 TEST_P(SpdyNetworkTransactionTest, RedirectGetRequest) {
2488 const SpdyHeaderInfo kSynStartHeader = spdy_util_.MakeSpdyHeader(SYN_STREAM);
2489 scoped_ptr<SpdyHeaderBlock> headers(
2490 spdy_util_.ConstructGetHeaderBlock("http://www.google.com/"));
2491 (*headers)["user-agent"] = "";
2492 (*headers)["accept-encoding"] = "gzip,deflate";
2493 scoped_ptr<SpdyHeaderBlock> headers2(
2494 spdy_util_.ConstructGetHeaderBlock("http://www.foo.com/index.php"));
2495 (*headers2)["user-agent"] = "";
2496 (*headers2)["accept-encoding"] = "gzip,deflate";
2498 // Setup writes/reads to www.google.com
2499 scoped_ptr<SpdyFrame> req(spdy_util_.ConstructSpdyFrame(
2500 kSynStartHeader, headers.Pass()));
2501 scoped_ptr<SpdyFrame> req2(spdy_util_.ConstructSpdyFrame(
2502 kSynStartHeader, headers2.Pass()));
2503 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReplyRedirect(1));
2504 MockWrite writes[] = {
2505 CreateMockWrite(*req, 1),
2507 MockRead reads[] = {
2508 CreateMockRead(*resp, 2),
2509 MockRead(ASYNC, 0, 0, 3) // EOF
2512 // Setup writes/reads to www.foo.com
2513 scoped_ptr<SpdyFrame> resp2(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
2514 scoped_ptr<SpdyFrame> body2(spdy_util_.ConstructSpdyBodyFrame(1, true));
2515 MockWrite writes2[] = {
2516 CreateMockWrite(*req2, 1),
2518 MockRead reads2[] = {
2519 CreateMockRead(*resp2, 2),
2520 CreateMockRead(*body2, 3),
2521 MockRead(ASYNC, 0, 0, 4) // EOF
2523 OrderedSocketData data(reads, arraysize(reads),
2524 writes, arraysize(writes));
2525 OrderedSocketData data2(reads2, arraysize(reads2),
2526 writes2, arraysize(writes2));
2528 // TODO(erikchen): Make test support SPDYSSL, SPDYNPN
2529 HttpStreamFactory::set_force_spdy_over_ssl(false);
2530 HttpStreamFactory::set_force_spdy_always(true);
2533 SpdyURLRequestContext spdy_url_request_context(GetParam().protocol);
2534 net::URLRequest r(GURL("http://www.google.com/"),
2537 &spdy_url_request_context);
2538 spdy_url_request_context.socket_factory().
2539 AddSocketDataProvider(&data);
2540 spdy_url_request_context.socket_factory().
2541 AddSocketDataProvider(&data2);
2543 d.set_quit_on_redirect(true);
2545 base::RunLoop().Run();
2547 EXPECT_EQ(1, d.received_redirect_count());
2549 r.FollowDeferredRedirect();
2550 base::RunLoop().Run();
2551 EXPECT_EQ(1, d.response_started_count());
2552 EXPECT_FALSE(d.received_data_before_response());
2553 EXPECT_EQ(net::URLRequestStatus::SUCCESS, r.status().status());
2554 std::string contents("hello!");
2555 EXPECT_EQ(contents, d.data_received());
2557 EXPECT_TRUE(data.at_read_eof());
2558 EXPECT_TRUE(data.at_write_eof());
2559 EXPECT_TRUE(data2.at_read_eof());
2560 EXPECT_TRUE(data2.at_write_eof());
2563 // Send a spdy request to www.google.com. Get a pushed stream that redirects to
2565 TEST_P(SpdyNetworkTransactionTest, RedirectServerPush) {
2566 const SpdyHeaderInfo kSynStartHeader = spdy_util_.MakeSpdyHeader(SYN_STREAM);
2568 scoped_ptr<SpdyHeaderBlock> headers(
2569 spdy_util_.ConstructGetHeaderBlock("http://www.google.com/"));
2570 (*headers)["user-agent"] = "";
2571 (*headers)["accept-encoding"] = "gzip,deflate";
2573 // Setup writes/reads to www.google.com
2574 scoped_ptr<SpdyFrame> req(
2575 spdy_util_.ConstructSpdyFrame(kSynStartHeader, headers.Pass()));
2576 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
2577 scoped_ptr<SpdyFrame> rep(
2578 spdy_util_.ConstructSpdyPush(NULL,
2582 "http://www.google.com/foo.dat",
2583 "301 Moved Permanently",
2584 "http://www.foo.com/index.php"));
2585 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
2586 scoped_ptr<SpdyFrame> rst(
2587 spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_CANCEL));
2588 MockWrite writes[] = {
2589 CreateMockWrite(*req, 1),
2590 CreateMockWrite(*rst, 6),
2592 MockRead reads[] = {
2593 CreateMockRead(*resp, 2),
2594 CreateMockRead(*rep, 3),
2595 CreateMockRead(*body, 4),
2596 MockRead(ASYNC, ERR_IO_PENDING, 5), // Force a pause
2597 MockRead(ASYNC, 0, 0, 7) // EOF
2600 // Setup writes/reads to www.foo.com
2601 scoped_ptr<SpdyHeaderBlock> headers2(
2602 spdy_util_.ConstructGetHeaderBlock("http://www.foo.com/index.php"));
2603 (*headers2)["user-agent"] = "";
2604 (*headers2)["accept-encoding"] = "gzip,deflate";
2605 scoped_ptr<SpdyFrame> req2(
2606 spdy_util_.ConstructSpdyFrame(kSynStartHeader, headers2.Pass()));
2607 scoped_ptr<SpdyFrame> resp2(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
2608 scoped_ptr<SpdyFrame> body2(spdy_util_.ConstructSpdyBodyFrame(1, true));
2609 MockWrite writes2[] = {
2610 CreateMockWrite(*req2, 1),
2612 MockRead reads2[] = {
2613 CreateMockRead(*resp2, 2),
2614 CreateMockRead(*body2, 3),
2615 MockRead(ASYNC, 0, 0, 5) // EOF
2617 OrderedSocketData data(reads, arraysize(reads),
2618 writes, arraysize(writes));
2619 OrderedSocketData data2(reads2, arraysize(reads2),
2620 writes2, arraysize(writes2));
2622 // TODO(erikchen): Make test support SPDYSSL, SPDYNPN
2623 HttpStreamFactory::set_force_spdy_over_ssl(false);
2624 HttpStreamFactory::set_force_spdy_always(true);
2627 SpdyURLRequestContext spdy_url_request_context(GetParam().protocol);
2629 net::URLRequest r(GURL("http://www.google.com/"),
2632 &spdy_url_request_context);
2633 spdy_url_request_context.socket_factory().
2634 AddSocketDataProvider(&data);
2637 base::RunLoop().Run();
2639 EXPECT_EQ(0, d.received_redirect_count());
2640 std::string contents("hello!");
2641 EXPECT_EQ(contents, d.data_received());
2643 net::URLRequest r2(GURL("http://www.google.com/foo.dat"),
2646 &spdy_url_request_context);
2647 spdy_url_request_context.socket_factory().
2648 AddSocketDataProvider(&data2);
2650 d2.set_quit_on_redirect(true);
2652 base::RunLoop().Run();
2653 EXPECT_EQ(1, d2.received_redirect_count());
2655 r2.FollowDeferredRedirect();
2656 base::RunLoop().Run();
2657 EXPECT_EQ(1, d2.response_started_count());
2658 EXPECT_FALSE(d2.received_data_before_response());
2659 EXPECT_EQ(net::URLRequestStatus::SUCCESS, r2.status().status());
2660 std::string contents2("hello!");
2661 EXPECT_EQ(contents2, d2.data_received());
2663 data.CompleteRead();
2664 data2.CompleteRead();
2665 EXPECT_TRUE(data.at_read_eof());
2666 EXPECT_TRUE(data.at_write_eof());
2667 EXPECT_TRUE(data2.at_read_eof());
2668 EXPECT_TRUE(data2.at_write_eof());
2671 TEST_P(SpdyNetworkTransactionTest, ServerPushSingleDataFrame) {
2672 scoped_ptr<SpdyFrame> stream1_syn(
2673 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
2674 scoped_ptr<SpdyFrame> stream1_body(
2675 spdy_util_.ConstructSpdyBodyFrame(1, true));
2676 MockWrite writes[] = {
2677 CreateMockWrite(*stream1_syn, 1),
2680 scoped_ptr<SpdyFrame>
2681 stream1_reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
2682 scoped_ptr<SpdyFrame>
2683 stream2_syn(spdy_util_.ConstructSpdyPush(NULL,
2687 "http://www.google.com/foo.dat"));
2688 const char kPushedData[] = "pushed";
2689 scoped_ptr<SpdyFrame> stream2_body(
2690 spdy_util_.ConstructSpdyBodyFrame(
2691 2, kPushedData, strlen(kPushedData), true));
2692 MockRead reads[] = {
2693 CreateMockRead(*stream1_reply, 2),
2694 CreateMockRead(*stream2_syn, 3),
2695 CreateMockRead(*stream1_body, 4, SYNCHRONOUS),
2696 CreateMockRead(*stream2_body, 5),
2697 MockRead(ASYNC, ERR_IO_PENDING, 6), // Force a pause
2700 HttpResponseInfo response;
2701 HttpResponseInfo response2;
2702 std::string expected_push_result("pushed");
2703 OrderedSocketData data(reads, arraysize(reads),
2704 writes, arraysize(writes));
2705 RunServerPushTest(&data,
2708 expected_push_result);
2710 // Verify the SYN_REPLY.
2711 EXPECT_TRUE(response.headers.get() != NULL);
2712 EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine());
2714 // Verify the pushed stream.
2715 EXPECT_TRUE(response2.headers.get() != NULL);
2716 EXPECT_EQ("HTTP/1.1 200 OK", response2.headers->GetStatusLine());
2719 TEST_P(SpdyNetworkTransactionTest, ServerPushBeforeSynReply) {
2720 scoped_ptr<SpdyFrame> stream1_syn(
2721 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
2722 scoped_ptr<SpdyFrame> stream1_body(
2723 spdy_util_.ConstructSpdyBodyFrame(1, true));
2724 MockWrite writes[] = {
2725 CreateMockWrite(*stream1_syn, 1),
2728 scoped_ptr<SpdyFrame>
2729 stream1_reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
2730 scoped_ptr<SpdyFrame>
2731 stream2_syn(spdy_util_.ConstructSpdyPush(NULL,
2735 "http://www.google.com/foo.dat"));
2736 const char kPushedData[] = "pushed";
2737 scoped_ptr<SpdyFrame> stream2_body(
2738 spdy_util_.ConstructSpdyBodyFrame(
2739 2, kPushedData, strlen(kPushedData), true));
2740 MockRead reads[] = {
2741 CreateMockRead(*stream2_syn, 2),
2742 CreateMockRead(*stream1_reply, 3),
2743 CreateMockRead(*stream1_body, 4, SYNCHRONOUS),
2744 CreateMockRead(*stream2_body, 5),
2745 MockRead(ASYNC, ERR_IO_PENDING, 6), // Force a pause
2748 HttpResponseInfo response;
2749 HttpResponseInfo response2;
2750 std::string expected_push_result("pushed");
2751 OrderedSocketData data(reads, arraysize(reads),
2752 writes, arraysize(writes));
2753 RunServerPushTest(&data,
2756 expected_push_result);
2758 // Verify the SYN_REPLY.
2759 EXPECT_TRUE(response.headers.get() != NULL);
2760 EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine());
2762 // Verify the pushed stream.
2763 EXPECT_TRUE(response2.headers.get() != NULL);
2764 EXPECT_EQ("HTTP/1.1 200 OK", response2.headers->GetStatusLine());
2767 TEST_P(SpdyNetworkTransactionTest, ServerPushSingleDataFrame2) {
2768 scoped_ptr<SpdyFrame> stream1_syn(
2769 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
2770 MockWrite writes[] = { CreateMockWrite(*stream1_syn, 1), };
2772 scoped_ptr<SpdyFrame>
2773 stream1_reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
2774 scoped_ptr<SpdyFrame>
2775 stream2_syn(spdy_util_.ConstructSpdyPush(NULL,
2779 "http://www.google.com/foo.dat"));
2780 const char kPushedData[] = "pushed";
2781 scoped_ptr<SpdyFrame> stream2_body(
2782 spdy_util_.ConstructSpdyBodyFrame(
2783 2, kPushedData, strlen(kPushedData), true));
2784 scoped_ptr<SpdyFrame>
2785 stream1_body(spdy_util_.ConstructSpdyBodyFrame(1, true));
2786 MockRead reads[] = {
2787 CreateMockRead(*stream1_reply, 2),
2788 CreateMockRead(*stream2_syn, 3),
2789 CreateMockRead(*stream2_body, 4),
2790 CreateMockRead(*stream1_body, 5, SYNCHRONOUS),
2791 MockRead(ASYNC, ERR_IO_PENDING, 6), // Force a pause
2794 HttpResponseInfo response;
2795 HttpResponseInfo response2;
2796 std::string expected_push_result("pushed");
2797 OrderedSocketData data(reads, arraysize(reads),
2798 writes, arraysize(writes));
2799 RunServerPushTest(&data,
2802 expected_push_result);
2804 // Verify the SYN_REPLY.
2805 EXPECT_TRUE(response.headers.get() != NULL);
2806 EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine());
2808 // Verify the pushed stream.
2809 EXPECT_TRUE(response2.headers.get() != NULL);
2810 EXPECT_EQ("HTTP/1.1 200 OK", response2.headers->GetStatusLine());
2813 TEST_P(SpdyNetworkTransactionTest, ServerPushServerAborted) {
2814 scoped_ptr<SpdyFrame> stream1_syn(
2815 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
2816 scoped_ptr<SpdyFrame> stream1_body(
2817 spdy_util_.ConstructSpdyBodyFrame(1, true));
2818 MockWrite writes[] = {
2819 CreateMockWrite(*stream1_syn, 1),
2822 scoped_ptr<SpdyFrame>
2823 stream1_reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
2824 scoped_ptr<SpdyFrame>
2825 stream2_syn(spdy_util_.ConstructSpdyPush(NULL,
2829 "http://www.google.com/foo.dat"));
2830 scoped_ptr<SpdyFrame> stream2_rst(
2831 spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR));
2832 MockRead reads[] = {
2833 CreateMockRead(*stream1_reply, 2),
2834 CreateMockRead(*stream2_syn, 3),
2835 CreateMockRead(*stream2_rst, 4),
2836 CreateMockRead(*stream1_body, 5, SYNCHRONOUS),
2837 MockRead(ASYNC, ERR_IO_PENDING, 6), // Force a pause
2840 OrderedSocketData data(reads, arraysize(reads),
2841 writes, arraysize(writes));
2842 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
2843 BoundNetLog(), GetParam(), NULL);
2845 helper.RunPreTestSetup();
2846 helper.AddData(&data);
2848 HttpNetworkTransaction* trans = helper.trans();
2850 // Start the transaction with basic parameters.
2851 TestCompletionCallback callback;
2852 int rv = trans->Start(
2853 &CreateGetRequest(), callback.callback(), BoundNetLog());
2854 EXPECT_EQ(ERR_IO_PENDING, rv);
2855 rv = callback.WaitForResult();
2858 // Verify that we consumed all test data.
2859 EXPECT_TRUE(data.at_read_eof()) << "Read count: "
2860 << data.read_count()
2862 << data.read_index();
2863 EXPECT_TRUE(data.at_write_eof()) << "Write count: "
2864 << data.write_count()
2866 << data.write_index();
2868 // Verify the SYN_REPLY.
2869 HttpResponseInfo response = *trans->GetResponseInfo();
2870 EXPECT_TRUE(response.headers.get() != NULL);
2871 EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine());
2874 // Verify that we don't leak streams and that we properly send a reset
2875 // if the server pushes the same stream twice.
2876 TEST_P(SpdyNetworkTransactionTest, ServerPushDuplicate) {
2877 scoped_ptr<SpdyFrame> stream1_syn(
2878 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
2879 scoped_ptr<SpdyFrame> stream1_body(
2880 spdy_util_.ConstructSpdyBodyFrame(1, true));
2881 scoped_ptr<SpdyFrame> stream3_rst(
2882 spdy_util_.ConstructSpdyRstStream(4, RST_STREAM_PROTOCOL_ERROR));
2883 MockWrite writes[] = {
2884 CreateMockWrite(*stream1_syn, 1),
2885 CreateMockWrite(*stream3_rst, 5),
2888 scoped_ptr<SpdyFrame>
2889 stream1_reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
2890 scoped_ptr<SpdyFrame>
2891 stream2_syn(spdy_util_.ConstructSpdyPush(NULL,
2895 "http://www.google.com/foo.dat"));
2896 const char kPushedData[] = "pushed";
2897 scoped_ptr<SpdyFrame> stream2_body(
2898 spdy_util_.ConstructSpdyBodyFrame(
2899 2, kPushedData, strlen(kPushedData), true));
2900 scoped_ptr<SpdyFrame>
2901 stream3_syn(spdy_util_.ConstructSpdyPush(NULL,
2905 "http://www.google.com/foo.dat"));
2906 MockRead reads[] = {
2907 CreateMockRead(*stream1_reply, 2),
2908 CreateMockRead(*stream2_syn, 3),
2909 CreateMockRead(*stream3_syn, 4),
2910 CreateMockRead(*stream1_body, 6, SYNCHRONOUS),
2911 CreateMockRead(*stream2_body, 7),
2912 MockRead(ASYNC, ERR_IO_PENDING, 8), // Force a pause
2915 HttpResponseInfo response;
2916 HttpResponseInfo response2;
2917 std::string expected_push_result("pushed");
2918 OrderedSocketData data(reads, arraysize(reads),
2919 writes, arraysize(writes));
2920 RunServerPushTest(&data,
2923 expected_push_result);
2925 // Verify the SYN_REPLY.
2926 EXPECT_TRUE(response.headers.get() != NULL);
2927 EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine());
2929 // Verify the pushed stream.
2930 EXPECT_TRUE(response2.headers.get() != NULL);
2931 EXPECT_EQ("HTTP/1.1 200 OK", response2.headers->GetStatusLine());
2934 TEST_P(SpdyNetworkTransactionTest, ServerPushMultipleDataFrame) {
2935 scoped_ptr<SpdyFrame> stream1_syn(
2936 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
2937 scoped_ptr<SpdyFrame> stream1_body(
2938 spdy_util_.ConstructSpdyBodyFrame(1, true));
2939 MockWrite writes[] = {
2940 CreateMockWrite(*stream1_syn, 1),
2943 scoped_ptr<SpdyFrame>
2944 stream1_reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
2945 scoped_ptr<SpdyFrame>
2946 stream2_syn(spdy_util_.ConstructSpdyPush(NULL,
2950 "http://www.google.com/foo.dat"));
2951 static const char kPushedData[] = "pushed my darling hello my baby";
2952 scoped_ptr<SpdyFrame> stream2_body_base(
2953 spdy_util_.ConstructSpdyBodyFrame(
2954 2, kPushedData, strlen(kPushedData), true));
2955 const size_t kChunkSize = strlen(kPushedData) / 4;
2956 scoped_ptr<SpdyFrame> stream2_body1(
2957 new SpdyFrame(stream2_body_base->data(), kChunkSize, false));
2958 scoped_ptr<SpdyFrame> stream2_body2(
2959 new SpdyFrame(stream2_body_base->data() + kChunkSize, kChunkSize, false));
2960 scoped_ptr<SpdyFrame> stream2_body3(
2961 new SpdyFrame(stream2_body_base->data() + 2 * kChunkSize,
2962 kChunkSize, false));
2963 scoped_ptr<SpdyFrame> stream2_body4(
2964 new SpdyFrame(stream2_body_base->data() + 3 * kChunkSize,
2965 stream2_body_base->size() - 3 * kChunkSize, false));
2966 MockRead reads[] = {
2967 CreateMockRead(*stream1_reply, 2),
2968 CreateMockRead(*stream2_syn, 3),
2969 CreateMockRead(*stream2_body1, 4),
2970 CreateMockRead(*stream2_body2, 5),
2971 CreateMockRead(*stream2_body3, 6),
2972 CreateMockRead(*stream2_body4, 7),
2973 CreateMockRead(*stream1_body, 8, SYNCHRONOUS),
2974 MockRead(ASYNC, ERR_IO_PENDING, 9), // Force a pause
2977 HttpResponseInfo response;
2978 HttpResponseInfo response2;
2979 std::string expected_push_result("pushed my darling hello my baby");
2980 OrderedSocketData data(reads, arraysize(reads),
2981 writes, arraysize(writes));
2982 RunServerPushTest(&data, &response, &response2, kPushedData);
2984 // Verify the SYN_REPLY.
2985 EXPECT_TRUE(response.headers.get() != NULL);
2986 EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine());
2988 // Verify the pushed stream.
2989 EXPECT_TRUE(response2.headers.get() != NULL);
2990 EXPECT_EQ("HTTP/1.1 200 OK", response2.headers->GetStatusLine());
2993 TEST_P(SpdyNetworkTransactionTest, ServerPushMultipleDataFrameInterrupted) {
2994 scoped_ptr<SpdyFrame> stream1_syn(
2995 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
2996 scoped_ptr<SpdyFrame> stream1_body(
2997 spdy_util_.ConstructSpdyBodyFrame(1, true));
2998 MockWrite writes[] = {
2999 CreateMockWrite(*stream1_syn, 1),
3002 scoped_ptr<SpdyFrame>
3003 stream1_reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
3004 scoped_ptr<SpdyFrame>
3005 stream2_syn(spdy_util_.ConstructSpdyPush(NULL,
3009 "http://www.google.com/foo.dat"));
3010 static const char kPushedData[] = "pushed my darling hello my baby";
3011 scoped_ptr<SpdyFrame> stream2_body_base(
3012 spdy_util_.ConstructSpdyBodyFrame(
3013 2, kPushedData, strlen(kPushedData), true));
3014 const size_t kChunkSize = strlen(kPushedData) / 4;
3015 scoped_ptr<SpdyFrame> stream2_body1(
3016 new SpdyFrame(stream2_body_base->data(), kChunkSize, false));
3017 scoped_ptr<SpdyFrame> stream2_body2(
3018 new SpdyFrame(stream2_body_base->data() + kChunkSize, kChunkSize, false));
3019 scoped_ptr<SpdyFrame> stream2_body3(
3020 new SpdyFrame(stream2_body_base->data() + 2 * kChunkSize,
3021 kChunkSize, false));
3022 scoped_ptr<SpdyFrame> stream2_body4(
3023 new SpdyFrame(stream2_body_base->data() + 3 * kChunkSize,
3024 stream2_body_base->size() - 3 * kChunkSize, false));
3025 MockRead reads[] = {
3026 CreateMockRead(*stream1_reply, 2),
3027 CreateMockRead(*stream2_syn, 3),
3028 CreateMockRead(*stream2_body1, 4),
3029 CreateMockRead(*stream2_body2, 5),
3030 MockRead(ASYNC, ERR_IO_PENDING, 6), // Force a pause
3031 CreateMockRead(*stream2_body3, 7),
3032 CreateMockRead(*stream2_body4, 8),
3033 CreateMockRead(*stream1_body.get(), 9, SYNCHRONOUS),
3034 MockRead(ASYNC, ERR_IO_PENDING, 10) // Force a pause.
3037 HttpResponseInfo response;
3038 HttpResponseInfo response2;
3039 OrderedSocketData data(reads, arraysize(reads),
3040 writes, arraysize(writes));
3041 RunServerPushTest(&data, &response, &response2, kPushedData);
3043 // Verify the SYN_REPLY.
3044 EXPECT_TRUE(response.headers.get() != NULL);
3045 EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine());
3047 // Verify the pushed stream.
3048 EXPECT_TRUE(response2.headers.get() != NULL);
3049 EXPECT_EQ("HTTP/1.1 200 OK", response2.headers->GetStatusLine());
3052 TEST_P(SpdyNetworkTransactionTest, ServerPushInvalidAssociatedStreamID0) {
3053 if (spdy_util_.spdy_version() == SPDY4) {
3054 // TODO(jgraettinger): We don't support associated stream
3055 // checks in SPDY4 yet.
3058 scoped_ptr<SpdyFrame> stream1_syn(
3059 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
3060 scoped_ptr<SpdyFrame> stream1_body(
3061 spdy_util_.ConstructSpdyBodyFrame(1, true));
3062 scoped_ptr<SpdyFrame> stream2_rst(
3063 spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_REFUSED_STREAM));
3064 MockWrite writes[] = {
3065 CreateMockWrite(*stream1_syn, 1),
3066 CreateMockWrite(*stream2_rst, 4),
3069 scoped_ptr<SpdyFrame>
3070 stream1_reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
3071 scoped_ptr<SpdyFrame>
3072 stream2_syn(spdy_util_.ConstructSpdyPush(NULL,
3076 "http://www.google.com/foo.dat"));
3077 MockRead reads[] = {
3078 CreateMockRead(*stream1_reply, 2),
3079 CreateMockRead(*stream2_syn, 3),
3080 CreateMockRead(*stream1_body, 4),
3081 MockRead(ASYNC, ERR_IO_PENDING, 5) // Force a pause
3084 OrderedSocketData data(reads, arraysize(reads),
3085 writes, arraysize(writes));
3086 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
3087 BoundNetLog(), GetParam(), NULL);
3089 helper.RunPreTestSetup();
3090 helper.AddData(&data);
3092 HttpNetworkTransaction* trans = helper.trans();
3094 // Start the transaction with basic parameters.
3095 TestCompletionCallback callback;
3096 int rv = trans->Start(
3097 &CreateGetRequest(), callback.callback(), BoundNetLog());
3098 EXPECT_EQ(ERR_IO_PENDING, rv);
3099 rv = callback.WaitForResult();
3102 // Verify that we consumed all test data.
3103 EXPECT_TRUE(data.at_read_eof()) << "Read count: "
3104 << data.read_count()
3106 << data.read_index();
3107 EXPECT_TRUE(data.at_write_eof()) << "Write count: "
3108 << data.write_count()
3110 << data.write_index();
3112 // Verify the SYN_REPLY.
3113 HttpResponseInfo response = *trans->GetResponseInfo();
3114 EXPECT_TRUE(response.headers.get() != NULL);
3115 EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine());
3118 TEST_P(SpdyNetworkTransactionTest, ServerPushInvalidAssociatedStreamID9) {
3119 if (spdy_util_.spdy_version() == SPDY4) {
3120 // TODO(jgraettinger): We don't support associated stream
3121 // checks in SPDY4 yet.
3124 scoped_ptr<SpdyFrame> stream1_syn(
3125 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
3126 scoped_ptr<SpdyFrame> stream1_body(
3127 spdy_util_.ConstructSpdyBodyFrame(1, true));
3128 scoped_ptr<SpdyFrame> stream2_rst(
3129 spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_INVALID_STREAM));
3130 MockWrite writes[] = {
3131 CreateMockWrite(*stream1_syn, 1),
3132 CreateMockWrite(*stream2_rst, 4),
3135 scoped_ptr<SpdyFrame>
3136 stream1_reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
3137 scoped_ptr<SpdyFrame>
3138 stream2_syn(spdy_util_.ConstructSpdyPush(NULL,
3142 "http://www.google.com/foo.dat"));
3143 MockRead reads[] = {
3144 CreateMockRead(*stream1_reply, 2),
3145 CreateMockRead(*stream2_syn, 3),
3146 CreateMockRead(*stream1_body, 4),
3147 MockRead(ASYNC, ERR_IO_PENDING, 5), // Force a pause
3150 OrderedSocketData data(reads, arraysize(reads),
3151 writes, arraysize(writes));
3152 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
3153 BoundNetLog(), GetParam(), NULL);
3155 helper.RunPreTestSetup();
3156 helper.AddData(&data);
3158 HttpNetworkTransaction* trans = helper.trans();
3160 // Start the transaction with basic parameters.
3161 TestCompletionCallback callback;
3162 int rv = trans->Start(
3163 &CreateGetRequest(), callback.callback(), BoundNetLog());
3164 EXPECT_EQ(ERR_IO_PENDING, rv);
3165 rv = callback.WaitForResult();
3168 // Verify that we consumed all test data.
3169 EXPECT_TRUE(data.at_read_eof()) << "Read count: "
3170 << data.read_count()
3172 << data.read_index();
3173 EXPECT_TRUE(data.at_write_eof()) << "Write count: "
3174 << data.write_count()
3176 << data.write_index();
3178 // Verify the SYN_REPLY.
3179 HttpResponseInfo response = *trans->GetResponseInfo();
3180 EXPECT_TRUE(response.headers.get() != NULL);
3181 EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine());
3184 TEST_P(SpdyNetworkTransactionTest, ServerPushNoURL) {
3185 scoped_ptr<SpdyFrame> stream1_syn(
3186 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
3187 scoped_ptr<SpdyFrame> stream1_body(
3188 spdy_util_.ConstructSpdyBodyFrame(1, true));
3189 scoped_ptr<SpdyFrame> stream2_rst(
3190 spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR));
3191 MockWrite writes[] = {
3192 CreateMockWrite(*stream1_syn, 1),
3193 CreateMockWrite(*stream2_rst, 4),
3196 scoped_ptr<SpdyFrame>
3197 stream1_reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
3198 scoped_ptr<SpdyHeaderBlock> incomplete_headers(new SpdyHeaderBlock());
3199 (*incomplete_headers)["hello"] = "bye";
3200 (*incomplete_headers)[spdy_util_.GetStatusKey()] = "200 OK";
3201 (*incomplete_headers)[spdy_util_.GetVersionKey()] = "HTTP/1.1";
3202 scoped_ptr<SpdyFrame> stream2_syn(
3203 spdy_util_.ConstructSpdyControlFrame(incomplete_headers.Pass(),
3209 // Associated stream ID
3211 MockRead reads[] = {
3212 CreateMockRead(*stream1_reply, 2),
3213 CreateMockRead(*stream2_syn, 3),
3214 CreateMockRead(*stream1_body, 4),
3215 MockRead(ASYNC, ERR_IO_PENDING, 5) // Force a pause
3218 OrderedSocketData data(reads, arraysize(reads),
3219 writes, arraysize(writes));
3220 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
3221 BoundNetLog(), GetParam(), NULL);
3223 helper.RunPreTestSetup();
3224 helper.AddData(&data);
3226 HttpNetworkTransaction* trans = helper.trans();
3228 // Start the transaction with basic parameters.
3229 TestCompletionCallback callback;
3230 int rv = trans->Start(
3231 &CreateGetRequest(), callback.callback(), BoundNetLog());
3232 EXPECT_EQ(ERR_IO_PENDING, rv);
3233 rv = callback.WaitForResult();
3235 // Verify that we consumed all test data.
3236 EXPECT_TRUE(data.at_read_eof()) << "Read count: "
3237 << data.read_count()
3239 << data.read_index();
3240 EXPECT_TRUE(data.at_write_eof()) << "Write count: "
3241 << data.write_count()
3243 << data.write_index();
3245 // Verify the SYN_REPLY.
3246 HttpResponseInfo response = *trans->GetResponseInfo();
3247 EXPECT_TRUE(response.headers.get() != NULL);
3248 EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine());
3251 // Verify that various SynReply headers parse correctly through the
3253 TEST_P(SpdyNetworkTransactionTest, SynReplyHeaders) {
3254 struct SynReplyHeadersTests {
3256 const char* extra_headers[5];
3257 SpdyHeaderBlock expected_headers;
3259 // This uses a multi-valued cookie header.
3262 "cookie", "val2", // will get appended separated by NULL
3266 // This is the minimalist set of headers.
3270 // Headers with a comma separated list.
3272 { "cookie", "val1,val2",
3278 test_cases[0].expected_headers["cookie"] = "val1";
3279 test_cases[0].expected_headers["cookie"] += '\0';
3280 test_cases[0].expected_headers["cookie"] += "val2";
3281 test_cases[0].expected_headers["hello"] = "bye";
3282 test_cases[0].expected_headers["status"] = "200";
3283 test_cases[0].expected_headers["version"] = "HTTP/1.1";
3285 test_cases[1].expected_headers["hello"] = "bye";
3286 test_cases[1].expected_headers["status"] = "200";
3287 test_cases[1].expected_headers["version"] = "HTTP/1.1";
3289 test_cases[2].expected_headers["cookie"] = "val1,val2";
3290 test_cases[2].expected_headers["hello"] = "bye";
3291 test_cases[2].expected_headers["status"] = "200";
3292 test_cases[2].expected_headers["version"] = "HTTP/1.1";
3294 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) {
3295 scoped_ptr<SpdyFrame> req(
3296 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
3297 MockWrite writes[] = { CreateMockWrite(*req) };
3299 scoped_ptr<SpdyFrame> resp(
3300 spdy_util_.ConstructSpdyGetSynReply(test_cases[i].extra_headers,
3301 test_cases[i].num_headers,
3303 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
3304 MockRead reads[] = {
3305 CreateMockRead(*resp),
3306 CreateMockRead(*body),
3307 MockRead(ASYNC, 0, 0) // EOF
3310 DelayedSocketData data(1, reads, arraysize(reads),
3311 writes, arraysize(writes));
3312 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
3313 BoundNetLog(), GetParam(), NULL);
3314 helper.RunToCompletion(&data);
3315 TransactionHelperResult out = helper.output();
3317 EXPECT_EQ(OK, out.rv);
3318 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
3319 EXPECT_EQ("hello!", out.response_data);
3321 scoped_refptr<HttpResponseHeaders> headers = out.response_info.headers;
3322 EXPECT_TRUE(headers.get() != NULL);
3324 std::string name, value;
3325 SpdyHeaderBlock header_block;
3326 while (headers->EnumerateHeaderLines(&iter, &name, &value)) {
3327 if (header_block[name].empty()) {
3328 header_block[name] = value;
3330 header_block[name] += '\0';
3331 header_block[name] += value;
3334 EXPECT_EQ(test_cases[i].expected_headers, header_block);
3338 // Verify that various SynReply headers parse vary fields correctly
3339 // through the HTTP layer, and the response matches the request.
3340 TEST_P(SpdyNetworkTransactionTest, SynReplyHeadersVary) {
3341 static const SpdyHeaderInfo syn_reply_info = {
3342 SYN_REPLY, // Syn Reply
3344 0, // Associated Stream ID
3345 ConvertRequestPriorityToSpdyPriority(
3346 LOWEST, spdy_util_.spdy_version()),
3347 kSpdyCredentialSlotUnused,
3348 CONTROL_FLAG_NONE, // Control Flags
3349 false, // Compressed
3350 RST_STREAM_INVALID, // Status
3353 DATA_FLAG_NONE // Data Flags
3355 // Modify the following data to change/add test cases:
3356 struct SynReplyTests {
3357 const SpdyHeaderInfo* syn_reply;
3360 const char* extra_headers[2][16];
3362 // Test the case of a multi-valued cookie. When the value is delimited
3363 // with NUL characters, it needs to be unfolded into multiple headers.
3368 { { "cookie", "val1,val2",
3372 spdy_util_.GetStatusKey(), "200",
3373 spdy_util_.GetPathKey(), "/index.php",
3374 spdy_util_.GetVersionKey(), "HTTP/1.1",
3378 }, { // Multiple vary fields.
3382 { { "friend", "barney",
3383 "enemy", "snaggletooth",
3388 spdy_util_.GetStatusKey(), "200",
3389 spdy_util_.GetPathKey(), "/index.php",
3390 spdy_util_.GetVersionKey(), "HTTP/1.1",
3394 }, { // Test a '*' vary field.
3398 { { "cookie", "val1,val2",
3402 spdy_util_.GetStatusKey(), "200",
3403 spdy_util_.GetPathKey(), "/index.php",
3404 spdy_util_.GetVersionKey(), "HTTP/1.1",
3408 }, { // Multiple comma-separated vary fields.
3412 { { "friend", "barney",
3413 "enemy", "snaggletooth",
3416 { "vary", "friend,enemy",
3417 spdy_util_.GetStatusKey(), "200",
3418 spdy_util_.GetPathKey(), "/index.php",
3419 spdy_util_.GetVersionKey(), "HTTP/1.1",
3426 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) {
3427 // Construct the request.
3428 scoped_ptr<SpdyFrame> frame_req(
3429 spdy_util_.ConstructSpdyGet(test_cases[i].extra_headers[0],
3430 test_cases[i].num_headers[0],
3431 false, 1, LOWEST, true));
3433 MockWrite writes[] = {
3434 CreateMockWrite(*frame_req),
3437 // Construct the reply.
3438 scoped_ptr<SpdyFrame> frame_reply(
3439 spdy_util_.ConstructSpdyFrame(*test_cases[i].syn_reply,
3440 test_cases[i].extra_headers[1],
3441 test_cases[i].num_headers[1],
3445 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
3446 MockRead reads[] = {
3447 CreateMockRead(*frame_reply),
3448 CreateMockRead(*body),
3449 MockRead(ASYNC, 0, 0) // EOF
3452 // Attach the headers to the request.
3453 int header_count = test_cases[i].num_headers[0];
3455 HttpRequestInfo request = CreateGetRequest();
3456 for (int ct = 0; ct < header_count; ct++) {
3457 const char* header_key = test_cases[i].extra_headers[0][ct * 2];
3458 const char* header_value = test_cases[i].extra_headers[0][ct * 2 + 1];
3459 request.extra_headers.SetHeader(header_key, header_value);
3462 DelayedSocketData data(1, reads, arraysize(reads),
3463 writes, arraysize(writes));
3464 NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY,
3465 BoundNetLog(), GetParam(), NULL);
3466 helper.RunToCompletion(&data);
3467 TransactionHelperResult out = helper.output();
3469 EXPECT_EQ(OK, out.rv) << i;
3470 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line) << i;
3471 EXPECT_EQ("hello!", out.response_data) << i;
3473 // Test the response information.
3474 EXPECT_TRUE(out.response_info.response_time >
3475 out.response_info.request_time) << i;
3476 base::TimeDelta test_delay = out.response_info.response_time -
3477 out.response_info.request_time;
3478 base::TimeDelta min_expected_delay;
3479 min_expected_delay.FromMilliseconds(10);
3480 EXPECT_GT(test_delay.InMillisecondsF(),
3481 min_expected_delay.InMillisecondsF()) << i;
3482 EXPECT_EQ(out.response_info.vary_data.is_valid(),
3483 test_cases[i].vary_matches) << i;
3485 // Check the headers.
3486 scoped_refptr<HttpResponseHeaders> headers = out.response_info.headers;
3487 ASSERT_TRUE(headers.get() != NULL) << i;
3489 std::string name, value, lines;
3490 while (headers->EnumerateHeaderLines(&iter, &name, &value)) {
3493 lines.append(value);
3497 // Construct the expected header reply string.
3498 SpdyHeaderBlock reply_headers;
3499 AppendToHeaderBlock(test_cases[i].extra_headers[1],
3500 test_cases[i].num_headers[1],
3502 std::string expected_reply =
3503 spdy_util_.ConstructSpdyReplyString(reply_headers);
3504 EXPECT_EQ(expected_reply, lines) << i;
3508 // Verify that we don't crash on invalid SynReply responses.
3509 TEST_P(SpdyNetworkTransactionTest, InvalidSynReply) {
3510 const SpdyHeaderInfo kSynStartHeader = {
3511 SYN_REPLY, // Kind = SynReply
3513 0, // Associated stream ID
3514 ConvertRequestPriorityToSpdyPriority(
3515 LOWEST, spdy_util_.spdy_version()),
3516 kSpdyCredentialSlotUnused,
3517 CONTROL_FLAG_NONE, // Control Flags
3518 false, // Compressed
3519 RST_STREAM_INVALID, // Status
3522 DATA_FLAG_NONE // Data Flags
3525 struct InvalidSynReplyTests {
3527 const char* headers[10];
3529 // SYN_REPLY missing status header
3533 spdy_util_.GetPathKey(), "/index.php",
3534 spdy_util_.GetVersionKey(), "HTTP/1.1",
3538 // SYN_REPLY missing version header
3541 spdy_util_.GetPathKey(), "/index.php",
3545 // SYN_REPLY with no headers
3549 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) {
3550 scoped_ptr<SpdyFrame> req(
3551 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
3552 scoped_ptr<SpdyFrame> rst(
3553 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR));
3554 MockWrite writes[] = {
3555 CreateMockWrite(*req),
3556 CreateMockWrite(*rst),
3559 scoped_ptr<SpdyFrame> resp(
3560 spdy_util_.ConstructSpdyFrame(kSynStartHeader,
3562 test_cases[i].headers,
3563 test_cases[i].num_headers));
3564 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
3565 MockRead reads[] = {
3566 CreateMockRead(*resp),
3567 MockRead(ASYNC, 0, 0) // EOF
3570 DelayedSocketData data(1, reads, arraysize(reads),
3571 writes, arraysize(writes));
3572 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
3573 BoundNetLog(), GetParam(), NULL);
3574 helper.RunToCompletion(&data);
3575 TransactionHelperResult out = helper.output();
3576 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, out.rv);
3580 // Verify that we don't crash on some corrupt frames.
3581 TEST_P(SpdyNetworkTransactionTest, CorruptFrameSessionError) {
3582 // This is the length field that's too short.
3583 scoped_ptr<SpdyFrame> syn_reply_wrong_length(
3584 spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
3585 BufferedSpdyFramer framer(spdy_util_.spdy_version(), false);
3587 (spdy_util_.spdy_version() < SPDY4) ?
3588 syn_reply_wrong_length->size() - framer.GetControlFrameHeaderSize() :
3589 syn_reply_wrong_length->size();
3590 size_t wrong_size = right_size - 4;
3591 test::SetFrameLength(syn_reply_wrong_length.get(),
3593 spdy_util_.spdy_version());
3595 struct SynReplyTests {
3596 const SpdyFrame* syn_reply;
3598 { syn_reply_wrong_length.get(), },
3601 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) {
3602 scoped_ptr<SpdyFrame> req(
3603 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
3604 scoped_ptr<SpdyFrame> rst(
3605 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR));
3606 MockWrite writes[] = {
3607 CreateMockWrite(*req),
3608 CreateMockWrite(*rst),
3611 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
3612 MockRead reads[] = {
3613 MockRead(ASYNC, test_cases[i].syn_reply->data(), wrong_size),
3614 CreateMockRead(*body),
3615 MockRead(ASYNC, 0, 0) // EOF
3618 DelayedSocketData data(1, reads, arraysize(reads),
3619 writes, arraysize(writes));
3620 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
3621 BoundNetLog(), GetParam(), NULL);
3622 helper.RunToCompletion(&data);
3623 TransactionHelperResult out = helper.output();
3624 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, out.rv);
3628 // Test that we shutdown correctly on write errors.
3629 TEST_P(SpdyNetworkTransactionTest, WriteError) {
3630 scoped_ptr<SpdyFrame> req(
3631 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
3632 MockWrite writes[] = {
3633 // We'll write 10 bytes successfully
3634 MockWrite(ASYNC, req->data(), 10, 0),
3635 // Followed by ERROR!
3636 MockWrite(ASYNC, ERR_FAILED, 1),
3639 MockRead reads[] = {
3640 MockRead(ASYNC, 0, 2) // EOF
3643 DeterministicSocketData data(reads, arraysize(reads),
3644 writes, arraysize(writes));
3646 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
3647 BoundNetLog(), GetParam(), NULL);
3648 helper.SetDeterministic();
3649 helper.RunPreTestSetup();
3650 helper.AddDeterministicData(&data);
3651 EXPECT_TRUE(helper.StartDefaultTest());
3653 helper.FinishDefaultTest();
3654 EXPECT_TRUE(data.at_write_eof());
3655 EXPECT_TRUE(!data.at_read_eof());
3656 TransactionHelperResult out = helper.output();
3657 EXPECT_EQ(ERR_FAILED, out.rv);
3660 // Test that partial writes work.
3661 TEST_P(SpdyNetworkTransactionTest, PartialWrite) {
3662 // Chop the SYN_STREAM frame into 5 chunks.
3663 scoped_ptr<SpdyFrame> req(
3664 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
3665 const int kChunks = 5;
3666 scoped_ptr<MockWrite[]> writes(ChopWriteFrame(*req.get(), kChunks));
3668 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
3669 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
3670 MockRead reads[] = {
3671 CreateMockRead(*resp),
3672 CreateMockRead(*body),
3673 MockRead(ASYNC, 0, 0) // EOF
3676 DelayedSocketData data(kChunks, reads, arraysize(reads),
3677 writes.get(), kChunks);
3678 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
3679 BoundNetLog(), GetParam(), NULL);
3680 helper.RunToCompletion(&data);
3681 TransactionHelperResult out = helper.output();
3682 EXPECT_EQ(OK, out.rv);
3683 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
3684 EXPECT_EQ("hello!", out.response_data);
3687 // In this test, we enable compression, but get a uncompressed SynReply from
3688 // the server. Verify that teardown is all clean.
3689 TEST_P(SpdyNetworkTransactionTest, DecompressFailureOnSynReply) {
3690 scoped_ptr<SpdyFrame> compressed(
3691 spdy_util_.ConstructSpdyGet(NULL, 0, true, 1, LOWEST, true));
3692 scoped_ptr<SpdyFrame> rst(
3693 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR));
3694 MockWrite writes[] = {
3695 CreateMockWrite(*compressed),
3698 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
3699 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
3700 MockRead reads[] = {
3701 CreateMockRead(*resp),
3704 DelayedSocketData data(1, reads, arraysize(reads),
3705 writes, arraysize(writes));
3706 SpdySessionDependencies* session_deps =
3707 CreateSpdySessionDependencies(GetParam());
3708 session_deps->enable_compression = true;
3709 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
3710 BoundNetLog(), GetParam(), session_deps);
3711 helper.RunToCompletion(&data);
3712 TransactionHelperResult out = helper.output();
3713 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, out.rv);
3717 // Test that the NetLog contains good data for a simple GET request.
3718 TEST_P(SpdyNetworkTransactionTest, NetLog) {
3719 static const char* const kExtraHeaders[] = {
3720 "user-agent", "Chrome",
3722 scoped_ptr<SpdyFrame> req(
3723 spdy_util_.ConstructSpdyGet(kExtraHeaders, 1, false, 1, LOWEST, true));
3724 MockWrite writes[] = { CreateMockWrite(*req) };
3726 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
3727 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
3728 MockRead reads[] = {
3729 CreateMockRead(*resp),
3730 CreateMockRead(*body),
3731 MockRead(ASYNC, 0, 0) // EOF
3734 CapturingBoundNetLog log;
3736 DelayedSocketData data(1, reads, arraysize(reads),
3737 writes, arraysize(writes));
3738 NormalSpdyTransactionHelper helper(CreateGetRequestWithUserAgent(),
3740 log.bound(), GetParam(), NULL);
3741 helper.RunToCompletion(&data);
3742 TransactionHelperResult out = helper.output();
3743 EXPECT_EQ(OK, out.rv);
3744 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
3745 EXPECT_EQ("hello!", out.response_data);
3747 // Check that the NetLog was filled reasonably.
3748 // This test is intentionally non-specific about the exact ordering of the
3749 // log; instead we just check to make sure that certain events exist, and that
3750 // they are in the right order.
3751 net::CapturingNetLog::CapturedEntryList entries;
3752 log.GetEntries(&entries);
3754 EXPECT_LT(0u, entries.size());
3756 pos = net::ExpectLogContainsSomewhere(entries, 0,
3757 net::NetLog::TYPE_HTTP_TRANSACTION_SEND_REQUEST,
3758 net::NetLog::PHASE_BEGIN);
3759 pos = net::ExpectLogContainsSomewhere(entries, pos + 1,
3760 net::NetLog::TYPE_HTTP_TRANSACTION_SEND_REQUEST,
3761 net::NetLog::PHASE_END);
3762 pos = net::ExpectLogContainsSomewhere(entries, pos + 1,
3763 net::NetLog::TYPE_HTTP_TRANSACTION_READ_HEADERS,
3764 net::NetLog::PHASE_BEGIN);
3765 pos = net::ExpectLogContainsSomewhere(entries, pos + 1,
3766 net::NetLog::TYPE_HTTP_TRANSACTION_READ_HEADERS,
3767 net::NetLog::PHASE_END);
3768 pos = net::ExpectLogContainsSomewhere(entries, pos + 1,
3769 net::NetLog::TYPE_HTTP_TRANSACTION_READ_BODY,
3770 net::NetLog::PHASE_BEGIN);
3771 pos = net::ExpectLogContainsSomewhere(entries, pos + 1,
3772 net::NetLog::TYPE_HTTP_TRANSACTION_READ_BODY,
3773 net::NetLog::PHASE_END);
3775 // Check that we logged all the headers correctly
3776 pos = net::ExpectLogContainsSomewhere(
3778 net::NetLog::TYPE_SPDY_SESSION_SYN_STREAM,
3779 net::NetLog::PHASE_NONE);
3781 base::ListValue* header_list;
3782 ASSERT_TRUE(entries[pos].params.get());
3783 ASSERT_TRUE(entries[pos].params->GetList("headers", &header_list));
3785 std::vector<std::string> expected;
3786 expected.push_back(std::string(spdy_util_.GetHostKey()) + ": www.google.com");
3787 expected.push_back(std::string(spdy_util_.GetPathKey()) + ": /");
3788 expected.push_back(std::string(spdy_util_.GetSchemeKey()) + ": http");
3789 expected.push_back(std::string(spdy_util_.GetVersionKey()) + ": HTTP/1.1");
3790 expected.push_back(std::string(spdy_util_.GetMethodKey()) + ": GET");
3791 expected.push_back("user-agent: Chrome");
3792 EXPECT_EQ(expected.size(), header_list->GetSize());
3793 for (std::vector<std::string>::const_iterator it = expected.begin();
3794 it != expected.end();
3796 base::StringValue header(*it);
3797 EXPECT_NE(header_list->end(), header_list->Find(header)) <<
3798 "Header not found: " << *it;
3802 // Since we buffer the IO from the stream to the renderer, this test verifies
3803 // that when we read out the maximum amount of data (e.g. we received 50 bytes
3804 // on the network, but issued a Read for only 5 of those bytes) that the data
3805 // flow still works correctly.
3806 TEST_P(SpdyNetworkTransactionTest, BufferFull) {
3807 BufferedSpdyFramer framer(spdy_util_.spdy_version(), false);
3809 scoped_ptr<SpdyFrame> req(
3810 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
3811 MockWrite writes[] = { CreateMockWrite(*req) };
3813 // 2 data frames in a single read.
3814 scoped_ptr<SpdyFrame> data_frame_1(
3815 framer.CreateDataFrame(1, "goodby", 6, DATA_FLAG_NONE));
3816 scoped_ptr<SpdyFrame> data_frame_2(
3817 framer.CreateDataFrame(1, "e worl", 6, DATA_FLAG_NONE));
3818 const SpdyFrame* data_frames[2] = {
3822 char combined_data_frames[100];
3823 int combined_data_frames_len =
3824 CombineFrames(data_frames, arraysize(data_frames),
3825 combined_data_frames, arraysize(combined_data_frames));
3826 scoped_ptr<SpdyFrame> last_frame(
3827 framer.CreateDataFrame(1, "d", 1, DATA_FLAG_FIN));
3829 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
3830 MockRead reads[] = {
3831 CreateMockRead(*resp),
3832 MockRead(ASYNC, ERR_IO_PENDING), // Force a pause
3833 MockRead(ASYNC, combined_data_frames, combined_data_frames_len),
3834 MockRead(ASYNC, ERR_IO_PENDING), // Force a pause
3835 CreateMockRead(*last_frame),
3836 MockRead(ASYNC, 0, 0) // EOF
3839 DelayedSocketData data(1, reads, arraysize(reads),
3840 writes, arraysize(writes));
3842 TestCompletionCallback callback;
3844 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
3845 BoundNetLog(), GetParam(), NULL);
3846 helper.RunPreTestSetup();
3847 helper.AddData(&data);
3848 HttpNetworkTransaction* trans = helper.trans();
3849 int rv = trans->Start(
3850 &CreateGetRequest(), callback.callback(), BoundNetLog());
3851 EXPECT_EQ(ERR_IO_PENDING, rv);
3853 TransactionHelperResult out = helper.output();
3854 out.rv = callback.WaitForResult();
3855 EXPECT_EQ(out.rv, OK);
3857 const HttpResponseInfo* response = trans->GetResponseInfo();
3858 EXPECT_TRUE(response->headers.get() != NULL);
3859 EXPECT_TRUE(response->was_fetched_via_spdy);
3860 out.status_line = response->headers->GetStatusLine();
3861 out.response_info = *response; // Make a copy so we can verify.
3864 TestCompletionCallback read_callback;
3866 std::string content;
3868 // Read small chunks at a time.
3869 const int kSmallReadSize = 3;
3870 scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(kSmallReadSize));
3871 rv = trans->Read(buf.get(), kSmallReadSize, read_callback.callback());
3872 if (rv == net::ERR_IO_PENDING) {
3873 data.CompleteRead();
3874 rv = read_callback.WaitForResult();
3877 content.append(buf->data(), rv);
3878 } else if (rv < 0) {
3883 out.response_data.swap(content);
3885 // Flush the MessageLoop while the SpdySessionDependencies (in particular, the
3886 // MockClientSocketFactory) are still alive.
3887 base::RunLoop().RunUntilIdle();
3889 // Verify that we consumed all test data.
3890 helper.VerifyDataConsumed();
3892 EXPECT_EQ(OK, out.rv);
3893 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
3894 EXPECT_EQ("goodbye world", out.response_data);
3897 // Verify that basic buffering works; when multiple data frames arrive
3898 // at the same time, ensure that we don't notify a read completion for
3899 // each data frame individually.
3900 TEST_P(SpdyNetworkTransactionTest, Buffering) {
3901 BufferedSpdyFramer framer(spdy_util_.spdy_version(), false);
3903 scoped_ptr<SpdyFrame> req(
3904 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
3905 MockWrite writes[] = { CreateMockWrite(*req) };
3907 // 4 data frames in a single read.
3908 scoped_ptr<SpdyFrame> data_frame(
3909 framer.CreateDataFrame(1, "message", 7, DATA_FLAG_NONE));
3910 scoped_ptr<SpdyFrame> data_frame_fin(
3911 framer.CreateDataFrame(1, "message", 7, DATA_FLAG_FIN));
3912 const SpdyFrame* data_frames[4] = {
3916 data_frame_fin.get()
3918 char combined_data_frames[100];
3919 int combined_data_frames_len =
3920 CombineFrames(data_frames, arraysize(data_frames),
3921 combined_data_frames, arraysize(combined_data_frames));
3923 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
3924 MockRead reads[] = {
3925 CreateMockRead(*resp),
3926 MockRead(ASYNC, ERR_IO_PENDING), // Force a pause
3927 MockRead(ASYNC, combined_data_frames, combined_data_frames_len),
3928 MockRead(ASYNC, 0, 0) // EOF
3931 DelayedSocketData data(1, reads, arraysize(reads),
3932 writes, arraysize(writes));
3934 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
3935 BoundNetLog(), GetParam(), NULL);
3936 helper.RunPreTestSetup();
3937 helper.AddData(&data);
3938 HttpNetworkTransaction* trans = helper.trans();
3940 TestCompletionCallback callback;
3941 int rv = trans->Start(
3942 &CreateGetRequest(), callback.callback(), BoundNetLog());
3943 EXPECT_EQ(ERR_IO_PENDING, rv);
3945 TransactionHelperResult out = helper.output();
3946 out.rv = callback.WaitForResult();
3947 EXPECT_EQ(out.rv, OK);
3949 const HttpResponseInfo* response = trans->GetResponseInfo();
3950 EXPECT_TRUE(response->headers.get() != NULL);
3951 EXPECT_TRUE(response->was_fetched_via_spdy);
3952 out.status_line = response->headers->GetStatusLine();
3953 out.response_info = *response; // Make a copy so we can verify.
3956 TestCompletionCallback read_callback;
3958 std::string content;
3959 int reads_completed = 0;
3961 // Read small chunks at a time.
3962 const int kSmallReadSize = 14;
3963 scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(kSmallReadSize));
3964 rv = trans->Read(buf.get(), kSmallReadSize, read_callback.callback());
3965 if (rv == net::ERR_IO_PENDING) {
3966 data.CompleteRead();
3967 rv = read_callback.WaitForResult();
3970 EXPECT_EQ(kSmallReadSize, rv);
3971 content.append(buf->data(), rv);
3972 } else if (rv < 0) {
3973 FAIL() << "Unexpected read error: " << rv;
3978 EXPECT_EQ(3, reads_completed); // Reads are: 14 bytes, 14 bytes, 0 bytes.
3980 out.response_data.swap(content);
3982 // Flush the MessageLoop while the SpdySessionDependencies (in particular, the
3983 // MockClientSocketFactory) are still alive.
3984 base::RunLoop().RunUntilIdle();
3986 // Verify that we consumed all test data.
3987 helper.VerifyDataConsumed();
3989 EXPECT_EQ(OK, out.rv);
3990 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
3991 EXPECT_EQ("messagemessagemessagemessage", out.response_data);
3994 // Verify the case where we buffer data but read it after it has been buffered.
3995 TEST_P(SpdyNetworkTransactionTest, BufferedAll) {
3996 BufferedSpdyFramer framer(spdy_util_.spdy_version(), false);
3998 scoped_ptr<SpdyFrame> req(
3999 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
4000 MockWrite writes[] = { CreateMockWrite(*req) };
4002 // 5 data frames in a single read.
4003 scoped_ptr<SpdyFrame> syn_reply(
4004 spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
4006 test::SetFrameFlags(
4007 syn_reply.get(), CONTROL_FLAG_NONE, spdy_util_.spdy_version());
4008 scoped_ptr<SpdyFrame> data_frame(
4009 framer.CreateDataFrame(1, "message", 7, DATA_FLAG_NONE));
4010 scoped_ptr<SpdyFrame> data_frame_fin(
4011 framer.CreateDataFrame(1, "message", 7, DATA_FLAG_FIN));
4012 const SpdyFrame* frames[5] = {
4017 data_frame_fin.get()
4019 char combined_frames[200];
4020 int combined_frames_len =
4021 CombineFrames(frames, arraysize(frames),
4022 combined_frames, arraysize(combined_frames));
4024 MockRead reads[] = {
4025 MockRead(ASYNC, combined_frames, combined_frames_len),
4026 MockRead(ASYNC, 0, 0) // EOF
4029 DelayedSocketData data(1, reads, arraysize(reads),
4030 writes, arraysize(writes));
4032 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
4033 BoundNetLog(), GetParam(), NULL);
4034 helper.RunPreTestSetup();
4035 helper.AddData(&data);
4036 HttpNetworkTransaction* trans = helper.trans();
4038 TestCompletionCallback callback;
4039 int rv = trans->Start(
4040 &CreateGetRequest(), callback.callback(), BoundNetLog());
4041 EXPECT_EQ(ERR_IO_PENDING, rv);
4043 TransactionHelperResult out = helper.output();
4044 out.rv = callback.WaitForResult();
4045 EXPECT_EQ(out.rv, OK);
4047 const HttpResponseInfo* response = trans->GetResponseInfo();
4048 EXPECT_TRUE(response->headers.get() != NULL);
4049 EXPECT_TRUE(response->was_fetched_via_spdy);
4050 out.status_line = response->headers->GetStatusLine();
4051 out.response_info = *response; // Make a copy so we can verify.
4054 TestCompletionCallback read_callback;
4056 std::string content;
4057 int reads_completed = 0;
4059 // Read small chunks at a time.
4060 const int kSmallReadSize = 14;
4061 scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(kSmallReadSize));
4062 rv = trans->Read(buf.get(), kSmallReadSize, read_callback.callback());
4064 EXPECT_EQ(kSmallReadSize, rv);
4065 content.append(buf->data(), rv);
4066 } else if (rv < 0) {
4067 FAIL() << "Unexpected read error: " << rv;
4072 EXPECT_EQ(3, reads_completed);
4074 out.response_data.swap(content);
4076 // Flush the MessageLoop while the SpdySessionDependencies (in particular, the
4077 // MockClientSocketFactory) are still alive.
4078 base::RunLoop().RunUntilIdle();
4080 // Verify that we consumed all test data.
4081 helper.VerifyDataConsumed();
4083 EXPECT_EQ(OK, out.rv);
4084 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
4085 EXPECT_EQ("messagemessagemessagemessage", out.response_data);
4088 // Verify the case where we buffer data and close the connection.
4089 TEST_P(SpdyNetworkTransactionTest, BufferedClosed) {
4090 BufferedSpdyFramer framer(spdy_util_.spdy_version(), false);
4092 scoped_ptr<SpdyFrame> req(
4093 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
4094 MockWrite writes[] = { CreateMockWrite(*req) };
4096 // All data frames in a single read.
4097 // NOTE: We don't FIN the stream.
4098 scoped_ptr<SpdyFrame> data_frame(
4099 framer.CreateDataFrame(1, "message", 7, DATA_FLAG_NONE));
4100 const SpdyFrame* data_frames[4] = {
4106 char combined_data_frames[100];
4107 int combined_data_frames_len =
4108 CombineFrames(data_frames, arraysize(data_frames),
4109 combined_data_frames, arraysize(combined_data_frames));
4110 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
4111 MockRead reads[] = {
4112 CreateMockRead(*resp),
4113 MockRead(ASYNC, ERR_IO_PENDING), // Force a wait
4114 MockRead(ASYNC, combined_data_frames, combined_data_frames_len),
4115 MockRead(ASYNC, 0, 0) // EOF
4118 DelayedSocketData data(1, reads, arraysize(reads),
4119 writes, arraysize(writes));
4121 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
4122 BoundNetLog(), GetParam(), NULL);
4123 helper.RunPreTestSetup();
4124 helper.AddData(&data);
4125 HttpNetworkTransaction* trans = helper.trans();
4127 TestCompletionCallback callback;
4129 int rv = trans->Start(
4130 &CreateGetRequest(), callback.callback(), BoundNetLog());
4131 EXPECT_EQ(ERR_IO_PENDING, rv);
4133 TransactionHelperResult out = helper.output();
4134 out.rv = callback.WaitForResult();
4135 EXPECT_EQ(out.rv, OK);
4137 const HttpResponseInfo* response = trans->GetResponseInfo();
4138 EXPECT_TRUE(response->headers.get() != NULL);
4139 EXPECT_TRUE(response->was_fetched_via_spdy);
4140 out.status_line = response->headers->GetStatusLine();
4141 out.response_info = *response; // Make a copy so we can verify.
4144 TestCompletionCallback read_callback;
4146 std::string content;
4147 int reads_completed = 0;
4149 // Read small chunks at a time.
4150 const int kSmallReadSize = 14;
4151 scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(kSmallReadSize));
4152 rv = trans->Read(buf.get(), kSmallReadSize, read_callback.callback());
4153 if (rv == net::ERR_IO_PENDING) {
4154 data.CompleteRead();
4155 rv = read_callback.WaitForResult();
4158 content.append(buf->data(), rv);
4159 } else if (rv < 0) {
4160 // This test intentionally closes the connection, and will get an error.
4161 EXPECT_EQ(ERR_CONNECTION_CLOSED, rv);
4167 EXPECT_EQ(0, reads_completed);
4169 out.response_data.swap(content);
4171 // Flush the MessageLoop while the SpdySessionDependencies (in particular, the
4172 // MockClientSocketFactory) are still alive.
4173 base::RunLoop().RunUntilIdle();
4175 // Verify that we consumed all test data.
4176 helper.VerifyDataConsumed();
4179 // Verify the case where we buffer data and cancel the transaction.
4180 TEST_P(SpdyNetworkTransactionTest, BufferedCancelled) {
4181 BufferedSpdyFramer framer(spdy_util_.spdy_version(), false);
4183 scoped_ptr<SpdyFrame> req(
4184 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
4185 MockWrite writes[] = { CreateMockWrite(*req) };
4187 // NOTE: We don't FIN the stream.
4188 scoped_ptr<SpdyFrame> data_frame(
4189 framer.CreateDataFrame(1, "message", 7, DATA_FLAG_NONE));
4191 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
4192 MockRead reads[] = {
4193 CreateMockRead(*resp),
4194 MockRead(ASYNC, ERR_IO_PENDING), // Force a wait
4195 CreateMockRead(*data_frame),
4196 MockRead(ASYNC, 0, 0) // EOF
4199 DelayedSocketData data(1, reads, arraysize(reads),
4200 writes, arraysize(writes));
4202 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
4203 BoundNetLog(), GetParam(), NULL);
4204 helper.RunPreTestSetup();
4205 helper.AddData(&data);
4206 HttpNetworkTransaction* trans = helper.trans();
4207 TestCompletionCallback callback;
4209 int rv = trans->Start(
4210 &CreateGetRequest(), callback.callback(), BoundNetLog());
4211 EXPECT_EQ(ERR_IO_PENDING, rv);
4213 TransactionHelperResult out = helper.output();
4214 out.rv = callback.WaitForResult();
4215 EXPECT_EQ(out.rv, OK);
4217 const HttpResponseInfo* response = trans->GetResponseInfo();
4218 EXPECT_TRUE(response->headers.get() != NULL);
4219 EXPECT_TRUE(response->was_fetched_via_spdy);
4220 out.status_line = response->headers->GetStatusLine();
4221 out.response_info = *response; // Make a copy so we can verify.
4224 TestCompletionCallback read_callback;
4227 const int kReadSize = 256;
4228 scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(kReadSize));
4229 rv = trans->Read(buf.get(), kReadSize, read_callback.callback());
4230 if (rv == net::ERR_IO_PENDING) {
4231 // Complete the read now, which causes buffering to start.
4232 data.CompleteRead();
4233 // Destroy the transaction, causing the stream to get cancelled
4234 // and orphaning the buffered IO task.
4235 helper.ResetTrans();
4238 // We shouldn't get here in this test.
4239 FAIL() << "Unexpected read: " << rv;
4242 // Flush the MessageLoop; this will cause the buffered IO task
4243 // to run for the final time.
4244 base::RunLoop().RunUntilIdle();
4246 // Verify that we consumed all test data.
4247 helper.VerifyDataConsumed();
4250 // Test that if the server requests persistence of settings, that we save
4251 // the settings in the HttpServerProperties.
4252 TEST_P(SpdyNetworkTransactionTest, SettingsSaved) {
4253 static const SpdyHeaderInfo kSynReplyInfo = {
4254 SYN_REPLY, // Syn Reply
4256 0, // Associated Stream ID
4257 ConvertRequestPriorityToSpdyPriority(
4258 LOWEST, spdy_util_.spdy_version()),
4259 kSpdyCredentialSlotUnused,
4260 CONTROL_FLAG_NONE, // Control Flags
4261 false, // Compressed
4262 RST_STREAM_INVALID, // Status
4265 DATA_FLAG_NONE // Data Flags
4268 BoundNetLog net_log;
4269 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
4270 net_log, GetParam(), NULL);
4271 helper.RunPreTestSetup();
4273 // Verify that no settings exist initially.
4274 HostPortPair host_port_pair("www.google.com", helper.port());
4275 SpdySessionPool* spdy_session_pool = helper.session()->spdy_session_pool();
4276 EXPECT_TRUE(spdy_session_pool->http_server_properties()->GetSpdySettings(
4277 host_port_pair).empty());
4279 // Construct the request.
4280 scoped_ptr<SpdyFrame> req(
4281 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
4282 MockWrite writes[] = { CreateMockWrite(*req) };
4284 // Construct the reply.
4285 scoped_ptr<SpdyHeaderBlock> reply_headers(new SpdyHeaderBlock());
4286 (*reply_headers)[spdy_util_.GetStatusKey()] = "200";
4287 (*reply_headers)[spdy_util_.GetVersionKey()] = "HTTP/1.1";
4288 scoped_ptr<SpdyFrame> reply(
4289 spdy_util_.ConstructSpdyFrame(kSynReplyInfo, reply_headers.Pass()));
4291 const SpdySettingsIds kSampleId1 = SETTINGS_UPLOAD_BANDWIDTH;
4292 unsigned int kSampleValue1 = 0x0a0a0a0a;
4293 const SpdySettingsIds kSampleId2 = SETTINGS_DOWNLOAD_BANDWIDTH;
4294 unsigned int kSampleValue2 = 0x0b0b0b0b;
4295 const SpdySettingsIds kSampleId3 = SETTINGS_ROUND_TRIP_TIME;
4296 unsigned int kSampleValue3 = 0x0c0c0c0c;
4297 scoped_ptr<SpdyFrame> settings_frame;
4299 // Construct the SETTINGS frame.
4300 SettingsMap settings;
4301 // First add a persisted setting.
4302 settings[kSampleId1] =
4303 SettingsFlagsAndValue(SETTINGS_FLAG_PLEASE_PERSIST, kSampleValue1);
4304 // Next add a non-persisted setting.
4305 settings[kSampleId2] =
4306 SettingsFlagsAndValue(SETTINGS_FLAG_NONE, kSampleValue2);
4307 // Next add another persisted setting.
4308 settings[kSampleId3] =
4309 SettingsFlagsAndValue(SETTINGS_FLAG_PLEASE_PERSIST, kSampleValue3);
4310 settings_frame.reset(spdy_util_.ConstructSpdySettings(settings));
4313 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
4314 MockRead reads[] = {
4315 CreateMockRead(*reply),
4316 CreateMockRead(*body),
4317 CreateMockRead(*settings_frame),
4318 MockRead(ASYNC, 0, 0) // EOF
4321 DelayedSocketData data(1, reads, arraysize(reads),
4322 writes, arraysize(writes));
4323 helper.AddData(&data);
4324 helper.RunDefaultTest();
4325 helper.VerifyDataConsumed();
4326 TransactionHelperResult out = helper.output();
4327 EXPECT_EQ(OK, out.rv);
4328 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
4329 EXPECT_EQ("hello!", out.response_data);
4332 // Verify we had two persisted settings.
4333 const SettingsMap& settings_map =
4334 spdy_session_pool->http_server_properties()->GetSpdySettings(
4336 ASSERT_EQ(2u, settings_map.size());
4338 // Verify the first persisted setting.
4339 SettingsMap::const_iterator it1 = settings_map.find(kSampleId1);
4340 EXPECT_TRUE(it1 != settings_map.end());
4341 SettingsFlagsAndValue flags_and_value1 = it1->second;
4342 EXPECT_EQ(SETTINGS_FLAG_PERSISTED, flags_and_value1.first);
4343 EXPECT_EQ(kSampleValue1, flags_and_value1.second);
4345 // Verify the second persisted setting.
4346 SettingsMap::const_iterator it3 = settings_map.find(kSampleId3);
4347 EXPECT_TRUE(it3 != settings_map.end());
4348 SettingsFlagsAndValue flags_and_value3 = it3->second;
4349 EXPECT_EQ(SETTINGS_FLAG_PERSISTED, flags_and_value3.first);
4350 EXPECT_EQ(kSampleValue3, flags_and_value3.second);
4354 // Test that when there are settings saved that they are sent back to the
4355 // server upon session establishment.
4356 TEST_P(SpdyNetworkTransactionTest, SettingsPlayback) {
4357 static const SpdyHeaderInfo kSynReplyInfo = {
4358 SYN_REPLY, // Syn Reply
4360 0, // Associated Stream ID
4361 ConvertRequestPriorityToSpdyPriority(
4362 LOWEST, spdy_util_.spdy_version()),
4363 kSpdyCredentialSlotUnused,
4364 CONTROL_FLAG_NONE, // Control Flags
4365 false, // Compressed
4366 RST_STREAM_INVALID, // Status
4369 DATA_FLAG_NONE // Data Flags
4372 BoundNetLog net_log;
4373 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
4374 net_log, GetParam(), NULL);
4375 helper.RunPreTestSetup();
4377 SpdySessionPool* spdy_session_pool = helper.session()->spdy_session_pool();
4379 SpdySessionPoolPeer pool_peer(spdy_session_pool);
4380 pool_peer.SetEnableSendingInitialData(true);
4382 // Verify that no settings exist initially.
4383 HostPortPair host_port_pair("www.google.com", helper.port());
4384 EXPECT_TRUE(spdy_session_pool->http_server_properties()->GetSpdySettings(
4385 host_port_pair).empty());
4387 const SpdySettingsIds kSampleId1 = SETTINGS_UPLOAD_BANDWIDTH;
4388 unsigned int kSampleValue1 = 0x0a0a0a0a;
4389 const SpdySettingsIds kSampleId2 = SETTINGS_ROUND_TRIP_TIME;
4390 unsigned int kSampleValue2 = 0x0c0c0c0c;
4392 // First add a persisted setting.
4393 spdy_session_pool->http_server_properties()->SetSpdySetting(
4396 SETTINGS_FLAG_PLEASE_PERSIST,
4399 // Next add another persisted setting.
4400 spdy_session_pool->http_server_properties()->SetSpdySetting(
4403 SETTINGS_FLAG_PLEASE_PERSIST,
4406 EXPECT_EQ(2u, spdy_session_pool->http_server_properties()->GetSpdySettings(
4407 host_port_pair).size());
4409 // Construct the initial SETTINGS frame.
4410 SettingsMap initial_settings;
4411 initial_settings[SETTINGS_MAX_CONCURRENT_STREAMS] =
4412 SettingsFlagsAndValue(SETTINGS_FLAG_NONE, kMaxConcurrentPushedStreams);
4413 scoped_ptr<SpdyFrame> initial_settings_frame(
4414 spdy_util_.ConstructSpdySettings(initial_settings));
4416 // Construct the initial window update.
4417 scoped_ptr<SpdyFrame> initial_window_update(
4418 spdy_util_.ConstructSpdyWindowUpdate(
4419 kSessionFlowControlStreamId,
4420 kDefaultInitialRecvWindowSize - kSpdySessionInitialWindowSize));
4422 // Construct the persisted SETTINGS frame.
4423 const SettingsMap& settings =
4424 spdy_session_pool->http_server_properties()->GetSpdySettings(
4426 scoped_ptr<SpdyFrame> settings_frame(
4427 spdy_util_.ConstructSpdySettings(settings));
4429 // Construct the request.
4430 scoped_ptr<SpdyFrame> req(
4431 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
4433 std::vector<MockWrite> writes;
4434 if (GetParam().protocol == kProtoHTTP2Draft04) {
4437 kHttp2ConnectionHeaderPrefix,
4438 kHttp2ConnectionHeaderPrefixSize));
4440 writes.push_back(CreateMockWrite(*initial_settings_frame));
4441 if (GetParam().protocol >= kProtoSPDY31) {
4442 writes.push_back(CreateMockWrite(*initial_window_update));
4444 writes.push_back(CreateMockWrite(*settings_frame));
4445 writes.push_back(CreateMockWrite(*req));
4447 // Construct the reply.
4448 scoped_ptr<SpdyHeaderBlock> reply_headers(new SpdyHeaderBlock());
4449 (*reply_headers)[spdy_util_.GetStatusKey()] = "200";
4450 (*reply_headers)[spdy_util_.GetVersionKey()] = "HTTP/1.1";
4451 scoped_ptr<SpdyFrame> reply(
4452 spdy_util_.ConstructSpdyFrame(kSynReplyInfo, reply_headers.Pass()));
4454 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
4455 MockRead reads[] = {
4456 CreateMockRead(*reply),
4457 CreateMockRead(*body),
4458 MockRead(ASYNC, 0, 0) // EOF
4461 DelayedSocketData data(2, reads, arraysize(reads),
4462 vector_as_array(&writes), writes.size());
4463 helper.AddData(&data);
4464 helper.RunDefaultTest();
4465 helper.VerifyDataConsumed();
4466 TransactionHelperResult out = helper.output();
4467 EXPECT_EQ(OK, out.rv);
4468 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
4469 EXPECT_EQ("hello!", out.response_data);
4472 // Verify we had two persisted settings.
4473 const SettingsMap& settings_map =
4474 spdy_session_pool->http_server_properties()->GetSpdySettings(
4476 ASSERT_EQ(2u, settings_map.size());
4478 // Verify the first persisted setting.
4479 SettingsMap::const_iterator it1 = settings_map.find(kSampleId1);
4480 EXPECT_TRUE(it1 != settings_map.end());
4481 SettingsFlagsAndValue flags_and_value1 = it1->second;
4482 EXPECT_EQ(SETTINGS_FLAG_PERSISTED, flags_and_value1.first);
4483 EXPECT_EQ(kSampleValue1, flags_and_value1.second);
4485 // Verify the second persisted setting.
4486 SettingsMap::const_iterator it2 = settings_map.find(kSampleId2);
4487 EXPECT_TRUE(it2 != settings_map.end());
4488 SettingsFlagsAndValue flags_and_value2 = it2->second;
4489 EXPECT_EQ(SETTINGS_FLAG_PERSISTED, flags_and_value2.first);
4490 EXPECT_EQ(kSampleValue2, flags_and_value2.second);
4494 TEST_P(SpdyNetworkTransactionTest, GoAwayWithActiveStream) {
4495 scoped_ptr<SpdyFrame> req(
4496 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
4497 MockWrite writes[] = { CreateMockWrite(*req) };
4499 scoped_ptr<SpdyFrame> go_away(spdy_util_.ConstructSpdyGoAway());
4500 MockRead reads[] = {
4501 CreateMockRead(*go_away),
4504 DelayedSocketData data(1, reads, arraysize(reads),
4505 writes, arraysize(writes));
4506 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
4507 BoundNetLog(), GetParam(), NULL);
4508 helper.AddData(&data);
4509 helper.RunToCompletion(&data);
4510 TransactionHelperResult out = helper.output();
4511 EXPECT_EQ(ERR_ABORTED, out.rv);
4514 TEST_P(SpdyNetworkTransactionTest, CloseWithActiveStream) {
4515 scoped_ptr<SpdyFrame> req(
4516 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
4517 MockWrite writes[] = { CreateMockWrite(*req) };
4519 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
4520 MockRead reads[] = {
4521 CreateMockRead(*resp),
4522 MockRead(SYNCHRONOUS, 0, 0) // EOF
4525 DelayedSocketData data(1, reads, arraysize(reads),
4526 writes, arraysize(writes));
4528 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
4529 log, GetParam(), NULL);
4530 helper.RunPreTestSetup();
4531 helper.AddData(&data);
4532 HttpNetworkTransaction* trans = helper.trans();
4534 TestCompletionCallback callback;
4535 TransactionHelperResult out;
4536 out.rv = trans->Start(&CreateGetRequest(), callback.callback(), log);
4538 EXPECT_EQ(out.rv, ERR_IO_PENDING);
4539 out.rv = callback.WaitForResult();
4540 EXPECT_EQ(out.rv, OK);
4542 const HttpResponseInfo* response = trans->GetResponseInfo();
4543 EXPECT_TRUE(response->headers.get() != NULL);
4544 EXPECT_TRUE(response->was_fetched_via_spdy);
4545 out.rv = ReadTransaction(trans, &out.response_data);
4546 EXPECT_EQ(ERR_CONNECTION_CLOSED, out.rv);
4548 // Verify that we consumed all test data.
4549 helper.VerifyDataConsumed();
4552 // Test to make sure we can correctly connect through a proxy.
4553 TEST_P(SpdyNetworkTransactionTest, ProxyConnect) {
4554 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
4555 BoundNetLog(), GetParam(), NULL);
4556 helper.session_deps().reset(CreateSpdySessionDependencies(
4558 ProxyService::CreateFixedFromPacResult("PROXY myproxy:70")));
4559 helper.SetSession(make_scoped_refptr(
4560 SpdySessionDependencies::SpdyCreateSession(helper.session_deps().get())));
4561 helper.RunPreTestSetup();
4562 HttpNetworkTransaction* trans = helper.trans();
4564 const char kConnect443[] = {"CONNECT www.google.com:443 HTTP/1.1\r\n"
4565 "Host: www.google.com\r\n"
4566 "Proxy-Connection: keep-alive\r\n\r\n"};
4567 const char kConnect80[] = {"CONNECT www.google.com:80 HTTP/1.1\r\n"
4568 "Host: www.google.com\r\n"
4569 "Proxy-Connection: keep-alive\r\n\r\n"};
4570 const char kHTTP200[] = {"HTTP/1.1 200 OK\r\n\r\n"};
4571 scoped_ptr<SpdyFrame> req(
4572 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
4573 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
4574 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
4576 MockWrite writes_SPDYNPN[] = {
4577 MockWrite(SYNCHRONOUS, kConnect443, arraysize(kConnect443) - 1, 0),
4578 CreateMockWrite(*req, 2),
4580 MockRead reads_SPDYNPN[] = {
4581 MockRead(SYNCHRONOUS, kHTTP200, arraysize(kHTTP200) - 1, 1),
4582 CreateMockRead(*resp, 3),
4583 CreateMockRead(*body.get(), 4),
4584 MockRead(ASYNC, 0, 0, 5),
4587 MockWrite writes_SPDYSSL[] = {
4588 MockWrite(SYNCHRONOUS, kConnect80, arraysize(kConnect80) - 1, 0),
4589 CreateMockWrite(*req, 2),
4591 MockRead reads_SPDYSSL[] = {
4592 MockRead(SYNCHRONOUS, kHTTP200, arraysize(kHTTP200) - 1, 1),
4593 CreateMockRead(*resp, 3),
4594 CreateMockRead(*body.get(), 4),
4595 MockRead(ASYNC, 0, 0, 5),
4598 MockWrite writes_SPDYNOSSL[] = {
4599 CreateMockWrite(*req, 0),
4602 MockRead reads_SPDYNOSSL[] = {
4603 CreateMockRead(*resp, 1),
4604 CreateMockRead(*body.get(), 2),
4605 MockRead(ASYNC, 0, 0, 3),
4608 scoped_ptr<OrderedSocketData> data;
4609 switch(GetParam().ssl_type) {
4611 data.reset(new OrderedSocketData(reads_SPDYNOSSL,
4612 arraysize(reads_SPDYNOSSL),
4614 arraysize(writes_SPDYNOSSL)));
4617 data.reset(new OrderedSocketData(reads_SPDYSSL,
4618 arraysize(reads_SPDYSSL),
4620 arraysize(writes_SPDYSSL)));
4623 data.reset(new OrderedSocketData(reads_SPDYNPN,
4624 arraysize(reads_SPDYNPN),
4626 arraysize(writes_SPDYNPN)));
4632 helper.AddData(data.get());
4633 TestCompletionCallback callback;
4635 int rv = trans->Start(
4636 &CreateGetRequest(), callback.callback(), BoundNetLog());
4637 EXPECT_EQ(ERR_IO_PENDING, rv);
4639 rv = callback.WaitForResult();
4642 // Verify the SYN_REPLY.
4643 HttpResponseInfo response = *trans->GetResponseInfo();
4644 EXPECT_TRUE(response.headers.get() != NULL);
4645 EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine());
4647 std::string response_data;
4648 ASSERT_EQ(OK, ReadTransaction(trans, &response_data));
4649 EXPECT_EQ("hello!", response_data);
4650 helper.VerifyDataConsumed();
4653 // Test to make sure we can correctly connect through a proxy to www.google.com,
4654 // if there already exists a direct spdy connection to www.google.com. See
4655 // http://crbug.com/49874
4656 TEST_P(SpdyNetworkTransactionTest, DirectConnectProxyReconnect) {
4657 // When setting up the first transaction, we store the SpdySessionPool so that
4658 // we can use the same pool in the second transaction.
4659 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
4660 BoundNetLog(), GetParam(), NULL);
4662 // Use a proxy service which returns a proxy fallback list from DIRECT to
4663 // myproxy:70. For this test there will be no fallback, so it is equivalent
4664 // to simply DIRECT. The reason for appending the second proxy is to verify
4665 // that the session pool key used does is just "DIRECT".
4666 helper.session_deps().reset(CreateSpdySessionDependencies(
4668 ProxyService::CreateFixedFromPacResult("DIRECT; PROXY myproxy:70")));
4669 helper.SetSession(make_scoped_refptr(
4670 SpdySessionDependencies::SpdyCreateSession(helper.session_deps().get())));
4672 SpdySessionPool* spdy_session_pool = helper.session()->spdy_session_pool();
4673 helper.RunPreTestSetup();
4675 // Construct and send a simple GET request.
4676 scoped_ptr<SpdyFrame> req(
4677 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
4678 MockWrite writes[] = {
4679 CreateMockWrite(*req, 1),
4682 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
4683 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
4684 MockRead reads[] = {
4685 CreateMockRead(*resp, 2),
4686 CreateMockRead(*body, 3),
4687 MockRead(ASYNC, ERR_IO_PENDING, 4), // Force a pause
4688 MockRead(ASYNC, 0, 5) // EOF
4690 OrderedSocketData data(reads, arraysize(reads),
4691 writes, arraysize(writes));
4692 helper.AddData(&data);
4693 HttpNetworkTransaction* trans = helper.trans();
4695 TestCompletionCallback callback;
4696 TransactionHelperResult out;
4697 out.rv = trans->Start(
4698 &CreateGetRequest(), callback.callback(), BoundNetLog());
4700 EXPECT_EQ(out.rv, ERR_IO_PENDING);
4701 out.rv = callback.WaitForResult();
4702 EXPECT_EQ(out.rv, OK);
4704 const HttpResponseInfo* response = trans->GetResponseInfo();
4705 EXPECT_TRUE(response->headers.get() != NULL);
4706 EXPECT_TRUE(response->was_fetched_via_spdy);
4707 out.rv = ReadTransaction(trans, &out.response_data);
4708 EXPECT_EQ(OK, out.rv);
4709 out.status_line = response->headers->GetStatusLine();
4710 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
4711 EXPECT_EQ("hello!", out.response_data);
4713 // Check that the SpdySession is still in the SpdySessionPool.
4714 HostPortPair host_port_pair("www.google.com", helper.port());
4715 SpdySessionKey session_pool_key_direct(
4716 host_port_pair, ProxyServer::Direct(), kPrivacyModeDisabled);
4717 EXPECT_TRUE(HasSpdySession(spdy_session_pool, session_pool_key_direct));
4718 SpdySessionKey session_pool_key_proxy(
4720 ProxyServer::FromURI("www.foo.com", ProxyServer::SCHEME_HTTP),
4721 kPrivacyModeDisabled);
4722 EXPECT_FALSE(HasSpdySession(spdy_session_pool, session_pool_key_proxy));
4724 // Set up data for the proxy connection.
4725 const char kConnect443[] = {"CONNECT www.google.com:443 HTTP/1.1\r\n"
4726 "Host: www.google.com\r\n"
4727 "Proxy-Connection: keep-alive\r\n\r\n"};
4728 const char kConnect80[] = {"CONNECT www.google.com:80 HTTP/1.1\r\n"
4729 "Host: www.google.com\r\n"
4730 "Proxy-Connection: keep-alive\r\n\r\n"};
4731 const char kHTTP200[] = {"HTTP/1.1 200 OK\r\n\r\n"};
4732 scoped_ptr<SpdyFrame> req2(spdy_util_.ConstructSpdyGet(
4733 "http://www.google.com/foo.dat", false, 1, LOWEST));
4734 scoped_ptr<SpdyFrame> resp2(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
4735 scoped_ptr<SpdyFrame> body2(spdy_util_.ConstructSpdyBodyFrame(1, true));
4737 MockWrite writes_SPDYNPN[] = {
4738 MockWrite(SYNCHRONOUS, kConnect443, arraysize(kConnect443) - 1, 0),
4739 CreateMockWrite(*req2, 2),
4741 MockRead reads_SPDYNPN[] = {
4742 MockRead(SYNCHRONOUS, kHTTP200, arraysize(kHTTP200) - 1, 1),
4743 CreateMockRead(*resp2, 3),
4744 CreateMockRead(*body2, 4),
4745 MockRead(ASYNC, 0, 5) // EOF
4748 MockWrite writes_SPDYNOSSL[] = {
4749 CreateMockWrite(*req2, 0),
4751 MockRead reads_SPDYNOSSL[] = {
4752 CreateMockRead(*resp2, 1),
4753 CreateMockRead(*body2, 2),
4754 MockRead(ASYNC, 0, 3) // EOF
4757 MockWrite writes_SPDYSSL[] = {
4758 MockWrite(SYNCHRONOUS, kConnect80, arraysize(kConnect80) - 1, 0),
4759 CreateMockWrite(*req2, 2),
4761 MockRead reads_SPDYSSL[] = {
4762 MockRead(SYNCHRONOUS, kHTTP200, arraysize(kHTTP200) - 1, 1),
4763 CreateMockRead(*resp2, 3),
4764 CreateMockRead(*body2, 4),
4765 MockRead(ASYNC, 0, 0, 5),
4768 scoped_ptr<OrderedSocketData> data_proxy;
4769 switch(GetParam().ssl_type) {
4771 data_proxy.reset(new OrderedSocketData(reads_SPDYNPN,
4772 arraysize(reads_SPDYNPN),
4774 arraysize(writes_SPDYNPN)));
4777 data_proxy.reset(new OrderedSocketData(reads_SPDYNOSSL,
4778 arraysize(reads_SPDYNOSSL),
4780 arraysize(writes_SPDYNOSSL)));
4783 data_proxy.reset(new OrderedSocketData(reads_SPDYSSL,
4784 arraysize(reads_SPDYSSL),
4786 arraysize(writes_SPDYSSL)));
4792 // Create another request to www.google.com, but this time through a proxy.
4793 HttpRequestInfo request_proxy;
4794 request_proxy.method = "GET";
4795 request_proxy.url = GURL("http://www.google.com/foo.dat");
4796 request_proxy.load_flags = 0;
4797 scoped_ptr<SpdySessionDependencies> ssd_proxy(
4798 CreateSpdySessionDependencies(GetParam()));
4799 // Ensure that this transaction uses the same SpdySessionPool.
4800 scoped_refptr<HttpNetworkSession> session_proxy(
4801 SpdySessionDependencies::SpdyCreateSession(ssd_proxy.get()));
4802 NormalSpdyTransactionHelper helper_proxy(request_proxy, DEFAULT_PRIORITY,
4803 BoundNetLog(), GetParam(), NULL);
4804 HttpNetworkSessionPeer session_peer(session_proxy);
4805 scoped_ptr<net::ProxyService> proxy_service(
4806 ProxyService::CreateFixedFromPacResult("PROXY myproxy:70"));
4807 session_peer.SetProxyService(proxy_service.get());
4808 helper_proxy.session_deps().swap(ssd_proxy);
4809 helper_proxy.SetSession(session_proxy);
4810 helper_proxy.RunPreTestSetup();
4811 helper_proxy.AddData(data_proxy.get());
4813 HttpNetworkTransaction* trans_proxy = helper_proxy.trans();
4814 TestCompletionCallback callback_proxy;
4815 int rv = trans_proxy->Start(
4816 &request_proxy, callback_proxy.callback(), BoundNetLog());
4817 EXPECT_EQ(ERR_IO_PENDING, rv);
4818 rv = callback_proxy.WaitForResult();
4821 HttpResponseInfo response_proxy = *trans_proxy->GetResponseInfo();
4822 EXPECT_TRUE(response_proxy.headers.get() != NULL);
4823 EXPECT_EQ("HTTP/1.1 200 OK", response_proxy.headers->GetStatusLine());
4825 std::string response_data;
4826 ASSERT_EQ(OK, ReadTransaction(trans_proxy, &response_data));
4827 EXPECT_EQ("hello!", response_data);
4829 data.CompleteRead();
4830 helper_proxy.VerifyDataConsumed();
4833 // When we get a TCP-level RST, we need to retry a HttpNetworkTransaction
4834 // on a new connection, if the connection was previously known to be good.
4835 // This can happen when a server reboots without saying goodbye, or when
4836 // we're behind a NAT that masked the RST.
4837 TEST_P(SpdyNetworkTransactionTest, VerifyRetryOnConnectionReset) {
4838 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
4839 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
4840 MockRead reads[] = {
4841 CreateMockRead(*resp),
4842 CreateMockRead(*body),
4843 MockRead(ASYNC, ERR_IO_PENDING),
4844 MockRead(ASYNC, ERR_CONNECTION_RESET),
4847 MockRead reads2[] = {
4848 CreateMockRead(*resp),
4849 CreateMockRead(*body),
4850 MockRead(ASYNC, 0, 0) // EOF
4853 // This test has a couple of variants.
4855 // Induce the RST while waiting for our transaction to send.
4856 VARIANT_RST_DURING_SEND_COMPLETION,
4857 // Induce the RST while waiting for our transaction to read.
4858 // In this case, the send completed - everything copied into the SNDBUF.
4859 VARIANT_RST_DURING_READ_COMPLETION
4862 for (int variant = VARIANT_RST_DURING_SEND_COMPLETION;
4863 variant <= VARIANT_RST_DURING_READ_COMPLETION;
4865 DelayedSocketData data1(1, reads, arraysize(reads), NULL, 0);
4867 DelayedSocketData data2(1, reads2, arraysize(reads2), NULL, 0);
4869 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
4870 BoundNetLog(), GetParam(), NULL);
4871 helper.AddData(&data1);
4872 helper.AddData(&data2);
4873 helper.RunPreTestSetup();
4875 for (int i = 0; i < 2; ++i) {
4876 scoped_ptr<HttpNetworkTransaction> trans(
4877 new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get()));
4879 TestCompletionCallback callback;
4880 int rv = trans->Start(
4881 &helper.request(), callback.callback(), BoundNetLog());
4882 EXPECT_EQ(ERR_IO_PENDING, rv);
4883 // On the second transaction, we trigger the RST.
4885 if (variant == VARIANT_RST_DURING_READ_COMPLETION) {
4886 // Writes to the socket complete asynchronously on SPDY by running
4887 // through the message loop. Complete the write here.
4888 base::RunLoop().RunUntilIdle();
4891 // Now schedule the ERR_CONNECTION_RESET.
4892 EXPECT_EQ(3u, data1.read_index());
4893 data1.CompleteRead();
4894 EXPECT_EQ(4u, data1.read_index());
4896 rv = callback.WaitForResult();
4899 const HttpResponseInfo* response = trans->GetResponseInfo();
4900 ASSERT_TRUE(response != NULL);
4901 EXPECT_TRUE(response->headers.get() != NULL);
4902 EXPECT_TRUE(response->was_fetched_via_spdy);
4903 std::string response_data;
4904 rv = ReadTransaction(trans.get(), &response_data);
4906 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
4907 EXPECT_EQ("hello!", response_data);
4910 helper.VerifyDataConsumed();
4914 // Test that turning SPDY on and off works properly.
4915 TEST_P(SpdyNetworkTransactionTest, SpdyOnOffToggle) {
4916 net::HttpStreamFactory::set_spdy_enabled(true);
4917 scoped_ptr<SpdyFrame> req(
4918 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
4919 MockWrite spdy_writes[] = { CreateMockWrite(*req) };
4921 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
4922 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
4923 MockRead spdy_reads[] = {
4924 CreateMockRead(*resp),
4925 CreateMockRead(*body),
4926 MockRead(ASYNC, 0, 0) // EOF
4929 DelayedSocketData data(1, spdy_reads, arraysize(spdy_reads),
4930 spdy_writes, arraysize(spdy_writes));
4931 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
4932 BoundNetLog(), GetParam(), NULL);
4933 helper.RunToCompletion(&data);
4934 TransactionHelperResult out = helper.output();
4935 EXPECT_EQ(OK, out.rv);
4936 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
4937 EXPECT_EQ("hello!", out.response_data);
4939 net::HttpStreamFactory::set_spdy_enabled(false);
4940 MockRead http_reads[] = {
4941 MockRead("HTTP/1.1 200 OK\r\n\r\n"),
4942 MockRead("hello from http"),
4943 MockRead(SYNCHRONOUS, OK),
4945 DelayedSocketData data2(1, http_reads, arraysize(http_reads), NULL, 0);
4946 NormalSpdyTransactionHelper helper2(CreateGetRequest(), DEFAULT_PRIORITY,
4947 BoundNetLog(), GetParam(), NULL);
4948 helper2.SetSpdyDisabled();
4949 helper2.RunToCompletion(&data2);
4950 TransactionHelperResult out2 = helper2.output();
4951 EXPECT_EQ(OK, out2.rv);
4952 EXPECT_EQ("HTTP/1.1 200 OK", out2.status_line);
4953 EXPECT_EQ("hello from http", out2.response_data);
4955 net::HttpStreamFactory::set_spdy_enabled(true);
4958 // Tests that Basic authentication works over SPDY
4959 TEST_P(SpdyNetworkTransactionTest, SpdyBasicAuth) {
4960 net::HttpStreamFactory::set_spdy_enabled(true);
4962 // The first request will be a bare GET, the second request will be a
4963 // GET with an Authorization header.
4964 scoped_ptr<SpdyFrame> req_get(
4965 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
4966 const char* const kExtraAuthorizationHeaders[] = {
4967 "authorization", "Basic Zm9vOmJhcg=="
4969 scoped_ptr<SpdyFrame> req_get_authorization(
4970 spdy_util_.ConstructSpdyGet(kExtraAuthorizationHeaders,
4971 arraysize(kExtraAuthorizationHeaders) / 2,
4972 false, 3, LOWEST, true));
4973 MockWrite spdy_writes[] = {
4974 CreateMockWrite(*req_get, 1),
4975 CreateMockWrite(*req_get_authorization, 4),
4978 // The first response is a 401 authentication challenge, and the second
4979 // response will be a 200 response since the second request includes a valid
4980 // Authorization header.
4981 const char* const kExtraAuthenticationHeaders[] = {
4983 "Basic realm=\"MyRealm\""
4985 scoped_ptr<SpdyFrame> resp_authentication(
4986 spdy_util_.ConstructSpdySynReplyError(
4987 "401 Authentication Required",
4988 kExtraAuthenticationHeaders,
4989 arraysize(kExtraAuthenticationHeaders) / 2,
4991 scoped_ptr<SpdyFrame> body_authentication(
4992 spdy_util_.ConstructSpdyBodyFrame(1, true));
4993 scoped_ptr<SpdyFrame> resp_data(
4994 spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3));
4995 scoped_ptr<SpdyFrame> body_data(spdy_util_.ConstructSpdyBodyFrame(3, true));
4996 MockRead spdy_reads[] = {
4997 CreateMockRead(*resp_authentication, 2),
4998 CreateMockRead(*body_authentication, 3),
4999 CreateMockRead(*resp_data, 5),
5000 CreateMockRead(*body_data, 6),
5001 MockRead(ASYNC, 0, 7),
5004 OrderedSocketData data(spdy_reads, arraysize(spdy_reads),
5005 spdy_writes, arraysize(spdy_writes));
5006 HttpRequestInfo request(CreateGetRequest());
5007 BoundNetLog net_log;
5008 NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY,
5009 net_log, GetParam(), NULL);
5011 helper.RunPreTestSetup();
5012 helper.AddData(&data);
5013 HttpNetworkTransaction* trans = helper.trans();
5014 TestCompletionCallback callback;
5015 const int rv_start = trans->Start(&request, callback.callback(), net_log);
5016 EXPECT_EQ(ERR_IO_PENDING, rv_start);
5017 const int rv_start_complete = callback.WaitForResult();
5018 EXPECT_EQ(OK, rv_start_complete);
5020 // Make sure the response has an auth challenge.
5021 const HttpResponseInfo* const response_start = trans->GetResponseInfo();
5022 ASSERT_TRUE(response_start != NULL);
5023 ASSERT_TRUE(response_start->headers.get() != NULL);
5024 EXPECT_EQ(401, response_start->headers->response_code());
5025 EXPECT_TRUE(response_start->was_fetched_via_spdy);
5026 AuthChallengeInfo* auth_challenge = response_start->auth_challenge.get();
5027 ASSERT_TRUE(auth_challenge != NULL);
5028 EXPECT_FALSE(auth_challenge->is_proxy);
5029 EXPECT_EQ("basic", auth_challenge->scheme);
5030 EXPECT_EQ("MyRealm", auth_challenge->realm);
5032 // Restart with a username/password.
5033 AuthCredentials credentials(base::ASCIIToUTF16("foo"),
5034 base::ASCIIToUTF16("bar"));
5035 TestCompletionCallback callback_restart;
5036 const int rv_restart = trans->RestartWithAuth(
5037 credentials, callback_restart.callback());
5038 EXPECT_EQ(ERR_IO_PENDING, rv_restart);
5039 const int rv_restart_complete = callback_restart.WaitForResult();
5040 EXPECT_EQ(OK, rv_restart_complete);
5041 // TODO(cbentzel): This is actually the same response object as before, but
5042 // data has changed.
5043 const HttpResponseInfo* const response_restart = trans->GetResponseInfo();
5044 ASSERT_TRUE(response_restart != NULL);
5045 ASSERT_TRUE(response_restart->headers.get() != NULL);
5046 EXPECT_EQ(200, response_restart->headers->response_code());
5047 EXPECT_TRUE(response_restart->auth_challenge.get() == NULL);
5050 TEST_P(SpdyNetworkTransactionTest, ServerPushWithHeaders) {
5051 scoped_ptr<SpdyFrame> stream1_syn(
5052 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
5053 scoped_ptr<SpdyFrame> stream1_body(
5054 spdy_util_.ConstructSpdyBodyFrame(1, true));
5055 MockWrite writes[] = {
5056 CreateMockWrite(*stream1_syn, 1),
5059 scoped_ptr<SpdyHeaderBlock> initial_headers(new SpdyHeaderBlock());
5060 spdy_util_.AddUrlToHeaderBlock(
5061 "http://www.google.com/foo.dat", initial_headers.get());
5062 scoped_ptr<SpdyFrame> stream2_syn(
5063 spdy_util_.ConstructSpdyControlFrame(initial_headers.Pass(),
5071 scoped_ptr<SpdyHeaderBlock> late_headers(new SpdyHeaderBlock());
5072 (*late_headers)["hello"] = "bye";
5073 (*late_headers)[spdy_util_.GetStatusKey()] = "200";
5074 (*late_headers)[spdy_util_.GetVersionKey()] = "HTTP/1.1";
5075 scoped_ptr<SpdyFrame> stream2_headers(
5076 spdy_util_.ConstructSpdyControlFrame(late_headers.Pass(),
5084 scoped_ptr<SpdyFrame>
5085 stream1_reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
5086 const char kPushedData[] = "pushed";
5087 scoped_ptr<SpdyFrame> stream2_body(
5088 spdy_util_.ConstructSpdyBodyFrame(
5089 2, kPushedData, strlen(kPushedData), true));
5090 MockRead reads[] = {
5091 CreateMockRead(*stream1_reply, 2),
5092 CreateMockRead(*stream2_syn, 3),
5093 CreateMockRead(*stream2_headers, 4),
5094 CreateMockRead(*stream1_body, 5, SYNCHRONOUS),
5095 CreateMockRead(*stream2_body, 5),
5096 MockRead(ASYNC, ERR_IO_PENDING, 7), // Force a pause
5099 HttpResponseInfo response;
5100 HttpResponseInfo response2;
5101 std::string expected_push_result("pushed");
5102 OrderedSocketData data(reads, arraysize(reads),
5103 writes, arraysize(writes));
5104 RunServerPushTest(&data,
5107 expected_push_result);
5109 // Verify the SYN_REPLY.
5110 EXPECT_TRUE(response.headers.get() != NULL);
5111 EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine());
5113 // Verify the pushed stream.
5114 EXPECT_TRUE(response2.headers.get() != NULL);
5115 EXPECT_EQ("HTTP/1.1 200 OK", response2.headers->GetStatusLine());
5118 TEST_P(SpdyNetworkTransactionTest, ServerPushClaimBeforeHeaders) {
5119 // We push a stream and attempt to claim it before the headers come down.
5120 scoped_ptr<SpdyFrame> stream1_syn(
5121 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
5122 scoped_ptr<SpdyFrame> stream1_body(
5123 spdy_util_.ConstructSpdyBodyFrame(1, true));
5124 MockWrite writes[] = {
5125 CreateMockWrite(*stream1_syn, 0, SYNCHRONOUS),
5128 scoped_ptr<SpdyHeaderBlock> initial_headers(new SpdyHeaderBlock());
5129 spdy_util_.AddUrlToHeaderBlock(
5130 "http://www.google.com/foo.dat", initial_headers.get());
5131 scoped_ptr<SpdyFrame> stream2_syn(
5132 spdy_util_.ConstructSpdyControlFrame(initial_headers.Pass(),
5140 scoped_ptr<SpdyHeaderBlock> late_headers(new SpdyHeaderBlock());
5141 (*late_headers)["hello"] = "bye";
5142 (*late_headers)[spdy_util_.GetStatusKey()] = "200";
5143 (*late_headers)[spdy_util_.GetVersionKey()] = "HTTP/1.1";
5144 scoped_ptr<SpdyFrame> stream2_headers(
5145 spdy_util_.ConstructSpdyControlFrame(late_headers.Pass(),
5153 scoped_ptr<SpdyFrame>
5154 stream1_reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
5155 const char kPushedData[] = "pushed";
5156 scoped_ptr<SpdyFrame> stream2_body(
5157 spdy_util_.ConstructSpdyBodyFrame(
5158 2, kPushedData, strlen(kPushedData), true));
5159 MockRead reads[] = {
5160 CreateMockRead(*stream1_reply, 1),
5161 CreateMockRead(*stream2_syn, 2),
5162 CreateMockRead(*stream1_body, 3),
5163 CreateMockRead(*stream2_headers, 4),
5164 CreateMockRead(*stream2_body, 5),
5165 MockRead(ASYNC, 0, 6), // EOF
5168 HttpResponseInfo response;
5169 HttpResponseInfo response2;
5170 std::string expected_push_result("pushed");
5171 DeterministicSocketData data(reads, arraysize(reads),
5172 writes, arraysize(writes));
5174 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
5175 BoundNetLog(), GetParam(), NULL);
5176 helper.SetDeterministic();
5177 helper.AddDeterministicData(&data);
5178 helper.RunPreTestSetup();
5180 HttpNetworkTransaction* trans = helper.trans();
5182 // Run until we've received the primary SYN_STREAM, the pushed SYN_STREAM,
5183 // and the body of the primary stream, but before we've received the HEADERS
5184 // for the pushed stream.
5187 // Start the transaction.
5188 TestCompletionCallback callback;
5189 int rv = trans->Start(
5190 &CreateGetRequest(), callback.callback(), BoundNetLog());
5191 EXPECT_EQ(ERR_IO_PENDING, rv);
5193 rv = callback.WaitForResult();
5196 // Request the pushed path. At this point, we've received the push, but the
5197 // headers are not yet complete.
5198 scoped_ptr<HttpNetworkTransaction> trans2(
5199 new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get()));
5201 &CreateGetPushRequest(), callback.callback(), BoundNetLog());
5202 EXPECT_EQ(ERR_IO_PENDING, rv);
5204 base::RunLoop().RunUntilIdle();
5206 // Read the server push body.
5207 std::string result2;
5208 ReadResult(trans2.get(), &data, &result2);
5209 // Read the response body.
5211 ReadResult(trans, &data, &result);
5213 // Verify that the received push data is same as the expected push data.
5214 EXPECT_EQ(result2.compare(expected_push_result), 0)
5215 << "Received data: "
5217 << "||||| Expected data: "
5218 << expected_push_result;
5220 // Verify the SYN_REPLY.
5221 // Copy the response info, because trans goes away.
5222 response = *trans->GetResponseInfo();
5223 response2 = *trans2->GetResponseInfo();
5225 VerifyStreamsClosed(helper);
5227 // Verify the SYN_REPLY.
5228 EXPECT_TRUE(response.headers.get() != NULL);
5229 EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine());
5231 // Verify the pushed stream.
5232 EXPECT_TRUE(response2.headers.get() != NULL);
5233 EXPECT_EQ("HTTP/1.1 200 OK", response2.headers->GetStatusLine());
5235 // Read the final EOF (which will close the session)
5238 // Verify that we consumed all test data.
5239 EXPECT_TRUE(data.at_read_eof());
5240 EXPECT_TRUE(data.at_write_eof());
5243 TEST_P(SpdyNetworkTransactionTest, ServerPushWithTwoHeaderFrames) {
5244 // We push a stream and attempt to claim it before the headers come down.
5245 scoped_ptr<SpdyFrame> stream1_syn(
5246 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
5247 scoped_ptr<SpdyFrame> stream1_body(
5248 spdy_util_.ConstructSpdyBodyFrame(1, true));
5249 MockWrite writes[] = {
5250 CreateMockWrite(*stream1_syn, 0, SYNCHRONOUS),
5253 scoped_ptr<SpdyHeaderBlock> initial_headers(new SpdyHeaderBlock());
5254 spdy_util_.AddUrlToHeaderBlock(
5255 "http://www.google.com/foo.dat", initial_headers.get());
5256 scoped_ptr<SpdyFrame> stream2_syn(
5257 spdy_util_.ConstructSpdyControlFrame(initial_headers.Pass(),
5265 scoped_ptr<SpdyHeaderBlock> middle_headers(new SpdyHeaderBlock());
5266 (*middle_headers)["hello"] = "bye";
5267 scoped_ptr<SpdyFrame> stream2_headers1(
5268 spdy_util_.ConstructSpdyControlFrame(middle_headers.Pass(),
5276 scoped_ptr<SpdyHeaderBlock> late_headers(new SpdyHeaderBlock());
5277 (*late_headers)[spdy_util_.GetStatusKey()] = "200";
5278 (*late_headers)[spdy_util_.GetVersionKey()] = "HTTP/1.1";
5279 scoped_ptr<SpdyFrame> stream2_headers2(
5280 spdy_util_.ConstructSpdyControlFrame(late_headers.Pass(),
5288 scoped_ptr<SpdyFrame>
5289 stream1_reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
5290 const char kPushedData[] = "pushed";
5291 scoped_ptr<SpdyFrame> stream2_body(
5292 spdy_util_.ConstructSpdyBodyFrame(
5293 2, kPushedData, strlen(kPushedData), true));
5294 MockRead reads[] = {
5295 CreateMockRead(*stream1_reply, 1),
5296 CreateMockRead(*stream2_syn, 2),
5297 CreateMockRead(*stream1_body, 3),
5298 CreateMockRead(*stream2_headers1, 4),
5299 CreateMockRead(*stream2_headers2, 5),
5300 CreateMockRead(*stream2_body, 6),
5301 MockRead(ASYNC, 0, 7), // EOF
5304 HttpResponseInfo response;
5305 HttpResponseInfo response2;
5306 std::string expected_push_result("pushed");
5307 DeterministicSocketData data(reads, arraysize(reads),
5308 writes, arraysize(writes));
5310 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
5311 BoundNetLog(), GetParam(), NULL);
5312 helper.SetDeterministic();
5313 helper.AddDeterministicData(&data);
5314 helper.RunPreTestSetup();
5316 HttpNetworkTransaction* trans = helper.trans();
5318 // Run until we've received the primary SYN_STREAM, the pushed SYN_STREAM,
5319 // the first HEADERS frame, and the body of the primary stream, but before
5320 // we've received the final HEADERS for the pushed stream.
5323 // Start the transaction.
5324 TestCompletionCallback callback;
5325 int rv = trans->Start(
5326 &CreateGetRequest(), callback.callback(), BoundNetLog());
5327 EXPECT_EQ(ERR_IO_PENDING, rv);
5329 rv = callback.WaitForResult();
5332 // Request the pushed path. At this point, we've received the push, but the
5333 // headers are not yet complete.
5334 scoped_ptr<HttpNetworkTransaction> trans2(
5335 new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get()));
5337 &CreateGetPushRequest(), callback.callback(), BoundNetLog());
5338 EXPECT_EQ(ERR_IO_PENDING, rv);
5340 base::RunLoop().RunUntilIdle();
5342 // Read the server push body.
5343 std::string result2;
5344 ReadResult(trans2.get(), &data, &result2);
5345 // Read the response body.
5347 ReadResult(trans, &data, &result);
5349 // Verify that the received push data is same as the expected push data.
5350 EXPECT_EQ(expected_push_result, result2);
5352 // Verify the SYN_REPLY.
5353 // Copy the response info, because trans goes away.
5354 response = *trans->GetResponseInfo();
5355 response2 = *trans2->GetResponseInfo();
5357 VerifyStreamsClosed(helper);
5359 // Verify the SYN_REPLY.
5360 EXPECT_TRUE(response.headers.get() != NULL);
5361 EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine());
5363 // Verify the pushed stream.
5364 EXPECT_TRUE(response2.headers.get() != NULL);
5365 EXPECT_EQ("HTTP/1.1 200 OK", response2.headers->GetStatusLine());
5367 // Verify we got all the headers
5368 if (spdy_util_.spdy_version() < SPDY3) {
5369 EXPECT_TRUE(response2.headers->HasHeaderValue(
5371 "http://www.google.com/foo.dat"));
5373 EXPECT_TRUE(response2.headers->HasHeaderValue(
5375 EXPECT_TRUE(response2.headers->HasHeaderValue(
5376 "host", "www.google.com"));
5377 EXPECT_TRUE(response2.headers->HasHeaderValue(
5378 "path", "/foo.dat"));
5380 EXPECT_TRUE(response2.headers->HasHeaderValue("hello", "bye"));
5381 EXPECT_TRUE(response2.headers->HasHeaderValue("status", "200"));
5382 EXPECT_TRUE(response2.headers->HasHeaderValue("version", "HTTP/1.1"));
5384 // Read the final EOF (which will close the session)
5387 // Verify that we consumed all test data.
5388 EXPECT_TRUE(data.at_read_eof());
5389 EXPECT_TRUE(data.at_write_eof());
5392 TEST_P(SpdyNetworkTransactionTest, ServerPushWithNoStatusHeaderFrames) {
5393 // We push a stream and attempt to claim it before the headers come down.
5394 scoped_ptr<SpdyFrame> stream1_syn(
5395 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
5396 scoped_ptr<SpdyFrame> stream1_body(
5397 spdy_util_.ConstructSpdyBodyFrame(1, true));
5398 MockWrite writes[] = {
5399 CreateMockWrite(*stream1_syn, 0, SYNCHRONOUS),
5402 scoped_ptr<SpdyHeaderBlock> initial_headers(new SpdyHeaderBlock());
5403 spdy_util_.AddUrlToHeaderBlock(
5404 "http://www.google.com/foo.dat", initial_headers.get());
5405 scoped_ptr<SpdyFrame> stream2_syn(
5406 spdy_util_.ConstructSpdyControlFrame(initial_headers.Pass(),
5414 scoped_ptr<SpdyHeaderBlock> middle_headers(new SpdyHeaderBlock());
5415 (*middle_headers)["hello"] = "bye";
5416 scoped_ptr<SpdyFrame> stream2_headers1(
5417 spdy_util_.ConstructSpdyControlFrame(middle_headers.Pass(),
5425 scoped_ptr<SpdyFrame>
5426 stream1_reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
5427 const char kPushedData[] = "pushed";
5428 scoped_ptr<SpdyFrame> stream2_body(
5429 spdy_util_.ConstructSpdyBodyFrame(
5430 2, kPushedData, strlen(kPushedData), true));
5431 MockRead reads[] = {
5432 CreateMockRead(*stream1_reply, 1),
5433 CreateMockRead(*stream2_syn, 2),
5434 CreateMockRead(*stream1_body, 3),
5435 CreateMockRead(*stream2_headers1, 4),
5436 CreateMockRead(*stream2_body, 5),
5437 MockRead(ASYNC, 0, 6), // EOF
5440 DeterministicSocketData data(reads, arraysize(reads),
5441 writes, arraysize(writes));
5443 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
5444 BoundNetLog(), GetParam(), NULL);
5445 helper.SetDeterministic();
5446 helper.AddDeterministicData(&data);
5447 helper.RunPreTestSetup();
5449 HttpNetworkTransaction* trans = helper.trans();
5451 // Run until we've received the primary SYN_STREAM, the pushed SYN_STREAM,
5452 // the first HEADERS frame, and the body of the primary stream, but before
5453 // we've received the final HEADERS for the pushed stream.
5456 // Start the transaction.
5457 TestCompletionCallback callback;
5458 int rv = trans->Start(
5459 &CreateGetRequest(), callback.callback(), BoundNetLog());
5460 EXPECT_EQ(ERR_IO_PENDING, rv);
5462 rv = callback.WaitForResult();
5465 // Request the pushed path. At this point, we've received the push, but the
5466 // headers are not yet complete.
5467 scoped_ptr<HttpNetworkTransaction> trans2(
5468 new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get()));
5470 &CreateGetPushRequest(), callback.callback(), BoundNetLog());
5471 EXPECT_EQ(ERR_IO_PENDING, rv);
5473 base::RunLoop().RunUntilIdle();
5475 // Read the server push body.
5476 std::string result2;
5477 ReadResult(trans2.get(), &data, &result2);
5478 // Read the response body.
5480 ReadResult(trans, &data, &result);
5481 EXPECT_EQ("hello!", result);
5483 // Verify that we haven't received any push data.
5484 EXPECT_EQ("", result2);
5486 // Verify the SYN_REPLY.
5487 // Copy the response info, because trans goes away.
5488 HttpResponseInfo response = *trans->GetResponseInfo();
5489 ASSERT_TRUE(trans2->GetResponseInfo() == NULL);
5491 VerifyStreamsClosed(helper);
5493 // Verify the SYN_REPLY.
5494 EXPECT_TRUE(response.headers.get() != NULL);
5495 EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine());
5497 // Read the final EOF (which will close the session).
5500 // Verify that we consumed all test data.
5501 EXPECT_TRUE(data.at_read_eof());
5502 EXPECT_TRUE(data.at_write_eof());
5505 TEST_P(SpdyNetworkTransactionTest, SynReplyWithHeaders) {
5506 scoped_ptr<SpdyFrame> req(
5507 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
5508 scoped_ptr<SpdyFrame> rst(
5509 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR));
5510 MockWrite writes[] = {
5511 CreateMockWrite(*req),
5512 CreateMockWrite(*rst),
5515 scoped_ptr<SpdyHeaderBlock> initial_headers(new SpdyHeaderBlock());
5516 (*initial_headers)[spdy_util_.GetStatusKey()] = "200 OK";
5517 (*initial_headers)[spdy_util_.GetVersionKey()] = "HTTP/1.1";
5518 scoped_ptr<SpdyFrame> stream1_reply(
5519 spdy_util_.ConstructSpdyControlFrame(initial_headers.Pass(),
5527 scoped_ptr<SpdyHeaderBlock> late_headers(new SpdyHeaderBlock());
5528 (*late_headers)["hello"] = "bye";
5529 scoped_ptr<SpdyFrame> stream1_headers(
5530 spdy_util_.ConstructSpdyControlFrame(late_headers.Pass(),
5537 scoped_ptr<SpdyFrame> stream1_body(
5538 spdy_util_.ConstructSpdyBodyFrame(1, true));
5539 MockRead reads[] = {
5540 CreateMockRead(*stream1_reply),
5541 CreateMockRead(*stream1_headers),
5542 CreateMockRead(*stream1_body),
5543 MockRead(ASYNC, 0, 0) // EOF
5546 DelayedSocketData data(1, reads, arraysize(reads),
5547 writes, arraysize(writes));
5548 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
5549 BoundNetLog(), GetParam(), NULL);
5550 helper.RunToCompletion(&data);
5551 TransactionHelperResult out = helper.output();
5552 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, out.rv);
5555 TEST_P(SpdyNetworkTransactionTest, SynReplyWithLateHeaders) {
5556 scoped_ptr<SpdyFrame> req(
5557 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
5558 scoped_ptr<SpdyFrame> rst(
5559 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR));
5560 MockWrite writes[] = {
5561 CreateMockWrite(*req),
5562 CreateMockWrite(*rst),
5565 scoped_ptr<SpdyHeaderBlock> initial_headers(new SpdyHeaderBlock());
5566 (*initial_headers)[spdy_util_.GetStatusKey()] = "200 OK";
5567 (*initial_headers)[spdy_util_.GetVersionKey()] = "HTTP/1.1";
5568 scoped_ptr<SpdyFrame> stream1_reply(
5569 spdy_util_.ConstructSpdyControlFrame(initial_headers.Pass(),
5577 scoped_ptr<SpdyHeaderBlock> late_headers(new SpdyHeaderBlock());
5578 (*late_headers)["hello"] = "bye";
5579 scoped_ptr<SpdyFrame> stream1_headers(
5580 spdy_util_.ConstructSpdyControlFrame(late_headers.Pass(),
5587 scoped_ptr<SpdyFrame> stream1_body(
5588 spdy_util_.ConstructSpdyBodyFrame(1, false));
5589 scoped_ptr<SpdyFrame> stream1_body2(
5590 spdy_util_.ConstructSpdyBodyFrame(1, true));
5591 MockRead reads[] = {
5592 CreateMockRead(*stream1_reply),
5593 CreateMockRead(*stream1_body),
5594 CreateMockRead(*stream1_headers),
5595 CreateMockRead(*stream1_body2),
5596 MockRead(ASYNC, 0, 0) // EOF
5599 DelayedSocketData data(1, reads, arraysize(reads),
5600 writes, arraysize(writes));
5601 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
5602 BoundNetLog(), GetParam(), NULL);
5603 helper.RunToCompletion(&data);
5604 TransactionHelperResult out = helper.output();
5605 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, out.rv);
5608 TEST_P(SpdyNetworkTransactionTest, ServerPushCrossOriginCorrectness) {
5609 if (spdy_util_.spdy_version() == SPDY4) {
5610 // TODO(jgraettinger): We don't support associated stream
5611 // checks in SPDY4 yet.
5614 // In this test we want to verify that we can't accidentally push content
5615 // which can't be pushed by this content server.
5616 // This test assumes that:
5617 // - if we're requesting http://www.foo.com/barbaz
5618 // - the browser has made a connection to "www.foo.com".
5620 // A list of the URL to fetch, followed by the URL being pushed.
5621 static const char* const kTestCases[] = {
5622 "http://www.google.com/foo.html",
5623 "http://www.google.com:81/foo.js", // Bad port
5625 "http://www.google.com/foo.html",
5626 "https://www.google.com/foo.js", // Bad protocol
5628 "http://www.google.com/foo.html",
5629 "ftp://www.google.com/foo.js", // Invalid Protocol
5631 "http://www.google.com/foo.html",
5632 "http://blat.www.google.com/foo.js", // Cross subdomain
5634 "http://www.google.com/foo.html",
5635 "http://www.foo.com/foo.js", // Cross domain
5638 for (size_t index = 0; index < arraysize(kTestCases); index += 2) {
5639 const char* url_to_fetch = kTestCases[index];
5640 const char* url_to_push = kTestCases[index + 1];
5642 scoped_ptr<SpdyFrame> stream1_syn(
5643 spdy_util_.ConstructSpdyGet(url_to_fetch, false, 1, LOWEST));
5644 scoped_ptr<SpdyFrame> stream1_body(
5645 spdy_util_.ConstructSpdyBodyFrame(1, true));
5646 scoped_ptr<SpdyFrame> push_rst(
5647 spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_REFUSED_STREAM));
5648 MockWrite writes[] = {
5649 CreateMockWrite(*stream1_syn, 1),
5650 CreateMockWrite(*push_rst, 4),
5653 scoped_ptr<SpdyFrame>
5654 stream1_reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
5655 scoped_ptr<SpdyFrame>
5656 stream2_syn(spdy_util_.ConstructSpdyPush(NULL,
5661 const char kPushedData[] = "pushed";
5662 scoped_ptr<SpdyFrame> stream2_body(
5663 spdy_util_.ConstructSpdyBodyFrame(
5664 2, kPushedData, strlen(kPushedData), true));
5665 scoped_ptr<SpdyFrame> rst(
5666 spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_CANCEL));
5668 MockRead reads[] = {
5669 CreateMockRead(*stream1_reply, 2),
5670 CreateMockRead(*stream2_syn, 3),
5671 CreateMockRead(*stream1_body, 5, SYNCHRONOUS),
5672 CreateMockRead(*stream2_body, 6),
5673 MockRead(ASYNC, ERR_IO_PENDING, 7), // Force a pause
5676 HttpResponseInfo response;
5677 OrderedSocketData data(reads, arraysize(reads),
5678 writes, arraysize(writes));
5680 HttpRequestInfo request;
5681 request.method = "GET";
5682 request.url = GURL(url_to_fetch);
5683 request.load_flags = 0;
5685 // Enable cross-origin push. Since we are not using a proxy, this should
5686 // not actually enable cross-origin SPDY push.
5687 scoped_ptr<SpdySessionDependencies> session_deps(
5688 CreateSpdySessionDependencies(GetParam()));
5689 session_deps->trusted_spdy_proxy = "123.45.67.89:8080";
5690 NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY,
5691 BoundNetLog(), GetParam(),
5692 session_deps.release());
5693 helper.RunPreTestSetup();
5694 helper.AddData(&data);
5696 HttpNetworkTransaction* trans = helper.trans();
5698 // Start the transaction with basic parameters.
5699 TestCompletionCallback callback;
5701 int rv = trans->Start(&request, callback.callback(), BoundNetLog());
5702 EXPECT_EQ(ERR_IO_PENDING, rv);
5703 rv = callback.WaitForResult();
5705 // Read the response body.
5707 ReadResult(trans, &data, &result);
5709 // Verify that we consumed all test data.
5710 EXPECT_TRUE(data.at_read_eof());
5711 EXPECT_TRUE(data.at_write_eof());
5713 // Verify the SYN_REPLY.
5714 // Copy the response info, because trans goes away.
5715 response = *trans->GetResponseInfo();
5717 VerifyStreamsClosed(helper);
5719 // Verify the SYN_REPLY.
5720 EXPECT_TRUE(response.headers.get() != NULL);
5721 EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine());
5725 TEST_P(SpdyNetworkTransactionTest, RetryAfterRefused) {
5726 // Construct the request.
5727 scoped_ptr<SpdyFrame> req(
5728 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
5729 scoped_ptr<SpdyFrame> req2(
5730 spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, LOWEST, true));
5731 MockWrite writes[] = {
5732 CreateMockWrite(*req, 1),
5733 CreateMockWrite(*req2, 3),
5736 scoped_ptr<SpdyFrame> refused(
5737 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_REFUSED_STREAM));
5738 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3));
5739 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(3, true));
5740 MockRead reads[] = {
5741 CreateMockRead(*refused, 2),
5742 CreateMockRead(*resp, 4),
5743 CreateMockRead(*body, 5),
5744 MockRead(ASYNC, 0, 6) // EOF
5747 OrderedSocketData data(reads, arraysize(reads),
5748 writes, arraysize(writes));
5749 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
5750 BoundNetLog(), GetParam(), NULL);
5752 helper.RunPreTestSetup();
5753 helper.AddData(&data);
5755 HttpNetworkTransaction* trans = helper.trans();
5757 // Start the transaction with basic parameters.
5758 TestCompletionCallback callback;
5759 int rv = trans->Start(
5760 &CreateGetRequest(), callback.callback(), BoundNetLog());
5761 EXPECT_EQ(ERR_IO_PENDING, rv);
5762 rv = callback.WaitForResult();
5765 // Verify that we consumed all test data.
5766 EXPECT_TRUE(data.at_read_eof()) << "Read count: "
5767 << data.read_count()
5769 << data.read_index();
5770 EXPECT_TRUE(data.at_write_eof()) << "Write count: "
5771 << data.write_count()
5773 << data.write_index();
5775 // Verify the SYN_REPLY.
5776 HttpResponseInfo response = *trans->GetResponseInfo();
5777 EXPECT_TRUE(response.headers.get() != NULL);
5778 EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine());
5781 TEST_P(SpdyNetworkTransactionTest, OutOfOrderSynStream) {
5782 // This first request will start to establish the SpdySession.
5783 // Then we will start the second (MEDIUM priority) and then third
5784 // (HIGHEST priority) request in such a way that the third will actually
5785 // start before the second, causing the second to be numbered differently
5786 // than the order they were created.
5787 scoped_ptr<SpdyFrame> req1(
5788 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
5789 scoped_ptr<SpdyFrame> req2(
5790 spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, HIGHEST, true));
5791 scoped_ptr<SpdyFrame> req3(
5792 spdy_util_.ConstructSpdyGet(NULL, 0, false, 5, MEDIUM, true));
5793 MockWrite writes[] = {
5794 CreateMockWrite(*req1, 0),
5795 CreateMockWrite(*req2, 3),
5796 CreateMockWrite(*req3, 4),
5799 scoped_ptr<SpdyFrame> resp1(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
5800 scoped_ptr<SpdyFrame> body1(spdy_util_.ConstructSpdyBodyFrame(1, true));
5801 scoped_ptr<SpdyFrame> resp2(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3));
5802 scoped_ptr<SpdyFrame> body2(spdy_util_.ConstructSpdyBodyFrame(3, true));
5803 scoped_ptr<SpdyFrame> resp3(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 5));
5804 scoped_ptr<SpdyFrame> body3(spdy_util_.ConstructSpdyBodyFrame(5, true));
5805 MockRead reads[] = {
5806 CreateMockRead(*resp1, 1),
5807 CreateMockRead(*body1, 2),
5808 CreateMockRead(*resp2, 5),
5809 CreateMockRead(*body2, 6),
5810 CreateMockRead(*resp3, 7),
5811 CreateMockRead(*body3, 8),
5812 MockRead(ASYNC, 0, 9) // EOF
5815 DeterministicSocketData data(reads, arraysize(reads),
5816 writes, arraysize(writes));
5817 NormalSpdyTransactionHelper helper(CreateGetRequest(), LOWEST,
5818 BoundNetLog(), GetParam(), NULL);
5819 helper.SetDeterministic();
5820 helper.RunPreTestSetup();
5821 helper.AddDeterministicData(&data);
5823 // Start the first transaction to set up the SpdySession
5824 HttpNetworkTransaction* trans = helper.trans();
5825 TestCompletionCallback callback;
5826 HttpRequestInfo info1 = CreateGetRequest();
5827 int rv = trans->Start(&info1, callback.callback(), BoundNetLog());
5828 EXPECT_EQ(ERR_IO_PENDING, rv);
5830 // Run the message loop, but do not allow the write to complete.
5831 // This leaves the SpdySession with a write pending, which prevents
5832 // SpdySession from attempting subsequent writes until this write completes.
5833 base::RunLoop().RunUntilIdle();
5835 // Now, start both new transactions
5836 HttpRequestInfo info2 = CreateGetRequest();
5837 TestCompletionCallback callback2;
5838 scoped_ptr<HttpNetworkTransaction> trans2(
5839 new HttpNetworkTransaction(MEDIUM, helper.session().get()));
5840 rv = trans2->Start(&info2, callback2.callback(), BoundNetLog());
5841 EXPECT_EQ(ERR_IO_PENDING, rv);
5842 base::RunLoop().RunUntilIdle();
5844 HttpRequestInfo info3 = CreateGetRequest();
5845 TestCompletionCallback callback3;
5846 scoped_ptr<HttpNetworkTransaction> trans3(
5847 new HttpNetworkTransaction(HIGHEST, helper.session().get()));
5848 rv = trans3->Start(&info3, callback3.callback(), BoundNetLog());
5849 EXPECT_EQ(ERR_IO_PENDING, rv);
5850 base::RunLoop().RunUntilIdle();
5852 // We now have two SYN_STREAM frames queued up which will be
5853 // dequeued only once the first write completes, which we
5854 // now allow to happen.
5856 EXPECT_EQ(OK, callback.WaitForResult());
5858 // And now we can allow everything else to run to completion.
5861 EXPECT_EQ(OK, callback2.WaitForResult());
5862 EXPECT_EQ(OK, callback3.WaitForResult());
5864 helper.VerifyDataConsumed();
5867 // The tests below are only for SPDY/3 and above.
5869 // Test that sent data frames and received WINDOW_UPDATE frames change
5870 // the send_window_size_ correctly.
5872 // WINDOW_UPDATE is different than most other frames in that it can arrive
5873 // while the client is still sending the request body. In order to enforce
5874 // this scenario, we feed a couple of dummy frames and give a delay of 0 to
5875 // socket data provider, so that initial read that is done as soon as the
5876 // stream is created, succeeds and schedules another read. This way reads
5877 // and writes are interleaved; after doing a full frame write, SpdyStream
5878 // will break out of DoLoop and will read and process a WINDOW_UPDATE.
5879 // Once our WINDOW_UPDATE is read, we cannot send SYN_REPLY right away
5880 // since request has not been completely written, therefore we feed
5881 // enough number of WINDOW_UPDATEs to finish the first read and cause a
5882 // write, leading to a complete write of request body; after that we send
5883 // a reply with a body, to cause a graceful shutdown.
5885 // TODO(agayev): develop a socket data provider where both, reads and
5886 // writes are ordered so that writing tests like these are easy and rewrite
5887 // all these tests using it. Right now we are working around the
5888 // limitations as described above and it's not deterministic, tests may
5889 // fail under specific circumstances.
5890 TEST_P(SpdyNetworkTransactionTest, WindowUpdateReceived) {
5891 if (GetParam().protocol < kProtoSPDY3)
5894 static int kFrameCount = 2;
5895 scoped_ptr<std::string> content(
5896 new std::string(kMaxSpdyFrameChunkSize, 'a'));
5897 scoped_ptr<SpdyFrame> req(spdy_util_.ConstructSpdyPost(
5898 kRequestUrl, 1, kMaxSpdyFrameChunkSize * kFrameCount, LOWEST, NULL, 0));
5899 scoped_ptr<SpdyFrame> body(
5900 spdy_util_.ConstructSpdyBodyFrame(
5901 1, content->c_str(), content->size(), false));
5902 scoped_ptr<SpdyFrame> body_end(
5903 spdy_util_.ConstructSpdyBodyFrame(
5904 1, content->c_str(), content->size(), true));
5906 MockWrite writes[] = {
5907 CreateMockWrite(*req, 0),
5908 CreateMockWrite(*body, 1),
5909 CreateMockWrite(*body_end, 2),
5912 static const int32 kDeltaWindowSize = 0xff;
5913 static const int kDeltaCount = 4;
5914 scoped_ptr<SpdyFrame> window_update(
5915 spdy_util_.ConstructSpdyWindowUpdate(1, kDeltaWindowSize));
5916 scoped_ptr<SpdyFrame> window_update_dummy(
5917 spdy_util_.ConstructSpdyWindowUpdate(2, kDeltaWindowSize));
5918 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
5919 MockRead reads[] = {
5920 CreateMockRead(*window_update_dummy, 3),
5921 CreateMockRead(*window_update_dummy, 4),
5922 CreateMockRead(*window_update_dummy, 5),
5923 CreateMockRead(*window_update, 6), // Four updates, therefore window
5924 CreateMockRead(*window_update, 7), // size should increase by
5925 CreateMockRead(*window_update, 8), // kDeltaWindowSize * 4
5926 CreateMockRead(*window_update, 9),
5927 CreateMockRead(*resp, 10),
5928 CreateMockRead(*body_end, 11),
5929 MockRead(ASYNC, 0, 0, 12) // EOF
5932 DeterministicSocketData data(reads, arraysize(reads),
5933 writes, arraysize(writes));
5935 ScopedVector<UploadElementReader> element_readers;
5936 for (int i = 0; i < kFrameCount; ++i) {
5937 element_readers.push_back(
5938 new UploadBytesElementReader(content->c_str(), content->size()));
5940 UploadDataStream upload_data_stream(element_readers.Pass(), 0);
5942 // Setup the request
5943 HttpRequestInfo request;
5944 request.method = "POST";
5945 request.url = GURL(kDefaultURL);
5946 request.upload_data_stream = &upload_data_stream;
5948 NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY,
5949 BoundNetLog(), GetParam(), NULL);
5950 helper.SetDeterministic();
5951 helper.AddDeterministicData(&data);
5952 helper.RunPreTestSetup();
5954 HttpNetworkTransaction* trans = helper.trans();
5956 TestCompletionCallback callback;
5957 int rv = trans->Start(&helper.request(), callback.callback(), BoundNetLog());
5959 EXPECT_EQ(ERR_IO_PENDING, rv);
5963 SpdyHttpStream* stream = static_cast<SpdyHttpStream*>(trans->stream_.get());
5964 ASSERT_TRUE(stream != NULL);
5965 ASSERT_TRUE(stream->stream() != NULL);
5966 EXPECT_EQ(static_cast<int>(kSpdyStreamInitialWindowSize) +
5967 kDeltaWindowSize * kDeltaCount -
5968 kMaxSpdyFrameChunkSize * kFrameCount,
5969 stream->stream()->send_window_size());
5973 rv = callback.WaitForResult();
5976 helper.VerifyDataConsumed();
5979 // Test that received data frames and sent WINDOW_UPDATE frames change
5980 // the recv_window_size_ correctly.
5981 TEST_P(SpdyNetworkTransactionTest, WindowUpdateSent) {
5982 if (GetParam().protocol < kProtoSPDY3)
5985 // Set the data in the body frame large enough to trigger sending a
5986 // WINDOW_UPDATE by the stream.
5987 const std::string body_data(kSpdyStreamInitialWindowSize / 2 + 1, 'x');
5989 scoped_ptr<SpdyFrame> req(
5990 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
5991 scoped_ptr<SpdyFrame> session_window_update(
5992 spdy_util_.ConstructSpdyWindowUpdate(0, body_data.size()));
5993 scoped_ptr<SpdyFrame> window_update(
5994 spdy_util_.ConstructSpdyWindowUpdate(1, body_data.size()));
5996 std::vector<MockWrite> writes;
5997 writes.push_back(CreateMockWrite(*req));
5998 if (GetParam().protocol >= kProtoSPDY31)
5999 writes.push_back(CreateMockWrite(*session_window_update));
6000 writes.push_back(CreateMockWrite(*window_update));
6002 scoped_ptr<SpdyFrame> resp(
6003 spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
6004 scoped_ptr<SpdyFrame> body_no_fin(
6005 spdy_util_.ConstructSpdyBodyFrame(
6006 1, body_data.data(), body_data.size(), false));
6007 scoped_ptr<SpdyFrame> body_fin(
6008 spdy_util_.ConstructSpdyBodyFrame(1, NULL, 0, true));
6009 MockRead reads[] = {
6010 CreateMockRead(*resp),
6011 CreateMockRead(*body_no_fin),
6012 MockRead(ASYNC, ERR_IO_PENDING, 0), // Force a pause
6013 CreateMockRead(*body_fin),
6014 MockRead(ASYNC, ERR_IO_PENDING, 0), // Force a pause
6015 MockRead(ASYNC, 0, 0) // EOF
6018 DelayedSocketData data(1, reads, arraysize(reads),
6019 vector_as_array(&writes), writes.size());
6021 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
6022 BoundNetLog(), GetParam(), NULL);
6023 helper.AddData(&data);
6024 helper.RunPreTestSetup();
6025 HttpNetworkTransaction* trans = helper.trans();
6027 TestCompletionCallback callback;
6028 int rv = trans->Start(&helper.request(), callback.callback(), BoundNetLog());
6030 EXPECT_EQ(ERR_IO_PENDING, rv);
6031 rv = callback.WaitForResult();
6034 SpdyHttpStream* stream =
6035 static_cast<SpdyHttpStream*>(trans->stream_.get());
6036 ASSERT_TRUE(stream != NULL);
6037 ASSERT_TRUE(stream->stream() != NULL);
6040 static_cast<int>(kSpdyStreamInitialWindowSize - body_data.size()),
6041 stream->stream()->recv_window_size());
6043 const HttpResponseInfo* response = trans->GetResponseInfo();
6044 ASSERT_TRUE(response != NULL);
6045 ASSERT_TRUE(response->headers.get() != NULL);
6046 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
6047 EXPECT_TRUE(response->was_fetched_via_spdy);
6049 // Issue a read which will cause a WINDOW_UPDATE to be sent and window
6050 // size increased to default.
6051 scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(body_data.size()));
6052 rv = trans->Read(buf.get(), body_data.size(), CompletionCallback());
6053 EXPECT_EQ(static_cast<int>(body_data.size()), rv);
6054 std::string content(buf->data(), buf->data() + body_data.size());
6055 EXPECT_EQ(body_data, content);
6057 // Schedule the reading of empty data frame with FIN
6058 data.CompleteRead();
6060 // Force write of WINDOW_UPDATE which was scheduled during the above
6062 base::RunLoop().RunUntilIdle();
6065 data.CompleteRead();
6067 helper.VerifyDataConsumed();
6070 // Test that WINDOW_UPDATE frame causing overflow is handled correctly.
6071 TEST_P(SpdyNetworkTransactionTest, WindowUpdateOverflow) {
6072 if (GetParam().protocol < kProtoSPDY3)
6075 // Number of full frames we hope to write (but will not, used to
6076 // set content-length header correctly)
6077 static int kFrameCount = 3;
6079 scoped_ptr<std::string> content(
6080 new std::string(kMaxSpdyFrameChunkSize, 'a'));
6081 scoped_ptr<SpdyFrame> req(spdy_util_.ConstructSpdyPost(
6082 kRequestUrl, 1, kMaxSpdyFrameChunkSize * kFrameCount, LOWEST, NULL, 0));
6083 scoped_ptr<SpdyFrame> body(
6084 spdy_util_.ConstructSpdyBodyFrame(
6085 1, content->c_str(), content->size(), false));
6086 scoped_ptr<SpdyFrame> rst(
6087 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_FLOW_CONTROL_ERROR));
6089 // We're not going to write a data frame with FIN, we'll receive a bad
6090 // WINDOW_UPDATE while sending a request and will send a RST_STREAM frame.
6091 MockWrite writes[] = {
6092 CreateMockWrite(*req, 0),
6093 CreateMockWrite(*body, 2),
6094 CreateMockWrite(*rst, 3),
6097 static const int32 kDeltaWindowSize = 0x7fffffff; // cause an overflow
6098 scoped_ptr<SpdyFrame> window_update(
6099 spdy_util_.ConstructSpdyWindowUpdate(1, kDeltaWindowSize));
6100 MockRead reads[] = {
6101 CreateMockRead(*window_update, 1),
6102 MockRead(ASYNC, 0, 4) // EOF
6105 DeterministicSocketData data(reads, arraysize(reads),
6106 writes, arraysize(writes));
6108 ScopedVector<UploadElementReader> element_readers;
6109 for (int i = 0; i < kFrameCount; ++i) {
6110 element_readers.push_back(
6111 new UploadBytesElementReader(content->c_str(), content->size()));
6113 UploadDataStream upload_data_stream(element_readers.Pass(), 0);
6115 // Setup the request
6116 HttpRequestInfo request;
6117 request.method = "POST";
6118 request.url = GURL("http://www.google.com/");
6119 request.upload_data_stream = &upload_data_stream;
6121 NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY,
6122 BoundNetLog(), GetParam(), NULL);
6123 helper.SetDeterministic();
6124 helper.RunPreTestSetup();
6125 helper.AddDeterministicData(&data);
6126 HttpNetworkTransaction* trans = helper.trans();
6128 TestCompletionCallback callback;
6129 int rv = trans->Start(&helper.request(), callback.callback(), BoundNetLog());
6130 ASSERT_EQ(ERR_IO_PENDING, rv);
6133 ASSERT_TRUE(callback.have_result());
6134 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, callback.WaitForResult());
6135 helper.VerifyDataConsumed();
6138 // Test that after hitting a send window size of 0, the write process
6139 // stalls and upon receiving WINDOW_UPDATE frame write resumes.
6141 // This test constructs a POST request followed by enough data frames
6142 // containing 'a' that would make the window size 0, followed by another
6143 // data frame containing default content (which is "hello!") and this frame
6144 // also contains a FIN flag. DelayedSocketData is used to enforce all
6145 // writes go through before a read could happen. However, the last frame
6146 // ("hello!") is not supposed to go through since by the time its turn
6147 // arrives, window size is 0. At this point MessageLoop::Run() called via
6148 // callback would block. Therefore we call MessageLoop::RunUntilIdle()
6149 // which returns after performing all possible writes. We use DCHECKS to
6150 // ensure that last data frame is still there and stream has stalled.
6151 // After that, next read is artifically enforced, which causes a
6152 // WINDOW_UPDATE to be read and I/O process resumes.
6153 TEST_P(SpdyNetworkTransactionTest, FlowControlStallResume) {
6154 if (GetParam().protocol < kProtoSPDY3)
6157 // Number of frames we need to send to zero out the window size: data
6158 // frames plus SYN_STREAM plus the last data frame; also we need another
6159 // data frame that we will send once the WINDOW_UPDATE is received,
6161 size_t num_writes = kSpdyStreamInitialWindowSize / kMaxSpdyFrameChunkSize + 3;
6163 // Calculate last frame's size; 0 size data frame is legal.
6164 size_t last_frame_size =
6165 kSpdyStreamInitialWindowSize % kMaxSpdyFrameChunkSize;
6167 // Construct content for a data frame of maximum size.
6168 std::string content(kMaxSpdyFrameChunkSize, 'a');
6170 scoped_ptr<SpdyFrame> req(spdy_util_.ConstructSpdyPost(
6171 kRequestUrl, 1, kSpdyStreamInitialWindowSize + kUploadDataSize,
6175 scoped_ptr<SpdyFrame> body1(
6176 spdy_util_.ConstructSpdyBodyFrame(
6177 1, content.c_str(), content.size(), false));
6179 // Last frame to zero out the window size.
6180 scoped_ptr<SpdyFrame> body2(
6181 spdy_util_.ConstructSpdyBodyFrame(
6182 1, content.c_str(), last_frame_size, false));
6184 // Data frame to be sent once WINDOW_UPDATE frame is received.
6185 scoped_ptr<SpdyFrame> body3(spdy_util_.ConstructSpdyBodyFrame(1, true));
6187 // Fill in mock writes.
6188 scoped_ptr<MockWrite[]> writes(new MockWrite[num_writes]);
6190 writes[i] = CreateMockWrite(*req);
6191 for (i = 1; i < num_writes - 2; i++)
6192 writes[i] = CreateMockWrite(*body1);
6193 writes[i++] = CreateMockWrite(*body2);
6194 writes[i] = CreateMockWrite(*body3);
6196 // Construct read frame, give enough space to upload the rest of the
6198 scoped_ptr<SpdyFrame> session_window_update(
6199 spdy_util_.ConstructSpdyWindowUpdate(0, kUploadDataSize));
6200 scoped_ptr<SpdyFrame> window_update(
6201 spdy_util_.ConstructSpdyWindowUpdate(1, kUploadDataSize));
6202 scoped_ptr<SpdyFrame> reply(spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
6203 MockRead reads[] = {
6204 CreateMockRead(*session_window_update),
6205 CreateMockRead(*session_window_update),
6206 CreateMockRead(*window_update),
6207 CreateMockRead(*window_update),
6208 CreateMockRead(*reply),
6209 CreateMockRead(*body2),
6210 CreateMockRead(*body3),
6211 MockRead(ASYNC, 0, 0) // EOF
6214 // Skip the session window updates unless we're using SPDY/3.1 and
6216 size_t read_offset = (GetParam().protocol >= kProtoSPDY31) ? 0 : 2;
6217 size_t num_reads = arraysize(reads) - read_offset;
6219 // Force all writes to happen before any read, last write will not
6220 // actually queue a frame, due to window size being 0.
6221 DelayedSocketData data(num_writes, reads + read_offset, num_reads,
6222 writes.get(), num_writes);
6224 ScopedVector<UploadElementReader> element_readers;
6225 std::string upload_data_string(kSpdyStreamInitialWindowSize, 'a');
6226 upload_data_string.append(kUploadData, kUploadDataSize);
6227 element_readers.push_back(new UploadBytesElementReader(
6228 upload_data_string.c_str(), upload_data_string.size()));
6229 UploadDataStream upload_data_stream(element_readers.Pass(), 0);
6231 HttpRequestInfo request;
6232 request.method = "POST";
6233 request.url = GURL("http://www.google.com/");
6234 request.upload_data_stream = &upload_data_stream;
6235 NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY,
6236 BoundNetLog(), GetParam(), NULL);
6237 helper.AddData(&data);
6238 helper.RunPreTestSetup();
6240 HttpNetworkTransaction* trans = helper.trans();
6242 TestCompletionCallback callback;
6243 int rv = trans->Start(&helper.request(), callback.callback(), BoundNetLog());
6244 EXPECT_EQ(ERR_IO_PENDING, rv);
6246 base::RunLoop().RunUntilIdle(); // Write as much as we can.
6248 SpdyHttpStream* stream = static_cast<SpdyHttpStream*>(trans->stream_.get());
6249 ASSERT_TRUE(stream != NULL);
6250 ASSERT_TRUE(stream->stream() != NULL);
6251 EXPECT_EQ(0, stream->stream()->send_window_size());
6252 // All the body data should have been read.
6253 // TODO(satorux): This is because of the weirdness in reading the request
6254 // body in OnSendBodyComplete(). See crbug.com/113107.
6255 EXPECT_TRUE(upload_data_stream.IsEOF());
6256 // But the body is not yet fully sent (kUploadData is not yet sent)
6257 // since we're send-stalled.
6258 EXPECT_TRUE(stream->stream()->send_stalled_by_flow_control());
6260 data.ForceNextRead(); // Read in WINDOW_UPDATE frame.
6261 rv = callback.WaitForResult();
6262 helper.VerifyDataConsumed();
6265 // Test we correctly handle the case where the SETTINGS frame results in
6266 // unstalling the send window.
6267 TEST_P(SpdyNetworkTransactionTest, FlowControlStallResumeAfterSettings) {
6268 if (GetParam().protocol < kProtoSPDY3)
6271 // Number of frames we need to send to zero out the window size: data
6272 // frames plus SYN_STREAM plus the last data frame; also we need another
6273 // data frame that we will send once the SETTING is received, therefore +3.
6274 size_t num_writes = kSpdyStreamInitialWindowSize / kMaxSpdyFrameChunkSize + 3;
6276 // Calculate last frame's size; 0 size data frame is legal.
6277 size_t last_frame_size =
6278 kSpdyStreamInitialWindowSize % kMaxSpdyFrameChunkSize;
6280 // Construct content for a data frame of maximum size.
6281 std::string content(kMaxSpdyFrameChunkSize, 'a');
6283 scoped_ptr<SpdyFrame> req(spdy_util_.ConstructSpdyPost(
6284 kRequestUrl, 1, kSpdyStreamInitialWindowSize + kUploadDataSize,
6288 scoped_ptr<SpdyFrame> body1(
6289 spdy_util_.ConstructSpdyBodyFrame(
6290 1, content.c_str(), content.size(), false));
6292 // Last frame to zero out the window size.
6293 scoped_ptr<SpdyFrame> body2(
6294 spdy_util_.ConstructSpdyBodyFrame(
6295 1, content.c_str(), last_frame_size, false));
6297 // Data frame to be sent once SETTINGS frame is received.
6298 scoped_ptr<SpdyFrame> body3(spdy_util_.ConstructSpdyBodyFrame(1, true));
6300 // Fill in mock reads/writes.
6301 std::vector<MockRead> reads;
6302 std::vector<MockWrite> writes;
6304 writes.push_back(CreateMockWrite(*req, i++));
6305 while (i < num_writes - 2)
6306 writes.push_back(CreateMockWrite(*body1, i++));
6307 writes.push_back(CreateMockWrite(*body2, i++));
6309 // Construct read frame for SETTINGS that gives enough space to upload the
6310 // rest of the data.
6311 SettingsMap settings;
6312 settings[SETTINGS_INITIAL_WINDOW_SIZE] =
6313 SettingsFlagsAndValue(
6314 SETTINGS_FLAG_NONE, kSpdyStreamInitialWindowSize * 2);
6315 scoped_ptr<SpdyFrame> settings_frame_large(
6316 spdy_util_.ConstructSpdySettings(settings));
6318 reads.push_back(CreateMockRead(*settings_frame_large, i++));
6320 scoped_ptr<SpdyFrame> session_window_update(
6321 spdy_util_.ConstructSpdyWindowUpdate(0, kUploadDataSize));
6322 if (GetParam().protocol >= kProtoSPDY31)
6323 reads.push_back(CreateMockRead(*session_window_update, i++));
6325 writes.push_back(CreateMockWrite(*body3, i++));
6327 scoped_ptr<SpdyFrame> reply(spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
6328 reads.push_back(CreateMockRead(*reply, i++));
6329 reads.push_back(CreateMockRead(*body2, i++));
6330 reads.push_back(CreateMockRead(*body3, i++));
6331 reads.push_back(MockRead(ASYNC, 0, i++)); // EOF
6333 // Force all writes to happen before any read, last write will not
6334 // actually queue a frame, due to window size being 0.
6335 DeterministicSocketData data(vector_as_array(&reads), reads.size(),
6336 vector_as_array(&writes), writes.size());
6338 ScopedVector<UploadElementReader> element_readers;
6339 std::string upload_data_string(kSpdyStreamInitialWindowSize, 'a');
6340 upload_data_string.append(kUploadData, kUploadDataSize);
6341 element_readers.push_back(new UploadBytesElementReader(
6342 upload_data_string.c_str(), upload_data_string.size()));
6343 UploadDataStream upload_data_stream(element_readers.Pass(), 0);
6345 HttpRequestInfo request;
6346 request.method = "POST";
6347 request.url = GURL("http://www.google.com/");
6348 request.upload_data_stream = &upload_data_stream;
6349 NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY,
6350 BoundNetLog(), GetParam(), NULL);
6351 helper.SetDeterministic();
6352 helper.RunPreTestSetup();
6353 helper.AddDeterministicData(&data);
6355 HttpNetworkTransaction* trans = helper.trans();
6357 TestCompletionCallback callback;
6358 int rv = trans->Start(&helper.request(), callback.callback(), BoundNetLog());
6359 EXPECT_EQ(ERR_IO_PENDING, rv);
6361 data.RunFor(num_writes - 1); // Write as much as we can.
6363 SpdyHttpStream* stream = static_cast<SpdyHttpStream*>(trans->stream_.get());
6364 ASSERT_TRUE(stream != NULL);
6365 ASSERT_TRUE(stream->stream() != NULL);
6366 EXPECT_EQ(0, stream->stream()->send_window_size());
6368 // All the body data should have been read.
6369 // TODO(satorux): This is because of the weirdness in reading the request
6370 // body in OnSendBodyComplete(). See crbug.com/113107.
6371 EXPECT_TRUE(upload_data_stream.IsEOF());
6372 // But the body is not yet fully sent (kUploadData is not yet sent)
6373 // since we're send-stalled.
6374 EXPECT_TRUE(stream->stream()->send_stalled_by_flow_control());
6376 data.RunFor(6); // Read in SETTINGS frame to unstall.
6377 rv = callback.WaitForResult();
6378 helper.VerifyDataConsumed();
6379 // If stream is NULL, that means it was unstalled and closed.
6380 EXPECT_TRUE(stream->stream() == NULL);
6383 // Test we correctly handle the case where the SETTINGS frame results in a
6384 // negative send window size.
6385 TEST_P(SpdyNetworkTransactionTest, FlowControlNegativeSendWindowSize) {
6386 if (GetParam().protocol < kProtoSPDY3)
6389 // Number of frames we need to send to zero out the window size: data
6390 // frames plus SYN_STREAM plus the last data frame; also we need another
6391 // data frame that we will send once the SETTING is received, therefore +3.
6392 size_t num_writes = kSpdyStreamInitialWindowSize / kMaxSpdyFrameChunkSize + 3;
6394 // Calculate last frame's size; 0 size data frame is legal.
6395 size_t last_frame_size =
6396 kSpdyStreamInitialWindowSize % kMaxSpdyFrameChunkSize;
6398 // Construct content for a data frame of maximum size.
6399 std::string content(kMaxSpdyFrameChunkSize, 'a');
6401 scoped_ptr<SpdyFrame> req(spdy_util_.ConstructSpdyPost(
6402 kRequestUrl, 1, kSpdyStreamInitialWindowSize + kUploadDataSize,
6406 scoped_ptr<SpdyFrame> body1(
6407 spdy_util_.ConstructSpdyBodyFrame(
6408 1, content.c_str(), content.size(), false));
6410 // Last frame to zero out the window size.
6411 scoped_ptr<SpdyFrame> body2(
6412 spdy_util_.ConstructSpdyBodyFrame(
6413 1, content.c_str(), last_frame_size, false));
6415 // Data frame to be sent once SETTINGS frame is received.
6416 scoped_ptr<SpdyFrame> body3(spdy_util_.ConstructSpdyBodyFrame(1, true));
6418 // Fill in mock reads/writes.
6419 std::vector<MockRead> reads;
6420 std::vector<MockWrite> writes;
6422 writes.push_back(CreateMockWrite(*req, i++));
6423 while (i < num_writes - 2)
6424 writes.push_back(CreateMockWrite(*body1, i++));
6425 writes.push_back(CreateMockWrite(*body2, i++));
6427 // Construct read frame for SETTINGS that makes the send_window_size
6429 SettingsMap new_settings;
6430 new_settings[SETTINGS_INITIAL_WINDOW_SIZE] =
6431 SettingsFlagsAndValue(
6432 SETTINGS_FLAG_NONE, kSpdyStreamInitialWindowSize / 2);
6433 scoped_ptr<SpdyFrame> settings_frame_small(
6434 spdy_util_.ConstructSpdySettings(new_settings));
6435 // Construct read frames for WINDOW_UPDATE that makes the send_window_size
6437 scoped_ptr<SpdyFrame> session_window_update_init_size(
6438 spdy_util_.ConstructSpdyWindowUpdate(0, kSpdyStreamInitialWindowSize));
6439 scoped_ptr<SpdyFrame> window_update_init_size(
6440 spdy_util_.ConstructSpdyWindowUpdate(1, kSpdyStreamInitialWindowSize));
6442 reads.push_back(CreateMockRead(*settings_frame_small, i++));
6444 if (GetParam().protocol >= kProtoSPDY3)
6445 reads.push_back(CreateMockRead(*session_window_update_init_size, i++));
6447 reads.push_back(CreateMockRead(*window_update_init_size, i++));
6449 writes.push_back(CreateMockWrite(*body3, i++));
6451 scoped_ptr<SpdyFrame> reply(spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
6452 reads.push_back(CreateMockRead(*reply, i++));
6453 reads.push_back(CreateMockRead(*body2, i++));
6454 reads.push_back(CreateMockRead(*body3, i++));
6455 reads.push_back(MockRead(ASYNC, 0, i++)); // EOF
6457 // Force all writes to happen before any read, last write will not
6458 // actually queue a frame, due to window size being 0.
6459 DeterministicSocketData data(vector_as_array(&reads), reads.size(),
6460 vector_as_array(&writes), writes.size());
6462 ScopedVector<UploadElementReader> element_readers;
6463 std::string upload_data_string(kSpdyStreamInitialWindowSize, 'a');
6464 upload_data_string.append(kUploadData, kUploadDataSize);
6465 element_readers.push_back(new UploadBytesElementReader(
6466 upload_data_string.c_str(), upload_data_string.size()));
6467 UploadDataStream upload_data_stream(element_readers.Pass(), 0);
6469 HttpRequestInfo request;
6470 request.method = "POST";
6471 request.url = GURL("http://www.google.com/");
6472 request.upload_data_stream = &upload_data_stream;
6473 NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY,
6474 BoundNetLog(), GetParam(), NULL);
6475 helper.SetDeterministic();
6476 helper.RunPreTestSetup();
6477 helper.AddDeterministicData(&data);
6479 HttpNetworkTransaction* trans = helper.trans();
6481 TestCompletionCallback callback;
6482 int rv = trans->Start(&helper.request(), callback.callback(), BoundNetLog());
6483 EXPECT_EQ(ERR_IO_PENDING, rv);
6485 data.RunFor(num_writes - 1); // Write as much as we can.
6487 SpdyHttpStream* stream = static_cast<SpdyHttpStream*>(trans->stream_.get());
6488 ASSERT_TRUE(stream != NULL);
6489 ASSERT_TRUE(stream->stream() != NULL);
6490 EXPECT_EQ(0, stream->stream()->send_window_size());
6492 // All the body data should have been read.
6493 // TODO(satorux): This is because of the weirdness in reading the request
6494 // body in OnSendBodyComplete(). See crbug.com/113107.
6495 EXPECT_TRUE(upload_data_stream.IsEOF());
6496 // But the body is not yet fully sent (kUploadData is not yet sent)
6497 // since we're send-stalled.
6498 EXPECT_TRUE(stream->stream()->send_stalled_by_flow_control());
6500 // Read in WINDOW_UPDATE or SETTINGS frame.
6501 data.RunFor((GetParam().protocol >= kProtoSPDY31) ? 8 : 7);
6502 rv = callback.WaitForResult();
6503 helper.VerifyDataConsumed();