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