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/files/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/chunked_upload_data_stream.h"
19 #include "net/base/elements_upload_data_stream.h"
20 #include "net/base/request_priority.h"
21 #include "net/base/test_data_directory.h"
22 #include "net/base/upload_bytes_element_reader.h"
23 #include "net/base/upload_file_element_reader.h"
24 #include "net/http/http_network_session_peer.h"
25 #include "net/http/http_network_transaction.h"
26 #include "net/http/http_server_properties.h"
27 #include "net/http/http_transaction_test_util.h"
28 #include "net/log/test_net_log.h"
29 #include "net/log/test_net_log_entry.h"
30 #include "net/log/test_net_log_util.h"
31 #include "net/socket/client_socket_pool_base.h"
32 #include "net/socket/next_proto.h"
33 #include "net/spdy/buffered_spdy_framer.h"
34 #include "net/spdy/spdy_http_stream.h"
35 #include "net/spdy/spdy_http_utils.h"
36 #include "net/spdy/spdy_session.h"
37 #include "net/spdy/spdy_session_pool.h"
38 #include "net/spdy/spdy_test_util_common.h"
39 #include "net/spdy/spdy_test_utils.h"
40 #include "net/ssl/ssl_connection_status_flags.h"
41 #include "net/test/cert_test_util.h"
42 #include "net/url_request/url_request_test_util.h"
43 #include "testing/gmock/include/gmock/gmock.h"
44 #include "testing/platform_test.h"
46 //-----------------------------------------------------------------------------
55 enum SpdyNetworkTransactionTestSSLType
{
56 // Request an https:// URL and use NPN (or ALPN) to negotiate SPDY during
59 // Request and http:// URL to a server that supports SPDY via Alternative
60 // Service on port 443.
61 // See: https//tools.ietf.org/id/draft-ietf-httpbis-alt-svc-06.html
62 HTTP_SPDY_VIA_ALT_SVC
,
65 struct SpdyNetworkTransactionTestParams
{
66 SpdyNetworkTransactionTestParams()
67 : protocol(kProtoSPDY31
), ssl_type(HTTPS_SPDY_VIA_NPN
) {}
69 SpdyNetworkTransactionTestParams(NextProto protocol
,
70 SpdyNetworkTransactionTestSSLType ssl_type
)
71 : protocol(protocol
), ssl_type(ssl_type
) {}
73 friend std::ostream
& operator<<(std::ostream
& os
,
74 const SpdyNetworkTransactionTestParams
& p
) {
77 case HTTP_SPDY_VIA_ALT_SVC
:
78 type_str
= "HTTP_SPDY_VIA_ALT_SVC";
80 case HTTPS_SPDY_VIA_NPN
:
81 type_str
= "HTTPS_SPDY_VIA_NPN";
84 os
<< "{ protocol: " << SSLClientSocket::NextProtoToString(p
.protocol
)
85 << ", ssl_type: " << type_str
<< " }";
90 SpdyNetworkTransactionTestSSLType ssl_type
;
93 void UpdateSpdySessionDependencies(SpdyNetworkTransactionTestParams test_params
,
94 SpdySessionDependencies
* session_deps
) {
95 session_deps
->use_alternate_protocols
= true;
96 session_deps
->next_protos
= SpdyNextProtos();
97 if (test_params
.ssl_type
== HTTP_SPDY_VIA_ALT_SVC
) {
98 session_deps
->http_server_properties
.SetAlternativeService(
99 HostPortPair("www.example.org", 80),
100 AlternativeService(AlternateProtocolFromNextProto(test_params
.protocol
),
101 "www.example.org", 443),
106 SpdySessionDependencies
* CreateSpdySessionDependencies(
107 SpdyNetworkTransactionTestParams test_params
) {
108 SpdySessionDependencies
* session_deps
=
109 new SpdySessionDependencies(test_params
.protocol
);
110 UpdateSpdySessionDependencies(test_params
, session_deps
);
114 SpdySessionDependencies
* CreateSpdySessionDependencies(
115 SpdyNetworkTransactionTestParams test_params
,
116 ProxyService
* proxy_service
) {
117 SpdySessionDependencies
* session_deps
=
118 new SpdySessionDependencies(test_params
.protocol
, proxy_service
);
119 UpdateSpdySessionDependencies(test_params
, session_deps
);
125 class SpdyNetworkTransactionTest
126 : public ::testing::TestWithParam
<SpdyNetworkTransactionTestParams
> {
128 SpdyNetworkTransactionTest() : spdy_util_(GetParam().protocol
) {
129 spdy_util_
.set_default_url(GURL(GetDefaultUrl()));
132 virtual ~SpdyNetworkTransactionTest() {
133 // UploadDataStream may post a deletion tasks back to the message loop on
135 upload_data_stream_
.reset();
136 base::RunLoop().RunUntilIdle();
139 void SetUp() override
{
140 get_request_initialized_
= false;
141 post_request_initialized_
= false;
142 chunked_post_request_initialized_
= false;
143 ASSERT_TRUE(temp_dir_
.CreateUniqueTempDir());
146 struct TransactionHelperResult
{
148 std::string status_line
;
149 std::string response_data
;
150 HttpResponseInfo response_info
;
153 // A helper class that handles all the initial npn/ssl setup.
154 class NormalSpdyTransactionHelper
{
156 NormalSpdyTransactionHelper(const HttpRequestInfo
& request
,
157 RequestPriority priority
,
158 const BoundNetLog
& log
,
159 SpdyNetworkTransactionTestParams test_params
,
160 SpdySessionDependencies
* session_deps
)
163 session_deps_(session_deps
== NULL
164 ? CreateSpdySessionDependencies(test_params
)
167 SpdySessionDependencies::SpdyCreateSession(session_deps_
.get())),
169 test_params_(test_params
),
171 deterministic_(false),
172 spdy_enabled_(true) {}
174 ~NormalSpdyTransactionHelper() {
175 // Any test which doesn't close the socket by sending it an EOF will
176 // have a valid session left open, which leaks the entire session pool.
177 // This is just fine - in fact, some of our tests intentionally do this
178 // so that we can check consistency of the SpdySessionPool as the test
179 // finishes. If we had put an EOF on the socket, the SpdySession would
180 // have closed and we wouldn't be able to check the consistency.
182 // Forcefully close existing sessions here.
183 session()->spdy_session_pool()->CloseAllSessions();
186 void SetDeterministic() {
187 session_
= SpdySessionDependencies::SpdyCreateSessionDeterministic(
188 session_deps_
.get());
189 deterministic_
= true;
192 void SetSpdyDisabled() {
193 spdy_enabled_
= false;
194 port_
= test_params_
.ssl_type
== HTTP_SPDY_VIA_ALT_SVC
? 80 : 443;
197 void RunPreTestSetup() {
198 if (!session_deps_
.get())
199 session_deps_
.reset(CreateSpdySessionDependencies(test_params_
));
200 if (!session_
.get()) {
201 session_
= SpdySessionDependencies::SpdyCreateSession(
202 session_deps_
.get());
205 // We're now ready to use SSL-npn SPDY.
206 trans_
.reset(new HttpNetworkTransaction(priority_
, session_
.get()));
209 // Start the transaction, read some data, finish.
210 void RunDefaultTest() {
211 if (!StartDefaultTest())
216 bool StartDefaultTest() {
217 output_
.rv
= trans_
->Start(&request_
, callback_
.callback(), log_
);
219 // We expect an IO Pending or some sort of error.
220 EXPECT_LT(output_
.rv
, 0);
221 return output_
.rv
== ERR_IO_PENDING
;
224 void FinishDefaultTest() {
225 output_
.rv
= callback_
.WaitForResult();
226 if (output_
.rv
!= OK
) {
227 session_
->spdy_session_pool()->CloseCurrentSessions(ERR_ABORTED
);
232 const HttpResponseInfo
* response
= trans_
->GetResponseInfo();
233 ASSERT_TRUE(response
!= NULL
);
234 ASSERT_TRUE(response
->headers
.get() != NULL
);
235 EXPECT_EQ("HTTP/1.1 200 OK", response
->headers
->GetStatusLine());
236 EXPECT_EQ(spdy_enabled_
, response
->was_fetched_via_spdy
);
237 if (HttpStreamFactory::spdy_enabled()) {
239 HttpResponseInfo::ConnectionInfoFromNextProto(
240 test_params_
.protocol
),
241 response
->connection_info
);
243 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP1
,
244 response
->connection_info
);
247 EXPECT_TRUE(response
->was_npn_negotiated
);
249 // If SPDY is disabled, an HTTP request should not be diverted
250 // over an SSL session.
251 EXPECT_EQ(request_
.url
.SchemeIs("https"),
252 response
->was_npn_negotiated
);
254 EXPECT_EQ("127.0.0.1", response
->socket_address
.host());
255 EXPECT_EQ(port_
, response
->socket_address
.port());
256 output_
.status_line
= response
->headers
->GetStatusLine();
257 output_
.response_info
= *response
; // Make a copy so we can verify.
258 output_
.rv
= ReadTransaction(trans_
.get(), &output_
.response_data
);
261 void FinishDefaultTestWithoutVerification() {
262 output_
.rv
= callback_
.WaitForResult();
263 if (output_
.rv
!= OK
)
264 session_
->spdy_session_pool()->CloseCurrentSessions(ERR_ABORTED
);
267 // Most tests will want to call this function. In particular, the MockReads
268 // should end with an empty read, and that read needs to be processed to
269 // ensure proper deletion of the spdy_session_pool.
270 void VerifyDataConsumed() {
271 for (const SocketDataProvider
* provider
: data_vector_
) {
272 EXPECT_TRUE(provider
->AllReadDataConsumed());
273 EXPECT_TRUE(provider
->AllWriteDataConsumed());
277 // Occasionally a test will expect to error out before certain reads are
278 // processed. In that case we want to explicitly ensure that the reads were
280 void VerifyDataNotConsumed() {
281 for (const SocketDataProvider
* provider
: data_vector_
) {
282 EXPECT_FALSE(provider
->AllReadDataConsumed());
283 EXPECT_FALSE(provider
->AllWriteDataConsumed());
287 void RunToCompletion(SocketDataProvider
* data
) {
291 VerifyDataConsumed();
294 void RunToCompletionWithSSLData(
295 SocketDataProvider
* data
,
296 scoped_ptr
<SSLSocketDataProvider
> ssl_provider
) {
298 AddDataWithSSLSocketDataProvider(data
, ssl_provider
.Pass());
300 VerifyDataConsumed();
303 void AddData(SocketDataProvider
* data
) {
304 scoped_ptr
<SSLSocketDataProvider
> ssl_provider(
305 new SSLSocketDataProvider(ASYNC
, OK
));
307 ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem");
308 AddDataWithSSLSocketDataProvider(data
, ssl_provider
.Pass());
311 void AddDataWithSSLSocketDataProvider(
312 SocketDataProvider
* data
,
313 scoped_ptr
<SSLSocketDataProvider
> ssl_provider
) {
314 DCHECK(!deterministic_
);
315 data_vector_
.push_back(data
);
316 if (ssl_provider
->next_proto_status
==
317 SSLClientSocket::kNextProtoUnsupported
) {
318 ssl_provider
->SetNextProto(test_params_
.protocol
);
321 session_deps_
->socket_factory
->AddSSLSocketDataProvider(
323 ssl_vector_
.push_back(ssl_provider
.release());
325 session_deps_
->socket_factory
->AddSocketDataProvider(data
);
326 if (test_params_
.ssl_type
== HTTP_SPDY_VIA_ALT_SVC
) {
327 MockConnect
hanging_connect(SYNCHRONOUS
, ERR_IO_PENDING
);
328 StaticSocketDataProvider
* hanging_non_alt_svc_socket
=
329 new StaticSocketDataProvider(NULL
, 0, NULL
, 0);
330 hanging_non_alt_svc_socket
->set_connect_data(hanging_connect
);
331 session_deps_
->socket_factory
->AddSocketDataProvider(
332 hanging_non_alt_svc_socket
);
333 alternate_vector_
.push_back(hanging_non_alt_svc_socket
);
337 void AddDeterministicData(DeterministicSocketData
* data
) {
338 DCHECK(deterministic_
);
339 data_vector_
.push_back(data
);
340 SSLSocketDataProvider
* ssl_provider
=
341 new SSLSocketDataProvider(ASYNC
, OK
);
342 ssl_provider
->SetNextProto(test_params_
.protocol
);
344 ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem");
345 ssl_vector_
.push_back(ssl_provider
);
346 session_deps_
->deterministic_socket_factory
->AddSSLSocketDataProvider(
349 session_deps_
->deterministic_socket_factory
->AddSocketDataProvider(data
);
350 if (test_params_
.ssl_type
== HTTP_SPDY_VIA_ALT_SVC
) {
351 MockConnect
hanging_connect(SYNCHRONOUS
, ERR_IO_PENDING
);
352 DeterministicSocketData
* hanging_non_alt_svc_socket
=
353 new DeterministicSocketData(NULL
, 0, NULL
, 0);
354 hanging_non_alt_svc_socket
->set_connect_data(hanging_connect
);
355 session_deps_
->deterministic_socket_factory
->AddSocketDataProvider(
356 hanging_non_alt_svc_socket
);
357 alternate_vector_
.push_back(hanging_non_alt_svc_socket
);
361 void SetSession(const scoped_refptr
<HttpNetworkSession
>& session
) {
364 HttpNetworkTransaction
* trans() { return trans_
.get(); }
365 void ResetTrans() { trans_
.reset(); }
366 TransactionHelperResult
& output() { return output_
; }
367 const HttpRequestInfo
& request() const { return request_
; }
368 const scoped_refptr
<HttpNetworkSession
>& session() const {
371 scoped_ptr
<SpdySessionDependencies
>& session_deps() {
372 return session_deps_
;
374 int port() const { return port_
; }
375 SpdyNetworkTransactionTestParams
test_params() const {
380 typedef std::vector
<SocketDataProvider
*> DataVector
;
381 typedef ScopedVector
<SSLSocketDataProvider
> SSLVector
;
382 typedef ScopedVector
<SocketDataProvider
> AlternateVector
;
383 typedef ScopedVector
<DeterministicSocketData
> AlternateDeterministicVector
;
384 HttpRequestInfo request_
;
385 RequestPriority priority_
;
386 scoped_ptr
<SpdySessionDependencies
> session_deps_
;
387 scoped_refptr
<HttpNetworkSession
> session_
;
388 TransactionHelperResult output_
;
389 scoped_ptr
<SocketDataProvider
> first_transaction_
;
390 SSLVector ssl_vector_
;
391 TestCompletionCallback callback_
;
392 scoped_ptr
<HttpNetworkTransaction
> trans_
;
393 scoped_ptr
<HttpNetworkTransaction
> trans_http_
;
394 DataVector data_vector_
;
395 AlternateVector alternate_vector_
;
396 AlternateDeterministicVector alternate_deterministic_vector_
;
397 const BoundNetLog log_
;
398 SpdyNetworkTransactionTestParams test_params_
;
404 void ConnectStatusHelperWithExpectedStatus(const MockRead
& status
,
405 int expected_status
);
407 void ConnectStatusHelper(const MockRead
& status
);
409 const HttpRequestInfo
& CreateGetPushRequest() {
410 get_push_request_
.method
= "GET";
411 get_push_request_
.url
= GURL(GetDefaultUrlWithPath("/foo.dat"));
412 get_push_request_
.load_flags
= 0;
413 return get_push_request_
;
416 const HttpRequestInfo
& CreateGetRequest() {
417 if (!get_request_initialized_
) {
418 get_request_
.method
= "GET";
419 get_request_
.url
= GURL(GetDefaultUrl());
420 get_request_
.load_flags
= 0;
421 get_request_initialized_
= true;
426 const HttpRequestInfo
& CreateGetRequestWithUserAgent() {
427 if (!get_request_initialized_
) {
428 get_request_
.method
= "GET";
429 get_request_
.url
= GURL(GetDefaultUrl());
430 get_request_
.load_flags
= 0;
431 get_request_
.extra_headers
.SetHeader("User-Agent", "Chrome");
432 get_request_initialized_
= true;
437 const HttpRequestInfo
& CreatePostRequest() {
438 if (!post_request_initialized_
) {
439 ScopedVector
<UploadElementReader
> element_readers
;
440 element_readers
.push_back(
441 new UploadBytesElementReader(kUploadData
, kUploadDataSize
));
442 upload_data_stream_
.reset(
443 new ElementsUploadDataStream(element_readers
.Pass(), 0));
445 post_request_
.method
= "POST";
446 post_request_
.url
= GURL(GetDefaultUrl());
447 post_request_
.upload_data_stream
= upload_data_stream_
.get();
448 post_request_initialized_
= true;
450 return post_request_
;
453 const HttpRequestInfo
& CreateFilePostRequest() {
454 if (!post_request_initialized_
) {
455 base::FilePath file_path
;
456 CHECK(base::CreateTemporaryFileInDir(temp_dir_
.path(), &file_path
));
457 CHECK_EQ(static_cast<int>(kUploadDataSize
),
458 base::WriteFile(file_path
, kUploadData
, kUploadDataSize
));
460 ScopedVector
<UploadElementReader
> element_readers
;
461 element_readers
.push_back(
462 new UploadFileElementReader(base::MessageLoopProxy::current().get(),
467 upload_data_stream_
.reset(
468 new ElementsUploadDataStream(element_readers
.Pass(), 0));
470 post_request_
.method
= "POST";
471 post_request_
.url
= GURL(GetDefaultUrl());
472 post_request_
.upload_data_stream
= upload_data_stream_
.get();
473 post_request_initialized_
= true;
475 return post_request_
;
478 const HttpRequestInfo
& CreateUnreadableFilePostRequest() {
479 if (post_request_initialized_
)
480 return post_request_
;
482 base::FilePath file_path
;
483 CHECK(base::CreateTemporaryFileInDir(temp_dir_
.path(), &file_path
));
484 CHECK_EQ(static_cast<int>(kUploadDataSize
),
485 base::WriteFile(file_path
, kUploadData
, kUploadDataSize
));
486 CHECK(base::MakeFileUnreadable(file_path
));
488 ScopedVector
<UploadElementReader
> element_readers
;
489 element_readers
.push_back(
490 new UploadFileElementReader(base::MessageLoopProxy::current().get(),
495 upload_data_stream_
.reset(
496 new ElementsUploadDataStream(element_readers
.Pass(), 0));
498 post_request_
.method
= "POST";
499 post_request_
.url
= GURL(GetDefaultUrl());
500 post_request_
.upload_data_stream
= upload_data_stream_
.get();
501 post_request_initialized_
= true;
502 return post_request_
;
505 const HttpRequestInfo
& CreateComplexPostRequest() {
506 if (!post_request_initialized_
) {
507 const int kFileRangeOffset
= 1;
508 const int kFileRangeLength
= 3;
509 CHECK_LT(kFileRangeOffset
+ kFileRangeLength
, kUploadDataSize
);
511 base::FilePath file_path
;
512 CHECK(base::CreateTemporaryFileInDir(temp_dir_
.path(), &file_path
));
513 CHECK_EQ(static_cast<int>(kUploadDataSize
),
514 base::WriteFile(file_path
, kUploadData
, kUploadDataSize
));
516 ScopedVector
<UploadElementReader
> element_readers
;
517 element_readers
.push_back(
518 new UploadBytesElementReader(kUploadData
, kFileRangeOffset
));
519 element_readers
.push_back(
520 new UploadFileElementReader(base::MessageLoopProxy::current().get(),
525 element_readers
.push_back(new UploadBytesElementReader(
526 kUploadData
+ kFileRangeOffset
+ kFileRangeLength
,
527 kUploadDataSize
- (kFileRangeOffset
+ kFileRangeLength
)));
528 upload_data_stream_
.reset(
529 new ElementsUploadDataStream(element_readers
.Pass(), 0));
531 post_request_
.method
= "POST";
532 post_request_
.url
= GURL(GetDefaultUrl());
533 post_request_
.upload_data_stream
= upload_data_stream_
.get();
534 post_request_initialized_
= true;
536 return post_request_
;
539 const HttpRequestInfo
& CreateChunkedPostRequest() {
540 if (!chunked_post_request_initialized_
) {
541 upload_chunked_data_stream_
.reset(new ChunkedUploadDataStream(0));
542 chunked_post_request_
.method
= "POST";
543 chunked_post_request_
.url
= GURL(GetDefaultUrl());
544 chunked_post_request_
.upload_data_stream
=
545 upload_chunked_data_stream_
.get();
546 chunked_post_request_initialized_
= true;
548 return chunked_post_request_
;
551 // Read the result of a particular transaction, knowing that we've got
552 // multiple transactions in the read pipeline; so as we read, we may have
553 // to skip over data destined for other transactions while we consume
554 // the data for |trans|.
555 int ReadResult(HttpNetworkTransaction
* trans
,
556 SocketDataProvider
* data
,
557 std::string
* result
) {
558 const int kSize
= 3000;
561 scoped_refptr
<IOBufferWithSize
> buf(new IOBufferWithSize(kSize
));
562 TestCompletionCallback callback
;
564 int rv
= trans
->Read(buf
.get(), kSize
, callback
.callback());
565 if (rv
== ERR_IO_PENDING
) {
566 rv
= callback
.WaitForResult();
567 } else if (rv
<= 0) {
570 result
->append(buf
->data(), rv
);
576 void VerifyStreamsClosed(const NormalSpdyTransactionHelper
& helper
) {
577 // This lengthy block is reaching into the pool to dig out the active
578 // session. Once we have the session, we verify that the streams are
579 // all closed and not leaked at this point.
580 const GURL
& url
= helper
.request().url
;
581 HostPortPair
host_port_pair(url
.host(), 443);
582 SpdySessionKey
key(host_port_pair
, ProxyServer::Direct(),
583 PRIVACY_MODE_DISABLED
);
585 const scoped_refptr
<HttpNetworkSession
>& session
= helper
.session();
586 base::WeakPtr
<SpdySession
> spdy_session
=
587 session
->spdy_session_pool()->FindAvailableSession(key
, log
);
588 ASSERT_TRUE(spdy_session
!= NULL
);
589 EXPECT_EQ(0u, spdy_session
->num_active_streams());
590 EXPECT_EQ(0u, spdy_session
->num_unclaimed_pushed_streams());
593 void RunServerPushTest(SequencedSocketData
* data
,
594 HttpResponseInfo
* response
,
595 HttpResponseInfo
* push_response
,
596 const std::string
& expected
) {
597 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
598 BoundNetLog(), GetParam(), NULL
);
599 helper
.RunPreTestSetup();
600 helper
.AddData(data
);
602 HttpNetworkTransaction
* trans
= helper
.trans();
604 // Start the transaction with basic parameters.
605 TestCompletionCallback callback
;
606 int rv
= trans
->Start(
607 &CreateGetRequest(), callback
.callback(), BoundNetLog());
608 EXPECT_EQ(ERR_IO_PENDING
, rv
);
609 rv
= callback
.WaitForResult();
611 // Request the pushed path.
612 scoped_ptr
<HttpNetworkTransaction
> trans2(
613 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
615 &CreateGetPushRequest(), callback
.callback(), BoundNetLog());
616 EXPECT_EQ(ERR_IO_PENDING
, rv
);
617 base::RunLoop().RunUntilIdle();
619 // The data for the pushed path may be coming in more than 1 frame. Compile
620 // the results into a single string.
622 // Read the server push body.
624 ReadResult(trans2
.get(), data
, &result2
);
625 // Read the response body.
627 ReadResult(trans
, data
, &result
);
629 // Verify that we consumed all test data.
630 EXPECT_TRUE(data
->AllReadDataConsumed());
631 EXPECT_TRUE(data
->AllWriteDataConsumed());
633 // Verify that the received push data is same as the expected push data.
634 EXPECT_EQ(result2
.compare(expected
), 0) << "Received data: "
636 << "||||| Expected data: "
639 // Verify the SYN_REPLY.
640 // Copy the response info, because trans goes away.
641 *response
= *trans
->GetResponseInfo();
642 *push_response
= *trans2
->GetResponseInfo();
644 VerifyStreamsClosed(helper
);
647 static void DeleteSessionCallback(NormalSpdyTransactionHelper
* helper
,
649 helper
->ResetTrans();
652 static void StartTransactionCallback(
653 const scoped_refptr
<HttpNetworkSession
>& session
,
656 scoped_ptr
<HttpNetworkTransaction
> trans(
657 new HttpNetworkTransaction(DEFAULT_PRIORITY
, session
.get()));
658 TestCompletionCallback callback
;
659 HttpRequestInfo request
;
660 request
.method
= "GET";
662 request
.load_flags
= 0;
663 int rv
= trans
->Start(&request
, callback
.callback(), BoundNetLog());
664 EXPECT_EQ(ERR_IO_PENDING
, rv
);
665 callback
.WaitForResult();
668 ChunkedUploadDataStream
* upload_chunked_data_stream() const {
669 return upload_chunked_data_stream_
.get();
672 const char* GetDefaultUrl() {
673 switch (GetParam().ssl_type
) {
674 case HTTP_SPDY_VIA_ALT_SVC
:
675 return "http://www.example.org";
676 case HTTPS_SPDY_VIA_NPN
:
677 return "https://www.example.org";
684 std::string
GetDefaultUrlWithPath(const char* path
) {
685 return std::string(GetDefaultUrl()) + path
;
688 SpdyTestUtil spdy_util_
;
691 scoped_ptr
<ChunkedUploadDataStream
> upload_chunked_data_stream_
;
692 scoped_ptr
<UploadDataStream
> upload_data_stream_
;
693 bool get_request_initialized_
;
694 bool post_request_initialized_
;
695 bool chunked_post_request_initialized_
;
696 HttpRequestInfo get_request_
;
697 HttpRequestInfo post_request_
;
698 HttpRequestInfo chunked_post_request_
;
699 HttpRequestInfo get_push_request_
;
700 base::ScopedTempDir temp_dir_
;
703 //-----------------------------------------------------------------------------
704 // All tests are run with three different connection types: SPDY after NPN
705 // negotiation, SPDY without SSL, and SPDY with SSL.
707 // TODO(akalin): Use ::testing::Combine() when we are able to use
709 INSTANTIATE_TEST_CASE_P(
711 SpdyNetworkTransactionTest
,
713 SpdyNetworkTransactionTestParams(kProtoSPDY31
, HTTPS_SPDY_VIA_NPN
),
714 SpdyNetworkTransactionTestParams(kProtoSPDY31
, HTTP_SPDY_VIA_ALT_SVC
),
715 SpdyNetworkTransactionTestParams(kProtoSPDY4_14
, HTTPS_SPDY_VIA_NPN
),
716 SpdyNetworkTransactionTestParams(kProtoSPDY4_14
, HTTP_SPDY_VIA_ALT_SVC
),
717 SpdyNetworkTransactionTestParams(kProtoSPDY4
, HTTPS_SPDY_VIA_NPN
),
718 SpdyNetworkTransactionTestParams(kProtoSPDY4
, HTTP_SPDY_VIA_ALT_SVC
)));
720 // Verify HttpNetworkTransaction constructor.
721 TEST_P(SpdyNetworkTransactionTest
, Constructor
) {
722 scoped_ptr
<SpdySessionDependencies
> session_deps(
723 CreateSpdySessionDependencies(GetParam()));
724 scoped_refptr
<HttpNetworkSession
> session(
725 SpdySessionDependencies::SpdyCreateSession(session_deps
.get()));
726 scoped_ptr
<HttpTransaction
> trans(
727 new HttpNetworkTransaction(DEFAULT_PRIORITY
, session
.get()));
730 TEST_P(SpdyNetworkTransactionTest
, Get
) {
731 // Construct the request.
732 scoped_ptr
<SpdyFrame
> req(
733 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
734 MockWrite writes
[] = {CreateMockWrite(*req
, 0)};
736 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
737 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
739 CreateMockRead(*resp
, 1),
740 CreateMockRead(*body
, 2),
741 MockRead(ASYNC
, 0, 3) // EOF
744 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
745 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
746 BoundNetLog(), GetParam(), NULL
);
747 helper
.RunToCompletion(&data
);
748 TransactionHelperResult out
= helper
.output();
749 EXPECT_EQ(OK
, out
.rv
);
750 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
751 EXPECT_EQ("hello!", out
.response_data
);
754 TEST_P(SpdyNetworkTransactionTest
, GetAtEachPriority
) {
755 for (RequestPriority p
= MINIMUM_PRIORITY
; p
<= MAXIMUM_PRIORITY
;
756 p
= RequestPriority(p
+ 1)) {
757 // Construct the request.
758 scoped_ptr
<SpdyFrame
> req(
759 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, p
, true));
760 MockWrite writes
[] = {CreateMockWrite(*req
, 0)};
762 SpdyPriority spdy_prio
= 0;
763 EXPECT_TRUE(GetSpdyPriority(spdy_util_
.spdy_version(), *req
, &spdy_prio
));
764 // this repeats the RequestPriority-->SpdyPriority mapping from
765 // SpdyFramer::ConvertRequestPriorityToSpdyPriority to make
766 // sure it's being done right.
767 if (spdy_util_
.spdy_version() < SPDY3
) {
770 EXPECT_EQ(0, spdy_prio
);
773 EXPECT_EQ(1, spdy_prio
);
777 EXPECT_EQ(2, spdy_prio
);
780 EXPECT_EQ(3, spdy_prio
);
788 EXPECT_EQ(0, spdy_prio
);
791 EXPECT_EQ(1, spdy_prio
);
794 EXPECT_EQ(2, spdy_prio
);
797 EXPECT_EQ(3, spdy_prio
);
800 EXPECT_EQ(4, spdy_prio
);
807 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
808 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
810 CreateMockRead(*resp
, 1),
811 CreateMockRead(*body
, 2),
812 MockRead(ASYNC
, 0, 3) // EOF
815 SequencedSocketData
data(reads
, arraysize(reads
), writes
,
817 HttpRequestInfo http_req
= CreateGetRequest();
819 NormalSpdyTransactionHelper
helper(http_req
, p
, BoundNetLog(),
821 helper
.RunToCompletion(&data
);
822 TransactionHelperResult out
= helper
.output();
823 EXPECT_EQ(OK
, out
.rv
);
824 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
825 EXPECT_EQ("hello!", out
.response_data
);
829 // Start three gets simultaniously; making sure that multiplexed
830 // streams work properly.
832 // This can't use the TransactionHelper method, since it only
833 // handles a single transaction, and finishes them as soon
834 // as it launches them.
836 // TODO(gavinp): create a working generalized TransactionHelper that
837 // can allow multiple streams in flight.
839 TEST_P(SpdyNetworkTransactionTest
, ThreeGets
) {
840 scoped_ptr
<SpdyFrame
> req(
841 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
842 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
843 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, false));
844 scoped_ptr
<SpdyFrame
> fbody(spdy_util_
.ConstructSpdyBodyFrame(1, true));
846 scoped_ptr
<SpdyFrame
> req2(
847 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 3, LOWEST
, true));
848 scoped_ptr
<SpdyFrame
> resp2(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 3));
849 scoped_ptr
<SpdyFrame
> body2(spdy_util_
.ConstructSpdyBodyFrame(3, false));
850 scoped_ptr
<SpdyFrame
> fbody2(spdy_util_
.ConstructSpdyBodyFrame(3, true));
852 scoped_ptr
<SpdyFrame
> req3(
853 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 5, LOWEST
, true));
854 scoped_ptr
<SpdyFrame
> resp3(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 5));
855 scoped_ptr
<SpdyFrame
> body3(spdy_util_
.ConstructSpdyBodyFrame(5, false));
856 scoped_ptr
<SpdyFrame
> fbody3(spdy_util_
.ConstructSpdyBodyFrame(5, true));
858 MockWrite writes
[] = {
859 CreateMockWrite(*req
, 0),
860 CreateMockWrite(*req2
, 3),
861 CreateMockWrite(*req3
, 6),
864 CreateMockRead(*resp
, 1),
865 CreateMockRead(*body
, 2),
866 CreateMockRead(*resp2
, 4),
867 CreateMockRead(*body2
, 5),
868 CreateMockRead(*resp3
, 7),
869 CreateMockRead(*body3
, 8),
871 CreateMockRead(*fbody
, 9),
872 CreateMockRead(*fbody2
, 10),
873 CreateMockRead(*fbody3
, 11),
875 MockRead(ASYNC
, 0, 12), // EOF
877 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
878 SequencedSocketData
data_placeholder(NULL
, 0, NULL
, 0);
881 TransactionHelperResult out
;
882 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
883 BoundNetLog(), GetParam(), NULL
);
884 helper
.RunPreTestSetup();
885 helper
.AddData(&data
);
886 // We require placeholder data because three get requests are sent out at
887 // the same time which results in three sockets being connected. The first
888 // on will negotiate SPDY and will be used for all requests.
889 helper
.AddData(&data_placeholder
);
890 helper
.AddData(&data_placeholder
);
891 scoped_ptr
<HttpNetworkTransaction
> trans1(
892 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
893 scoped_ptr
<HttpNetworkTransaction
> trans2(
894 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
895 scoped_ptr
<HttpNetworkTransaction
> trans3(
896 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
898 TestCompletionCallback callback1
;
899 TestCompletionCallback callback2
;
900 TestCompletionCallback callback3
;
902 HttpRequestInfo httpreq1
= CreateGetRequest();
903 HttpRequestInfo httpreq2
= CreateGetRequest();
904 HttpRequestInfo httpreq3
= CreateGetRequest();
906 out
.rv
= trans1
->Start(&httpreq1
, callback1
.callback(), log
);
907 ASSERT_EQ(ERR_IO_PENDING
, out
.rv
);
908 out
.rv
= trans2
->Start(&httpreq2
, callback2
.callback(), log
);
909 ASSERT_EQ(ERR_IO_PENDING
, out
.rv
);
910 out
.rv
= trans3
->Start(&httpreq3
, callback3
.callback(), log
);
911 ASSERT_EQ(ERR_IO_PENDING
, out
.rv
);
913 out
.rv
= callback1
.WaitForResult();
914 ASSERT_EQ(OK
, out
.rv
);
915 out
.rv
= callback3
.WaitForResult();
916 ASSERT_EQ(OK
, out
.rv
);
918 const HttpResponseInfo
* response1
= trans1
->GetResponseInfo();
919 EXPECT_TRUE(response1
->headers
.get() != NULL
);
920 EXPECT_TRUE(response1
->was_fetched_via_spdy
);
921 out
.status_line
= response1
->headers
->GetStatusLine();
922 out
.response_info
= *response1
;
924 trans2
->GetResponseInfo();
926 out
.rv
= ReadTransaction(trans1
.get(), &out
.response_data
);
927 helper
.VerifyDataConsumed();
928 EXPECT_EQ(OK
, out
.rv
);
930 EXPECT_EQ(OK
, out
.rv
);
931 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
932 EXPECT_EQ("hello!hello!", out
.response_data
);
935 TEST_P(SpdyNetworkTransactionTest
, TwoGetsLateBinding
) {
936 scoped_ptr
<SpdyFrame
> req(
937 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
938 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
939 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, false));
940 scoped_ptr
<SpdyFrame
> fbody(spdy_util_
.ConstructSpdyBodyFrame(1, true));
942 scoped_ptr
<SpdyFrame
> req2(
943 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 3, LOWEST
, true));
944 scoped_ptr
<SpdyFrame
> resp2(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 3));
945 scoped_ptr
<SpdyFrame
> body2(spdy_util_
.ConstructSpdyBodyFrame(3, false));
946 scoped_ptr
<SpdyFrame
> fbody2(spdy_util_
.ConstructSpdyBodyFrame(3, true));
948 MockWrite writes
[] = {
949 CreateMockWrite(*req
, 0), CreateMockWrite(*req2
, 3),
952 CreateMockRead(*resp
, 1),
953 CreateMockRead(*body
, 2),
954 CreateMockRead(*resp2
, 4),
955 CreateMockRead(*body2
, 5),
956 CreateMockRead(*fbody
, 6),
957 CreateMockRead(*fbody2
, 7),
958 MockRead(ASYNC
, 0, 8), // EOF
960 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
962 MockConnect
never_finishing_connect(SYNCHRONOUS
, ERR_IO_PENDING
);
963 SequencedSocketData
data_placeholder(NULL
, 0, NULL
, 0);
964 data_placeholder
.set_connect_data(never_finishing_connect
);
967 TransactionHelperResult out
;
968 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
969 BoundNetLog(), GetParam(), NULL
);
970 helper
.RunPreTestSetup();
971 helper
.AddData(&data
);
972 // We require placeholder data because two requests are sent out at
973 // the same time which results in two sockets being connected. The first
974 // on will negotiate SPDY and will be used for all requests.
975 helper
.AddData(&data_placeholder
);
976 scoped_ptr
<HttpNetworkTransaction
> trans1(
977 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
978 scoped_ptr
<HttpNetworkTransaction
> trans2(
979 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
981 TestCompletionCallback callback1
;
982 TestCompletionCallback callback2
;
984 HttpRequestInfo httpreq1
= CreateGetRequest();
985 HttpRequestInfo httpreq2
= CreateGetRequest();
987 out
.rv
= trans1
->Start(&httpreq1
, callback1
.callback(), log
);
988 ASSERT_EQ(ERR_IO_PENDING
, out
.rv
);
989 out
.rv
= trans2
->Start(&httpreq2
, callback2
.callback(), log
);
990 ASSERT_EQ(ERR_IO_PENDING
, out
.rv
);
992 out
.rv
= callback1
.WaitForResult();
993 ASSERT_EQ(OK
, out
.rv
);
994 out
.rv
= callback2
.WaitForResult();
995 ASSERT_EQ(OK
, out
.rv
);
997 const HttpResponseInfo
* response1
= trans1
->GetResponseInfo();
998 EXPECT_TRUE(response1
->headers
.get() != NULL
);
999 EXPECT_TRUE(response1
->was_fetched_via_spdy
);
1000 out
.status_line
= response1
->headers
->GetStatusLine();
1001 out
.response_info
= *response1
;
1002 out
.rv
= ReadTransaction(trans1
.get(), &out
.response_data
);
1003 EXPECT_EQ(OK
, out
.rv
);
1004 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1005 EXPECT_EQ("hello!hello!", out
.response_data
);
1007 const HttpResponseInfo
* response2
= trans2
->GetResponseInfo();
1008 EXPECT_TRUE(response2
->headers
.get() != NULL
);
1009 EXPECT_TRUE(response2
->was_fetched_via_spdy
);
1010 out
.status_line
= response2
->headers
->GetStatusLine();
1011 out
.response_info
= *response2
;
1012 out
.rv
= ReadTransaction(trans2
.get(), &out
.response_data
);
1013 EXPECT_EQ(OK
, out
.rv
);
1014 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1015 EXPECT_EQ("hello!hello!", out
.response_data
);
1017 helper
.VerifyDataConsumed();
1020 TEST_P(SpdyNetworkTransactionTest
, TwoGetsLateBindingFromPreconnect
) {
1021 scoped_ptr
<SpdyFrame
> req(
1022 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
1023 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
1024 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, false));
1025 scoped_ptr
<SpdyFrame
> fbody(spdy_util_
.ConstructSpdyBodyFrame(1, true));
1027 scoped_ptr
<SpdyFrame
> req2(
1028 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 3, LOWEST
, true));
1029 scoped_ptr
<SpdyFrame
> resp2(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 3));
1030 scoped_ptr
<SpdyFrame
> body2(spdy_util_
.ConstructSpdyBodyFrame(3, false));
1031 scoped_ptr
<SpdyFrame
> fbody2(spdy_util_
.ConstructSpdyBodyFrame(3, true));
1033 MockWrite writes
[] = {
1034 CreateMockWrite(*req
, 0), CreateMockWrite(*req2
, 3),
1036 MockRead reads
[] = {
1037 CreateMockRead(*resp
, 1),
1038 CreateMockRead(*body
, 2),
1039 CreateMockRead(*resp2
, 4),
1040 CreateMockRead(*body2
, 5),
1041 CreateMockRead(*fbody
, 6),
1042 CreateMockRead(*fbody2
, 7),
1043 MockRead(ASYNC
, 0, 8), // EOF
1045 SequencedSocketData
preconnect_data(reads
, arraysize(reads
), writes
,
1048 MockConnect
never_finishing_connect(ASYNC
, ERR_IO_PENDING
);
1050 SequencedSocketData
data_placeholder(NULL
, 0, NULL
, 0);
1051 data_placeholder
.set_connect_data(never_finishing_connect
);
1054 TransactionHelperResult out
;
1055 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
1056 BoundNetLog(), GetParam(), NULL
);
1057 helper
.RunPreTestSetup();
1058 helper
.AddData(&preconnect_data
);
1059 // We require placeholder data because 3 connections are attempted (first is
1060 // the preconnect, 2nd and 3rd are the never finished connections.
1061 helper
.AddData(&data_placeholder
);
1062 helper
.AddData(&data_placeholder
);
1064 scoped_ptr
<HttpNetworkTransaction
> trans1(
1065 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
1066 scoped_ptr
<HttpNetworkTransaction
> trans2(
1067 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
1069 TestCompletionCallback callback1
;
1070 TestCompletionCallback callback2
;
1072 HttpRequestInfo httpreq
= CreateGetRequest();
1074 // Preconnect the first.
1075 SSLConfig preconnect_ssl_config
;
1076 helper
.session()->ssl_config_service()->GetSSLConfig(&preconnect_ssl_config
);
1077 HttpStreamFactory
* http_stream_factory
=
1078 helper
.session()->http_stream_factory();
1079 helper
.session()->GetNextProtos(&preconnect_ssl_config
.next_protos
);
1081 http_stream_factory
->PreconnectStreams(
1082 1, httpreq
, DEFAULT_PRIORITY
,
1083 preconnect_ssl_config
, preconnect_ssl_config
);
1085 out
.rv
= trans1
->Start(&httpreq
, callback1
.callback(), log
);
1086 ASSERT_EQ(ERR_IO_PENDING
, out
.rv
);
1087 out
.rv
= trans2
->Start(&httpreq
, callback2
.callback(), log
);
1088 ASSERT_EQ(ERR_IO_PENDING
, out
.rv
);
1090 out
.rv
= callback1
.WaitForResult();
1091 ASSERT_EQ(OK
, out
.rv
);
1092 out
.rv
= callback2
.WaitForResult();
1093 ASSERT_EQ(OK
, out
.rv
);
1095 const HttpResponseInfo
* response1
= trans1
->GetResponseInfo();
1096 EXPECT_TRUE(response1
->headers
.get() != NULL
);
1097 EXPECT_TRUE(response1
->was_fetched_via_spdy
);
1098 out
.status_line
= response1
->headers
->GetStatusLine();
1099 out
.response_info
= *response1
;
1100 out
.rv
= ReadTransaction(trans1
.get(), &out
.response_data
);
1101 EXPECT_EQ(OK
, out
.rv
);
1102 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1103 EXPECT_EQ("hello!hello!", out
.response_data
);
1105 const HttpResponseInfo
* response2
= trans2
->GetResponseInfo();
1106 EXPECT_TRUE(response2
->headers
.get() != NULL
);
1107 EXPECT_TRUE(response2
->was_fetched_via_spdy
);
1108 out
.status_line
= response2
->headers
->GetStatusLine();
1109 out
.response_info
= *response2
;
1110 out
.rv
= ReadTransaction(trans2
.get(), &out
.response_data
);
1111 EXPECT_EQ(OK
, out
.rv
);
1112 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1113 EXPECT_EQ("hello!hello!", out
.response_data
);
1115 helper
.VerifyDataConsumed();
1118 // Similar to ThreeGets above, however this test adds a SETTINGS
1119 // frame. The SETTINGS frame is read during the IO loop waiting on
1120 // the first transaction completion, and sets a maximum concurrent
1121 // stream limit of 1. This means that our IO loop exists after the
1122 // second transaction completes, so we can assert on read_index().
1123 TEST_P(SpdyNetworkTransactionTest
, ThreeGetsWithMaxConcurrent
) {
1124 // Construct the request.
1125 scoped_ptr
<SpdyFrame
> req(
1126 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
1127 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
1128 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, false));
1129 scoped_ptr
<SpdyFrame
> fbody(spdy_util_
.ConstructSpdyBodyFrame(1, true));
1131 scoped_ptr
<SpdyFrame
> req2(
1132 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 3, LOWEST
, true));
1133 scoped_ptr
<SpdyFrame
> resp2(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 3));
1134 scoped_ptr
<SpdyFrame
> body2(spdy_util_
.ConstructSpdyBodyFrame(3, false));
1135 scoped_ptr
<SpdyFrame
> fbody2(spdy_util_
.ConstructSpdyBodyFrame(3, true));
1137 scoped_ptr
<SpdyFrame
> req3(
1138 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 5, LOWEST
, true));
1139 scoped_ptr
<SpdyFrame
> resp3(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 5));
1140 scoped_ptr
<SpdyFrame
> body3(spdy_util_
.ConstructSpdyBodyFrame(5, false));
1141 scoped_ptr
<SpdyFrame
> fbody3(spdy_util_
.ConstructSpdyBodyFrame(5, true));
1143 SettingsMap settings
;
1144 const uint32 max_concurrent_streams
= 1;
1145 settings
[SETTINGS_MAX_CONCURRENT_STREAMS
] =
1146 SettingsFlagsAndValue(SETTINGS_FLAG_NONE
, max_concurrent_streams
);
1147 scoped_ptr
<SpdyFrame
> settings_frame(
1148 spdy_util_
.ConstructSpdySettings(settings
));
1149 scoped_ptr
<SpdyFrame
> settings_ack(spdy_util_
.ConstructSpdySettingsAck());
1151 MockWrite writes
[] = {
1152 CreateMockWrite(*req
, 0),
1153 CreateMockWrite(*settings_ack
, 5),
1154 CreateMockWrite(*req2
, 6),
1155 CreateMockWrite(*req3
, 10),
1158 MockRead reads
[] = {
1159 CreateMockRead(*settings_frame
, 1),
1160 CreateMockRead(*resp
, 2),
1161 CreateMockRead(*body
, 3),
1162 CreateMockRead(*fbody
, 4),
1163 CreateMockRead(*resp2
, 7),
1164 CreateMockRead(*body2
, 8),
1165 CreateMockRead(*fbody2
, 9),
1166 CreateMockRead(*resp3
, 11),
1167 CreateMockRead(*body3
, 12),
1168 CreateMockRead(*fbody3
, 13),
1170 MockRead(ASYNC
, 0, 14), // EOF
1173 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
1176 TransactionHelperResult out
;
1178 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
1179 BoundNetLog(), GetParam(), NULL
);
1180 helper
.RunPreTestSetup();
1181 helper
.AddData(&data
);
1182 scoped_ptr
<HttpNetworkTransaction
> trans1(
1183 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
1184 scoped_ptr
<HttpNetworkTransaction
> trans2(
1185 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
1186 scoped_ptr
<HttpNetworkTransaction
> trans3(
1187 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
1189 TestCompletionCallback callback1
;
1190 TestCompletionCallback callback2
;
1191 TestCompletionCallback callback3
;
1193 HttpRequestInfo httpreq1
= CreateGetRequest();
1194 HttpRequestInfo httpreq2
= CreateGetRequest();
1195 HttpRequestInfo httpreq3
= CreateGetRequest();
1197 out
.rv
= trans1
->Start(&httpreq1
, callback1
.callback(), log
);
1198 ASSERT_EQ(out
.rv
, ERR_IO_PENDING
);
1199 // Run transaction 1 through quickly to force a read of our SETTINGS
1201 out
.rv
= callback1
.WaitForResult();
1202 ASSERT_EQ(OK
, out
.rv
);
1204 out
.rv
= trans2
->Start(&httpreq2
, callback2
.callback(), log
);
1205 ASSERT_EQ(out
.rv
, ERR_IO_PENDING
);
1206 out
.rv
= trans3
->Start(&httpreq3
, callback3
.callback(), log
);
1207 ASSERT_EQ(out
.rv
, ERR_IO_PENDING
);
1208 out
.rv
= callback2
.WaitForResult();
1209 ASSERT_EQ(OK
, out
.rv
);
1211 out
.rv
= callback3
.WaitForResult();
1212 ASSERT_EQ(OK
, out
.rv
);
1214 const HttpResponseInfo
* response1
= trans1
->GetResponseInfo();
1215 ASSERT_TRUE(response1
!= NULL
);
1216 EXPECT_TRUE(response1
->headers
.get() != NULL
);
1217 EXPECT_TRUE(response1
->was_fetched_via_spdy
);
1218 out
.status_line
= response1
->headers
->GetStatusLine();
1219 out
.response_info
= *response1
;
1220 out
.rv
= ReadTransaction(trans1
.get(), &out
.response_data
);
1221 EXPECT_EQ(OK
, out
.rv
);
1222 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1223 EXPECT_EQ("hello!hello!", out
.response_data
);
1225 const HttpResponseInfo
* response2
= trans2
->GetResponseInfo();
1226 out
.status_line
= response2
->headers
->GetStatusLine();
1227 out
.response_info
= *response2
;
1228 out
.rv
= ReadTransaction(trans2
.get(), &out
.response_data
);
1229 EXPECT_EQ(OK
, out
.rv
);
1230 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1231 EXPECT_EQ("hello!hello!", out
.response_data
);
1233 const HttpResponseInfo
* response3
= trans3
->GetResponseInfo();
1234 out
.status_line
= response3
->headers
->GetStatusLine();
1235 out
.response_info
= *response3
;
1236 out
.rv
= ReadTransaction(trans3
.get(), &out
.response_data
);
1237 EXPECT_EQ(OK
, out
.rv
);
1238 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1239 EXPECT_EQ("hello!hello!", out
.response_data
);
1241 helper
.VerifyDataConsumed();
1243 EXPECT_EQ(OK
, out
.rv
);
1246 // Similar to ThreeGetsWithMaxConcurrent above, however this test adds
1247 // a fourth transaction. The third and fourth transactions have
1248 // different data ("hello!" vs "hello!hello!") and because of the
1249 // user specified priority, we expect to see them inverted in
1250 // the response from the server.
1251 TEST_P(SpdyNetworkTransactionTest
, FourGetsWithMaxConcurrentPriority
) {
1252 // Construct the request.
1253 scoped_ptr
<SpdyFrame
> req(
1254 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
1255 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
1256 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, false));
1257 scoped_ptr
<SpdyFrame
> fbody(spdy_util_
.ConstructSpdyBodyFrame(1, true));
1259 scoped_ptr
<SpdyFrame
> req2(
1260 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 3, LOWEST
, true));
1261 scoped_ptr
<SpdyFrame
> resp2(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 3));
1262 scoped_ptr
<SpdyFrame
> body2(spdy_util_
.ConstructSpdyBodyFrame(3, false));
1263 scoped_ptr
<SpdyFrame
> fbody2(spdy_util_
.ConstructSpdyBodyFrame(3, true));
1265 scoped_ptr
<SpdyFrame
> req4(
1266 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 5, HIGHEST
, true));
1267 scoped_ptr
<SpdyFrame
> resp4(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 5));
1268 scoped_ptr
<SpdyFrame
> fbody4(spdy_util_
.ConstructSpdyBodyFrame(5, true));
1270 scoped_ptr
<SpdyFrame
> req3(
1271 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 7, LOWEST
, true));
1272 scoped_ptr
<SpdyFrame
> resp3(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 7));
1273 scoped_ptr
<SpdyFrame
> body3(spdy_util_
.ConstructSpdyBodyFrame(7, false));
1274 scoped_ptr
<SpdyFrame
> fbody3(spdy_util_
.ConstructSpdyBodyFrame(7, true));
1276 SettingsMap settings
;
1277 const uint32 max_concurrent_streams
= 1;
1278 settings
[SETTINGS_MAX_CONCURRENT_STREAMS
] =
1279 SettingsFlagsAndValue(SETTINGS_FLAG_NONE
, max_concurrent_streams
);
1280 scoped_ptr
<SpdyFrame
> settings_frame(
1281 spdy_util_
.ConstructSpdySettings(settings
));
1282 scoped_ptr
<SpdyFrame
> settings_ack(spdy_util_
.ConstructSpdySettingsAck());
1283 MockWrite writes
[] = {
1284 CreateMockWrite(*req
, 0),
1285 CreateMockWrite(*settings_ack
, 5),
1286 // By making these synchronous, it guarantees that they are not *started*
1287 // before their sequence number, which in turn verifies that only a single
1288 // request is in-flight at a time.
1289 CreateMockWrite(*req2
, 6, SYNCHRONOUS
),
1290 CreateMockWrite(*req4
, 10, SYNCHRONOUS
),
1291 CreateMockWrite(*req3
, 13, SYNCHRONOUS
),
1293 MockRead reads
[] = {
1294 CreateMockRead(*settings_frame
, 1),
1295 CreateMockRead(*resp
, 2),
1296 CreateMockRead(*body
, 3),
1297 CreateMockRead(*fbody
, 4),
1298 CreateMockRead(*resp2
, 7),
1299 CreateMockRead(*body2
, 8),
1300 CreateMockRead(*fbody2
, 9),
1301 CreateMockRead(*resp4
, 11),
1302 CreateMockRead(*fbody4
, 12),
1303 CreateMockRead(*resp3
, 14),
1304 CreateMockRead(*body3
, 15),
1305 CreateMockRead(*fbody3
, 16),
1307 MockRead(ASYNC
, 0, 17), // EOF
1309 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
1311 TransactionHelperResult out
;
1312 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
1313 BoundNetLog(), GetParam(), NULL
);
1314 helper
.RunPreTestSetup();
1315 helper
.AddData(&data
);
1317 scoped_ptr
<HttpNetworkTransaction
> trans1(
1318 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
1319 scoped_ptr
<HttpNetworkTransaction
> trans2(
1320 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
1321 scoped_ptr
<HttpNetworkTransaction
> trans3(
1322 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
1323 scoped_ptr
<HttpNetworkTransaction
> trans4(
1324 new HttpNetworkTransaction(HIGHEST
, helper
.session().get()));
1326 TestCompletionCallback callback1
;
1327 TestCompletionCallback callback2
;
1328 TestCompletionCallback callback3
;
1329 TestCompletionCallback callback4
;
1331 HttpRequestInfo httpreq1
= CreateGetRequest();
1332 HttpRequestInfo httpreq2
= CreateGetRequest();
1333 HttpRequestInfo httpreq3
= CreateGetRequest();
1334 HttpRequestInfo httpreq4
= CreateGetRequest();
1336 out
.rv
= trans1
->Start(&httpreq1
, callback1
.callback(), log
);
1337 ASSERT_EQ(ERR_IO_PENDING
, out
.rv
);
1338 // Run transaction 1 through quickly to force a read of our SETTINGS frame.
1339 out
.rv
= callback1
.WaitForResult();
1340 ASSERT_EQ(OK
, out
.rv
);
1342 out
.rv
= trans2
->Start(&httpreq2
, callback2
.callback(), log
);
1343 ASSERT_EQ(ERR_IO_PENDING
, out
.rv
);
1344 out
.rv
= trans3
->Start(&httpreq3
, callback3
.callback(), log
);
1345 ASSERT_EQ(ERR_IO_PENDING
, out
.rv
);
1346 out
.rv
= trans4
->Start(&httpreq4
, callback4
.callback(), log
);
1347 ASSERT_EQ(ERR_IO_PENDING
, out
.rv
);
1349 out
.rv
= callback2
.WaitForResult();
1350 ASSERT_EQ(OK
, out
.rv
);
1352 out
.rv
= callback3
.WaitForResult();
1353 ASSERT_EQ(OK
, out
.rv
);
1355 const HttpResponseInfo
* response1
= trans1
->GetResponseInfo();
1356 EXPECT_TRUE(response1
->headers
.get() != NULL
);
1357 EXPECT_TRUE(response1
->was_fetched_via_spdy
);
1358 out
.status_line
= response1
->headers
->GetStatusLine();
1359 out
.response_info
= *response1
;
1360 out
.rv
= ReadTransaction(trans1
.get(), &out
.response_data
);
1361 EXPECT_EQ(OK
, out
.rv
);
1362 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1363 EXPECT_EQ("hello!hello!", out
.response_data
);
1365 const HttpResponseInfo
* response2
= trans2
->GetResponseInfo();
1366 out
.status_line
= response2
->headers
->GetStatusLine();
1367 out
.response_info
= *response2
;
1368 out
.rv
= ReadTransaction(trans2
.get(), &out
.response_data
);
1369 EXPECT_EQ(OK
, out
.rv
);
1370 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1371 EXPECT_EQ("hello!hello!", out
.response_data
);
1373 // notice: response3 gets two hellos, response4 gets one
1374 // hello, so we know dequeuing priority was respected.
1375 const HttpResponseInfo
* response3
= trans3
->GetResponseInfo();
1376 out
.status_line
= response3
->headers
->GetStatusLine();
1377 out
.response_info
= *response3
;
1378 out
.rv
= ReadTransaction(trans3
.get(), &out
.response_data
);
1379 EXPECT_EQ(OK
, out
.rv
);
1380 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1381 EXPECT_EQ("hello!hello!", out
.response_data
);
1383 out
.rv
= callback4
.WaitForResult();
1384 EXPECT_EQ(OK
, out
.rv
);
1385 const HttpResponseInfo
* response4
= trans4
->GetResponseInfo();
1386 out
.status_line
= response4
->headers
->GetStatusLine();
1387 out
.response_info
= *response4
;
1388 out
.rv
= ReadTransaction(trans4
.get(), &out
.response_data
);
1389 EXPECT_EQ(OK
, out
.rv
);
1390 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1391 EXPECT_EQ("hello!", out
.response_data
);
1392 helper
.VerifyDataConsumed();
1393 EXPECT_EQ(OK
, out
.rv
);
1396 // Similar to ThreeGetsMaxConcurrrent above, however, this test
1397 // deletes a session in the middle of the transaction to ensure
1398 // that we properly remove pendingcreatestream objects from
1400 TEST_P(SpdyNetworkTransactionTest
, ThreeGetsWithMaxConcurrentDelete
) {
1401 // Construct the request.
1402 scoped_ptr
<SpdyFrame
> req(
1403 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
1404 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
1405 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, false));
1406 scoped_ptr
<SpdyFrame
> fbody(spdy_util_
.ConstructSpdyBodyFrame(1, true));
1408 scoped_ptr
<SpdyFrame
> req2(
1409 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 3, LOWEST
, true));
1410 scoped_ptr
<SpdyFrame
> resp2(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 3));
1411 scoped_ptr
<SpdyFrame
> body2(spdy_util_
.ConstructSpdyBodyFrame(3, false));
1412 scoped_ptr
<SpdyFrame
> fbody2(spdy_util_
.ConstructSpdyBodyFrame(3, true));
1414 SettingsMap settings
;
1415 const uint32 max_concurrent_streams
= 1;
1416 settings
[SETTINGS_MAX_CONCURRENT_STREAMS
] =
1417 SettingsFlagsAndValue(SETTINGS_FLAG_NONE
, max_concurrent_streams
);
1418 scoped_ptr
<SpdyFrame
> settings_frame(
1419 spdy_util_
.ConstructSpdySettings(settings
));
1420 scoped_ptr
<SpdyFrame
> settings_ack(spdy_util_
.ConstructSpdySettingsAck());
1422 MockWrite writes
[] = {
1423 CreateMockWrite(*req
, 0),
1424 CreateMockWrite(*settings_ack
, 5),
1425 CreateMockWrite(*req2
, 6),
1427 MockRead reads
[] = {
1428 CreateMockRead(*settings_frame
, 1),
1429 CreateMockRead(*resp
, 2),
1430 CreateMockRead(*body
, 3),
1431 CreateMockRead(*fbody
, 4),
1432 CreateMockRead(*resp2
, 7),
1433 CreateMockRead(*body2
, 8),
1434 CreateMockRead(*fbody2
, 9),
1435 MockRead(ASYNC
, 0, 10), // EOF
1438 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
1441 TransactionHelperResult out
;
1442 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
1443 BoundNetLog(), GetParam(), NULL
);
1444 helper
.RunPreTestSetup();
1445 helper
.AddData(&data
);
1446 scoped_ptr
<HttpNetworkTransaction
> trans1(
1447 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
1448 scoped_ptr
<HttpNetworkTransaction
> trans2(
1449 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
1450 scoped_ptr
<HttpNetworkTransaction
> trans3(
1451 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
1453 TestCompletionCallback callback1
;
1454 TestCompletionCallback callback2
;
1455 TestCompletionCallback callback3
;
1457 HttpRequestInfo httpreq1
= CreateGetRequest();
1458 HttpRequestInfo httpreq2
= CreateGetRequest();
1459 HttpRequestInfo httpreq3
= CreateGetRequest();
1461 out
.rv
= trans1
->Start(&httpreq1
, callback1
.callback(), log
);
1462 ASSERT_EQ(out
.rv
, ERR_IO_PENDING
);
1463 // Run transaction 1 through quickly to force a read of our SETTINGS frame.
1464 out
.rv
= callback1
.WaitForResult();
1465 ASSERT_EQ(OK
, out
.rv
);
1467 out
.rv
= trans2
->Start(&httpreq2
, callback2
.callback(), log
);
1468 ASSERT_EQ(out
.rv
, ERR_IO_PENDING
);
1469 out
.rv
= trans3
->Start(&httpreq3
, callback3
.callback(), log
);
1470 delete trans3
.release();
1471 ASSERT_EQ(out
.rv
, ERR_IO_PENDING
);
1472 out
.rv
= callback2
.WaitForResult();
1473 ASSERT_EQ(OK
, out
.rv
);
1475 const HttpResponseInfo
* response1
= trans1
->GetResponseInfo();
1476 ASSERT_TRUE(response1
!= NULL
);
1477 EXPECT_TRUE(response1
->headers
.get() != NULL
);
1478 EXPECT_TRUE(response1
->was_fetched_via_spdy
);
1479 out
.status_line
= response1
->headers
->GetStatusLine();
1480 out
.response_info
= *response1
;
1481 out
.rv
= ReadTransaction(trans1
.get(), &out
.response_data
);
1482 EXPECT_EQ(OK
, out
.rv
);
1483 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1484 EXPECT_EQ("hello!hello!", out
.response_data
);
1486 const HttpResponseInfo
* response2
= trans2
->GetResponseInfo();
1487 ASSERT_TRUE(response2
!= NULL
);
1488 out
.status_line
= response2
->headers
->GetStatusLine();
1489 out
.response_info
= *response2
;
1490 out
.rv
= ReadTransaction(trans2
.get(), &out
.response_data
);
1491 EXPECT_EQ(OK
, out
.rv
);
1492 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1493 EXPECT_EQ("hello!hello!", out
.response_data
);
1494 helper
.VerifyDataConsumed();
1495 EXPECT_EQ(OK
, out
.rv
);
1500 // The KillerCallback will delete the transaction on error as part of the
1502 class KillerCallback
: public TestCompletionCallbackBase
{
1504 explicit KillerCallback(HttpNetworkTransaction
* transaction
)
1505 : transaction_(transaction
),
1506 callback_(base::Bind(&KillerCallback::OnComplete
,
1507 base::Unretained(this))) {
1510 ~KillerCallback() override
{}
1512 const CompletionCallback
& callback() const { return callback_
; }
1515 void OnComplete(int result
) {
1517 delete transaction_
;
1522 HttpNetworkTransaction
* transaction_
;
1523 CompletionCallback callback_
;
1528 // Similar to ThreeGetsMaxConcurrrentDelete above, however, this test
1529 // closes the socket while we have a pending transaction waiting for
1530 // a pending stream creation. http://crbug.com/52901
1531 TEST_P(SpdyNetworkTransactionTest
, ThreeGetsWithMaxConcurrentSocketClose
) {
1532 // Construct the request.
1533 scoped_ptr
<SpdyFrame
> req(
1534 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
1535 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
1536 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, false));
1537 scoped_ptr
<SpdyFrame
> fin_body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
1539 scoped_ptr
<SpdyFrame
> req2(
1540 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 3, LOWEST
, true));
1541 scoped_ptr
<SpdyFrame
> resp2(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 3));
1543 SettingsMap settings
;
1544 const uint32 max_concurrent_streams
= 1;
1545 settings
[SETTINGS_MAX_CONCURRENT_STREAMS
] =
1546 SettingsFlagsAndValue(SETTINGS_FLAG_NONE
, max_concurrent_streams
);
1547 scoped_ptr
<SpdyFrame
> settings_frame(
1548 spdy_util_
.ConstructSpdySettings(settings
));
1549 scoped_ptr
<SpdyFrame
> settings_ack(spdy_util_
.ConstructSpdySettingsAck());
1551 MockWrite writes
[] = {
1552 CreateMockWrite(*req
, 0),
1553 CreateMockWrite(*settings_ack
, 5),
1554 CreateMockWrite(*req2
, 6),
1556 MockRead reads
[] = {
1557 CreateMockRead(*settings_frame
, 1),
1558 CreateMockRead(*resp
, 2),
1559 CreateMockRead(*body
, 3),
1560 CreateMockRead(*fin_body
, 4),
1561 CreateMockRead(*resp2
, 7),
1562 MockRead(ASYNC
, ERR_CONNECTION_RESET
, 8), // Abort!
1565 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
1566 SequencedSocketData
data_placeholder(NULL
, 0, NULL
, 0);
1569 TransactionHelperResult out
;
1570 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
1571 BoundNetLog(), GetParam(), NULL
);
1572 helper
.RunPreTestSetup();
1573 helper
.AddData(&data
);
1574 // We require placeholder data because three get requests are sent out, so
1575 // there needs to be three sets of SSL connection data.
1576 helper
.AddData(&data_placeholder
);
1577 helper
.AddData(&data_placeholder
);
1578 HttpNetworkTransaction
trans1(DEFAULT_PRIORITY
, helper
.session().get());
1579 HttpNetworkTransaction
trans2(DEFAULT_PRIORITY
, helper
.session().get());
1580 HttpNetworkTransaction
* trans3(
1581 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
1583 TestCompletionCallback callback1
;
1584 TestCompletionCallback callback2
;
1585 KillerCallback
callback3(trans3
);
1587 HttpRequestInfo httpreq1
= CreateGetRequest();
1588 HttpRequestInfo httpreq2
= CreateGetRequest();
1589 HttpRequestInfo httpreq3
= CreateGetRequest();
1591 out
.rv
= trans1
.Start(&httpreq1
, callback1
.callback(), log
);
1592 ASSERT_EQ(out
.rv
, ERR_IO_PENDING
);
1593 // Run transaction 1 through quickly to force a read of our SETTINGS frame.
1594 out
.rv
= callback1
.WaitForResult();
1595 ASSERT_EQ(OK
, out
.rv
);
1597 out
.rv
= trans2
.Start(&httpreq2
, callback2
.callback(), log
);
1598 ASSERT_EQ(out
.rv
, ERR_IO_PENDING
);
1599 out
.rv
= trans3
->Start(&httpreq3
, callback3
.callback(), log
);
1600 ASSERT_EQ(out
.rv
, ERR_IO_PENDING
);
1601 out
.rv
= callback3
.WaitForResult();
1602 ASSERT_EQ(ERR_ABORTED
, out
.rv
);
1604 const HttpResponseInfo
* response1
= trans1
.GetResponseInfo();
1605 ASSERT_TRUE(response1
!= NULL
);
1606 EXPECT_TRUE(response1
->headers
.get() != NULL
);
1607 EXPECT_TRUE(response1
->was_fetched_via_spdy
);
1608 out
.status_line
= response1
->headers
->GetStatusLine();
1609 out
.response_info
= *response1
;
1610 out
.rv
= ReadTransaction(&trans1
, &out
.response_data
);
1611 EXPECT_EQ(OK
, out
.rv
);
1613 const HttpResponseInfo
* response2
= trans2
.GetResponseInfo();
1614 ASSERT_TRUE(response2
!= NULL
);
1615 out
.status_line
= response2
->headers
->GetStatusLine();
1616 out
.response_info
= *response2
;
1617 out
.rv
= ReadTransaction(&trans2
, &out
.response_data
);
1618 EXPECT_EQ(ERR_CONNECTION_RESET
, out
.rv
);
1620 helper
.VerifyDataConsumed();
1623 // Test that a simple PUT request works.
1624 TEST_P(SpdyNetworkTransactionTest
, Put
) {
1625 // Setup the request
1626 HttpRequestInfo request
;
1627 request
.method
= "PUT";
1628 request
.url
= GURL(GetDefaultUrl());
1630 scoped_ptr
<SpdyHeaderBlock
> put_headers(
1631 spdy_util_
.ConstructPutHeaderBlock(GetDefaultUrl(), 0));
1632 scoped_ptr
<SpdyFrame
> req(
1633 spdy_util_
.ConstructSpdySyn(1, *put_headers
, LOWEST
, false, true));
1634 MockWrite writes
[] = {
1635 CreateMockWrite(*req
, 0),
1638 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
1639 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
1640 MockRead reads
[] = {
1641 CreateMockRead(*resp
, 1),
1642 CreateMockRead(*body
, 2),
1643 MockRead(ASYNC
, 0, 3) // EOF
1646 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
1647 NormalSpdyTransactionHelper
helper(request
, DEFAULT_PRIORITY
,
1648 BoundNetLog(), GetParam(), NULL
);
1649 helper
.RunToCompletion(&data
);
1650 TransactionHelperResult out
= helper
.output();
1652 EXPECT_EQ(OK
, out
.rv
);
1653 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1656 // Test that a simple HEAD request works.
1657 TEST_P(SpdyNetworkTransactionTest
, Head
) {
1658 // Setup the request
1659 HttpRequestInfo request
;
1660 request
.method
= "HEAD";
1661 request
.url
= GURL(GetDefaultUrl());
1663 scoped_ptr
<SpdyHeaderBlock
> head_headers(
1664 spdy_util_
.ConstructHeadHeaderBlock(GetDefaultUrl(), 0));
1665 scoped_ptr
<SpdyFrame
> req(
1666 spdy_util_
.ConstructSpdySyn(1, *head_headers
, LOWEST
, false, true));
1667 MockWrite writes
[] = {
1668 CreateMockWrite(*req
, 0),
1671 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
1672 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
1673 MockRead reads
[] = {
1674 CreateMockRead(*resp
, 1),
1675 CreateMockRead(*body
, 2),
1676 MockRead(ASYNC
, 0, 3) // EOF
1679 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
1680 NormalSpdyTransactionHelper
helper(request
, DEFAULT_PRIORITY
,
1681 BoundNetLog(), GetParam(), NULL
);
1682 helper
.RunToCompletion(&data
);
1683 TransactionHelperResult out
= helper
.output();
1685 EXPECT_EQ(OK
, out
.rv
);
1686 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1689 // Test that a simple POST works.
1690 TEST_P(SpdyNetworkTransactionTest
, Post
) {
1691 scoped_ptr
<SpdyFrame
> req(spdy_util_
.ConstructSpdyPost(
1692 GetDefaultUrl(), 1, kUploadDataSize
, LOWEST
, NULL
, 0));
1693 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
1694 MockWrite writes
[] = {
1695 CreateMockWrite(*req
, 0), CreateMockWrite(*body
, 1), // POST upload frame
1698 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyPostSynReply(NULL
, 0));
1699 MockRead reads
[] = {
1700 CreateMockRead(*resp
, 2),
1701 CreateMockRead(*body
, 3),
1702 MockRead(ASYNC
, 0, 4) // EOF
1705 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
1706 NormalSpdyTransactionHelper
helper(CreatePostRequest(), DEFAULT_PRIORITY
,
1707 BoundNetLog(), GetParam(), NULL
);
1708 helper
.RunToCompletion(&data
);
1709 TransactionHelperResult out
= helper
.output();
1710 EXPECT_EQ(OK
, out
.rv
);
1711 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1712 EXPECT_EQ("hello!", out
.response_data
);
1715 // Test that a POST with a file works.
1716 TEST_P(SpdyNetworkTransactionTest
, FilePost
) {
1717 scoped_ptr
<SpdyFrame
> req(spdy_util_
.ConstructSpdyPost(
1718 GetDefaultUrl(), 1, kUploadDataSize
, LOWEST
, NULL
, 0));
1719 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
1720 MockWrite writes
[] = {
1721 CreateMockWrite(*req
, 0), CreateMockWrite(*body
, 1), // POST upload frame
1724 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyPostSynReply(NULL
, 0));
1725 MockRead reads
[] = {
1726 CreateMockRead(*resp
, 2),
1727 CreateMockRead(*body
, 3),
1728 MockRead(ASYNC
, 0, 4) // EOF
1731 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
1732 NormalSpdyTransactionHelper
helper(CreateFilePostRequest(), DEFAULT_PRIORITY
,
1733 BoundNetLog(), GetParam(), NULL
);
1734 helper
.RunToCompletion(&data
);
1735 TransactionHelperResult out
= helper
.output();
1736 EXPECT_EQ(OK
, out
.rv
);
1737 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1738 EXPECT_EQ("hello!", out
.response_data
);
1741 // Test that a POST with a unreadable file fails.
1742 TEST_P(SpdyNetworkTransactionTest
, UnreadableFilePost
) {
1743 MockWrite writes
[] = {
1744 MockWrite(ASYNC
, 0, 0) // EOF
1746 MockRead reads
[] = {
1747 MockRead(ASYNC
, 0, 1) // EOF
1750 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
1751 NormalSpdyTransactionHelper
helper(CreateUnreadableFilePostRequest(),
1753 BoundNetLog(), GetParam(), NULL
);
1754 helper
.RunPreTestSetup();
1755 helper
.AddData(&data
);
1756 helper
.RunDefaultTest();
1758 base::RunLoop().RunUntilIdle();
1759 helper
.VerifyDataNotConsumed();
1760 EXPECT_EQ(ERR_ACCESS_DENIED
, helper
.output().rv
);
1763 // Test that a complex POST works.
1764 TEST_P(SpdyNetworkTransactionTest
, ComplexPost
) {
1765 scoped_ptr
<SpdyFrame
> req(spdy_util_
.ConstructSpdyPost(
1766 GetDefaultUrl(), 1, kUploadDataSize
, LOWEST
, NULL
, 0));
1767 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
1768 MockWrite writes
[] = {
1769 CreateMockWrite(*req
, 0), CreateMockWrite(*body
, 1), // POST upload frame
1772 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyPostSynReply(NULL
, 0));
1773 MockRead reads
[] = {
1774 CreateMockRead(*resp
, 2),
1775 CreateMockRead(*body
, 3),
1776 MockRead(ASYNC
, 0, 4) // EOF
1779 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
1780 NormalSpdyTransactionHelper
helper(CreateComplexPostRequest(),
1782 BoundNetLog(), GetParam(), NULL
);
1783 helper
.RunToCompletion(&data
);
1784 TransactionHelperResult out
= helper
.output();
1785 EXPECT_EQ(OK
, out
.rv
);
1786 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1787 EXPECT_EQ("hello!", out
.response_data
);
1790 // Test that a chunked POST works.
1791 TEST_P(SpdyNetworkTransactionTest
, ChunkedPost
) {
1792 scoped_ptr
<SpdyFrame
> req(spdy_util_
.ConstructChunkedSpdyPost(NULL
, 0));
1793 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
1794 MockWrite writes
[] = {
1795 CreateMockWrite(*req
, 0), CreateMockWrite(*body
, 1),
1798 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyPostSynReply(NULL
, 0));
1799 MockRead reads
[] = {
1800 CreateMockRead(*resp
, 2),
1801 CreateMockRead(*body
, 3),
1802 MockRead(ASYNC
, 0, 4) // EOF
1805 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
1806 NormalSpdyTransactionHelper
helper(CreateChunkedPostRequest(),
1808 BoundNetLog(), GetParam(), NULL
);
1810 // These chunks get merged into a single frame when being sent.
1811 const int kFirstChunkSize
= kUploadDataSize
/2;
1812 upload_chunked_data_stream()->AppendData(kUploadData
, kFirstChunkSize
, false);
1813 upload_chunked_data_stream()->AppendData(
1814 kUploadData
+ kFirstChunkSize
, kUploadDataSize
- kFirstChunkSize
, true);
1816 helper
.RunToCompletion(&data
);
1817 TransactionHelperResult out
= helper
.output();
1818 EXPECT_EQ(OK
, out
.rv
);
1819 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1820 EXPECT_EQ(kUploadData
, out
.response_data
);
1823 // Test that a chunked POST works with chunks appended after transaction starts.
1824 TEST_P(SpdyNetworkTransactionTest
, DelayedChunkedPost
) {
1825 scoped_ptr
<SpdyFrame
> req(spdy_util_
.ConstructChunkedSpdyPost(NULL
, 0));
1826 scoped_ptr
<SpdyFrame
> chunk1(spdy_util_
.ConstructSpdyBodyFrame(1, false));
1827 scoped_ptr
<SpdyFrame
> chunk2(spdy_util_
.ConstructSpdyBodyFrame(1, false));
1828 scoped_ptr
<SpdyFrame
> chunk3(spdy_util_
.ConstructSpdyBodyFrame(1, true));
1829 MockWrite writes
[] = {
1830 CreateMockWrite(*req
, 0),
1831 CreateMockWrite(*chunk1
, 1),
1832 CreateMockWrite(*chunk2
, 2),
1833 CreateMockWrite(*chunk3
, 3),
1836 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyPostSynReply(NULL
, 0));
1837 MockRead reads
[] = {
1838 CreateMockRead(*resp
, 4),
1839 CreateMockRead(*chunk1
, 5),
1840 CreateMockRead(*chunk2
, 6),
1841 CreateMockRead(*chunk3
, 7),
1842 MockRead(ASYNC
, 0, 8) // EOF
1845 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
1846 NormalSpdyTransactionHelper
helper(CreateChunkedPostRequest(),
1848 BoundNetLog(), GetParam(), NULL
);
1850 upload_chunked_data_stream()->AppendData(kUploadData
, kUploadDataSize
, false);
1852 helper
.RunPreTestSetup();
1853 helper
.AddData(&data
);
1854 ASSERT_TRUE(helper
.StartDefaultTest());
1856 base::RunLoop().RunUntilIdle();
1857 upload_chunked_data_stream()->AppendData(kUploadData
, kUploadDataSize
, false);
1858 base::RunLoop().RunUntilIdle();
1859 upload_chunked_data_stream()->AppendData(kUploadData
, kUploadDataSize
, true);
1861 helper
.FinishDefaultTest();
1862 helper
.VerifyDataConsumed();
1864 std::string expected_response
;
1865 expected_response
+= kUploadData
;
1866 expected_response
+= kUploadData
;
1867 expected_response
+= kUploadData
;
1869 TransactionHelperResult out
= helper
.output();
1870 EXPECT_EQ(OK
, out
.rv
);
1871 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1872 EXPECT_EQ(expected_response
, out
.response_data
);
1875 // Test that a POST without any post data works.
1876 TEST_P(SpdyNetworkTransactionTest
, NullPost
) {
1877 BufferedSpdyFramer
framer(spdy_util_
.spdy_version(), false);
1878 // Setup the request
1879 HttpRequestInfo request
;
1880 request
.method
= "POST";
1881 request
.url
= GURL(GetDefaultUrl());
1882 // Create an empty UploadData.
1883 request
.upload_data_stream
= NULL
;
1885 // When request.upload_data_stream is NULL for post, content-length is
1886 // expected to be 0.
1887 scoped_ptr
<SpdyHeaderBlock
> req_block(
1888 spdy_util_
.ConstructPostHeaderBlock(GetDefaultUrl(), 0));
1889 scoped_ptr
<SpdyFrame
> req(
1890 spdy_util_
.ConstructSpdySyn(1, *req_block
, LOWEST
, false, true));
1892 MockWrite writes
[] = {
1893 CreateMockWrite(*req
, 0),
1896 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyPostSynReply(NULL
, 0));
1897 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
1898 MockRead reads
[] = {
1899 CreateMockRead(*resp
, 1),
1900 CreateMockRead(*body
, 2),
1901 MockRead(ASYNC
, 0, 3) // EOF
1904 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
1906 NormalSpdyTransactionHelper
helper(request
, DEFAULT_PRIORITY
,
1907 BoundNetLog(), GetParam(), NULL
);
1908 helper
.RunToCompletion(&data
);
1909 TransactionHelperResult out
= helper
.output();
1910 EXPECT_EQ(OK
, out
.rv
);
1911 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1912 EXPECT_EQ("hello!", out
.response_data
);
1915 // Test that a simple POST works.
1916 TEST_P(SpdyNetworkTransactionTest
, EmptyPost
) {
1917 BufferedSpdyFramer
framer(spdy_util_
.spdy_version(), false);
1918 // Create an empty UploadDataStream.
1919 ScopedVector
<UploadElementReader
> element_readers
;
1920 ElementsUploadDataStream
stream(element_readers
.Pass(), 0);
1922 // Setup the request
1923 HttpRequestInfo request
;
1924 request
.method
= "POST";
1925 request
.url
= GURL(GetDefaultUrl());
1926 request
.upload_data_stream
= &stream
;
1928 const uint64 kContentLength
= 0;
1930 scoped_ptr
<SpdyHeaderBlock
> req_block(
1931 spdy_util_
.ConstructPostHeaderBlock(GetDefaultUrl(), kContentLength
));
1932 scoped_ptr
<SpdyFrame
> req(
1933 spdy_util_
.ConstructSpdySyn(1, *req_block
, LOWEST
, false, true));
1935 MockWrite writes
[] = {
1936 CreateMockWrite(*req
, 0),
1939 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyPostSynReply(NULL
, 0));
1940 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
1941 MockRead reads
[] = {
1942 CreateMockRead(*resp
, 1),
1943 CreateMockRead(*body
, 2),
1944 MockRead(ASYNC
, 0, 3) // EOF
1947 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
1949 NormalSpdyTransactionHelper
helper(request
, DEFAULT_PRIORITY
,
1950 BoundNetLog(), GetParam(), NULL
);
1951 helper
.RunToCompletion(&data
);
1952 TransactionHelperResult out
= helper
.output();
1953 EXPECT_EQ(OK
, out
.rv
);
1954 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1955 EXPECT_EQ("hello!", out
.response_data
);
1958 // While we're doing a post, the server sends the reply before upload completes.
1959 TEST_P(SpdyNetworkTransactionTest
, ResponseBeforePostCompletes
) {
1960 scoped_ptr
<SpdyFrame
> req(spdy_util_
.ConstructChunkedSpdyPost(NULL
, 0));
1961 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
1962 MockWrite writes
[] = {
1963 CreateMockWrite(*req
, 0),
1964 CreateMockWrite(*body
, 3),
1966 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyPostSynReply(NULL
, 0));
1967 MockRead reads
[] = {
1968 CreateMockRead(*resp
, 1),
1969 CreateMockRead(*body
, 2),
1970 MockRead(ASYNC
, 0, 4) // EOF
1973 // Write the request headers, and read the complete response
1974 // while still waiting for chunked request data.
1975 DeterministicSocketData
data(reads
, arraysize(reads
),
1976 writes
, arraysize(writes
));
1977 NormalSpdyTransactionHelper
helper(CreateChunkedPostRequest(),
1979 BoundNetLog(), GetParam(), NULL
);
1980 helper
.SetDeterministic();
1981 helper
.RunPreTestSetup();
1982 helper
.AddDeterministicData(&data
);
1984 ASSERT_TRUE(helper
.StartDefaultTest());
1986 // Process the request headers, SYN_REPLY, and response body.
1987 // The request body is still in flight.
1990 const HttpResponseInfo
* response
= helper
.trans()->GetResponseInfo();
1991 EXPECT_EQ("HTTP/1.1 200 OK", response
->headers
->GetStatusLine());
1993 // Finish sending the request body.
1994 upload_chunked_data_stream()->AppendData(kUploadData
, kUploadDataSize
, true);
1997 std::string response_body
;
1998 EXPECT_EQ(OK
, ReadTransaction(helper
.trans(), &response_body
));
1999 EXPECT_EQ(kUploadData
, response_body
);
2000 helper
.VerifyDataConsumed();
2003 // The client upon cancellation tries to send a RST_STREAM frame. The mock
2004 // socket causes the TCP write to return zero. This test checks that the client
2005 // tries to queue up the RST_STREAM frame again.
2006 TEST_P(SpdyNetworkTransactionTest
, SocketWriteReturnsZero
) {
2007 scoped_ptr
<SpdyFrame
> req(
2008 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2009 scoped_ptr
<SpdyFrame
> rst(
2010 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_CANCEL
));
2011 MockWrite writes
[] = {
2012 CreateMockWrite(*req
.get(), 0, SYNCHRONOUS
),
2013 MockWrite(SYNCHRONOUS
, 0, 0, 2),
2014 CreateMockWrite(*rst
.get(), 3, SYNCHRONOUS
),
2017 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2018 MockRead reads
[] = {
2019 CreateMockRead(*resp
.get(), 1, ASYNC
),
2020 MockRead(ASYNC
, 0, 0, 4) // EOF
2023 DeterministicSocketData
data(reads
, arraysize(reads
),
2024 writes
, arraysize(writes
));
2025 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
2026 BoundNetLog(), GetParam(), NULL
);
2027 helper
.SetDeterministic();
2028 helper
.RunPreTestSetup();
2029 helper
.AddDeterministicData(&data
);
2030 HttpNetworkTransaction
* trans
= helper
.trans();
2032 TestCompletionCallback callback
;
2033 int rv
= trans
->Start(
2034 &CreateGetRequest(), callback
.callback(), BoundNetLog());
2035 EXPECT_EQ(ERR_IO_PENDING
, rv
);
2039 helper
.ResetTrans();
2043 helper
.VerifyDataConsumed();
2046 // Test that the transaction doesn't crash when we don't have a reply.
2047 TEST_P(SpdyNetworkTransactionTest
, ResponseWithoutSynReply
) {
2048 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
2049 MockRead reads
[] = {
2050 CreateMockRead(*body
, 1), MockRead(ASYNC
, 0, 3) // EOF
2053 scoped_ptr
<SpdyFrame
> req(
2054 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2055 scoped_ptr
<SpdyFrame
> rst(
2056 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR
));
2057 MockWrite writes
[] = {
2058 CreateMockWrite(*req
, 0), CreateMockWrite(*rst
, 2),
2060 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
2061 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
2062 BoundNetLog(), GetParam(), NULL
);
2063 helper
.RunToCompletion(&data
);
2064 TransactionHelperResult out
= helper
.output();
2065 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR
, out
.rv
);
2068 // Test that the transaction doesn't crash when we get two replies on the same
2069 // stream ID. See http://crbug.com/45639.
2070 TEST_P(SpdyNetworkTransactionTest
, ResponseWithTwoSynReplies
) {
2071 scoped_ptr
<SpdyFrame
> req(
2072 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2073 scoped_ptr
<SpdyFrame
> rst(
2074 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR
));
2075 MockWrite writes
[] = {
2076 CreateMockWrite(*req
, 0), CreateMockWrite(*rst
, 4),
2079 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2080 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
2081 MockRead reads
[] = {
2082 CreateMockRead(*resp
, 1),
2083 CreateMockRead(*resp
, 2),
2084 CreateMockRead(*body
, 3),
2085 MockRead(ASYNC
, 0, 5) // EOF
2088 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
2090 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
2091 BoundNetLog(), GetParam(), NULL
);
2092 helper
.RunPreTestSetup();
2093 helper
.AddData(&data
);
2095 HttpNetworkTransaction
* trans
= helper
.trans();
2097 TestCompletionCallback callback
;
2098 int rv
= trans
->Start(&helper
.request(), callback
.callback(), BoundNetLog());
2099 EXPECT_EQ(ERR_IO_PENDING
, rv
);
2100 rv
= callback
.WaitForResult();
2103 const HttpResponseInfo
* response
= trans
->GetResponseInfo();
2104 ASSERT_TRUE(response
!= NULL
);
2105 EXPECT_TRUE(response
->headers
.get() != NULL
);
2106 EXPECT_TRUE(response
->was_fetched_via_spdy
);
2107 std::string response_data
;
2108 rv
= ReadTransaction(trans
, &response_data
);
2109 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR
, rv
);
2111 helper
.VerifyDataConsumed();
2114 TEST_P(SpdyNetworkTransactionTest
, ResetReplyWithTransferEncoding
) {
2115 // Construct the request.
2116 scoped_ptr
<SpdyFrame
> req(
2117 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2118 scoped_ptr
<SpdyFrame
> rst(
2119 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR
));
2120 MockWrite writes
[] = {
2121 CreateMockWrite(*req
, 0), CreateMockWrite(*rst
, 2),
2124 const char* const headers
[] = {
2125 "transfer-encoding", "chunked"
2127 scoped_ptr
<SpdyFrame
> resp(
2128 spdy_util_
.ConstructSpdyGetSynReply(headers
, 1, 1));
2129 scoped_ptr
<SpdyFrame
> body(
2130 spdy_util_
.ConstructSpdyBodyFrame(1, true));
2131 MockRead reads
[] = {
2132 CreateMockRead(*resp
, 1),
2133 CreateMockRead(*body
, 3),
2134 MockRead(ASYNC
, 0, 4) // EOF
2137 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
2138 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
2139 BoundNetLog(), GetParam(), NULL
);
2140 helper
.RunToCompletion(&data
);
2141 TransactionHelperResult out
= helper
.output();
2142 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR
, out
.rv
);
2144 helper
.session()->spdy_session_pool()->CloseAllSessions();
2145 helper
.VerifyDataConsumed();
2148 TEST_P(SpdyNetworkTransactionTest
, ResetPushWithTransferEncoding
) {
2149 // Construct the request.
2150 scoped_ptr
<SpdyFrame
> req(
2151 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2152 scoped_ptr
<SpdyFrame
> rst(
2153 spdy_util_
.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR
));
2154 MockWrite writes
[] = {
2155 CreateMockWrite(*req
, 0), CreateMockWrite(*rst
, 4),
2158 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2159 const char* const headers
[] = {
2160 "transfer-encoding", "chunked"
2162 scoped_ptr
<SpdyFrame
> push(
2163 spdy_util_
.ConstructSpdyPush(headers
, arraysize(headers
) / 2, 2, 1,
2164 GetDefaultUrlWithPath("/1").c_str()));
2165 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
2166 MockRead reads
[] = {
2167 CreateMockRead(*resp
, 1),
2168 CreateMockRead(*push
, 2),
2169 CreateMockRead(*body
, 3),
2170 MockRead(ASYNC
, 0, 5) // EOF
2173 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
2174 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
2175 BoundNetLog(), GetParam(), NULL
);
2176 helper
.RunToCompletion(&data
);
2177 TransactionHelperResult out
= helper
.output();
2178 EXPECT_EQ(OK
, out
.rv
);
2179 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
2180 EXPECT_EQ("hello!", out
.response_data
);
2182 helper
.session()->spdy_session_pool()->CloseAllSessions();
2183 helper
.VerifyDataConsumed();
2186 TEST_P(SpdyNetworkTransactionTest
, CancelledTransaction
) {
2187 // Construct the request.
2188 scoped_ptr
<SpdyFrame
> req(
2189 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2190 MockWrite writes
[] = {
2191 CreateMockWrite(*req
),
2194 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2195 MockRead reads
[] = {
2196 CreateMockRead(*resp
),
2197 // This following read isn't used by the test, except during the
2198 // RunUntilIdle() call at the end since the SpdySession survives the
2199 // HttpNetworkTransaction and still tries to continue Read()'ing. Any
2200 // MockRead will do here.
2201 MockRead(ASYNC
, 0, 0) // EOF
2204 StaticSocketDataProvider
data(reads
, arraysize(reads
),
2205 writes
, arraysize(writes
));
2207 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
2208 BoundNetLog(), GetParam(), NULL
);
2209 helper
.RunPreTestSetup();
2210 helper
.AddData(&data
);
2211 HttpNetworkTransaction
* trans
= helper
.trans();
2213 TestCompletionCallback callback
;
2214 int rv
= trans
->Start(
2215 &CreateGetRequest(), callback
.callback(), BoundNetLog());
2216 EXPECT_EQ(ERR_IO_PENDING
, rv
);
2217 helper
.ResetTrans(); // Cancel the transaction.
2219 // Flush the MessageLoop while the SpdySessionDependencies (in particular, the
2220 // MockClientSocketFactory) are still alive.
2221 base::RunLoop().RunUntilIdle();
2222 helper
.VerifyDataNotConsumed();
2225 // Verify that the client sends a Rst Frame upon cancelling the stream.
2226 TEST_P(SpdyNetworkTransactionTest
, CancelledTransactionSendRst
) {
2227 scoped_ptr
<SpdyFrame
> req(
2228 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2229 scoped_ptr
<SpdyFrame
> rst(
2230 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_CANCEL
));
2231 MockWrite writes
[] = {
2232 CreateMockWrite(*req
, 0, SYNCHRONOUS
),
2233 CreateMockWrite(*rst
, 2, SYNCHRONOUS
),
2236 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2237 MockRead reads
[] = {
2238 CreateMockRead(*resp
, 1, ASYNC
),
2239 MockRead(ASYNC
, 0, 0, 3) // EOF
2242 DeterministicSocketData
data(reads
, arraysize(reads
),
2243 writes
, arraysize(writes
));
2245 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
2248 helper
.SetDeterministic();
2249 helper
.RunPreTestSetup();
2250 helper
.AddDeterministicData(&data
);
2251 HttpNetworkTransaction
* trans
= helper
.trans();
2253 TestCompletionCallback callback
;
2255 int rv
= trans
->Start(
2256 &CreateGetRequest(), callback
.callback(), BoundNetLog());
2257 EXPECT_EQ(ERR_IO_PENDING
, rv
);
2261 helper
.ResetTrans();
2265 helper
.VerifyDataConsumed();
2268 // Verify that the client can correctly deal with the user callback attempting
2269 // to start another transaction on a session that is closing down. See
2270 // http://crbug.com/47455
2271 TEST_P(SpdyNetworkTransactionTest
, StartTransactionOnReadCallback
) {
2272 scoped_ptr
<SpdyFrame
> req(
2273 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2274 MockWrite writes
[] = {CreateMockWrite(*req
)};
2275 MockWrite writes2
[] = {CreateMockWrite(*req
, 0)};
2277 // The indicated length of this frame is longer than its actual length. When
2278 // the session receives an empty frame after this one, it shuts down the
2279 // session, and calls the read callback with the incomplete data.
2280 const uint8 kGetBodyFrame2
[] = {
2281 0x00, 0x00, 0x00, 0x01,
2282 0x01, 0x00, 0x00, 0x07,
2283 'h', 'e', 'l', 'l', 'o', '!',
2286 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2287 MockRead reads
[] = {
2288 CreateMockRead(*resp
, 2),
2289 MockRead(ASYNC
, ERR_IO_PENDING
, 3), // Force a pause
2290 MockRead(ASYNC
, reinterpret_cast<const char*>(kGetBodyFrame2
),
2291 arraysize(kGetBodyFrame2
), 4),
2292 MockRead(ASYNC
, ERR_IO_PENDING
, 5), // Force a pause
2293 MockRead(ASYNC
, 0, 0, 6), // EOF
2295 MockRead reads2
[] = {
2296 CreateMockRead(*resp
, 1), MockRead(ASYNC
, 0, 0, 2), // EOF
2299 OrderedSocketData
data(reads
, arraysize(reads
),
2300 writes
, arraysize(writes
));
2301 SequencedSocketData
data2(reads2
, arraysize(reads2
), writes2
,
2302 arraysize(writes2
));
2304 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
2305 BoundNetLog(), GetParam(), NULL
);
2306 helper
.RunPreTestSetup();
2307 helper
.AddData(&data
);
2308 helper
.AddData(&data2
);
2309 HttpNetworkTransaction
* trans
= helper
.trans();
2311 // Start the transaction with basic parameters.
2312 TestCompletionCallback callback
;
2313 int rv
= trans
->Start(&helper
.request(), callback
.callback(), BoundNetLog());
2314 EXPECT_EQ(ERR_IO_PENDING
, rv
);
2315 rv
= callback
.WaitForResult();
2317 const int kSize
= 3000;
2318 scoped_refptr
<IOBuffer
> buf(new IOBuffer(kSize
));
2321 base::Bind(&SpdyNetworkTransactionTest::StartTransactionCallback
,
2322 helper
.session(), GURL(GetDefaultUrl())));
2323 // This forces an err_IO_pending, which sets the callback.
2324 data
.CompleteRead();
2325 // This finishes the read.
2326 data
.CompleteRead();
2327 helper
.VerifyDataConsumed();
2330 // Verify that the client can correctly deal with the user callback deleting the
2331 // transaction. Failures will usually be valgrind errors. See
2332 // http://crbug.com/46925
2333 TEST_P(SpdyNetworkTransactionTest
, DeleteSessionOnReadCallback
) {
2334 scoped_ptr
<SpdyFrame
> req(
2335 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2336 MockWrite writes
[] = { CreateMockWrite(*req
) };
2338 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2339 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
2340 MockRead reads
[] = {
2341 CreateMockRead(*resp
.get(), 2),
2342 MockRead(ASYNC
, ERR_IO_PENDING
, 3), // Force a pause
2343 CreateMockRead(*body
.get(), 4),
2344 MockRead(ASYNC
, 0, 0, 5), // EOF
2347 OrderedSocketData
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 // Start the transaction with basic parameters.
2357 TestCompletionCallback callback
;
2358 int rv
= trans
->Start(&helper
.request(), callback
.callback(), BoundNetLog());
2359 EXPECT_EQ(ERR_IO_PENDING
, rv
);
2360 rv
= callback
.WaitForResult();
2362 // Setup a user callback which will delete the session, and clear out the
2363 // memory holding the stream object. Note that the callback deletes trans.
2364 const int kSize
= 3000;
2365 scoped_refptr
<IOBuffer
> buf(new IOBuffer(kSize
));
2369 base::Bind(&SpdyNetworkTransactionTest::DeleteSessionCallback
,
2370 base::Unretained(&helper
)));
2371 ASSERT_EQ(ERR_IO_PENDING
, rv
);
2372 data
.CompleteRead();
2374 // Finish running rest of tasks.
2375 base::RunLoop().RunUntilIdle();
2376 helper
.VerifyDataConsumed();
2379 // Send a spdy request to www.example.org that gets redirected to www.foo.com.
2380 TEST_P(SpdyNetworkTransactionTest
, DISABLED_RedirectGetRequest
) {
2381 scoped_ptr
<SpdyHeaderBlock
> headers(
2382 spdy_util_
.ConstructGetHeaderBlock(GetDefaultUrl()));
2383 (*headers
)["user-agent"] = "";
2384 (*headers
)["accept-encoding"] = "gzip, deflate";
2385 scoped_ptr
<SpdyHeaderBlock
> headers2(
2386 spdy_util_
.ConstructGetHeaderBlock("http://www.foo.com/index.php"));
2387 (*headers2
)["user-agent"] = "";
2388 (*headers2
)["accept-encoding"] = "gzip, deflate";
2390 // Setup writes/reads to www.example.org
2391 scoped_ptr
<SpdyFrame
> req(
2392 spdy_util_
.ConstructSpdySyn(1, *headers
, LOWEST
, false, true));
2393 scoped_ptr
<SpdyFrame
> req2(
2394 spdy_util_
.ConstructSpdySyn(1, *headers2
, LOWEST
, false, true));
2395 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReplyRedirect(1));
2396 MockWrite writes
[] = {
2397 CreateMockWrite(*req
, 1),
2399 MockRead reads
[] = {
2400 CreateMockRead(*resp
, 2),
2401 MockRead(ASYNC
, 0, 0, 3) // EOF
2404 // Setup writes/reads to www.foo.com
2405 scoped_ptr
<SpdyFrame
> resp2(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2406 scoped_ptr
<SpdyFrame
> body2(spdy_util_
.ConstructSpdyBodyFrame(1, true));
2407 MockWrite writes2
[] = {
2408 CreateMockWrite(*req2
, 1),
2410 MockRead reads2
[] = {
2411 CreateMockRead(*resp2
, 2),
2412 CreateMockRead(*body2
, 3),
2413 MockRead(ASYNC
, 0, 0, 4) // EOF
2415 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
2416 SequencedSocketData
data2(reads2
, arraysize(reads2
), writes2
,
2417 arraysize(writes2
));
2419 // TODO(erikchen): Make test support SPDYSSL, SPDYNPN
2422 SpdyURLRequestContext
spdy_url_request_context(GetParam().protocol
);
2423 scoped_ptr
<URLRequest
> r(spdy_url_request_context
.CreateRequest(
2424 GURL(GetDefaultUrl()), DEFAULT_PRIORITY
, &d
));
2425 spdy_url_request_context
.socket_factory().
2426 AddSocketDataProvider(&data
);
2427 spdy_url_request_context
.socket_factory().
2428 AddSocketDataProvider(&data2
);
2430 d
.set_quit_on_redirect(true);
2432 base::RunLoop().Run();
2434 EXPECT_EQ(1, d
.received_redirect_count());
2436 r
->FollowDeferredRedirect();
2437 base::RunLoop().Run();
2438 EXPECT_EQ(1, d
.response_started_count());
2439 EXPECT_FALSE(d
.received_data_before_response());
2440 EXPECT_EQ(URLRequestStatus::SUCCESS
, r
->status().status());
2441 std::string
contents("hello!");
2442 EXPECT_EQ(contents
, d
.data_received());
2444 EXPECT_TRUE(data
.AllReadDataConsumed());
2445 EXPECT_TRUE(data
.AllWriteDataConsumed());
2446 EXPECT_TRUE(data2
.AllReadDataConsumed());
2447 EXPECT_TRUE(data2
.AllWriteDataConsumed());
2450 // Send a spdy request to www.example.org. Get a pushed stream that redirects to
2452 TEST_P(SpdyNetworkTransactionTest
, DISABLED_RedirectServerPush
) {
2453 scoped_ptr
<SpdyHeaderBlock
> headers(
2454 spdy_util_
.ConstructGetHeaderBlock(GetDefaultUrl()));
2455 (*headers
)["user-agent"] = "";
2456 (*headers
)["accept-encoding"] = "gzip, deflate";
2458 // Setup writes/reads to www.example.org
2459 scoped_ptr
<SpdyFrame
> req(
2460 spdy_util_
.ConstructSpdySyn(1, *headers
, LOWEST
, false, true));
2461 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2462 scoped_ptr
<SpdyFrame
> rep(spdy_util_
.ConstructSpdyPush(
2463 NULL
, 0, 2, 1, GetDefaultUrlWithPath("/foo.dat").c_str(),
2464 "301 Moved Permanently", "http://www.foo.com/index.php"));
2465 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
2466 scoped_ptr
<SpdyFrame
> rst(
2467 spdy_util_
.ConstructSpdyRstStream(2, RST_STREAM_CANCEL
));
2468 MockWrite writes
[] = {
2469 CreateMockWrite(*req
, 1),
2470 CreateMockWrite(*rst
, 6),
2472 MockRead reads
[] = {
2473 CreateMockRead(*resp
, 2),
2474 CreateMockRead(*rep
, 3),
2475 CreateMockRead(*body
, 4),
2476 MockRead(ASYNC
, ERR_IO_PENDING
, 5), // Force a pause
2477 MockRead(ASYNC
, 0, 0, 7) // EOF
2480 // Setup writes/reads to www.foo.com
2481 scoped_ptr
<SpdyHeaderBlock
> headers2(
2482 spdy_util_
.ConstructGetHeaderBlock("http://www.foo.com/index.php"));
2483 (*headers2
)["user-agent"] = "";
2484 (*headers2
)["accept-encoding"] = "gzip, deflate";
2485 scoped_ptr
<SpdyFrame
> req2(
2486 spdy_util_
.ConstructSpdySyn(1, *headers2
, LOWEST
, false, true));
2487 scoped_ptr
<SpdyFrame
> resp2(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2488 scoped_ptr
<SpdyFrame
> body2(spdy_util_
.ConstructSpdyBodyFrame(1, true));
2489 MockWrite writes2
[] = {
2490 CreateMockWrite(*req2
, 1),
2492 MockRead reads2
[] = {
2493 CreateMockRead(*resp2
, 2),
2494 CreateMockRead(*body2
, 3),
2495 MockRead(ASYNC
, 0, 0, 5) // EOF
2497 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
2498 SequencedSocketData
data2(reads2
, arraysize(reads2
), writes2
,
2499 arraysize(writes2
));
2501 // TODO(erikchen): Make test support SPDYSSL, SPDYNPN
2504 SpdyURLRequestContext
spdy_url_request_context(GetParam().protocol
);
2506 scoped_ptr
<URLRequest
> r(spdy_url_request_context
.CreateRequest(
2507 GURL(GetDefaultUrl()), DEFAULT_PRIORITY
, &d
));
2508 spdy_url_request_context
.socket_factory().
2509 AddSocketDataProvider(&data
);
2512 base::RunLoop().Run();
2514 EXPECT_EQ(0, d
.received_redirect_count());
2515 std::string
contents("hello!");
2516 EXPECT_EQ(contents
, d
.data_received());
2518 scoped_ptr
<URLRequest
> r2(spdy_url_request_context
.CreateRequest(
2519 GURL(GetDefaultUrlWithPath("/foo.dat")), DEFAULT_PRIORITY
, &d2
));
2520 spdy_url_request_context
.socket_factory().
2521 AddSocketDataProvider(&data2
);
2523 d2
.set_quit_on_redirect(true);
2525 base::RunLoop().Run();
2526 EXPECT_EQ(1, d2
.received_redirect_count());
2528 r2
->FollowDeferredRedirect();
2529 base::RunLoop().Run();
2530 EXPECT_EQ(1, d2
.response_started_count());
2531 EXPECT_FALSE(d2
.received_data_before_response());
2532 EXPECT_EQ(URLRequestStatus::SUCCESS
, r2
->status().status());
2533 std::string
contents2("hello!");
2534 EXPECT_EQ(contents2
, d2
.data_received());
2536 EXPECT_TRUE(data
.AllReadDataConsumed());
2537 EXPECT_TRUE(data
.AllWriteDataConsumed());
2538 EXPECT_TRUE(data2
.AllReadDataConsumed());
2539 EXPECT_TRUE(data2
.AllWriteDataConsumed());
2542 TEST_P(SpdyNetworkTransactionTest
, ServerPushSingleDataFrame
) {
2543 scoped_ptr
<SpdyFrame
> stream1_syn(
2544 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2545 scoped_ptr
<SpdyFrame
> stream1_body(
2546 spdy_util_
.ConstructSpdyBodyFrame(1, true));
2547 MockWrite writes
[] = {
2548 CreateMockWrite(*stream1_syn
, 0),
2551 scoped_ptr
<SpdyFrame
>
2552 stream1_reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2553 scoped_ptr
<SpdyFrame
> stream2_syn(spdy_util_
.ConstructSpdyPush(
2554 NULL
, 0, 2, 1, GetDefaultUrlWithPath("/foo.dat").c_str()));
2555 const char kPushedData
[] = "pushed";
2556 scoped_ptr
<SpdyFrame
> stream2_body(
2557 spdy_util_
.ConstructSpdyBodyFrame(
2558 2, kPushedData
, strlen(kPushedData
), true));
2559 MockRead reads
[] = {
2560 CreateMockRead(*stream1_reply
, 1),
2561 CreateMockRead(*stream2_syn
, 2),
2562 CreateMockRead(*stream1_body
, 3, SYNCHRONOUS
),
2563 CreateMockRead(*stream2_body
, 4),
2564 MockRead(SYNCHRONOUS
, ERR_IO_PENDING
, 5), // Force a pause
2567 HttpResponseInfo response
;
2568 HttpResponseInfo response2
;
2569 std::string
expected_push_result("pushed");
2570 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
2571 RunServerPushTest(&data
,
2574 expected_push_result
);
2576 // Verify the SYN_REPLY.
2577 EXPECT_TRUE(response
.headers
.get() != NULL
);
2578 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
2580 // Verify the pushed stream.
2581 EXPECT_TRUE(response2
.headers
.get() != NULL
);
2582 EXPECT_EQ("HTTP/1.1 200 OK", response2
.headers
->GetStatusLine());
2585 TEST_P(SpdyNetworkTransactionTest
, ServerPushBeforeSynReply
) {
2586 scoped_ptr
<SpdyFrame
> stream1_syn(
2587 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2588 scoped_ptr
<SpdyFrame
> stream1_body(
2589 spdy_util_
.ConstructSpdyBodyFrame(1, true));
2590 MockWrite writes
[] = {
2591 CreateMockWrite(*stream1_syn
, 0),
2594 scoped_ptr
<SpdyFrame
>
2595 stream1_reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2596 scoped_ptr
<SpdyFrame
> stream2_syn(spdy_util_
.ConstructSpdyPush(
2597 NULL
, 0, 2, 1, GetDefaultUrlWithPath("/foo.dat").c_str()));
2598 const char kPushedData
[] = "pushed";
2599 scoped_ptr
<SpdyFrame
> stream2_body(
2600 spdy_util_
.ConstructSpdyBodyFrame(
2601 2, kPushedData
, strlen(kPushedData
), true));
2602 MockRead reads
[] = {
2603 CreateMockRead(*stream2_syn
, 1),
2604 CreateMockRead(*stream1_reply
, 2),
2605 CreateMockRead(*stream1_body
, 3, SYNCHRONOUS
),
2606 CreateMockRead(*stream2_body
, 4),
2607 MockRead(SYNCHRONOUS
, ERR_IO_PENDING
, 5), // Force a pause
2610 HttpResponseInfo response
;
2611 HttpResponseInfo response2
;
2612 std::string
expected_push_result("pushed");
2613 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
2614 RunServerPushTest(&data
,
2617 expected_push_result
);
2619 // Verify the SYN_REPLY.
2620 EXPECT_TRUE(response
.headers
.get() != NULL
);
2621 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
2623 // Verify the pushed stream.
2624 EXPECT_TRUE(response2
.headers
.get() != NULL
);
2625 EXPECT_EQ("HTTP/1.1 200 OK", response2
.headers
->GetStatusLine());
2628 TEST_P(SpdyNetworkTransactionTest
, ServerPushSingleDataFrame2
) {
2629 scoped_ptr
<SpdyFrame
> stream1_syn(
2630 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2631 MockWrite writes
[] = {
2632 CreateMockWrite(*stream1_syn
, 0),
2635 scoped_ptr
<SpdyFrame
>
2636 stream1_reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2637 scoped_ptr
<SpdyFrame
> stream2_syn(spdy_util_
.ConstructSpdyPush(
2638 NULL
, 0, 2, 1, GetDefaultUrlWithPath("/foo.dat").c_str()));
2639 const char kPushedData
[] = "pushed";
2640 scoped_ptr
<SpdyFrame
> stream2_body(
2641 spdy_util_
.ConstructSpdyBodyFrame(
2642 2, kPushedData
, strlen(kPushedData
), true));
2643 scoped_ptr
<SpdyFrame
>
2644 stream1_body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
2645 MockRead reads
[] = {
2646 CreateMockRead(*stream1_reply
, 1),
2647 CreateMockRead(*stream2_syn
, 2),
2648 CreateMockRead(*stream2_body
, 3),
2649 CreateMockRead(*stream1_body
, 4, SYNCHRONOUS
),
2650 MockRead(SYNCHRONOUS
, ERR_IO_PENDING
, 5), // Force a pause
2653 HttpResponseInfo response
;
2654 HttpResponseInfo response2
;
2655 std::string
expected_push_result("pushed");
2656 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
2657 RunServerPushTest(&data
,
2660 expected_push_result
);
2662 // Verify the SYN_REPLY.
2663 EXPECT_TRUE(response
.headers
.get() != NULL
);
2664 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
2666 // Verify the pushed stream.
2667 EXPECT_TRUE(response2
.headers
.get() != NULL
);
2668 EXPECT_EQ("HTTP/1.1 200 OK", response2
.headers
->GetStatusLine());
2671 TEST_P(SpdyNetworkTransactionTest
, ServerPushServerAborted
) {
2672 scoped_ptr
<SpdyFrame
> stream1_syn(
2673 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2674 scoped_ptr
<SpdyFrame
> stream1_body(
2675 spdy_util_
.ConstructSpdyBodyFrame(1, true));
2676 MockWrite writes
[] = {
2677 CreateMockWrite(*stream1_syn
, 0),
2680 scoped_ptr
<SpdyFrame
>
2681 stream1_reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2682 scoped_ptr
<SpdyFrame
> stream2_syn(spdy_util_
.ConstructSpdyPush(
2683 NULL
, 0, 2, 1, GetDefaultUrlWithPath("/foo.dat").c_str()));
2684 scoped_ptr
<SpdyFrame
> stream2_rst(
2685 spdy_util_
.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR
));
2686 MockRead reads
[] = {
2687 CreateMockRead(*stream1_reply
, 1),
2688 CreateMockRead(*stream2_syn
, 2),
2689 CreateMockRead(*stream2_rst
, 3),
2690 CreateMockRead(*stream1_body
, 4, SYNCHRONOUS
),
2691 MockRead(SYNCHRONOUS
, ERR_IO_PENDING
, 5), // Force a pause
2694 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
2695 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
2696 BoundNetLog(), GetParam(), NULL
);
2698 helper
.RunPreTestSetup();
2699 helper
.AddData(&data
);
2701 HttpNetworkTransaction
* trans
= helper
.trans();
2703 // Start the transaction with basic parameters.
2704 TestCompletionCallback callback
;
2705 int rv
= trans
->Start(
2706 &CreateGetRequest(), callback
.callback(), BoundNetLog());
2707 EXPECT_EQ(ERR_IO_PENDING
, rv
);
2708 rv
= callback
.WaitForResult();
2711 // Verify that we consumed all test data.
2712 EXPECT_TRUE(data
.AllReadDataConsumed());
2713 EXPECT_TRUE(data
.AllWriteDataConsumed());
2715 // Verify the SYN_REPLY.
2716 HttpResponseInfo response
= *trans
->GetResponseInfo();
2717 EXPECT_TRUE(response
.headers
.get() != NULL
);
2718 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
2721 // Verify that we don't leak streams and that we properly send a reset
2722 // if the server pushes the same stream twice.
2723 TEST_P(SpdyNetworkTransactionTest
, ServerPushDuplicate
) {
2724 scoped_ptr
<SpdyFrame
> stream1_syn(
2725 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2726 scoped_ptr
<SpdyFrame
> stream1_body(
2727 spdy_util_
.ConstructSpdyBodyFrame(1, true));
2728 scoped_ptr
<SpdyFrame
> stream3_rst(
2729 spdy_util_
.ConstructSpdyRstStream(4, RST_STREAM_PROTOCOL_ERROR
));
2730 MockWrite writes
[] = {
2731 CreateMockWrite(*stream1_syn
, 0), CreateMockWrite(*stream3_rst
, 4),
2734 scoped_ptr
<SpdyFrame
>
2735 stream1_reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2736 scoped_ptr
<SpdyFrame
> stream2_syn(spdy_util_
.ConstructSpdyPush(
2737 NULL
, 0, 2, 1, GetDefaultUrlWithPath("/foo.dat").c_str()));
2738 const char kPushedData
[] = "pushed";
2739 scoped_ptr
<SpdyFrame
> stream2_body(
2740 spdy_util_
.ConstructSpdyBodyFrame(
2741 2, kPushedData
, strlen(kPushedData
), true));
2742 scoped_ptr
<SpdyFrame
> stream3_syn(spdy_util_
.ConstructSpdyPush(
2743 NULL
, 0, 4, 1, GetDefaultUrlWithPath("/foo.dat").c_str()));
2744 MockRead reads
[] = {
2745 CreateMockRead(*stream1_reply
, 1),
2746 CreateMockRead(*stream2_syn
, 2),
2747 CreateMockRead(*stream3_syn
, 3),
2748 CreateMockRead(*stream1_body
, 5),
2749 CreateMockRead(*stream2_body
, 6),
2750 MockRead(SYNCHRONOUS
, ERR_IO_PENDING
, 7), // Force a pause
2753 HttpResponseInfo response
;
2754 HttpResponseInfo response2
;
2755 std::string
expected_push_result("pushed");
2756 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
2757 RunServerPushTest(&data
,
2760 expected_push_result
);
2762 // Verify the SYN_REPLY.
2763 EXPECT_TRUE(response
.headers
.get() != NULL
);
2764 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
2766 // Verify the pushed stream.
2767 EXPECT_TRUE(response2
.headers
.get() != NULL
);
2768 EXPECT_EQ("HTTP/1.1 200 OK", response2
.headers
->GetStatusLine());
2771 TEST_P(SpdyNetworkTransactionTest
, ServerPushMultipleDataFrame
) {
2772 scoped_ptr
<SpdyFrame
> stream1_syn(
2773 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2774 scoped_ptr
<SpdyFrame
> stream1_body(
2775 spdy_util_
.ConstructSpdyBodyFrame(1, true));
2776 MockWrite writes
[] = {
2777 CreateMockWrite(*stream1_syn
, 0),
2780 scoped_ptr
<SpdyFrame
>
2781 stream1_reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2782 scoped_ptr
<SpdyFrame
> stream2_syn(spdy_util_
.ConstructSpdyPush(
2783 NULL
, 0, 2, 1, GetDefaultUrlWithPath("/foo.dat").c_str()));
2784 static const char kPushedData
[] = "pushed my darling hello my baby";
2785 scoped_ptr
<SpdyFrame
> stream2_body_base(
2786 spdy_util_
.ConstructSpdyBodyFrame(
2787 2, kPushedData
, strlen(kPushedData
), true));
2788 const size_t kChunkSize
= strlen(kPushedData
) / 4;
2789 scoped_ptr
<SpdyFrame
> stream2_body1(
2790 new SpdyFrame(stream2_body_base
->data(), kChunkSize
, false));
2791 scoped_ptr
<SpdyFrame
> stream2_body2(
2792 new SpdyFrame(stream2_body_base
->data() + kChunkSize
, kChunkSize
, false));
2793 scoped_ptr
<SpdyFrame
> stream2_body3(
2794 new SpdyFrame(stream2_body_base
->data() + 2 * kChunkSize
,
2795 kChunkSize
, false));
2796 scoped_ptr
<SpdyFrame
> stream2_body4(
2797 new SpdyFrame(stream2_body_base
->data() + 3 * kChunkSize
,
2798 stream2_body_base
->size() - 3 * kChunkSize
, false));
2799 MockRead reads
[] = {
2800 CreateMockRead(*stream1_reply
, 1),
2801 CreateMockRead(*stream2_syn
, 2),
2802 CreateMockRead(*stream2_body1
, 3),
2803 CreateMockRead(*stream2_body2
, 4),
2804 CreateMockRead(*stream2_body3
, 5),
2805 CreateMockRead(*stream2_body4
, 6),
2806 CreateMockRead(*stream1_body
, 7, SYNCHRONOUS
),
2807 MockRead(SYNCHRONOUS
, ERR_IO_PENDING
, 8), // Force a pause
2810 HttpResponseInfo response
;
2811 HttpResponseInfo response2
;
2812 std::string
expected_push_result("pushed my darling hello my baby");
2813 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
2814 RunServerPushTest(&data
, &response
, &response2
, kPushedData
);
2816 // Verify the SYN_REPLY.
2817 EXPECT_TRUE(response
.headers
.get() != NULL
);
2818 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
2820 // Verify the pushed stream.
2821 EXPECT_TRUE(response2
.headers
.get() != NULL
);
2822 EXPECT_EQ("HTTP/1.1 200 OK", response2
.headers
->GetStatusLine());
2825 TEST_P(SpdyNetworkTransactionTest
, ServerPushMultipleDataFrameInterrupted
) {
2826 scoped_ptr
<SpdyFrame
> stream1_syn(
2827 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2828 scoped_ptr
<SpdyFrame
> stream1_body(
2829 spdy_util_
.ConstructSpdyBodyFrame(1, true));
2830 MockWrite writes
[] = {
2831 CreateMockWrite(*stream1_syn
, 0),
2834 scoped_ptr
<SpdyFrame
>
2835 stream1_reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2836 scoped_ptr
<SpdyFrame
> stream2_syn(spdy_util_
.ConstructSpdyPush(
2837 NULL
, 0, 2, 1, GetDefaultUrlWithPath("/foo.dat").c_str()));
2838 static const char kPushedData
[] = "pushed my darling hello my baby";
2839 scoped_ptr
<SpdyFrame
> stream2_body_base(
2840 spdy_util_
.ConstructSpdyBodyFrame(
2841 2, kPushedData
, strlen(kPushedData
), true));
2842 const size_t kChunkSize
= strlen(kPushedData
) / 4;
2843 scoped_ptr
<SpdyFrame
> stream2_body1(
2844 new SpdyFrame(stream2_body_base
->data(), kChunkSize
, false));
2845 scoped_ptr
<SpdyFrame
> stream2_body2(
2846 new SpdyFrame(stream2_body_base
->data() + kChunkSize
, kChunkSize
, false));
2847 scoped_ptr
<SpdyFrame
> stream2_body3(
2848 new SpdyFrame(stream2_body_base
->data() + 2 * kChunkSize
,
2849 kChunkSize
, false));
2850 scoped_ptr
<SpdyFrame
> stream2_body4(
2851 new SpdyFrame(stream2_body_base
->data() + 3 * kChunkSize
,
2852 stream2_body_base
->size() - 3 * kChunkSize
, false));
2853 MockRead reads
[] = {
2854 CreateMockRead(*stream1_reply
, 1),
2855 CreateMockRead(*stream2_syn
, 2),
2856 CreateMockRead(*stream2_body1
, 3),
2857 CreateMockRead(*stream2_body2
, 4),
2858 CreateMockRead(*stream2_body3
, 5),
2859 CreateMockRead(*stream2_body4
, 6),
2860 CreateMockRead(*stream1_body
.get(), 7, SYNCHRONOUS
),
2861 MockRead(SYNCHRONOUS
, ERR_IO_PENDING
, 8) // Force a pause.
2864 HttpResponseInfo response
;
2865 HttpResponseInfo response2
;
2866 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
2867 RunServerPushTest(&data
, &response
, &response2
, kPushedData
);
2869 // Verify the SYN_REPLY.
2870 EXPECT_TRUE(response
.headers
.get() != NULL
);
2871 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
2873 // Verify the pushed stream.
2874 EXPECT_TRUE(response2
.headers
.get() != NULL
);
2875 EXPECT_EQ("HTTP/1.1 200 OK", response2
.headers
->GetStatusLine());
2878 TEST_P(SpdyNetworkTransactionTest
, ServerPushInvalidAssociatedStreamID0
) {
2879 if (spdy_util_
.spdy_version() == SPDY4
) {
2880 // PUSH_PROMISE with stream id 0 is connection-level error.
2881 // TODO(baranovich): Test session going away.
2885 scoped_ptr
<SpdyFrame
> stream1_syn(
2886 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2887 scoped_ptr
<SpdyFrame
> stream1_body(
2888 spdy_util_
.ConstructSpdyBodyFrame(1, true));
2889 scoped_ptr
<SpdyFrame
> stream2_rst(
2890 spdy_util_
.ConstructSpdyRstStream(2, RST_STREAM_REFUSED_STREAM
));
2891 MockWrite writes
[] = {
2892 CreateMockWrite(*stream1_syn
, 0), CreateMockWrite(*stream2_rst
, 3),
2895 scoped_ptr
<SpdyFrame
>
2896 stream1_reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2897 scoped_ptr
<SpdyFrame
> stream2_syn(spdy_util_
.ConstructSpdyPush(
2898 NULL
, 0, 2, 0, GetDefaultUrlWithPath("/foo.dat").c_str()));
2899 MockRead reads
[] = {
2900 CreateMockRead(*stream1_reply
, 1),
2901 CreateMockRead(*stream2_syn
, 2),
2902 CreateMockRead(*stream1_body
, 4),
2903 MockRead(SYNCHRONOUS
, ERR_IO_PENDING
, 5) // Force a pause
2906 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
2907 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
2908 BoundNetLog(), GetParam(), NULL
);
2910 helper
.RunPreTestSetup();
2911 helper
.AddData(&data
);
2913 HttpNetworkTransaction
* trans
= helper
.trans();
2915 // Start the transaction with basic parameters.
2916 TestCompletionCallback callback
;
2917 int rv
= trans
->Start(
2918 &CreateGetRequest(), callback
.callback(), BoundNetLog());
2919 EXPECT_EQ(ERR_IO_PENDING
, rv
);
2920 rv
= callback
.WaitForResult();
2923 // Verify that we consumed all test data.
2924 EXPECT_TRUE(data
.AllReadDataConsumed());
2925 EXPECT_TRUE(data
.AllWriteDataConsumed());
2927 // Verify the SYN_REPLY.
2928 HttpResponseInfo response
= *trans
->GetResponseInfo();
2929 EXPECT_TRUE(response
.headers
.get() != NULL
);
2930 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
2933 TEST_P(SpdyNetworkTransactionTest
, ServerPushInvalidAssociatedStreamID9
) {
2934 scoped_ptr
<SpdyFrame
> stream1_syn(
2935 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2936 scoped_ptr
<SpdyFrame
> stream1_body(
2937 spdy_util_
.ConstructSpdyBodyFrame(1, true));
2938 scoped_ptr
<SpdyFrame
> stream2_rst(
2939 spdy_util_
.ConstructSpdyRstStream(2, RST_STREAM_INVALID_STREAM
));
2940 MockWrite writes
[] = {
2941 CreateMockWrite(*stream1_syn
, 0), CreateMockWrite(*stream2_rst
, 3),
2944 scoped_ptr
<SpdyFrame
>
2945 stream1_reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2946 scoped_ptr
<SpdyFrame
> stream2_syn(spdy_util_
.ConstructSpdyPush(
2947 NULL
, 0, 2, 9, GetDefaultUrlWithPath("/foo.dat").c_str()));
2948 MockRead reads
[] = {
2949 CreateMockRead(*stream1_reply
, 1),
2950 CreateMockRead(*stream2_syn
, 2),
2951 CreateMockRead(*stream1_body
, 4),
2952 MockRead(SYNCHRONOUS
, ERR_IO_PENDING
, 5), // Force a pause
2955 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
2956 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
2957 BoundNetLog(), GetParam(), NULL
);
2959 helper
.RunPreTestSetup();
2960 helper
.AddData(&data
);
2962 HttpNetworkTransaction
* trans
= helper
.trans();
2964 // Start the transaction with basic parameters.
2965 TestCompletionCallback callback
;
2966 int rv
= trans
->Start(
2967 &CreateGetRequest(), callback
.callback(), BoundNetLog());
2968 EXPECT_EQ(ERR_IO_PENDING
, rv
);
2969 rv
= callback
.WaitForResult();
2972 // Verify that we consumed all test data.
2973 EXPECT_TRUE(data
.AllReadDataConsumed());
2974 EXPECT_TRUE(data
.AllWriteDataConsumed());
2976 // Verify the SYN_REPLY.
2977 HttpResponseInfo response
= *trans
->GetResponseInfo();
2978 EXPECT_TRUE(response
.headers
.get() != NULL
);
2979 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
2982 TEST_P(SpdyNetworkTransactionTest
, ServerPushNoURL
) {
2983 scoped_ptr
<SpdyFrame
> stream1_syn(
2984 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2985 scoped_ptr
<SpdyFrame
> stream1_body(
2986 spdy_util_
.ConstructSpdyBodyFrame(1, true));
2987 scoped_ptr
<SpdyFrame
> stream2_rst(
2988 spdy_util_
.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR
));
2989 MockWrite writes
[] = {
2990 CreateMockWrite(*stream1_syn
, 0), CreateMockWrite(*stream2_rst
, 3),
2993 scoped_ptr
<SpdyFrame
>
2994 stream1_reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2995 scoped_ptr
<SpdyHeaderBlock
> incomplete_headers(new SpdyHeaderBlock());
2996 (*incomplete_headers
)["hello"] = "bye";
2997 (*incomplete_headers
)[spdy_util_
.GetStatusKey()] = "200 OK";
2998 (*incomplete_headers
)[spdy_util_
.GetVersionKey()] = "HTTP/1.1";
2999 scoped_ptr
<SpdyFrame
> stream2_syn(spdy_util_
.ConstructInitialSpdyPushFrame(
3000 incomplete_headers
.Pass(), 2, 1));
3001 MockRead reads
[] = {
3002 CreateMockRead(*stream1_reply
, 1),
3003 CreateMockRead(*stream2_syn
, 2),
3004 CreateMockRead(*stream1_body
, 4),
3005 MockRead(SYNCHRONOUS
, ERR_IO_PENDING
, 5) // Force a pause
3008 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
3009 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
3010 BoundNetLog(), GetParam(), NULL
);
3012 helper
.RunPreTestSetup();
3013 helper
.AddData(&data
);
3015 HttpNetworkTransaction
* trans
= helper
.trans();
3017 // Start the transaction with basic parameters.
3018 TestCompletionCallback callback
;
3019 int rv
= trans
->Start(
3020 &CreateGetRequest(), callback
.callback(), BoundNetLog());
3021 EXPECT_EQ(ERR_IO_PENDING
, rv
);
3022 rv
= callback
.WaitForResult();
3025 // Verify that we consumed all test data.
3026 EXPECT_TRUE(data
.AllReadDataConsumed());
3027 EXPECT_TRUE(data
.AllWriteDataConsumed());
3029 // Verify the SYN_REPLY.
3030 HttpResponseInfo response
= *trans
->GetResponseInfo();
3031 EXPECT_TRUE(response
.headers
.get() != NULL
);
3032 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
3035 // Verify that various SynReply headers parse correctly through the
3037 TEST_P(SpdyNetworkTransactionTest
, SynReplyHeaders
) {
3038 struct SynReplyHeadersTests
{
3040 const char* extra_headers
[5];
3041 SpdyHeaderBlock expected_headers
;
3043 // This uses a multi-valued cookie header.
3046 "cookie", "val2", // will get appended separated by NULL
3050 // This is the minimalist set of headers.
3054 // Headers with a comma separated list.
3056 { "cookie", "val1,val2",
3062 test_cases
[0].expected_headers
["cookie"] = "val1";
3063 test_cases
[0].expected_headers
["cookie"] += '\0';
3064 test_cases
[0].expected_headers
["cookie"] += "val2";
3065 test_cases
[0].expected_headers
["hello"] = "bye";
3066 test_cases
[0].expected_headers
["status"] = "200";
3068 test_cases
[1].expected_headers
["hello"] = "bye";
3069 test_cases
[1].expected_headers
["status"] = "200";
3071 test_cases
[2].expected_headers
["cookie"] = "val1,val2";
3072 test_cases
[2].expected_headers
["hello"] = "bye";
3073 test_cases
[2].expected_headers
["status"] = "200";
3075 if (spdy_util_
.spdy_version() < SPDY4
) {
3076 // SPDY4/HTTP2 eliminates use of the :version header.
3077 test_cases
[0].expected_headers
["version"] = "HTTP/1.1";
3078 test_cases
[1].expected_headers
["version"] = "HTTP/1.1";
3079 test_cases
[2].expected_headers
["version"] = "HTTP/1.1";
3082 for (size_t i
= 0; i
< arraysize(test_cases
); ++i
) {
3083 scoped_ptr
<SpdyFrame
> req(
3084 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
3085 MockWrite writes
[] = {CreateMockWrite(*req
, 0)};
3087 scoped_ptr
<SpdyFrame
> resp(
3088 spdy_util_
.ConstructSpdyGetSynReply(test_cases
[i
].extra_headers
,
3089 test_cases
[i
].num_headers
,
3091 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
3092 MockRead reads
[] = {
3093 CreateMockRead(*resp
, 1),
3094 CreateMockRead(*body
, 2),
3095 MockRead(ASYNC
, 0, 3) // EOF
3098 SequencedSocketData
data(reads
, arraysize(reads
), writes
,
3100 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
3101 BoundNetLog(), GetParam(), NULL
);
3102 helper
.RunToCompletion(&data
);
3103 TransactionHelperResult out
= helper
.output();
3105 EXPECT_EQ(OK
, out
.rv
);
3106 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
3107 EXPECT_EQ("hello!", out
.response_data
);
3109 scoped_refptr
<HttpResponseHeaders
> headers
= out
.response_info
.headers
;
3110 EXPECT_TRUE(headers
.get() != NULL
);
3112 std::string name
, value
;
3113 SpdyHeaderBlock header_block
;
3114 while (headers
->EnumerateHeaderLines(&iter
, &name
, &value
)) {
3115 if (header_block
[name
].empty()) {
3116 header_block
[name
] = value
;
3118 header_block
[name
] += '\0';
3119 header_block
[name
] += value
;
3122 EXPECT_EQ(test_cases
[i
].expected_headers
, header_block
);
3126 // Verify that various SynReply headers parse vary fields correctly
3127 // through the HTTP layer, and the response matches the request.
3128 TEST_P(SpdyNetworkTransactionTest
, SynReplyHeadersVary
) {
3129 // Modify the following data to change/add test cases:
3130 struct SynReplyTests
{
3133 const char* extra_headers
[2][16];
3135 // Test the case of a multi-valued cookie. When the value is delimited
3136 // with NUL characters, it needs to be unfolded into multiple headers.
3140 { { "cookie", "val1,val2",
3144 spdy_util_
.GetStatusKey(), "200",
3145 spdy_util_
.GetPathKey(), "/index.php",
3146 spdy_util_
.GetVersionKey(), "HTTP/1.1",
3150 }, { // Multiple vary fields.
3153 { { "friend", "barney",
3154 "enemy", "snaggletooth",
3159 spdy_util_
.GetStatusKey(), "200",
3160 spdy_util_
.GetPathKey(), "/index.php",
3161 spdy_util_
.GetVersionKey(), "HTTP/1.1",
3165 }, { // Test a '*' vary field.
3168 { { "cookie", "val1,val2",
3172 spdy_util_
.GetStatusKey(), "200",
3173 spdy_util_
.GetPathKey(), "/index.php",
3174 spdy_util_
.GetVersionKey(), "HTTP/1.1",
3178 }, { // Multiple comma-separated vary fields.
3181 { { "friend", "barney",
3182 "enemy", "snaggletooth",
3185 { "vary", "friend,enemy",
3186 spdy_util_
.GetStatusKey(), "200",
3187 spdy_util_
.GetPathKey(), "/index.php",
3188 spdy_util_
.GetVersionKey(), "HTTP/1.1",
3195 for (size_t i
= 0; i
< arraysize(test_cases
); ++i
) {
3196 // Construct the request.
3197 scoped_ptr
<SpdyFrame
> frame_req(
3198 spdy_util_
.ConstructSpdyGet(test_cases
[i
].extra_headers
[0],
3199 test_cases
[i
].num_headers
[0],
3200 false, 1, LOWEST
, true));
3202 MockWrite writes
[] = {
3203 CreateMockWrite(*frame_req
, 0),
3206 // Construct the reply.
3207 SpdyHeaderBlock reply_headers
;
3208 AppendToHeaderBlock(test_cases
[i
].extra_headers
[1],
3209 test_cases
[i
].num_headers
[1],
3211 scoped_ptr
<SpdyFrame
> frame_reply(
3212 spdy_util_
.ConstructSpdyReply(1, reply_headers
));
3214 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
3215 MockRead reads
[] = {
3216 CreateMockRead(*frame_reply
, 1),
3217 CreateMockRead(*body
, 2),
3218 MockRead(ASYNC
, 0, 3) // EOF
3221 // Attach the headers to the request.
3222 int header_count
= test_cases
[i
].num_headers
[0];
3224 HttpRequestInfo request
= CreateGetRequest();
3225 for (int ct
= 0; ct
< header_count
; ct
++) {
3226 const char* header_key
= test_cases
[i
].extra_headers
[0][ct
* 2];
3227 const char* header_value
= test_cases
[i
].extra_headers
[0][ct
* 2 + 1];
3228 request
.extra_headers
.SetHeader(header_key
, header_value
);
3231 SequencedSocketData
data(reads
, arraysize(reads
), writes
,
3233 NormalSpdyTransactionHelper
helper(request
, DEFAULT_PRIORITY
,
3234 BoundNetLog(), GetParam(), NULL
);
3235 helper
.RunToCompletion(&data
);
3236 TransactionHelperResult out
= helper
.output();
3238 EXPECT_EQ(OK
, out
.rv
) << i
;
3239 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
) << i
;
3240 EXPECT_EQ("hello!", out
.response_data
) << i
;
3242 // Test the response information.
3243 EXPECT_TRUE(out
.response_info
.response_time
>
3244 out
.response_info
.request_time
) << i
;
3245 base::TimeDelta test_delay
= out
.response_info
.response_time
-
3246 out
.response_info
.request_time
;
3247 base::TimeDelta min_expected_delay
;
3248 min_expected_delay
.FromMilliseconds(10);
3249 EXPECT_GT(test_delay
.InMillisecondsF(),
3250 min_expected_delay
.InMillisecondsF()) << i
;
3251 EXPECT_EQ(out
.response_info
.vary_data
.is_valid(),
3252 test_cases
[i
].vary_matches
) << i
;
3254 // Check the headers.
3255 scoped_refptr
<HttpResponseHeaders
> headers
= out
.response_info
.headers
;
3256 ASSERT_TRUE(headers
.get() != NULL
) << i
;
3258 std::string name
, value
, lines
;
3259 while (headers
->EnumerateHeaderLines(&iter
, &name
, &value
)) {
3262 lines
.append(value
);
3266 // Construct the expected header reply string.
3267 std::string expected_reply
=
3268 spdy_util_
.ConstructSpdyReplyString(reply_headers
);
3269 EXPECT_EQ(expected_reply
, lines
) << i
;
3273 // Verify that we don't crash on invalid SynReply responses.
3274 TEST_P(SpdyNetworkTransactionTest
, InvalidSynReply
) {
3275 struct InvalidSynReplyTests
{
3277 const char* headers
[10];
3279 // SYN_REPLY missing status header
3283 spdy_util_
.GetPathKey(), "/index.php",
3284 spdy_util_
.GetVersionKey(), "HTTP/1.1",
3288 // SYN_REPLY missing version header
3291 spdy_util_
.GetPathKey(), "/index.php",
3295 // SYN_REPLY with no headers
3299 for (size_t i
= 0; i
< arraysize(test_cases
); ++i
) {
3300 scoped_ptr
<SpdyFrame
> req(
3301 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
3302 scoped_ptr
<SpdyFrame
> rst(
3303 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR
));
3304 MockWrite writes
[] = {
3305 CreateMockWrite(*req
, 0), CreateMockWrite(*rst
, 2),
3308 // Construct the reply.
3309 SpdyHeaderBlock reply_headers
;
3310 AppendToHeaderBlock(
3311 test_cases
[i
].headers
, test_cases
[i
].num_headers
, &reply_headers
);
3312 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyReply(1, reply_headers
));
3313 MockRead reads
[] = {
3314 CreateMockRead(*resp
, 1), MockRead(ASYNC
, 0, 3) // EOF
3317 SequencedSocketData
data(reads
, arraysize(reads
), writes
,
3319 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
3320 BoundNetLog(), GetParam(), NULL
);
3321 helper
.RunToCompletion(&data
);
3322 TransactionHelperResult out
= helper
.output();
3323 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR
, out
.rv
);
3327 // Verify that we don't crash on some corrupt frames.
3328 // TODO(jgraettinger): SPDY4 and up treats a header decompression failure as a
3329 // connection error. I'd like to backport this behavior to SPDY3 as well.
3330 TEST_P(SpdyNetworkTransactionTest
, CorruptFrameSessionError
) {
3331 if (spdy_util_
.spdy_version() >= SPDY4
) {
3334 // This is the length field that's too short.
3335 scoped_ptr
<SpdyFrame
> syn_reply_wrong_length(
3336 spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
3337 BufferedSpdyFramer
framer(spdy_util_
.spdy_version(), false);
3339 (spdy_util_
.spdy_version() < SPDY4
) ?
3340 syn_reply_wrong_length
->size() - framer
.GetControlFrameHeaderSize() :
3341 syn_reply_wrong_length
->size();
3342 size_t wrong_size
= right_size
- 4;
3343 test::SetFrameLength(syn_reply_wrong_length
.get(),
3345 spdy_util_
.spdy_version());
3347 struct SynReplyTests
{
3348 const SpdyFrame
* syn_reply
;
3350 { syn_reply_wrong_length
.get(), },
3353 for (size_t i
= 0; i
< arraysize(test_cases
); ++i
) {
3354 scoped_ptr
<SpdyFrame
> req(
3355 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
3356 scoped_ptr
<SpdyFrame
> rst(
3357 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR
));
3358 MockWrite writes
[] = {
3359 CreateMockWrite(*req
, 0), CreateMockWrite(*rst
, 3),
3362 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
3363 MockRead reads
[] = {
3364 MockRead(ASYNC
, test_cases
[i
].syn_reply
->data(), wrong_size
, 1),
3365 CreateMockRead(*body
, 2),
3366 MockRead(ASYNC
, 0, 4) // EOF
3369 SequencedSocketData
data(reads
, arraysize(reads
), writes
,
3371 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
3372 BoundNetLog(), GetParam(), NULL
);
3373 helper
.RunToCompletion(&data
);
3374 TransactionHelperResult out
= helper
.output();
3375 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR
, out
.rv
);
3379 // SPDY4 treats a header decompression failure as a connection-level error.
3380 TEST_P(SpdyNetworkTransactionTest
, CorruptFrameSessionErrorSpdy4
) {
3381 if (spdy_util_
.spdy_version() < SPDY4
) {
3384 // This is the length field that's too short.
3385 scoped_ptr
<SpdyFrame
> syn_reply_wrong_length(
3386 spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
3387 BufferedSpdyFramer
framer(spdy_util_
.spdy_version(), false);
3389 syn_reply_wrong_length
->size() - framer
.GetControlFrameHeaderSize();
3390 size_t wrong_size
= right_size
- 4;
3391 test::SetFrameLength(syn_reply_wrong_length
.get(),
3393 spdy_util_
.spdy_version());
3395 scoped_ptr
<SpdyFrame
> req(
3396 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
3397 scoped_ptr
<SpdyFrame
> goaway(spdy_util_
.ConstructSpdyGoAway(
3398 0, GOAWAY_COMPRESSION_ERROR
, "Framer error: 5 (DECOMPRESS_FAILURE)."));
3399 MockWrite writes
[] = {CreateMockWrite(*req
, 0), CreateMockWrite(*goaway
, 2)};
3401 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
3402 MockRead reads
[] = {
3403 MockRead(ASYNC
, syn_reply_wrong_length
->data(),
3404 syn_reply_wrong_length
->size() - 4, 1),
3407 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
3408 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
3409 BoundNetLog(), GetParam(), NULL
);
3410 helper
.RunToCompletion(&data
);
3411 TransactionHelperResult out
= helper
.output();
3412 EXPECT_EQ(ERR_SPDY_COMPRESSION_ERROR
, out
.rv
);
3415 TEST_P(SpdyNetworkTransactionTest
, GoAwayOnDecompressionFailure
) {
3416 if (GetParam().protocol
< kProtoSPDY4MinimumVersion
) {
3417 // Decompression failures are a stream error in SPDY3 and above.
3420 scoped_ptr
<SpdyFrame
> req(
3421 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
3422 scoped_ptr
<SpdyFrame
> goaway(spdy_util_
.ConstructSpdyGoAway(
3423 0, GOAWAY_COMPRESSION_ERROR
, "Framer error: 5 (DECOMPRESS_FAILURE)."));
3424 MockWrite writes
[] = {CreateMockWrite(*req
, 0), CreateMockWrite(*goaway
, 2)};
3426 // Read HEADERS with corrupted payload.
3427 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
3428 memset(resp
->data() + 12, 0xff, resp
->size() - 12);
3429 MockRead reads
[] = {CreateMockRead(*resp
, 1)};
3431 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
3432 NormalSpdyTransactionHelper
helper(
3433 CreateGetRequest(), DEFAULT_PRIORITY
, BoundNetLog(), GetParam(), NULL
);
3434 helper
.RunToCompletion(&data
);
3435 TransactionHelperResult out
= helper
.output();
3436 EXPECT_EQ(ERR_SPDY_COMPRESSION_ERROR
, out
.rv
);
3439 TEST_P(SpdyNetworkTransactionTest
, GoAwayOnFrameSizeError
) {
3440 scoped_ptr
<SpdyFrame
> req(
3441 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
3442 scoped_ptr
<SpdyFrame
> goaway(spdy_util_
.ConstructSpdyGoAway(
3443 0, GOAWAY_PROTOCOL_ERROR
, "Framer error: 1 (INVALID_CONTROL_FRAME)."));
3444 MockWrite writes
[] = {CreateMockWrite(*req
, 0), CreateMockWrite(*goaway
, 2)};
3446 // Read WINDOW_UPDATE with incorrectly-sized payload.
3447 // TODO(jgraettinger): SpdyFramer signals this as an INVALID_CONTROL_FRAME,
3448 // which is mapped to a protocol error, and not a frame size error.
3449 scoped_ptr
<SpdyFrame
> bad_window_update(
3450 spdy_util_
.ConstructSpdyWindowUpdate(1, 1));
3451 test::SetFrameLength(bad_window_update
.get(),
3452 bad_window_update
->size() - 1,
3453 spdy_util_
.spdy_version());
3454 MockRead reads
[] = {CreateMockRead(*bad_window_update
, 1)};
3456 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
3457 NormalSpdyTransactionHelper
helper(
3458 CreateGetRequest(), DEFAULT_PRIORITY
, BoundNetLog(), GetParam(), NULL
);
3459 helper
.RunToCompletion(&data
);
3460 TransactionHelperResult out
= helper
.output();
3461 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR
, out
.rv
);
3464 // Test that we shutdown correctly on write errors.
3465 TEST_P(SpdyNetworkTransactionTest
, WriteError
) {
3466 scoped_ptr
<SpdyFrame
> req(
3467 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
3468 MockWrite writes
[] = {
3469 // We'll write 10 bytes successfully
3470 MockWrite(ASYNC
, req
->data(), 10, 0),
3471 // Followed by ERROR!
3472 MockWrite(ASYNC
, ERR_FAILED
, 1),
3473 // Session drains and attempts to write a GOAWAY: Another ERROR!
3474 MockWrite(ASYNC
, ERR_FAILED
, 2),
3477 MockRead reads
[] = {
3478 MockRead(ASYNC
, 0, 3) // EOF
3481 DeterministicSocketData
data(reads
, arraysize(reads
),
3482 writes
, arraysize(writes
));
3484 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
3485 BoundNetLog(), GetParam(), NULL
);
3486 helper
.SetDeterministic();
3487 helper
.RunPreTestSetup();
3488 helper
.AddDeterministicData(&data
);
3489 EXPECT_TRUE(helper
.StartDefaultTest());
3491 helper
.FinishDefaultTest();
3492 EXPECT_TRUE(data
.AllWriteDataConsumed());
3493 EXPECT_TRUE(!data
.AllReadDataConsumed());
3494 TransactionHelperResult out
= helper
.output();
3495 EXPECT_EQ(ERR_FAILED
, out
.rv
);
3498 // Test that partial writes work.
3499 TEST_P(SpdyNetworkTransactionTest
, PartialWrite
) {
3500 // Chop the SYN_STREAM frame into 5 chunks.
3501 scoped_ptr
<SpdyFrame
> req(
3502 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
3503 const int kChunks
= 5;
3504 scoped_ptr
<MockWrite
[]> writes(ChopWriteFrame(*req
.get(), kChunks
));
3505 for (int i
= 0; i
< kChunks
; ++i
) {
3506 writes
[i
].sequence_number
= i
;
3509 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
3510 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
3511 MockRead reads
[] = {
3512 CreateMockRead(*resp
, kChunks
),
3513 CreateMockRead(*body
, kChunks
+ 1),
3514 MockRead(ASYNC
, 0, kChunks
+ 2) // EOF
3517 SequencedSocketData
data(reads
, arraysize(reads
), writes
.get(), kChunks
);
3518 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
3519 BoundNetLog(), GetParam(), NULL
);
3520 helper
.RunToCompletion(&data
);
3521 TransactionHelperResult out
= helper
.output();
3522 EXPECT_EQ(OK
, out
.rv
);
3523 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
3524 EXPECT_EQ("hello!", out
.response_data
);
3527 // In this test, we enable compression, but get a uncompressed SynReply from
3528 // the server. Verify that teardown is all clean.
3529 TEST_P(SpdyNetworkTransactionTest
, DecompressFailureOnSynReply
) {
3530 if (spdy_util_
.spdy_version() >= SPDY4
) {
3531 // HPACK doesn't use deflate compression.
3534 scoped_ptr
<SpdyFrame
> compressed(
3535 spdy_util_
.ConstructSpdyGet(NULL
, 0, true, 1, LOWEST
, true));
3536 scoped_ptr
<SpdyFrame
> goaway(spdy_util_
.ConstructSpdyGoAway(
3537 0, GOAWAY_COMPRESSION_ERROR
, "Framer error: 5 (DECOMPRESS_FAILURE)."));
3538 MockWrite writes
[] = {CreateMockWrite(*compressed
, 0),
3539 CreateMockWrite(*goaway
, 2)};
3541 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
3542 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
3543 MockRead reads
[] = {
3544 CreateMockRead(*resp
, 1),
3547 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
3548 SpdySessionDependencies
* session_deps
=
3549 CreateSpdySessionDependencies(GetParam());
3550 session_deps
->enable_compression
= true;
3551 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
3552 BoundNetLog(), GetParam(), session_deps
);
3553 helper
.RunToCompletion(&data
);
3554 TransactionHelperResult out
= helper
.output();
3555 EXPECT_EQ(ERR_SPDY_COMPRESSION_ERROR
, out
.rv
);
3559 // Test that the NetLog contains good data for a simple GET request.
3560 TEST_P(SpdyNetworkTransactionTest
, NetLog
) {
3561 static const char* const kExtraHeaders
[] = {
3562 "user-agent", "Chrome",
3564 scoped_ptr
<SpdyFrame
> req(
3565 spdy_util_
.ConstructSpdyGet(kExtraHeaders
, 1, false, 1, LOWEST
, true));
3566 MockWrite writes
[] = {CreateMockWrite(*req
, 0)};
3568 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
3569 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
3570 MockRead reads
[] = {
3571 CreateMockRead(*resp
, 1),
3572 CreateMockRead(*body
, 2),
3573 MockRead(ASYNC
, 0, 3) // EOF
3576 BoundTestNetLog log
;
3578 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
3579 NormalSpdyTransactionHelper
helper(CreateGetRequestWithUserAgent(),
3581 log
.bound(), GetParam(), NULL
);
3582 helper
.RunToCompletion(&data
);
3583 TransactionHelperResult out
= helper
.output();
3584 EXPECT_EQ(OK
, out
.rv
);
3585 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
3586 EXPECT_EQ("hello!", out
.response_data
);
3588 // Check that the NetLog was filled reasonably.
3589 // This test is intentionally non-specific about the exact ordering of the
3590 // log; instead we just check to make sure that certain events exist, and that
3591 // they are in the right order.
3592 TestNetLogEntry::List entries
;
3593 log
.GetEntries(&entries
);
3595 EXPECT_LT(0u, entries
.size());
3597 pos
= ExpectLogContainsSomewhere(entries
, 0,
3598 NetLog::TYPE_HTTP_TRANSACTION_SEND_REQUEST
,
3599 NetLog::PHASE_BEGIN
);
3600 pos
= ExpectLogContainsSomewhere(entries
, pos
+ 1,
3601 NetLog::TYPE_HTTP_TRANSACTION_SEND_REQUEST
,
3603 pos
= ExpectLogContainsSomewhere(entries
, pos
+ 1,
3604 NetLog::TYPE_HTTP_TRANSACTION_READ_HEADERS
,
3605 NetLog::PHASE_BEGIN
);
3606 pos
= ExpectLogContainsSomewhere(entries
, pos
+ 1,
3607 NetLog::TYPE_HTTP_TRANSACTION_READ_HEADERS
,
3609 pos
= ExpectLogContainsSomewhere(entries
, pos
+ 1,
3610 NetLog::TYPE_HTTP_TRANSACTION_READ_BODY
,
3611 NetLog::PHASE_BEGIN
);
3612 pos
= ExpectLogContainsSomewhere(entries
, pos
+ 1,
3613 NetLog::TYPE_HTTP_TRANSACTION_READ_BODY
,
3616 // Check that we logged all the headers correctly
3617 const NetLog::EventType type
= (GetParam().protocol
<= kProtoSPDY31
)
3618 ? NetLog::TYPE_HTTP2_SESSION_SYN_STREAM
3619 : NetLog::TYPE_HTTP2_SESSION_SEND_HEADERS
;
3620 pos
= ExpectLogContainsSomewhere(entries
, 0, type
, NetLog::PHASE_NONE
);
3622 base::ListValue
* header_list
;
3623 ASSERT_TRUE(entries
[pos
].params
.get());
3624 ASSERT_TRUE(entries
[pos
].params
->GetList("headers", &header_list
));
3626 std::vector
<std::string
> expected
;
3627 expected
.push_back(std::string(spdy_util_
.GetHostKey()) +
3628 ": www.example.org");
3629 expected
.push_back(std::string(spdy_util_
.GetPathKey()) + ": /");
3630 expected
.push_back(std::string(spdy_util_
.GetSchemeKey()) + ": " +
3631 spdy_util_
.default_url().scheme());
3632 expected
.push_back(std::string(spdy_util_
.GetMethodKey()) + ": GET");
3633 expected
.push_back("user-agent: Chrome");
3634 if (spdy_util_
.spdy_version() < SPDY4
) {
3635 // SPDY4/HTTP2 eliminates use of the :version header.
3636 expected
.push_back(std::string(spdy_util_
.GetVersionKey()) + ": HTTP/1.1");
3638 EXPECT_EQ(expected
.size(), header_list
->GetSize());
3639 for (std::vector
<std::string
>::const_iterator it
= expected
.begin();
3640 it
!= expected
.end();
3642 base::StringValue
header(*it
);
3643 EXPECT_NE(header_list
->end(), header_list
->Find(header
)) <<
3644 "Header not found: " << *it
;
3648 // Since we buffer the IO from the stream to the renderer, this test verifies
3649 // that when we read out the maximum amount of data (e.g. we received 50 bytes
3650 // on the network, but issued a Read for only 5 of those bytes) that the data
3651 // flow still works correctly.
3652 TEST_P(SpdyNetworkTransactionTest
, BufferFull
) {
3653 BufferedSpdyFramer
framer(spdy_util_
.spdy_version(), false);
3655 scoped_ptr
<SpdyFrame
> req(
3656 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
3657 MockWrite writes
[] = {CreateMockWrite(*req
, 0)};
3659 // 2 data frames in a single read.
3660 scoped_ptr
<SpdyFrame
> data_frame_1(
3661 framer
.CreateDataFrame(1, "goodby", 6, DATA_FLAG_NONE
));
3662 scoped_ptr
<SpdyFrame
> data_frame_2(
3663 framer
.CreateDataFrame(1, "e worl", 6, DATA_FLAG_NONE
));
3664 const SpdyFrame
* data_frames
[2] = {
3668 char combined_data_frames
[100];
3669 int combined_data_frames_len
=
3670 CombineFrames(data_frames
, arraysize(data_frames
),
3671 combined_data_frames
, arraysize(combined_data_frames
));
3672 scoped_ptr
<SpdyFrame
> last_frame(
3673 framer
.CreateDataFrame(1, "d", 1, DATA_FLAG_FIN
));
3675 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
3676 MockRead reads
[] = {
3677 CreateMockRead(*resp
),
3678 MockRead(ASYNC
, ERR_IO_PENDING
), // Force a pause
3679 MockRead(ASYNC
, combined_data_frames
, combined_data_frames_len
),
3680 MockRead(ASYNC
, ERR_IO_PENDING
), // Force a pause
3681 CreateMockRead(*last_frame
),
3682 MockRead(ASYNC
, 0, 0) // EOF
3685 DelayedSocketData
data(1, reads
, arraysize(reads
),
3686 writes
, arraysize(writes
));
3688 TestCompletionCallback callback
;
3690 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
3691 BoundNetLog(), GetParam(), NULL
);
3692 helper
.RunPreTestSetup();
3693 helper
.AddData(&data
);
3694 HttpNetworkTransaction
* trans
= helper
.trans();
3695 int rv
= trans
->Start(
3696 &CreateGetRequest(), callback
.callback(), BoundNetLog());
3697 EXPECT_EQ(ERR_IO_PENDING
, rv
);
3699 TransactionHelperResult out
= helper
.output();
3700 out
.rv
= callback
.WaitForResult();
3701 EXPECT_EQ(out
.rv
, OK
);
3703 const HttpResponseInfo
* response
= trans
->GetResponseInfo();
3704 EXPECT_TRUE(response
->headers
.get() != NULL
);
3705 EXPECT_TRUE(response
->was_fetched_via_spdy
);
3706 out
.status_line
= response
->headers
->GetStatusLine();
3707 out
.response_info
= *response
; // Make a copy so we can verify.
3710 TestCompletionCallback read_callback
;
3712 std::string content
;
3714 // Read small chunks at a time.
3715 const int kSmallReadSize
= 3;
3716 scoped_refptr
<IOBuffer
> buf(new IOBuffer(kSmallReadSize
));
3717 rv
= trans
->Read(buf
.get(), kSmallReadSize
, read_callback
.callback());
3718 if (rv
== ERR_IO_PENDING
) {
3719 data
.CompleteRead();
3720 rv
= read_callback
.WaitForResult();
3723 content
.append(buf
->data(), rv
);
3724 } else if (rv
< 0) {
3729 out
.response_data
.swap(content
);
3731 // Flush the MessageLoop while the SpdySessionDependencies (in particular, the
3732 // MockClientSocketFactory) are still alive.
3733 base::RunLoop().RunUntilIdle();
3735 // Verify that we consumed all test data.
3736 helper
.VerifyDataConsumed();
3738 EXPECT_EQ(OK
, out
.rv
);
3739 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
3740 EXPECT_EQ("goodbye world", out
.response_data
);
3743 // Verify that basic buffering works; when multiple data frames arrive
3744 // at the same time, ensure that we don't notify a read completion for
3745 // each data frame individually.
3746 TEST_P(SpdyNetworkTransactionTest
, Buffering
) {
3747 BufferedSpdyFramer
framer(spdy_util_
.spdy_version(), false);
3749 scoped_ptr
<SpdyFrame
> req(
3750 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
3751 MockWrite writes
[] = { CreateMockWrite(*req
) };
3753 // 4 data frames in a single read.
3754 scoped_ptr
<SpdyFrame
> data_frame(
3755 framer
.CreateDataFrame(1, "message", 7, DATA_FLAG_NONE
));
3756 scoped_ptr
<SpdyFrame
> data_frame_fin(
3757 framer
.CreateDataFrame(1, "message", 7, DATA_FLAG_FIN
));
3758 const SpdyFrame
* data_frames
[4] = {
3762 data_frame_fin
.get()
3764 char combined_data_frames
[100];
3765 int combined_data_frames_len
=
3766 CombineFrames(data_frames
, arraysize(data_frames
),
3767 combined_data_frames
, arraysize(combined_data_frames
));
3769 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
3770 MockRead reads
[] = {
3771 CreateMockRead(*resp
),
3772 MockRead(ASYNC
, ERR_IO_PENDING
), // Force a pause
3773 MockRead(ASYNC
, combined_data_frames
, combined_data_frames_len
),
3774 MockRead(ASYNC
, 0, 0) // EOF
3777 DelayedSocketData
data(1, reads
, arraysize(reads
),
3778 writes
, arraysize(writes
));
3780 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
3781 BoundNetLog(), GetParam(), NULL
);
3782 helper
.RunPreTestSetup();
3783 helper
.AddData(&data
);
3784 HttpNetworkTransaction
* trans
= helper
.trans();
3786 TestCompletionCallback callback
;
3787 int rv
= trans
->Start(
3788 &CreateGetRequest(), callback
.callback(), BoundNetLog());
3789 EXPECT_EQ(ERR_IO_PENDING
, rv
);
3791 TransactionHelperResult out
= helper
.output();
3792 out
.rv
= callback
.WaitForResult();
3793 EXPECT_EQ(out
.rv
, OK
);
3795 const HttpResponseInfo
* response
= trans
->GetResponseInfo();
3796 EXPECT_TRUE(response
->headers
.get() != NULL
);
3797 EXPECT_TRUE(response
->was_fetched_via_spdy
);
3798 out
.status_line
= response
->headers
->GetStatusLine();
3799 out
.response_info
= *response
; // Make a copy so we can verify.
3802 TestCompletionCallback read_callback
;
3804 std::string content
;
3805 int reads_completed
= 0;
3807 // Read small chunks at a time.
3808 const int kSmallReadSize
= 14;
3809 scoped_refptr
<IOBuffer
> buf(new IOBuffer(kSmallReadSize
));
3810 rv
= trans
->Read(buf
.get(), kSmallReadSize
, read_callback
.callback());
3811 if (rv
== ERR_IO_PENDING
) {
3812 data
.CompleteRead();
3813 rv
= read_callback
.WaitForResult();
3816 EXPECT_EQ(kSmallReadSize
, rv
);
3817 content
.append(buf
->data(), rv
);
3818 } else if (rv
< 0) {
3819 FAIL() << "Unexpected read error: " << rv
;
3824 EXPECT_EQ(3, reads_completed
); // Reads are: 14 bytes, 14 bytes, 0 bytes.
3826 out
.response_data
.swap(content
);
3828 // Flush the MessageLoop while the SpdySessionDependencies (in particular, the
3829 // MockClientSocketFactory) are still alive.
3830 base::RunLoop().RunUntilIdle();
3832 // Verify that we consumed all test data.
3833 helper
.VerifyDataConsumed();
3835 EXPECT_EQ(OK
, out
.rv
);
3836 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
3837 EXPECT_EQ("messagemessagemessagemessage", out
.response_data
);
3840 // Verify the case where we buffer data but read it after it has been buffered.
3841 TEST_P(SpdyNetworkTransactionTest
, BufferedAll
) {
3842 BufferedSpdyFramer
framer(spdy_util_
.spdy_version(), false);
3844 scoped_ptr
<SpdyFrame
> req(
3845 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
3846 MockWrite writes
[] = {CreateMockWrite(*req
, 0)};
3848 // 5 data frames in a single read.
3849 scoped_ptr
<SpdyFrame
> reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
3850 scoped_ptr
<SpdyFrame
> data_frame(
3851 framer
.CreateDataFrame(1, "message", 7, DATA_FLAG_NONE
));
3852 scoped_ptr
<SpdyFrame
> data_frame_fin(
3853 framer
.CreateDataFrame(1, "message", 7, DATA_FLAG_FIN
));
3854 const SpdyFrame
* frames
[5] = {reply
.get(), data_frame
.get(), data_frame
.get(),
3855 data_frame
.get(), data_frame_fin
.get()};
3856 char combined_frames
[200];
3857 int combined_frames_len
=
3858 CombineFrames(frames
, arraysize(frames
),
3859 combined_frames
, arraysize(combined_frames
));
3861 MockRead reads
[] = {
3862 MockRead(ASYNC
, combined_frames
, combined_frames_len
, 1),
3863 MockRead(ASYNC
, 0, 2) // EOF
3866 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
3868 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
3869 BoundNetLog(), GetParam(), NULL
);
3870 helper
.RunPreTestSetup();
3871 helper
.AddData(&data
);
3872 HttpNetworkTransaction
* trans
= helper
.trans();
3874 TestCompletionCallback callback
;
3875 int rv
= trans
->Start(
3876 &CreateGetRequest(), callback
.callback(), BoundNetLog());
3877 EXPECT_EQ(ERR_IO_PENDING
, rv
);
3879 TransactionHelperResult out
= helper
.output();
3880 out
.rv
= callback
.WaitForResult();
3881 EXPECT_EQ(out
.rv
, OK
);
3883 const HttpResponseInfo
* response
= trans
->GetResponseInfo();
3884 EXPECT_TRUE(response
->headers
.get() != NULL
);
3885 EXPECT_TRUE(response
->was_fetched_via_spdy
);
3886 out
.status_line
= response
->headers
->GetStatusLine();
3887 out
.response_info
= *response
; // Make a copy so we can verify.
3890 TestCompletionCallback read_callback
;
3892 std::string content
;
3893 int reads_completed
= 0;
3895 // Read small chunks at a time.
3896 const int kSmallReadSize
= 14;
3897 scoped_refptr
<IOBuffer
> buf(new IOBuffer(kSmallReadSize
));
3898 rv
= trans
->Read(buf
.get(), kSmallReadSize
, read_callback
.callback());
3900 EXPECT_EQ(kSmallReadSize
, rv
);
3901 content
.append(buf
->data(), rv
);
3902 } else if (rv
< 0) {
3903 FAIL() << "Unexpected read error: " << rv
;
3908 EXPECT_EQ(3, reads_completed
);
3910 out
.response_data
.swap(content
);
3912 // Flush the MessageLoop while the SpdySessionDependencies (in particular, the
3913 // MockClientSocketFactory) are still alive.
3914 base::RunLoop().RunUntilIdle();
3916 // Verify that we consumed all test data.
3917 helper
.VerifyDataConsumed();
3919 EXPECT_EQ(OK
, out
.rv
);
3920 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
3921 EXPECT_EQ("messagemessagemessagemessage", out
.response_data
);
3924 // Verify the case where we buffer data and close the connection.
3925 TEST_P(SpdyNetworkTransactionTest
, BufferedClosed
) {
3926 BufferedSpdyFramer
framer(spdy_util_
.spdy_version(), false);
3928 scoped_ptr
<SpdyFrame
> req(
3929 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
3930 MockWrite writes
[] = { CreateMockWrite(*req
) };
3932 // All data frames in a single read.
3933 // NOTE: We don't FIN the stream.
3934 scoped_ptr
<SpdyFrame
> data_frame(
3935 framer
.CreateDataFrame(1, "message", 7, DATA_FLAG_NONE
));
3936 const SpdyFrame
* data_frames
[4] = {
3942 char combined_data_frames
[100];
3943 int combined_data_frames_len
=
3944 CombineFrames(data_frames
, arraysize(data_frames
),
3945 combined_data_frames
, arraysize(combined_data_frames
));
3946 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
3947 MockRead reads
[] = {
3948 CreateMockRead(*resp
),
3949 MockRead(ASYNC
, ERR_IO_PENDING
), // Force a wait
3950 MockRead(ASYNC
, combined_data_frames
, combined_data_frames_len
),
3951 MockRead(ASYNC
, 0, 0) // EOF
3954 DelayedSocketData
data(1, reads
, arraysize(reads
),
3955 writes
, arraysize(writes
));
3957 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
3958 BoundNetLog(), GetParam(), NULL
);
3959 helper
.RunPreTestSetup();
3960 helper
.AddData(&data
);
3961 HttpNetworkTransaction
* trans
= helper
.trans();
3963 TestCompletionCallback callback
;
3965 int rv
= trans
->Start(
3966 &CreateGetRequest(), callback
.callback(), BoundNetLog());
3967 EXPECT_EQ(ERR_IO_PENDING
, rv
);
3969 TransactionHelperResult out
= helper
.output();
3970 out
.rv
= callback
.WaitForResult();
3971 EXPECT_EQ(out
.rv
, OK
);
3973 const HttpResponseInfo
* response
= trans
->GetResponseInfo();
3974 EXPECT_TRUE(response
->headers
.get() != NULL
);
3975 EXPECT_TRUE(response
->was_fetched_via_spdy
);
3976 out
.status_line
= response
->headers
->GetStatusLine();
3977 out
.response_info
= *response
; // Make a copy so we can verify.
3980 TestCompletionCallback read_callback
;
3982 std::string content
;
3983 int reads_completed
= 0;
3985 // Read small chunks at a time.
3986 const int kSmallReadSize
= 14;
3987 scoped_refptr
<IOBuffer
> buf(new IOBuffer(kSmallReadSize
));
3988 rv
= trans
->Read(buf
.get(), kSmallReadSize
, read_callback
.callback());
3989 if (rv
== ERR_IO_PENDING
) {
3990 data
.CompleteRead();
3991 rv
= read_callback
.WaitForResult();
3994 content
.append(buf
->data(), rv
);
3995 } else if (rv
< 0) {
3996 // This test intentionally closes the connection, and will get an error.
3997 EXPECT_EQ(ERR_CONNECTION_CLOSED
, rv
);
4003 EXPECT_EQ(0, reads_completed
);
4005 out
.response_data
.swap(content
);
4007 // Flush the MessageLoop while the SpdySessionDependencies (in particular, the
4008 // MockClientSocketFactory) are still alive.
4009 base::RunLoop().RunUntilIdle();
4011 // Verify that we consumed all test data.
4012 helper
.VerifyDataConsumed();
4015 // Verify the case where we buffer data and cancel the transaction.
4016 TEST_P(SpdyNetworkTransactionTest
, BufferedCancelled
) {
4017 BufferedSpdyFramer
framer(spdy_util_
.spdy_version(), false);
4019 scoped_ptr
<SpdyFrame
> req(
4020 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
4021 scoped_ptr
<SpdyFrame
> rst(
4022 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_CANCEL
));
4023 MockWrite writes
[] = {CreateMockWrite(*req
), CreateMockWrite(*rst
)};
4025 // NOTE: We don't FIN the stream.
4026 scoped_ptr
<SpdyFrame
> data_frame(
4027 framer
.CreateDataFrame(1, "message", 7, DATA_FLAG_NONE
));
4029 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
4030 MockRead reads
[] = {
4031 CreateMockRead(*resp
),
4032 MockRead(ASYNC
, ERR_IO_PENDING
), // Force a wait
4033 CreateMockRead(*data_frame
),
4034 MockRead(ASYNC
, 0, 0) // EOF
4037 DelayedSocketData
data(1, reads
, arraysize(reads
),
4038 writes
, arraysize(writes
));
4040 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
4041 BoundNetLog(), GetParam(), NULL
);
4042 helper
.RunPreTestSetup();
4043 helper
.AddData(&data
);
4044 HttpNetworkTransaction
* trans
= helper
.trans();
4045 TestCompletionCallback callback
;
4047 int rv
= trans
->Start(
4048 &CreateGetRequest(), callback
.callback(), BoundNetLog());
4049 EXPECT_EQ(ERR_IO_PENDING
, rv
);
4051 TransactionHelperResult out
= helper
.output();
4052 out
.rv
= callback
.WaitForResult();
4053 EXPECT_EQ(out
.rv
, OK
);
4055 const HttpResponseInfo
* response
= trans
->GetResponseInfo();
4056 EXPECT_TRUE(response
->headers
.get() != NULL
);
4057 EXPECT_TRUE(response
->was_fetched_via_spdy
);
4058 out
.status_line
= response
->headers
->GetStatusLine();
4059 out
.response_info
= *response
; // Make a copy so we can verify.
4062 TestCompletionCallback read_callback
;
4064 const int kReadSize
= 256;
4065 scoped_refptr
<IOBuffer
> buf(new IOBuffer(kReadSize
));
4066 rv
= trans
->Read(buf
.get(), kReadSize
, read_callback
.callback());
4067 ASSERT_EQ(ERR_IO_PENDING
, rv
) << "Unexpected read: " << rv
;
4069 // Complete the read now, which causes buffering to start.
4070 data
.CompleteRead();
4071 // Destroy the transaction, causing the stream to get cancelled
4072 // and orphaning the buffered IO task.
4073 helper
.ResetTrans();
4075 // Flush the MessageLoop; this will cause the buffered IO task
4076 // to run for the final time.
4077 base::RunLoop().RunUntilIdle();
4079 // Verify that we consumed all test data.
4080 helper
.VerifyDataConsumed();
4083 // Test that if the server requests persistence of settings, that we save
4084 // the settings in the HttpServerProperties.
4085 TEST_P(SpdyNetworkTransactionTest
, SettingsSaved
) {
4086 if (spdy_util_
.spdy_version() >= SPDY4
) {
4087 // SPDY4 doesn't support settings persistence.
4090 static const SpdyHeaderInfo kSynReplyInfo
= {
4091 SYN_REPLY
, // Syn Reply
4093 0, // Associated Stream ID
4094 ConvertRequestPriorityToSpdyPriority(
4095 LOWEST
, spdy_util_
.spdy_version()),
4096 kSpdyCredentialSlotUnused
,
4097 CONTROL_FLAG_NONE
, // Control Flags
4098 false, // Compressed
4099 RST_STREAM_INVALID
, // Status
4102 DATA_FLAG_NONE
// Data Flags
4105 BoundNetLog net_log
;
4106 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
4107 net_log
, GetParam(), NULL
);
4108 helper
.RunPreTestSetup();
4110 // Verify that no settings exist initially.
4111 HostPortPair
host_port_pair("www.example.org", helper
.port());
4112 SpdySessionPool
* spdy_session_pool
= helper
.session()->spdy_session_pool();
4113 EXPECT_TRUE(spdy_session_pool
->http_server_properties()->GetSpdySettings(
4114 host_port_pair
).empty());
4116 // Construct the request.
4117 scoped_ptr
<SpdyFrame
> req(
4118 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
4119 MockWrite writes
[] = {CreateMockWrite(*req
, 0)};
4121 // Construct the reply.
4122 scoped_ptr
<SpdyHeaderBlock
> reply_headers(new SpdyHeaderBlock());
4123 (*reply_headers
)[spdy_util_
.GetStatusKey()] = "200";
4124 (*reply_headers
)[spdy_util_
.GetVersionKey()] = "HTTP/1.1";
4125 scoped_ptr
<SpdyFrame
> reply(
4126 spdy_util_
.ConstructSpdyFrame(kSynReplyInfo
, reply_headers
.Pass()));
4128 const SpdySettingsIds kSampleId1
= SETTINGS_UPLOAD_BANDWIDTH
;
4129 unsigned int kSampleValue1
= 0x0a0a0a0a;
4130 const SpdySettingsIds kSampleId2
= SETTINGS_DOWNLOAD_BANDWIDTH
;
4131 unsigned int kSampleValue2
= 0x0b0b0b0b;
4132 const SpdySettingsIds kSampleId3
= SETTINGS_ROUND_TRIP_TIME
;
4133 unsigned int kSampleValue3
= 0x0c0c0c0c;
4134 scoped_ptr
<SpdyFrame
> settings_frame
;
4136 // Construct the SETTINGS frame.
4137 SettingsMap settings
;
4138 // First add a persisted setting.
4139 settings
[kSampleId1
] =
4140 SettingsFlagsAndValue(SETTINGS_FLAG_PLEASE_PERSIST
, kSampleValue1
);
4141 // Next add a non-persisted setting.
4142 settings
[kSampleId2
] =
4143 SettingsFlagsAndValue(SETTINGS_FLAG_NONE
, kSampleValue2
);
4144 // Next add another persisted setting.
4145 settings
[kSampleId3
] =
4146 SettingsFlagsAndValue(SETTINGS_FLAG_PLEASE_PERSIST
, kSampleValue3
);
4147 settings_frame
.reset(spdy_util_
.ConstructSpdySettings(settings
));
4150 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
4151 MockRead reads
[] = {
4152 CreateMockRead(*reply
, 1),
4153 CreateMockRead(*body
, 2),
4154 CreateMockRead(*settings_frame
, 3),
4155 MockRead(ASYNC
, 0, 4) // EOF
4158 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
4159 helper
.AddData(&data
);
4160 helper
.RunDefaultTest();
4161 helper
.VerifyDataConsumed();
4162 TransactionHelperResult out
= helper
.output();
4163 EXPECT_EQ(OK
, out
.rv
);
4164 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
4165 EXPECT_EQ("hello!", out
.response_data
);
4168 // Verify we had two persisted settings.
4169 const SettingsMap
& settings_map
=
4170 spdy_session_pool
->http_server_properties()->GetSpdySettings(
4172 ASSERT_EQ(2u, settings_map
.size());
4174 // Verify the first persisted setting.
4175 SettingsMap::const_iterator it1
= settings_map
.find(kSampleId1
);
4176 EXPECT_TRUE(it1
!= settings_map
.end());
4177 SettingsFlagsAndValue flags_and_value1
= it1
->second
;
4178 EXPECT_EQ(SETTINGS_FLAG_PERSISTED
, flags_and_value1
.first
);
4179 EXPECT_EQ(kSampleValue1
, flags_and_value1
.second
);
4181 // Verify the second persisted setting.
4182 SettingsMap::const_iterator it3
= settings_map
.find(kSampleId3
);
4183 EXPECT_TRUE(it3
!= settings_map
.end());
4184 SettingsFlagsAndValue flags_and_value3
= it3
->second
;
4185 EXPECT_EQ(SETTINGS_FLAG_PERSISTED
, flags_and_value3
.first
);
4186 EXPECT_EQ(kSampleValue3
, flags_and_value3
.second
);
4190 // Test that when there are settings saved that they are sent back to the
4191 // server upon session establishment.
4192 TEST_P(SpdyNetworkTransactionTest
, SettingsPlayback
) {
4193 if (spdy_util_
.spdy_version() >= SPDY4
) {
4194 // SPDY4 doesn't support settings persistence.
4197 static const SpdyHeaderInfo kSynReplyInfo
= {
4198 SYN_REPLY
, // Syn Reply
4200 0, // Associated Stream ID
4201 ConvertRequestPriorityToSpdyPriority(
4202 LOWEST
, spdy_util_
.spdy_version()),
4203 kSpdyCredentialSlotUnused
,
4204 CONTROL_FLAG_NONE
, // Control Flags
4205 false, // Compressed
4206 RST_STREAM_INVALID
, // Status
4209 DATA_FLAG_NONE
// Data Flags
4212 BoundNetLog net_log
;
4213 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
4214 net_log
, GetParam(), NULL
);
4215 helper
.RunPreTestSetup();
4217 SpdySessionPool
* spdy_session_pool
= helper
.session()->spdy_session_pool();
4219 SpdySessionPoolPeer
pool_peer(spdy_session_pool
);
4220 pool_peer
.SetEnableSendingInitialData(true);
4222 // Verify that no settings exist initially.
4223 HostPortPair
host_port_pair("www.example.org", helper
.port());
4224 EXPECT_TRUE(spdy_session_pool
->http_server_properties()->GetSpdySettings(
4225 host_port_pair
).empty());
4227 const SpdySettingsIds kSampleId1
= SETTINGS_MAX_CONCURRENT_STREAMS
;
4228 unsigned int kSampleValue1
= 0x0a0a0a0a;
4229 const SpdySettingsIds kSampleId2
= SETTINGS_INITIAL_WINDOW_SIZE
;
4230 unsigned int kSampleValue2
= 0x0c0c0c0c;
4232 // First add a persisted setting.
4233 spdy_session_pool
->http_server_properties()->SetSpdySetting(
4236 SETTINGS_FLAG_PLEASE_PERSIST
,
4239 // Next add another persisted setting.
4240 spdy_session_pool
->http_server_properties()->SetSpdySetting(
4243 SETTINGS_FLAG_PLEASE_PERSIST
,
4246 EXPECT_EQ(2u, spdy_session_pool
->http_server_properties()->GetSpdySettings(
4247 host_port_pair
).size());
4249 // Construct the initial SETTINGS frame.
4250 SettingsMap initial_settings
;
4251 initial_settings
[SETTINGS_MAX_CONCURRENT_STREAMS
] =
4252 SettingsFlagsAndValue(SETTINGS_FLAG_NONE
, kMaxConcurrentPushedStreams
);
4253 scoped_ptr
<SpdyFrame
> initial_settings_frame(
4254 spdy_util_
.ConstructSpdySettings(initial_settings
));
4256 // Construct the persisted SETTINGS frame.
4257 const SettingsMap
& settings
=
4258 spdy_session_pool
->http_server_properties()->GetSpdySettings(
4260 scoped_ptr
<SpdyFrame
> settings_frame(
4261 spdy_util_
.ConstructSpdySettings(settings
));
4263 // Construct the request.
4264 scoped_ptr
<SpdyFrame
> req(
4265 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
4267 std::vector
<MockWrite
> writes
;
4268 if ((GetParam().protocol
>= kProtoSPDY4MinimumVersion
) &&
4269 (GetParam().protocol
<= kProtoSPDY4MaximumVersion
)) {
4272 kHttp2ConnectionHeaderPrefix
,
4273 kHttp2ConnectionHeaderPrefixSize
));
4275 writes
.push_back(CreateMockWrite(*initial_settings_frame
));
4276 writes
.push_back(CreateMockWrite(*settings_frame
));
4277 writes
.push_back(CreateMockWrite(*req
));
4279 // Construct the reply.
4280 scoped_ptr
<SpdyHeaderBlock
> reply_headers(new SpdyHeaderBlock());
4281 (*reply_headers
)[spdy_util_
.GetStatusKey()] = "200";
4282 (*reply_headers
)[spdy_util_
.GetVersionKey()] = "HTTP/1.1";
4283 scoped_ptr
<SpdyFrame
> reply(
4284 spdy_util_
.ConstructSpdyFrame(kSynReplyInfo
, reply_headers
.Pass()));
4286 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
4287 MockRead reads
[] = {
4288 CreateMockRead(*reply
),
4289 CreateMockRead(*body
),
4290 MockRead(ASYNC
, 0, 0) // EOF
4293 DelayedSocketData
data(2, reads
, arraysize(reads
),
4294 vector_as_array(&writes
), writes
.size());
4295 helper
.AddData(&data
);
4296 helper
.RunDefaultTest();
4297 helper
.VerifyDataConsumed();
4298 TransactionHelperResult out
= helper
.output();
4299 EXPECT_EQ(OK
, out
.rv
);
4300 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
4301 EXPECT_EQ("hello!", out
.response_data
);
4304 // Verify we had two persisted settings.
4305 const SettingsMap
& settings_map
=
4306 spdy_session_pool
->http_server_properties()->GetSpdySettings(
4308 ASSERT_EQ(2u, settings_map
.size());
4310 // Verify the first persisted setting.
4311 SettingsMap::const_iterator it1
= settings_map
.find(kSampleId1
);
4312 EXPECT_TRUE(it1
!= settings_map
.end());
4313 SettingsFlagsAndValue flags_and_value1
= it1
->second
;
4314 EXPECT_EQ(SETTINGS_FLAG_PERSISTED
, flags_and_value1
.first
);
4315 EXPECT_EQ(kSampleValue1
, flags_and_value1
.second
);
4317 // Verify the second persisted setting.
4318 SettingsMap::const_iterator it2
= settings_map
.find(kSampleId2
);
4319 EXPECT_TRUE(it2
!= settings_map
.end());
4320 SettingsFlagsAndValue flags_and_value2
= it2
->second
;
4321 EXPECT_EQ(SETTINGS_FLAG_PERSISTED
, flags_and_value2
.first
);
4322 EXPECT_EQ(kSampleValue2
, flags_and_value2
.second
);
4326 TEST_P(SpdyNetworkTransactionTest
, GoAwayWithActiveStream
) {
4327 scoped_ptr
<SpdyFrame
> req(
4328 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
4329 MockWrite writes
[] = {CreateMockWrite(*req
, 0)};
4331 scoped_ptr
<SpdyFrame
> go_away(spdy_util_
.ConstructSpdyGoAway());
4332 MockRead reads
[] = {
4333 CreateMockRead(*go_away
, 1),
4336 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
4337 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
4338 BoundNetLog(), GetParam(), NULL
);
4339 helper
.AddData(&data
);
4340 helper
.RunToCompletion(&data
);
4341 TransactionHelperResult out
= helper
.output();
4342 EXPECT_EQ(ERR_ABORTED
, out
.rv
);
4345 TEST_P(SpdyNetworkTransactionTest
, CloseWithActiveStream
) {
4346 scoped_ptr
<SpdyFrame
> req(
4347 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
4348 MockWrite writes
[] = {CreateMockWrite(*req
, 0)};
4350 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
4351 MockRead reads
[] = {
4352 CreateMockRead(*resp
, 1), MockRead(SYNCHRONOUS
, 0, 2) // EOF
4355 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
4357 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
4358 log
, GetParam(), NULL
);
4359 helper
.RunPreTestSetup();
4360 helper
.AddData(&data
);
4361 HttpNetworkTransaction
* trans
= helper
.trans();
4363 TestCompletionCallback callback
;
4364 TransactionHelperResult out
;
4365 out
.rv
= trans
->Start(&CreateGetRequest(), callback
.callback(), log
);
4367 EXPECT_EQ(out
.rv
, ERR_IO_PENDING
);
4368 out
.rv
= callback
.WaitForResult();
4369 EXPECT_EQ(out
.rv
, OK
);
4371 const HttpResponseInfo
* response
= trans
->GetResponseInfo();
4372 EXPECT_TRUE(response
->headers
.get() != NULL
);
4373 EXPECT_TRUE(response
->was_fetched_via_spdy
);
4374 out
.rv
= ReadTransaction(trans
, &out
.response_data
);
4375 EXPECT_EQ(ERR_CONNECTION_CLOSED
, out
.rv
);
4377 // Verify that we consumed all test data.
4378 helper
.VerifyDataConsumed();
4381 // HTTP_1_1_REQUIRED results in ERR_HTTP_1_1_REQUIRED.
4382 TEST_P(SpdyNetworkTransactionTest
, HTTP11RequiredError
) {
4383 // HTTP_1_1_REQUIRED is only supported by SPDY4.
4384 if (spdy_util_
.spdy_version() < SPDY4
)
4387 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
4388 BoundNetLog(), GetParam(), nullptr);
4390 scoped_ptr
<SpdyFrame
> go_away(spdy_util_
.ConstructSpdyGoAway(
4391 0, GOAWAY_HTTP_1_1_REQUIRED
, "Try again using HTTP/1.1 please."));
4392 MockRead reads
[] = {
4393 CreateMockRead(*go_away
, 0),
4395 SequencedSocketData
data(reads
, arraysize(reads
), nullptr, 0);
4397 helper
.RunToCompletion(&data
);
4398 TransactionHelperResult out
= helper
.output();
4399 EXPECT_EQ(ERR_HTTP_1_1_REQUIRED
, out
.rv
);
4402 // Retry with HTTP/1.1 when receiving HTTP_1_1_REQUIRED. Note that no actual
4403 // protocol negotiation happens, instead this test forces protocols for both
4405 TEST_P(SpdyNetworkTransactionTest
, HTTP11RequiredRetry
) {
4406 // HTTP_1_1_REQUIRED is only supported by SPDY4.
4407 if (spdy_util_
.spdy_version() < SPDY4
)
4409 // HTTP_1_1_REQUIRED implementation relies on the assumption that HTTP/2 is
4410 // only spoken over SSL.
4411 if (GetParam().ssl_type
!= HTTPS_SPDY_VIA_NPN
)
4414 HttpRequestInfo request
;
4415 request
.method
= "GET";
4416 request
.url
= GURL("https://www.example.org/");
4417 scoped_ptr
<SpdySessionDependencies
> session_deps(
4418 CreateSpdySessionDependencies(GetParam()));
4419 // Do not force SPDY so that second socket can negotiate HTTP/1.1.
4420 session_deps
->next_protos
= SpdyNextProtos();
4421 NormalSpdyTransactionHelper
helper(request
, DEFAULT_PRIORITY
, BoundNetLog(),
4422 GetParam(), session_deps
.release());
4424 // First socket: HTTP/2 request rejected with HTTP_1_1_REQUIRED.
4425 const char* url
= request
.url
.spec().c_str();
4426 scoped_ptr
<SpdyHeaderBlock
> headers(spdy_util_
.ConstructGetHeaderBlock(url
));
4427 scoped_ptr
<SpdyFrame
> req(
4428 spdy_util_
.ConstructSpdySyn(1, *headers
, LOWEST
, false, true));
4429 MockWrite writes0
[] = {CreateMockWrite(*req
, 0)};
4430 scoped_ptr
<SpdyFrame
> go_away(spdy_util_
.ConstructSpdyGoAway(
4431 0, GOAWAY_HTTP_1_1_REQUIRED
, "Try again using HTTP/1.1 please."));
4432 MockRead reads0
[] = {CreateMockRead(*go_away
, 1)};
4433 SequencedSocketData
data0(reads0
, arraysize(reads0
), writes0
,
4434 arraysize(writes0
));
4436 scoped_ptr
<SSLSocketDataProvider
> ssl_provider0(
4437 new SSLSocketDataProvider(ASYNC
, OK
));
4438 // Expect HTTP/2 protocols too in SSLConfig.
4439 ssl_provider0
->next_protos_expected_in_ssl_config
.push_back(kProtoHTTP11
);
4440 ssl_provider0
->next_protos_expected_in_ssl_config
.push_back(kProtoSPDY31
);
4441 ssl_provider0
->next_protos_expected_in_ssl_config
.push_back(kProtoSPDY4_14
);
4442 ssl_provider0
->next_protos_expected_in_ssl_config
.push_back(kProtoSPDY4
);
4444 ssl_provider0
->SetNextProto(GetParam().protocol
);
4445 helper
.AddDataWithSSLSocketDataProvider(&data0
, ssl_provider0
.Pass());
4447 // Second socket: falling back to HTTP/1.1.
4448 MockWrite writes1
[] = {MockWrite(ASYNC
, 0,
4449 "GET / HTTP/1.1\r\n"
4450 "Host: www.example.org\r\n"
4451 "Connection: keep-alive\r\n\r\n")};
4452 MockRead reads1
[] = {MockRead(ASYNC
, 1,
4453 "HTTP/1.1 200 OK\r\n"
4454 "Content-Length: 5\r\n\r\n"
4456 SequencedSocketData
data1(reads1
, arraysize(reads1
), writes1
,
4457 arraysize(writes1
));
4459 scoped_ptr
<SSLSocketDataProvider
> ssl_provider1(
4460 new SSLSocketDataProvider(ASYNC
, OK
));
4461 // Expect only HTTP/1.1 protocol in SSLConfig.
4462 ssl_provider1
->next_protos_expected_in_ssl_config
.push_back(kProtoHTTP11
);
4464 ssl_provider1
->SetNextProto(kProtoHTTP11
);
4465 helper
.AddDataWithSSLSocketDataProvider(&data1
, ssl_provider1
.Pass());
4467 base::WeakPtr
<HttpServerProperties
> http_server_properties
=
4468 helper
.session()->spdy_session_pool()->http_server_properties();
4469 const HostPortPair host_port_pair
= HostPortPair::FromURL(GURL(url
));
4470 EXPECT_FALSE(http_server_properties
->RequiresHTTP11(host_port_pair
));
4472 helper
.RunPreTestSetup();
4473 helper
.StartDefaultTest();
4474 helper
.FinishDefaultTestWithoutVerification();
4475 helper
.VerifyDataConsumed();
4476 EXPECT_TRUE(http_server_properties
->RequiresHTTP11(host_port_pair
));
4478 const HttpResponseInfo
* response
= helper
.trans()->GetResponseInfo();
4479 ASSERT_TRUE(response
!= nullptr);
4480 ASSERT_TRUE(response
->headers
.get() != nullptr);
4481 EXPECT_EQ("HTTP/1.1 200 OK", response
->headers
->GetStatusLine());
4482 EXPECT_FALSE(response
->was_fetched_via_spdy
);
4483 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP1
, response
->connection_info
);
4484 EXPECT_TRUE(response
->was_npn_negotiated
);
4485 EXPECT_TRUE(request
.url
.SchemeIs("https"));
4486 EXPECT_EQ("127.0.0.1", response
->socket_address
.host());
4487 EXPECT_EQ(443, response
->socket_address
.port());
4488 std::string response_data
;
4489 ASSERT_EQ(OK
, ReadTransaction(helper
.trans(), &response_data
));
4490 EXPECT_EQ("hello", response_data
);
4493 // Retry with HTTP/1.1 to the proxy when receiving HTTP_1_1_REQUIRED from the
4494 // proxy. Note that no actual protocol negotiation happens, instead this test
4495 // forces protocols for both sockets.
4496 TEST_P(SpdyNetworkTransactionTest
, HTTP11RequiredProxyRetry
) {
4497 // HTTP_1_1_REQUIRED is only supported by SPDY4.
4498 if (spdy_util_
.spdy_version() < SPDY4
)
4500 // HTTP_1_1_REQUIRED implementation relies on the assumption that HTTP/2 is
4501 // only spoken over SSL.
4502 if (GetParam().ssl_type
!= HTTPS_SPDY_VIA_NPN
)
4505 HttpRequestInfo request
;
4506 request
.method
= "GET";
4507 request
.url
= GURL("https://www.example.org/");
4508 scoped_ptr
<SpdySessionDependencies
> session_deps(
4509 CreateSpdySessionDependencies(
4511 ProxyService::CreateFixedFromPacResult("HTTPS myproxy:70")));
4512 // Do not force SPDY so that second socket can negotiate HTTP/1.1.
4513 session_deps
->next_protos
= SpdyNextProtos();
4514 NormalSpdyTransactionHelper
helper(request
, DEFAULT_PRIORITY
, BoundNetLog(),
4515 GetParam(), session_deps
.release());
4517 // First socket: HTTP/2 CONNECT rejected with HTTP_1_1_REQUIRED.
4518 scoped_ptr
<SpdyFrame
> req(spdy_util_
.ConstructSpdyConnect(
4519 nullptr, 0, 1, LOWEST
, HostPortPair("www.example.org", 443)));
4520 MockWrite writes0
[] = {CreateMockWrite(*req
, 0)};
4521 scoped_ptr
<SpdyFrame
> go_away(spdy_util_
.ConstructSpdyGoAway(
4522 0, GOAWAY_HTTP_1_1_REQUIRED
, "Try again using HTTP/1.1 please."));
4523 MockRead reads0
[] = {CreateMockRead(*go_away
, 1)};
4524 SequencedSocketData
data0(reads0
, arraysize(reads0
), writes0
,
4525 arraysize(writes0
));
4527 scoped_ptr
<SSLSocketDataProvider
> ssl_provider0(
4528 new SSLSocketDataProvider(ASYNC
, OK
));
4529 // Expect HTTP/2 protocols too in SSLConfig.
4530 ssl_provider0
->next_protos_expected_in_ssl_config
.push_back(kProtoHTTP11
);
4531 ssl_provider0
->next_protos_expected_in_ssl_config
.push_back(kProtoSPDY31
);
4532 ssl_provider0
->next_protos_expected_in_ssl_config
.push_back(kProtoSPDY4_14
);
4533 ssl_provider0
->next_protos_expected_in_ssl_config
.push_back(kProtoSPDY4
);
4535 ssl_provider0
->SetNextProto(GetParam().protocol
);
4536 helper
.AddDataWithSSLSocketDataProvider(&data0
, ssl_provider0
.Pass());
4538 // Second socket: retry using HTTP/1.1.
4539 MockWrite writes1
[] = {
4541 "CONNECT www.example.org:443 HTTP/1.1\r\n"
4542 "Host: www.example.org\r\n"
4543 "Proxy-Connection: keep-alive\r\n\r\n"),
4545 "GET / HTTP/1.1\r\n"
4546 "Host: www.example.org\r\n"
4547 "Connection: keep-alive\r\n\r\n"),
4550 MockRead reads1
[] = {
4551 MockRead(ASYNC
, 1, "HTTP/1.1 200 OK\r\n\r\n"),
4553 "HTTP/1.1 200 OK\r\n"
4554 "Content-Length: 5\r\n\r\n"
4557 SequencedSocketData
data1(reads1
, arraysize(reads1
), writes1
,
4558 arraysize(writes1
));
4560 scoped_ptr
<SSLSocketDataProvider
> ssl_provider1(
4561 new SSLSocketDataProvider(ASYNC
, OK
));
4562 // Expect only HTTP/1.1 protocol in SSLConfig.
4563 ssl_provider1
->next_protos_expected_in_ssl_config
.push_back(kProtoHTTP11
);
4565 ssl_provider1
->SetNextProto(kProtoHTTP11
);
4566 helper
.AddDataWithSSLSocketDataProvider(&data1
, ssl_provider1
.Pass());
4568 // A third socket is needed for the tunnelled connection.
4569 scoped_ptr
<SSLSocketDataProvider
> ssl_provider2(
4570 new SSLSocketDataProvider(ASYNC
, OK
));
4571 helper
.session_deps()->socket_factory
->AddSSLSocketDataProvider(
4572 ssl_provider2
.get());
4574 base::WeakPtr
<HttpServerProperties
> http_server_properties
=
4575 helper
.session()->spdy_session_pool()->http_server_properties();
4576 const HostPortPair proxy_host_port_pair
= HostPortPair("myproxy", 70);
4577 EXPECT_FALSE(http_server_properties
->RequiresHTTP11(proxy_host_port_pair
));
4579 helper
.RunPreTestSetup();
4580 helper
.StartDefaultTest();
4581 helper
.FinishDefaultTestWithoutVerification();
4582 helper
.VerifyDataConsumed();
4583 EXPECT_TRUE(http_server_properties
->RequiresHTTP11(proxy_host_port_pair
));
4585 const HttpResponseInfo
* response
= helper
.trans()->GetResponseInfo();
4586 ASSERT_TRUE(response
!= nullptr);
4587 ASSERT_TRUE(response
->headers
.get() != nullptr);
4588 EXPECT_EQ("HTTP/1.1 200 OK", response
->headers
->GetStatusLine());
4589 EXPECT_FALSE(response
->was_fetched_via_spdy
);
4590 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP1
, response
->connection_info
);
4591 EXPECT_FALSE(response
->was_npn_negotiated
);
4592 EXPECT_TRUE(request
.url
.SchemeIs("https"));
4593 EXPECT_EQ("127.0.0.1", response
->socket_address
.host());
4594 EXPECT_EQ(70, response
->socket_address
.port());
4595 std::string response_data
;
4596 ASSERT_EQ(OK
, ReadTransaction(helper
.trans(), &response_data
));
4597 EXPECT_EQ("hello", response_data
);
4600 // Test to make sure we can correctly connect through a proxy.
4601 TEST_P(SpdyNetworkTransactionTest
, ProxyConnect
) {
4602 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
4603 BoundNetLog(), GetParam(), NULL
);
4604 helper
.session_deps().reset(CreateSpdySessionDependencies(
4606 ProxyService::CreateFixedFromPacResult("PROXY myproxy:70")));
4607 helper
.SetSession(make_scoped_refptr(
4608 SpdySessionDependencies::SpdyCreateSession(helper
.session_deps().get())));
4609 helper
.RunPreTestSetup();
4610 HttpNetworkTransaction
* trans
= helper
.trans();
4612 const char kConnect443
[] = {
4613 "CONNECT www.example.org:443 HTTP/1.1\r\n"
4614 "Host: www.example.org\r\n"
4615 "Proxy-Connection: keep-alive\r\n\r\n"};
4616 const char kHTTP200
[] = {"HTTP/1.1 200 OK\r\n\r\n"};
4617 scoped_ptr
<SpdyFrame
> req(
4618 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
4619 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
4620 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
4622 MockWrite writes
[] = {
4623 MockWrite(SYNCHRONOUS
, kConnect443
, arraysize(kConnect443
) - 1, 0),
4624 CreateMockWrite(*req
, 2),
4626 MockRead reads
[] = {
4627 MockRead(SYNCHRONOUS
, kHTTP200
, arraysize(kHTTP200
) - 1, 1),
4628 CreateMockRead(*resp
, 3),
4629 CreateMockRead(*body
.get(), 4),
4630 MockRead(ASYNC
, 0, 0, 5),
4632 scoped_ptr
<SequencedSocketData
> data(new SequencedSocketData(
4633 reads
, arraysize(reads
), writes
, arraysize(writes
)));
4635 helper
.AddData(data
.get());
4636 TestCompletionCallback callback
;
4638 int rv
= trans
->Start(
4639 &CreateGetRequest(), callback
.callback(), BoundNetLog());
4640 EXPECT_EQ(ERR_IO_PENDING
, rv
);
4642 rv
= callback
.WaitForResult();
4645 // Verify the SYN_REPLY.
4646 HttpResponseInfo response
= *trans
->GetResponseInfo();
4647 EXPECT_TRUE(response
.headers
.get() != NULL
);
4648 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
4650 std::string response_data
;
4651 ASSERT_EQ(OK
, ReadTransaction(trans
, &response_data
));
4652 EXPECT_EQ("hello!", response_data
);
4653 helper
.VerifyDataConsumed();
4656 // Test to make sure we can correctly connect through a proxy to
4657 // www.example.org, if there already exists a direct spdy connection to
4658 // www.example.org. See https://crbug.com/49874.
4659 TEST_P(SpdyNetworkTransactionTest
, DirectConnectProxyReconnect
) {
4660 // When setting up the first transaction, we store the SpdySessionPool so that
4661 // we can use the same pool in the second transaction.
4662 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
4663 BoundNetLog(), GetParam(), NULL
);
4665 // Use a proxy service which returns a proxy fallback list from DIRECT to
4666 // myproxy:70. For this test there will be no fallback, so it is equivalent
4667 // to simply DIRECT. The reason for appending the second proxy is to verify
4668 // that the session pool key used does is just "DIRECT".
4669 helper
.session_deps().reset(CreateSpdySessionDependencies(
4671 ProxyService::CreateFixedFromPacResult("DIRECT; PROXY myproxy:70")));
4672 helper
.SetSession(make_scoped_refptr(
4673 SpdySessionDependencies::SpdyCreateSession(helper
.session_deps().get())));
4675 SpdySessionPool
* spdy_session_pool
= helper
.session()->spdy_session_pool();
4676 helper
.RunPreTestSetup();
4678 // Construct and send a simple GET request.
4679 scoped_ptr
<SpdyFrame
> req(
4680 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
4681 MockWrite writes
[] = {
4682 CreateMockWrite(*req
, 0),
4685 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
4686 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
4687 MockRead reads
[] = {
4688 CreateMockRead(*resp
, 1),
4689 CreateMockRead(*body
, 2),
4690 MockRead(SYNCHRONOUS
, ERR_IO_PENDING
, 3), // Force a pause
4692 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
4693 helper
.AddData(&data
);
4694 HttpNetworkTransaction
* trans
= helper
.trans();
4696 TestCompletionCallback callback
;
4697 TransactionHelperResult out
;
4698 out
.rv
= trans
->Start(
4699 &CreateGetRequest(), callback
.callback(), BoundNetLog());
4701 EXPECT_EQ(out
.rv
, ERR_IO_PENDING
);
4702 out
.rv
= callback
.WaitForResult();
4703 EXPECT_EQ(out
.rv
, OK
);
4705 const HttpResponseInfo
* response
= trans
->GetResponseInfo();
4706 EXPECT_TRUE(response
->headers
.get() != NULL
);
4707 EXPECT_TRUE(response
->was_fetched_via_spdy
);
4708 out
.rv
= ReadTransaction(trans
, &out
.response_data
);
4709 EXPECT_EQ(OK
, out
.rv
);
4710 out
.status_line
= response
->headers
->GetStatusLine();
4711 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
4712 EXPECT_EQ("hello!", out
.response_data
);
4714 // Check that the SpdySession is still in the SpdySessionPool.
4715 HostPortPair
host_port_pair("www.example.org", helper
.port());
4716 SpdySessionKey
session_pool_key_direct(
4717 host_port_pair
, ProxyServer::Direct(), PRIVACY_MODE_DISABLED
);
4718 EXPECT_TRUE(HasSpdySession(spdy_session_pool
, session_pool_key_direct
));
4719 SpdySessionKey
session_pool_key_proxy(
4721 ProxyServer::FromURI("www.foo.com", ProxyServer::SCHEME_HTTP
),
4722 PRIVACY_MODE_DISABLED
);
4723 EXPECT_FALSE(HasSpdySession(spdy_session_pool
, session_pool_key_proxy
));
4725 // Set up data for the proxy connection.
4726 const char kConnect443
[] = {
4727 "CONNECT www.example.org:443 HTTP/1.1\r\n"
4728 "Host: www.example.org\r\n"
4729 "Proxy-Connection: keep-alive\r\n\r\n"};
4730 const char kHTTP200
[] = {"HTTP/1.1 200 OK\r\n\r\n"};
4731 scoped_ptr
<SpdyFrame
> req2(spdy_util_
.ConstructSpdyGet(
4732 GetDefaultUrlWithPath("/foo.dat").c_str(), false, 1, LOWEST
));
4733 scoped_ptr
<SpdyFrame
> resp2(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
4734 scoped_ptr
<SpdyFrame
> body2(spdy_util_
.ConstructSpdyBodyFrame(1, true));
4736 MockWrite writes2
[] = {
4737 MockWrite(SYNCHRONOUS
, kConnect443
, arraysize(kConnect443
) - 1, 0),
4738 CreateMockWrite(*req2
, 2),
4740 MockRead reads2
[] = {
4741 MockRead(SYNCHRONOUS
, kHTTP200
, arraysize(kHTTP200
) - 1, 1),
4742 CreateMockRead(*resp2
, 3),
4743 CreateMockRead(*body2
, 4),
4744 MockRead(ASYNC
, 0, 5) // EOF
4747 scoped_ptr
<SequencedSocketData
> data_proxy(new SequencedSocketData(
4748 reads2
, arraysize(reads2
), writes2
, arraysize(writes2
)));
4750 // Create another request to www.example.org, but this time through a proxy.
4751 HttpRequestInfo request_proxy
;
4752 request_proxy
.method
= "GET";
4753 request_proxy
.url
= GURL(GetDefaultUrlWithPath("/foo.dat"));
4754 request_proxy
.load_flags
= 0;
4755 scoped_ptr
<SpdySessionDependencies
> ssd_proxy(
4756 CreateSpdySessionDependencies(GetParam()));
4757 // Ensure that this transaction uses the same SpdySessionPool.
4758 scoped_refptr
<HttpNetworkSession
> session_proxy(
4759 SpdySessionDependencies::SpdyCreateSession(ssd_proxy
.get()));
4760 NormalSpdyTransactionHelper
helper_proxy(request_proxy
, DEFAULT_PRIORITY
,
4761 BoundNetLog(), GetParam(), NULL
);
4762 HttpNetworkSessionPeer
session_peer(session_proxy
);
4763 scoped_ptr
<ProxyService
> proxy_service(
4764 ProxyService::CreateFixedFromPacResult("PROXY myproxy:70"));
4765 session_peer
.SetProxyService(proxy_service
.get());
4766 helper_proxy
.session_deps().swap(ssd_proxy
);
4767 helper_proxy
.SetSession(session_proxy
);
4768 helper_proxy
.RunPreTestSetup();
4769 helper_proxy
.AddData(data_proxy
.get());
4771 HttpNetworkTransaction
* trans_proxy
= helper_proxy
.trans();
4772 TestCompletionCallback callback_proxy
;
4773 int rv
= trans_proxy
->Start(
4774 &request_proxy
, callback_proxy
.callback(), BoundNetLog());
4775 EXPECT_EQ(ERR_IO_PENDING
, rv
);
4776 rv
= callback_proxy
.WaitForResult();
4779 HttpResponseInfo response_proxy
= *trans_proxy
->GetResponseInfo();
4780 EXPECT_TRUE(response_proxy
.headers
.get() != NULL
);
4781 EXPECT_EQ("HTTP/1.1 200 OK", response_proxy
.headers
->GetStatusLine());
4783 std::string response_data
;
4784 ASSERT_EQ(OK
, ReadTransaction(trans_proxy
, &response_data
));
4785 EXPECT_EQ("hello!", response_data
);
4787 helper_proxy
.VerifyDataConsumed();
4790 // When we get a TCP-level RST, we need to retry a HttpNetworkTransaction
4791 // on a new connection, if the connection was previously known to be good.
4792 // This can happen when a server reboots without saying goodbye, or when
4793 // we're behind a NAT that masked the RST.
4794 TEST_P(SpdyNetworkTransactionTest
, VerifyRetryOnConnectionReset
) {
4795 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
4796 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
4797 MockRead reads
[] = {
4798 CreateMockRead(*resp
, 0),
4799 CreateMockRead(*body
, 1),
4800 MockRead(ASYNC
, ERR_IO_PENDING
, 2),
4801 MockRead(ASYNC
, ERR_CONNECTION_RESET
, 3),
4804 MockRead reads2
[] = {
4805 CreateMockRead(*resp
, 0),
4806 CreateMockRead(*body
, 1),
4807 MockRead(ASYNC
, 0, 2) // EOF
4810 // This test has a couple of variants.
4812 // Induce the RST while waiting for our transaction to send.
4813 VARIANT_RST_DURING_SEND_COMPLETION
,
4814 // Induce the RST while waiting for our transaction to read.
4815 // In this case, the send completed - everything copied into the SNDBUF.
4816 VARIANT_RST_DURING_READ_COMPLETION
4819 for (int variant
= VARIANT_RST_DURING_SEND_COMPLETION
;
4820 variant
<= VARIANT_RST_DURING_READ_COMPLETION
;
4822 DelayedSocketData
data1(1, reads
, arraysize(reads
), NULL
, 0);
4824 DelayedSocketData
data2(1, reads2
, arraysize(reads2
), NULL
, 0);
4826 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
4827 BoundNetLog(), GetParam(), NULL
);
4828 helper
.AddData(&data1
);
4829 helper
.AddData(&data2
);
4830 helper
.RunPreTestSetup();
4832 for (int i
= 0; i
< 2; ++i
) {
4833 scoped_ptr
<HttpNetworkTransaction
> trans(
4834 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
4836 TestCompletionCallback callback
;
4837 int rv
= trans
->Start(
4838 &helper
.request(), callback
.callback(), BoundNetLog());
4839 EXPECT_EQ(ERR_IO_PENDING
, rv
);
4840 // On the second transaction, we trigger the RST.
4842 if (variant
== VARIANT_RST_DURING_READ_COMPLETION
) {
4843 // Writes to the socket complete asynchronously on SPDY by running
4844 // through the message loop. Complete the write here.
4845 base::RunLoop().RunUntilIdle();
4848 // Now schedule the ERR_CONNECTION_RESET.
4849 EXPECT_EQ(3u, data1
.read_index());
4850 data1
.CompleteRead();
4851 EXPECT_EQ(4u, data1
.read_index());
4853 rv
= callback
.WaitForResult();
4856 const HttpResponseInfo
* response
= trans
->GetResponseInfo();
4857 ASSERT_TRUE(response
!= NULL
);
4858 EXPECT_TRUE(response
->headers
.get() != NULL
);
4859 EXPECT_TRUE(response
->was_fetched_via_spdy
);
4860 std::string response_data
;
4861 rv
= ReadTransaction(trans
.get(), &response_data
);
4863 EXPECT_EQ("HTTP/1.1 200 OK", response
->headers
->GetStatusLine());
4864 EXPECT_EQ("hello!", response_data
);
4867 helper
.VerifyDataConsumed();
4871 // Test that turning SPDY on and off works properly.
4872 TEST_P(SpdyNetworkTransactionTest
, SpdyOnOffToggle
) {
4873 HttpStreamFactory::set_spdy_enabled(true);
4874 scoped_ptr
<SpdyFrame
> req(
4875 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
4876 MockWrite spdy_writes
[] = {CreateMockWrite(*req
, 0)};
4878 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
4879 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
4880 MockRead spdy_reads
[] = {
4881 CreateMockRead(*resp
, 1),
4882 CreateMockRead(*body
, 2),
4883 MockRead(ASYNC
, 0, 3) // EOF
4886 SequencedSocketData
data(spdy_reads
, arraysize(spdy_reads
), spdy_writes
,
4887 arraysize(spdy_writes
));
4888 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
4889 BoundNetLog(), GetParam(), NULL
);
4890 helper
.RunToCompletion(&data
);
4891 TransactionHelperResult out
= helper
.output();
4892 EXPECT_EQ(OK
, out
.rv
);
4893 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
4894 EXPECT_EQ("hello!", out
.response_data
);
4896 HttpStreamFactory::set_spdy_enabled(false);
4897 MockWrite http_writes
[] = {
4898 MockWrite(SYNCHRONOUS
, 0,
4899 "GET / HTTP/1.1\r\n"
4900 "Host: www.example.org\r\n"
4901 "Connection: keep-alive\r\n\r\n"),
4904 MockRead http_reads
[] = {
4905 MockRead(SYNCHRONOUS
, 1, "HTTP/1.1 200 OK\r\n\r\n"),
4906 MockRead(SYNCHRONOUS
, 2, "hello from http"),
4907 MockRead(SYNCHRONOUS
, OK
, 3),
4909 SequencedSocketData
data2(http_reads
, arraysize(http_reads
), http_writes
,
4910 arraysize(http_writes
));
4911 NormalSpdyTransactionHelper
helper2(CreateGetRequest(), DEFAULT_PRIORITY
,
4912 BoundNetLog(), GetParam(), NULL
);
4913 helper2
.SetSpdyDisabled();
4914 helper2
.RunToCompletion(&data2
);
4915 TransactionHelperResult out2
= helper2
.output();
4916 EXPECT_EQ(OK
, out2
.rv
);
4917 EXPECT_EQ("HTTP/1.1 200 OK", out2
.status_line
);
4918 EXPECT_EQ("hello from http", out2
.response_data
);
4920 HttpStreamFactory::set_spdy_enabled(true);
4923 // Tests that Basic authentication works over SPDY
4924 TEST_P(SpdyNetworkTransactionTest
, SpdyBasicAuth
) {
4925 HttpStreamFactory::set_spdy_enabled(true);
4927 // The first request will be a bare GET, the second request will be a
4928 // GET with an Authorization header.
4929 scoped_ptr
<SpdyFrame
> req_get(
4930 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
4931 const char* const kExtraAuthorizationHeaders
[] = {
4932 "authorization", "Basic Zm9vOmJhcg=="
4934 scoped_ptr
<SpdyFrame
> req_get_authorization(
4935 spdy_util_
.ConstructSpdyGet(kExtraAuthorizationHeaders
,
4936 arraysize(kExtraAuthorizationHeaders
) / 2,
4937 false, 3, LOWEST
, true));
4938 MockWrite spdy_writes
[] = {
4939 CreateMockWrite(*req_get
, 0), CreateMockWrite(*req_get_authorization
, 3),
4942 // The first response is a 401 authentication challenge, and the second
4943 // response will be a 200 response since the second request includes a valid
4944 // Authorization header.
4945 const char* const kExtraAuthenticationHeaders
[] = {
4947 "Basic realm=\"MyRealm\""
4949 scoped_ptr
<SpdyFrame
> resp_authentication(
4950 spdy_util_
.ConstructSpdySynReplyError(
4951 "401 Authentication Required",
4952 kExtraAuthenticationHeaders
,
4953 arraysize(kExtraAuthenticationHeaders
) / 2,
4955 scoped_ptr
<SpdyFrame
> body_authentication(
4956 spdy_util_
.ConstructSpdyBodyFrame(1, true));
4957 scoped_ptr
<SpdyFrame
> resp_data(
4958 spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 3));
4959 scoped_ptr
<SpdyFrame
> body_data(spdy_util_
.ConstructSpdyBodyFrame(3, true));
4960 MockRead spdy_reads
[] = {
4961 CreateMockRead(*resp_authentication
, 1),
4962 CreateMockRead(*body_authentication
, 2),
4963 CreateMockRead(*resp_data
, 4),
4964 CreateMockRead(*body_data
, 5),
4965 MockRead(ASYNC
, 0, 6),
4968 SequencedSocketData
data(spdy_reads
, arraysize(spdy_reads
), spdy_writes
,
4969 arraysize(spdy_writes
));
4970 HttpRequestInfo
request(CreateGetRequest());
4971 BoundNetLog net_log
;
4972 NormalSpdyTransactionHelper
helper(request
, DEFAULT_PRIORITY
,
4973 net_log
, GetParam(), NULL
);
4975 helper
.RunPreTestSetup();
4976 helper
.AddData(&data
);
4977 HttpNetworkTransaction
* trans
= helper
.trans();
4978 TestCompletionCallback callback
;
4979 const int rv_start
= trans
->Start(&request
, callback
.callback(), net_log
);
4980 EXPECT_EQ(ERR_IO_PENDING
, rv_start
);
4981 const int rv_start_complete
= callback
.WaitForResult();
4982 EXPECT_EQ(OK
, rv_start_complete
);
4984 // Make sure the response has an auth challenge.
4985 const HttpResponseInfo
* const response_start
= trans
->GetResponseInfo();
4986 ASSERT_TRUE(response_start
!= NULL
);
4987 ASSERT_TRUE(response_start
->headers
.get() != NULL
);
4988 EXPECT_EQ(401, response_start
->headers
->response_code());
4989 EXPECT_TRUE(response_start
->was_fetched_via_spdy
);
4990 AuthChallengeInfo
* auth_challenge
= response_start
->auth_challenge
.get();
4991 ASSERT_TRUE(auth_challenge
!= NULL
);
4992 EXPECT_FALSE(auth_challenge
->is_proxy
);
4993 EXPECT_EQ("basic", auth_challenge
->scheme
);
4994 EXPECT_EQ("MyRealm", auth_challenge
->realm
);
4996 // Restart with a username/password.
4997 AuthCredentials
credentials(base::ASCIIToUTF16("foo"),
4998 base::ASCIIToUTF16("bar"));
4999 TestCompletionCallback callback_restart
;
5000 const int rv_restart
= trans
->RestartWithAuth(
5001 credentials
, callback_restart
.callback());
5002 EXPECT_EQ(ERR_IO_PENDING
, rv_restart
);
5003 const int rv_restart_complete
= callback_restart
.WaitForResult();
5004 EXPECT_EQ(OK
, rv_restart_complete
);
5005 // TODO(cbentzel): This is actually the same response object as before, but
5006 // data has changed.
5007 const HttpResponseInfo
* const response_restart
= trans
->GetResponseInfo();
5008 ASSERT_TRUE(response_restart
!= NULL
);
5009 ASSERT_TRUE(response_restart
->headers
.get() != NULL
);
5010 EXPECT_EQ(200, response_restart
->headers
->response_code());
5011 EXPECT_TRUE(response_restart
->auth_challenge
.get() == NULL
);
5014 TEST_P(SpdyNetworkTransactionTest
, ServerPushWithHeaders
) {
5015 scoped_ptr
<SpdyFrame
> stream1_syn(
5016 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
5017 scoped_ptr
<SpdyFrame
> stream1_body(
5018 spdy_util_
.ConstructSpdyBodyFrame(1, true));
5019 MockWrite writes
[] = {
5020 CreateMockWrite(*stream1_syn
, 0),
5023 scoped_ptr
<SpdyHeaderBlock
> initial_headers(new SpdyHeaderBlock());
5024 spdy_util_
.AddUrlToHeaderBlock(GetDefaultUrlWithPath("/foo.dat"),
5025 initial_headers
.get());
5026 scoped_ptr
<SpdyFrame
> stream2_syn(
5027 spdy_util_
.ConstructInitialSpdyPushFrame(initial_headers
.Pass(), 2, 1));
5029 scoped_ptr
<SpdyHeaderBlock
> late_headers(new SpdyHeaderBlock());
5030 (*late_headers
)["hello"] = "bye";
5031 (*late_headers
)[spdy_util_
.GetStatusKey()] = "200";
5032 (*late_headers
)[spdy_util_
.GetVersionKey()] = "HTTP/1.1";
5033 scoped_ptr
<SpdyFrame
> stream2_headers(
5034 spdy_util_
.ConstructSpdyControlFrame(late_headers
.Pass(),
5042 scoped_ptr
<SpdyFrame
>
5043 stream1_reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
5044 const char kPushedData
[] = "pushed";
5045 scoped_ptr
<SpdyFrame
> stream2_body(
5046 spdy_util_
.ConstructSpdyBodyFrame(
5047 2, kPushedData
, strlen(kPushedData
), true));
5048 MockRead reads
[] = {
5049 CreateMockRead(*stream1_reply
, 1),
5050 CreateMockRead(*stream2_syn
, 2),
5051 CreateMockRead(*stream2_headers
, 3),
5052 CreateMockRead(*stream1_body
, 4, SYNCHRONOUS
),
5053 CreateMockRead(*stream2_body
, 5),
5054 MockRead(SYNCHRONOUS
, ERR_IO_PENDING
, 6), // Force a pause
5057 HttpResponseInfo response
;
5058 HttpResponseInfo response2
;
5059 std::string
expected_push_result("pushed");
5060 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
5061 RunServerPushTest(&data
,
5064 expected_push_result
);
5066 // Verify the SYN_REPLY.
5067 EXPECT_TRUE(response
.headers
.get() != NULL
);
5068 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
5070 // Verify the pushed stream.
5071 EXPECT_TRUE(response2
.headers
.get() != NULL
);
5072 EXPECT_EQ("HTTP/1.1 200 OK", response2
.headers
->GetStatusLine());
5075 TEST_P(SpdyNetworkTransactionTest
, ServerPushClaimBeforeHeaders
) {
5076 // We push a stream and attempt to claim it before the headers come down.
5077 scoped_ptr
<SpdyFrame
> stream1_syn(
5078 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
5079 scoped_ptr
<SpdyFrame
> stream1_body(
5080 spdy_util_
.ConstructSpdyBodyFrame(1, true));
5081 MockWrite writes
[] = {
5082 CreateMockWrite(*stream1_syn
, 0, SYNCHRONOUS
),
5085 scoped_ptr
<SpdyHeaderBlock
> initial_headers(new SpdyHeaderBlock());
5086 spdy_util_
.AddUrlToHeaderBlock(GetDefaultUrlWithPath("/foo.dat"),
5087 initial_headers
.get());
5088 scoped_ptr
<SpdyFrame
> stream2_syn(
5089 spdy_util_
.ConstructInitialSpdyPushFrame(initial_headers
.Pass(), 2, 1));
5091 scoped_ptr
<SpdyHeaderBlock
> late_headers(new SpdyHeaderBlock());
5092 (*late_headers
)["hello"] = "bye";
5093 (*late_headers
)[spdy_util_
.GetStatusKey()] = "200";
5094 (*late_headers
)[spdy_util_
.GetVersionKey()] = "HTTP/1.1";
5095 scoped_ptr
<SpdyFrame
> stream2_headers(
5096 spdy_util_
.ConstructSpdyControlFrame(late_headers
.Pass(),
5104 scoped_ptr
<SpdyFrame
>
5105 stream1_reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
5106 const char kPushedData
[] = "pushed";
5107 scoped_ptr
<SpdyFrame
> stream2_body(
5108 spdy_util_
.ConstructSpdyBodyFrame(
5109 2, kPushedData
, strlen(kPushedData
), true));
5110 MockRead reads
[] = {
5111 CreateMockRead(*stream1_reply
, 1),
5112 CreateMockRead(*stream2_syn
, 2),
5113 CreateMockRead(*stream1_body
, 3),
5114 CreateMockRead(*stream2_headers
, 4),
5115 CreateMockRead(*stream2_body
, 5),
5116 MockRead(ASYNC
, 0, 6), // EOF
5119 HttpResponseInfo response
;
5120 HttpResponseInfo response2
;
5121 std::string
expected_push_result("pushed");
5122 DeterministicSocketData
data(reads
, arraysize(reads
),
5123 writes
, arraysize(writes
));
5125 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
5126 BoundNetLog(), GetParam(), NULL
);
5127 helper
.SetDeterministic();
5128 helper
.AddDeterministicData(&data
);
5129 helper
.RunPreTestSetup();
5131 HttpNetworkTransaction
* trans
= helper
.trans();
5133 // Run until we've received the primary SYN_STREAM, the pushed SYN_STREAM,
5134 // and the body of the primary stream, but before we've received the HEADERS
5135 // for the pushed stream.
5138 // Start the transaction.
5139 TestCompletionCallback callback
;
5140 int rv
= trans
->Start(
5141 &CreateGetRequest(), callback
.callback(), BoundNetLog());
5142 EXPECT_EQ(ERR_IO_PENDING
, rv
);
5144 rv
= callback
.WaitForResult();
5147 // Request the pushed path. At this point, we've received the push, but the
5148 // headers are not yet complete.
5149 scoped_ptr
<HttpNetworkTransaction
> trans2(
5150 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
5152 &CreateGetPushRequest(), callback
.callback(), BoundNetLog());
5153 EXPECT_EQ(ERR_IO_PENDING
, rv
);
5155 base::RunLoop().RunUntilIdle();
5157 // Read the server push body.
5158 std::string result2
;
5159 ReadResult(trans2
.get(), &data
, &result2
);
5160 // Read the response body.
5162 ReadResult(trans
, &data
, &result
);
5164 // Verify that the received push data is same as the expected push data.
5165 EXPECT_EQ(result2
.compare(expected_push_result
), 0)
5166 << "Received data: "
5168 << "||||| Expected data: "
5169 << expected_push_result
;
5171 // Verify the SYN_REPLY.
5172 // Copy the response info, because trans goes away.
5173 response
= *trans
->GetResponseInfo();
5174 response2
= *trans2
->GetResponseInfo();
5176 VerifyStreamsClosed(helper
);
5178 // Verify the SYN_REPLY.
5179 EXPECT_TRUE(response
.headers
.get() != NULL
);
5180 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
5182 // Verify the pushed stream.
5183 EXPECT_TRUE(response2
.headers
.get() != NULL
);
5184 EXPECT_EQ("HTTP/1.1 200 OK", response2
.headers
->GetStatusLine());
5186 // Read the final EOF (which will close the session)
5189 // Verify that we consumed all test data.
5190 EXPECT_TRUE(data
.AllReadDataConsumed());
5191 EXPECT_TRUE(data
.AllWriteDataConsumed());
5194 // TODO(baranovich): HTTP 2 does not allow multiple HEADERS frames
5195 TEST_P(SpdyNetworkTransactionTest
, ServerPushWithTwoHeaderFrames
) {
5196 // We push a stream and attempt to claim it before the headers come down.
5197 scoped_ptr
<SpdyFrame
> stream1_syn(
5198 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
5199 scoped_ptr
<SpdyFrame
> stream1_body(
5200 spdy_util_
.ConstructSpdyBodyFrame(1, true));
5201 MockWrite writes
[] = {
5202 CreateMockWrite(*stream1_syn
, 0, SYNCHRONOUS
),
5205 scoped_ptr
<SpdyHeaderBlock
> initial_headers(new SpdyHeaderBlock());
5206 if (spdy_util_
.spdy_version() < SPDY4
) {
5207 // In SPDY4 PUSH_PROMISE headers won't show up in the response headers.
5208 (*initial_headers
)["alpha"] = "beta";
5210 spdy_util_
.AddUrlToHeaderBlock(GetDefaultUrlWithPath("/foo.dat"),
5211 initial_headers
.get());
5212 scoped_ptr
<SpdyFrame
> stream2_syn(
5213 spdy_util_
.ConstructInitialSpdyPushFrame(initial_headers
.Pass(), 2, 1));
5215 scoped_ptr
<SpdyHeaderBlock
> middle_headers(new SpdyHeaderBlock());
5216 (*middle_headers
)["hello"] = "bye";
5217 scoped_ptr
<SpdyFrame
> stream2_headers1(
5218 spdy_util_
.ConstructSpdyControlFrame(middle_headers
.Pass(),
5226 scoped_ptr
<SpdyHeaderBlock
> late_headers(new SpdyHeaderBlock());
5227 (*late_headers
)[spdy_util_
.GetStatusKey()] = "200";
5228 if (spdy_util_
.spdy_version() < SPDY4
) {
5229 // SPDY4/HTTP2 eliminates use of the :version header.
5230 (*late_headers
)[spdy_util_
.GetVersionKey()] = "HTTP/1.1";
5232 scoped_ptr
<SpdyFrame
> stream2_headers2(
5233 spdy_util_
.ConstructSpdyControlFrame(late_headers
.Pass(),
5241 scoped_ptr
<SpdyFrame
>
5242 stream1_reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
5243 const char kPushedData
[] = "pushed";
5244 scoped_ptr
<SpdyFrame
> stream2_body(
5245 spdy_util_
.ConstructSpdyBodyFrame(
5246 2, kPushedData
, strlen(kPushedData
), true));
5247 MockRead reads
[] = {
5248 CreateMockRead(*stream1_reply
, 1),
5249 CreateMockRead(*stream2_syn
, 2),
5250 CreateMockRead(*stream1_body
, 3),
5251 CreateMockRead(*stream2_headers1
, 4),
5252 CreateMockRead(*stream2_headers2
, 5),
5253 CreateMockRead(*stream2_body
, 6),
5254 MockRead(ASYNC
, 0, 7), // EOF
5257 HttpResponseInfo response
;
5258 HttpResponseInfo response2
;
5259 std::string
expected_push_result("pushed");
5260 DeterministicSocketData
data(reads
, arraysize(reads
),
5261 writes
, arraysize(writes
));
5263 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
5264 BoundNetLog(), GetParam(), NULL
);
5265 helper
.SetDeterministic();
5266 helper
.AddDeterministicData(&data
);
5267 helper
.RunPreTestSetup();
5269 HttpNetworkTransaction
* trans
= helper
.trans();
5271 // Run until we've received the primary SYN_STREAM, the pushed SYN_STREAM,
5272 // the first HEADERS frame, and the body of the primary stream, but before
5273 // we've received the final HEADERS for the pushed stream.
5276 // Start the transaction.
5277 TestCompletionCallback callback
;
5278 int rv
= trans
->Start(
5279 &CreateGetRequest(), callback
.callback(), BoundNetLog());
5280 EXPECT_EQ(ERR_IO_PENDING
, rv
);
5282 rv
= callback
.WaitForResult();
5285 // Request the pushed path. At this point, we've received the push, but the
5286 // headers are not yet complete.
5287 scoped_ptr
<HttpNetworkTransaction
> trans2(
5288 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
5290 &CreateGetPushRequest(), callback
.callback(), BoundNetLog());
5291 EXPECT_EQ(ERR_IO_PENDING
, rv
);
5293 base::RunLoop().RunUntilIdle();
5295 // Read the server push body.
5296 std::string result2
;
5297 ReadResult(trans2
.get(), &data
, &result2
);
5298 // Read the response body.
5300 ReadResult(trans
, &data
, &result
);
5302 // Verify that the received push data is same as the expected push data.
5303 EXPECT_EQ(expected_push_result
, result2
);
5305 // Verify the SYN_REPLY.
5306 // Copy the response info, because trans goes away.
5307 response
= *trans
->GetResponseInfo();
5308 response2
= *trans2
->GetResponseInfo();
5310 VerifyStreamsClosed(helper
);
5312 // Verify the SYN_REPLY.
5313 EXPECT_TRUE(response
.headers
.get() != NULL
);
5314 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
5316 // Verify the pushed stream.
5317 EXPECT_TRUE(response2
.headers
.get() != NULL
);
5318 EXPECT_EQ("HTTP/1.1 200 OK", response2
.headers
->GetStatusLine());
5320 // Verify we got all the headers from all header blocks.
5321 if (spdy_util_
.spdy_version() < SPDY4
)
5322 EXPECT_TRUE(response2
.headers
->HasHeaderValue("alpha", "beta"));
5323 EXPECT_TRUE(response2
.headers
->HasHeaderValue("hello", "bye"));
5324 EXPECT_TRUE(response2
.headers
->HasHeaderValue("status", "200"));
5326 // Read the final EOF (which will close the session)
5329 // Verify that we consumed all test data.
5330 EXPECT_TRUE(data
.AllReadDataConsumed());
5331 EXPECT_TRUE(data
.AllWriteDataConsumed());
5334 TEST_P(SpdyNetworkTransactionTest
, ServerPushWithNoStatusHeaderFrames
) {
5335 // We push a stream and attempt to claim it before the headers come down.
5336 scoped_ptr
<SpdyFrame
> stream1_syn(
5337 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
5338 scoped_ptr
<SpdyFrame
> stream1_body(
5339 spdy_util_
.ConstructSpdyBodyFrame(1, true));
5340 MockWrite writes
[] = {
5341 CreateMockWrite(*stream1_syn
, 0, SYNCHRONOUS
),
5344 scoped_ptr
<SpdyHeaderBlock
> initial_headers(new SpdyHeaderBlock());
5345 spdy_util_
.AddUrlToHeaderBlock(GetDefaultUrlWithPath("/foo.dat"),
5346 initial_headers
.get());
5347 scoped_ptr
<SpdyFrame
> stream2_syn(
5348 spdy_util_
.ConstructInitialSpdyPushFrame(initial_headers
.Pass(), 2, 1));
5350 scoped_ptr
<SpdyHeaderBlock
> middle_headers(new SpdyHeaderBlock());
5351 (*middle_headers
)["hello"] = "bye";
5352 scoped_ptr
<SpdyFrame
> stream2_headers1(
5353 spdy_util_
.ConstructSpdyControlFrame(middle_headers
.Pass(),
5361 scoped_ptr
<SpdyFrame
>
5362 stream1_reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
5363 const char kPushedData
[] = "pushed";
5364 scoped_ptr
<SpdyFrame
> stream2_body(
5365 spdy_util_
.ConstructSpdyBodyFrame(
5366 2, kPushedData
, strlen(kPushedData
), true));
5367 MockRead reads
[] = {
5368 CreateMockRead(*stream1_reply
, 1),
5369 CreateMockRead(*stream2_syn
, 2),
5370 CreateMockRead(*stream1_body
, 3),
5371 CreateMockRead(*stream2_headers1
, 4),
5372 CreateMockRead(*stream2_body
, 5),
5373 MockRead(ASYNC
, 0, 6), // EOF
5376 DeterministicSocketData
data(reads
, arraysize(reads
),
5377 writes
, arraysize(writes
));
5379 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
5380 BoundNetLog(), GetParam(), NULL
);
5381 helper
.SetDeterministic();
5382 helper
.AddDeterministicData(&data
);
5383 helper
.RunPreTestSetup();
5385 HttpNetworkTransaction
* trans
= helper
.trans();
5387 // Run until we've received the primary SYN_STREAM, the pushed SYN_STREAM,
5388 // the first HEADERS frame, and the body of the primary stream, but before
5389 // we've received the final HEADERS for the pushed stream.
5392 // Start the transaction.
5393 TestCompletionCallback callback
;
5394 int rv
= trans
->Start(
5395 &CreateGetRequest(), callback
.callback(), BoundNetLog());
5396 EXPECT_EQ(ERR_IO_PENDING
, rv
);
5398 rv
= callback
.WaitForResult();
5401 // Request the pushed path. At this point, we've received the push, but the
5402 // headers are not yet complete.
5403 scoped_ptr
<HttpNetworkTransaction
> trans2(
5404 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
5406 &CreateGetPushRequest(), callback
.callback(), BoundNetLog());
5407 EXPECT_EQ(ERR_IO_PENDING
, rv
);
5409 base::RunLoop().RunUntilIdle();
5411 // Read the server push body.
5412 std::string result2
;
5413 ReadResult(trans2
.get(), &data
, &result2
);
5414 // Read the response body.
5416 ReadResult(trans
, &data
, &result
);
5417 EXPECT_EQ("hello!", result
);
5419 // Verify that we haven't received any push data.
5420 EXPECT_EQ("", result2
);
5422 // Verify the SYN_REPLY.
5423 // Copy the response info, because trans goes away.
5424 HttpResponseInfo response
= *trans
->GetResponseInfo();
5425 ASSERT_TRUE(trans2
->GetResponseInfo() == NULL
);
5427 VerifyStreamsClosed(helper
);
5429 // Verify the SYN_REPLY.
5430 EXPECT_TRUE(response
.headers
.get() != NULL
);
5431 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
5433 // Read the final EOF (which will close the session).
5436 // Verify that we consumed all test data.
5437 EXPECT_TRUE(data
.AllReadDataConsumed());
5438 EXPECT_TRUE(data
.AllWriteDataConsumed());
5441 TEST_P(SpdyNetworkTransactionTest
, SynReplyWithHeaders
) {
5442 scoped_ptr
<SpdyFrame
> req(
5443 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
5444 scoped_ptr
<SpdyFrame
> rst(
5445 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR
));
5446 MockWrite writes
[] = {
5447 CreateMockWrite(*req
, 0), CreateMockWrite(*rst
, 4),
5450 scoped_ptr
<SpdyFrame
> stream1_reply(
5451 spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
5453 scoped_ptr
<SpdyHeaderBlock
> late_headers(new SpdyHeaderBlock());
5454 (*late_headers
)["hello"] = "bye";
5455 scoped_ptr
<SpdyFrame
> stream1_headers(
5456 spdy_util_
.ConstructSpdyControlFrame(late_headers
.Pass(),
5463 scoped_ptr
<SpdyFrame
> stream1_body(
5464 spdy_util_
.ConstructSpdyBodyFrame(1, true));
5465 MockRead reads
[] = {
5466 CreateMockRead(*stream1_reply
, 1),
5467 CreateMockRead(*stream1_headers
, 2),
5468 CreateMockRead(*stream1_body
, 3),
5469 MockRead(ASYNC
, 0, 5) // EOF
5472 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
5473 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
5474 BoundNetLog(), GetParam(), NULL
);
5475 helper
.RunToCompletion(&data
);
5476 TransactionHelperResult out
= helper
.output();
5477 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR
, out
.rv
);
5480 TEST_P(SpdyNetworkTransactionTest
, SynReplyWithLateHeaders
) {
5481 scoped_ptr
<SpdyFrame
> req(
5482 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
5483 scoped_ptr
<SpdyFrame
> rst(
5484 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR
));
5485 MockWrite writes
[] = {
5486 CreateMockWrite(*req
, 0), CreateMockWrite(*rst
, 4),
5489 scoped_ptr
<SpdyFrame
> stream1_reply(
5490 spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
5492 scoped_ptr
<SpdyHeaderBlock
> late_headers(new SpdyHeaderBlock());
5493 (*late_headers
)["hello"] = "bye";
5494 scoped_ptr
<SpdyFrame
> stream1_headers(
5495 spdy_util_
.ConstructSpdyControlFrame(late_headers
.Pass(),
5502 scoped_ptr
<SpdyFrame
> stream1_body(
5503 spdy_util_
.ConstructSpdyBodyFrame(1, false));
5504 scoped_ptr
<SpdyFrame
> stream1_body2(
5505 spdy_util_
.ConstructSpdyBodyFrame(1, true));
5506 MockRead reads
[] = {
5507 CreateMockRead(*stream1_reply
, 1),
5508 CreateMockRead(*stream1_body
, 2),
5509 CreateMockRead(*stream1_headers
, 3),
5510 CreateMockRead(*stream1_body2
, 5),
5511 MockRead(ASYNC
, 0, 6) // EOF
5514 DelayedSocketData
data(1, reads
, arraysize(reads
),
5515 writes
, arraysize(writes
));
5516 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
5517 BoundNetLog(), GetParam(), NULL
);
5518 helper
.RunToCompletion(&data
);
5519 TransactionHelperResult out
= helper
.output();
5520 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR
, out
.rv
);
5523 TEST_P(SpdyNetworkTransactionTest
, ServerPushCrossOriginCorrectness
) {
5524 // Running these tests via Alt-Svc is too complicated to be worthwhile.
5525 if (GetParam().ssl_type
!= HTTPS_SPDY_VIA_NPN
)
5528 // In this test we want to verify that we can't accidentally push content
5529 // which can't be pushed by this content server.
5530 // This test assumes that:
5531 // - if we're requesting http://www.foo.com/barbaz
5532 // - the browser has made a connection to "www.foo.com".
5534 // A list of the URL to fetch, followed by the URL being pushed.
5535 static const char* const kTestCases
[] = {
5536 "https://www.example.org/foo.html",
5537 "https://www.example.org:81/foo.js", // Bad port
5539 "https://www.example.org/foo.html",
5540 "http://www.example.org/foo.js", // Bad protocol
5542 "https://www.example.org/foo.html",
5543 "ftp://www.example.org/foo.js", // Invalid Protocol
5545 "https://www.example.org/foo.html",
5546 "https://blat.www.example.org/foo.js", // Cross subdomain
5548 "https://www.example.org/foo.html",
5549 "https://www.foo.com/foo.js", // Cross domain
5552 for (size_t index
= 0; index
< arraysize(kTestCases
); index
+= 2) {
5553 const char* url_to_fetch
= kTestCases
[index
];
5554 const char* url_to_push
= kTestCases
[index
+ 1];
5556 scoped_ptr
<SpdyFrame
> stream1_syn(
5557 spdy_util_
.ConstructSpdyGet(url_to_fetch
, false, 1, LOWEST
));
5558 scoped_ptr
<SpdyFrame
> stream1_body(
5559 spdy_util_
.ConstructSpdyBodyFrame(1, true));
5560 scoped_ptr
<SpdyFrame
> push_rst(
5561 spdy_util_
.ConstructSpdyRstStream(2, RST_STREAM_REFUSED_STREAM
));
5562 MockWrite writes
[] = {
5563 CreateMockWrite(*stream1_syn
, 0), CreateMockWrite(*push_rst
, 3),
5566 scoped_ptr
<SpdyFrame
>
5567 stream1_reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
5568 scoped_ptr
<SpdyFrame
>
5569 stream2_syn(spdy_util_
.ConstructSpdyPush(NULL
,
5574 const char kPushedData
[] = "pushed";
5575 scoped_ptr
<SpdyFrame
> stream2_body(
5576 spdy_util_
.ConstructSpdyBodyFrame(
5577 2, kPushedData
, strlen(kPushedData
), true));
5578 scoped_ptr
<SpdyFrame
> rst(
5579 spdy_util_
.ConstructSpdyRstStream(2, RST_STREAM_CANCEL
));
5581 MockRead reads
[] = {
5582 CreateMockRead(*stream1_reply
, 1),
5583 CreateMockRead(*stream2_syn
, 2),
5584 CreateMockRead(*stream1_body
, 4),
5585 CreateMockRead(*stream2_body
, 5),
5586 MockRead(SYNCHRONOUS
, ERR_IO_PENDING
, 6), // Force a pause
5589 HttpResponseInfo response
;
5590 SequencedSocketData
data(reads
, arraysize(reads
), writes
,
5593 HttpRequestInfo request
;
5594 request
.method
= "GET";
5595 request
.url
= GURL(url_to_fetch
);
5596 request
.load_flags
= 0;
5598 // Enable cross-origin push. Since we are not using a proxy, this should
5599 // not actually enable cross-origin SPDY push.
5600 scoped_ptr
<SpdySessionDependencies
> session_deps(
5601 CreateSpdySessionDependencies(GetParam()));
5602 session_deps
->trusted_spdy_proxy
= "123.45.67.89:8080";
5603 NormalSpdyTransactionHelper
helper(request
, DEFAULT_PRIORITY
,
5604 BoundNetLog(), GetParam(),
5605 session_deps
.release());
5606 helper
.RunPreTestSetup();
5607 helper
.AddData(&data
);
5609 HttpNetworkTransaction
* trans
= helper
.trans();
5611 // Start the transaction with basic parameters.
5612 TestCompletionCallback callback
;
5614 int rv
= trans
->Start(&request
, callback
.callback(), BoundNetLog());
5615 EXPECT_EQ(ERR_IO_PENDING
, rv
);
5616 rv
= callback
.WaitForResult();
5618 // Read the response body.
5620 ReadResult(trans
, &data
, &result
);
5622 // Verify that we consumed all test data.
5623 EXPECT_TRUE(data
.AllReadDataConsumed());
5624 EXPECT_TRUE(data
.AllWriteDataConsumed());
5626 // Verify the SYN_REPLY.
5627 // Copy the response info, because trans goes away.
5628 response
= *trans
->GetResponseInfo();
5630 VerifyStreamsClosed(helper
);
5632 // Verify the SYN_REPLY.
5633 EXPECT_TRUE(response
.headers
.get() != NULL
);
5634 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
5638 TEST_P(SpdyNetworkTransactionTest
, RetryAfterRefused
) {
5639 // Construct the request.
5640 scoped_ptr
<SpdyFrame
> req(
5641 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
5642 scoped_ptr
<SpdyFrame
> req2(
5643 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 3, LOWEST
, true));
5644 MockWrite writes
[] = {
5645 CreateMockWrite(*req
, 0), CreateMockWrite(*req2
, 2),
5648 scoped_ptr
<SpdyFrame
> refused(
5649 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_REFUSED_STREAM
));
5650 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 3));
5651 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(3, true));
5652 MockRead reads
[] = {
5653 CreateMockRead(*refused
, 1),
5654 CreateMockRead(*resp
, 3),
5655 CreateMockRead(*body
, 4),
5656 MockRead(ASYNC
, 0, 5) // EOF
5659 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
5660 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
5661 BoundNetLog(), GetParam(), NULL
);
5663 helper
.RunPreTestSetup();
5664 helper
.AddData(&data
);
5666 HttpNetworkTransaction
* trans
= helper
.trans();
5668 // Start the transaction with basic parameters.
5669 TestCompletionCallback callback
;
5670 int rv
= trans
->Start(
5671 &CreateGetRequest(), callback
.callback(), BoundNetLog());
5672 EXPECT_EQ(ERR_IO_PENDING
, rv
);
5673 rv
= callback
.WaitForResult();
5676 // Verify that we consumed all test data.
5677 EXPECT_TRUE(data
.AllReadDataConsumed());
5678 EXPECT_TRUE(data
.AllWriteDataConsumed());
5680 // Verify the SYN_REPLY.
5681 HttpResponseInfo response
= *trans
->GetResponseInfo();
5682 EXPECT_TRUE(response
.headers
.get() != NULL
);
5683 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
5686 TEST_P(SpdyNetworkTransactionTest
, OutOfOrderSynStream
) {
5687 // This first request will start to establish the SpdySession.
5688 // Then we will start the second (MEDIUM priority) and then third
5689 // (HIGHEST priority) request in such a way that the third will actually
5690 // start before the second, causing the second to be numbered differently
5691 // than the order they were created.
5692 scoped_ptr
<SpdyFrame
> req1(
5693 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
5694 scoped_ptr
<SpdyFrame
> req2(
5695 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 3, HIGHEST
, true));
5696 scoped_ptr
<SpdyFrame
> req3(
5697 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 5, MEDIUM
, true));
5698 MockWrite writes
[] = {
5699 CreateMockWrite(*req1
, 0),
5700 CreateMockWrite(*req2
, 3),
5701 CreateMockWrite(*req3
, 4),
5704 scoped_ptr
<SpdyFrame
> resp1(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
5705 scoped_ptr
<SpdyFrame
> body1(spdy_util_
.ConstructSpdyBodyFrame(1, true));
5706 scoped_ptr
<SpdyFrame
> resp2(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 3));
5707 scoped_ptr
<SpdyFrame
> body2(spdy_util_
.ConstructSpdyBodyFrame(3, true));
5708 scoped_ptr
<SpdyFrame
> resp3(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 5));
5709 scoped_ptr
<SpdyFrame
> body3(spdy_util_
.ConstructSpdyBodyFrame(5, true));
5710 MockRead reads
[] = {
5711 CreateMockRead(*resp1
, 1),
5712 CreateMockRead(*body1
, 2),
5713 CreateMockRead(*resp2
, 5),
5714 CreateMockRead(*body2
, 6),
5715 CreateMockRead(*resp3
, 7),
5716 CreateMockRead(*body3
, 8),
5717 MockRead(ASYNC
, 0, 9) // EOF
5720 DeterministicSocketData
data(reads
, arraysize(reads
),
5721 writes
, arraysize(writes
));
5722 NormalSpdyTransactionHelper
helper(CreateGetRequest(), LOWEST
,
5723 BoundNetLog(), GetParam(), NULL
);
5724 helper
.SetDeterministic();
5725 helper
.RunPreTestSetup();
5726 helper
.AddDeterministicData(&data
);
5728 // Start the first transaction to set up the SpdySession
5729 HttpNetworkTransaction
* trans
= helper
.trans();
5730 TestCompletionCallback callback
;
5731 HttpRequestInfo info1
= CreateGetRequest();
5732 int rv
= trans
->Start(&info1
, callback
.callback(), BoundNetLog());
5733 EXPECT_EQ(ERR_IO_PENDING
, rv
);
5735 // Run the message loop, but do not allow the write to complete.
5736 // This leaves the SpdySession with a write pending, which prevents
5737 // SpdySession from attempting subsequent writes until this write completes.
5738 base::RunLoop().RunUntilIdle();
5740 // Now, start both new transactions
5741 HttpRequestInfo info2
= CreateGetRequest();
5742 TestCompletionCallback callback2
;
5743 scoped_ptr
<HttpNetworkTransaction
> trans2(
5744 new HttpNetworkTransaction(MEDIUM
, helper
.session().get()));
5745 rv
= trans2
->Start(&info2
, callback2
.callback(), BoundNetLog());
5746 EXPECT_EQ(ERR_IO_PENDING
, rv
);
5747 base::RunLoop().RunUntilIdle();
5749 HttpRequestInfo info3
= CreateGetRequest();
5750 TestCompletionCallback callback3
;
5751 scoped_ptr
<HttpNetworkTransaction
> trans3(
5752 new HttpNetworkTransaction(HIGHEST
, helper
.session().get()));
5753 rv
= trans3
->Start(&info3
, callback3
.callback(), BoundNetLog());
5754 EXPECT_EQ(ERR_IO_PENDING
, rv
);
5755 base::RunLoop().RunUntilIdle();
5757 // We now have two SYN_STREAM frames queued up which will be
5758 // dequeued only once the first write completes, which we
5759 // now allow to happen.
5761 EXPECT_EQ(OK
, callback
.WaitForResult());
5763 // And now we can allow everything else to run to completion.
5766 EXPECT_EQ(OK
, callback2
.WaitForResult());
5767 EXPECT_EQ(OK
, callback3
.WaitForResult());
5769 helper
.VerifyDataConsumed();
5772 // The tests below are only for SPDY/3 and above.
5774 // Test that sent data frames and received WINDOW_UPDATE frames change
5775 // the send_window_size_ correctly.
5777 // WINDOW_UPDATE is different than most other frames in that it can arrive
5778 // while the client is still sending the request body. In order to enforce
5779 // this scenario, we feed a couple of dummy frames and give a delay of 0 to
5780 // socket data provider, so that initial read that is done as soon as the
5781 // stream is created, succeeds and schedules another read. This way reads
5782 // and writes are interleaved; after doing a full frame write, SpdyStream
5783 // will break out of DoLoop and will read and process a WINDOW_UPDATE.
5784 // Once our WINDOW_UPDATE is read, we cannot send SYN_REPLY right away
5785 // since request has not been completely written, therefore we feed
5786 // enough number of WINDOW_UPDATEs to finish the first read and cause a
5787 // write, leading to a complete write of request body; after that we send
5788 // a reply with a body, to cause a graceful shutdown.
5790 // TODO(agayev): develop a socket data provider where both, reads and
5791 // writes are ordered so that writing tests like these are easy and rewrite
5792 // all these tests using it. Right now we are working around the
5793 // limitations as described above and it's not deterministic, tests may
5794 // fail under specific circumstances.
5795 TEST_P(SpdyNetworkTransactionTest
, WindowUpdateReceived
) {
5796 static int kFrameCount
= 2;
5797 scoped_ptr
<std::string
> content(
5798 new std::string(kMaxSpdyFrameChunkSize
, 'a'));
5799 scoped_ptr
<SpdyFrame
> req(spdy_util_
.ConstructSpdyPost(
5800 GetDefaultUrl(), 1, kMaxSpdyFrameChunkSize
* kFrameCount
, LOWEST
, NULL
,
5802 scoped_ptr
<SpdyFrame
> body(
5803 spdy_util_
.ConstructSpdyBodyFrame(
5804 1, content
->c_str(), content
->size(), false));
5805 scoped_ptr
<SpdyFrame
> body_end(
5806 spdy_util_
.ConstructSpdyBodyFrame(
5807 1, content
->c_str(), content
->size(), true));
5809 MockWrite writes
[] = {
5810 CreateMockWrite(*req
, 0),
5811 CreateMockWrite(*body
, 1),
5812 CreateMockWrite(*body_end
, 2),
5815 static const int32 kDeltaWindowSize
= 0xff;
5816 static const int kDeltaCount
= 4;
5817 scoped_ptr
<SpdyFrame
> window_update(
5818 spdy_util_
.ConstructSpdyWindowUpdate(1, kDeltaWindowSize
));
5819 scoped_ptr
<SpdyFrame
> window_update_dummy(
5820 spdy_util_
.ConstructSpdyWindowUpdate(2, kDeltaWindowSize
));
5821 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyPostSynReply(NULL
, 0));
5822 MockRead reads
[] = {
5823 CreateMockRead(*window_update_dummy
, 3),
5824 CreateMockRead(*window_update_dummy
, 4),
5825 CreateMockRead(*window_update_dummy
, 5),
5826 CreateMockRead(*window_update
, 6), // Four updates, therefore window
5827 CreateMockRead(*window_update
, 7), // size should increase by
5828 CreateMockRead(*window_update
, 8), // kDeltaWindowSize * 4
5829 CreateMockRead(*window_update
, 9),
5830 CreateMockRead(*resp
, 10),
5831 CreateMockRead(*body_end
, 11),
5832 MockRead(ASYNC
, 0, 0, 12) // EOF
5835 DeterministicSocketData
data(reads
, arraysize(reads
),
5836 writes
, arraysize(writes
));
5838 ScopedVector
<UploadElementReader
> element_readers
;
5839 for (int i
= 0; i
< kFrameCount
; ++i
) {
5840 element_readers
.push_back(
5841 new UploadBytesElementReader(content
->c_str(), content
->size()));
5843 ElementsUploadDataStream
upload_data_stream(element_readers
.Pass(), 0);
5845 // Setup the request
5846 HttpRequestInfo request
;
5847 request
.method
= "POST";
5848 request
.url
= GURL(GetDefaultUrl());
5849 request
.upload_data_stream
= &upload_data_stream
;
5851 NormalSpdyTransactionHelper
helper(request
, DEFAULT_PRIORITY
,
5852 BoundNetLog(), GetParam(), NULL
);
5853 helper
.SetDeterministic();
5854 helper
.AddDeterministicData(&data
);
5855 helper
.RunPreTestSetup();
5857 HttpNetworkTransaction
* trans
= helper
.trans();
5859 TestCompletionCallback callback
;
5860 int rv
= trans
->Start(&helper
.request(), callback
.callback(), BoundNetLog());
5862 EXPECT_EQ(ERR_IO_PENDING
, rv
);
5866 SpdyHttpStream
* stream
= static_cast<SpdyHttpStream
*>(trans
->stream_
.get());
5867 ASSERT_TRUE(stream
!= NULL
);
5868 ASSERT_TRUE(stream
->stream() != NULL
);
5869 EXPECT_EQ(static_cast<int>(
5870 SpdySession::GetDefaultInitialWindowSize(GetParam().protocol
)) +
5871 kDeltaWindowSize
* kDeltaCount
-
5872 kMaxSpdyFrameChunkSize
* kFrameCount
,
5873 stream
->stream()->send_window_size());
5877 rv
= callback
.WaitForResult();
5880 helper
.VerifyDataConsumed();
5883 // Test that received data frames and sent WINDOW_UPDATE frames change
5884 // the recv_window_size_ correctly.
5885 TEST_P(SpdyNetworkTransactionTest
, WindowUpdateSent
) {
5886 const int32 default_initial_window_size
=
5887 SpdySession::GetDefaultInitialWindowSize(GetParam().protocol
);
5888 // Session level maximum window size that is more than twice the default
5889 // initial window size so that an initial window update is sent.
5890 const int32 session_max_recv_window_size
= 5 * 64 * 1024;
5891 ASSERT_LT(2 * default_initial_window_size
, session_max_recv_window_size
);
5892 // Stream level maximum window size that is less than the session level
5893 // maximum window size so that we test for confusion between the two.
5894 const int32 stream_max_recv_window_size
= 4 * 64 * 1024;
5895 ASSERT_GT(session_max_recv_window_size
, stream_max_recv_window_size
);
5896 // Size of body to be sent. Has to be less than or equal to both window sizes
5897 // so that we do not run out of receiving window. Also has to be greater than
5898 // half of them so that it triggers both a session level and a stream level
5899 // window update frame.
5900 const int32 kTargetSize
= 3 * 64 * 1024;
5901 ASSERT_GE(session_max_recv_window_size
, kTargetSize
);
5902 ASSERT_GE(stream_max_recv_window_size
, kTargetSize
);
5903 ASSERT_LT(session_max_recv_window_size
/ 2, kTargetSize
);
5904 ASSERT_LT(stream_max_recv_window_size
/ 2, kTargetSize
);
5905 // Size of each DATA frame.
5906 const int32 kChunkSize
= 4096;
5907 // Size of window updates.
5908 ASSERT_EQ(0, session_max_recv_window_size
/ 2 % kChunkSize
);
5909 const int32 session_window_update_delta
=
5910 session_max_recv_window_size
/ 2 + kChunkSize
;
5911 ASSERT_EQ(0, stream_max_recv_window_size
/ 2 % kChunkSize
);
5912 const int32 stream_window_update_delta
=
5913 stream_max_recv_window_size
/ 2 + kChunkSize
;
5915 SettingsMap initial_settings
;
5916 initial_settings
[SETTINGS_MAX_CONCURRENT_STREAMS
] =
5917 SettingsFlagsAndValue(SETTINGS_FLAG_NONE
, kMaxConcurrentPushedStreams
);
5918 initial_settings
[SETTINGS_INITIAL_WINDOW_SIZE
] =
5919 SettingsFlagsAndValue(SETTINGS_FLAG_NONE
, stream_max_recv_window_size
);
5920 scoped_ptr
<SpdyFrame
> initial_settings_frame(
5921 spdy_util_
.ConstructSpdySettings(initial_settings
));
5922 scoped_ptr
<SpdyFrame
> initial_window_update(
5923 spdy_util_
.ConstructSpdyWindowUpdate(
5924 kSessionFlowControlStreamId
,
5925 session_max_recv_window_size
- default_initial_window_size
));
5926 scoped_ptr
<SpdyFrame
> req(
5927 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
5928 scoped_ptr
<SpdyFrame
> session_window_update(
5929 spdy_util_
.ConstructSpdyWindowUpdate(0, session_window_update_delta
));
5930 scoped_ptr
<SpdyFrame
> stream_window_update(
5931 spdy_util_
.ConstructSpdyWindowUpdate(1, stream_window_update_delta
));
5933 std::vector
<MockWrite
> writes
;
5934 if ((GetParam().protocol
>= kProtoSPDY4MinimumVersion
) &&
5935 (GetParam().protocol
<= kProtoSPDY4MaximumVersion
)) {
5936 writes
.push_back(MockWrite(ASYNC
, kHttp2ConnectionHeaderPrefix
,
5937 kHttp2ConnectionHeaderPrefixSize
, 0));
5939 writes
.push_back(CreateMockWrite(*initial_settings_frame
));
5940 writes
.push_back(CreateMockWrite(*initial_window_update
));
5941 writes
.push_back(CreateMockWrite(*req
));
5942 writes
.push_back(CreateMockWrite(*session_window_update
));
5943 writes
.push_back(CreateMockWrite(*stream_window_update
));
5945 std::vector
<MockRead
> reads
;
5946 scoped_ptr
<SpdyFrame
> resp(
5947 spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
5948 reads
.push_back(CreateMockRead(*resp
));
5950 ScopedVector
<SpdyFrame
> body_frames
;
5951 const std::string
body_data(kChunkSize
, 'x');
5952 for (size_t remaining
= kTargetSize
; remaining
!= 0;) {
5953 size_t frame_size
= std::min(remaining
, body_data
.size());
5954 body_frames
.push_back(spdy_util_
.ConstructSpdyBodyFrame(
5955 1, body_data
.data(), frame_size
, false));
5956 reads
.push_back(CreateMockRead(*body_frames
.back()));
5957 remaining
-= frame_size
;
5959 reads
.push_back(MockRead(ASYNC
, ERR_IO_PENDING
, 0)); // Yield.
5961 DelayedSocketData
data(2, vector_as_array(&reads
), reads
.size(),
5962 vector_as_array(&writes
), writes
.size());
5964 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
5965 BoundNetLog(), GetParam(), NULL
);
5966 helper
.AddData(&data
);
5967 helper
.RunPreTestSetup();
5969 SpdySessionPool
* spdy_session_pool
= helper
.session()->spdy_session_pool();
5970 SpdySessionPoolPeer
pool_peer(spdy_session_pool
);
5971 pool_peer
.SetEnableSendingInitialData(true);
5972 pool_peer
.SetSessionMaxRecvWindowSize(session_max_recv_window_size
);
5973 pool_peer
.SetStreamInitialRecvWindowSize(stream_max_recv_window_size
);
5975 HttpNetworkTransaction
* trans
= helper
.trans();
5976 TestCompletionCallback callback
;
5977 int rv
= trans
->Start(&helper
.request(), callback
.callback(), BoundNetLog());
5979 EXPECT_EQ(ERR_IO_PENDING
, rv
);
5980 rv
= callback
.WaitForResult();
5983 SpdyHttpStream
* stream
=
5984 static_cast<SpdyHttpStream
*>(trans
->stream_
.get());
5985 ASSERT_TRUE(stream
!= NULL
);
5986 ASSERT_TRUE(stream
->stream() != NULL
);
5988 // All data has been read, but not consumed. The window reflects this.
5989 EXPECT_EQ(static_cast<int>(stream_max_recv_window_size
- kTargetSize
),
5990 stream
->stream()->recv_window_size());
5992 const HttpResponseInfo
* response
= trans
->GetResponseInfo();
5993 ASSERT_TRUE(response
!= NULL
);
5994 ASSERT_TRUE(response
->headers
.get() != NULL
);
5995 EXPECT_EQ("HTTP/1.1 200 OK", response
->headers
->GetStatusLine());
5996 EXPECT_TRUE(response
->was_fetched_via_spdy
);
5998 // Issue a read which will cause a WINDOW_UPDATE to be sent and window
5999 // size increased to default.
6000 scoped_refptr
<IOBuffer
> buf(new IOBuffer(kTargetSize
));
6001 EXPECT_EQ(static_cast<int>(kTargetSize
),
6002 trans
->Read(buf
.get(), kTargetSize
, CompletionCallback()));
6003 EXPECT_EQ(static_cast<int>(stream_max_recv_window_size
),
6004 stream
->stream()->recv_window_size());
6005 EXPECT_THAT(base::StringPiece(buf
->data(), kTargetSize
), Each(Eq('x')));
6007 // Allow scheduled WINDOW_UPDATE frames to write.
6008 base::RunLoop().RunUntilIdle();
6009 helper
.VerifyDataConsumed();
6012 // Test that WINDOW_UPDATE frame causing overflow is handled correctly.
6013 TEST_P(SpdyNetworkTransactionTest
, WindowUpdateOverflow
) {
6014 // Number of full frames we hope to write (but will not, used to
6015 // set content-length header correctly)
6016 static int kFrameCount
= 3;
6018 scoped_ptr
<std::string
> content(
6019 new std::string(kMaxSpdyFrameChunkSize
, 'a'));
6020 scoped_ptr
<SpdyFrame
> req(spdy_util_
.ConstructSpdyPost(
6021 GetDefaultUrl(), 1, kMaxSpdyFrameChunkSize
* kFrameCount
, LOWEST
, NULL
,
6023 scoped_ptr
<SpdyFrame
> body(
6024 spdy_util_
.ConstructSpdyBodyFrame(
6025 1, content
->c_str(), content
->size(), false));
6026 scoped_ptr
<SpdyFrame
> rst(
6027 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_FLOW_CONTROL_ERROR
));
6029 // We're not going to write a data frame with FIN, we'll receive a bad
6030 // WINDOW_UPDATE while sending a request and will send a RST_STREAM frame.
6031 MockWrite writes
[] = {
6032 CreateMockWrite(*req
, 0),
6033 CreateMockWrite(*body
, 2),
6034 CreateMockWrite(*rst
, 3),
6037 static const int32 kDeltaWindowSize
= 0x7fffffff; // cause an overflow
6038 scoped_ptr
<SpdyFrame
> window_update(
6039 spdy_util_
.ConstructSpdyWindowUpdate(1, kDeltaWindowSize
));
6040 MockRead reads
[] = {
6041 CreateMockRead(*window_update
, 1),
6042 MockRead(ASYNC
, 0, 4) // EOF
6045 DeterministicSocketData
data(reads
, arraysize(reads
),
6046 writes
, arraysize(writes
));
6048 ScopedVector
<UploadElementReader
> element_readers
;
6049 for (int i
= 0; i
< kFrameCount
; ++i
) {
6050 element_readers
.push_back(
6051 new UploadBytesElementReader(content
->c_str(), content
->size()));
6053 ElementsUploadDataStream
upload_data_stream(element_readers
.Pass(), 0);
6055 // Setup the request
6056 HttpRequestInfo request
;
6057 request
.method
= "POST";
6058 request
.url
= GURL(GetDefaultUrl());
6059 request
.upload_data_stream
= &upload_data_stream
;
6061 NormalSpdyTransactionHelper
helper(request
, DEFAULT_PRIORITY
,
6062 BoundNetLog(), GetParam(), NULL
);
6063 helper
.SetDeterministic();
6064 helper
.RunPreTestSetup();
6065 helper
.AddDeterministicData(&data
);
6066 HttpNetworkTransaction
* trans
= helper
.trans();
6068 TestCompletionCallback callback
;
6069 int rv
= trans
->Start(&helper
.request(), callback
.callback(), BoundNetLog());
6070 ASSERT_EQ(ERR_IO_PENDING
, rv
);
6073 ASSERT_TRUE(callback
.have_result());
6074 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR
, callback
.WaitForResult());
6075 helper
.VerifyDataConsumed();
6078 // Test that after hitting a send window size of 0, the write process
6079 // stalls and upon receiving WINDOW_UPDATE frame write resumes.
6081 // This test constructs a POST request followed by enough data frames
6082 // containing 'a' that would make the window size 0, followed by another
6083 // data frame containing default content (which is "hello!") and this frame
6084 // also contains a FIN flag. DelayedSocketData is used to enforce all
6085 // writes go through before a read could happen. However, the last frame
6086 // ("hello!") is not supposed to go through since by the time its turn
6087 // arrives, window size is 0. At this point MessageLoop::Run() called via
6088 // callback would block. Therefore we call MessageLoop::RunUntilIdle()
6089 // which returns after performing all possible writes. We use DCHECKS to
6090 // ensure that last data frame is still there and stream has stalled.
6091 // After that, next read is artifically enforced, which causes a
6092 // WINDOW_UPDATE to be read and I/O process resumes.
6093 TEST_P(SpdyNetworkTransactionTest
, FlowControlStallResume
) {
6094 const int32 initial_window_size
=
6095 SpdySession::GetDefaultInitialWindowSize(GetParam().protocol
);
6096 // Number of frames we need to send to zero out the window size: data
6097 // frames plus SYN_STREAM plus the last data frame; also we need another
6098 // data frame that we will send once the WINDOW_UPDATE is received,
6100 size_t num_writes
= initial_window_size
/ kMaxSpdyFrameChunkSize
+ 3;
6102 // Calculate last frame's size; 0 size data frame is legal.
6103 size_t last_frame_size
= initial_window_size
% kMaxSpdyFrameChunkSize
;
6105 // Construct content for a data frame of maximum size.
6106 std::string
content(kMaxSpdyFrameChunkSize
, 'a');
6108 scoped_ptr
<SpdyFrame
> req(spdy_util_
.ConstructSpdyPost(
6109 GetDefaultUrl(), 1, initial_window_size
+ kUploadDataSize
, LOWEST
, NULL
,
6113 scoped_ptr
<SpdyFrame
> body1(
6114 spdy_util_
.ConstructSpdyBodyFrame(
6115 1, content
.c_str(), content
.size(), false));
6117 // Last frame to zero out the window size.
6118 scoped_ptr
<SpdyFrame
> body2(
6119 spdy_util_
.ConstructSpdyBodyFrame(
6120 1, content
.c_str(), last_frame_size
, false));
6122 // Data frame to be sent once WINDOW_UPDATE frame is received.
6123 scoped_ptr
<SpdyFrame
> body3(spdy_util_
.ConstructSpdyBodyFrame(1, true));
6125 // Fill in mock writes.
6126 scoped_ptr
<MockWrite
[]> writes(new MockWrite
[num_writes
]);
6128 writes
[i
] = CreateMockWrite(*req
);
6129 for (i
= 1; i
< num_writes
- 2; i
++)
6130 writes
[i
] = CreateMockWrite(*body1
);
6131 writes
[i
++] = CreateMockWrite(*body2
);
6132 writes
[i
] = CreateMockWrite(*body3
);
6134 // Construct read frame, give enough space to upload the rest of the
6136 scoped_ptr
<SpdyFrame
> session_window_update(
6137 spdy_util_
.ConstructSpdyWindowUpdate(0, kUploadDataSize
));
6138 scoped_ptr
<SpdyFrame
> window_update(
6139 spdy_util_
.ConstructSpdyWindowUpdate(1, kUploadDataSize
));
6140 scoped_ptr
<SpdyFrame
> reply(spdy_util_
.ConstructSpdyPostSynReply(NULL
, 0));
6141 MockRead reads
[] = {
6142 CreateMockRead(*session_window_update
),
6143 CreateMockRead(*session_window_update
),
6144 CreateMockRead(*window_update
),
6145 CreateMockRead(*window_update
),
6146 CreateMockRead(*reply
),
6147 CreateMockRead(*body2
),
6148 CreateMockRead(*body3
),
6149 MockRead(ASYNC
, 0, 0) // EOF
6152 // Skip the session window updates unless we're using SPDY/3.1 and
6154 size_t read_offset
= (GetParam().protocol
>= kProtoSPDY31
) ? 0 : 2;
6155 size_t num_reads
= arraysize(reads
) - read_offset
;
6157 // Force all writes to happen before any read, last write will not
6158 // actually queue a frame, due to window size being 0.
6159 DelayedSocketData
data(num_writes
, reads
+ read_offset
, num_reads
,
6160 writes
.get(), num_writes
);
6162 ScopedVector
<UploadElementReader
> element_readers
;
6163 std::string
upload_data_string(initial_window_size
, 'a');
6164 upload_data_string
.append(kUploadData
, kUploadDataSize
);
6165 element_readers
.push_back(new UploadBytesElementReader(
6166 upload_data_string
.c_str(), upload_data_string
.size()));
6167 ElementsUploadDataStream
upload_data_stream(element_readers
.Pass(), 0);
6169 HttpRequestInfo request
;
6170 request
.method
= "POST";
6171 request
.url
= GURL(GetDefaultUrl());
6172 request
.upload_data_stream
= &upload_data_stream
;
6173 NormalSpdyTransactionHelper
helper(request
, DEFAULT_PRIORITY
,
6174 BoundNetLog(), GetParam(), NULL
);
6175 helper
.AddData(&data
);
6176 helper
.RunPreTestSetup();
6178 HttpNetworkTransaction
* trans
= helper
.trans();
6180 TestCompletionCallback callback
;
6181 int rv
= trans
->Start(&helper
.request(), callback
.callback(), BoundNetLog());
6182 EXPECT_EQ(ERR_IO_PENDING
, rv
);
6184 base::RunLoop().RunUntilIdle(); // Write as much as we can.
6186 SpdyHttpStream
* stream
= static_cast<SpdyHttpStream
*>(trans
->stream_
.get());
6187 ASSERT_TRUE(stream
!= NULL
);
6188 ASSERT_TRUE(stream
->stream() != NULL
);
6189 EXPECT_EQ(0, stream
->stream()->send_window_size());
6190 // All the body data should have been read.
6191 // TODO(satorux): This is because of the weirdness in reading the request
6192 // body in OnSendBodyComplete(). See crbug.com/113107.
6193 EXPECT_TRUE(upload_data_stream
.IsEOF());
6194 // But the body is not yet fully sent (kUploadData is not yet sent)
6195 // since we're send-stalled.
6196 EXPECT_TRUE(stream
->stream()->send_stalled_by_flow_control());
6198 data
.ForceNextRead(); // Read in WINDOW_UPDATE frame.
6199 rv
= callback
.WaitForResult();
6200 helper
.VerifyDataConsumed();
6203 // Test we correctly handle the case where the SETTINGS frame results in
6204 // unstalling the send window.
6205 TEST_P(SpdyNetworkTransactionTest
, FlowControlStallResumeAfterSettings
) {
6206 const int32 initial_window_size
=
6207 SpdySession::GetDefaultInitialWindowSize(GetParam().protocol
);
6209 // Number of frames we need to send to zero out the window size: data
6210 // frames plus SYN_STREAM plus the last data frame; also we need another
6211 // data frame that we will send once the SETTING is received, therefore +3.
6212 size_t num_writes
= initial_window_size
/ kMaxSpdyFrameChunkSize
+ 3;
6214 // Calculate last frame's size; 0 size data frame is legal.
6215 size_t last_frame_size
= initial_window_size
% kMaxSpdyFrameChunkSize
;
6217 // Construct content for a data frame of maximum size.
6218 std::string
content(kMaxSpdyFrameChunkSize
, 'a');
6220 scoped_ptr
<SpdyFrame
> req(spdy_util_
.ConstructSpdyPost(
6221 GetDefaultUrl(), 1, initial_window_size
+ kUploadDataSize
, LOWEST
, NULL
,
6225 scoped_ptr
<SpdyFrame
> body1(
6226 spdy_util_
.ConstructSpdyBodyFrame(
6227 1, content
.c_str(), content
.size(), false));
6229 // Last frame to zero out the window size.
6230 scoped_ptr
<SpdyFrame
> body2(
6231 spdy_util_
.ConstructSpdyBodyFrame(
6232 1, content
.c_str(), last_frame_size
, false));
6234 // Data frame to be sent once SETTINGS frame is received.
6235 scoped_ptr
<SpdyFrame
> body3(spdy_util_
.ConstructSpdyBodyFrame(1, true));
6237 // Fill in mock reads/writes.
6238 std::vector
<MockRead
> reads
;
6239 std::vector
<MockWrite
> writes
;
6241 writes
.push_back(CreateMockWrite(*req
, i
++));
6242 while (i
< num_writes
- 2)
6243 writes
.push_back(CreateMockWrite(*body1
, i
++));
6244 writes
.push_back(CreateMockWrite(*body2
, i
++));
6246 // Construct read frame for SETTINGS that gives enough space to upload the
6247 // rest of the data.
6248 SettingsMap settings
;
6249 settings
[SETTINGS_INITIAL_WINDOW_SIZE
] =
6250 SettingsFlagsAndValue(SETTINGS_FLAG_NONE
, initial_window_size
* 2);
6251 scoped_ptr
<SpdyFrame
> settings_frame_large(
6252 spdy_util_
.ConstructSpdySettings(settings
));
6254 reads
.push_back(CreateMockRead(*settings_frame_large
, i
++));
6256 scoped_ptr
<SpdyFrame
> session_window_update(
6257 spdy_util_
.ConstructSpdyWindowUpdate(0, kUploadDataSize
));
6258 if (GetParam().protocol
>= kProtoSPDY31
)
6259 reads
.push_back(CreateMockRead(*session_window_update
, i
++));
6261 scoped_ptr
<SpdyFrame
> settings_ack(spdy_util_
.ConstructSpdySettingsAck());
6262 writes
.push_back(CreateMockWrite(*settings_ack
, i
++));
6264 writes
.push_back(CreateMockWrite(*body3
, i
++));
6266 scoped_ptr
<SpdyFrame
> reply(spdy_util_
.ConstructSpdyPostSynReply(NULL
, 0));
6267 reads
.push_back(CreateMockRead(*reply
, i
++));
6268 reads
.push_back(CreateMockRead(*body2
, i
++));
6269 reads
.push_back(CreateMockRead(*body3
, i
++));
6270 reads
.push_back(MockRead(ASYNC
, 0, i
++)); // EOF
6272 // Force all writes to happen before any read, last write will not
6273 // actually queue a frame, due to window size being 0.
6274 DeterministicSocketData
data(vector_as_array(&reads
), reads
.size(),
6275 vector_as_array(&writes
), writes
.size());
6277 ScopedVector
<UploadElementReader
> element_readers
;
6278 std::string
upload_data_string(initial_window_size
, 'a');
6279 upload_data_string
.append(kUploadData
, kUploadDataSize
);
6280 element_readers
.push_back(new UploadBytesElementReader(
6281 upload_data_string
.c_str(), upload_data_string
.size()));
6282 ElementsUploadDataStream
upload_data_stream(element_readers
.Pass(), 0);
6284 HttpRequestInfo request
;
6285 request
.method
= "POST";
6286 request
.url
= GURL(GetDefaultUrl());
6287 request
.upload_data_stream
= &upload_data_stream
;
6288 NormalSpdyTransactionHelper
helper(request
, DEFAULT_PRIORITY
,
6289 BoundNetLog(), GetParam(), NULL
);
6290 helper
.SetDeterministic();
6291 helper
.RunPreTestSetup();
6292 helper
.AddDeterministicData(&data
);
6294 HttpNetworkTransaction
* trans
= helper
.trans();
6296 TestCompletionCallback callback
;
6297 int rv
= trans
->Start(&helper
.request(), callback
.callback(), BoundNetLog());
6298 EXPECT_EQ(ERR_IO_PENDING
, rv
);
6300 data
.RunFor(num_writes
- 1); // Write as much as we can.
6302 SpdyHttpStream
* stream
= static_cast<SpdyHttpStream
*>(trans
->stream_
.get());
6303 ASSERT_TRUE(stream
!= NULL
);
6304 ASSERT_TRUE(stream
->stream() != NULL
);
6305 EXPECT_EQ(0, stream
->stream()->send_window_size());
6307 // All the body data should have been read.
6308 // TODO(satorux): This is because of the weirdness in reading the request
6309 // body in OnSendBodyComplete(). See crbug.com/113107.
6310 EXPECT_TRUE(upload_data_stream
.IsEOF());
6311 // But the body is not yet fully sent (kUploadData is not yet sent)
6312 // since we're send-stalled.
6313 EXPECT_TRUE(stream
->stream()->send_stalled_by_flow_control());
6315 data
.RunFor(7); // Read in SETTINGS frame to unstall.
6316 rv
= callback
.WaitForResult();
6317 helper
.VerifyDataConsumed();
6318 // If stream is NULL, that means it was unstalled and closed.
6319 EXPECT_TRUE(stream
->stream() == NULL
);
6322 // Test we correctly handle the case where the SETTINGS frame results in a
6323 // negative send window size.
6324 TEST_P(SpdyNetworkTransactionTest
, FlowControlNegativeSendWindowSize
) {
6325 const int32 initial_window_size
=
6326 SpdySession::GetDefaultInitialWindowSize(GetParam().protocol
);
6327 // Number of frames we need to send to zero out the window size: data
6328 // frames plus SYN_STREAM plus the last data frame; also we need another
6329 // data frame that we will send once the SETTING is received, therefore +3.
6330 size_t num_writes
= initial_window_size
/ kMaxSpdyFrameChunkSize
+ 3;
6332 // Calculate last frame's size; 0 size data frame is legal.
6333 size_t last_frame_size
= initial_window_size
% kMaxSpdyFrameChunkSize
;
6335 // Construct content for a data frame of maximum size.
6336 std::string
content(kMaxSpdyFrameChunkSize
, 'a');
6338 scoped_ptr
<SpdyFrame
> req(spdy_util_
.ConstructSpdyPost(
6339 GetDefaultUrl(), 1, initial_window_size
+ kUploadDataSize
, LOWEST
, NULL
,
6343 scoped_ptr
<SpdyFrame
> body1(
6344 spdy_util_
.ConstructSpdyBodyFrame(
6345 1, content
.c_str(), content
.size(), false));
6347 // Last frame to zero out the window size.
6348 scoped_ptr
<SpdyFrame
> body2(
6349 spdy_util_
.ConstructSpdyBodyFrame(
6350 1, content
.c_str(), last_frame_size
, false));
6352 // Data frame to be sent once SETTINGS frame is received.
6353 scoped_ptr
<SpdyFrame
> body3(spdy_util_
.ConstructSpdyBodyFrame(1, true));
6355 // Fill in mock reads/writes.
6356 std::vector
<MockRead
> reads
;
6357 std::vector
<MockWrite
> writes
;
6359 writes
.push_back(CreateMockWrite(*req
, i
++));
6360 while (i
< num_writes
- 2)
6361 writes
.push_back(CreateMockWrite(*body1
, i
++));
6362 writes
.push_back(CreateMockWrite(*body2
, i
++));
6364 // Construct read frame for SETTINGS that makes the send_window_size
6366 SettingsMap new_settings
;
6367 new_settings
[SETTINGS_INITIAL_WINDOW_SIZE
] =
6368 SettingsFlagsAndValue(SETTINGS_FLAG_NONE
, initial_window_size
/ 2);
6369 scoped_ptr
<SpdyFrame
> settings_frame_small(
6370 spdy_util_
.ConstructSpdySettings(new_settings
));
6371 // Construct read frames for WINDOW_UPDATE that makes the send_window_size
6373 scoped_ptr
<SpdyFrame
> session_window_update_init_size(
6374 spdy_util_
.ConstructSpdyWindowUpdate(0, initial_window_size
));
6375 scoped_ptr
<SpdyFrame
> window_update_init_size(
6376 spdy_util_
.ConstructSpdyWindowUpdate(1, initial_window_size
));
6378 reads
.push_back(CreateMockRead(*settings_frame_small
, i
++));
6379 reads
.push_back(CreateMockRead(*session_window_update_init_size
, i
++));
6380 reads
.push_back(CreateMockRead(*window_update_init_size
, i
++));
6382 scoped_ptr
<SpdyFrame
> settings_ack(spdy_util_
.ConstructSpdySettingsAck());
6383 writes
.push_back(CreateMockWrite(*settings_ack
, i
++));
6385 writes
.push_back(CreateMockWrite(*body3
, i
++));
6387 scoped_ptr
<SpdyFrame
> reply(spdy_util_
.ConstructSpdyPostSynReply(NULL
, 0));
6388 reads
.push_back(CreateMockRead(*reply
, i
++));
6389 reads
.push_back(CreateMockRead(*body2
, i
++));
6390 reads
.push_back(CreateMockRead(*body3
, i
++));
6391 reads
.push_back(MockRead(ASYNC
, 0, i
++)); // EOF
6393 // Force all writes to happen before any read, last write will not
6394 // actually queue a frame, due to window size being 0.
6395 DeterministicSocketData
data(vector_as_array(&reads
), reads
.size(),
6396 vector_as_array(&writes
), writes
.size());
6398 ScopedVector
<UploadElementReader
> element_readers
;
6399 std::string
upload_data_string(initial_window_size
, 'a');
6400 upload_data_string
.append(kUploadData
, kUploadDataSize
);
6401 element_readers
.push_back(new UploadBytesElementReader(
6402 upload_data_string
.c_str(), upload_data_string
.size()));
6403 ElementsUploadDataStream
upload_data_stream(element_readers
.Pass(), 0);
6405 HttpRequestInfo request
;
6406 request
.method
= "POST";
6407 request
.url
= GURL(GetDefaultUrl());
6408 request
.upload_data_stream
= &upload_data_stream
;
6409 NormalSpdyTransactionHelper
helper(request
, DEFAULT_PRIORITY
,
6410 BoundNetLog(), GetParam(), NULL
);
6411 helper
.SetDeterministic();
6412 helper
.RunPreTestSetup();
6413 helper
.AddDeterministicData(&data
);
6415 HttpNetworkTransaction
* trans
= helper
.trans();
6417 TestCompletionCallback callback
;
6418 int rv
= trans
->Start(&helper
.request(), callback
.callback(), BoundNetLog());
6419 EXPECT_EQ(ERR_IO_PENDING
, rv
);
6421 data
.RunFor(num_writes
- 1); // Write as much as we can.
6423 SpdyHttpStream
* stream
= static_cast<SpdyHttpStream
*>(trans
->stream_
.get());
6424 ASSERT_TRUE(stream
!= NULL
);
6425 ASSERT_TRUE(stream
->stream() != NULL
);
6426 EXPECT_EQ(0, stream
->stream()->send_window_size());
6428 // All the body data should have been read.
6429 // TODO(satorux): This is because of the weirdness in reading the request
6430 // body in OnSendBodyComplete(). See crbug.com/113107.
6431 EXPECT_TRUE(upload_data_stream
.IsEOF());
6432 // But the body is not yet fully sent (kUploadData is not yet sent)
6433 // since we're send-stalled.
6434 EXPECT_TRUE(stream
->stream()->send_stalled_by_flow_control());
6436 // Read in WINDOW_UPDATE or SETTINGS frame.
6437 data
.RunFor((GetParam().protocol
>= kProtoSPDY31
) ? 9 : 8);
6438 rv
= callback
.WaitForResult();
6439 helper
.VerifyDataConsumed();
6442 TEST_P(SpdyNetworkTransactionTest
, GoAwayOnOddPushStreamId
) {
6443 if (spdy_util_
.spdy_version() < SPDY3
)
6446 scoped_ptr
<SpdyHeaderBlock
> push_headers(new SpdyHeaderBlock
);
6447 spdy_util_
.AddUrlToHeaderBlock("http://www.example.org/a.dat",
6448 push_headers
.get());
6449 scoped_ptr
<SpdyFrame
> push(
6450 spdy_util_
.ConstructInitialSpdyPushFrame(push_headers
.Pass(), 3, 1));
6451 MockRead reads
[] = {CreateMockRead(*push
, 1)};
6453 scoped_ptr
<SpdyFrame
> req(
6454 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
6455 scoped_ptr
<SpdyFrame
> goaway(spdy_util_
.ConstructSpdyGoAway(
6456 0, GOAWAY_PROTOCOL_ERROR
, "Odd push stream id."));
6457 MockWrite writes
[] = {
6458 CreateMockWrite(*req
, 0), CreateMockWrite(*goaway
, 2),
6461 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
6462 NormalSpdyTransactionHelper
helper(
6463 CreateGetRequest(), DEFAULT_PRIORITY
, BoundNetLog(), GetParam(), NULL
);
6464 helper
.RunToCompletion(&data
);
6465 TransactionHelperResult out
= helper
.output();
6466 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR
, out
.rv
);
6469 TEST_P(SpdyNetworkTransactionTest
,
6470 GoAwayOnPushStreamIdLesserOrEqualThanLastAccepted
) {
6471 if (spdy_util_
.spdy_version() < SPDY3
)
6474 scoped_ptr
<SpdyFrame
> push_a(spdy_util_
.ConstructSpdyPush(
6475 NULL
, 0, 4, 1, GetDefaultUrlWithPath("/a.dat").c_str()));
6476 scoped_ptr
<SpdyHeaderBlock
> push_b_headers(new SpdyHeaderBlock
);
6477 spdy_util_
.AddUrlToHeaderBlock(GetDefaultUrlWithPath("/b.dat"),
6478 push_b_headers
.get());
6479 scoped_ptr
<SpdyFrame
> push_b(
6480 spdy_util_
.ConstructInitialSpdyPushFrame(push_b_headers
.Pass(), 2, 1));
6481 MockRead reads
[] = {
6482 CreateMockRead(*push_a
, 1), CreateMockRead(*push_b
, 2),
6485 scoped_ptr
<SpdyFrame
> req(
6486 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
6487 scoped_ptr
<SpdyFrame
> goaway(spdy_util_
.ConstructSpdyGoAway(
6489 GOAWAY_PROTOCOL_ERROR
,
6490 "New push stream id must be greater than the last accepted."));
6491 MockWrite writes
[] = {
6492 CreateMockWrite(*req
, 0), CreateMockWrite(*goaway
, 3),
6495 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
6496 NormalSpdyTransactionHelper
helper(
6497 CreateGetRequest(), DEFAULT_PRIORITY
, BoundNetLog(), GetParam(), NULL
);
6498 helper
.RunToCompletion(&data
);
6499 TransactionHelperResult out
= helper
.output();
6500 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR
, out
.rv
);
6503 class SpdyNetworkTransactionNoTLSUsageCheckTest
6504 : public SpdyNetworkTransactionTest
{
6506 void RunNoTLSUsageCheckTest(scoped_ptr
<SSLSocketDataProvider
> ssl_provider
) {
6507 // Construct the request.
6508 scoped_ptr
<SpdyFrame
> req(
6509 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
6510 MockWrite writes
[] = {CreateMockWrite(*req
, 0)};
6512 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
6513 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
6514 MockRead reads
[] = {
6515 CreateMockRead(*resp
, 1),
6516 CreateMockRead(*body
, 2),
6517 MockRead(ASYNC
, 0, 3) // EOF
6520 SequencedSocketData
data(reads
, arraysize(reads
), writes
,
6522 HttpRequestInfo request
;
6523 request
.method
= "GET";
6524 request
.url
= GURL("https://www.example.org/");
6525 NormalSpdyTransactionHelper
helper(
6526 request
, DEFAULT_PRIORITY
, BoundNetLog(), GetParam(), NULL
);
6527 helper
.RunToCompletionWithSSLData(&data
, ssl_provider
.Pass());
6528 TransactionHelperResult out
= helper
.output();
6529 EXPECT_EQ(OK
, out
.rv
);
6530 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
6531 EXPECT_EQ("hello!", out
.response_data
);
6535 //-----------------------------------------------------------------------------
6536 // All tests are run with three different connection types: SPDY after NPN
6537 // negotiation, SPDY without SSL, and SPDY with SSL.
6539 // TODO(akalin): Use ::testing::Combine() when we are able to use
6541 INSTANTIATE_TEST_CASE_P(
6543 SpdyNetworkTransactionNoTLSUsageCheckTest
,
6544 ::testing::Values(SpdyNetworkTransactionTestParams(kProtoSPDY31
,
6545 HTTPS_SPDY_VIA_NPN
)));
6547 TEST_P(SpdyNetworkTransactionNoTLSUsageCheckTest
, TLSVersionTooOld
) {
6548 scoped_ptr
<SSLSocketDataProvider
> ssl_provider(
6549 new SSLSocketDataProvider(ASYNC
, OK
));
6550 SSLConnectionStatusSetVersion(SSL_CONNECTION_VERSION_SSL3
,
6551 &ssl_provider
->connection_status
);
6553 RunNoTLSUsageCheckTest(ssl_provider
.Pass());
6556 TEST_P(SpdyNetworkTransactionNoTLSUsageCheckTest
, TLSCipherSuiteSucky
) {
6557 scoped_ptr
<SSLSocketDataProvider
> ssl_provider(
6558 new SSLSocketDataProvider(ASYNC
, OK
));
6559 // Set to TLS_RSA_WITH_NULL_MD5
6560 SSLConnectionStatusSetCipherSuite(0x1, &ssl_provider
->connection_status
);
6562 RunNoTLSUsageCheckTest(ssl_provider
.Pass());
6565 class SpdyNetworkTransactionTLSUsageCheckTest
6566 : public SpdyNetworkTransactionTest
{
6568 void RunTLSUsageCheckTest(scoped_ptr
<SSLSocketDataProvider
> ssl_provider
) {
6569 scoped_ptr
<SpdyFrame
> goaway(
6570 spdy_util_
.ConstructSpdyGoAway(0, GOAWAY_INADEQUATE_SECURITY
, ""));
6571 MockWrite writes
[] = {CreateMockWrite(*goaway
)};
6573 StaticSocketDataProvider
data(NULL
, 0, writes
, arraysize(writes
));
6574 HttpRequestInfo request
;
6575 request
.method
= "GET";
6576 request
.url
= GURL("https://www.example.org/");
6577 NormalSpdyTransactionHelper
helper(
6578 request
, DEFAULT_PRIORITY
, BoundNetLog(), GetParam(), NULL
);
6579 helper
.RunToCompletionWithSSLData(&data
, ssl_provider
.Pass());
6580 TransactionHelperResult out
= helper
.output();
6581 EXPECT_EQ(ERR_SPDY_INADEQUATE_TRANSPORT_SECURITY
, out
.rv
);
6585 INSTANTIATE_TEST_CASE_P(
6587 SpdyNetworkTransactionTLSUsageCheckTest
,
6589 SpdyNetworkTransactionTestParams(kProtoSPDY4_14
, HTTPS_SPDY_VIA_NPN
),
6590 SpdyNetworkTransactionTestParams(kProtoSPDY4
, HTTPS_SPDY_VIA_NPN
)));
6592 TEST_P(SpdyNetworkTransactionTLSUsageCheckTest
, TLSVersionTooOld
) {
6593 scoped_ptr
<SSLSocketDataProvider
> ssl_provider(
6594 new SSLSocketDataProvider(ASYNC
, OK
));
6595 SSLConnectionStatusSetVersion(SSL_CONNECTION_VERSION_SSL3
,
6596 &ssl_provider
->connection_status
);
6598 RunTLSUsageCheckTest(ssl_provider
.Pass());
6601 TEST_P(SpdyNetworkTransactionTLSUsageCheckTest
, TLSCipherSuiteSucky
) {
6602 scoped_ptr
<SSLSocketDataProvider
> ssl_provider(
6603 new SSLSocketDataProvider(ASYNC
, OK
));
6604 // Set to TLS_RSA_WITH_NULL_MD5
6605 SSLConnectionStatusSetCipherSuite(0x1, &ssl_provider
->connection_status
);
6607 RunTLSUsageCheckTest(ssl_provider
.Pass());