1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
9 #include "base/bind_helpers.h"
10 #include "base/file_util.h"
11 #include "base/files/scoped_temp_dir.h"
12 #include "base/memory/scoped_vector.h"
13 #include "base/run_loop.h"
14 #include "base/stl_util.h"
15 #include "base/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 //-----------------------------------------------------------------------------
50 const char kRequestUrl
[] = "http://www.google.com/";
52 enum SpdyNetworkTransactionTestSSLType
{
58 struct SpdyNetworkTransactionTestParams
{
59 SpdyNetworkTransactionTestParams()
60 : protocol(kProtoSPDY3
),
63 SpdyNetworkTransactionTestParams(
65 SpdyNetworkTransactionTestSSLType ssl_type
)
70 SpdyNetworkTransactionTestSSLType ssl_type
;
73 void UpdateSpdySessionDependencies(
74 SpdyNetworkTransactionTestParams test_params
,
75 SpdySessionDependencies
* session_deps
) {
76 switch (test_params
.ssl_type
) {
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();
85 session_deps
->force_spdy_over_ssl
= false;
86 session_deps
->force_spdy_always
= true;
89 session_deps
->force_spdy_over_ssl
= true;
90 session_deps
->force_spdy_always
= true;
97 SpdySessionDependencies
* CreateSpdySessionDependencies(
98 SpdyNetworkTransactionTestParams test_params
) {
99 SpdySessionDependencies
* session_deps
=
100 new SpdySessionDependencies(test_params
.protocol
);
101 UpdateSpdySessionDependencies(test_params
, 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
);
116 class SpdyNetworkTransactionTest
117 : public ::testing::TestWithParam
<SpdyNetworkTransactionTestParams
> {
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
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
{
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
{
151 NormalSpdyTransactionHelper(const HttpRequestInfo
& request
,
152 RequestPriority priority
,
153 const BoundNetLog
& log
,
154 SpdyNetworkTransactionTestParams test_params
,
155 SpdySessionDependencies
* session_deps
)
158 session_deps_(session_deps
== NULL
?
159 CreateSpdySessionDependencies(test_params
) :
161 session_(SpdySessionDependencies::SpdyCreateSession(
162 session_deps_
.get())),
164 test_params_(test_params
),
165 deterministic_(false),
166 spdy_enabled_(true) {
167 switch (test_params_
.ssl_type
) {
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;
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())
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
);
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()) {
249 HttpResponseInfo::ConnectionInfoFromNextProto(
250 test_params_
.protocol
),
251 response
->connection_info
);
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
);
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()
283 << (*it
)->read_index();
284 EXPECT_TRUE((*it
)->at_write_eof()) << "Write count: "
285 << (*it
)->write_count()
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
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()
300 << (*it
)->read_index();
301 EXPECT_TRUE(!(*it
)->at_write_eof()) << "Write count: "
302 << (*it
)->write_count()
304 << (*it
)->write_index();
308 void RunToCompletion(StaticSocketDataProvider
* data
) {
312 VerifyDataConsumed();
315 void RunToCompletionWithSSLData(
316 StaticSocketDataProvider
* data
,
317 scoped_ptr
<SSLSocketDataProvider
> ssl_provider
) {
319 AddDataWithSSLSocketDataProvider(data
, ssl_provider
.Pass());
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(
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
) {
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 {
396 scoped_ptr
<SpdySessionDependencies
>& session_deps() {
397 return session_deps_
;
399 int port() const { return port_
; }
400 SpdyNetworkTransactionTestParams
test_params() const {
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_
;
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(),
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(),
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(),
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;
587 scoped_refptr
<net::IOBufferWithSize
> buf(new net::IOBufferWithSize(kSize
));
588 TestCompletionCallback callback
;
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) {
602 result
->append(buf
->data(), rv
);
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
);
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()));
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.
657 ReadResult(trans2
.get(), data
, &result2
);
658 // Read the response body.
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: "
669 << "||||| Expected data: "
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
,
682 helper
->ResetTrans();
685 static void StartTransactionCallback(
686 const scoped_refptr
<HttpNetworkSession
>& session
,
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_
;
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
720 INSTANTIATE_TEST_CASE_P(
722 SpdyNetworkTransactionTest
,
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));
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
) {
793 EXPECT_EQ(0, spdy_prio
);
796 EXPECT_EQ(1, spdy_prio
);
800 EXPECT_EQ(2, spdy_prio
);
803 EXPECT_EQ(3, spdy_prio
);
811 EXPECT_EQ(0, spdy_prio
);
814 EXPECT_EQ(1, spdy_prio
);
817 EXPECT_EQ(2, spdy_prio
);
820 EXPECT_EQ(3, spdy_prio
);
823 EXPECT_EQ(4, spdy_prio
);
830 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
831 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
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(),
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
),
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);
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
),
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
);
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
);
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);
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
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);
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
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);
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
);
1547 // The KillerCallback will delete the transaction on error as part of the
1549 class KillerCallback
: public TestCompletionCallbackBase
{
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_
; }
1562 void OnComplete(int result
) {
1564 delete transaction_
;
1569 HttpNetworkTransaction
* transaction_
;
1570 CompletionCallback callback_
;
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);
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
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
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
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
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
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
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
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
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(
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(),
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(),
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(),
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(),
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(),
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.
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);
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
);
2182 helper
.ResetTrans();
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();
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
,
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
);
2404 helper
.ResetTrans();
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
));
2466 base::Bind(&SpdyNetworkTransactionTest::StartTransactionCallback
,
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
));
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
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/"),
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);
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
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
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/"),
2672 &spdy_url_request_context
);
2673 spdy_url_request_context
.socket_factory().
2674 AddSocketDataProvider(&data
);
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"),
2686 &spdy_url_request_context
);
2687 spdy_url_request_context
.socket_factory().
2688 AddSocketDataProvider(&data2
);
2690 d2
.set_quit_on_redirect(true);
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
,
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
,
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
,
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();
2898 // Verify that we consumed all test data.
2899 EXPECT_TRUE(data
.at_read_eof()) << "Read count: "
2900 << data
.read_count()
2902 << data
.read_index();
2903 EXPECT_TRUE(data
.at_write_eof()) << "Write count: "
2904 << data
.write_count()
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
,
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.
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();
3142 // Verify that we consumed all test data.
3143 EXPECT_TRUE(data
.at_read_eof()) << "Read count: "
3144 << data
.read_count()
3146 << data
.read_index();
3147 EXPECT_TRUE(data
.at_write_eof()) << "Write count: "
3148 << data
.write_count()
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.
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();
3208 // Verify that we consumed all test data.
3209 EXPECT_TRUE(data
.at_read_eof()) << "Read count: "
3210 << data
.read_count()
3212 << data
.read_index();
3213 EXPECT_TRUE(data
.at_write_eof()) << "Write count: "
3214 << data
.write_count()
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(),
3249 // Associated stream ID
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();
3275 // Verify that we consumed all test data.
3276 EXPECT_TRUE(data
.at_read_eof()) << "Read count: "
3277 << data
.read_count()
3279 << data
.read_index();
3280 EXPECT_TRUE(data
.at_write_eof()) << "Write count: "
3281 << data
.write_count()
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
3293 TEST_P(SpdyNetworkTransactionTest
, SynReplyHeaders
) {
3294 struct SynReplyHeadersTests
{
3296 const char* extra_headers
[5];
3297 SpdyHeaderBlock expected_headers
;
3299 // This uses a multi-valued cookie header.
3302 "cookie", "val2", // will get appended separated by NULL
3306 // This is the minimalist set of headers.
3310 // Headers with a comma separated list.
3312 { "cookie", "val1,val2",
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
,
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
);
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
;
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
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
3397 DATA_FLAG_NONE
// Data Flags
3399 // Modify the following data to change/add test cases:
3400 struct SynReplyTests
{
3401 const SpdyHeaderInfo
* syn_reply
;
3404 const char* extra_headers
[2][16];
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.
3412 { { "cookie", "val1,val2",
3416 spdy_util_
.GetStatusKey(), "200",
3417 spdy_util_
.GetPathKey(), "/index.php",
3418 spdy_util_
.GetVersionKey(), "HTTP/1.1",
3422 }, { // Multiple vary fields.
3426 { { "friend", "barney",
3427 "enemy", "snaggletooth",
3432 spdy_util_
.GetStatusKey(), "200",
3433 spdy_util_
.GetPathKey(), "/index.php",
3434 spdy_util_
.GetVersionKey(), "HTTP/1.1",
3438 }, { // Test a '*' vary field.
3442 { { "cookie", "val1,val2",
3446 spdy_util_
.GetStatusKey(), "200",
3447 spdy_util_
.GetPathKey(), "/index.php",
3448 spdy_util_
.GetVersionKey(), "HTTP/1.1",
3452 }, { // Multiple comma-separated vary fields.
3456 { { "friend", "barney",
3457 "enemy", "snaggletooth",
3460 { "vary", "friend,enemy",
3461 spdy_util_
.GetStatusKey(), "200",
3462 spdy_util_
.GetPathKey(), "/index.php",
3463 spdy_util_
.GetVersionKey(), "HTTP/1.1",
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],
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
;
3533 std::string name
, value
, lines
;
3534 while (headers
->EnumerateHeaderLines(&iter
, &name
, &value
)) {
3537 lines
.append(value
);
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],
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
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
3566 DATA_FLAG_NONE
// Data Flags
3569 struct InvalidSynReplyTests
{
3571 const char* headers
[10];
3573 // SYN_REPLY missing status header
3577 spdy_util_
.GetPathKey(), "/index.php",
3578 spdy_util_
.GetVersionKey(), "HTTP/1.1",
3582 // SYN_REPLY missing version header
3585 spdy_util_
.GetPathKey(), "/index.php",
3589 // SYN_REPLY with no headers
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
,
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
) {
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);
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(),
3642 spdy_util_
.spdy_version());
3644 struct SynReplyTests
{
3645 const SpdyFrame
* syn_reply
;
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
) {
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);
3687 syn_reply_wrong_length
->size() - framer
.GetControlFrameHeaderSize();
3688 size_t wrong_size
= right_size
- 4;
3689 test::SetFrameLength(syn_reply_wrong_length
.get(),
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());
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.
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
);
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(),
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());
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(
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();
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] = {
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.
3959 TestCompletionCallback read_callback
;
3961 std::string content
;
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();
3972 content
.append(buf
->data(), rv
);
3973 } else if (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] = {
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.
4051 TestCompletionCallback read_callback
;
4053 std::string content
;
4054 int reads_completed
= 0;
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();
4065 EXPECT_EQ(kSmallReadSize
, rv
);
4066 content
.append(buf
->data(), rv
);
4067 } else if (rv
< 0) {
4068 FAIL() << "Unexpected read error: " << rv
;
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] = {
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.
4149 TestCompletionCallback read_callback
;
4151 std::string content
;
4152 int reads_completed
= 0;
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());
4159 EXPECT_EQ(kSmallReadSize
, rv
);
4160 content
.append(buf
->data(), rv
);
4161 } else if (rv
< 0) {
4162 FAIL() << "Unexpected read error: " << rv
;
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] = {
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.
4239 TestCompletionCallback read_callback
;
4241 std::string content
;
4242 int reads_completed
= 0;
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();
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
);
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.
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.
4348 static const SpdyHeaderInfo kSynReplyInfo
= {
4349 SYN_REPLY
, // Syn Reply
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
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(
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
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
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(
4492 SETTINGS_FLAG_PLEASE_PERSIST
,
4495 // Next add another persisted setting.
4496 spdy_session_pool
->http_server_properties()->SetSpdySetting(
4499 SETTINGS_FLAG_PLEASE_PERSIST
,
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(
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
) {
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(
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
));
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(
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
) {
4707 data
.reset(new OrderedSocketData(reads_SPDYNOSSL
,
4708 arraysize(reads_SPDYNOSSL
),
4710 arraysize(writes_SPDYNOSSL
)));
4713 data
.reset(new OrderedSocketData(reads_SPDYSSL
,
4714 arraysize(reads_SPDYSSL
),
4716 arraysize(writes_SPDYSSL
)));
4719 data
.reset(new OrderedSocketData(reads_SPDYNPN
,
4720 arraysize(reads_SPDYNPN
),
4722 arraysize(writes_SPDYNPN
)));
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();
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(
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(
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
) {
4867 data_proxy
.reset(new OrderedSocketData(reads_SPDYNPN
,
4868 arraysize(reads_SPDYNPN
),
4870 arraysize(writes_SPDYNPN
)));
4873 data_proxy
.reset(new OrderedSocketData(reads_SPDYNOSSL
,
4874 arraysize(reads_SPDYNOSSL
),
4876 arraysize(writes_SPDYNOSSL
)));
4879 data_proxy
.reset(new OrderedSocketData(reads_SPDYSSL
,
4880 arraysize(reads_SPDYSSL
),
4882 arraysize(writes_SPDYSSL
)));
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();
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.
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
;
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.
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();
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
);
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
[] = {
5079 "Basic realm=\"MyRealm\""
5081 scoped_ptr
<SpdyFrame
> resp_authentication(
5082 spdy_util_
.ConstructSpdySynReplyError(
5083 "401 Authentication Required",
5084 kExtraAuthenticationHeaders
,
5085 arraysize(kExtraAuthenticationHeaders
) / 2,
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(),
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(),
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
,
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(),
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(),
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.
5283 // Start the transaction.
5284 TestCompletionCallback callback
;
5285 int rv
= trans
->Start(
5286 &CreateGetRequest(), callback
.callback(), BoundNetLog());
5287 EXPECT_EQ(ERR_IO_PENDING
, rv
);
5289 rv
= callback
.WaitForResult();
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()));
5297 &CreateGetPushRequest(), callback
.callback(), BoundNetLog());
5298 EXPECT_EQ(ERR_IO_PENDING
, rv
);
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.
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: "
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)
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(),
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(),
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(),
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.
5422 // Start the transaction.
5423 TestCompletionCallback callback
;
5424 int rv
= trans
->Start(
5425 &CreateGetRequest(), callback
.callback(), BoundNetLog());
5426 EXPECT_EQ(ERR_IO_PENDING
, rv
);
5428 rv
= callback
.WaitForResult();
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()));
5436 &CreateGetPushRequest(), callback
.callback(), BoundNetLog());
5437 EXPECT_EQ(ERR_IO_PENDING
, rv
);
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.
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(
5470 "http://www.google.com/foo.dat"));
5472 EXPECT_TRUE(response2
.headers
->HasHeaderValue(
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"));
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)
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(),
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(),
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.
5559 // Start the transaction.
5560 TestCompletionCallback callback
;
5561 int rv
= trans
->Start(
5562 &CreateGetRequest(), callback
.callback(), BoundNetLog());
5563 EXPECT_EQ(ERR_IO_PENDING
, rv
);
5565 rv
= callback
.WaitForResult();
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()));
5573 &CreateGetPushRequest(), callback
.callback(), BoundNetLog());
5574 EXPECT_EQ(ERR_IO_PENDING
, rv
);
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.
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).
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(),
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(),
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(),
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(),
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.
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
,
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.
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();
5868 // Verify that we consumed all test data.
5869 EXPECT_TRUE(data
.at_read_eof()) << "Read count: "
5870 << data
.read_count()
5872 << data
.read_index();
5873 EXPECT_TRUE(data
.at_write_eof()) << "Write count: "
5874 << data
.write_count()
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.
5959 EXPECT_EQ(OK
, callback
.WaitForResult());
5961 // And now we can allow everything else to run to completion.
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
)
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
);
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());
6076 rv
= callback
.WaitForResult();
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
)
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();
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
)
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
);
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
)
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,
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
,
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
]);
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
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
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
)
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
,
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
;
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
)
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
,
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
;
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
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
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
{
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
6644 INSTANTIATE_TEST_CASE_P(
6646 SpdyNetworkTransactionNoTLSUsageCheckTest
,
6647 ::testing::Values(SpdyNetworkTransactionTestParams(kProtoDeprecatedSPDY2
,
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
{
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)
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(
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());