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 "base/thread_task_runner_handle.h"
18 #include "net/base/auth.h"
19 #include "net/base/chunked_upload_data_stream.h"
20 #include "net/base/elements_upload_data_stream.h"
21 #include "net/base/request_priority.h"
22 #include "net/base/test_data_directory.h"
23 #include "net/base/upload_bytes_element_reader.h"
24 #include "net/base/upload_file_element_reader.h"
25 #include "net/http/http_network_session_peer.h"
26 #include "net/http/http_network_transaction.h"
27 #include "net/http/http_server_properties.h"
28 #include "net/http/http_transaction_test_util.h"
29 #include "net/log/test_net_log.h"
30 #include "net/log/test_net_log_entry.h"
31 #include "net/log/test_net_log_util.h"
32 #include "net/socket/client_socket_pool_base.h"
33 #include "net/socket/next_proto.h"
34 #include "net/spdy/buffered_spdy_framer.h"
35 #include "net/spdy/spdy_http_stream.h"
36 #include "net/spdy/spdy_http_utils.h"
37 #include "net/spdy/spdy_session.h"
38 #include "net/spdy/spdy_session_pool.h"
39 #include "net/spdy/spdy_test_util_common.h"
40 #include "net/spdy/spdy_test_utils.h"
41 #include "net/ssl/ssl_connection_status_flags.h"
42 #include "net/test/cert_test_util.h"
43 #include "net/url_request/url_request_test_util.h"
44 #include "testing/gmock/include/gmock/gmock.h"
45 #include "testing/platform_test.h"
47 //-----------------------------------------------------------------------------
56 enum SpdyNetworkTransactionTestSSLType
{
57 // Request an https:// URL and use NPN (or ALPN) to negotiate SPDY during
60 // Request and http:// URL to a server that supports SPDY via Alternative
61 // Service on port 443.
62 // See: https//tools.ietf.org/id/draft-ietf-httpbis-alt-svc-06.html
63 HTTP_SPDY_VIA_ALT_SVC
,
66 struct SpdyNetworkTransactionTestParams
{
67 SpdyNetworkTransactionTestParams()
68 : protocol(kProtoSPDY31
), ssl_type(HTTPS_SPDY_VIA_NPN
) {}
70 SpdyNetworkTransactionTestParams(NextProto protocol
,
71 SpdyNetworkTransactionTestSSLType ssl_type
)
72 : protocol(protocol
), ssl_type(ssl_type
) {}
74 friend std::ostream
& operator<<(std::ostream
& os
,
75 const SpdyNetworkTransactionTestParams
& p
) {
78 case HTTP_SPDY_VIA_ALT_SVC
:
79 type_str
= "HTTP_SPDY_VIA_ALT_SVC";
81 case HTTPS_SPDY_VIA_NPN
:
82 type_str
= "HTTPS_SPDY_VIA_NPN";
85 os
<< "{ protocol: " << SSLClientSocket::NextProtoToString(p
.protocol
)
86 << ", ssl_type: " << type_str
<< " }";
91 SpdyNetworkTransactionTestSSLType ssl_type
;
94 void UpdateSpdySessionDependencies(SpdyNetworkTransactionTestParams test_params
,
95 SpdySessionDependencies
* session_deps
) {
96 session_deps
->use_alternate_protocols
= true;
97 session_deps
->next_protos
= SpdyNextProtos();
98 if (test_params
.ssl_type
== HTTP_SPDY_VIA_ALT_SVC
) {
99 session_deps
->http_server_properties
.SetAlternativeService(
100 HostPortPair("www.example.org", 80),
101 AlternativeService(AlternateProtocolFromNextProto(test_params
.protocol
),
102 "www.example.org", 443),
107 SpdySessionDependencies
* CreateSpdySessionDependencies(
108 SpdyNetworkTransactionTestParams test_params
) {
109 SpdySessionDependencies
* session_deps
=
110 new SpdySessionDependencies(test_params
.protocol
);
111 UpdateSpdySessionDependencies(test_params
, session_deps
);
115 SpdySessionDependencies
* CreateSpdySessionDependencies(
116 SpdyNetworkTransactionTestParams test_params
,
117 ProxyService
* proxy_service
) {
118 SpdySessionDependencies
* session_deps
=
119 new SpdySessionDependencies(test_params
.protocol
, proxy_service
);
120 UpdateSpdySessionDependencies(test_params
, session_deps
);
126 class SpdyNetworkTransactionTest
127 : public ::testing::TestWithParam
<SpdyNetworkTransactionTestParams
> {
129 SpdyNetworkTransactionTest() : spdy_util_(GetParam().protocol
) {
130 spdy_util_
.set_default_url(GURL(GetDefaultUrl()));
133 virtual ~SpdyNetworkTransactionTest() {
134 // UploadDataStream may post a deletion tasks back to the message loop on
136 upload_data_stream_
.reset();
137 base::RunLoop().RunUntilIdle();
140 void SetUp() override
{
141 get_request_initialized_
= false;
142 post_request_initialized_
= false;
143 chunked_post_request_initialized_
= false;
144 ASSERT_TRUE(temp_dir_
.CreateUniqueTempDir());
147 struct TransactionHelperResult
{
149 std::string status_line
;
150 std::string response_data
;
151 HttpResponseInfo response_info
;
154 // A helper class that handles all the initial npn/ssl setup.
155 class NormalSpdyTransactionHelper
{
157 NormalSpdyTransactionHelper(const HttpRequestInfo
& request
,
158 RequestPriority priority
,
159 const BoundNetLog
& log
,
160 SpdyNetworkTransactionTestParams test_params
,
161 SpdySessionDependencies
* session_deps
)
164 session_deps_(session_deps
== NULL
165 ? CreateSpdySessionDependencies(test_params
)
168 SpdySessionDependencies::SpdyCreateSession(session_deps_
.get())),
170 test_params_(test_params
),
172 deterministic_(false),
173 spdy_enabled_(true) {}
175 ~NormalSpdyTransactionHelper() {
176 // Any test which doesn't close the socket by sending it an EOF will
177 // have a valid session left open, which leaks the entire session pool.
178 // This is just fine - in fact, some of our tests intentionally do this
179 // so that we can check consistency of the SpdySessionPool as the test
180 // finishes. If we had put an EOF on the socket, the SpdySession would
181 // have closed and we wouldn't be able to check the consistency.
183 // Forcefully close existing sessions here.
184 session()->spdy_session_pool()->CloseAllSessions();
187 void SetDeterministic() {
188 session_
= SpdySessionDependencies::SpdyCreateSessionDeterministic(
189 session_deps_
.get());
190 deterministic_
= true;
193 void SetSpdyDisabled() {
194 spdy_enabled_
= false;
195 port_
= test_params_
.ssl_type
== HTTP_SPDY_VIA_ALT_SVC
? 80 : 443;
198 void RunPreTestSetup() {
199 if (!session_deps_
.get())
200 session_deps_
.reset(CreateSpdySessionDependencies(test_params_
));
201 if (!session_
.get()) {
202 session_
= SpdySessionDependencies::SpdyCreateSession(
203 session_deps_
.get());
206 // We're now ready to use SSL-npn SPDY.
207 trans_
.reset(new HttpNetworkTransaction(priority_
, session_
.get()));
210 // Start the transaction, read some data, finish.
211 void RunDefaultTest() {
212 if (!StartDefaultTest())
217 bool StartDefaultTest() {
218 output_
.rv
= trans_
->Start(&request_
, callback_
.callback(), log_
);
220 // We expect an IO Pending or some sort of error.
221 EXPECT_LT(output_
.rv
, 0);
222 return output_
.rv
== ERR_IO_PENDING
;
225 void FinishDefaultTest() {
226 output_
.rv
= callback_
.WaitForResult();
227 if (output_
.rv
!= OK
) {
228 session_
->spdy_session_pool()->CloseCurrentSessions(ERR_ABORTED
);
233 const HttpResponseInfo
* response
= trans_
->GetResponseInfo();
234 ASSERT_TRUE(response
!= NULL
);
235 ASSERT_TRUE(response
->headers
.get() != NULL
);
236 EXPECT_EQ("HTTP/1.1 200 OK", response
->headers
->GetStatusLine());
237 EXPECT_EQ(spdy_enabled_
, response
->was_fetched_via_spdy
);
238 if (HttpStreamFactory::spdy_enabled()) {
240 HttpResponseInfo::ConnectionInfoFromNextProto(
241 test_params_
.protocol
),
242 response
->connection_info
);
244 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP1
,
245 response
->connection_info
);
248 EXPECT_TRUE(response
->was_npn_negotiated
);
250 // If SPDY is disabled, an HTTP request should not be diverted
251 // over an SSL session.
252 EXPECT_EQ(request_
.url
.SchemeIs("https"),
253 response
->was_npn_negotiated
);
255 EXPECT_EQ("127.0.0.1", response
->socket_address
.host());
256 EXPECT_EQ(port_
, response
->socket_address
.port());
257 output_
.status_line
= response
->headers
->GetStatusLine();
258 output_
.response_info
= *response
; // Make a copy so we can verify.
259 output_
.rv
= ReadTransaction(trans_
.get(), &output_
.response_data
);
262 void FinishDefaultTestWithoutVerification() {
263 output_
.rv
= callback_
.WaitForResult();
264 if (output_
.rv
!= OK
)
265 session_
->spdy_session_pool()->CloseCurrentSessions(ERR_ABORTED
);
268 // Most tests will want to call this function. In particular, the MockReads
269 // should end with an empty read, and that read needs to be processed to
270 // ensure proper deletion of the spdy_session_pool.
271 void VerifyDataConsumed() {
272 for (const SocketDataProvider
* provider
: data_vector_
) {
273 EXPECT_TRUE(provider
->AllReadDataConsumed());
274 EXPECT_TRUE(provider
->AllWriteDataConsumed());
276 for (const DeterministicSocketData
* provider
:
277 deterministic_data_vector_
) {
278 EXPECT_TRUE(provider
->AllReadDataConsumed());
279 EXPECT_TRUE(provider
->AllWriteDataConsumed());
283 // Occasionally a test will expect to error out before certain reads are
284 // processed. In that case we want to explicitly ensure that the reads were
286 void VerifyDataNotConsumed() {
287 for (const SocketDataProvider
* provider
: data_vector_
) {
288 EXPECT_FALSE(provider
->AllReadDataConsumed());
289 EXPECT_FALSE(provider
->AllWriteDataConsumed());
291 for (const DeterministicSocketData
* provider
:
292 deterministic_data_vector_
) {
293 EXPECT_FALSE(provider
->AllReadDataConsumed());
294 EXPECT_FALSE(provider
->AllWriteDataConsumed());
298 void RunToCompletion(SocketDataProvider
* data
) {
302 VerifyDataConsumed();
305 void RunToCompletionWithSSLData(
306 SocketDataProvider
* data
,
307 scoped_ptr
<SSLSocketDataProvider
> ssl_provider
) {
309 AddDataWithSSLSocketDataProvider(data
, ssl_provider
.Pass());
311 VerifyDataConsumed();
314 void AddData(SocketDataProvider
* data
) {
315 scoped_ptr
<SSLSocketDataProvider
> ssl_provider(
316 new SSLSocketDataProvider(ASYNC
, OK
));
318 ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem");
319 AddDataWithSSLSocketDataProvider(data
, ssl_provider
.Pass());
322 void AddDataWithSSLSocketDataProvider(
323 SocketDataProvider
* data
,
324 scoped_ptr
<SSLSocketDataProvider
> ssl_provider
) {
325 DCHECK(!deterministic_
);
326 data_vector_
.push_back(data
);
327 if (ssl_provider
->next_proto_status
==
328 SSLClientSocket::kNextProtoUnsupported
) {
329 ssl_provider
->SetNextProto(test_params_
.protocol
);
332 session_deps_
->socket_factory
->AddSSLSocketDataProvider(
334 ssl_vector_
.push_back(ssl_provider
.release());
336 session_deps_
->socket_factory
->AddSocketDataProvider(data
);
337 if (test_params_
.ssl_type
== HTTP_SPDY_VIA_ALT_SVC
) {
338 MockConnect
hanging_connect(SYNCHRONOUS
, ERR_IO_PENDING
);
339 StaticSocketDataProvider
* hanging_non_alt_svc_socket
=
340 new StaticSocketDataProvider(NULL
, 0, NULL
, 0);
341 hanging_non_alt_svc_socket
->set_connect_data(hanging_connect
);
342 session_deps_
->socket_factory
->AddSocketDataProvider(
343 hanging_non_alt_svc_socket
);
344 alternate_vector_
.push_back(hanging_non_alt_svc_socket
);
348 void AddDeterministicData(DeterministicSocketData
* data
) {
349 DCHECK(deterministic_
);
350 deterministic_data_vector_
.push_back(data
);
351 SSLSocketDataProvider
* ssl_provider
=
352 new SSLSocketDataProvider(ASYNC
, OK
);
353 ssl_provider
->SetNextProto(test_params_
.protocol
);
355 ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem");
356 ssl_vector_
.push_back(ssl_provider
);
357 session_deps_
->deterministic_socket_factory
->AddSSLSocketDataProvider(
360 session_deps_
->deterministic_socket_factory
->AddSocketDataProvider(data
);
361 if (test_params_
.ssl_type
== HTTP_SPDY_VIA_ALT_SVC
) {
362 MockConnect
hanging_connect(SYNCHRONOUS
, ERR_IO_PENDING
);
363 DeterministicSocketData
* hanging_non_alt_svc_socket
=
364 new DeterministicSocketData(NULL
, 0, NULL
, 0);
365 hanging_non_alt_svc_socket
->set_connect_data(hanging_connect
);
366 session_deps_
->deterministic_socket_factory
->AddSocketDataProvider(
367 hanging_non_alt_svc_socket
);
368 alternate_deterministic_vector_
.push_back(hanging_non_alt_svc_socket
);
372 void SetSession(const scoped_refptr
<HttpNetworkSession
>& session
) {
375 HttpNetworkTransaction
* trans() { return trans_
.get(); }
376 void ResetTrans() { trans_
.reset(); }
377 TransactionHelperResult
& output() { return output_
; }
378 const HttpRequestInfo
& request() const { return request_
; }
379 const scoped_refptr
<HttpNetworkSession
>& session() const {
382 scoped_ptr
<SpdySessionDependencies
>& session_deps() {
383 return session_deps_
;
385 int port() const { return port_
; }
386 SpdyNetworkTransactionTestParams
test_params() const {
391 typedef std::vector
<SocketDataProvider
*> DataVector
;
392 typedef std::vector
<DeterministicSocketData
*> DeterministicDataVector
;
393 typedef ScopedVector
<SSLSocketDataProvider
> SSLVector
;
394 typedef ScopedVector
<SocketDataProvider
> AlternateVector
;
395 typedef ScopedVector
<DeterministicSocketData
> AlternateDeterministicVector
;
396 HttpRequestInfo request_
;
397 RequestPriority priority_
;
398 scoped_ptr
<SpdySessionDependencies
> session_deps_
;
399 scoped_refptr
<HttpNetworkSession
> session_
;
400 TransactionHelperResult output_
;
401 scoped_ptr
<SocketDataProvider
> first_transaction_
;
402 SSLVector ssl_vector_
;
403 TestCompletionCallback callback_
;
404 scoped_ptr
<HttpNetworkTransaction
> trans_
;
405 scoped_ptr
<HttpNetworkTransaction
> trans_http_
;
406 DataVector data_vector_
;
407 DeterministicDataVector deterministic_data_vector_
;
408 AlternateVector alternate_vector_
;
409 AlternateDeterministicVector alternate_deterministic_vector_
;
410 const BoundNetLog log_
;
411 SpdyNetworkTransactionTestParams test_params_
;
417 void ConnectStatusHelperWithExpectedStatus(const MockRead
& status
,
418 int expected_status
);
420 void ConnectStatusHelper(const MockRead
& status
);
422 const HttpRequestInfo
& CreateGetPushRequest() {
423 get_push_request_
.method
= "GET";
424 get_push_request_
.url
= GURL(GetDefaultUrlWithPath("/foo.dat"));
425 get_push_request_
.load_flags
= 0;
426 return get_push_request_
;
429 const HttpRequestInfo
& CreateGetRequest() {
430 if (!get_request_initialized_
) {
431 get_request_
.method
= "GET";
432 get_request_
.url
= GURL(GetDefaultUrl());
433 get_request_
.load_flags
= 0;
434 get_request_initialized_
= true;
439 const HttpRequestInfo
& CreateGetRequestWithUserAgent() {
440 if (!get_request_initialized_
) {
441 get_request_
.method
= "GET";
442 get_request_
.url
= GURL(GetDefaultUrl());
443 get_request_
.load_flags
= 0;
444 get_request_
.extra_headers
.SetHeader("User-Agent", "Chrome");
445 get_request_initialized_
= true;
450 const HttpRequestInfo
& CreatePostRequest() {
451 if (!post_request_initialized_
) {
452 ScopedVector
<UploadElementReader
> element_readers
;
453 element_readers
.push_back(
454 new UploadBytesElementReader(kUploadData
, kUploadDataSize
));
455 upload_data_stream_
.reset(
456 new ElementsUploadDataStream(element_readers
.Pass(), 0));
458 post_request_
.method
= "POST";
459 post_request_
.url
= GURL(GetDefaultUrl());
460 post_request_
.upload_data_stream
= upload_data_stream_
.get();
461 post_request_initialized_
= true;
463 return post_request_
;
466 const HttpRequestInfo
& CreateFilePostRequest() {
467 if (!post_request_initialized_
) {
468 base::FilePath file_path
;
469 CHECK(base::CreateTemporaryFileInDir(temp_dir_
.path(), &file_path
));
470 CHECK_EQ(static_cast<int>(kUploadDataSize
),
471 base::WriteFile(file_path
, kUploadData
, kUploadDataSize
));
473 ScopedVector
<UploadElementReader
> element_readers
;
474 element_readers
.push_back(new UploadFileElementReader(
475 base::ThreadTaskRunnerHandle::Get().get(), file_path
, 0,
476 kUploadDataSize
, base::Time()));
477 upload_data_stream_
.reset(
478 new ElementsUploadDataStream(element_readers
.Pass(), 0));
480 post_request_
.method
= "POST";
481 post_request_
.url
= GURL(GetDefaultUrl());
482 post_request_
.upload_data_stream
= upload_data_stream_
.get();
483 post_request_initialized_
= true;
485 return post_request_
;
488 const HttpRequestInfo
& CreateUnreadableFilePostRequest() {
489 if (post_request_initialized_
)
490 return post_request_
;
492 base::FilePath file_path
;
493 CHECK(base::CreateTemporaryFileInDir(temp_dir_
.path(), &file_path
));
494 CHECK_EQ(static_cast<int>(kUploadDataSize
),
495 base::WriteFile(file_path
, kUploadData
, kUploadDataSize
));
496 CHECK(base::MakeFileUnreadable(file_path
));
498 ScopedVector
<UploadElementReader
> element_readers
;
499 element_readers
.push_back(new UploadFileElementReader(
500 base::ThreadTaskRunnerHandle::Get().get(), file_path
, 0,
501 kUploadDataSize
, base::Time()));
502 upload_data_stream_
.reset(
503 new ElementsUploadDataStream(element_readers
.Pass(), 0));
505 post_request_
.method
= "POST";
506 post_request_
.url
= GURL(GetDefaultUrl());
507 post_request_
.upload_data_stream
= upload_data_stream_
.get();
508 post_request_initialized_
= true;
509 return post_request_
;
512 const HttpRequestInfo
& CreateComplexPostRequest() {
513 if (!post_request_initialized_
) {
514 const int kFileRangeOffset
= 1;
515 const int kFileRangeLength
= 3;
516 CHECK_LT(kFileRangeOffset
+ kFileRangeLength
, kUploadDataSize
);
518 base::FilePath file_path
;
519 CHECK(base::CreateTemporaryFileInDir(temp_dir_
.path(), &file_path
));
520 CHECK_EQ(static_cast<int>(kUploadDataSize
),
521 base::WriteFile(file_path
, kUploadData
, kUploadDataSize
));
523 ScopedVector
<UploadElementReader
> element_readers
;
524 element_readers
.push_back(
525 new UploadBytesElementReader(kUploadData
, kFileRangeOffset
));
526 element_readers
.push_back(new UploadFileElementReader(
527 base::ThreadTaskRunnerHandle::Get().get(), file_path
,
528 kFileRangeOffset
, kFileRangeLength
, base::Time()));
529 element_readers
.push_back(new UploadBytesElementReader(
530 kUploadData
+ kFileRangeOffset
+ kFileRangeLength
,
531 kUploadDataSize
- (kFileRangeOffset
+ kFileRangeLength
)));
532 upload_data_stream_
.reset(
533 new ElementsUploadDataStream(element_readers
.Pass(), 0));
535 post_request_
.method
= "POST";
536 post_request_
.url
= GURL(GetDefaultUrl());
537 post_request_
.upload_data_stream
= upload_data_stream_
.get();
538 post_request_initialized_
= true;
540 return post_request_
;
543 const HttpRequestInfo
& CreateChunkedPostRequest() {
544 if (!chunked_post_request_initialized_
) {
545 upload_chunked_data_stream_
.reset(new ChunkedUploadDataStream(0));
546 chunked_post_request_
.method
= "POST";
547 chunked_post_request_
.url
= GURL(GetDefaultUrl());
548 chunked_post_request_
.upload_data_stream
=
549 upload_chunked_data_stream_
.get();
550 chunked_post_request_initialized_
= true;
552 return chunked_post_request_
;
555 // Read the result of a particular transaction, knowing that we've got
556 // multiple transactions in the read pipeline; so as we read, we may have
557 // to skip over data destined for other transactions while we consume
558 // the data for |trans|.
559 int ReadResult(HttpNetworkTransaction
* trans
,
560 std::string
* result
) {
561 const int kSize
= 3000;
564 scoped_refptr
<IOBufferWithSize
> buf(new IOBufferWithSize(kSize
));
565 TestCompletionCallback callback
;
567 int rv
= trans
->Read(buf
.get(), kSize
, callback
.callback());
568 if (rv
== ERR_IO_PENDING
) {
569 rv
= callback
.WaitForResult();
570 } else if (rv
<= 0) {
573 result
->append(buf
->data(), rv
);
579 void VerifyStreamsClosed(const NormalSpdyTransactionHelper
& helper
) {
580 // This lengthy block is reaching into the pool to dig out the active
581 // session. Once we have the session, we verify that the streams are
582 // all closed and not leaked at this point.
583 const GURL
& url
= helper
.request().url
;
584 HostPortPair
host_port_pair(url
.host(), 443);
585 SpdySessionKey
key(host_port_pair
, ProxyServer::Direct(),
586 PRIVACY_MODE_DISABLED
);
588 const scoped_refptr
<HttpNetworkSession
>& session
= helper
.session();
589 base::WeakPtr
<SpdySession
> spdy_session
=
590 session
->spdy_session_pool()->FindAvailableSession(key
, log
);
591 ASSERT_TRUE(spdy_session
!= NULL
);
592 EXPECT_EQ(0u, spdy_session
->num_active_streams());
593 EXPECT_EQ(0u, spdy_session
->num_unclaimed_pushed_streams());
596 void RunServerPushTest(SequencedSocketData
* data
,
597 HttpResponseInfo
* response
,
598 HttpResponseInfo
* push_response
,
599 const std::string
& expected
) {
600 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
601 BoundNetLog(), GetParam(), NULL
);
602 helper
.RunPreTestSetup();
603 helper
.AddData(data
);
605 HttpNetworkTransaction
* trans
= helper
.trans();
607 // Start the transaction with basic parameters.
608 TestCompletionCallback callback
;
609 int rv
= trans
->Start(
610 &CreateGetRequest(), callback
.callback(), BoundNetLog());
611 EXPECT_EQ(ERR_IO_PENDING
, rv
);
612 rv
= callback
.WaitForResult();
614 // Request the pushed path.
615 scoped_ptr
<HttpNetworkTransaction
> trans2(
616 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
618 &CreateGetPushRequest(), callback
.callback(), BoundNetLog());
619 EXPECT_EQ(ERR_IO_PENDING
, rv
);
620 base::RunLoop().RunUntilIdle();
622 // The data for the pushed path may be coming in more than 1 frame. Compile
623 // the results into a single string.
625 // Read the server push body.
627 ReadResult(trans2
.get(), &result2
);
628 // Read the response body.
630 ReadResult(trans
, &result
);
632 // Verify that we consumed all test data.
633 EXPECT_TRUE(data
->AllReadDataConsumed());
634 EXPECT_TRUE(data
->AllWriteDataConsumed());
636 // Verify that the received push data is same as the expected push data.
637 EXPECT_EQ(result2
.compare(expected
), 0) << "Received data: "
639 << "||||| Expected data: "
642 // Verify the SYN_REPLY.
643 // Copy the response info, because trans goes away.
644 *response
= *trans
->GetResponseInfo();
645 *push_response
= *trans2
->GetResponseInfo();
647 VerifyStreamsClosed(helper
);
650 static void DeleteSessionCallback(NormalSpdyTransactionHelper
* helper
,
652 helper
->ResetTrans();
655 static void StartTransactionCallback(
656 const scoped_refptr
<HttpNetworkSession
>& session
,
659 scoped_ptr
<HttpNetworkTransaction
> trans(
660 new HttpNetworkTransaction(DEFAULT_PRIORITY
, session
.get()));
661 TestCompletionCallback callback
;
662 HttpRequestInfo request
;
663 request
.method
= "GET";
665 request
.load_flags
= 0;
666 int rv
= trans
->Start(&request
, callback
.callback(), BoundNetLog());
667 EXPECT_EQ(ERR_IO_PENDING
, rv
);
668 callback
.WaitForResult();
671 ChunkedUploadDataStream
* upload_chunked_data_stream() const {
672 return upload_chunked_data_stream_
.get();
675 const char* GetDefaultUrl() {
676 switch (GetParam().ssl_type
) {
677 case HTTP_SPDY_VIA_ALT_SVC
:
678 return "http://www.example.org";
679 case HTTPS_SPDY_VIA_NPN
:
680 return "https://www.example.org";
687 std::string
GetDefaultUrlWithPath(const char* path
) {
688 return std::string(GetDefaultUrl()) + path
;
691 SpdyTestUtil spdy_util_
;
694 scoped_ptr
<ChunkedUploadDataStream
> upload_chunked_data_stream_
;
695 scoped_ptr
<UploadDataStream
> upload_data_stream_
;
696 bool get_request_initialized_
;
697 bool post_request_initialized_
;
698 bool chunked_post_request_initialized_
;
699 HttpRequestInfo get_request_
;
700 HttpRequestInfo post_request_
;
701 HttpRequestInfo chunked_post_request_
;
702 HttpRequestInfo get_push_request_
;
703 base::ScopedTempDir temp_dir_
;
706 //-----------------------------------------------------------------------------
707 // All tests are run with three different connection types: SPDY after NPN
708 // negotiation, SPDY without SSL, and SPDY with SSL.
710 // TODO(akalin): Use ::testing::Combine() when we are able to use
712 INSTANTIATE_TEST_CASE_P(
714 SpdyNetworkTransactionTest
,
716 SpdyNetworkTransactionTestParams(kProtoSPDY31
, HTTPS_SPDY_VIA_NPN
),
717 SpdyNetworkTransactionTestParams(kProtoSPDY31
, HTTP_SPDY_VIA_ALT_SVC
),
718 SpdyNetworkTransactionTestParams(kProtoHTTP2_14
, HTTPS_SPDY_VIA_NPN
),
719 SpdyNetworkTransactionTestParams(kProtoHTTP2_14
, HTTP_SPDY_VIA_ALT_SVC
),
720 SpdyNetworkTransactionTestParams(kProtoHTTP2
, HTTPS_SPDY_VIA_NPN
),
721 SpdyNetworkTransactionTestParams(kProtoHTTP2
, HTTP_SPDY_VIA_ALT_SVC
)));
723 // Verify HttpNetworkTransaction constructor.
724 TEST_P(SpdyNetworkTransactionTest
, Constructor
) {
725 scoped_ptr
<SpdySessionDependencies
> session_deps(
726 CreateSpdySessionDependencies(GetParam()));
727 scoped_refptr
<HttpNetworkSession
> session(
728 SpdySessionDependencies::SpdyCreateSession(session_deps
.get()));
729 scoped_ptr
<HttpTransaction
> trans(
730 new HttpNetworkTransaction(DEFAULT_PRIORITY
, session
.get()));
733 TEST_P(SpdyNetworkTransactionTest
, Get
) {
734 // Construct the request.
735 scoped_ptr
<SpdyFrame
> req(
736 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
737 MockWrite writes
[] = {CreateMockWrite(*req
, 0)};
739 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
740 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
742 CreateMockRead(*resp
, 1),
743 CreateMockRead(*body
, 2),
744 MockRead(ASYNC
, 0, 3) // EOF
747 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
748 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
749 BoundNetLog(), GetParam(), NULL
);
750 helper
.RunToCompletion(&data
);
751 TransactionHelperResult out
= helper
.output();
752 EXPECT_EQ(OK
, out
.rv
);
753 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
754 EXPECT_EQ("hello!", out
.response_data
);
757 TEST_P(SpdyNetworkTransactionTest
, GetAtEachPriority
) {
758 for (RequestPriority p
= MINIMUM_PRIORITY
; p
<= MAXIMUM_PRIORITY
;
759 p
= RequestPriority(p
+ 1)) {
760 // Construct the request.
761 scoped_ptr
<SpdyFrame
> req(
762 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, p
, true));
763 MockWrite writes
[] = {CreateMockWrite(*req
, 0)};
765 SpdyPriority spdy_prio
= 0;
766 EXPECT_TRUE(GetSpdyPriority(spdy_util_
.spdy_version(), *req
, &spdy_prio
));
767 // this repeats the RequestPriority-->SpdyPriority mapping from
768 // SpdyFramer::ConvertRequestPriorityToSpdyPriority to make
769 // sure it's being done right.
770 if (spdy_util_
.spdy_version() < SPDY3
) {
773 EXPECT_EQ(0, spdy_prio
);
776 EXPECT_EQ(1, spdy_prio
);
780 EXPECT_EQ(2, spdy_prio
);
783 EXPECT_EQ(3, spdy_prio
);
791 EXPECT_EQ(0, spdy_prio
);
794 EXPECT_EQ(1, spdy_prio
);
797 EXPECT_EQ(2, spdy_prio
);
800 EXPECT_EQ(3, spdy_prio
);
803 EXPECT_EQ(4, spdy_prio
);
810 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
811 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
813 CreateMockRead(*resp
, 1),
814 CreateMockRead(*body
, 2),
815 MockRead(ASYNC
, 0, 3) // EOF
818 SequencedSocketData
data(reads
, arraysize(reads
), writes
,
820 HttpRequestInfo http_req
= CreateGetRequest();
822 NormalSpdyTransactionHelper
helper(http_req
, p
, BoundNetLog(),
824 helper
.RunToCompletion(&data
);
825 TransactionHelperResult out
= helper
.output();
826 EXPECT_EQ(OK
, out
.rv
);
827 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
828 EXPECT_EQ("hello!", out
.response_data
);
832 // Start three gets simultaniously; making sure that multiplexed
833 // streams work properly.
835 // This can't use the TransactionHelper method, since it only
836 // handles a single transaction, and finishes them as soon
837 // as it launches them.
839 // TODO(gavinp): create a working generalized TransactionHelper that
840 // can allow multiple streams in flight.
842 TEST_P(SpdyNetworkTransactionTest
, ThreeGets
) {
843 scoped_ptr
<SpdyFrame
> req(
844 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
845 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
846 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, false));
847 scoped_ptr
<SpdyFrame
> fbody(spdy_util_
.ConstructSpdyBodyFrame(1, true));
849 scoped_ptr
<SpdyFrame
> req2(
850 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 3, LOWEST
, true));
851 scoped_ptr
<SpdyFrame
> resp2(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 3));
852 scoped_ptr
<SpdyFrame
> body2(spdy_util_
.ConstructSpdyBodyFrame(3, false));
853 scoped_ptr
<SpdyFrame
> fbody2(spdy_util_
.ConstructSpdyBodyFrame(3, true));
855 scoped_ptr
<SpdyFrame
> req3(
856 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 5, LOWEST
, true));
857 scoped_ptr
<SpdyFrame
> resp3(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 5));
858 scoped_ptr
<SpdyFrame
> body3(spdy_util_
.ConstructSpdyBodyFrame(5, false));
859 scoped_ptr
<SpdyFrame
> fbody3(spdy_util_
.ConstructSpdyBodyFrame(5, true));
861 MockWrite writes
[] = {
862 CreateMockWrite(*req
, 0),
863 CreateMockWrite(*req2
, 3),
864 CreateMockWrite(*req3
, 6),
867 CreateMockRead(*resp
, 1),
868 CreateMockRead(*body
, 2),
869 CreateMockRead(*resp2
, 4),
870 CreateMockRead(*body2
, 5),
871 CreateMockRead(*resp3
, 7),
872 CreateMockRead(*body3
, 8),
874 CreateMockRead(*fbody
, 9),
875 CreateMockRead(*fbody2
, 10),
876 CreateMockRead(*fbody3
, 11),
878 MockRead(ASYNC
, 0, 12), // EOF
880 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
881 SequencedSocketData
data_placeholder(NULL
, 0, NULL
, 0);
884 TransactionHelperResult out
;
885 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
886 BoundNetLog(), GetParam(), NULL
);
887 helper
.RunPreTestSetup();
888 helper
.AddData(&data
);
889 // We require placeholder data because three get requests are sent out at
890 // the same time which results in three sockets being connected. The first
891 // on will negotiate SPDY and will be used for all requests.
892 helper
.AddData(&data_placeholder
);
893 helper
.AddData(&data_placeholder
);
894 scoped_ptr
<HttpNetworkTransaction
> trans1(
895 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
896 scoped_ptr
<HttpNetworkTransaction
> trans2(
897 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
898 scoped_ptr
<HttpNetworkTransaction
> trans3(
899 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
901 TestCompletionCallback callback1
;
902 TestCompletionCallback callback2
;
903 TestCompletionCallback callback3
;
905 HttpRequestInfo httpreq1
= CreateGetRequest();
906 HttpRequestInfo httpreq2
= CreateGetRequest();
907 HttpRequestInfo httpreq3
= CreateGetRequest();
909 out
.rv
= trans1
->Start(&httpreq1
, callback1
.callback(), log
);
910 ASSERT_EQ(ERR_IO_PENDING
, out
.rv
);
911 out
.rv
= trans2
->Start(&httpreq2
, callback2
.callback(), log
);
912 ASSERT_EQ(ERR_IO_PENDING
, out
.rv
);
913 out
.rv
= trans3
->Start(&httpreq3
, callback3
.callback(), log
);
914 ASSERT_EQ(ERR_IO_PENDING
, out
.rv
);
916 out
.rv
= callback1
.WaitForResult();
917 ASSERT_EQ(OK
, out
.rv
);
918 out
.rv
= callback3
.WaitForResult();
919 ASSERT_EQ(OK
, out
.rv
);
921 const HttpResponseInfo
* response1
= trans1
->GetResponseInfo();
922 EXPECT_TRUE(response1
->headers
.get() != NULL
);
923 EXPECT_TRUE(response1
->was_fetched_via_spdy
);
924 out
.status_line
= response1
->headers
->GetStatusLine();
925 out
.response_info
= *response1
;
927 trans2
->GetResponseInfo();
929 out
.rv
= ReadTransaction(trans1
.get(), &out
.response_data
);
930 helper
.VerifyDataConsumed();
931 EXPECT_EQ(OK
, out
.rv
);
933 EXPECT_EQ(OK
, out
.rv
);
934 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
935 EXPECT_EQ("hello!hello!", out
.response_data
);
938 TEST_P(SpdyNetworkTransactionTest
, TwoGetsLateBinding
) {
939 scoped_ptr
<SpdyFrame
> req(
940 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
941 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
942 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, false));
943 scoped_ptr
<SpdyFrame
> fbody(spdy_util_
.ConstructSpdyBodyFrame(1, true));
945 scoped_ptr
<SpdyFrame
> req2(
946 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 3, LOWEST
, true));
947 scoped_ptr
<SpdyFrame
> resp2(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 3));
948 scoped_ptr
<SpdyFrame
> body2(spdy_util_
.ConstructSpdyBodyFrame(3, false));
949 scoped_ptr
<SpdyFrame
> fbody2(spdy_util_
.ConstructSpdyBodyFrame(3, true));
951 MockWrite writes
[] = {
952 CreateMockWrite(*req
, 0), CreateMockWrite(*req2
, 3),
955 CreateMockRead(*resp
, 1),
956 CreateMockRead(*body
, 2),
957 CreateMockRead(*resp2
, 4),
958 CreateMockRead(*body2
, 5),
959 CreateMockRead(*fbody
, 6),
960 CreateMockRead(*fbody2
, 7),
961 MockRead(ASYNC
, 0, 8), // EOF
963 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
965 MockConnect
never_finishing_connect(SYNCHRONOUS
, ERR_IO_PENDING
);
966 SequencedSocketData
data_placeholder(NULL
, 0, NULL
, 0);
967 data_placeholder
.set_connect_data(never_finishing_connect
);
970 TransactionHelperResult out
;
971 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
972 BoundNetLog(), GetParam(), NULL
);
973 helper
.RunPreTestSetup();
974 helper
.AddData(&data
);
975 // We require placeholder data because two requests are sent out at
976 // the same time which results in two sockets being connected. The first
977 // on will negotiate SPDY and will be used for all requests.
978 helper
.AddData(&data_placeholder
);
979 scoped_ptr
<HttpNetworkTransaction
> trans1(
980 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
981 scoped_ptr
<HttpNetworkTransaction
> trans2(
982 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
984 TestCompletionCallback callback1
;
985 TestCompletionCallback callback2
;
987 HttpRequestInfo httpreq1
= CreateGetRequest();
988 HttpRequestInfo httpreq2
= CreateGetRequest();
990 out
.rv
= trans1
->Start(&httpreq1
, callback1
.callback(), log
);
991 ASSERT_EQ(ERR_IO_PENDING
, out
.rv
);
992 out
.rv
= trans2
->Start(&httpreq2
, callback2
.callback(), log
);
993 ASSERT_EQ(ERR_IO_PENDING
, out
.rv
);
995 out
.rv
= callback1
.WaitForResult();
996 ASSERT_EQ(OK
, out
.rv
);
997 out
.rv
= callback2
.WaitForResult();
998 ASSERT_EQ(OK
, out
.rv
);
1000 const HttpResponseInfo
* response1
= trans1
->GetResponseInfo();
1001 EXPECT_TRUE(response1
->headers
.get() != NULL
);
1002 EXPECT_TRUE(response1
->was_fetched_via_spdy
);
1003 out
.status_line
= response1
->headers
->GetStatusLine();
1004 out
.response_info
= *response1
;
1005 out
.rv
= ReadTransaction(trans1
.get(), &out
.response_data
);
1006 EXPECT_EQ(OK
, out
.rv
);
1007 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1008 EXPECT_EQ("hello!hello!", out
.response_data
);
1010 const HttpResponseInfo
* response2
= trans2
->GetResponseInfo();
1011 EXPECT_TRUE(response2
->headers
.get() != NULL
);
1012 EXPECT_TRUE(response2
->was_fetched_via_spdy
);
1013 out
.status_line
= response2
->headers
->GetStatusLine();
1014 out
.response_info
= *response2
;
1015 out
.rv
= ReadTransaction(trans2
.get(), &out
.response_data
);
1016 EXPECT_EQ(OK
, out
.rv
);
1017 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1018 EXPECT_EQ("hello!hello!", out
.response_data
);
1020 helper
.VerifyDataConsumed();
1023 TEST_P(SpdyNetworkTransactionTest
, TwoGetsLateBindingFromPreconnect
) {
1024 scoped_ptr
<SpdyFrame
> req(
1025 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
1026 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
1027 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, false));
1028 scoped_ptr
<SpdyFrame
> fbody(spdy_util_
.ConstructSpdyBodyFrame(1, true));
1030 scoped_ptr
<SpdyFrame
> req2(
1031 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 3, LOWEST
, true));
1032 scoped_ptr
<SpdyFrame
> resp2(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 3));
1033 scoped_ptr
<SpdyFrame
> body2(spdy_util_
.ConstructSpdyBodyFrame(3, false));
1034 scoped_ptr
<SpdyFrame
> fbody2(spdy_util_
.ConstructSpdyBodyFrame(3, true));
1036 MockWrite writes
[] = {
1037 CreateMockWrite(*req
, 0), CreateMockWrite(*req2
, 3),
1039 MockRead reads
[] = {
1040 CreateMockRead(*resp
, 1),
1041 CreateMockRead(*body
, 2),
1042 CreateMockRead(*resp2
, 4),
1043 CreateMockRead(*body2
, 5),
1044 CreateMockRead(*fbody
, 6),
1045 CreateMockRead(*fbody2
, 7),
1046 MockRead(ASYNC
, 0, 8), // EOF
1048 SequencedSocketData
preconnect_data(reads
, arraysize(reads
), writes
,
1051 MockConnect
never_finishing_connect(ASYNC
, ERR_IO_PENDING
);
1053 SequencedSocketData
data_placeholder(NULL
, 0, NULL
, 0);
1054 data_placeholder
.set_connect_data(never_finishing_connect
);
1057 TransactionHelperResult out
;
1058 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
1059 BoundNetLog(), GetParam(), NULL
);
1060 helper
.RunPreTestSetup();
1061 helper
.AddData(&preconnect_data
);
1062 // We require placeholder data because 3 connections are attempted (first is
1063 // the preconnect, 2nd and 3rd are the never finished connections.
1064 helper
.AddData(&data_placeholder
);
1065 helper
.AddData(&data_placeholder
);
1067 scoped_ptr
<HttpNetworkTransaction
> trans1(
1068 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
1069 scoped_ptr
<HttpNetworkTransaction
> trans2(
1070 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
1072 TestCompletionCallback callback1
;
1073 TestCompletionCallback callback2
;
1075 HttpRequestInfo httpreq
= CreateGetRequest();
1077 // Preconnect the first.
1078 SSLConfig preconnect_ssl_config
;
1079 helper
.session()->ssl_config_service()->GetSSLConfig(&preconnect_ssl_config
);
1080 HttpStreamFactory
* http_stream_factory
=
1081 helper
.session()->http_stream_factory();
1082 helper
.session()->GetNextProtos(&preconnect_ssl_config
.next_protos
);
1084 http_stream_factory
->PreconnectStreams(1, httpreq
, preconnect_ssl_config
,
1085 preconnect_ssl_config
);
1087 out
.rv
= trans1
->Start(&httpreq
, callback1
.callback(), log
);
1088 ASSERT_EQ(ERR_IO_PENDING
, out
.rv
);
1089 out
.rv
= trans2
->Start(&httpreq
, callback2
.callback(), log
);
1090 ASSERT_EQ(ERR_IO_PENDING
, out
.rv
);
1092 out
.rv
= callback1
.WaitForResult();
1093 ASSERT_EQ(OK
, out
.rv
);
1094 out
.rv
= callback2
.WaitForResult();
1095 ASSERT_EQ(OK
, out
.rv
);
1097 const HttpResponseInfo
* response1
= trans1
->GetResponseInfo();
1098 EXPECT_TRUE(response1
->headers
.get() != NULL
);
1099 EXPECT_TRUE(response1
->was_fetched_via_spdy
);
1100 out
.status_line
= response1
->headers
->GetStatusLine();
1101 out
.response_info
= *response1
;
1102 out
.rv
= ReadTransaction(trans1
.get(), &out
.response_data
);
1103 EXPECT_EQ(OK
, out
.rv
);
1104 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1105 EXPECT_EQ("hello!hello!", out
.response_data
);
1107 const HttpResponseInfo
* response2
= trans2
->GetResponseInfo();
1108 EXPECT_TRUE(response2
->headers
.get() != NULL
);
1109 EXPECT_TRUE(response2
->was_fetched_via_spdy
);
1110 out
.status_line
= response2
->headers
->GetStatusLine();
1111 out
.response_info
= *response2
;
1112 out
.rv
= ReadTransaction(trans2
.get(), &out
.response_data
);
1113 EXPECT_EQ(OK
, out
.rv
);
1114 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1115 EXPECT_EQ("hello!hello!", out
.response_data
);
1117 helper
.VerifyDataConsumed();
1120 // Similar to ThreeGets above, however this test adds a SETTINGS
1121 // frame. The SETTINGS frame is read during the IO loop waiting on
1122 // the first transaction completion, and sets a maximum concurrent
1123 // stream limit of 1. This means that our IO loop exists after the
1124 // second transaction completes, so we can assert on read_index().
1125 TEST_P(SpdyNetworkTransactionTest
, ThreeGetsWithMaxConcurrent
) {
1126 // Construct the request.
1127 scoped_ptr
<SpdyFrame
> req(
1128 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
1129 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
1130 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, false));
1131 scoped_ptr
<SpdyFrame
> fbody(spdy_util_
.ConstructSpdyBodyFrame(1, true));
1133 scoped_ptr
<SpdyFrame
> req2(
1134 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 3, LOWEST
, true));
1135 scoped_ptr
<SpdyFrame
> resp2(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 3));
1136 scoped_ptr
<SpdyFrame
> body2(spdy_util_
.ConstructSpdyBodyFrame(3, false));
1137 scoped_ptr
<SpdyFrame
> fbody2(spdy_util_
.ConstructSpdyBodyFrame(3, true));
1139 scoped_ptr
<SpdyFrame
> req3(
1140 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 5, LOWEST
, true));
1141 scoped_ptr
<SpdyFrame
> resp3(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 5));
1142 scoped_ptr
<SpdyFrame
> body3(spdy_util_
.ConstructSpdyBodyFrame(5, false));
1143 scoped_ptr
<SpdyFrame
> fbody3(spdy_util_
.ConstructSpdyBodyFrame(5, true));
1145 SettingsMap settings
;
1146 const uint32 max_concurrent_streams
= 1;
1147 settings
[SETTINGS_MAX_CONCURRENT_STREAMS
] =
1148 SettingsFlagsAndValue(SETTINGS_FLAG_NONE
, max_concurrent_streams
);
1149 scoped_ptr
<SpdyFrame
> settings_frame(
1150 spdy_util_
.ConstructSpdySettings(settings
));
1151 scoped_ptr
<SpdyFrame
> settings_ack(spdy_util_
.ConstructSpdySettingsAck());
1153 MockWrite writes
[] = {
1154 CreateMockWrite(*req
, 0),
1155 CreateMockWrite(*settings_ack
, 5),
1156 CreateMockWrite(*req2
, 6),
1157 CreateMockWrite(*req3
, 10),
1160 MockRead reads
[] = {
1161 CreateMockRead(*settings_frame
, 1),
1162 CreateMockRead(*resp
, 2),
1163 CreateMockRead(*body
, 3),
1164 CreateMockRead(*fbody
, 4),
1165 CreateMockRead(*resp2
, 7),
1166 CreateMockRead(*body2
, 8),
1167 CreateMockRead(*fbody2
, 9),
1168 CreateMockRead(*resp3
, 11),
1169 CreateMockRead(*body3
, 12),
1170 CreateMockRead(*fbody3
, 13),
1172 MockRead(ASYNC
, 0, 14), // EOF
1175 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
1178 TransactionHelperResult out
;
1180 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
1181 BoundNetLog(), GetParam(), NULL
);
1182 helper
.RunPreTestSetup();
1183 helper
.AddData(&data
);
1184 scoped_ptr
<HttpNetworkTransaction
> trans1(
1185 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
1186 scoped_ptr
<HttpNetworkTransaction
> trans2(
1187 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
1188 scoped_ptr
<HttpNetworkTransaction
> trans3(
1189 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
1191 TestCompletionCallback callback1
;
1192 TestCompletionCallback callback2
;
1193 TestCompletionCallback callback3
;
1195 HttpRequestInfo httpreq1
= CreateGetRequest();
1196 HttpRequestInfo httpreq2
= CreateGetRequest();
1197 HttpRequestInfo httpreq3
= CreateGetRequest();
1199 out
.rv
= trans1
->Start(&httpreq1
, callback1
.callback(), log
);
1200 ASSERT_EQ(out
.rv
, ERR_IO_PENDING
);
1201 // Run transaction 1 through quickly to force a read of our SETTINGS
1203 out
.rv
= callback1
.WaitForResult();
1204 ASSERT_EQ(OK
, out
.rv
);
1206 out
.rv
= trans2
->Start(&httpreq2
, callback2
.callback(), log
);
1207 ASSERT_EQ(out
.rv
, ERR_IO_PENDING
);
1208 out
.rv
= trans3
->Start(&httpreq3
, callback3
.callback(), log
);
1209 ASSERT_EQ(out
.rv
, ERR_IO_PENDING
);
1210 out
.rv
= callback2
.WaitForResult();
1211 ASSERT_EQ(OK
, out
.rv
);
1213 out
.rv
= callback3
.WaitForResult();
1214 ASSERT_EQ(OK
, out
.rv
);
1216 const HttpResponseInfo
* response1
= trans1
->GetResponseInfo();
1217 ASSERT_TRUE(response1
!= NULL
);
1218 EXPECT_TRUE(response1
->headers
.get() != NULL
);
1219 EXPECT_TRUE(response1
->was_fetched_via_spdy
);
1220 out
.status_line
= response1
->headers
->GetStatusLine();
1221 out
.response_info
= *response1
;
1222 out
.rv
= ReadTransaction(trans1
.get(), &out
.response_data
);
1223 EXPECT_EQ(OK
, out
.rv
);
1224 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1225 EXPECT_EQ("hello!hello!", out
.response_data
);
1227 const HttpResponseInfo
* response2
= trans2
->GetResponseInfo();
1228 out
.status_line
= response2
->headers
->GetStatusLine();
1229 out
.response_info
= *response2
;
1230 out
.rv
= ReadTransaction(trans2
.get(), &out
.response_data
);
1231 EXPECT_EQ(OK
, out
.rv
);
1232 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1233 EXPECT_EQ("hello!hello!", out
.response_data
);
1235 const HttpResponseInfo
* response3
= trans3
->GetResponseInfo();
1236 out
.status_line
= response3
->headers
->GetStatusLine();
1237 out
.response_info
= *response3
;
1238 out
.rv
= ReadTransaction(trans3
.get(), &out
.response_data
);
1239 EXPECT_EQ(OK
, out
.rv
);
1240 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1241 EXPECT_EQ("hello!hello!", out
.response_data
);
1243 helper
.VerifyDataConsumed();
1245 EXPECT_EQ(OK
, out
.rv
);
1248 // Similar to ThreeGetsWithMaxConcurrent above, however this test adds
1249 // a fourth transaction. The third and fourth transactions have
1250 // different data ("hello!" vs "hello!hello!") and because of the
1251 // user specified priority, we expect to see them inverted in
1252 // the response from the server.
1253 TEST_P(SpdyNetworkTransactionTest
, FourGetsWithMaxConcurrentPriority
) {
1254 // Construct the request.
1255 scoped_ptr
<SpdyFrame
> req(
1256 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
1257 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
1258 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, false));
1259 scoped_ptr
<SpdyFrame
> fbody(spdy_util_
.ConstructSpdyBodyFrame(1, true));
1261 scoped_ptr
<SpdyFrame
> req2(
1262 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 3, LOWEST
, true));
1263 scoped_ptr
<SpdyFrame
> resp2(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 3));
1264 scoped_ptr
<SpdyFrame
> body2(spdy_util_
.ConstructSpdyBodyFrame(3, false));
1265 scoped_ptr
<SpdyFrame
> fbody2(spdy_util_
.ConstructSpdyBodyFrame(3, true));
1267 scoped_ptr
<SpdyFrame
> req4(
1268 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 5, HIGHEST
, true));
1269 scoped_ptr
<SpdyFrame
> resp4(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 5));
1270 scoped_ptr
<SpdyFrame
> fbody4(spdy_util_
.ConstructSpdyBodyFrame(5, true));
1272 scoped_ptr
<SpdyFrame
> req3(
1273 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 7, LOWEST
, true));
1274 scoped_ptr
<SpdyFrame
> resp3(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 7));
1275 scoped_ptr
<SpdyFrame
> body3(spdy_util_
.ConstructSpdyBodyFrame(7, false));
1276 scoped_ptr
<SpdyFrame
> fbody3(spdy_util_
.ConstructSpdyBodyFrame(7, true));
1278 SettingsMap settings
;
1279 const uint32 max_concurrent_streams
= 1;
1280 settings
[SETTINGS_MAX_CONCURRENT_STREAMS
] =
1281 SettingsFlagsAndValue(SETTINGS_FLAG_NONE
, max_concurrent_streams
);
1282 scoped_ptr
<SpdyFrame
> settings_frame(
1283 spdy_util_
.ConstructSpdySettings(settings
));
1284 scoped_ptr
<SpdyFrame
> settings_ack(spdy_util_
.ConstructSpdySettingsAck());
1285 MockWrite writes
[] = {
1286 CreateMockWrite(*req
, 0),
1287 CreateMockWrite(*settings_ack
, 5),
1288 // By making these synchronous, it guarantees that they are not *started*
1289 // before their sequence number, which in turn verifies that only a single
1290 // request is in-flight at a time.
1291 CreateMockWrite(*req2
, 6, SYNCHRONOUS
),
1292 CreateMockWrite(*req4
, 10, SYNCHRONOUS
),
1293 CreateMockWrite(*req3
, 13, SYNCHRONOUS
),
1295 MockRead reads
[] = {
1296 CreateMockRead(*settings_frame
, 1),
1297 CreateMockRead(*resp
, 2),
1298 CreateMockRead(*body
, 3),
1299 CreateMockRead(*fbody
, 4),
1300 CreateMockRead(*resp2
, 7),
1301 CreateMockRead(*body2
, 8),
1302 CreateMockRead(*fbody2
, 9),
1303 CreateMockRead(*resp4
, 11),
1304 CreateMockRead(*fbody4
, 12),
1305 CreateMockRead(*resp3
, 14),
1306 CreateMockRead(*body3
, 15),
1307 CreateMockRead(*fbody3
, 16),
1309 MockRead(ASYNC
, 0, 17), // EOF
1311 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
1313 TransactionHelperResult out
;
1314 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
1315 BoundNetLog(), GetParam(), NULL
);
1316 helper
.RunPreTestSetup();
1317 helper
.AddData(&data
);
1319 scoped_ptr
<HttpNetworkTransaction
> trans1(
1320 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
1321 scoped_ptr
<HttpNetworkTransaction
> trans2(
1322 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
1323 scoped_ptr
<HttpNetworkTransaction
> trans3(
1324 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
1325 scoped_ptr
<HttpNetworkTransaction
> trans4(
1326 new HttpNetworkTransaction(HIGHEST
, helper
.session().get()));
1328 TestCompletionCallback callback1
;
1329 TestCompletionCallback callback2
;
1330 TestCompletionCallback callback3
;
1331 TestCompletionCallback callback4
;
1333 HttpRequestInfo httpreq1
= CreateGetRequest();
1334 HttpRequestInfo httpreq2
= CreateGetRequest();
1335 HttpRequestInfo httpreq3
= CreateGetRequest();
1336 HttpRequestInfo httpreq4
= CreateGetRequest();
1338 out
.rv
= trans1
->Start(&httpreq1
, callback1
.callback(), log
);
1339 ASSERT_EQ(ERR_IO_PENDING
, out
.rv
);
1340 // Run transaction 1 through quickly to force a read of our SETTINGS frame.
1341 out
.rv
= callback1
.WaitForResult();
1342 ASSERT_EQ(OK
, out
.rv
);
1344 out
.rv
= trans2
->Start(&httpreq2
, callback2
.callback(), log
);
1345 ASSERT_EQ(ERR_IO_PENDING
, out
.rv
);
1346 out
.rv
= trans3
->Start(&httpreq3
, callback3
.callback(), log
);
1347 ASSERT_EQ(ERR_IO_PENDING
, out
.rv
);
1348 out
.rv
= trans4
->Start(&httpreq4
, callback4
.callback(), log
);
1349 ASSERT_EQ(ERR_IO_PENDING
, out
.rv
);
1351 out
.rv
= callback2
.WaitForResult();
1352 ASSERT_EQ(OK
, out
.rv
);
1354 out
.rv
= callback3
.WaitForResult();
1355 ASSERT_EQ(OK
, out
.rv
);
1357 const HttpResponseInfo
* response1
= trans1
->GetResponseInfo();
1358 EXPECT_TRUE(response1
->headers
.get() != NULL
);
1359 EXPECT_TRUE(response1
->was_fetched_via_spdy
);
1360 out
.status_line
= response1
->headers
->GetStatusLine();
1361 out
.response_info
= *response1
;
1362 out
.rv
= ReadTransaction(trans1
.get(), &out
.response_data
);
1363 EXPECT_EQ(OK
, out
.rv
);
1364 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1365 EXPECT_EQ("hello!hello!", out
.response_data
);
1367 const HttpResponseInfo
* response2
= trans2
->GetResponseInfo();
1368 out
.status_line
= response2
->headers
->GetStatusLine();
1369 out
.response_info
= *response2
;
1370 out
.rv
= ReadTransaction(trans2
.get(), &out
.response_data
);
1371 EXPECT_EQ(OK
, out
.rv
);
1372 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1373 EXPECT_EQ("hello!hello!", out
.response_data
);
1375 // notice: response3 gets two hellos, response4 gets one
1376 // hello, so we know dequeuing priority was respected.
1377 const HttpResponseInfo
* response3
= trans3
->GetResponseInfo();
1378 out
.status_line
= response3
->headers
->GetStatusLine();
1379 out
.response_info
= *response3
;
1380 out
.rv
= ReadTransaction(trans3
.get(), &out
.response_data
);
1381 EXPECT_EQ(OK
, out
.rv
);
1382 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1383 EXPECT_EQ("hello!hello!", out
.response_data
);
1385 out
.rv
= callback4
.WaitForResult();
1386 EXPECT_EQ(OK
, out
.rv
);
1387 const HttpResponseInfo
* response4
= trans4
->GetResponseInfo();
1388 out
.status_line
= response4
->headers
->GetStatusLine();
1389 out
.response_info
= *response4
;
1390 out
.rv
= ReadTransaction(trans4
.get(), &out
.response_data
);
1391 EXPECT_EQ(OK
, out
.rv
);
1392 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1393 EXPECT_EQ("hello!", out
.response_data
);
1394 helper
.VerifyDataConsumed();
1395 EXPECT_EQ(OK
, out
.rv
);
1398 // Similar to ThreeGetsMaxConcurrrent above, however, this test
1399 // deletes a session in the middle of the transaction to ensure
1400 // that we properly remove pendingcreatestream objects from
1402 TEST_P(SpdyNetworkTransactionTest
, ThreeGetsWithMaxConcurrentDelete
) {
1403 // Construct the request.
1404 scoped_ptr
<SpdyFrame
> req(
1405 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
1406 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
1407 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, false));
1408 scoped_ptr
<SpdyFrame
> fbody(spdy_util_
.ConstructSpdyBodyFrame(1, true));
1410 scoped_ptr
<SpdyFrame
> req2(
1411 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 3, LOWEST
, true));
1412 scoped_ptr
<SpdyFrame
> resp2(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 3));
1413 scoped_ptr
<SpdyFrame
> body2(spdy_util_
.ConstructSpdyBodyFrame(3, false));
1414 scoped_ptr
<SpdyFrame
> fbody2(spdy_util_
.ConstructSpdyBodyFrame(3, true));
1416 SettingsMap settings
;
1417 const uint32 max_concurrent_streams
= 1;
1418 settings
[SETTINGS_MAX_CONCURRENT_STREAMS
] =
1419 SettingsFlagsAndValue(SETTINGS_FLAG_NONE
, max_concurrent_streams
);
1420 scoped_ptr
<SpdyFrame
> settings_frame(
1421 spdy_util_
.ConstructSpdySettings(settings
));
1422 scoped_ptr
<SpdyFrame
> settings_ack(spdy_util_
.ConstructSpdySettingsAck());
1424 MockWrite writes
[] = {
1425 CreateMockWrite(*req
, 0),
1426 CreateMockWrite(*settings_ack
, 5),
1427 CreateMockWrite(*req2
, 6),
1429 MockRead reads
[] = {
1430 CreateMockRead(*settings_frame
, 1),
1431 CreateMockRead(*resp
, 2),
1432 CreateMockRead(*body
, 3),
1433 CreateMockRead(*fbody
, 4),
1434 CreateMockRead(*resp2
, 7),
1435 CreateMockRead(*body2
, 8),
1436 CreateMockRead(*fbody2
, 9),
1437 MockRead(ASYNC
, 0, 10), // EOF
1440 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
1443 TransactionHelperResult out
;
1444 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
1445 BoundNetLog(), GetParam(), NULL
);
1446 helper
.RunPreTestSetup();
1447 helper
.AddData(&data
);
1448 scoped_ptr
<HttpNetworkTransaction
> trans1(
1449 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
1450 scoped_ptr
<HttpNetworkTransaction
> trans2(
1451 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
1452 scoped_ptr
<HttpNetworkTransaction
> trans3(
1453 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
1455 TestCompletionCallback callback1
;
1456 TestCompletionCallback callback2
;
1457 TestCompletionCallback callback3
;
1459 HttpRequestInfo httpreq1
= CreateGetRequest();
1460 HttpRequestInfo httpreq2
= CreateGetRequest();
1461 HttpRequestInfo httpreq3
= CreateGetRequest();
1463 out
.rv
= trans1
->Start(&httpreq1
, callback1
.callback(), log
);
1464 ASSERT_EQ(out
.rv
, ERR_IO_PENDING
);
1465 // Run transaction 1 through quickly to force a read of our SETTINGS frame.
1466 out
.rv
= callback1
.WaitForResult();
1467 ASSERT_EQ(OK
, out
.rv
);
1469 out
.rv
= trans2
->Start(&httpreq2
, callback2
.callback(), log
);
1470 ASSERT_EQ(out
.rv
, ERR_IO_PENDING
);
1471 out
.rv
= trans3
->Start(&httpreq3
, callback3
.callback(), log
);
1472 delete trans3
.release();
1473 ASSERT_EQ(out
.rv
, ERR_IO_PENDING
);
1474 out
.rv
= callback2
.WaitForResult();
1475 ASSERT_EQ(OK
, out
.rv
);
1477 const HttpResponseInfo
* response1
= trans1
->GetResponseInfo();
1478 ASSERT_TRUE(response1
!= NULL
);
1479 EXPECT_TRUE(response1
->headers
.get() != NULL
);
1480 EXPECT_TRUE(response1
->was_fetched_via_spdy
);
1481 out
.status_line
= response1
->headers
->GetStatusLine();
1482 out
.response_info
= *response1
;
1483 out
.rv
= ReadTransaction(trans1
.get(), &out
.response_data
);
1484 EXPECT_EQ(OK
, out
.rv
);
1485 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1486 EXPECT_EQ("hello!hello!", out
.response_data
);
1488 const HttpResponseInfo
* response2
= trans2
->GetResponseInfo();
1489 ASSERT_TRUE(response2
!= NULL
);
1490 out
.status_line
= response2
->headers
->GetStatusLine();
1491 out
.response_info
= *response2
;
1492 out
.rv
= ReadTransaction(trans2
.get(), &out
.response_data
);
1493 EXPECT_EQ(OK
, out
.rv
);
1494 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1495 EXPECT_EQ("hello!hello!", out
.response_data
);
1496 helper
.VerifyDataConsumed();
1497 EXPECT_EQ(OK
, out
.rv
);
1502 // The KillerCallback will delete the transaction on error as part of the
1504 class KillerCallback
: public TestCompletionCallbackBase
{
1506 explicit KillerCallback(HttpNetworkTransaction
* transaction
)
1507 : transaction_(transaction
),
1508 callback_(base::Bind(&KillerCallback::OnComplete
,
1509 base::Unretained(this))) {
1512 ~KillerCallback() override
{}
1514 const CompletionCallback
& callback() const { return callback_
; }
1517 void OnComplete(int result
) {
1519 delete transaction_
;
1524 HttpNetworkTransaction
* transaction_
;
1525 CompletionCallback callback_
;
1530 // Similar to ThreeGetsMaxConcurrrentDelete above, however, this test
1531 // closes the socket while we have a pending transaction waiting for
1532 // a pending stream creation. http://crbug.com/52901
1533 TEST_P(SpdyNetworkTransactionTest
, ThreeGetsWithMaxConcurrentSocketClose
) {
1534 // Construct the request.
1535 scoped_ptr
<SpdyFrame
> req(
1536 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
1537 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
1538 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, false));
1539 scoped_ptr
<SpdyFrame
> fin_body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
1541 scoped_ptr
<SpdyFrame
> req2(
1542 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 3, LOWEST
, true));
1543 scoped_ptr
<SpdyFrame
> resp2(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 3));
1545 SettingsMap settings
;
1546 const uint32 max_concurrent_streams
= 1;
1547 settings
[SETTINGS_MAX_CONCURRENT_STREAMS
] =
1548 SettingsFlagsAndValue(SETTINGS_FLAG_NONE
, max_concurrent_streams
);
1549 scoped_ptr
<SpdyFrame
> settings_frame(
1550 spdy_util_
.ConstructSpdySettings(settings
));
1551 scoped_ptr
<SpdyFrame
> settings_ack(spdy_util_
.ConstructSpdySettingsAck());
1553 MockWrite writes
[] = {
1554 CreateMockWrite(*req
, 0),
1555 CreateMockWrite(*settings_ack
, 5),
1556 CreateMockWrite(*req2
, 6),
1558 MockRead reads
[] = {
1559 CreateMockRead(*settings_frame
, 1),
1560 CreateMockRead(*resp
, 2),
1561 CreateMockRead(*body
, 3),
1562 CreateMockRead(*fin_body
, 4),
1563 CreateMockRead(*resp2
, 7),
1564 MockRead(ASYNC
, ERR_CONNECTION_RESET
, 8), // Abort!
1567 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
1568 SequencedSocketData
data_placeholder(NULL
, 0, NULL
, 0);
1571 TransactionHelperResult out
;
1572 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
1573 BoundNetLog(), GetParam(), NULL
);
1574 helper
.RunPreTestSetup();
1575 helper
.AddData(&data
);
1576 // We require placeholder data because three get requests are sent out, so
1577 // there needs to be three sets of SSL connection data.
1578 helper
.AddData(&data_placeholder
);
1579 helper
.AddData(&data_placeholder
);
1580 HttpNetworkTransaction
trans1(DEFAULT_PRIORITY
, helper
.session().get());
1581 HttpNetworkTransaction
trans2(DEFAULT_PRIORITY
, helper
.session().get());
1582 HttpNetworkTransaction
* trans3(
1583 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
1585 TestCompletionCallback callback1
;
1586 TestCompletionCallback callback2
;
1587 KillerCallback
callback3(trans3
);
1589 HttpRequestInfo httpreq1
= CreateGetRequest();
1590 HttpRequestInfo httpreq2
= CreateGetRequest();
1591 HttpRequestInfo httpreq3
= CreateGetRequest();
1593 out
.rv
= trans1
.Start(&httpreq1
, callback1
.callback(), log
);
1594 ASSERT_EQ(out
.rv
, ERR_IO_PENDING
);
1595 // Run transaction 1 through quickly to force a read of our SETTINGS frame.
1596 out
.rv
= callback1
.WaitForResult();
1597 ASSERT_EQ(OK
, out
.rv
);
1599 out
.rv
= trans2
.Start(&httpreq2
, callback2
.callback(), log
);
1600 ASSERT_EQ(out
.rv
, ERR_IO_PENDING
);
1601 out
.rv
= trans3
->Start(&httpreq3
, callback3
.callback(), log
);
1602 ASSERT_EQ(out
.rv
, ERR_IO_PENDING
);
1603 out
.rv
= callback3
.WaitForResult();
1604 ASSERT_EQ(ERR_ABORTED
, out
.rv
);
1606 const HttpResponseInfo
* response1
= trans1
.GetResponseInfo();
1607 ASSERT_TRUE(response1
!= NULL
);
1608 EXPECT_TRUE(response1
->headers
.get() != NULL
);
1609 EXPECT_TRUE(response1
->was_fetched_via_spdy
);
1610 out
.status_line
= response1
->headers
->GetStatusLine();
1611 out
.response_info
= *response1
;
1612 out
.rv
= ReadTransaction(&trans1
, &out
.response_data
);
1613 EXPECT_EQ(OK
, out
.rv
);
1615 const HttpResponseInfo
* response2
= trans2
.GetResponseInfo();
1616 ASSERT_TRUE(response2
!= NULL
);
1617 out
.status_line
= response2
->headers
->GetStatusLine();
1618 out
.response_info
= *response2
;
1619 out
.rv
= ReadTransaction(&trans2
, &out
.response_data
);
1620 EXPECT_EQ(ERR_CONNECTION_RESET
, out
.rv
);
1622 helper
.VerifyDataConsumed();
1625 // Test that a simple PUT request works.
1626 TEST_P(SpdyNetworkTransactionTest
, Put
) {
1627 // Setup the request
1628 HttpRequestInfo request
;
1629 request
.method
= "PUT";
1630 request
.url
= GURL(GetDefaultUrl());
1632 scoped_ptr
<SpdyHeaderBlock
> put_headers(
1633 spdy_util_
.ConstructPutHeaderBlock(GetDefaultUrl(), 0));
1634 scoped_ptr
<SpdyFrame
> req(
1635 spdy_util_
.ConstructSpdySyn(1, *put_headers
, LOWEST
, false, true));
1636 MockWrite writes
[] = {
1637 CreateMockWrite(*req
, 0),
1640 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
1641 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
1642 MockRead reads
[] = {
1643 CreateMockRead(*resp
, 1),
1644 CreateMockRead(*body
, 2),
1645 MockRead(ASYNC
, 0, 3) // EOF
1648 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
1649 NormalSpdyTransactionHelper
helper(request
, DEFAULT_PRIORITY
,
1650 BoundNetLog(), GetParam(), NULL
);
1651 helper
.RunToCompletion(&data
);
1652 TransactionHelperResult out
= helper
.output();
1654 EXPECT_EQ(OK
, out
.rv
);
1655 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1658 // Test that a simple HEAD request works.
1659 TEST_P(SpdyNetworkTransactionTest
, Head
) {
1660 // Setup the request
1661 HttpRequestInfo request
;
1662 request
.method
= "HEAD";
1663 request
.url
= GURL(GetDefaultUrl());
1665 scoped_ptr
<SpdyHeaderBlock
> head_headers(
1666 spdy_util_
.ConstructHeadHeaderBlock(GetDefaultUrl(), 0));
1667 scoped_ptr
<SpdyFrame
> req(
1668 spdy_util_
.ConstructSpdySyn(1, *head_headers
, LOWEST
, false, true));
1669 MockWrite writes
[] = {
1670 CreateMockWrite(*req
, 0),
1673 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
1674 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
1675 MockRead reads
[] = {
1676 CreateMockRead(*resp
, 1),
1677 CreateMockRead(*body
, 2),
1678 MockRead(ASYNC
, 0, 3) // EOF
1681 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
1682 NormalSpdyTransactionHelper
helper(request
, DEFAULT_PRIORITY
,
1683 BoundNetLog(), GetParam(), NULL
);
1684 helper
.RunToCompletion(&data
);
1685 TransactionHelperResult out
= helper
.output();
1687 EXPECT_EQ(OK
, out
.rv
);
1688 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1691 // Test that a simple POST works.
1692 TEST_P(SpdyNetworkTransactionTest
, Post
) {
1693 scoped_ptr
<SpdyFrame
> req(spdy_util_
.ConstructSpdyPost(
1694 GetDefaultUrl(), 1, kUploadDataSize
, LOWEST
, NULL
, 0));
1695 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
1696 MockWrite writes
[] = {
1697 CreateMockWrite(*req
, 0), CreateMockWrite(*body
, 1), // POST upload frame
1700 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyPostSynReply(NULL
, 0));
1701 MockRead reads
[] = {
1702 CreateMockRead(*resp
, 2),
1703 CreateMockRead(*body
, 3),
1704 MockRead(ASYNC
, 0, 4) // EOF
1707 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
1708 NormalSpdyTransactionHelper
helper(CreatePostRequest(), DEFAULT_PRIORITY
,
1709 BoundNetLog(), GetParam(), NULL
);
1710 helper
.RunToCompletion(&data
);
1711 TransactionHelperResult out
= helper
.output();
1712 EXPECT_EQ(OK
, out
.rv
);
1713 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1714 EXPECT_EQ("hello!", out
.response_data
);
1717 // Test that a POST with a file works.
1718 TEST_P(SpdyNetworkTransactionTest
, FilePost
) {
1719 scoped_ptr
<SpdyFrame
> req(spdy_util_
.ConstructSpdyPost(
1720 GetDefaultUrl(), 1, kUploadDataSize
, LOWEST
, NULL
, 0));
1721 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
1722 MockWrite writes
[] = {
1723 CreateMockWrite(*req
, 0), CreateMockWrite(*body
, 1), // POST upload frame
1726 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyPostSynReply(NULL
, 0));
1727 MockRead reads
[] = {
1728 CreateMockRead(*resp
, 2),
1729 CreateMockRead(*body
, 3),
1730 MockRead(ASYNC
, 0, 4) // EOF
1733 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
1734 NormalSpdyTransactionHelper
helper(CreateFilePostRequest(), DEFAULT_PRIORITY
,
1735 BoundNetLog(), GetParam(), NULL
);
1736 helper
.RunToCompletion(&data
);
1737 TransactionHelperResult out
= helper
.output();
1738 EXPECT_EQ(OK
, out
.rv
);
1739 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1740 EXPECT_EQ("hello!", out
.response_data
);
1743 // Test that a POST with a unreadable file fails.
1744 TEST_P(SpdyNetworkTransactionTest
, UnreadableFilePost
) {
1745 MockWrite writes
[] = {
1746 MockWrite(ASYNC
, 0, 0) // EOF
1748 MockRead reads
[] = {
1749 MockRead(ASYNC
, 0, 1) // EOF
1752 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
1753 NormalSpdyTransactionHelper
helper(CreateUnreadableFilePostRequest(),
1755 BoundNetLog(), GetParam(), NULL
);
1756 helper
.RunPreTestSetup();
1757 helper
.AddData(&data
);
1758 helper
.RunDefaultTest();
1760 base::RunLoop().RunUntilIdle();
1761 helper
.VerifyDataNotConsumed();
1762 EXPECT_EQ(ERR_ACCESS_DENIED
, helper
.output().rv
);
1765 // Test that a complex POST works.
1766 TEST_P(SpdyNetworkTransactionTest
, ComplexPost
) {
1767 scoped_ptr
<SpdyFrame
> req(spdy_util_
.ConstructSpdyPost(
1768 GetDefaultUrl(), 1, kUploadDataSize
, LOWEST
, NULL
, 0));
1769 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
1770 MockWrite writes
[] = {
1771 CreateMockWrite(*req
, 0), CreateMockWrite(*body
, 1), // POST upload frame
1774 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyPostSynReply(NULL
, 0));
1775 MockRead reads
[] = {
1776 CreateMockRead(*resp
, 2),
1777 CreateMockRead(*body
, 3),
1778 MockRead(ASYNC
, 0, 4) // EOF
1781 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
1782 NormalSpdyTransactionHelper
helper(CreateComplexPostRequest(),
1784 BoundNetLog(), GetParam(), NULL
);
1785 helper
.RunToCompletion(&data
);
1786 TransactionHelperResult out
= helper
.output();
1787 EXPECT_EQ(OK
, out
.rv
);
1788 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1789 EXPECT_EQ("hello!", out
.response_data
);
1792 // Test that a chunked POST works.
1793 TEST_P(SpdyNetworkTransactionTest
, ChunkedPost
) {
1794 scoped_ptr
<SpdyFrame
> req(spdy_util_
.ConstructChunkedSpdyPost(NULL
, 0));
1795 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
1796 MockWrite writes
[] = {
1797 CreateMockWrite(*req
, 0), CreateMockWrite(*body
, 1),
1800 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyPostSynReply(NULL
, 0));
1801 MockRead reads
[] = {
1802 CreateMockRead(*resp
, 2),
1803 CreateMockRead(*body
, 3),
1804 MockRead(ASYNC
, 0, 4) // EOF
1807 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
1808 NormalSpdyTransactionHelper
helper(CreateChunkedPostRequest(),
1810 BoundNetLog(), GetParam(), NULL
);
1812 // These chunks get merged into a single frame when being sent.
1813 const int kFirstChunkSize
= kUploadDataSize
/2;
1814 upload_chunked_data_stream()->AppendData(kUploadData
, kFirstChunkSize
, false);
1815 upload_chunked_data_stream()->AppendData(
1816 kUploadData
+ kFirstChunkSize
, kUploadDataSize
- kFirstChunkSize
, true);
1818 helper
.RunToCompletion(&data
);
1819 TransactionHelperResult out
= helper
.output();
1820 EXPECT_EQ(OK
, out
.rv
);
1821 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1822 EXPECT_EQ(kUploadData
, out
.response_data
);
1825 // Test that a chunked POST works with chunks appended after transaction starts.
1826 TEST_P(SpdyNetworkTransactionTest
, DelayedChunkedPost
) {
1827 scoped_ptr
<SpdyFrame
> req(spdy_util_
.ConstructChunkedSpdyPost(NULL
, 0));
1828 scoped_ptr
<SpdyFrame
> chunk1(spdy_util_
.ConstructSpdyBodyFrame(1, false));
1829 scoped_ptr
<SpdyFrame
> chunk2(spdy_util_
.ConstructSpdyBodyFrame(1, false));
1830 scoped_ptr
<SpdyFrame
> chunk3(spdy_util_
.ConstructSpdyBodyFrame(1, true));
1831 MockWrite writes
[] = {
1832 CreateMockWrite(*req
, 0),
1833 CreateMockWrite(*chunk1
, 1),
1834 CreateMockWrite(*chunk2
, 2),
1835 CreateMockWrite(*chunk3
, 3),
1838 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyPostSynReply(NULL
, 0));
1839 MockRead reads
[] = {
1840 CreateMockRead(*resp
, 4),
1841 CreateMockRead(*chunk1
, 5),
1842 CreateMockRead(*chunk2
, 6),
1843 CreateMockRead(*chunk3
, 7),
1844 MockRead(ASYNC
, 0, 8) // EOF
1847 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
1848 NormalSpdyTransactionHelper
helper(CreateChunkedPostRequest(),
1850 BoundNetLog(), GetParam(), NULL
);
1852 upload_chunked_data_stream()->AppendData(kUploadData
, kUploadDataSize
, false);
1854 helper
.RunPreTestSetup();
1855 helper
.AddData(&data
);
1856 ASSERT_TRUE(helper
.StartDefaultTest());
1858 base::RunLoop().RunUntilIdle();
1859 upload_chunked_data_stream()->AppendData(kUploadData
, kUploadDataSize
, false);
1860 base::RunLoop().RunUntilIdle();
1861 upload_chunked_data_stream()->AppendData(kUploadData
, kUploadDataSize
, true);
1863 helper
.FinishDefaultTest();
1864 helper
.VerifyDataConsumed();
1866 std::string expected_response
;
1867 expected_response
+= kUploadData
;
1868 expected_response
+= kUploadData
;
1869 expected_response
+= kUploadData
;
1871 TransactionHelperResult out
= helper
.output();
1872 EXPECT_EQ(OK
, out
.rv
);
1873 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1874 EXPECT_EQ(expected_response
, out
.response_data
);
1877 // Test that a POST without any post data works.
1878 TEST_P(SpdyNetworkTransactionTest
, NullPost
) {
1879 BufferedSpdyFramer
framer(spdy_util_
.spdy_version(), false);
1880 // Setup the request
1881 HttpRequestInfo request
;
1882 request
.method
= "POST";
1883 request
.url
= GURL(GetDefaultUrl());
1884 // Create an empty UploadData.
1885 request
.upload_data_stream
= NULL
;
1887 // When request.upload_data_stream is NULL for post, content-length is
1888 // expected to be 0.
1889 scoped_ptr
<SpdyHeaderBlock
> req_block(
1890 spdy_util_
.ConstructPostHeaderBlock(GetDefaultUrl(), 0));
1891 scoped_ptr
<SpdyFrame
> req(
1892 spdy_util_
.ConstructSpdySyn(1, *req_block
, LOWEST
, false, true));
1894 MockWrite writes
[] = {
1895 CreateMockWrite(*req
, 0),
1898 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyPostSynReply(NULL
, 0));
1899 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
1900 MockRead reads
[] = {
1901 CreateMockRead(*resp
, 1),
1902 CreateMockRead(*body
, 2),
1903 MockRead(ASYNC
, 0, 3) // EOF
1906 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
1908 NormalSpdyTransactionHelper
helper(request
, DEFAULT_PRIORITY
,
1909 BoundNetLog(), GetParam(), NULL
);
1910 helper
.RunToCompletion(&data
);
1911 TransactionHelperResult out
= helper
.output();
1912 EXPECT_EQ(OK
, out
.rv
);
1913 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1914 EXPECT_EQ("hello!", out
.response_data
);
1917 // Test that a simple POST works.
1918 TEST_P(SpdyNetworkTransactionTest
, EmptyPost
) {
1919 BufferedSpdyFramer
framer(spdy_util_
.spdy_version(), false);
1920 // Create an empty UploadDataStream.
1921 ScopedVector
<UploadElementReader
> element_readers
;
1922 ElementsUploadDataStream
stream(element_readers
.Pass(), 0);
1924 // Setup the request
1925 HttpRequestInfo request
;
1926 request
.method
= "POST";
1927 request
.url
= GURL(GetDefaultUrl());
1928 request
.upload_data_stream
= &stream
;
1930 const uint64 kContentLength
= 0;
1932 scoped_ptr
<SpdyHeaderBlock
> req_block(
1933 spdy_util_
.ConstructPostHeaderBlock(GetDefaultUrl(), kContentLength
));
1934 scoped_ptr
<SpdyFrame
> req(
1935 spdy_util_
.ConstructSpdySyn(1, *req_block
, LOWEST
, false, true));
1937 MockWrite writes
[] = {
1938 CreateMockWrite(*req
, 0),
1941 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyPostSynReply(NULL
, 0));
1942 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
1943 MockRead reads
[] = {
1944 CreateMockRead(*resp
, 1),
1945 CreateMockRead(*body
, 2),
1946 MockRead(ASYNC
, 0, 3) // EOF
1949 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
1951 NormalSpdyTransactionHelper
helper(request
, DEFAULT_PRIORITY
,
1952 BoundNetLog(), GetParam(), NULL
);
1953 helper
.RunToCompletion(&data
);
1954 TransactionHelperResult out
= helper
.output();
1955 EXPECT_EQ(OK
, out
.rv
);
1956 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1957 EXPECT_EQ("hello!", out
.response_data
);
1960 // While we're doing a post, the server sends the reply before upload completes.
1961 TEST_P(SpdyNetworkTransactionTest
, ResponseBeforePostCompletes
) {
1962 scoped_ptr
<SpdyFrame
> req(spdy_util_
.ConstructChunkedSpdyPost(NULL
, 0));
1963 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
1964 MockWrite writes
[] = {
1965 CreateMockWrite(*req
, 0),
1966 CreateMockWrite(*body
, 3),
1968 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyPostSynReply(NULL
, 0));
1969 MockRead reads
[] = {
1970 CreateMockRead(*resp
, 1),
1971 CreateMockRead(*body
, 2),
1972 MockRead(ASYNC
, 0, 4) // EOF
1975 // Write the request headers, and read the complete response
1976 // while still waiting for chunked request data.
1977 DeterministicSocketData
data(reads
, arraysize(reads
),
1978 writes
, arraysize(writes
));
1979 NormalSpdyTransactionHelper
helper(CreateChunkedPostRequest(),
1981 BoundNetLog(), GetParam(), NULL
);
1982 helper
.SetDeterministic();
1983 helper
.RunPreTestSetup();
1984 helper
.AddDeterministicData(&data
);
1986 ASSERT_TRUE(helper
.StartDefaultTest());
1988 // Process the request headers, SYN_REPLY, and response body.
1989 // The request body is still in flight.
1992 const HttpResponseInfo
* response
= helper
.trans()->GetResponseInfo();
1993 EXPECT_EQ("HTTP/1.1 200 OK", response
->headers
->GetStatusLine());
1995 // Finish sending the request body.
1996 upload_chunked_data_stream()->AppendData(kUploadData
, kUploadDataSize
, true);
1999 std::string response_body
;
2000 EXPECT_EQ(OK
, ReadTransaction(helper
.trans(), &response_body
));
2001 EXPECT_EQ(kUploadData
, response_body
);
2002 helper
.VerifyDataConsumed();
2005 // The client upon cancellation tries to send a RST_STREAM frame. The mock
2006 // socket causes the TCP write to return zero. This test checks that the client
2007 // tries to queue up the RST_STREAM frame again.
2008 TEST_P(SpdyNetworkTransactionTest
, SocketWriteReturnsZero
) {
2009 scoped_ptr
<SpdyFrame
> req(
2010 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2011 scoped_ptr
<SpdyFrame
> rst(
2012 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_CANCEL
));
2013 MockWrite writes
[] = {
2014 CreateMockWrite(*req
.get(), 0, SYNCHRONOUS
),
2015 MockWrite(SYNCHRONOUS
, 0, 0, 2),
2016 CreateMockWrite(*rst
.get(), 3, SYNCHRONOUS
),
2019 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2020 MockRead reads
[] = {
2021 CreateMockRead(*resp
.get(), 1, ASYNC
),
2022 MockRead(ASYNC
, 0, 0, 4) // EOF
2025 DeterministicSocketData
data(reads
, arraysize(reads
),
2026 writes
, arraysize(writes
));
2027 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
2028 BoundNetLog(), GetParam(), NULL
);
2029 helper
.SetDeterministic();
2030 helper
.RunPreTestSetup();
2031 helper
.AddDeterministicData(&data
);
2032 HttpNetworkTransaction
* trans
= helper
.trans();
2034 TestCompletionCallback callback
;
2035 int rv
= trans
->Start(
2036 &CreateGetRequest(), callback
.callback(), BoundNetLog());
2037 EXPECT_EQ(ERR_IO_PENDING
, rv
);
2041 helper
.ResetTrans();
2045 helper
.VerifyDataConsumed();
2048 // Test that the transaction doesn't crash when we don't have a reply.
2049 TEST_P(SpdyNetworkTransactionTest
, ResponseWithoutSynReply
) {
2050 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
2051 MockRead reads
[] = {
2052 CreateMockRead(*body
, 1), MockRead(ASYNC
, 0, 3) // EOF
2055 scoped_ptr
<SpdyFrame
> req(
2056 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2057 scoped_ptr
<SpdyFrame
> rst(
2058 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR
));
2059 MockWrite writes
[] = {
2060 CreateMockWrite(*req
, 0), CreateMockWrite(*rst
, 2),
2062 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
2063 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
2064 BoundNetLog(), GetParam(), NULL
);
2065 helper
.RunToCompletion(&data
);
2066 TransactionHelperResult out
= helper
.output();
2067 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR
, out
.rv
);
2070 // Test that the transaction doesn't crash when we get two replies on the same
2071 // stream ID. See http://crbug.com/45639.
2072 TEST_P(SpdyNetworkTransactionTest
, ResponseWithTwoSynReplies
) {
2073 scoped_ptr
<SpdyFrame
> req(
2074 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2075 scoped_ptr
<SpdyFrame
> rst(
2076 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR
));
2077 MockWrite writes
[] = {
2078 CreateMockWrite(*req
, 0), CreateMockWrite(*rst
, 4),
2081 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2082 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
2083 MockRead reads
[] = {
2084 CreateMockRead(*resp
, 1),
2085 CreateMockRead(*resp
, 2),
2086 CreateMockRead(*body
, 3),
2087 MockRead(ASYNC
, 0, 5) // EOF
2090 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
2092 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
2093 BoundNetLog(), GetParam(), NULL
);
2094 helper
.RunPreTestSetup();
2095 helper
.AddData(&data
);
2097 HttpNetworkTransaction
* trans
= helper
.trans();
2099 TestCompletionCallback callback
;
2100 int rv
= trans
->Start(&helper
.request(), callback
.callback(), BoundNetLog());
2101 EXPECT_EQ(ERR_IO_PENDING
, rv
);
2102 rv
= callback
.WaitForResult();
2105 const HttpResponseInfo
* response
= trans
->GetResponseInfo();
2106 ASSERT_TRUE(response
!= NULL
);
2107 EXPECT_TRUE(response
->headers
.get() != NULL
);
2108 EXPECT_TRUE(response
->was_fetched_via_spdy
);
2109 std::string response_data
;
2110 rv
= ReadTransaction(trans
, &response_data
);
2111 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR
, rv
);
2113 helper
.VerifyDataConsumed();
2116 TEST_P(SpdyNetworkTransactionTest
, ResetReplyWithTransferEncoding
) {
2117 // Construct the request.
2118 scoped_ptr
<SpdyFrame
> req(
2119 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2120 scoped_ptr
<SpdyFrame
> rst(
2121 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR
));
2122 MockWrite writes
[] = {
2123 CreateMockWrite(*req
, 0), CreateMockWrite(*rst
, 2),
2126 const char* const headers
[] = {
2127 "transfer-encoding", "chunked"
2129 scoped_ptr
<SpdyFrame
> resp(
2130 spdy_util_
.ConstructSpdyGetSynReply(headers
, 1, 1));
2131 scoped_ptr
<SpdyFrame
> body(
2132 spdy_util_
.ConstructSpdyBodyFrame(1, true));
2133 MockRead reads
[] = {
2134 CreateMockRead(*resp
, 1),
2135 CreateMockRead(*body
, 3),
2136 MockRead(ASYNC
, 0, 4) // EOF
2139 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
2140 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
2141 BoundNetLog(), GetParam(), NULL
);
2142 helper
.RunToCompletion(&data
);
2143 TransactionHelperResult out
= helper
.output();
2144 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR
, out
.rv
);
2146 helper
.session()->spdy_session_pool()->CloseAllSessions();
2147 helper
.VerifyDataConsumed();
2150 TEST_P(SpdyNetworkTransactionTest
, ResetPushWithTransferEncoding
) {
2151 // Construct the request.
2152 scoped_ptr
<SpdyFrame
> req(
2153 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2154 scoped_ptr
<SpdyFrame
> rst(
2155 spdy_util_
.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR
));
2156 MockWrite writes
[] = {
2157 CreateMockWrite(*req
, 0), CreateMockWrite(*rst
, 4),
2160 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2161 const char* const headers
[] = {
2162 "transfer-encoding", "chunked"
2164 scoped_ptr
<SpdyFrame
> push(
2165 spdy_util_
.ConstructSpdyPush(headers
, arraysize(headers
) / 2, 2, 1,
2166 GetDefaultUrlWithPath("/1").c_str()));
2167 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
2168 MockRead reads
[] = {
2169 CreateMockRead(*resp
, 1),
2170 CreateMockRead(*push
, 2),
2171 CreateMockRead(*body
, 3),
2172 MockRead(ASYNC
, 0, 5) // EOF
2175 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
2176 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
2177 BoundNetLog(), GetParam(), NULL
);
2178 helper
.RunToCompletion(&data
);
2179 TransactionHelperResult out
= helper
.output();
2180 EXPECT_EQ(OK
, out
.rv
);
2181 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
2182 EXPECT_EQ("hello!", out
.response_data
);
2184 helper
.session()->spdy_session_pool()->CloseAllSessions();
2185 helper
.VerifyDataConsumed();
2188 TEST_P(SpdyNetworkTransactionTest
, CancelledTransaction
) {
2189 // Construct the request.
2190 scoped_ptr
<SpdyFrame
> req(
2191 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2192 MockWrite writes
[] = {
2193 CreateMockWrite(*req
),
2196 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2197 MockRead reads
[] = {
2198 CreateMockRead(*resp
),
2199 // This following read isn't used by the test, except during the
2200 // RunUntilIdle() call at the end since the SpdySession survives the
2201 // HttpNetworkTransaction and still tries to continue Read()'ing. Any
2202 // MockRead will do here.
2203 MockRead(ASYNC
, 0, 0) // EOF
2206 StaticSocketDataProvider
data(reads
, arraysize(reads
),
2207 writes
, arraysize(writes
));
2209 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
2210 BoundNetLog(), GetParam(), NULL
);
2211 helper
.RunPreTestSetup();
2212 helper
.AddData(&data
);
2213 HttpNetworkTransaction
* trans
= helper
.trans();
2215 TestCompletionCallback callback
;
2216 int rv
= trans
->Start(
2217 &CreateGetRequest(), callback
.callback(), BoundNetLog());
2218 EXPECT_EQ(ERR_IO_PENDING
, rv
);
2219 helper
.ResetTrans(); // Cancel the transaction.
2221 // Flush the MessageLoop while the SpdySessionDependencies (in particular, the
2222 // MockClientSocketFactory) are still alive.
2223 base::RunLoop().RunUntilIdle();
2224 helper
.VerifyDataNotConsumed();
2227 // Verify that the client sends a Rst Frame upon cancelling the stream.
2228 TEST_P(SpdyNetworkTransactionTest
, CancelledTransactionSendRst
) {
2229 scoped_ptr
<SpdyFrame
> req(
2230 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2231 scoped_ptr
<SpdyFrame
> rst(
2232 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_CANCEL
));
2233 MockWrite writes
[] = {
2234 CreateMockWrite(*req
, 0, SYNCHRONOUS
),
2235 CreateMockWrite(*rst
, 2, SYNCHRONOUS
),
2238 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2239 MockRead reads
[] = {
2240 CreateMockRead(*resp
, 1, ASYNC
),
2241 MockRead(ASYNC
, 0, 0, 3) // EOF
2244 DeterministicSocketData
data(reads
, arraysize(reads
),
2245 writes
, arraysize(writes
));
2247 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
2250 helper
.SetDeterministic();
2251 helper
.RunPreTestSetup();
2252 helper
.AddDeterministicData(&data
);
2253 HttpNetworkTransaction
* trans
= helper
.trans();
2255 TestCompletionCallback callback
;
2257 int rv
= trans
->Start(
2258 &CreateGetRequest(), callback
.callback(), BoundNetLog());
2259 EXPECT_EQ(ERR_IO_PENDING
, rv
);
2263 helper
.ResetTrans();
2267 helper
.VerifyDataConsumed();
2270 // Verify that the client can correctly deal with the user callback attempting
2271 // to start another transaction on a session that is closing down. See
2272 // http://crbug.com/47455
2273 TEST_P(SpdyNetworkTransactionTest
, StartTransactionOnReadCallback
) {
2274 scoped_ptr
<SpdyFrame
> req(
2275 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2276 MockWrite writes
[] = {CreateMockWrite(*req
)};
2277 MockWrite writes2
[] = {CreateMockWrite(*req
, 0)};
2279 // The indicated length of this frame is longer than its actual length. When
2280 // the session receives an empty frame after this one, it shuts down the
2281 // session, and calls the read callback with the incomplete data.
2282 const uint8 kGetBodyFrame2
[] = {
2283 0x00, 0x00, 0x00, 0x01,
2284 0x01, 0x00, 0x00, 0x07,
2285 'h', 'e', 'l', 'l', 'o', '!',
2288 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2289 MockRead reads
[] = {
2290 CreateMockRead(*resp
, 1),
2291 MockRead(ASYNC
, ERR_IO_PENDING
, 2), // Force a pause
2292 MockRead(ASYNC
, reinterpret_cast<const char*>(kGetBodyFrame2
),
2293 arraysize(kGetBodyFrame2
), 3),
2294 MockRead(ASYNC
, ERR_IO_PENDING
, 4), // Force a pause
2295 MockRead(ASYNC
, 0, 0, 5), // EOF
2297 MockRead reads2
[] = {
2298 CreateMockRead(*resp
, 1), MockRead(ASYNC
, 0, 0, 2), // EOF
2301 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
2302 SequencedSocketData
data2(reads2
, arraysize(reads2
), writes2
,
2303 arraysize(writes2
));
2305 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
2306 BoundNetLog(), GetParam(), NULL
);
2307 helper
.RunPreTestSetup();
2308 helper
.AddData(&data
);
2309 helper
.AddData(&data2
);
2310 HttpNetworkTransaction
* trans
= helper
.trans();
2312 // Start the transaction with basic parameters.
2313 TestCompletionCallback callback
;
2314 int rv
= trans
->Start(&helper
.request(), callback
.callback(), BoundNetLog());
2315 EXPECT_EQ(ERR_IO_PENDING
, rv
);
2316 rv
= callback
.WaitForResult();
2318 const int kSize
= 3000;
2319 scoped_refptr
<IOBuffer
> buf(new IOBuffer(kSize
));
2322 base::Bind(&SpdyNetworkTransactionTest::StartTransactionCallback
,
2323 helper
.session(), GURL(GetDefaultUrl())));
2324 ASSERT_EQ(ERR_IO_PENDING
, rv
);
2325 // This forces an err_IO_pending, which sets the callback.
2326 data
.CompleteRead();
2327 // This finishes the read.
2328 data
.CompleteRead();
2329 helper
.VerifyDataConsumed();
2332 // Verify that the client can correctly deal with the user callback deleting the
2333 // transaction. Failures will usually be valgrind errors. See
2334 // http://crbug.com/46925
2335 TEST_P(SpdyNetworkTransactionTest
, DeleteSessionOnReadCallback
) {
2336 scoped_ptr
<SpdyFrame
> req(
2337 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2338 MockWrite writes
[] = {CreateMockWrite(*req
, 0)};
2340 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2341 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
2342 MockRead reads
[] = {
2343 CreateMockRead(*resp
.get(), 1),
2344 MockRead(ASYNC
, ERR_IO_PENDING
, 2), // Force a pause
2345 CreateMockRead(*body
.get(), 3),
2346 MockRead(ASYNC
, 0, 0, 4), // EOF
2349 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
2351 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
2352 BoundNetLog(), GetParam(), NULL
);
2353 helper
.RunPreTestSetup();
2354 helper
.AddData(&data
);
2355 HttpNetworkTransaction
* trans
= helper
.trans();
2357 // Start the transaction with basic parameters.
2358 TestCompletionCallback callback
;
2359 int rv
= trans
->Start(&helper
.request(), callback
.callback(), BoundNetLog());
2360 EXPECT_EQ(ERR_IO_PENDING
, rv
);
2361 rv
= callback
.WaitForResult();
2363 // Setup a user callback which will delete the session, and clear out the
2364 // memory holding the stream object. Note that the callback deletes trans.
2365 const int kSize
= 3000;
2366 scoped_refptr
<IOBuffer
> buf(new IOBuffer(kSize
));
2370 base::Bind(&SpdyNetworkTransactionTest::DeleteSessionCallback
,
2371 base::Unretained(&helper
)));
2372 ASSERT_EQ(ERR_IO_PENDING
, rv
);
2373 data
.CompleteRead();
2375 // Finish running rest of tasks.
2376 base::RunLoop().RunUntilIdle();
2377 helper
.VerifyDataConsumed();
2380 // Send a spdy request to www.example.org that gets redirected to www.foo.com.
2381 TEST_P(SpdyNetworkTransactionTest
, DISABLED_RedirectGetRequest
) {
2382 scoped_ptr
<SpdyHeaderBlock
> headers(
2383 spdy_util_
.ConstructGetHeaderBlock(GetDefaultUrl()));
2384 (*headers
)["user-agent"] = "";
2385 (*headers
)["accept-encoding"] = "gzip, deflate";
2386 scoped_ptr
<SpdyHeaderBlock
> headers2(
2387 spdy_util_
.ConstructGetHeaderBlock("http://www.foo.com/index.php"));
2388 (*headers2
)["user-agent"] = "";
2389 (*headers2
)["accept-encoding"] = "gzip, deflate";
2391 // Setup writes/reads to www.example.org
2392 scoped_ptr
<SpdyFrame
> req(
2393 spdy_util_
.ConstructSpdySyn(1, *headers
, LOWEST
, false, true));
2394 scoped_ptr
<SpdyFrame
> req2(
2395 spdy_util_
.ConstructSpdySyn(1, *headers2
, LOWEST
, false, true));
2396 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReplyRedirect(1));
2397 MockWrite writes
[] = {
2398 CreateMockWrite(*req
, 1),
2400 MockRead reads
[] = {
2401 CreateMockRead(*resp
, 2),
2402 MockRead(ASYNC
, 0, 0, 3) // EOF
2405 // Setup writes/reads to www.foo.com
2406 scoped_ptr
<SpdyFrame
> resp2(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2407 scoped_ptr
<SpdyFrame
> body2(spdy_util_
.ConstructSpdyBodyFrame(1, true));
2408 MockWrite writes2
[] = {
2409 CreateMockWrite(*req2
, 1),
2411 MockRead reads2
[] = {
2412 CreateMockRead(*resp2
, 2),
2413 CreateMockRead(*body2
, 3),
2414 MockRead(ASYNC
, 0, 0, 4) // EOF
2416 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
2417 SequencedSocketData
data2(reads2
, arraysize(reads2
), writes2
,
2418 arraysize(writes2
));
2420 // TODO(erikchen): Make test support SPDYSSL, SPDYNPN
2423 SpdyURLRequestContext
spdy_url_request_context(GetParam().protocol
);
2424 scoped_ptr
<URLRequest
> r(spdy_url_request_context
.CreateRequest(
2425 GURL(GetDefaultUrl()), DEFAULT_PRIORITY
, &d
));
2426 spdy_url_request_context
.socket_factory().
2427 AddSocketDataProvider(&data
);
2428 spdy_url_request_context
.socket_factory().
2429 AddSocketDataProvider(&data2
);
2431 d
.set_quit_on_redirect(true);
2433 base::RunLoop().Run();
2435 EXPECT_EQ(1, d
.received_redirect_count());
2437 r
->FollowDeferredRedirect();
2438 base::RunLoop().Run();
2439 EXPECT_EQ(1, d
.response_started_count());
2440 EXPECT_FALSE(d
.received_data_before_response());
2441 EXPECT_EQ(URLRequestStatus::SUCCESS
, r
->status().status());
2442 std::string
contents("hello!");
2443 EXPECT_EQ(contents
, d
.data_received());
2445 EXPECT_TRUE(data
.AllReadDataConsumed());
2446 EXPECT_TRUE(data
.AllWriteDataConsumed());
2447 EXPECT_TRUE(data2
.AllReadDataConsumed());
2448 EXPECT_TRUE(data2
.AllWriteDataConsumed());
2451 // Send a spdy request to www.example.org. Get a pushed stream that redirects to
2453 TEST_P(SpdyNetworkTransactionTest
, DISABLED_RedirectServerPush
) {
2454 scoped_ptr
<SpdyHeaderBlock
> headers(
2455 spdy_util_
.ConstructGetHeaderBlock(GetDefaultUrl()));
2456 (*headers
)["user-agent"] = "";
2457 (*headers
)["accept-encoding"] = "gzip, deflate";
2459 // Setup writes/reads to www.example.org
2460 scoped_ptr
<SpdyFrame
> req(
2461 spdy_util_
.ConstructSpdySyn(1, *headers
, LOWEST
, false, true));
2462 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2463 scoped_ptr
<SpdyFrame
> rep(spdy_util_
.ConstructSpdyPush(
2464 NULL
, 0, 2, 1, GetDefaultUrlWithPath("/foo.dat").c_str(),
2465 "301 Moved Permanently", "http://www.foo.com/index.php"));
2466 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
2467 scoped_ptr
<SpdyFrame
> rst(
2468 spdy_util_
.ConstructSpdyRstStream(2, RST_STREAM_CANCEL
));
2469 MockWrite writes
[] = {
2470 CreateMockWrite(*req
, 1),
2471 CreateMockWrite(*rst
, 6),
2473 MockRead reads
[] = {
2474 CreateMockRead(*resp
, 2),
2475 CreateMockRead(*rep
, 3),
2476 CreateMockRead(*body
, 4),
2477 MockRead(ASYNC
, ERR_IO_PENDING
, 5), // Force a pause
2478 MockRead(ASYNC
, 0, 0, 7) // EOF
2481 // Setup writes/reads to www.foo.com
2482 scoped_ptr
<SpdyHeaderBlock
> headers2(
2483 spdy_util_
.ConstructGetHeaderBlock("http://www.foo.com/index.php"));
2484 (*headers2
)["user-agent"] = "";
2485 (*headers2
)["accept-encoding"] = "gzip, deflate";
2486 scoped_ptr
<SpdyFrame
> req2(
2487 spdy_util_
.ConstructSpdySyn(1, *headers2
, LOWEST
, false, true));
2488 scoped_ptr
<SpdyFrame
> resp2(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2489 scoped_ptr
<SpdyFrame
> body2(spdy_util_
.ConstructSpdyBodyFrame(1, true));
2490 MockWrite writes2
[] = {
2491 CreateMockWrite(*req2
, 1),
2493 MockRead reads2
[] = {
2494 CreateMockRead(*resp2
, 2),
2495 CreateMockRead(*body2
, 3),
2496 MockRead(ASYNC
, 0, 0, 5) // EOF
2498 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
2499 SequencedSocketData
data2(reads2
, arraysize(reads2
), writes2
,
2500 arraysize(writes2
));
2502 // TODO(erikchen): Make test support SPDYSSL, SPDYNPN
2505 SpdyURLRequestContext
spdy_url_request_context(GetParam().protocol
);
2507 scoped_ptr
<URLRequest
> r(spdy_url_request_context
.CreateRequest(
2508 GURL(GetDefaultUrl()), DEFAULT_PRIORITY
, &d
));
2509 spdy_url_request_context
.socket_factory().
2510 AddSocketDataProvider(&data
);
2513 base::RunLoop().Run();
2515 EXPECT_EQ(0, d
.received_redirect_count());
2516 std::string
contents("hello!");
2517 EXPECT_EQ(contents
, d
.data_received());
2519 scoped_ptr
<URLRequest
> r2(spdy_url_request_context
.CreateRequest(
2520 GURL(GetDefaultUrlWithPath("/foo.dat")), DEFAULT_PRIORITY
, &d2
));
2521 spdy_url_request_context
.socket_factory().
2522 AddSocketDataProvider(&data2
);
2524 d2
.set_quit_on_redirect(true);
2526 base::RunLoop().Run();
2527 EXPECT_EQ(1, d2
.received_redirect_count());
2529 r2
->FollowDeferredRedirect();
2530 base::RunLoop().Run();
2531 EXPECT_EQ(1, d2
.response_started_count());
2532 EXPECT_FALSE(d2
.received_data_before_response());
2533 EXPECT_EQ(URLRequestStatus::SUCCESS
, r2
->status().status());
2534 std::string
contents2("hello!");
2535 EXPECT_EQ(contents2
, d2
.data_received());
2537 EXPECT_TRUE(data
.AllReadDataConsumed());
2538 EXPECT_TRUE(data
.AllWriteDataConsumed());
2539 EXPECT_TRUE(data2
.AllReadDataConsumed());
2540 EXPECT_TRUE(data2
.AllWriteDataConsumed());
2543 TEST_P(SpdyNetworkTransactionTest
, ServerPushSingleDataFrame
) {
2544 scoped_ptr
<SpdyFrame
> stream1_syn(
2545 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2546 scoped_ptr
<SpdyFrame
> stream1_body(
2547 spdy_util_
.ConstructSpdyBodyFrame(1, true));
2548 MockWrite writes
[] = {
2549 CreateMockWrite(*stream1_syn
, 0),
2552 scoped_ptr
<SpdyFrame
>
2553 stream1_reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2554 scoped_ptr
<SpdyFrame
> stream2_syn(spdy_util_
.ConstructSpdyPush(
2555 NULL
, 0, 2, 1, GetDefaultUrlWithPath("/foo.dat").c_str()));
2556 const char kPushedData
[] = "pushed";
2557 scoped_ptr
<SpdyFrame
> stream2_body(
2558 spdy_util_
.ConstructSpdyBodyFrame(
2559 2, kPushedData
, strlen(kPushedData
), true));
2560 MockRead reads
[] = {
2561 CreateMockRead(*stream1_reply
, 1),
2562 CreateMockRead(*stream2_syn
, 2),
2563 CreateMockRead(*stream1_body
, 3, SYNCHRONOUS
),
2564 CreateMockRead(*stream2_body
, 4),
2565 MockRead(SYNCHRONOUS
, ERR_IO_PENDING
, 5), // Force a pause
2568 HttpResponseInfo response
;
2569 HttpResponseInfo response2
;
2570 std::string
expected_push_result("pushed");
2571 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
2572 RunServerPushTest(&data
,
2575 expected_push_result
);
2577 // Verify the SYN_REPLY.
2578 EXPECT_TRUE(response
.headers
.get() != NULL
);
2579 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
2581 // Verify the pushed stream.
2582 EXPECT_TRUE(response2
.headers
.get() != NULL
);
2583 EXPECT_EQ("HTTP/1.1 200 OK", response2
.headers
->GetStatusLine());
2586 TEST_P(SpdyNetworkTransactionTest
, ServerPushBeforeSynReply
) {
2587 scoped_ptr
<SpdyFrame
> stream1_syn(
2588 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2589 scoped_ptr
<SpdyFrame
> stream1_body(
2590 spdy_util_
.ConstructSpdyBodyFrame(1, true));
2591 MockWrite writes
[] = {
2592 CreateMockWrite(*stream1_syn
, 0),
2595 scoped_ptr
<SpdyFrame
>
2596 stream1_reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2597 scoped_ptr
<SpdyFrame
> stream2_syn(spdy_util_
.ConstructSpdyPush(
2598 NULL
, 0, 2, 1, GetDefaultUrlWithPath("/foo.dat").c_str()));
2599 const char kPushedData
[] = "pushed";
2600 scoped_ptr
<SpdyFrame
> stream2_body(
2601 spdy_util_
.ConstructSpdyBodyFrame(
2602 2, kPushedData
, strlen(kPushedData
), true));
2603 MockRead reads
[] = {
2604 CreateMockRead(*stream2_syn
, 1),
2605 CreateMockRead(*stream1_reply
, 2),
2606 CreateMockRead(*stream1_body
, 3, SYNCHRONOUS
),
2607 CreateMockRead(*stream2_body
, 4),
2608 MockRead(SYNCHRONOUS
, ERR_IO_PENDING
, 5), // Force a pause
2611 HttpResponseInfo response
;
2612 HttpResponseInfo response2
;
2613 std::string
expected_push_result("pushed");
2614 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
2615 RunServerPushTest(&data
,
2618 expected_push_result
);
2620 // Verify the SYN_REPLY.
2621 EXPECT_TRUE(response
.headers
.get() != NULL
);
2622 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
2624 // Verify the pushed stream.
2625 EXPECT_TRUE(response2
.headers
.get() != NULL
);
2626 EXPECT_EQ("HTTP/1.1 200 OK", response2
.headers
->GetStatusLine());
2629 TEST_P(SpdyNetworkTransactionTest
, ServerPushSingleDataFrame2
) {
2630 scoped_ptr
<SpdyFrame
> stream1_syn(
2631 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2632 MockWrite writes
[] = {
2633 CreateMockWrite(*stream1_syn
, 0),
2636 scoped_ptr
<SpdyFrame
>
2637 stream1_reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2638 scoped_ptr
<SpdyFrame
> stream2_syn(spdy_util_
.ConstructSpdyPush(
2639 NULL
, 0, 2, 1, GetDefaultUrlWithPath("/foo.dat").c_str()));
2640 const char kPushedData
[] = "pushed";
2641 scoped_ptr
<SpdyFrame
> stream2_body(
2642 spdy_util_
.ConstructSpdyBodyFrame(
2643 2, kPushedData
, strlen(kPushedData
), true));
2644 scoped_ptr
<SpdyFrame
>
2645 stream1_body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
2646 MockRead reads
[] = {
2647 CreateMockRead(*stream1_reply
, 1),
2648 CreateMockRead(*stream2_syn
, 2),
2649 CreateMockRead(*stream2_body
, 3),
2650 CreateMockRead(*stream1_body
, 4, SYNCHRONOUS
),
2651 MockRead(SYNCHRONOUS
, ERR_IO_PENDING
, 5), // Force a pause
2654 HttpResponseInfo response
;
2655 HttpResponseInfo response2
;
2656 std::string
expected_push_result("pushed");
2657 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
2658 RunServerPushTest(&data
,
2661 expected_push_result
);
2663 // Verify the SYN_REPLY.
2664 EXPECT_TRUE(response
.headers
.get() != NULL
);
2665 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
2667 // Verify the pushed stream.
2668 EXPECT_TRUE(response2
.headers
.get() != NULL
);
2669 EXPECT_EQ("HTTP/1.1 200 OK", response2
.headers
->GetStatusLine());
2672 TEST_P(SpdyNetworkTransactionTest
, ServerPushServerAborted
) {
2673 scoped_ptr
<SpdyFrame
> stream1_syn(
2674 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2675 scoped_ptr
<SpdyFrame
> stream1_body(
2676 spdy_util_
.ConstructSpdyBodyFrame(1, true));
2677 MockWrite writes
[] = {
2678 CreateMockWrite(*stream1_syn
, 0),
2681 scoped_ptr
<SpdyFrame
>
2682 stream1_reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2683 scoped_ptr
<SpdyFrame
> stream2_syn(spdy_util_
.ConstructSpdyPush(
2684 NULL
, 0, 2, 1, GetDefaultUrlWithPath("/foo.dat").c_str()));
2685 scoped_ptr
<SpdyFrame
> stream2_rst(
2686 spdy_util_
.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR
));
2687 MockRead reads
[] = {
2688 CreateMockRead(*stream1_reply
, 1),
2689 CreateMockRead(*stream2_syn
, 2),
2690 CreateMockRead(*stream2_rst
, 3),
2691 CreateMockRead(*stream1_body
, 4, SYNCHRONOUS
),
2692 MockRead(SYNCHRONOUS
, ERR_IO_PENDING
, 5), // Force a pause
2695 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
2696 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
2697 BoundNetLog(), GetParam(), NULL
);
2699 helper
.RunPreTestSetup();
2700 helper
.AddData(&data
);
2702 HttpNetworkTransaction
* trans
= helper
.trans();
2704 // Start the transaction with basic parameters.
2705 TestCompletionCallback callback
;
2706 int rv
= trans
->Start(
2707 &CreateGetRequest(), callback
.callback(), BoundNetLog());
2708 EXPECT_EQ(ERR_IO_PENDING
, rv
);
2709 rv
= callback
.WaitForResult();
2712 // Verify that we consumed all test data.
2713 EXPECT_TRUE(data
.AllReadDataConsumed());
2714 EXPECT_TRUE(data
.AllWriteDataConsumed());
2716 // Verify the SYN_REPLY.
2717 HttpResponseInfo response
= *trans
->GetResponseInfo();
2718 EXPECT_TRUE(response
.headers
.get() != NULL
);
2719 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
2722 // Verify that we don't leak streams and that we properly send a reset
2723 // if the server pushes the same stream twice.
2724 TEST_P(SpdyNetworkTransactionTest
, ServerPushDuplicate
) {
2725 scoped_ptr
<SpdyFrame
> stream1_syn(
2726 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2727 scoped_ptr
<SpdyFrame
> stream1_body(
2728 spdy_util_
.ConstructSpdyBodyFrame(1, true));
2729 scoped_ptr
<SpdyFrame
> stream3_rst(
2730 spdy_util_
.ConstructSpdyRstStream(4, RST_STREAM_PROTOCOL_ERROR
));
2731 MockWrite writes
[] = {
2732 CreateMockWrite(*stream1_syn
, 0), CreateMockWrite(*stream3_rst
, 4),
2735 scoped_ptr
<SpdyFrame
>
2736 stream1_reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2737 scoped_ptr
<SpdyFrame
> stream2_syn(spdy_util_
.ConstructSpdyPush(
2738 NULL
, 0, 2, 1, GetDefaultUrlWithPath("/foo.dat").c_str()));
2739 const char kPushedData
[] = "pushed";
2740 scoped_ptr
<SpdyFrame
> stream2_body(
2741 spdy_util_
.ConstructSpdyBodyFrame(
2742 2, kPushedData
, strlen(kPushedData
), true));
2743 scoped_ptr
<SpdyFrame
> stream3_syn(spdy_util_
.ConstructSpdyPush(
2744 NULL
, 0, 4, 1, GetDefaultUrlWithPath("/foo.dat").c_str()));
2745 MockRead reads
[] = {
2746 CreateMockRead(*stream1_reply
, 1),
2747 CreateMockRead(*stream2_syn
, 2),
2748 CreateMockRead(*stream3_syn
, 3),
2749 CreateMockRead(*stream1_body
, 5),
2750 CreateMockRead(*stream2_body
, 6),
2751 MockRead(SYNCHRONOUS
, ERR_IO_PENDING
, 7), // Force a pause
2754 HttpResponseInfo response
;
2755 HttpResponseInfo response2
;
2756 std::string
expected_push_result("pushed");
2757 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
2758 RunServerPushTest(&data
,
2761 expected_push_result
);
2763 // Verify the SYN_REPLY.
2764 EXPECT_TRUE(response
.headers
.get() != NULL
);
2765 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
2767 // Verify the pushed stream.
2768 EXPECT_TRUE(response2
.headers
.get() != NULL
);
2769 EXPECT_EQ("HTTP/1.1 200 OK", response2
.headers
->GetStatusLine());
2772 TEST_P(SpdyNetworkTransactionTest
, ServerPushMultipleDataFrame
) {
2773 scoped_ptr
<SpdyFrame
> stream1_syn(
2774 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2775 scoped_ptr
<SpdyFrame
> stream1_body(
2776 spdy_util_
.ConstructSpdyBodyFrame(1, true));
2777 MockWrite writes
[] = {
2778 CreateMockWrite(*stream1_syn
, 0),
2781 scoped_ptr
<SpdyFrame
>
2782 stream1_reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2783 scoped_ptr
<SpdyFrame
> stream2_syn(spdy_util_
.ConstructSpdyPush(
2784 NULL
, 0, 2, 1, GetDefaultUrlWithPath("/foo.dat").c_str()));
2785 static const char kPushedData
[] = "pushed my darling hello my baby";
2786 scoped_ptr
<SpdyFrame
> stream2_body_base(
2787 spdy_util_
.ConstructSpdyBodyFrame(
2788 2, kPushedData
, strlen(kPushedData
), true));
2789 const size_t kChunkSize
= strlen(kPushedData
) / 4;
2790 scoped_ptr
<SpdyFrame
> stream2_body1(
2791 new SpdyFrame(stream2_body_base
->data(), kChunkSize
, false));
2792 scoped_ptr
<SpdyFrame
> stream2_body2(
2793 new SpdyFrame(stream2_body_base
->data() + kChunkSize
, kChunkSize
, false));
2794 scoped_ptr
<SpdyFrame
> stream2_body3(
2795 new SpdyFrame(stream2_body_base
->data() + 2 * kChunkSize
,
2796 kChunkSize
, false));
2797 scoped_ptr
<SpdyFrame
> stream2_body4(
2798 new SpdyFrame(stream2_body_base
->data() + 3 * kChunkSize
,
2799 stream2_body_base
->size() - 3 * kChunkSize
, false));
2800 MockRead reads
[] = {
2801 CreateMockRead(*stream1_reply
, 1),
2802 CreateMockRead(*stream2_syn
, 2),
2803 CreateMockRead(*stream2_body1
, 3),
2804 CreateMockRead(*stream2_body2
, 4),
2805 CreateMockRead(*stream2_body3
, 5),
2806 CreateMockRead(*stream2_body4
, 6),
2807 CreateMockRead(*stream1_body
, 7, SYNCHRONOUS
),
2808 MockRead(SYNCHRONOUS
, ERR_IO_PENDING
, 8), // Force a pause
2811 HttpResponseInfo response
;
2812 HttpResponseInfo response2
;
2813 std::string
expected_push_result("pushed my darling hello my baby");
2814 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
2815 RunServerPushTest(&data
, &response
, &response2
, kPushedData
);
2817 // Verify the SYN_REPLY.
2818 EXPECT_TRUE(response
.headers
.get() != NULL
);
2819 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
2821 // Verify the pushed stream.
2822 EXPECT_TRUE(response2
.headers
.get() != NULL
);
2823 EXPECT_EQ("HTTP/1.1 200 OK", response2
.headers
->GetStatusLine());
2826 TEST_P(SpdyNetworkTransactionTest
, ServerPushMultipleDataFrameInterrupted
) {
2827 scoped_ptr
<SpdyFrame
> stream1_syn(
2828 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2829 scoped_ptr
<SpdyFrame
> stream1_body(
2830 spdy_util_
.ConstructSpdyBodyFrame(1, true));
2831 MockWrite writes
[] = {
2832 CreateMockWrite(*stream1_syn
, 0),
2835 scoped_ptr
<SpdyFrame
>
2836 stream1_reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2837 scoped_ptr
<SpdyFrame
> stream2_syn(spdy_util_
.ConstructSpdyPush(
2838 NULL
, 0, 2, 1, GetDefaultUrlWithPath("/foo.dat").c_str()));
2839 static const char kPushedData
[] = "pushed my darling hello my baby";
2840 scoped_ptr
<SpdyFrame
> stream2_body_base(
2841 spdy_util_
.ConstructSpdyBodyFrame(
2842 2, kPushedData
, strlen(kPushedData
), true));
2843 const size_t kChunkSize
= strlen(kPushedData
) / 4;
2844 scoped_ptr
<SpdyFrame
> stream2_body1(
2845 new SpdyFrame(stream2_body_base
->data(), kChunkSize
, false));
2846 scoped_ptr
<SpdyFrame
> stream2_body2(
2847 new SpdyFrame(stream2_body_base
->data() + kChunkSize
, kChunkSize
, false));
2848 scoped_ptr
<SpdyFrame
> stream2_body3(
2849 new SpdyFrame(stream2_body_base
->data() + 2 * kChunkSize
,
2850 kChunkSize
, false));
2851 scoped_ptr
<SpdyFrame
> stream2_body4(
2852 new SpdyFrame(stream2_body_base
->data() + 3 * kChunkSize
,
2853 stream2_body_base
->size() - 3 * kChunkSize
, false));
2854 MockRead reads
[] = {
2855 CreateMockRead(*stream1_reply
, 1),
2856 CreateMockRead(*stream2_syn
, 2),
2857 CreateMockRead(*stream2_body1
, 3),
2858 CreateMockRead(*stream2_body2
, 4),
2859 CreateMockRead(*stream2_body3
, 5),
2860 CreateMockRead(*stream2_body4
, 6),
2861 CreateMockRead(*stream1_body
.get(), 7, SYNCHRONOUS
),
2862 MockRead(SYNCHRONOUS
, ERR_IO_PENDING
, 8) // Force a pause.
2865 HttpResponseInfo response
;
2866 HttpResponseInfo response2
;
2867 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
2868 RunServerPushTest(&data
, &response
, &response2
, kPushedData
);
2870 // Verify the SYN_REPLY.
2871 EXPECT_TRUE(response
.headers
.get() != NULL
);
2872 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
2874 // Verify the pushed stream.
2875 EXPECT_TRUE(response2
.headers
.get() != NULL
);
2876 EXPECT_EQ("HTTP/1.1 200 OK", response2
.headers
->GetStatusLine());
2879 TEST_P(SpdyNetworkTransactionTest
, ServerPushInvalidAssociatedStreamID0
) {
2880 if (spdy_util_
.spdy_version() == HTTP2
) {
2881 // PUSH_PROMISE with stream id 0 is connection-level error.
2882 // TODO(baranovich): Test session going away.
2886 scoped_ptr
<SpdyFrame
> stream1_syn(
2887 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2888 scoped_ptr
<SpdyFrame
> stream1_body(
2889 spdy_util_
.ConstructSpdyBodyFrame(1, true));
2890 scoped_ptr
<SpdyFrame
> stream2_rst(
2891 spdy_util_
.ConstructSpdyRstStream(2, RST_STREAM_REFUSED_STREAM
));
2892 MockWrite writes
[] = {
2893 CreateMockWrite(*stream1_syn
, 0), CreateMockWrite(*stream2_rst
, 3),
2896 scoped_ptr
<SpdyFrame
>
2897 stream1_reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2898 scoped_ptr
<SpdyFrame
> stream2_syn(spdy_util_
.ConstructSpdyPush(
2899 NULL
, 0, 2, 0, GetDefaultUrlWithPath("/foo.dat").c_str()));
2900 MockRead reads
[] = {
2901 CreateMockRead(*stream1_reply
, 1),
2902 CreateMockRead(*stream2_syn
, 2),
2903 CreateMockRead(*stream1_body
, 4),
2904 MockRead(SYNCHRONOUS
, ERR_IO_PENDING
, 5) // Force a pause
2907 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
2908 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
2909 BoundNetLog(), GetParam(), NULL
);
2911 helper
.RunPreTestSetup();
2912 helper
.AddData(&data
);
2914 HttpNetworkTransaction
* trans
= helper
.trans();
2916 // Start the transaction with basic parameters.
2917 TestCompletionCallback callback
;
2918 int rv
= trans
->Start(
2919 &CreateGetRequest(), callback
.callback(), BoundNetLog());
2920 EXPECT_EQ(ERR_IO_PENDING
, rv
);
2921 rv
= callback
.WaitForResult();
2924 // Verify that we consumed all test data.
2925 EXPECT_TRUE(data
.AllReadDataConsumed());
2926 EXPECT_TRUE(data
.AllWriteDataConsumed());
2928 // Verify the SYN_REPLY.
2929 HttpResponseInfo response
= *trans
->GetResponseInfo();
2930 EXPECT_TRUE(response
.headers
.get() != NULL
);
2931 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
2934 TEST_P(SpdyNetworkTransactionTest
, ServerPushInvalidAssociatedStreamID9
) {
2935 scoped_ptr
<SpdyFrame
> stream1_syn(
2936 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2937 scoped_ptr
<SpdyFrame
> stream1_body(
2938 spdy_util_
.ConstructSpdyBodyFrame(1, true));
2939 scoped_ptr
<SpdyFrame
> stream2_rst(
2940 spdy_util_
.ConstructSpdyRstStream(2, RST_STREAM_INVALID_STREAM
));
2941 MockWrite writes
[] = {
2942 CreateMockWrite(*stream1_syn
, 0), CreateMockWrite(*stream2_rst
, 3),
2945 scoped_ptr
<SpdyFrame
>
2946 stream1_reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2947 scoped_ptr
<SpdyFrame
> stream2_syn(spdy_util_
.ConstructSpdyPush(
2948 NULL
, 0, 2, 9, GetDefaultUrlWithPath("/foo.dat").c_str()));
2949 MockRead reads
[] = {
2950 CreateMockRead(*stream1_reply
, 1),
2951 CreateMockRead(*stream2_syn
, 2),
2952 CreateMockRead(*stream1_body
, 4),
2953 MockRead(SYNCHRONOUS
, ERR_IO_PENDING
, 5), // Force a pause
2956 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
2957 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
2958 BoundNetLog(), GetParam(), NULL
);
2960 helper
.RunPreTestSetup();
2961 helper
.AddData(&data
);
2963 HttpNetworkTransaction
* trans
= helper
.trans();
2965 // Start the transaction with basic parameters.
2966 TestCompletionCallback callback
;
2967 int rv
= trans
->Start(
2968 &CreateGetRequest(), callback
.callback(), BoundNetLog());
2969 EXPECT_EQ(ERR_IO_PENDING
, rv
);
2970 rv
= callback
.WaitForResult();
2973 // Verify that we consumed all test data.
2974 EXPECT_TRUE(data
.AllReadDataConsumed());
2975 EXPECT_TRUE(data
.AllWriteDataConsumed());
2977 // Verify the SYN_REPLY.
2978 HttpResponseInfo response
= *trans
->GetResponseInfo();
2979 EXPECT_TRUE(response
.headers
.get() != NULL
);
2980 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
2983 TEST_P(SpdyNetworkTransactionTest
, ServerPushNoURL
) {
2984 scoped_ptr
<SpdyFrame
> stream1_syn(
2985 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2986 scoped_ptr
<SpdyFrame
> stream1_body(
2987 spdy_util_
.ConstructSpdyBodyFrame(1, true));
2988 scoped_ptr
<SpdyFrame
> stream2_rst(
2989 spdy_util_
.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR
));
2990 MockWrite writes
[] = {
2991 CreateMockWrite(*stream1_syn
, 0), CreateMockWrite(*stream2_rst
, 3),
2994 scoped_ptr
<SpdyFrame
>
2995 stream1_reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2996 scoped_ptr
<SpdyHeaderBlock
> incomplete_headers(new SpdyHeaderBlock());
2997 (*incomplete_headers
)["hello"] = "bye";
2998 (*incomplete_headers
)[spdy_util_
.GetStatusKey()] = "200 OK";
2999 (*incomplete_headers
)[spdy_util_
.GetVersionKey()] = "HTTP/1.1";
3000 scoped_ptr
<SpdyFrame
> stream2_syn(spdy_util_
.ConstructInitialSpdyPushFrame(
3001 incomplete_headers
.Pass(), 2, 1));
3002 MockRead reads
[] = {
3003 CreateMockRead(*stream1_reply
, 1),
3004 CreateMockRead(*stream2_syn
, 2),
3005 CreateMockRead(*stream1_body
, 4),
3006 MockRead(SYNCHRONOUS
, ERR_IO_PENDING
, 5) // Force a pause
3009 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
3010 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
3011 BoundNetLog(), GetParam(), NULL
);
3013 helper
.RunPreTestSetup();
3014 helper
.AddData(&data
);
3016 HttpNetworkTransaction
* trans
= helper
.trans();
3018 // Start the transaction with basic parameters.
3019 TestCompletionCallback callback
;
3020 int rv
= trans
->Start(
3021 &CreateGetRequest(), callback
.callback(), BoundNetLog());
3022 EXPECT_EQ(ERR_IO_PENDING
, rv
);
3023 rv
= callback
.WaitForResult();
3026 // Verify that we consumed all test data.
3027 EXPECT_TRUE(data
.AllReadDataConsumed());
3028 EXPECT_TRUE(data
.AllWriteDataConsumed());
3030 // Verify the SYN_REPLY.
3031 HttpResponseInfo response
= *trans
->GetResponseInfo();
3032 EXPECT_TRUE(response
.headers
.get() != NULL
);
3033 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
3036 // Verify that various SynReply headers parse correctly through the
3038 TEST_P(SpdyNetworkTransactionTest
, SynReplyHeaders
) {
3039 struct SynReplyHeadersTests
{
3041 const char* extra_headers
[5];
3042 SpdyHeaderBlock expected_headers
;
3044 // This uses a multi-valued cookie header.
3047 "cookie", "val2", // will get appended separated by NULL
3051 // This is the minimalist set of headers.
3055 // Headers with a comma separated list.
3057 { "cookie", "val1,val2",
3063 test_cases
[0].expected_headers
["cookie"] = "val1";
3064 test_cases
[0].expected_headers
["cookie"] += '\0';
3065 test_cases
[0].expected_headers
["cookie"] += "val2";
3066 test_cases
[0].expected_headers
["hello"] = "bye";
3067 test_cases
[0].expected_headers
["status"] = "200";
3069 test_cases
[1].expected_headers
["hello"] = "bye";
3070 test_cases
[1].expected_headers
["status"] = "200";
3072 test_cases
[2].expected_headers
["cookie"] = "val1,val2";
3073 test_cases
[2].expected_headers
["hello"] = "bye";
3074 test_cases
[2].expected_headers
["status"] = "200";
3076 if (spdy_util_
.spdy_version() < HTTP2
) {
3077 // HTTP/2 eliminates use of the :version header.
3078 test_cases
[0].expected_headers
["version"] = "HTTP/1.1";
3079 test_cases
[1].expected_headers
["version"] = "HTTP/1.1";
3080 test_cases
[2].expected_headers
["version"] = "HTTP/1.1";
3083 for (size_t i
= 0; i
< arraysize(test_cases
); ++i
) {
3084 scoped_ptr
<SpdyFrame
> req(
3085 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
3086 MockWrite writes
[] = {CreateMockWrite(*req
, 0)};
3088 scoped_ptr
<SpdyFrame
> resp(
3089 spdy_util_
.ConstructSpdyGetSynReply(test_cases
[i
].extra_headers
,
3090 test_cases
[i
].num_headers
,
3092 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
3093 MockRead reads
[] = {
3094 CreateMockRead(*resp
, 1),
3095 CreateMockRead(*body
, 2),
3096 MockRead(ASYNC
, 0, 3) // EOF
3099 SequencedSocketData
data(reads
, arraysize(reads
), writes
,
3101 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
3102 BoundNetLog(), GetParam(), NULL
);
3103 helper
.RunToCompletion(&data
);
3104 TransactionHelperResult out
= helper
.output();
3106 EXPECT_EQ(OK
, out
.rv
);
3107 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
3108 EXPECT_EQ("hello!", out
.response_data
);
3110 scoped_refptr
<HttpResponseHeaders
> headers
= out
.response_info
.headers
;
3111 EXPECT_TRUE(headers
.get() != NULL
);
3113 std::string name
, value
;
3114 SpdyHeaderBlock header_block
;
3115 while (headers
->EnumerateHeaderLines(&iter
, &name
, &value
)) {
3116 if (header_block
[name
].empty()) {
3117 header_block
[name
] = value
;
3119 header_block
[name
] += '\0';
3120 header_block
[name
] += value
;
3123 EXPECT_EQ(test_cases
[i
].expected_headers
, header_block
);
3127 // Verify that various SynReply headers parse vary fields correctly
3128 // through the HTTP layer, and the response matches the request.
3129 TEST_P(SpdyNetworkTransactionTest
, SynReplyHeadersVary
) {
3130 // Modify the following data to change/add test cases:
3131 struct SynReplyTests
{
3134 const char* extra_headers
[2][16];
3136 // Test the case of a multi-valued cookie. When the value is delimited
3137 // with NUL characters, it needs to be unfolded into multiple headers.
3141 { { "cookie", "val1,val2",
3145 spdy_util_
.GetStatusKey(), "200",
3146 spdy_util_
.GetPathKey(), "/index.php",
3147 spdy_util_
.GetVersionKey(), "HTTP/1.1",
3151 }, { // Multiple vary fields.
3154 { { "friend", "barney",
3155 "enemy", "snaggletooth",
3160 spdy_util_
.GetStatusKey(), "200",
3161 spdy_util_
.GetPathKey(), "/index.php",
3162 spdy_util_
.GetVersionKey(), "HTTP/1.1",
3166 }, { // Test a '*' vary field.
3169 { { "cookie", "val1,val2",
3173 spdy_util_
.GetStatusKey(), "200",
3174 spdy_util_
.GetPathKey(), "/index.php",
3175 spdy_util_
.GetVersionKey(), "HTTP/1.1",
3179 }, { // Multiple comma-separated vary fields.
3182 { { "friend", "barney",
3183 "enemy", "snaggletooth",
3186 { "vary", "friend,enemy",
3187 spdy_util_
.GetStatusKey(), "200",
3188 spdy_util_
.GetPathKey(), "/index.php",
3189 spdy_util_
.GetVersionKey(), "HTTP/1.1",
3196 for (size_t i
= 0; i
< arraysize(test_cases
); ++i
) {
3197 // Construct the request.
3198 scoped_ptr
<SpdyFrame
> frame_req(
3199 spdy_util_
.ConstructSpdyGet(test_cases
[i
].extra_headers
[0],
3200 test_cases
[i
].num_headers
[0],
3201 false, 1, LOWEST
, true));
3203 MockWrite writes
[] = {
3204 CreateMockWrite(*frame_req
, 0),
3207 // Construct the reply.
3208 SpdyHeaderBlock reply_headers
;
3209 AppendToHeaderBlock(test_cases
[i
].extra_headers
[1],
3210 test_cases
[i
].num_headers
[1],
3212 scoped_ptr
<SpdyFrame
> frame_reply(
3213 spdy_util_
.ConstructSpdyReply(1, reply_headers
));
3215 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
3216 MockRead reads
[] = {
3217 CreateMockRead(*frame_reply
, 1),
3218 CreateMockRead(*body
, 2),
3219 MockRead(ASYNC
, 0, 3) // EOF
3222 // Attach the headers to the request.
3223 int header_count
= test_cases
[i
].num_headers
[0];
3225 HttpRequestInfo request
= CreateGetRequest();
3226 for (int ct
= 0; ct
< header_count
; ct
++) {
3227 const char* header_key
= test_cases
[i
].extra_headers
[0][ct
* 2];
3228 const char* header_value
= test_cases
[i
].extra_headers
[0][ct
* 2 + 1];
3229 request
.extra_headers
.SetHeader(header_key
, header_value
);
3232 SequencedSocketData
data(reads
, arraysize(reads
), writes
,
3234 NormalSpdyTransactionHelper
helper(request
, DEFAULT_PRIORITY
,
3235 BoundNetLog(), GetParam(), NULL
);
3236 helper
.RunToCompletion(&data
);
3237 TransactionHelperResult out
= helper
.output();
3239 EXPECT_EQ(OK
, out
.rv
) << i
;
3240 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
) << i
;
3241 EXPECT_EQ("hello!", out
.response_data
) << i
;
3243 // Test the response information.
3244 EXPECT_EQ(out
.response_info
.vary_data
.is_valid(),
3245 test_cases
[i
].vary_matches
) << i
;
3247 // Check the headers.
3248 scoped_refptr
<HttpResponseHeaders
> headers
= out
.response_info
.headers
;
3249 ASSERT_TRUE(headers
.get() != NULL
) << i
;
3251 std::string name
, value
, lines
;
3252 while (headers
->EnumerateHeaderLines(&iter
, &name
, &value
)) {
3255 lines
.append(value
);
3259 // Construct the expected header reply string.
3260 std::string expected_reply
=
3261 spdy_util_
.ConstructSpdyReplyString(reply_headers
);
3262 EXPECT_EQ(expected_reply
, lines
) << i
;
3266 // Verify that we don't crash on invalid SynReply responses.
3267 TEST_P(SpdyNetworkTransactionTest
, InvalidSynReply
) {
3268 struct InvalidSynReplyTests
{
3270 const char* headers
[10];
3272 // SYN_REPLY missing status header
3276 spdy_util_
.GetPathKey(), "/index.php",
3277 spdy_util_
.GetVersionKey(), "HTTP/1.1",
3281 // SYN_REPLY missing version header
3284 spdy_util_
.GetPathKey(), "/index.php",
3288 // SYN_REPLY with no headers
3292 for (size_t i
= 0; i
< arraysize(test_cases
); ++i
) {
3293 scoped_ptr
<SpdyFrame
> req(
3294 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
3295 scoped_ptr
<SpdyFrame
> rst(
3296 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR
));
3297 MockWrite writes
[] = {
3298 CreateMockWrite(*req
, 0), CreateMockWrite(*rst
, 2),
3301 // Construct the reply.
3302 SpdyHeaderBlock reply_headers
;
3303 AppendToHeaderBlock(
3304 test_cases
[i
].headers
, test_cases
[i
].num_headers
, &reply_headers
);
3305 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyReply(1, reply_headers
));
3306 MockRead reads
[] = {
3307 CreateMockRead(*resp
, 1), MockRead(ASYNC
, 0, 3) // EOF
3310 SequencedSocketData
data(reads
, arraysize(reads
), writes
,
3312 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
3313 BoundNetLog(), GetParam(), NULL
);
3314 helper
.RunToCompletion(&data
);
3315 TransactionHelperResult out
= helper
.output();
3316 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR
, out
.rv
);
3320 // Verify that we don't crash on some corrupt frames.
3321 // TODO(jgraettinger): HTTP/2 treats a header decompression failure as a
3322 // connection error. I'd like to backport this behavior to SPDY3 as well.
3323 TEST_P(SpdyNetworkTransactionTest
, CorruptFrameSessionError
) {
3324 if (spdy_util_
.spdy_version() >= HTTP2
) {
3327 // This is the length field that's too short.
3328 scoped_ptr
<SpdyFrame
> syn_reply_wrong_length(
3329 spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
3330 BufferedSpdyFramer
framer(spdy_util_
.spdy_version(), false);
3332 (spdy_util_
.spdy_version() < HTTP2
)
3333 ? syn_reply_wrong_length
->size() - framer
.GetControlFrameHeaderSize()
3334 : syn_reply_wrong_length
->size();
3335 size_t wrong_size
= right_size
- 4;
3336 test::SetFrameLength(syn_reply_wrong_length
.get(),
3338 spdy_util_
.spdy_version());
3340 struct SynReplyTests
{
3341 const SpdyFrame
* syn_reply
;
3343 { syn_reply_wrong_length
.get(), },
3346 for (size_t i
= 0; i
< arraysize(test_cases
); ++i
) {
3347 scoped_ptr
<SpdyFrame
> req(
3348 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
3349 scoped_ptr
<SpdyFrame
> rst(
3350 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR
));
3351 MockWrite writes
[] = {
3352 CreateMockWrite(*req
, 0), CreateMockWrite(*rst
, 3),
3355 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
3356 MockRead reads
[] = {
3357 MockRead(ASYNC
, test_cases
[i
].syn_reply
->data(), wrong_size
, 1),
3358 CreateMockRead(*body
, 2),
3359 MockRead(ASYNC
, 0, 4) // EOF
3362 SequencedSocketData
data(reads
, arraysize(reads
), writes
,
3364 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
3365 BoundNetLog(), GetParam(), NULL
);
3366 helper
.RunToCompletion(&data
);
3367 TransactionHelperResult out
= helper
.output();
3368 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR
, out
.rv
);
3372 // HTTP/2 treats a header decompression failure as a connection-level error.
3373 TEST_P(SpdyNetworkTransactionTest
, CorruptFrameSessionErrorSpdy4
) {
3374 if (spdy_util_
.spdy_version() < HTTP2
) {
3377 // This is the length field that's too short.
3378 scoped_ptr
<SpdyFrame
> syn_reply_wrong_length(
3379 spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
3380 BufferedSpdyFramer
framer(spdy_util_
.spdy_version(), false);
3382 syn_reply_wrong_length
->size() - framer
.GetControlFrameHeaderSize();
3383 size_t wrong_size
= right_size
- 4;
3384 test::SetFrameLength(syn_reply_wrong_length
.get(),
3386 spdy_util_
.spdy_version());
3388 scoped_ptr
<SpdyFrame
> req(
3389 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
3390 scoped_ptr
<SpdyFrame
> goaway(spdy_util_
.ConstructSpdyGoAway(
3391 0, GOAWAY_COMPRESSION_ERROR
, "Framer error: 5 (DECOMPRESS_FAILURE)."));
3392 MockWrite writes
[] = {CreateMockWrite(*req
, 0), CreateMockWrite(*goaway
, 2)};
3394 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
3395 MockRead reads
[] = {
3396 MockRead(ASYNC
, syn_reply_wrong_length
->data(),
3397 syn_reply_wrong_length
->size() - 4, 1),
3400 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
3401 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
3402 BoundNetLog(), GetParam(), NULL
);
3403 helper
.RunToCompletion(&data
);
3404 TransactionHelperResult out
= helper
.output();
3405 EXPECT_EQ(ERR_SPDY_COMPRESSION_ERROR
, out
.rv
);
3408 TEST_P(SpdyNetworkTransactionTest
, GoAwayOnDecompressionFailure
) {
3409 if (GetParam().protocol
< kProtoHTTP2MinimumVersion
) {
3410 // Decompression failures are a stream error in SPDY3 and above.
3413 scoped_ptr
<SpdyFrame
> req(
3414 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
3415 scoped_ptr
<SpdyFrame
> goaway(spdy_util_
.ConstructSpdyGoAway(
3416 0, GOAWAY_COMPRESSION_ERROR
, "Framer error: 5 (DECOMPRESS_FAILURE)."));
3417 MockWrite writes
[] = {CreateMockWrite(*req
, 0), CreateMockWrite(*goaway
, 2)};
3419 // Read HEADERS with corrupted payload.
3420 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
3421 memset(resp
->data() + 12, 0xff, resp
->size() - 12);
3422 MockRead reads
[] = {CreateMockRead(*resp
, 1)};
3424 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
3425 NormalSpdyTransactionHelper
helper(
3426 CreateGetRequest(), DEFAULT_PRIORITY
, BoundNetLog(), GetParam(), NULL
);
3427 helper
.RunToCompletion(&data
);
3428 TransactionHelperResult out
= helper
.output();
3429 EXPECT_EQ(ERR_SPDY_COMPRESSION_ERROR
, out
.rv
);
3432 TEST_P(SpdyNetworkTransactionTest
, GoAwayOnFrameSizeError
) {
3433 scoped_ptr
<SpdyFrame
> req(
3434 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
3435 scoped_ptr
<SpdyFrame
> goaway(spdy_util_
.ConstructSpdyGoAway(
3436 0, GOAWAY_PROTOCOL_ERROR
, "Framer error: 1 (INVALID_CONTROL_FRAME)."));
3437 MockWrite writes
[] = {CreateMockWrite(*req
, 0), CreateMockWrite(*goaway
, 2)};
3439 // Read WINDOW_UPDATE with incorrectly-sized payload.
3440 // TODO(jgraettinger): SpdyFramer signals this as an INVALID_CONTROL_FRAME,
3441 // which is mapped to a protocol error, and not a frame size error.
3442 scoped_ptr
<SpdyFrame
> bad_window_update(
3443 spdy_util_
.ConstructSpdyWindowUpdate(1, 1));
3444 test::SetFrameLength(bad_window_update
.get(),
3445 bad_window_update
->size() - 1,
3446 spdy_util_
.spdy_version());
3447 MockRead reads
[] = {CreateMockRead(*bad_window_update
, 1)};
3449 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
3450 NormalSpdyTransactionHelper
helper(
3451 CreateGetRequest(), DEFAULT_PRIORITY
, BoundNetLog(), GetParam(), NULL
);
3452 helper
.RunToCompletion(&data
);
3453 TransactionHelperResult out
= helper
.output();
3454 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR
, out
.rv
);
3457 // Test that we shutdown correctly on write errors.
3458 TEST_P(SpdyNetworkTransactionTest
, WriteError
) {
3459 scoped_ptr
<SpdyFrame
> req(
3460 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
3461 MockWrite writes
[] = {
3462 // We'll write 10 bytes successfully
3463 MockWrite(ASYNC
, req
->data(), 10, 0),
3464 // Followed by ERROR!
3465 MockWrite(ASYNC
, ERR_FAILED
, 1),
3466 // Session drains and attempts to write a GOAWAY: Another ERROR!
3467 MockWrite(ASYNC
, ERR_FAILED
, 2),
3470 MockRead reads
[] = {
3471 MockRead(ASYNC
, 0, 3) // EOF
3474 DeterministicSocketData
data(reads
, arraysize(reads
),
3475 writes
, arraysize(writes
));
3477 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
3478 BoundNetLog(), GetParam(), NULL
);
3479 helper
.SetDeterministic();
3480 helper
.RunPreTestSetup();
3481 helper
.AddDeterministicData(&data
);
3482 EXPECT_TRUE(helper
.StartDefaultTest());
3484 helper
.FinishDefaultTest();
3485 EXPECT_TRUE(data
.AllWriteDataConsumed());
3486 EXPECT_TRUE(!data
.AllReadDataConsumed());
3487 TransactionHelperResult out
= helper
.output();
3488 EXPECT_EQ(ERR_FAILED
, out
.rv
);
3491 // Test that partial writes work.
3492 TEST_P(SpdyNetworkTransactionTest
, PartialWrite
) {
3493 // Chop the SYN_STREAM frame into 5 chunks.
3494 scoped_ptr
<SpdyFrame
> req(
3495 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
3496 const int kChunks
= 5;
3497 scoped_ptr
<MockWrite
[]> writes(ChopWriteFrame(*req
.get(), kChunks
));
3498 for (int i
= 0; i
< kChunks
; ++i
) {
3499 writes
[i
].sequence_number
= i
;
3502 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
3503 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
3504 MockRead reads
[] = {
3505 CreateMockRead(*resp
, kChunks
),
3506 CreateMockRead(*body
, kChunks
+ 1),
3507 MockRead(ASYNC
, 0, kChunks
+ 2) // EOF
3510 SequencedSocketData
data(reads
, arraysize(reads
), writes
.get(), kChunks
);
3511 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
3512 BoundNetLog(), GetParam(), NULL
);
3513 helper
.RunToCompletion(&data
);
3514 TransactionHelperResult out
= helper
.output();
3515 EXPECT_EQ(OK
, out
.rv
);
3516 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
3517 EXPECT_EQ("hello!", out
.response_data
);
3520 // In this test, we enable compression, but get a uncompressed SynReply from
3521 // the server. Verify that teardown is all clean.
3522 TEST_P(SpdyNetworkTransactionTest
, DecompressFailureOnSynReply
) {
3523 if (spdy_util_
.spdy_version() >= HTTP2
) {
3524 // HPACK doesn't use deflate compression.
3527 scoped_ptr
<SpdyFrame
> compressed(
3528 spdy_util_
.ConstructSpdyGet(NULL
, 0, true, 1, LOWEST
, true));
3529 scoped_ptr
<SpdyFrame
> goaway(spdy_util_
.ConstructSpdyGoAway(
3530 0, GOAWAY_COMPRESSION_ERROR
, "Framer error: 5 (DECOMPRESS_FAILURE)."));
3531 MockWrite writes
[] = {CreateMockWrite(*compressed
, 0),
3532 CreateMockWrite(*goaway
, 2)};
3534 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
3535 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
3536 MockRead reads
[] = {
3537 CreateMockRead(*resp
, 1),
3540 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
3541 SpdySessionDependencies
* session_deps
=
3542 CreateSpdySessionDependencies(GetParam());
3543 session_deps
->enable_compression
= true;
3544 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
3545 BoundNetLog(), GetParam(), session_deps
);
3546 helper
.RunToCompletion(&data
);
3547 TransactionHelperResult out
= helper
.output();
3548 EXPECT_EQ(ERR_SPDY_COMPRESSION_ERROR
, out
.rv
);
3552 // Test that the NetLog contains good data for a simple GET request.
3553 TEST_P(SpdyNetworkTransactionTest
, NetLog
) {
3554 static const char* const kExtraHeaders
[] = {
3555 "user-agent", "Chrome",
3557 scoped_ptr
<SpdyFrame
> req(
3558 spdy_util_
.ConstructSpdyGet(kExtraHeaders
, 1, false, 1, LOWEST
, true));
3559 MockWrite writes
[] = {CreateMockWrite(*req
, 0)};
3561 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
3562 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
3563 MockRead reads
[] = {
3564 CreateMockRead(*resp
, 1),
3565 CreateMockRead(*body
, 2),
3566 MockRead(ASYNC
, 0, 3) // EOF
3569 BoundTestNetLog log
;
3571 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
3572 NormalSpdyTransactionHelper
helper(CreateGetRequestWithUserAgent(),
3574 log
.bound(), GetParam(), NULL
);
3575 helper
.RunToCompletion(&data
);
3576 TransactionHelperResult out
= helper
.output();
3577 EXPECT_EQ(OK
, out
.rv
);
3578 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
3579 EXPECT_EQ("hello!", out
.response_data
);
3581 // Check that the NetLog was filled reasonably.
3582 // This test is intentionally non-specific about the exact ordering of the
3583 // log; instead we just check to make sure that certain events exist, and that
3584 // they are in the right order.
3585 TestNetLogEntry::List entries
;
3586 log
.GetEntries(&entries
);
3588 EXPECT_LT(0u, entries
.size());
3590 pos
= ExpectLogContainsSomewhere(entries
, 0,
3591 NetLog::TYPE_HTTP_TRANSACTION_SEND_REQUEST
,
3592 NetLog::PHASE_BEGIN
);
3593 pos
= ExpectLogContainsSomewhere(entries
, pos
+ 1,
3594 NetLog::TYPE_HTTP_TRANSACTION_SEND_REQUEST
,
3596 pos
= ExpectLogContainsSomewhere(entries
, pos
+ 1,
3597 NetLog::TYPE_HTTP_TRANSACTION_READ_HEADERS
,
3598 NetLog::PHASE_BEGIN
);
3599 pos
= ExpectLogContainsSomewhere(entries
, pos
+ 1,
3600 NetLog::TYPE_HTTP_TRANSACTION_READ_HEADERS
,
3602 pos
= ExpectLogContainsSomewhere(entries
, pos
+ 1,
3603 NetLog::TYPE_HTTP_TRANSACTION_READ_BODY
,
3604 NetLog::PHASE_BEGIN
);
3605 pos
= ExpectLogContainsSomewhere(entries
, pos
+ 1,
3606 NetLog::TYPE_HTTP_TRANSACTION_READ_BODY
,
3609 // Check that we logged all the headers correctly
3610 const NetLog::EventType type
= (GetParam().protocol
<= kProtoSPDY31
)
3611 ? NetLog::TYPE_HTTP2_SESSION_SYN_STREAM
3612 : NetLog::TYPE_HTTP2_SESSION_SEND_HEADERS
;
3613 pos
= ExpectLogContainsSomewhere(entries
, 0, type
, NetLog::PHASE_NONE
);
3615 base::ListValue
* header_list
;
3616 ASSERT_TRUE(entries
[pos
].params
.get());
3617 ASSERT_TRUE(entries
[pos
].params
->GetList("headers", &header_list
));
3619 std::vector
<std::string
> expected
;
3620 expected
.push_back(std::string(spdy_util_
.GetHostKey()) +
3621 ": www.example.org");
3622 expected
.push_back(std::string(spdy_util_
.GetPathKey()) + ": /");
3623 expected
.push_back(std::string(spdy_util_
.GetSchemeKey()) + ": " +
3624 spdy_util_
.default_url().scheme());
3625 expected
.push_back(std::string(spdy_util_
.GetMethodKey()) + ": GET");
3626 expected
.push_back("user-agent: Chrome");
3627 if (spdy_util_
.spdy_version() < HTTP2
) {
3628 // HTTP/2 eliminates use of the :version header.
3629 expected
.push_back(std::string(spdy_util_
.GetVersionKey()) + ": HTTP/1.1");
3631 EXPECT_EQ(expected
.size(), header_list
->GetSize());
3632 for (std::vector
<std::string
>::const_iterator it
= expected
.begin();
3633 it
!= expected
.end();
3635 base::StringValue
header(*it
);
3636 EXPECT_NE(header_list
->end(), header_list
->Find(header
)) <<
3637 "Header not found: " << *it
;
3641 // Since we buffer the IO from the stream to the renderer, this test verifies
3642 // that when we read out the maximum amount of data (e.g. we received 50 bytes
3643 // on the network, but issued a Read for only 5 of those bytes) that the data
3644 // flow still works correctly.
3645 TEST_P(SpdyNetworkTransactionTest
, BufferFull
) {
3646 BufferedSpdyFramer
framer(spdy_util_
.spdy_version(), false);
3648 scoped_ptr
<SpdyFrame
> req(
3649 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
3650 MockWrite writes
[] = {CreateMockWrite(*req
, 0)};
3652 // 2 data frames in a single read.
3653 scoped_ptr
<SpdyFrame
> data_frame_1(
3654 framer
.CreateDataFrame(1, "goodby", 6, DATA_FLAG_NONE
));
3655 scoped_ptr
<SpdyFrame
> data_frame_2(
3656 framer
.CreateDataFrame(1, "e worl", 6, DATA_FLAG_NONE
));
3657 const SpdyFrame
* data_frames
[2] = {
3661 char combined_data_frames
[100];
3662 int combined_data_frames_len
=
3663 CombineFrames(data_frames
, arraysize(data_frames
),
3664 combined_data_frames
, arraysize(combined_data_frames
));
3665 scoped_ptr
<SpdyFrame
> last_frame(
3666 framer
.CreateDataFrame(1, "d", 1, DATA_FLAG_FIN
));
3668 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
3669 MockRead reads
[] = {
3670 CreateMockRead(*resp
, 1),
3671 MockRead(ASYNC
, ERR_IO_PENDING
, 2), // Force a pause
3672 MockRead(ASYNC
, combined_data_frames
, combined_data_frames_len
, 3),
3673 MockRead(ASYNC
, ERR_IO_PENDING
, 4), // Force a pause
3674 CreateMockRead(*last_frame
, 5),
3675 MockRead(ASYNC
, 0, 6) // EOF
3678 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
3680 TestCompletionCallback callback
;
3682 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
3683 BoundNetLog(), GetParam(), NULL
);
3684 helper
.RunPreTestSetup();
3685 helper
.AddData(&data
);
3686 HttpNetworkTransaction
* trans
= helper
.trans();
3687 int rv
= trans
->Start(
3688 &CreateGetRequest(), callback
.callback(), BoundNetLog());
3689 EXPECT_EQ(ERR_IO_PENDING
, rv
);
3691 TransactionHelperResult out
= helper
.output();
3692 out
.rv
= callback
.WaitForResult();
3693 EXPECT_EQ(out
.rv
, OK
);
3695 const HttpResponseInfo
* response
= trans
->GetResponseInfo();
3696 EXPECT_TRUE(response
->headers
.get() != NULL
);
3697 EXPECT_TRUE(response
->was_fetched_via_spdy
);
3698 out
.status_line
= response
->headers
->GetStatusLine();
3699 out
.response_info
= *response
; // Make a copy so we can verify.
3702 TestCompletionCallback read_callback
;
3704 std::string content
;
3706 // Read small chunks at a time.
3707 const int kSmallReadSize
= 3;
3708 scoped_refptr
<IOBuffer
> buf(new IOBuffer(kSmallReadSize
));
3709 rv
= trans
->Read(buf
.get(), kSmallReadSize
, read_callback
.callback());
3710 if (rv
== ERR_IO_PENDING
) {
3711 data
.CompleteRead();
3712 rv
= read_callback
.WaitForResult();
3715 content
.append(buf
->data(), rv
);
3716 } else if (rv
< 0) {
3721 out
.response_data
.swap(content
);
3723 // Flush the MessageLoop while the SpdySessionDependencies (in particular, the
3724 // MockClientSocketFactory) are still alive.
3725 base::RunLoop().RunUntilIdle();
3727 // Verify that we consumed all test data.
3728 helper
.VerifyDataConsumed();
3730 EXPECT_EQ(OK
, out
.rv
);
3731 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
3732 EXPECT_EQ("goodbye world", out
.response_data
);
3735 // Verify that basic buffering works; when multiple data frames arrive
3736 // at the same time, ensure that we don't notify a read completion for
3737 // each data frame individually.
3738 TEST_P(SpdyNetworkTransactionTest
, Buffering
) {
3739 BufferedSpdyFramer
framer(spdy_util_
.spdy_version(), false);
3741 scoped_ptr
<SpdyFrame
> req(
3742 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
3743 MockWrite writes
[] = {CreateMockWrite(*req
, 0)};
3745 // 4 data frames in a single read.
3746 scoped_ptr
<SpdyFrame
> data_frame(
3747 framer
.CreateDataFrame(1, "message", 7, DATA_FLAG_NONE
));
3748 scoped_ptr
<SpdyFrame
> data_frame_fin(
3749 framer
.CreateDataFrame(1, "message", 7, DATA_FLAG_FIN
));
3750 const SpdyFrame
* data_frames
[4] = {
3754 data_frame_fin
.get()
3756 char combined_data_frames
[100];
3757 int combined_data_frames_len
=
3758 CombineFrames(data_frames
, arraysize(data_frames
),
3759 combined_data_frames
, arraysize(combined_data_frames
));
3761 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
3762 MockRead reads
[] = {
3763 CreateMockRead(*resp
, 1),
3764 MockRead(ASYNC
, ERR_IO_PENDING
, 2), // Force a pause
3765 MockRead(ASYNC
, combined_data_frames
, combined_data_frames_len
, 3),
3766 MockRead(ASYNC
, 0, 4) // EOF
3769 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
3771 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
3772 BoundNetLog(), GetParam(), NULL
);
3773 helper
.RunPreTestSetup();
3774 helper
.AddData(&data
);
3775 HttpNetworkTransaction
* trans
= helper
.trans();
3777 TestCompletionCallback callback
;
3778 int rv
= trans
->Start(
3779 &CreateGetRequest(), callback
.callback(), BoundNetLog());
3780 EXPECT_EQ(ERR_IO_PENDING
, rv
);
3782 TransactionHelperResult out
= helper
.output();
3783 out
.rv
= callback
.WaitForResult();
3784 EXPECT_EQ(out
.rv
, OK
);
3786 const HttpResponseInfo
* response
= trans
->GetResponseInfo();
3787 EXPECT_TRUE(response
->headers
.get() != NULL
);
3788 EXPECT_TRUE(response
->was_fetched_via_spdy
);
3789 out
.status_line
= response
->headers
->GetStatusLine();
3790 out
.response_info
= *response
; // Make a copy so we can verify.
3793 TestCompletionCallback read_callback
;
3795 std::string content
;
3796 int reads_completed
= 0;
3798 // Read small chunks at a time.
3799 const int kSmallReadSize
= 14;
3800 scoped_refptr
<IOBuffer
> buf(new IOBuffer(kSmallReadSize
));
3801 rv
= trans
->Read(buf
.get(), kSmallReadSize
, read_callback
.callback());
3802 if (rv
== ERR_IO_PENDING
) {
3803 data
.CompleteRead();
3804 rv
= read_callback
.WaitForResult();
3807 EXPECT_EQ(kSmallReadSize
, rv
);
3808 content
.append(buf
->data(), rv
);
3809 } else if (rv
< 0) {
3810 FAIL() << "Unexpected read error: " << rv
;
3815 EXPECT_EQ(3, reads_completed
); // Reads are: 14 bytes, 14 bytes, 0 bytes.
3817 out
.response_data
.swap(content
);
3819 // Flush the MessageLoop while the SpdySessionDependencies (in particular, the
3820 // MockClientSocketFactory) are still alive.
3821 base::RunLoop().RunUntilIdle();
3823 // Verify that we consumed all test data.
3824 helper
.VerifyDataConsumed();
3826 EXPECT_EQ(OK
, out
.rv
);
3827 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
3828 EXPECT_EQ("messagemessagemessagemessage", out
.response_data
);
3831 // Verify the case where we buffer data but read it after it has been buffered.
3832 TEST_P(SpdyNetworkTransactionTest
, BufferedAll
) {
3833 BufferedSpdyFramer
framer(spdy_util_
.spdy_version(), false);
3835 scoped_ptr
<SpdyFrame
> req(
3836 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
3837 MockWrite writes
[] = {CreateMockWrite(*req
, 0)};
3839 // 5 data frames in a single read.
3840 scoped_ptr
<SpdyFrame
> reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
3841 scoped_ptr
<SpdyFrame
> data_frame(
3842 framer
.CreateDataFrame(1, "message", 7, DATA_FLAG_NONE
));
3843 scoped_ptr
<SpdyFrame
> data_frame_fin(
3844 framer
.CreateDataFrame(1, "message", 7, DATA_FLAG_FIN
));
3845 const SpdyFrame
* frames
[5] = {reply
.get(), data_frame
.get(), data_frame
.get(),
3846 data_frame
.get(), data_frame_fin
.get()};
3847 char combined_frames
[200];
3848 int combined_frames_len
=
3849 CombineFrames(frames
, arraysize(frames
),
3850 combined_frames
, arraysize(combined_frames
));
3852 MockRead reads
[] = {
3853 MockRead(ASYNC
, combined_frames
, combined_frames_len
, 1),
3854 MockRead(ASYNC
, 0, 2) // EOF
3857 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
3859 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
3860 BoundNetLog(), GetParam(), NULL
);
3861 helper
.RunPreTestSetup();
3862 helper
.AddData(&data
);
3863 HttpNetworkTransaction
* trans
= helper
.trans();
3865 TestCompletionCallback callback
;
3866 int rv
= trans
->Start(
3867 &CreateGetRequest(), callback
.callback(), BoundNetLog());
3868 EXPECT_EQ(ERR_IO_PENDING
, rv
);
3870 TransactionHelperResult out
= helper
.output();
3871 out
.rv
= callback
.WaitForResult();
3872 EXPECT_EQ(out
.rv
, OK
);
3874 const HttpResponseInfo
* response
= trans
->GetResponseInfo();
3875 EXPECT_TRUE(response
->headers
.get() != NULL
);
3876 EXPECT_TRUE(response
->was_fetched_via_spdy
);
3877 out
.status_line
= response
->headers
->GetStatusLine();
3878 out
.response_info
= *response
; // Make a copy so we can verify.
3881 TestCompletionCallback read_callback
;
3883 std::string content
;
3884 int reads_completed
= 0;
3886 // Read small chunks at a time.
3887 const int kSmallReadSize
= 14;
3888 scoped_refptr
<IOBuffer
> buf(new IOBuffer(kSmallReadSize
));
3889 rv
= trans
->Read(buf
.get(), kSmallReadSize
, read_callback
.callback());
3891 EXPECT_EQ(kSmallReadSize
, rv
);
3892 content
.append(buf
->data(), rv
);
3893 } else if (rv
< 0) {
3894 FAIL() << "Unexpected read error: " << rv
;
3899 EXPECT_EQ(3, reads_completed
);
3901 out
.response_data
.swap(content
);
3903 // Flush the MessageLoop while the SpdySessionDependencies (in particular, the
3904 // MockClientSocketFactory) are still alive.
3905 base::RunLoop().RunUntilIdle();
3907 // Verify that we consumed all test data.
3908 helper
.VerifyDataConsumed();
3910 EXPECT_EQ(OK
, out
.rv
);
3911 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
3912 EXPECT_EQ("messagemessagemessagemessage", out
.response_data
);
3915 // Verify the case where we buffer data and close the connection.
3916 TEST_P(SpdyNetworkTransactionTest
, BufferedClosed
) {
3917 BufferedSpdyFramer
framer(spdy_util_
.spdy_version(), false);
3919 scoped_ptr
<SpdyFrame
> req(
3920 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
3921 MockWrite writes
[] = {CreateMockWrite(*req
, 0)};
3923 // All data frames in a single read.
3924 // NOTE: We don't FIN the stream.
3925 scoped_ptr
<SpdyFrame
> data_frame(
3926 framer
.CreateDataFrame(1, "message", 7, DATA_FLAG_NONE
));
3927 const SpdyFrame
* data_frames
[4] = {
3933 char combined_data_frames
[100];
3934 int combined_data_frames_len
=
3935 CombineFrames(data_frames
, arraysize(data_frames
),
3936 combined_data_frames
, arraysize(combined_data_frames
));
3937 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
3938 MockRead reads
[] = {
3939 CreateMockRead(*resp
, 1),
3940 MockRead(ASYNC
, ERR_IO_PENDING
, 2), // Force a wait
3941 MockRead(ASYNC
, combined_data_frames
, combined_data_frames_len
, 3),
3942 MockRead(ASYNC
, 0, 4) // EOF
3945 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
3947 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
3948 BoundNetLog(), GetParam(), NULL
);
3949 helper
.RunPreTestSetup();
3950 helper
.AddData(&data
);
3951 HttpNetworkTransaction
* trans
= helper
.trans();
3953 TestCompletionCallback callback
;
3955 int rv
= trans
->Start(
3956 &CreateGetRequest(), callback
.callback(), BoundNetLog());
3957 EXPECT_EQ(ERR_IO_PENDING
, rv
);
3959 TransactionHelperResult out
= helper
.output();
3960 out
.rv
= callback
.WaitForResult();
3961 EXPECT_EQ(out
.rv
, OK
);
3963 const HttpResponseInfo
* response
= trans
->GetResponseInfo();
3964 EXPECT_TRUE(response
->headers
.get() != NULL
);
3965 EXPECT_TRUE(response
->was_fetched_via_spdy
);
3966 out
.status_line
= response
->headers
->GetStatusLine();
3967 out
.response_info
= *response
; // Make a copy so we can verify.
3970 TestCompletionCallback read_callback
;
3972 std::string content
;
3973 int reads_completed
= 0;
3975 // Read small chunks at a time.
3976 const int kSmallReadSize
= 14;
3977 scoped_refptr
<IOBuffer
> buf(new IOBuffer(kSmallReadSize
));
3978 rv
= trans
->Read(buf
.get(), kSmallReadSize
, read_callback
.callback());
3979 if (rv
== ERR_IO_PENDING
) {
3980 data
.CompleteRead();
3981 rv
= read_callback
.WaitForResult();
3984 content
.append(buf
->data(), rv
);
3985 } else if (rv
< 0) {
3986 // This test intentionally closes the connection, and will get an error.
3987 EXPECT_EQ(ERR_CONNECTION_CLOSED
, rv
);
3993 EXPECT_EQ(0, reads_completed
);
3995 out
.response_data
.swap(content
);
3997 // Flush the MessageLoop while the SpdySessionDependencies (in particular, the
3998 // MockClientSocketFactory) are still alive.
3999 base::RunLoop().RunUntilIdle();
4001 // Verify that we consumed all test data.
4002 helper
.VerifyDataConsumed();
4005 // Verify the case where we buffer data and cancel the transaction.
4006 TEST_P(SpdyNetworkTransactionTest
, BufferedCancelled
) {
4007 BufferedSpdyFramer
framer(spdy_util_
.spdy_version(), false);
4009 scoped_ptr
<SpdyFrame
> req(
4010 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
4011 scoped_ptr
<SpdyFrame
> rst(
4012 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_CANCEL
));
4013 MockWrite writes
[] = {CreateMockWrite(*req
, 0), CreateMockWrite(*rst
, 4)};
4015 // NOTE: We don't FIN the stream.
4016 scoped_ptr
<SpdyFrame
> data_frame(
4017 framer
.CreateDataFrame(1, "message", 7, DATA_FLAG_NONE
));
4019 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
4020 MockRead reads
[] = {
4021 CreateMockRead(*resp
, 1),
4022 MockRead(ASYNC
, ERR_IO_PENDING
, 2), // Force a wait
4023 CreateMockRead(*data_frame
, 3),
4024 MockRead(ASYNC
, 0, 5) // EOF
4027 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
4029 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
4030 BoundNetLog(), GetParam(), NULL
);
4031 helper
.RunPreTestSetup();
4032 helper
.AddData(&data
);
4033 HttpNetworkTransaction
* trans
= helper
.trans();
4034 TestCompletionCallback callback
;
4036 int rv
= trans
->Start(
4037 &CreateGetRequest(), callback
.callback(), BoundNetLog());
4038 EXPECT_EQ(ERR_IO_PENDING
, rv
);
4040 TransactionHelperResult out
= helper
.output();
4041 out
.rv
= callback
.WaitForResult();
4042 EXPECT_EQ(out
.rv
, OK
);
4044 const HttpResponseInfo
* response
= trans
->GetResponseInfo();
4045 EXPECT_TRUE(response
->headers
.get() != NULL
);
4046 EXPECT_TRUE(response
->was_fetched_via_spdy
);
4047 out
.status_line
= response
->headers
->GetStatusLine();
4048 out
.response_info
= *response
; // Make a copy so we can verify.
4051 TestCompletionCallback read_callback
;
4053 const int kReadSize
= 256;
4054 scoped_refptr
<IOBuffer
> buf(new IOBuffer(kReadSize
));
4055 rv
= trans
->Read(buf
.get(), kReadSize
, read_callback
.callback());
4056 ASSERT_EQ(ERR_IO_PENDING
, rv
) << "Unexpected read: " << rv
;
4058 // Complete the read now, which causes buffering to start.
4059 data
.CompleteRead();
4060 // Destroy the transaction, causing the stream to get cancelled
4061 // and orphaning the buffered IO task.
4062 helper
.ResetTrans();
4064 // Flush the MessageLoop; this will cause the buffered IO task
4065 // to run for the final time.
4066 base::RunLoop().RunUntilIdle();
4068 // Verify that we consumed all test data.
4069 helper
.VerifyDataConsumed();
4072 // Test that if the server requests persistence of settings, that we save
4073 // the settings in the HttpServerProperties.
4074 TEST_P(SpdyNetworkTransactionTest
, SettingsSaved
) {
4075 if (spdy_util_
.spdy_version() >= HTTP2
) {
4076 // HTTP/2 doesn't support settings persistence.
4079 static const SpdyHeaderInfo kSynReplyInfo
= {
4080 SYN_REPLY
, // Syn Reply
4082 0, // Associated Stream ID
4083 ConvertRequestPriorityToSpdyPriority(
4084 LOWEST
, spdy_util_
.spdy_version()),
4085 kSpdyCredentialSlotUnused
,
4086 CONTROL_FLAG_NONE
, // Control Flags
4087 false, // Compressed
4088 RST_STREAM_INVALID
, // Status
4091 DATA_FLAG_NONE
// Data Flags
4094 BoundNetLog net_log
;
4095 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
4096 net_log
, GetParam(), NULL
);
4097 helper
.RunPreTestSetup();
4099 // Verify that no settings exist initially.
4100 HostPortPair
host_port_pair("www.example.org", helper
.port());
4101 SpdySessionPool
* spdy_session_pool
= helper
.session()->spdy_session_pool();
4102 EXPECT_TRUE(spdy_session_pool
->http_server_properties()->GetSpdySettings(
4103 host_port_pair
).empty());
4105 // Construct the request.
4106 scoped_ptr
<SpdyFrame
> req(
4107 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
4108 MockWrite writes
[] = {CreateMockWrite(*req
, 0)};
4110 // Construct the reply.
4111 scoped_ptr
<SpdyHeaderBlock
> reply_headers(new SpdyHeaderBlock());
4112 (*reply_headers
)[spdy_util_
.GetStatusKey()] = "200";
4113 (*reply_headers
)[spdy_util_
.GetVersionKey()] = "HTTP/1.1";
4114 scoped_ptr
<SpdyFrame
> reply(
4115 spdy_util_
.ConstructSpdyFrame(kSynReplyInfo
, reply_headers
.Pass()));
4117 const SpdySettingsIds kSampleId1
= SETTINGS_UPLOAD_BANDWIDTH
;
4118 unsigned int kSampleValue1
= 0x0a0a0a0a;
4119 const SpdySettingsIds kSampleId2
= SETTINGS_DOWNLOAD_BANDWIDTH
;
4120 unsigned int kSampleValue2
= 0x0b0b0b0b;
4121 const SpdySettingsIds kSampleId3
= SETTINGS_ROUND_TRIP_TIME
;
4122 unsigned int kSampleValue3
= 0x0c0c0c0c;
4123 scoped_ptr
<SpdyFrame
> settings_frame
;
4125 // Construct the SETTINGS frame.
4126 SettingsMap settings
;
4127 // First add a persisted setting.
4128 settings
[kSampleId1
] =
4129 SettingsFlagsAndValue(SETTINGS_FLAG_PLEASE_PERSIST
, kSampleValue1
);
4130 // Next add a non-persisted setting.
4131 settings
[kSampleId2
] =
4132 SettingsFlagsAndValue(SETTINGS_FLAG_NONE
, kSampleValue2
);
4133 // Next add another persisted setting.
4134 settings
[kSampleId3
] =
4135 SettingsFlagsAndValue(SETTINGS_FLAG_PLEASE_PERSIST
, kSampleValue3
);
4136 settings_frame
.reset(spdy_util_
.ConstructSpdySettings(settings
));
4139 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
4140 MockRead reads
[] = {
4141 CreateMockRead(*reply
, 1),
4142 CreateMockRead(*body
, 2),
4143 CreateMockRead(*settings_frame
, 3),
4144 MockRead(ASYNC
, 0, 4) // EOF
4147 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
4148 helper
.AddData(&data
);
4149 helper
.RunDefaultTest();
4150 helper
.VerifyDataConsumed();
4151 TransactionHelperResult out
= helper
.output();
4152 EXPECT_EQ(OK
, out
.rv
);
4153 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
4154 EXPECT_EQ("hello!", out
.response_data
);
4157 // Verify we had two persisted settings.
4158 const SettingsMap
& settings_map
=
4159 spdy_session_pool
->http_server_properties()->GetSpdySettings(
4161 ASSERT_EQ(2u, settings_map
.size());
4163 // Verify the first persisted setting.
4164 SettingsMap::const_iterator it1
= settings_map
.find(kSampleId1
);
4165 EXPECT_TRUE(it1
!= settings_map
.end());
4166 SettingsFlagsAndValue flags_and_value1
= it1
->second
;
4167 EXPECT_EQ(SETTINGS_FLAG_PERSISTED
, flags_and_value1
.first
);
4168 EXPECT_EQ(kSampleValue1
, flags_and_value1
.second
);
4170 // Verify the second persisted setting.
4171 SettingsMap::const_iterator it3
= settings_map
.find(kSampleId3
);
4172 EXPECT_TRUE(it3
!= settings_map
.end());
4173 SettingsFlagsAndValue flags_and_value3
= it3
->second
;
4174 EXPECT_EQ(SETTINGS_FLAG_PERSISTED
, flags_and_value3
.first
);
4175 EXPECT_EQ(kSampleValue3
, flags_and_value3
.second
);
4179 // Test that when there are settings saved that they are sent back to the
4180 // server upon session establishment.
4181 TEST_P(SpdyNetworkTransactionTest
, SettingsPlayback
) {
4182 if (spdy_util_
.spdy_version() >= HTTP2
) {
4183 // HTTP/2 doesn't support settings persistence.
4186 static const SpdyHeaderInfo kSynReplyInfo
= {
4187 SYN_REPLY
, // Syn Reply
4189 0, // Associated Stream ID
4190 ConvertRequestPriorityToSpdyPriority(
4191 LOWEST
, spdy_util_
.spdy_version()),
4192 kSpdyCredentialSlotUnused
,
4193 CONTROL_FLAG_NONE
, // Control Flags
4194 false, // Compressed
4195 RST_STREAM_INVALID
, // Status
4198 DATA_FLAG_NONE
// Data Flags
4201 BoundNetLog net_log
;
4202 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
4203 net_log
, GetParam(), NULL
);
4204 helper
.RunPreTestSetup();
4206 SpdySessionPool
* spdy_session_pool
= helper
.session()->spdy_session_pool();
4208 SpdySessionPoolPeer
pool_peer(spdy_session_pool
);
4209 pool_peer
.SetEnableSendingInitialData(true);
4211 // Verify that no settings exist initially.
4212 HostPortPair
host_port_pair("www.example.org", helper
.port());
4213 EXPECT_TRUE(spdy_session_pool
->http_server_properties()->GetSpdySettings(
4214 host_port_pair
).empty());
4216 const SpdySettingsIds kSampleId1
= SETTINGS_MAX_CONCURRENT_STREAMS
;
4217 unsigned int kSampleValue1
= 0x0a0a0a0a;
4218 const SpdySettingsIds kSampleId2
= SETTINGS_INITIAL_WINDOW_SIZE
;
4219 unsigned int kSampleValue2
= 0x0c0c0c0c;
4221 // First add a persisted setting.
4222 spdy_session_pool
->http_server_properties()->SetSpdySetting(
4225 SETTINGS_FLAG_PLEASE_PERSIST
,
4228 // Next add another persisted setting.
4229 spdy_session_pool
->http_server_properties()->SetSpdySetting(
4232 SETTINGS_FLAG_PLEASE_PERSIST
,
4235 EXPECT_EQ(2u, spdy_session_pool
->http_server_properties()->GetSpdySettings(
4236 host_port_pair
).size());
4238 // Construct the initial SETTINGS frame.
4239 SettingsMap initial_settings
;
4240 initial_settings
[SETTINGS_MAX_CONCURRENT_STREAMS
] =
4241 SettingsFlagsAndValue(SETTINGS_FLAG_NONE
, kMaxConcurrentPushedStreams
);
4242 scoped_ptr
<SpdyFrame
> initial_settings_frame(
4243 spdy_util_
.ConstructSpdySettings(initial_settings
));
4245 // Construct the persisted SETTINGS frame.
4246 const SettingsMap
& settings
=
4247 spdy_session_pool
->http_server_properties()->GetSpdySettings(
4249 scoped_ptr
<SpdyFrame
> settings_frame(
4250 spdy_util_
.ConstructSpdySettings(settings
));
4252 // Construct the request.
4253 scoped_ptr
<SpdyFrame
> req(
4254 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
4256 MockWrite writes
[] = {
4257 CreateMockWrite(*initial_settings_frame
, 0),
4258 CreateMockWrite(*settings_frame
, 1),
4259 CreateMockWrite(*req
, 2),
4262 // Construct the reply.
4263 scoped_ptr
<SpdyHeaderBlock
> reply_headers(new SpdyHeaderBlock());
4264 (*reply_headers
)[spdy_util_
.GetStatusKey()] = "200";
4265 (*reply_headers
)[spdy_util_
.GetVersionKey()] = "HTTP/1.1";
4266 scoped_ptr
<SpdyFrame
> reply(
4267 spdy_util_
.ConstructSpdyFrame(kSynReplyInfo
, reply_headers
.Pass()));
4269 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
4270 MockRead reads
[] = {
4271 CreateMockRead(*reply
, 3),
4272 CreateMockRead(*body
, 4),
4273 MockRead(ASYNC
, 0, 5) // EOF
4276 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
4277 helper
.AddData(&data
);
4278 helper
.RunDefaultTest();
4279 helper
.VerifyDataConsumed();
4280 TransactionHelperResult out
= helper
.output();
4281 EXPECT_EQ(OK
, out
.rv
);
4282 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
4283 EXPECT_EQ("hello!", out
.response_data
);
4286 // Verify we had two persisted settings.
4287 const SettingsMap
& settings_map
=
4288 spdy_session_pool
->http_server_properties()->GetSpdySettings(
4290 ASSERT_EQ(2u, settings_map
.size());
4292 // Verify the first persisted setting.
4293 SettingsMap::const_iterator it1
= settings_map
.find(kSampleId1
);
4294 EXPECT_TRUE(it1
!= settings_map
.end());
4295 SettingsFlagsAndValue flags_and_value1
= it1
->second
;
4296 EXPECT_EQ(SETTINGS_FLAG_PERSISTED
, flags_and_value1
.first
);
4297 EXPECT_EQ(kSampleValue1
, flags_and_value1
.second
);
4299 // Verify the second persisted setting.
4300 SettingsMap::const_iterator it2
= settings_map
.find(kSampleId2
);
4301 EXPECT_TRUE(it2
!= settings_map
.end());
4302 SettingsFlagsAndValue flags_and_value2
= it2
->second
;
4303 EXPECT_EQ(SETTINGS_FLAG_PERSISTED
, flags_and_value2
.first
);
4304 EXPECT_EQ(kSampleValue2
, flags_and_value2
.second
);
4308 TEST_P(SpdyNetworkTransactionTest
, GoAwayWithActiveStream
) {
4309 scoped_ptr
<SpdyFrame
> req(
4310 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
4311 MockWrite writes
[] = {CreateMockWrite(*req
, 0)};
4313 scoped_ptr
<SpdyFrame
> go_away(spdy_util_
.ConstructSpdyGoAway());
4314 MockRead reads
[] = {
4315 CreateMockRead(*go_away
, 1),
4318 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
4319 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
4320 BoundNetLog(), GetParam(), NULL
);
4321 helper
.AddData(&data
);
4322 helper
.RunToCompletion(&data
);
4323 TransactionHelperResult out
= helper
.output();
4324 EXPECT_EQ(ERR_ABORTED
, out
.rv
);
4327 TEST_P(SpdyNetworkTransactionTest
, CloseWithActiveStream
) {
4328 scoped_ptr
<SpdyFrame
> req(
4329 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
4330 MockWrite writes
[] = {CreateMockWrite(*req
, 0)};
4332 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
4333 MockRead reads
[] = {
4334 CreateMockRead(*resp
, 1), MockRead(SYNCHRONOUS
, 0, 2) // EOF
4337 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
4339 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
4340 log
, GetParam(), NULL
);
4341 helper
.RunPreTestSetup();
4342 helper
.AddData(&data
);
4343 HttpNetworkTransaction
* trans
= helper
.trans();
4345 TestCompletionCallback callback
;
4346 TransactionHelperResult out
;
4347 out
.rv
= trans
->Start(&CreateGetRequest(), callback
.callback(), log
);
4349 EXPECT_EQ(out
.rv
, ERR_IO_PENDING
);
4350 out
.rv
= callback
.WaitForResult();
4351 EXPECT_EQ(out
.rv
, OK
);
4353 const HttpResponseInfo
* response
= trans
->GetResponseInfo();
4354 EXPECT_TRUE(response
->headers
.get() != NULL
);
4355 EXPECT_TRUE(response
->was_fetched_via_spdy
);
4356 out
.rv
= ReadTransaction(trans
, &out
.response_data
);
4357 EXPECT_EQ(ERR_CONNECTION_CLOSED
, out
.rv
);
4359 // Verify that we consumed all test data.
4360 helper
.VerifyDataConsumed();
4363 // HTTP_1_1_REQUIRED results in ERR_HTTP_1_1_REQUIRED.
4364 TEST_P(SpdyNetworkTransactionTest
, HTTP11RequiredError
) {
4365 // HTTP_1_1_REQUIRED is only supported by HTTP/2.
4366 if (spdy_util_
.spdy_version() < HTTP2
)
4369 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
4370 BoundNetLog(), GetParam(), nullptr);
4372 scoped_ptr
<SpdyFrame
> go_away(spdy_util_
.ConstructSpdyGoAway(
4373 0, GOAWAY_HTTP_1_1_REQUIRED
, "Try again using HTTP/1.1 please."));
4374 MockRead reads
[] = {
4375 CreateMockRead(*go_away
, 0),
4377 SequencedSocketData
data(reads
, arraysize(reads
), nullptr, 0);
4379 helper
.RunToCompletion(&data
);
4380 TransactionHelperResult out
= helper
.output();
4381 EXPECT_EQ(ERR_HTTP_1_1_REQUIRED
, out
.rv
);
4384 // Retry with HTTP/1.1 when receiving HTTP_1_1_REQUIRED. Note that no actual
4385 // protocol negotiation happens, instead this test forces protocols for both
4387 TEST_P(SpdyNetworkTransactionTest
, HTTP11RequiredRetry
) {
4388 // HTTP_1_1_REQUIRED is only supported by HTTP/2.
4389 if (spdy_util_
.spdy_version() < HTTP2
)
4391 // HTTP_1_1_REQUIRED implementation relies on the assumption that HTTP/2 is
4392 // only spoken over SSL.
4393 if (GetParam().ssl_type
!= HTTPS_SPDY_VIA_NPN
)
4396 HttpRequestInfo request
;
4397 request
.method
= "GET";
4398 request
.url
= GURL("https://www.example.org/");
4399 scoped_ptr
<SpdySessionDependencies
> session_deps(
4400 CreateSpdySessionDependencies(GetParam()));
4401 // Do not force SPDY so that second socket can negotiate HTTP/1.1.
4402 session_deps
->next_protos
= SpdyNextProtos();
4403 NormalSpdyTransactionHelper
helper(request
, DEFAULT_PRIORITY
, BoundNetLog(),
4404 GetParam(), session_deps
.release());
4406 // First socket: HTTP/2 request rejected with HTTP_1_1_REQUIRED.
4407 const char* url
= request
.url
.spec().c_str();
4408 scoped_ptr
<SpdyHeaderBlock
> headers(spdy_util_
.ConstructGetHeaderBlock(url
));
4409 scoped_ptr
<SpdyFrame
> req(
4410 spdy_util_
.ConstructSpdySyn(1, *headers
, LOWEST
, false, true));
4411 MockWrite writes0
[] = {CreateMockWrite(*req
, 0)};
4412 scoped_ptr
<SpdyFrame
> go_away(spdy_util_
.ConstructSpdyGoAway(
4413 0, GOAWAY_HTTP_1_1_REQUIRED
, "Try again using HTTP/1.1 please."));
4414 MockRead reads0
[] = {CreateMockRead(*go_away
, 1)};
4415 SequencedSocketData
data0(reads0
, arraysize(reads0
), writes0
,
4416 arraysize(writes0
));
4418 scoped_ptr
<SSLSocketDataProvider
> ssl_provider0(
4419 new SSLSocketDataProvider(ASYNC
, OK
));
4420 // Expect HTTP/2 protocols too in SSLConfig.
4421 ssl_provider0
->next_protos_expected_in_ssl_config
.push_back(kProtoHTTP11
);
4422 ssl_provider0
->next_protos_expected_in_ssl_config
.push_back(kProtoSPDY31
);
4423 ssl_provider0
->next_protos_expected_in_ssl_config
.push_back(kProtoHTTP2_14
);
4424 ssl_provider0
->next_protos_expected_in_ssl_config
.push_back(kProtoHTTP2
);
4426 ssl_provider0
->SetNextProto(GetParam().protocol
);
4427 helper
.AddDataWithSSLSocketDataProvider(&data0
, ssl_provider0
.Pass());
4429 // Second socket: falling back to HTTP/1.1.
4430 MockWrite writes1
[] = {MockWrite(ASYNC
, 0,
4431 "GET / HTTP/1.1\r\n"
4432 "Host: www.example.org\r\n"
4433 "Connection: keep-alive\r\n\r\n")};
4434 MockRead reads1
[] = {MockRead(ASYNC
, 1,
4435 "HTTP/1.1 200 OK\r\n"
4436 "Content-Length: 5\r\n\r\n"
4438 SequencedSocketData
data1(reads1
, arraysize(reads1
), writes1
,
4439 arraysize(writes1
));
4441 scoped_ptr
<SSLSocketDataProvider
> ssl_provider1(
4442 new SSLSocketDataProvider(ASYNC
, OK
));
4443 // Expect only HTTP/1.1 protocol in SSLConfig.
4444 ssl_provider1
->next_protos_expected_in_ssl_config
.push_back(kProtoHTTP11
);
4446 ssl_provider1
->SetNextProto(kProtoHTTP11
);
4447 helper
.AddDataWithSSLSocketDataProvider(&data1
, ssl_provider1
.Pass());
4449 base::WeakPtr
<HttpServerProperties
> http_server_properties
=
4450 helper
.session()->spdy_session_pool()->http_server_properties();
4451 const HostPortPair host_port_pair
= HostPortPair::FromURL(GURL(url
));
4452 EXPECT_FALSE(http_server_properties
->RequiresHTTP11(host_port_pair
));
4454 helper
.RunPreTestSetup();
4455 helper
.StartDefaultTest();
4456 helper
.FinishDefaultTestWithoutVerification();
4457 helper
.VerifyDataConsumed();
4458 EXPECT_TRUE(http_server_properties
->RequiresHTTP11(host_port_pair
));
4460 const HttpResponseInfo
* response
= helper
.trans()->GetResponseInfo();
4461 ASSERT_TRUE(response
!= nullptr);
4462 ASSERT_TRUE(response
->headers
.get() != nullptr);
4463 EXPECT_EQ("HTTP/1.1 200 OK", response
->headers
->GetStatusLine());
4464 EXPECT_FALSE(response
->was_fetched_via_spdy
);
4465 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP1
, response
->connection_info
);
4466 EXPECT_TRUE(response
->was_npn_negotiated
);
4467 EXPECT_TRUE(request
.url
.SchemeIs("https"));
4468 EXPECT_EQ("127.0.0.1", response
->socket_address
.host());
4469 EXPECT_EQ(443, response
->socket_address
.port());
4470 std::string response_data
;
4471 ASSERT_EQ(OK
, ReadTransaction(helper
.trans(), &response_data
));
4472 EXPECT_EQ("hello", response_data
);
4475 // Retry with HTTP/1.1 to the proxy when receiving HTTP_1_1_REQUIRED from the
4476 // proxy. Note that no actual protocol negotiation happens, instead this test
4477 // forces protocols for both sockets.
4478 TEST_P(SpdyNetworkTransactionTest
, HTTP11RequiredProxyRetry
) {
4479 // HTTP_1_1_REQUIRED is only supported by HTTP/2.
4480 if (spdy_util_
.spdy_version() < HTTP2
)
4482 // HTTP_1_1_REQUIRED implementation relies on the assumption that HTTP/2 is
4483 // only spoken over SSL.
4484 if (GetParam().ssl_type
!= HTTPS_SPDY_VIA_NPN
)
4487 HttpRequestInfo request
;
4488 request
.method
= "GET";
4489 request
.url
= GURL("https://www.example.org/");
4490 scoped_ptr
<SpdySessionDependencies
> session_deps(
4491 CreateSpdySessionDependencies(
4493 ProxyService::CreateFixedFromPacResult("HTTPS myproxy:70")));
4494 // Do not force SPDY so that second socket can negotiate HTTP/1.1.
4495 session_deps
->next_protos
= SpdyNextProtos();
4496 NormalSpdyTransactionHelper
helper(request
, DEFAULT_PRIORITY
, BoundNetLog(),
4497 GetParam(), session_deps
.release());
4499 // First socket: HTTP/2 CONNECT rejected with HTTP_1_1_REQUIRED.
4500 scoped_ptr
<SpdyFrame
> req(spdy_util_
.ConstructSpdyConnect(
4501 nullptr, 0, 1, LOWEST
, HostPortPair("www.example.org", 443)));
4502 MockWrite writes0
[] = {CreateMockWrite(*req
, 0)};
4503 scoped_ptr
<SpdyFrame
> go_away(spdy_util_
.ConstructSpdyGoAway(
4504 0, GOAWAY_HTTP_1_1_REQUIRED
, "Try again using HTTP/1.1 please."));
4505 MockRead reads0
[] = {CreateMockRead(*go_away
, 1)};
4506 SequencedSocketData
data0(reads0
, arraysize(reads0
), writes0
,
4507 arraysize(writes0
));
4509 scoped_ptr
<SSLSocketDataProvider
> ssl_provider0(
4510 new SSLSocketDataProvider(ASYNC
, OK
));
4511 // Expect HTTP/2 protocols too in SSLConfig.
4512 ssl_provider0
->next_protos_expected_in_ssl_config
.push_back(kProtoHTTP11
);
4513 ssl_provider0
->next_protos_expected_in_ssl_config
.push_back(kProtoSPDY31
);
4514 ssl_provider0
->next_protos_expected_in_ssl_config
.push_back(kProtoHTTP2_14
);
4515 ssl_provider0
->next_protos_expected_in_ssl_config
.push_back(kProtoHTTP2
);
4517 ssl_provider0
->SetNextProto(GetParam().protocol
);
4518 helper
.AddDataWithSSLSocketDataProvider(&data0
, ssl_provider0
.Pass());
4520 // Second socket: retry using HTTP/1.1.
4521 MockWrite writes1
[] = {
4523 "CONNECT www.example.org:443 HTTP/1.1\r\n"
4524 "Host: www.example.org\r\n"
4525 "Proxy-Connection: keep-alive\r\n\r\n"),
4527 "GET / HTTP/1.1\r\n"
4528 "Host: www.example.org\r\n"
4529 "Connection: keep-alive\r\n\r\n"),
4532 MockRead reads1
[] = {
4533 MockRead(ASYNC
, 1, "HTTP/1.1 200 OK\r\n\r\n"),
4535 "HTTP/1.1 200 OK\r\n"
4536 "Content-Length: 5\r\n\r\n"
4539 SequencedSocketData
data1(reads1
, arraysize(reads1
), writes1
,
4540 arraysize(writes1
));
4542 scoped_ptr
<SSLSocketDataProvider
> ssl_provider1(
4543 new SSLSocketDataProvider(ASYNC
, OK
));
4544 // Expect only HTTP/1.1 protocol in SSLConfig.
4545 ssl_provider1
->next_protos_expected_in_ssl_config
.push_back(kProtoHTTP11
);
4547 ssl_provider1
->SetNextProto(kProtoHTTP11
);
4548 helper
.AddDataWithSSLSocketDataProvider(&data1
, ssl_provider1
.Pass());
4550 // A third socket is needed for the tunnelled connection.
4551 scoped_ptr
<SSLSocketDataProvider
> ssl_provider2(
4552 new SSLSocketDataProvider(ASYNC
, OK
));
4553 helper
.session_deps()->socket_factory
->AddSSLSocketDataProvider(
4554 ssl_provider2
.get());
4556 base::WeakPtr
<HttpServerProperties
> http_server_properties
=
4557 helper
.session()->spdy_session_pool()->http_server_properties();
4558 const HostPortPair proxy_host_port_pair
= HostPortPair("myproxy", 70);
4559 EXPECT_FALSE(http_server_properties
->RequiresHTTP11(proxy_host_port_pair
));
4561 helper
.RunPreTestSetup();
4562 helper
.StartDefaultTest();
4563 helper
.FinishDefaultTestWithoutVerification();
4564 helper
.VerifyDataConsumed();
4565 EXPECT_TRUE(http_server_properties
->RequiresHTTP11(proxy_host_port_pair
));
4567 const HttpResponseInfo
* response
= helper
.trans()->GetResponseInfo();
4568 ASSERT_TRUE(response
!= nullptr);
4569 ASSERT_TRUE(response
->headers
.get() != nullptr);
4570 EXPECT_EQ("HTTP/1.1 200 OK", response
->headers
->GetStatusLine());
4571 EXPECT_FALSE(response
->was_fetched_via_spdy
);
4572 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP1
, response
->connection_info
);
4573 EXPECT_FALSE(response
->was_npn_negotiated
);
4574 EXPECT_TRUE(request
.url
.SchemeIs("https"));
4575 EXPECT_EQ("127.0.0.1", response
->socket_address
.host());
4576 EXPECT_EQ(70, response
->socket_address
.port());
4577 std::string response_data
;
4578 ASSERT_EQ(OK
, ReadTransaction(helper
.trans(), &response_data
));
4579 EXPECT_EQ("hello", response_data
);
4582 // Test to make sure we can correctly connect through a proxy.
4583 TEST_P(SpdyNetworkTransactionTest
, ProxyConnect
) {
4584 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
4585 BoundNetLog(), GetParam(), NULL
);
4586 helper
.session_deps().reset(CreateSpdySessionDependencies(
4588 ProxyService::CreateFixedFromPacResult("PROXY myproxy:70")));
4589 helper
.SetSession(make_scoped_refptr(
4590 SpdySessionDependencies::SpdyCreateSession(helper
.session_deps().get())));
4591 helper
.RunPreTestSetup();
4592 HttpNetworkTransaction
* trans
= helper
.trans();
4594 const char kConnect443
[] = {
4595 "CONNECT www.example.org:443 HTTP/1.1\r\n"
4596 "Host: www.example.org\r\n"
4597 "Proxy-Connection: keep-alive\r\n\r\n"};
4598 const char kHTTP200
[] = {"HTTP/1.1 200 OK\r\n\r\n"};
4599 scoped_ptr
<SpdyFrame
> req(
4600 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
4601 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
4602 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
4604 MockWrite writes
[] = {
4605 MockWrite(SYNCHRONOUS
, kConnect443
, arraysize(kConnect443
) - 1, 0),
4606 CreateMockWrite(*req
, 2),
4608 MockRead reads
[] = {
4609 MockRead(SYNCHRONOUS
, kHTTP200
, arraysize(kHTTP200
) - 1, 1),
4610 CreateMockRead(*resp
, 3),
4611 CreateMockRead(*body
.get(), 4),
4612 MockRead(ASYNC
, 0, 0, 5),
4614 scoped_ptr
<SequencedSocketData
> data(new SequencedSocketData(
4615 reads
, arraysize(reads
), writes
, arraysize(writes
)));
4617 helper
.AddData(data
.get());
4618 TestCompletionCallback callback
;
4620 int rv
= trans
->Start(
4621 &CreateGetRequest(), callback
.callback(), BoundNetLog());
4622 EXPECT_EQ(ERR_IO_PENDING
, rv
);
4624 rv
= callback
.WaitForResult();
4627 // Verify the SYN_REPLY.
4628 HttpResponseInfo response
= *trans
->GetResponseInfo();
4629 EXPECT_TRUE(response
.headers
.get() != NULL
);
4630 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
4632 std::string response_data
;
4633 ASSERT_EQ(OK
, ReadTransaction(trans
, &response_data
));
4634 EXPECT_EQ("hello!", response_data
);
4635 helper
.VerifyDataConsumed();
4638 // Test to make sure we can correctly connect through a proxy to
4639 // www.example.org, if there already exists a direct spdy connection to
4640 // www.example.org. See https://crbug.com/49874.
4641 TEST_P(SpdyNetworkTransactionTest
, DirectConnectProxyReconnect
) {
4642 // When setting up the first transaction, we store the SpdySessionPool so that
4643 // we can use the same pool in the second transaction.
4644 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
4645 BoundNetLog(), GetParam(), NULL
);
4647 // Use a proxy service which returns a proxy fallback list from DIRECT to
4648 // myproxy:70. For this test there will be no fallback, so it is equivalent
4649 // to simply DIRECT. The reason for appending the second proxy is to verify
4650 // that the session pool key used does is just "DIRECT".
4651 helper
.session_deps().reset(CreateSpdySessionDependencies(
4653 ProxyService::CreateFixedFromPacResult("DIRECT; PROXY myproxy:70")));
4654 helper
.SetSession(make_scoped_refptr(
4655 SpdySessionDependencies::SpdyCreateSession(helper
.session_deps().get())));
4657 SpdySessionPool
* spdy_session_pool
= helper
.session()->spdy_session_pool();
4658 helper
.RunPreTestSetup();
4660 // Construct and send a simple GET request.
4661 scoped_ptr
<SpdyFrame
> req(
4662 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
4663 MockWrite writes
[] = {
4664 CreateMockWrite(*req
, 0),
4667 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
4668 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
4669 MockRead reads
[] = {
4670 CreateMockRead(*resp
, 1),
4671 CreateMockRead(*body
, 2),
4672 MockRead(SYNCHRONOUS
, ERR_IO_PENDING
, 3), // Force a pause
4674 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
4675 helper
.AddData(&data
);
4676 HttpNetworkTransaction
* trans
= helper
.trans();
4678 TestCompletionCallback callback
;
4679 TransactionHelperResult out
;
4680 out
.rv
= trans
->Start(
4681 &CreateGetRequest(), callback
.callback(), BoundNetLog());
4683 EXPECT_EQ(out
.rv
, ERR_IO_PENDING
);
4684 out
.rv
= callback
.WaitForResult();
4685 EXPECT_EQ(out
.rv
, OK
);
4687 const HttpResponseInfo
* response
= trans
->GetResponseInfo();
4688 EXPECT_TRUE(response
->headers
.get() != NULL
);
4689 EXPECT_TRUE(response
->was_fetched_via_spdy
);
4690 out
.rv
= ReadTransaction(trans
, &out
.response_data
);
4691 EXPECT_EQ(OK
, out
.rv
);
4692 out
.status_line
= response
->headers
->GetStatusLine();
4693 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
4694 EXPECT_EQ("hello!", out
.response_data
);
4696 // Check that the SpdySession is still in the SpdySessionPool.
4697 HostPortPair
host_port_pair("www.example.org", helper
.port());
4698 SpdySessionKey
session_pool_key_direct(
4699 host_port_pair
, ProxyServer::Direct(), PRIVACY_MODE_DISABLED
);
4700 EXPECT_TRUE(HasSpdySession(spdy_session_pool
, session_pool_key_direct
));
4701 SpdySessionKey
session_pool_key_proxy(
4703 ProxyServer::FromURI("www.foo.com", ProxyServer::SCHEME_HTTP
),
4704 PRIVACY_MODE_DISABLED
);
4705 EXPECT_FALSE(HasSpdySession(spdy_session_pool
, session_pool_key_proxy
));
4707 // Set up data for the proxy connection.
4708 const char kConnect443
[] = {
4709 "CONNECT www.example.org:443 HTTP/1.1\r\n"
4710 "Host: www.example.org\r\n"
4711 "Proxy-Connection: keep-alive\r\n\r\n"};
4712 const char kHTTP200
[] = {"HTTP/1.1 200 OK\r\n\r\n"};
4713 scoped_ptr
<SpdyFrame
> req2(spdy_util_
.ConstructSpdyGet(
4714 GetDefaultUrlWithPath("/foo.dat").c_str(), false, 1, LOWEST
));
4715 scoped_ptr
<SpdyFrame
> resp2(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
4716 scoped_ptr
<SpdyFrame
> body2(spdy_util_
.ConstructSpdyBodyFrame(1, true));
4718 MockWrite writes2
[] = {
4719 MockWrite(SYNCHRONOUS
, kConnect443
, arraysize(kConnect443
) - 1, 0),
4720 CreateMockWrite(*req2
, 2),
4722 MockRead reads2
[] = {
4723 MockRead(SYNCHRONOUS
, kHTTP200
, arraysize(kHTTP200
) - 1, 1),
4724 CreateMockRead(*resp2
, 3),
4725 CreateMockRead(*body2
, 4),
4726 MockRead(ASYNC
, 0, 5) // EOF
4729 scoped_ptr
<SequencedSocketData
> data_proxy(new SequencedSocketData(
4730 reads2
, arraysize(reads2
), writes2
, arraysize(writes2
)));
4732 // Create another request to www.example.org, but this time through a proxy.
4733 HttpRequestInfo request_proxy
;
4734 request_proxy
.method
= "GET";
4735 request_proxy
.url
= GURL(GetDefaultUrlWithPath("/foo.dat"));
4736 request_proxy
.load_flags
= 0;
4737 scoped_ptr
<SpdySessionDependencies
> ssd_proxy(
4738 CreateSpdySessionDependencies(GetParam()));
4739 // Ensure that this transaction uses the same SpdySessionPool.
4740 scoped_refptr
<HttpNetworkSession
> session_proxy(
4741 SpdySessionDependencies::SpdyCreateSession(ssd_proxy
.get()));
4742 NormalSpdyTransactionHelper
helper_proxy(request_proxy
, DEFAULT_PRIORITY
,
4743 BoundNetLog(), GetParam(), NULL
);
4744 HttpNetworkSessionPeer
session_peer(session_proxy
);
4745 scoped_ptr
<ProxyService
> proxy_service(
4746 ProxyService::CreateFixedFromPacResult("PROXY myproxy:70"));
4747 session_peer
.SetProxyService(proxy_service
.get());
4748 helper_proxy
.session_deps().swap(ssd_proxy
);
4749 helper_proxy
.SetSession(session_proxy
);
4750 helper_proxy
.RunPreTestSetup();
4751 helper_proxy
.AddData(data_proxy
.get());
4753 HttpNetworkTransaction
* trans_proxy
= helper_proxy
.trans();
4754 TestCompletionCallback callback_proxy
;
4755 int rv
= trans_proxy
->Start(
4756 &request_proxy
, callback_proxy
.callback(), BoundNetLog());
4757 EXPECT_EQ(ERR_IO_PENDING
, rv
);
4758 rv
= callback_proxy
.WaitForResult();
4761 HttpResponseInfo response_proxy
= *trans_proxy
->GetResponseInfo();
4762 EXPECT_TRUE(response_proxy
.headers
.get() != NULL
);
4763 EXPECT_EQ("HTTP/1.1 200 OK", response_proxy
.headers
->GetStatusLine());
4765 std::string response_data
;
4766 ASSERT_EQ(OK
, ReadTransaction(trans_proxy
, &response_data
));
4767 EXPECT_EQ("hello!", response_data
);
4769 helper_proxy
.VerifyDataConsumed();
4772 // When we get a TCP-level RST, we need to retry a HttpNetworkTransaction
4773 // on a new connection, if the connection was previously known to be good.
4774 // This can happen when a server reboots without saying goodbye, or when
4775 // we're behind a NAT that masked the RST.
4776 TEST_P(SpdyNetworkTransactionTest
, VerifyRetryOnConnectionReset
) {
4777 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
4778 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
4779 MockRead reads
[] = {
4780 CreateMockRead(*resp
, 1),
4781 CreateMockRead(*body
, 2),
4782 MockRead(ASYNC
, ERR_IO_PENDING
, 3),
4783 MockRead(ASYNC
, ERR_CONNECTION_RESET
, 4),
4786 MockRead reads2
[] = {
4787 CreateMockRead(*resp
, 1),
4788 CreateMockRead(*body
, 2),
4789 MockRead(ASYNC
, 0, 3) // EOF
4792 scoped_ptr
<SpdyFrame
> req(
4793 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
4794 scoped_ptr
<SpdyFrame
> req3(
4795 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 3, LOWEST
, true));
4796 MockWrite writes1
[] = {CreateMockWrite(*req
, 0), CreateMockWrite(*req3
, 5)};
4797 MockWrite writes2
[] = {CreateMockWrite(*req
, 0)};
4799 // This test has a couple of variants.
4801 // Induce the RST while waiting for our transaction to send.
4802 VARIANT_RST_DURING_SEND_COMPLETION
= 0,
4803 // Induce the RST while waiting for our transaction to read.
4804 // In this case, the send completed - everything copied into the SNDBUF.
4805 VARIANT_RST_DURING_READ_COMPLETION
= 1
4808 for (int variant
= VARIANT_RST_DURING_SEND_COMPLETION
;
4809 variant
<= VARIANT_RST_DURING_READ_COMPLETION
;
4811 SequencedSocketData
data1(reads
, arraysize(reads
), writes1
, 1 + variant
);
4813 SequencedSocketData
data2(reads2
, arraysize(reads2
), writes2
,
4814 arraysize(writes2
));
4816 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
4817 BoundNetLog(), GetParam(), NULL
);
4818 helper
.AddData(&data1
);
4819 helper
.AddData(&data2
);
4820 helper
.RunPreTestSetup();
4822 for (int i
= 0; i
< 2; ++i
) {
4823 scoped_ptr
<HttpNetworkTransaction
> trans(
4824 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
4826 TestCompletionCallback callback
;
4827 int rv
= trans
->Start(
4828 &helper
.request(), callback
.callback(), BoundNetLog());
4829 EXPECT_EQ(ERR_IO_PENDING
, rv
);
4830 // On the second transaction, we trigger the RST.
4832 if (variant
== VARIANT_RST_DURING_READ_COMPLETION
) {
4833 // Writes to the socket complete asynchronously on SPDY by running
4834 // through the message loop. Complete the write here.
4835 base::RunLoop().RunUntilIdle();
4838 // Now schedule the ERR_CONNECTION_RESET.
4839 data1
.CompleteRead();
4841 rv
= callback
.WaitForResult();
4844 const HttpResponseInfo
* response
= trans
->GetResponseInfo();
4845 ASSERT_TRUE(response
!= NULL
);
4846 EXPECT_TRUE(response
->headers
.get() != NULL
);
4847 EXPECT_TRUE(response
->was_fetched_via_spdy
);
4848 std::string response_data
;
4849 rv
= ReadTransaction(trans
.get(), &response_data
);
4851 EXPECT_EQ("HTTP/1.1 200 OK", response
->headers
->GetStatusLine());
4852 EXPECT_EQ("hello!", response_data
);
4853 base::RunLoop().RunUntilIdle();
4856 helper
.VerifyDataConsumed();
4857 base::RunLoop().RunUntilIdle();
4861 // Test that turning SPDY on and off works properly.
4862 TEST_P(SpdyNetworkTransactionTest
, SpdyOnOffToggle
) {
4863 HttpStreamFactory::set_spdy_enabled(true);
4864 scoped_ptr
<SpdyFrame
> req(
4865 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
4866 MockWrite spdy_writes
[] = {CreateMockWrite(*req
, 0)};
4868 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
4869 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
4870 MockRead spdy_reads
[] = {
4871 CreateMockRead(*resp
, 1),
4872 CreateMockRead(*body
, 2),
4873 MockRead(ASYNC
, 0, 3) // EOF
4876 SequencedSocketData
data(spdy_reads
, arraysize(spdy_reads
), spdy_writes
,
4877 arraysize(spdy_writes
));
4878 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
4879 BoundNetLog(), GetParam(), NULL
);
4880 helper
.RunToCompletion(&data
);
4881 TransactionHelperResult out
= helper
.output();
4882 EXPECT_EQ(OK
, out
.rv
);
4883 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
4884 EXPECT_EQ("hello!", out
.response_data
);
4886 HttpStreamFactory::set_spdy_enabled(false);
4887 MockWrite http_writes
[] = {
4888 MockWrite(SYNCHRONOUS
, 0,
4889 "GET / HTTP/1.1\r\n"
4890 "Host: www.example.org\r\n"
4891 "Connection: keep-alive\r\n\r\n"),
4894 MockRead http_reads
[] = {
4895 MockRead(SYNCHRONOUS
, 1, "HTTP/1.1 200 OK\r\n\r\n"),
4896 MockRead(SYNCHRONOUS
, 2, "hello from http"),
4897 MockRead(SYNCHRONOUS
, OK
, 3),
4899 SequencedSocketData
data2(http_reads
, arraysize(http_reads
), http_writes
,
4900 arraysize(http_writes
));
4901 NormalSpdyTransactionHelper
helper2(CreateGetRequest(), DEFAULT_PRIORITY
,
4902 BoundNetLog(), GetParam(), NULL
);
4903 helper2
.SetSpdyDisabled();
4904 helper2
.RunToCompletion(&data2
);
4905 TransactionHelperResult out2
= helper2
.output();
4906 EXPECT_EQ(OK
, out2
.rv
);
4907 EXPECT_EQ("HTTP/1.1 200 OK", out2
.status_line
);
4908 EXPECT_EQ("hello from http", out2
.response_data
);
4910 HttpStreamFactory::set_spdy_enabled(true);
4913 // Tests that Basic authentication works over SPDY
4914 TEST_P(SpdyNetworkTransactionTest
, SpdyBasicAuth
) {
4915 HttpStreamFactory::set_spdy_enabled(true);
4917 // The first request will be a bare GET, the second request will be a
4918 // GET with an Authorization header.
4919 scoped_ptr
<SpdyFrame
> req_get(
4920 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
4921 const char* const kExtraAuthorizationHeaders
[] = {
4922 "authorization", "Basic Zm9vOmJhcg=="
4924 scoped_ptr
<SpdyFrame
> req_get_authorization(
4925 spdy_util_
.ConstructSpdyGet(kExtraAuthorizationHeaders
,
4926 arraysize(kExtraAuthorizationHeaders
) / 2,
4927 false, 3, LOWEST
, true));
4928 MockWrite spdy_writes
[] = {
4929 CreateMockWrite(*req_get
, 0), CreateMockWrite(*req_get_authorization
, 3),
4932 // The first response is a 401 authentication challenge, and the second
4933 // response will be a 200 response since the second request includes a valid
4934 // Authorization header.
4935 const char* const kExtraAuthenticationHeaders
[] = {
4937 "Basic realm=\"MyRealm\""
4939 scoped_ptr
<SpdyFrame
> resp_authentication(
4940 spdy_util_
.ConstructSpdySynReplyError(
4941 "401 Authentication Required",
4942 kExtraAuthenticationHeaders
,
4943 arraysize(kExtraAuthenticationHeaders
) / 2,
4945 scoped_ptr
<SpdyFrame
> body_authentication(
4946 spdy_util_
.ConstructSpdyBodyFrame(1, true));
4947 scoped_ptr
<SpdyFrame
> resp_data(
4948 spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 3));
4949 scoped_ptr
<SpdyFrame
> body_data(spdy_util_
.ConstructSpdyBodyFrame(3, true));
4950 MockRead spdy_reads
[] = {
4951 CreateMockRead(*resp_authentication
, 1),
4952 CreateMockRead(*body_authentication
, 2),
4953 CreateMockRead(*resp_data
, 4),
4954 CreateMockRead(*body_data
, 5),
4955 MockRead(ASYNC
, 0, 6),
4958 SequencedSocketData
data(spdy_reads
, arraysize(spdy_reads
), spdy_writes
,
4959 arraysize(spdy_writes
));
4960 HttpRequestInfo
request(CreateGetRequest());
4961 BoundNetLog net_log
;
4962 NormalSpdyTransactionHelper
helper(request
, DEFAULT_PRIORITY
,
4963 net_log
, GetParam(), NULL
);
4965 helper
.RunPreTestSetup();
4966 helper
.AddData(&data
);
4967 HttpNetworkTransaction
* trans
= helper
.trans();
4968 TestCompletionCallback callback
;
4969 const int rv_start
= trans
->Start(&request
, callback
.callback(), net_log
);
4970 EXPECT_EQ(ERR_IO_PENDING
, rv_start
);
4971 const int rv_start_complete
= callback
.WaitForResult();
4972 EXPECT_EQ(OK
, rv_start_complete
);
4974 // Make sure the response has an auth challenge.
4975 const HttpResponseInfo
* const response_start
= trans
->GetResponseInfo();
4976 ASSERT_TRUE(response_start
!= NULL
);
4977 ASSERT_TRUE(response_start
->headers
.get() != NULL
);
4978 EXPECT_EQ(401, response_start
->headers
->response_code());
4979 EXPECT_TRUE(response_start
->was_fetched_via_spdy
);
4980 AuthChallengeInfo
* auth_challenge
= response_start
->auth_challenge
.get();
4981 ASSERT_TRUE(auth_challenge
!= NULL
);
4982 EXPECT_FALSE(auth_challenge
->is_proxy
);
4983 EXPECT_EQ("basic", auth_challenge
->scheme
);
4984 EXPECT_EQ("MyRealm", auth_challenge
->realm
);
4986 // Restart with a username/password.
4987 AuthCredentials
credentials(base::ASCIIToUTF16("foo"),
4988 base::ASCIIToUTF16("bar"));
4989 TestCompletionCallback callback_restart
;
4990 const int rv_restart
= trans
->RestartWithAuth(
4991 credentials
, callback_restart
.callback());
4992 EXPECT_EQ(ERR_IO_PENDING
, rv_restart
);
4993 const int rv_restart_complete
= callback_restart
.WaitForResult();
4994 EXPECT_EQ(OK
, rv_restart_complete
);
4995 // TODO(cbentzel): This is actually the same response object as before, but
4996 // data has changed.
4997 const HttpResponseInfo
* const response_restart
= trans
->GetResponseInfo();
4998 ASSERT_TRUE(response_restart
!= NULL
);
4999 ASSERT_TRUE(response_restart
->headers
.get() != NULL
);
5000 EXPECT_EQ(200, response_restart
->headers
->response_code());
5001 EXPECT_TRUE(response_restart
->auth_challenge
.get() == NULL
);
5004 TEST_P(SpdyNetworkTransactionTest
, ServerPushWithHeaders
) {
5005 scoped_ptr
<SpdyFrame
> stream1_syn(
5006 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
5007 scoped_ptr
<SpdyFrame
> stream1_body(
5008 spdy_util_
.ConstructSpdyBodyFrame(1, true));
5009 MockWrite writes
[] = {
5010 CreateMockWrite(*stream1_syn
, 0),
5013 scoped_ptr
<SpdyHeaderBlock
> initial_headers(new SpdyHeaderBlock());
5014 spdy_util_
.AddUrlToHeaderBlock(GetDefaultUrlWithPath("/foo.dat"),
5015 initial_headers
.get());
5016 scoped_ptr
<SpdyFrame
> stream2_syn(
5017 spdy_util_
.ConstructInitialSpdyPushFrame(initial_headers
.Pass(), 2, 1));
5019 scoped_ptr
<SpdyHeaderBlock
> late_headers(new SpdyHeaderBlock());
5020 (*late_headers
)["hello"] = "bye";
5021 (*late_headers
)[spdy_util_
.GetStatusKey()] = "200";
5022 (*late_headers
)[spdy_util_
.GetVersionKey()] = "HTTP/1.1";
5023 scoped_ptr
<SpdyFrame
> stream2_headers(
5024 spdy_util_
.ConstructSpdyControlFrame(late_headers
.Pass(),
5032 scoped_ptr
<SpdyFrame
>
5033 stream1_reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
5034 const char kPushedData
[] = "pushed";
5035 scoped_ptr
<SpdyFrame
> stream2_body(
5036 spdy_util_
.ConstructSpdyBodyFrame(
5037 2, kPushedData
, strlen(kPushedData
), true));
5038 MockRead reads
[] = {
5039 CreateMockRead(*stream1_reply
, 1),
5040 CreateMockRead(*stream2_syn
, 2),
5041 CreateMockRead(*stream2_headers
, 3),
5042 CreateMockRead(*stream1_body
, 4, SYNCHRONOUS
),
5043 CreateMockRead(*stream2_body
, 5),
5044 MockRead(SYNCHRONOUS
, ERR_IO_PENDING
, 6), // Force a pause
5047 HttpResponseInfo response
;
5048 HttpResponseInfo response2
;
5049 std::string
expected_push_result("pushed");
5050 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
5051 RunServerPushTest(&data
,
5054 expected_push_result
);
5056 // Verify the SYN_REPLY.
5057 EXPECT_TRUE(response
.headers
.get() != NULL
);
5058 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
5060 // Verify the pushed stream.
5061 EXPECT_TRUE(response2
.headers
.get() != NULL
);
5062 EXPECT_EQ("HTTP/1.1 200 OK", response2
.headers
->GetStatusLine());
5065 TEST_P(SpdyNetworkTransactionTest
, ServerPushClaimBeforeHeaders
) {
5066 // We push a stream and attempt to claim it before the headers come down.
5067 scoped_ptr
<SpdyFrame
> stream1_syn(
5068 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
5069 scoped_ptr
<SpdyFrame
> stream1_body(
5070 spdy_util_
.ConstructSpdyBodyFrame(1, true));
5071 MockWrite writes
[] = {
5072 CreateMockWrite(*stream1_syn
, 0, SYNCHRONOUS
),
5075 scoped_ptr
<SpdyHeaderBlock
> initial_headers(new SpdyHeaderBlock());
5076 spdy_util_
.AddUrlToHeaderBlock(GetDefaultUrlWithPath("/foo.dat"),
5077 initial_headers
.get());
5078 scoped_ptr
<SpdyFrame
> stream2_syn(
5079 spdy_util_
.ConstructInitialSpdyPushFrame(initial_headers
.Pass(), 2, 1));
5081 scoped_ptr
<SpdyHeaderBlock
> late_headers(new SpdyHeaderBlock());
5082 (*late_headers
)["hello"] = "bye";
5083 (*late_headers
)[spdy_util_
.GetStatusKey()] = "200";
5084 (*late_headers
)[spdy_util_
.GetVersionKey()] = "HTTP/1.1";
5085 scoped_ptr
<SpdyFrame
> stream2_headers(
5086 spdy_util_
.ConstructSpdyControlFrame(late_headers
.Pass(),
5094 scoped_ptr
<SpdyFrame
>
5095 stream1_reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
5096 const char kPushedData
[] = "pushed";
5097 scoped_ptr
<SpdyFrame
> stream2_body(
5098 spdy_util_
.ConstructSpdyBodyFrame(
5099 2, kPushedData
, strlen(kPushedData
), true));
5100 MockRead reads
[] = {
5101 CreateMockRead(*stream1_reply
, 1),
5102 CreateMockRead(*stream2_syn
, 2),
5103 CreateMockRead(*stream1_body
, 3),
5104 CreateMockRead(*stream2_headers
, 4),
5105 CreateMockRead(*stream2_body
, 5),
5106 MockRead(ASYNC
, 0, 6), // EOF
5109 HttpResponseInfo response
;
5110 HttpResponseInfo response2
;
5111 std::string
expected_push_result("pushed");
5112 DeterministicSocketData
data(reads
, arraysize(reads
),
5113 writes
, arraysize(writes
));
5115 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
5116 BoundNetLog(), GetParam(), NULL
);
5117 helper
.SetDeterministic();
5118 helper
.AddDeterministicData(&data
);
5119 helper
.RunPreTestSetup();
5121 HttpNetworkTransaction
* trans
= helper
.trans();
5123 // Run until we've received the primary SYN_STREAM, the pushed SYN_STREAM,
5124 // and the body of the primary stream, but before we've received the HEADERS
5125 // for the pushed stream.
5128 // Start the transaction.
5129 TestCompletionCallback callback
;
5130 int rv
= trans
->Start(
5131 &CreateGetRequest(), callback
.callback(), BoundNetLog());
5132 EXPECT_EQ(ERR_IO_PENDING
, rv
);
5134 rv
= callback
.WaitForResult();
5137 // Request the pushed path. At this point, we've received the push, but the
5138 // headers are not yet complete.
5139 scoped_ptr
<HttpNetworkTransaction
> trans2(
5140 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
5142 &CreateGetPushRequest(), callback
.callback(), BoundNetLog());
5143 EXPECT_EQ(ERR_IO_PENDING
, rv
);
5145 base::RunLoop().RunUntilIdle();
5147 // Read the server push body.
5148 std::string result2
;
5149 ReadResult(trans2
.get(), &result2
);
5150 // Read the response body.
5152 ReadResult(trans
, &result
);
5154 // Verify that the received push data is same as the expected push data.
5155 EXPECT_EQ(result2
.compare(expected_push_result
), 0)
5156 << "Received data: "
5158 << "||||| Expected data: "
5159 << expected_push_result
;
5161 // Verify the SYN_REPLY.
5162 // Copy the response info, because trans goes away.
5163 response
= *trans
->GetResponseInfo();
5164 response2
= *trans2
->GetResponseInfo();
5166 VerifyStreamsClosed(helper
);
5168 // Verify the SYN_REPLY.
5169 EXPECT_TRUE(response
.headers
.get() != NULL
);
5170 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
5172 // Verify the pushed stream.
5173 EXPECT_TRUE(response2
.headers
.get() != NULL
);
5174 EXPECT_EQ("HTTP/1.1 200 OK", response2
.headers
->GetStatusLine());
5176 // Read the final EOF (which will close the session)
5179 // Verify that we consumed all test data.
5180 EXPECT_TRUE(data
.AllReadDataConsumed());
5181 EXPECT_TRUE(data
.AllWriteDataConsumed());
5184 // TODO(baranovich): HTTP 2 does not allow multiple HEADERS frames
5185 TEST_P(SpdyNetworkTransactionTest
, ServerPushWithTwoHeaderFrames
) {
5186 // We push a stream and attempt to claim it before the headers come down.
5187 scoped_ptr
<SpdyFrame
> stream1_syn(
5188 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
5189 scoped_ptr
<SpdyFrame
> stream1_body(
5190 spdy_util_
.ConstructSpdyBodyFrame(1, true));
5191 MockWrite writes
[] = {
5192 CreateMockWrite(*stream1_syn
, 0, SYNCHRONOUS
),
5195 scoped_ptr
<SpdyHeaderBlock
> initial_headers(new SpdyHeaderBlock());
5196 if (spdy_util_
.spdy_version() < HTTP2
) {
5197 // In HTTP/2 PUSH_PROMISE headers won't show up in the response headers.
5198 (*initial_headers
)["alpha"] = "beta";
5200 spdy_util_
.AddUrlToHeaderBlock(GetDefaultUrlWithPath("/foo.dat"),
5201 initial_headers
.get());
5202 scoped_ptr
<SpdyFrame
> stream2_syn(
5203 spdy_util_
.ConstructInitialSpdyPushFrame(initial_headers
.Pass(), 2, 1));
5205 scoped_ptr
<SpdyHeaderBlock
> middle_headers(new SpdyHeaderBlock());
5206 (*middle_headers
)["hello"] = "bye";
5207 scoped_ptr
<SpdyFrame
> stream2_headers1(
5208 spdy_util_
.ConstructSpdyControlFrame(middle_headers
.Pass(),
5216 scoped_ptr
<SpdyHeaderBlock
> late_headers(new SpdyHeaderBlock());
5217 (*late_headers
)[spdy_util_
.GetStatusKey()] = "200";
5218 if (spdy_util_
.spdy_version() < HTTP2
) {
5219 // HTTP/2 eliminates use of the :version header.
5220 (*late_headers
)[spdy_util_
.GetVersionKey()] = "HTTP/1.1";
5222 scoped_ptr
<SpdyFrame
> stream2_headers2(
5223 spdy_util_
.ConstructSpdyControlFrame(late_headers
.Pass(),
5231 scoped_ptr
<SpdyFrame
>
5232 stream1_reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
5233 const char kPushedData
[] = "pushed";
5234 scoped_ptr
<SpdyFrame
> stream2_body(
5235 spdy_util_
.ConstructSpdyBodyFrame(
5236 2, kPushedData
, strlen(kPushedData
), true));
5237 MockRead reads
[] = {
5238 CreateMockRead(*stream1_reply
, 1),
5239 CreateMockRead(*stream2_syn
, 2),
5240 CreateMockRead(*stream1_body
, 3),
5241 CreateMockRead(*stream2_headers1
, 4),
5242 CreateMockRead(*stream2_headers2
, 5),
5243 CreateMockRead(*stream2_body
, 6),
5244 MockRead(ASYNC
, 0, 7), // EOF
5247 HttpResponseInfo response
;
5248 HttpResponseInfo response2
;
5249 std::string
expected_push_result("pushed");
5250 DeterministicSocketData
data(reads
, arraysize(reads
),
5251 writes
, arraysize(writes
));
5253 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
5254 BoundNetLog(), GetParam(), NULL
);
5255 helper
.SetDeterministic();
5256 helper
.AddDeterministicData(&data
);
5257 helper
.RunPreTestSetup();
5259 HttpNetworkTransaction
* trans
= helper
.trans();
5261 // Run until we've received the primary SYN_STREAM, the pushed SYN_STREAM,
5262 // the first HEADERS frame, and the body of the primary stream, but before
5263 // we've received the final HEADERS for the pushed stream.
5266 // Start the transaction.
5267 TestCompletionCallback callback
;
5268 int rv
= trans
->Start(
5269 &CreateGetRequest(), callback
.callback(), BoundNetLog());
5270 EXPECT_EQ(ERR_IO_PENDING
, rv
);
5272 rv
= callback
.WaitForResult();
5275 // Request the pushed path. At this point, we've received the push, but the
5276 // headers are not yet complete.
5277 scoped_ptr
<HttpNetworkTransaction
> trans2(
5278 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
5280 &CreateGetPushRequest(), callback
.callback(), BoundNetLog());
5281 EXPECT_EQ(ERR_IO_PENDING
, rv
);
5283 base::RunLoop().RunUntilIdle();
5285 // Read the server push body.
5286 std::string result2
;
5287 ReadResult(trans2
.get(), &result2
);
5288 // Read the response body.
5290 ReadResult(trans
, &result
);
5292 // Verify that the received push data is same as the expected push data.
5293 EXPECT_EQ(expected_push_result
, result2
);
5295 // Verify the SYN_REPLY.
5296 // Copy the response info, because trans goes away.
5297 response
= *trans
->GetResponseInfo();
5298 response2
= *trans2
->GetResponseInfo();
5300 VerifyStreamsClosed(helper
);
5302 // Verify the SYN_REPLY.
5303 EXPECT_TRUE(response
.headers
.get() != NULL
);
5304 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
5306 // Verify the pushed stream.
5307 EXPECT_TRUE(response2
.headers
.get() != NULL
);
5308 EXPECT_EQ("HTTP/1.1 200 OK", response2
.headers
->GetStatusLine());
5310 // Verify we got all the headers from all header blocks.
5311 if (spdy_util_
.spdy_version() < HTTP2
)
5312 EXPECT_TRUE(response2
.headers
->HasHeaderValue("alpha", "beta"));
5313 EXPECT_TRUE(response2
.headers
->HasHeaderValue("hello", "bye"));
5314 EXPECT_TRUE(response2
.headers
->HasHeaderValue("status", "200"));
5316 // Read the final EOF (which will close the session)
5319 // Verify that we consumed all test data.
5320 EXPECT_TRUE(data
.AllReadDataConsumed());
5321 EXPECT_TRUE(data
.AllWriteDataConsumed());
5324 TEST_P(SpdyNetworkTransactionTest
, ServerPushWithNoStatusHeaderFrames
) {
5325 // We push a stream and attempt to claim it before the headers come down.
5326 scoped_ptr
<SpdyFrame
> stream1_syn(
5327 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
5328 scoped_ptr
<SpdyFrame
> stream1_body(
5329 spdy_util_
.ConstructSpdyBodyFrame(1, true));
5330 MockWrite writes
[] = {
5331 CreateMockWrite(*stream1_syn
, 0, SYNCHRONOUS
),
5334 scoped_ptr
<SpdyHeaderBlock
> initial_headers(new SpdyHeaderBlock());
5335 spdy_util_
.AddUrlToHeaderBlock(GetDefaultUrlWithPath("/foo.dat"),
5336 initial_headers
.get());
5337 scoped_ptr
<SpdyFrame
> stream2_syn(
5338 spdy_util_
.ConstructInitialSpdyPushFrame(initial_headers
.Pass(), 2, 1));
5340 scoped_ptr
<SpdyHeaderBlock
> middle_headers(new SpdyHeaderBlock());
5341 (*middle_headers
)["hello"] = "bye";
5342 scoped_ptr
<SpdyFrame
> stream2_headers1(
5343 spdy_util_
.ConstructSpdyControlFrame(middle_headers
.Pass(),
5351 scoped_ptr
<SpdyFrame
>
5352 stream1_reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
5353 const char kPushedData
[] = "pushed";
5354 scoped_ptr
<SpdyFrame
> stream2_body(
5355 spdy_util_
.ConstructSpdyBodyFrame(
5356 2, kPushedData
, strlen(kPushedData
), true));
5357 MockRead reads
[] = {
5358 CreateMockRead(*stream1_reply
, 1),
5359 CreateMockRead(*stream2_syn
, 2),
5360 CreateMockRead(*stream1_body
, 3),
5361 CreateMockRead(*stream2_headers1
, 4),
5362 CreateMockRead(*stream2_body
, 5),
5363 MockRead(ASYNC
, 0, 6), // EOF
5366 DeterministicSocketData
data(reads
, arraysize(reads
),
5367 writes
, arraysize(writes
));
5369 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
5370 BoundNetLog(), GetParam(), NULL
);
5371 helper
.SetDeterministic();
5372 helper
.AddDeterministicData(&data
);
5373 helper
.RunPreTestSetup();
5375 HttpNetworkTransaction
* trans
= helper
.trans();
5377 // Run until we've received the primary SYN_STREAM, the pushed SYN_STREAM,
5378 // the first HEADERS frame, and the body of the primary stream, but before
5379 // we've received the final HEADERS for the pushed stream.
5382 // Start the transaction.
5383 TestCompletionCallback callback
;
5384 int rv
= trans
->Start(
5385 &CreateGetRequest(), callback
.callback(), BoundNetLog());
5386 EXPECT_EQ(ERR_IO_PENDING
, rv
);
5388 rv
= callback
.WaitForResult();
5391 // Request the pushed path. At this point, we've received the push, but the
5392 // headers are not yet complete.
5393 scoped_ptr
<HttpNetworkTransaction
> trans2(
5394 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
5396 &CreateGetPushRequest(), callback
.callback(), BoundNetLog());
5397 EXPECT_EQ(ERR_IO_PENDING
, rv
);
5399 base::RunLoop().RunUntilIdle();
5401 // Read the server push body.
5402 std::string result2
;
5403 ReadResult(trans2
.get(), &result2
);
5404 // Read the response body.
5406 ReadResult(trans
, &result
);
5407 EXPECT_EQ("hello!", result
);
5409 // Verify that we haven't received any push data.
5410 EXPECT_EQ("", result2
);
5412 // Verify the SYN_REPLY.
5413 // Copy the response info, because trans goes away.
5414 HttpResponseInfo response
= *trans
->GetResponseInfo();
5416 VerifyStreamsClosed(helper
);
5418 // Verify the SYN_REPLY.
5419 EXPECT_TRUE(response
.headers
.get() != NULL
);
5420 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
5422 // Read the final EOF (which will close the session).
5425 // Verify that we consumed all test data.
5426 EXPECT_TRUE(data
.AllReadDataConsumed());
5427 EXPECT_TRUE(data
.AllWriteDataConsumed());
5430 TEST_P(SpdyNetworkTransactionTest
, SynReplyWithHeaders
) {
5431 scoped_ptr
<SpdyFrame
> req(
5432 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
5433 scoped_ptr
<SpdyFrame
> rst(
5434 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR
));
5435 MockWrite writes
[] = {
5436 CreateMockWrite(*req
, 0), CreateMockWrite(*rst
, 4),
5439 scoped_ptr
<SpdyFrame
> stream1_reply(
5440 spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
5442 scoped_ptr
<SpdyHeaderBlock
> late_headers(new SpdyHeaderBlock());
5443 (*late_headers
)["hello"] = "bye";
5444 scoped_ptr
<SpdyFrame
> stream1_headers(
5445 spdy_util_
.ConstructSpdyControlFrame(late_headers
.Pass(),
5452 scoped_ptr
<SpdyFrame
> stream1_body(
5453 spdy_util_
.ConstructSpdyBodyFrame(1, true));
5454 MockRead reads
[] = {
5455 CreateMockRead(*stream1_reply
, 1),
5456 CreateMockRead(*stream1_headers
, 2),
5457 CreateMockRead(*stream1_body
, 3),
5458 MockRead(ASYNC
, 0, 5) // EOF
5461 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
5462 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
5463 BoundNetLog(), GetParam(), NULL
);
5464 helper
.RunToCompletion(&data
);
5465 TransactionHelperResult out
= helper
.output();
5466 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR
, out
.rv
);
5469 TEST_P(SpdyNetworkTransactionTest
, SynReplyWithLateHeaders
) {
5470 scoped_ptr
<SpdyFrame
> req(
5471 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
5472 scoped_ptr
<SpdyFrame
> rst(
5473 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR
));
5474 MockWrite writes
[] = {
5475 CreateMockWrite(*req
, 0), CreateMockWrite(*rst
, 4),
5478 scoped_ptr
<SpdyFrame
> stream1_reply(
5479 spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
5481 scoped_ptr
<SpdyHeaderBlock
> late_headers(new SpdyHeaderBlock());
5482 (*late_headers
)["hello"] = "bye";
5483 scoped_ptr
<SpdyFrame
> stream1_headers(
5484 spdy_util_
.ConstructSpdyControlFrame(late_headers
.Pass(),
5491 scoped_ptr
<SpdyFrame
> stream1_body(
5492 spdy_util_
.ConstructSpdyBodyFrame(1, false));
5493 scoped_ptr
<SpdyFrame
> stream1_body2(
5494 spdy_util_
.ConstructSpdyBodyFrame(1, true));
5495 MockRead reads
[] = {
5496 CreateMockRead(*stream1_reply
, 1),
5497 CreateMockRead(*stream1_body
, 2),
5498 CreateMockRead(*stream1_headers
, 3),
5499 CreateMockRead(*stream1_body2
, 5),
5500 MockRead(ASYNC
, 0, 6) // EOF
5503 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
5504 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
5505 BoundNetLog(), GetParam(), NULL
);
5506 helper
.RunToCompletion(&data
);
5507 TransactionHelperResult out
= helper
.output();
5508 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR
, out
.rv
);
5511 TEST_P(SpdyNetworkTransactionTest
, ServerPushCrossOriginCorrectness
) {
5512 // Running these tests via Alt-Svc is too complicated to be worthwhile.
5513 if (GetParam().ssl_type
!= HTTPS_SPDY_VIA_NPN
)
5516 // In this test we want to verify that we can't accidentally push content
5517 // which can't be pushed by this content server.
5518 // This test assumes that:
5519 // - if we're requesting http://www.foo.com/barbaz
5520 // - the browser has made a connection to "www.foo.com".
5522 // A list of the URL to fetch, followed by the URL being pushed.
5523 static const char* const kTestCases
[] = {
5524 "https://www.example.org/foo.html",
5525 "https://www.example.org:81/foo.js", // Bad port
5527 "https://www.example.org/foo.html",
5528 "http://www.example.org/foo.js", // Bad protocol
5530 "https://www.example.org/foo.html",
5531 "ftp://www.example.org/foo.js", // Invalid Protocol
5533 "https://www.example.org/foo.html",
5534 "https://blat.www.example.org/foo.js", // Cross subdomain
5536 "https://www.example.org/foo.html",
5537 "https://www.foo.com/foo.js", // Cross domain
5540 for (size_t index
= 0; index
< arraysize(kTestCases
); index
+= 2) {
5541 const char* url_to_fetch
= kTestCases
[index
];
5542 const char* url_to_push
= kTestCases
[index
+ 1];
5544 scoped_ptr
<SpdyFrame
> stream1_syn(
5545 spdy_util_
.ConstructSpdyGet(url_to_fetch
, false, 1, LOWEST
));
5546 scoped_ptr
<SpdyFrame
> stream1_body(
5547 spdy_util_
.ConstructSpdyBodyFrame(1, true));
5548 scoped_ptr
<SpdyFrame
> push_rst(
5549 spdy_util_
.ConstructSpdyRstStream(2, RST_STREAM_REFUSED_STREAM
));
5550 MockWrite writes
[] = {
5551 CreateMockWrite(*stream1_syn
, 0), CreateMockWrite(*push_rst
, 3),
5554 scoped_ptr
<SpdyFrame
>
5555 stream1_reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
5556 scoped_ptr
<SpdyFrame
>
5557 stream2_syn(spdy_util_
.ConstructSpdyPush(NULL
,
5562 const char kPushedData
[] = "pushed";
5563 scoped_ptr
<SpdyFrame
> stream2_body(
5564 spdy_util_
.ConstructSpdyBodyFrame(
5565 2, kPushedData
, strlen(kPushedData
), true));
5566 scoped_ptr
<SpdyFrame
> rst(
5567 spdy_util_
.ConstructSpdyRstStream(2, RST_STREAM_CANCEL
));
5569 MockRead reads
[] = {
5570 CreateMockRead(*stream1_reply
, 1),
5571 CreateMockRead(*stream2_syn
, 2),
5572 CreateMockRead(*stream1_body
, 4),
5573 CreateMockRead(*stream2_body
, 5),
5574 MockRead(SYNCHRONOUS
, ERR_IO_PENDING
, 6), // Force a pause
5577 HttpResponseInfo response
;
5578 SequencedSocketData
data(reads
, arraysize(reads
), writes
,
5581 HttpRequestInfo request
;
5582 request
.method
= "GET";
5583 request
.url
= GURL(url_to_fetch
);
5584 request
.load_flags
= 0;
5586 // Enable cross-origin push. Since we are not using a proxy, this should
5587 // not actually enable cross-origin SPDY push.
5588 scoped_ptr
<SpdySessionDependencies
> session_deps(
5589 CreateSpdySessionDependencies(GetParam()));
5590 session_deps
->trusted_spdy_proxy
= "123.45.67.89:8080";
5591 NormalSpdyTransactionHelper
helper(request
, DEFAULT_PRIORITY
,
5592 BoundNetLog(), GetParam(),
5593 session_deps
.release());
5594 helper
.RunPreTestSetup();
5595 helper
.AddData(&data
);
5597 HttpNetworkTransaction
* trans
= helper
.trans();
5599 // Start the transaction with basic parameters.
5600 TestCompletionCallback callback
;
5602 int rv
= trans
->Start(&request
, callback
.callback(), BoundNetLog());
5603 EXPECT_EQ(ERR_IO_PENDING
, rv
);
5604 rv
= callback
.WaitForResult();
5606 // Read the response body.
5608 ReadResult(trans
, &result
);
5610 // Verify that we consumed all test data.
5611 EXPECT_TRUE(data
.AllReadDataConsumed());
5612 EXPECT_TRUE(data
.AllWriteDataConsumed());
5614 // Verify the SYN_REPLY.
5615 // Copy the response info, because trans goes away.
5616 response
= *trans
->GetResponseInfo();
5618 VerifyStreamsClosed(helper
);
5620 // Verify the SYN_REPLY.
5621 EXPECT_TRUE(response
.headers
.get() != NULL
);
5622 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
5626 TEST_P(SpdyNetworkTransactionTest
, RetryAfterRefused
) {
5627 // Construct the request.
5628 scoped_ptr
<SpdyFrame
> req(
5629 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
5630 scoped_ptr
<SpdyFrame
> req2(
5631 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 3, LOWEST
, true));
5632 MockWrite writes
[] = {
5633 CreateMockWrite(*req
, 0), CreateMockWrite(*req2
, 2),
5636 scoped_ptr
<SpdyFrame
> refused(
5637 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_REFUSED_STREAM
));
5638 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 3));
5639 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(3, true));
5640 MockRead reads
[] = {
5641 CreateMockRead(*refused
, 1),
5642 CreateMockRead(*resp
, 3),
5643 CreateMockRead(*body
, 4),
5644 MockRead(ASYNC
, 0, 5) // EOF
5647 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
5648 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
5649 BoundNetLog(), GetParam(), NULL
);
5651 helper
.RunPreTestSetup();
5652 helper
.AddData(&data
);
5654 HttpNetworkTransaction
* trans
= helper
.trans();
5656 // Start the transaction with basic parameters.
5657 TestCompletionCallback callback
;
5658 int rv
= trans
->Start(
5659 &CreateGetRequest(), callback
.callback(), BoundNetLog());
5660 EXPECT_EQ(ERR_IO_PENDING
, rv
);
5661 rv
= callback
.WaitForResult();
5664 // Verify that we consumed all test data.
5665 EXPECT_TRUE(data
.AllReadDataConsumed());
5666 EXPECT_TRUE(data
.AllWriteDataConsumed());
5668 // Verify the SYN_REPLY.
5669 HttpResponseInfo response
= *trans
->GetResponseInfo();
5670 EXPECT_TRUE(response
.headers
.get() != NULL
);
5671 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
5674 TEST_P(SpdyNetworkTransactionTest
, OutOfOrderSynStream
) {
5675 // This first request will start to establish the SpdySession.
5676 // Then we will start the second (MEDIUM priority) and then third
5677 // (HIGHEST priority) request in such a way that the third will actually
5678 // start before the second, causing the second to be numbered differently
5679 // than the order they were created.
5680 scoped_ptr
<SpdyFrame
> req1(
5681 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
5682 scoped_ptr
<SpdyFrame
> req2(
5683 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 3, HIGHEST
, true));
5684 scoped_ptr
<SpdyFrame
> req3(
5685 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 5, MEDIUM
, true));
5686 MockWrite writes
[] = {
5687 CreateMockWrite(*req1
, 0),
5688 CreateMockWrite(*req2
, 3),
5689 CreateMockWrite(*req3
, 4),
5692 scoped_ptr
<SpdyFrame
> resp1(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
5693 scoped_ptr
<SpdyFrame
> body1(spdy_util_
.ConstructSpdyBodyFrame(1, true));
5694 scoped_ptr
<SpdyFrame
> resp2(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 3));
5695 scoped_ptr
<SpdyFrame
> body2(spdy_util_
.ConstructSpdyBodyFrame(3, true));
5696 scoped_ptr
<SpdyFrame
> resp3(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 5));
5697 scoped_ptr
<SpdyFrame
> body3(spdy_util_
.ConstructSpdyBodyFrame(5, true));
5698 MockRead reads
[] = {
5699 CreateMockRead(*resp1
, 1),
5700 CreateMockRead(*body1
, 2),
5701 CreateMockRead(*resp2
, 5),
5702 CreateMockRead(*body2
, 6),
5703 CreateMockRead(*resp3
, 7),
5704 CreateMockRead(*body3
, 8),
5705 MockRead(ASYNC
, 0, 9) // EOF
5708 DeterministicSocketData
data(reads
, arraysize(reads
),
5709 writes
, arraysize(writes
));
5710 NormalSpdyTransactionHelper
helper(CreateGetRequest(), LOWEST
,
5711 BoundNetLog(), GetParam(), NULL
);
5712 helper
.SetDeterministic();
5713 helper
.RunPreTestSetup();
5714 helper
.AddDeterministicData(&data
);
5716 // Start the first transaction to set up the SpdySession
5717 HttpNetworkTransaction
* trans
= helper
.trans();
5718 TestCompletionCallback callback
;
5719 HttpRequestInfo info1
= CreateGetRequest();
5720 int rv
= trans
->Start(&info1
, callback
.callback(), BoundNetLog());
5721 EXPECT_EQ(ERR_IO_PENDING
, rv
);
5723 // Run the message loop, but do not allow the write to complete.
5724 // This leaves the SpdySession with a write pending, which prevents
5725 // SpdySession from attempting subsequent writes until this write completes.
5726 base::RunLoop().RunUntilIdle();
5728 // Now, start both new transactions
5729 HttpRequestInfo info2
= CreateGetRequest();
5730 TestCompletionCallback callback2
;
5731 scoped_ptr
<HttpNetworkTransaction
> trans2(
5732 new HttpNetworkTransaction(MEDIUM
, helper
.session().get()));
5733 rv
= trans2
->Start(&info2
, callback2
.callback(), BoundNetLog());
5734 EXPECT_EQ(ERR_IO_PENDING
, rv
);
5735 base::RunLoop().RunUntilIdle();
5737 HttpRequestInfo info3
= CreateGetRequest();
5738 TestCompletionCallback callback3
;
5739 scoped_ptr
<HttpNetworkTransaction
> trans3(
5740 new HttpNetworkTransaction(HIGHEST
, helper
.session().get()));
5741 rv
= trans3
->Start(&info3
, callback3
.callback(), BoundNetLog());
5742 EXPECT_EQ(ERR_IO_PENDING
, rv
);
5743 base::RunLoop().RunUntilIdle();
5745 // We now have two SYN_STREAM frames queued up which will be
5746 // dequeued only once the first write completes, which we
5747 // now allow to happen.
5749 EXPECT_EQ(OK
, callback
.WaitForResult());
5751 // And now we can allow everything else to run to completion.
5754 EXPECT_EQ(OK
, callback2
.WaitForResult());
5755 EXPECT_EQ(OK
, callback3
.WaitForResult());
5757 helper
.VerifyDataConsumed();
5760 // The tests below are only for SPDY/3 and above.
5762 // Test that sent data frames and received WINDOW_UPDATE frames change
5763 // the send_window_size_ correctly.
5765 // WINDOW_UPDATE is different than most other frames in that it can arrive
5766 // while the client is still sending the request body. In order to enforce
5767 // this scenario, we feed a couple of dummy frames and give a delay of 0 to
5768 // socket data provider, so that initial read that is done as soon as the
5769 // stream is created, succeeds and schedules another read. This way reads
5770 // and writes are interleaved; after doing a full frame write, SpdyStream
5771 // will break out of DoLoop and will read and process a WINDOW_UPDATE.
5772 // Once our WINDOW_UPDATE is read, we cannot send SYN_REPLY right away
5773 // since request has not been completely written, therefore we feed
5774 // enough number of WINDOW_UPDATEs to finish the first read and cause a
5775 // write, leading to a complete write of request body; after that we send
5776 // a reply with a body, to cause a graceful shutdown.
5778 // TODO(agayev): develop a socket data provider where both, reads and
5779 // writes are ordered so that writing tests like these are easy and rewrite
5780 // all these tests using it. Right now we are working around the
5781 // limitations as described above and it's not deterministic, tests may
5782 // fail under specific circumstances.
5783 TEST_P(SpdyNetworkTransactionTest
, WindowUpdateReceived
) {
5784 static int kFrameCount
= 2;
5785 scoped_ptr
<std::string
> content(
5786 new std::string(kMaxSpdyFrameChunkSize
, 'a'));
5787 scoped_ptr
<SpdyFrame
> req(spdy_util_
.ConstructSpdyPost(
5788 GetDefaultUrl(), 1, kMaxSpdyFrameChunkSize
* kFrameCount
, LOWEST
, NULL
,
5790 scoped_ptr
<SpdyFrame
> body(
5791 spdy_util_
.ConstructSpdyBodyFrame(
5792 1, content
->c_str(), content
->size(), false));
5793 scoped_ptr
<SpdyFrame
> body_end(
5794 spdy_util_
.ConstructSpdyBodyFrame(
5795 1, content
->c_str(), content
->size(), true));
5797 MockWrite writes
[] = {
5798 CreateMockWrite(*req
, 0),
5799 CreateMockWrite(*body
, 1),
5800 CreateMockWrite(*body_end
, 2),
5803 static const int32 kDeltaWindowSize
= 0xff;
5804 static const int kDeltaCount
= 4;
5805 scoped_ptr
<SpdyFrame
> window_update(
5806 spdy_util_
.ConstructSpdyWindowUpdate(1, kDeltaWindowSize
));
5807 scoped_ptr
<SpdyFrame
> window_update_dummy(
5808 spdy_util_
.ConstructSpdyWindowUpdate(2, kDeltaWindowSize
));
5809 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyPostSynReply(NULL
, 0));
5810 MockRead reads
[] = {
5811 CreateMockRead(*window_update_dummy
, 3),
5812 CreateMockRead(*window_update_dummy
, 4),
5813 CreateMockRead(*window_update_dummy
, 5),
5814 CreateMockRead(*window_update
, 6), // Four updates, therefore window
5815 CreateMockRead(*window_update
, 7), // size should increase by
5816 CreateMockRead(*window_update
, 8), // kDeltaWindowSize * 4
5817 CreateMockRead(*window_update
, 9),
5818 CreateMockRead(*resp
, 10),
5819 CreateMockRead(*body_end
, 11),
5820 MockRead(ASYNC
, 0, 0, 12) // EOF
5823 DeterministicSocketData
data(reads
, arraysize(reads
),
5824 writes
, arraysize(writes
));
5826 ScopedVector
<UploadElementReader
> element_readers
;
5827 for (int i
= 0; i
< kFrameCount
; ++i
) {
5828 element_readers
.push_back(
5829 new UploadBytesElementReader(content
->c_str(), content
->size()));
5831 ElementsUploadDataStream
upload_data_stream(element_readers
.Pass(), 0);
5833 // Setup the request
5834 HttpRequestInfo request
;
5835 request
.method
= "POST";
5836 request
.url
= GURL(GetDefaultUrl());
5837 request
.upload_data_stream
= &upload_data_stream
;
5839 NormalSpdyTransactionHelper
helper(request
, DEFAULT_PRIORITY
,
5840 BoundNetLog(), GetParam(), NULL
);
5841 helper
.SetDeterministic();
5842 helper
.AddDeterministicData(&data
);
5843 helper
.RunPreTestSetup();
5845 HttpNetworkTransaction
* trans
= helper
.trans();
5847 TestCompletionCallback callback
;
5848 int rv
= trans
->Start(&helper
.request(), callback
.callback(), BoundNetLog());
5850 EXPECT_EQ(ERR_IO_PENDING
, rv
);
5854 SpdyHttpStream
* stream
= static_cast<SpdyHttpStream
*>(trans
->stream_
.get());
5855 ASSERT_TRUE(stream
!= NULL
);
5856 ASSERT_TRUE(stream
->stream() != NULL
);
5857 EXPECT_EQ(static_cast<int>(
5858 SpdySession::GetDefaultInitialWindowSize(GetParam().protocol
)) +
5859 kDeltaWindowSize
* kDeltaCount
-
5860 kMaxSpdyFrameChunkSize
* kFrameCount
,
5861 stream
->stream()->send_window_size());
5865 rv
= callback
.WaitForResult();
5868 helper
.VerifyDataConsumed();
5871 // Test that received data frames and sent WINDOW_UPDATE frames change
5872 // the recv_window_size_ correctly.
5873 TEST_P(SpdyNetworkTransactionTest
, WindowUpdateSent
) {
5874 const int32 default_initial_window_size
=
5875 SpdySession::GetDefaultInitialWindowSize(GetParam().protocol
);
5876 // Session level maximum window size that is more than twice the default
5877 // initial window size so that an initial window update is sent.
5878 const int32 session_max_recv_window_size
= 5 * 64 * 1024;
5879 ASSERT_LT(2 * default_initial_window_size
, session_max_recv_window_size
);
5880 // Stream level maximum window size that is less than the session level
5881 // maximum window size so that we test for confusion between the two.
5882 const int32 stream_max_recv_window_size
= 4 * 64 * 1024;
5883 ASSERT_GT(session_max_recv_window_size
, stream_max_recv_window_size
);
5884 // Size of body to be sent. Has to be less than or equal to both window sizes
5885 // so that we do not run out of receiving window. Also has to be greater than
5886 // half of them so that it triggers both a session level and a stream level
5887 // window update frame.
5888 const int32 kTargetSize
= 3 * 64 * 1024;
5889 ASSERT_GE(session_max_recv_window_size
, kTargetSize
);
5890 ASSERT_GE(stream_max_recv_window_size
, kTargetSize
);
5891 ASSERT_LT(session_max_recv_window_size
/ 2, kTargetSize
);
5892 ASSERT_LT(stream_max_recv_window_size
/ 2, kTargetSize
);
5893 // Size of each DATA frame.
5894 const int32 kChunkSize
= 4096;
5895 // Size of window updates.
5896 ASSERT_EQ(0, session_max_recv_window_size
/ 2 % kChunkSize
);
5897 const int32 session_window_update_delta
=
5898 session_max_recv_window_size
/ 2 + kChunkSize
;
5899 ASSERT_EQ(0, stream_max_recv_window_size
/ 2 % kChunkSize
);
5900 const int32 stream_window_update_delta
=
5901 stream_max_recv_window_size
/ 2 + kChunkSize
;
5903 SettingsMap initial_settings
;
5904 initial_settings
[SETTINGS_MAX_CONCURRENT_STREAMS
] =
5905 SettingsFlagsAndValue(SETTINGS_FLAG_NONE
, kMaxConcurrentPushedStreams
);
5906 initial_settings
[SETTINGS_INITIAL_WINDOW_SIZE
] =
5907 SettingsFlagsAndValue(SETTINGS_FLAG_NONE
, stream_max_recv_window_size
);
5908 scoped_ptr
<SpdyFrame
> initial_settings_frame(
5909 spdy_util_
.ConstructSpdySettings(initial_settings
));
5910 scoped_ptr
<SpdyFrame
> initial_window_update(
5911 spdy_util_
.ConstructSpdyWindowUpdate(
5912 kSessionFlowControlStreamId
,
5913 session_max_recv_window_size
- default_initial_window_size
));
5914 scoped_ptr
<SpdyFrame
> req(
5915 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
5916 scoped_ptr
<SpdyFrame
> session_window_update(
5917 spdy_util_
.ConstructSpdyWindowUpdate(0, session_window_update_delta
));
5918 scoped_ptr
<SpdyFrame
> stream_window_update(
5919 spdy_util_
.ConstructSpdyWindowUpdate(1, stream_window_update_delta
));
5921 std::vector
<MockWrite
> writes
;
5922 if ((GetParam().protocol
>= kProtoHTTP2MinimumVersion
) &&
5923 (GetParam().protocol
<= kProtoHTTP2MaximumVersion
)) {
5924 writes
.push_back(MockWrite(ASYNC
, kHttp2ConnectionHeaderPrefix
,
5925 kHttp2ConnectionHeaderPrefixSize
, 0));
5927 writes
.push_back(CreateMockWrite(*initial_settings_frame
, writes
.size()));
5928 writes
.push_back(CreateMockWrite(*initial_window_update
, writes
.size()));
5929 writes
.push_back(CreateMockWrite(*req
, writes
.size()));
5931 std::vector
<MockRead
> reads
;
5932 scoped_ptr
<SpdyFrame
> resp(
5933 spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
5934 reads
.push_back(CreateMockRead(*resp
, writes
.size() + reads
.size()));
5936 ScopedVector
<SpdyFrame
> body_frames
;
5937 const std::string
body_data(kChunkSize
, 'x');
5938 for (size_t remaining
= kTargetSize
; remaining
!= 0;) {
5939 size_t frame_size
= std::min(remaining
, body_data
.size());
5940 body_frames
.push_back(spdy_util_
.ConstructSpdyBodyFrame(
5941 1, body_data
.data(), frame_size
, false));
5943 CreateMockRead(*body_frames
.back(), writes
.size() + reads
.size()));
5944 remaining
-= frame_size
;
5947 MockRead(ASYNC
, ERR_IO_PENDING
, writes
.size() + reads
.size())); // Yield.
5950 CreateMockWrite(*session_window_update
, writes
.size() + reads
.size()));
5952 CreateMockWrite(*stream_window_update
, writes
.size() + reads
.size()));
5954 SequencedSocketData
data(vector_as_array(&reads
), reads
.size(),
5955 vector_as_array(&writes
), writes
.size());
5957 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
5958 BoundNetLog(), GetParam(), NULL
);
5959 helper
.AddData(&data
);
5960 helper
.RunPreTestSetup();
5962 SpdySessionPool
* spdy_session_pool
= helper
.session()->spdy_session_pool();
5963 SpdySessionPoolPeer
pool_peer(spdy_session_pool
);
5964 pool_peer
.SetEnableSendingInitialData(true);
5965 pool_peer
.SetSessionMaxRecvWindowSize(session_max_recv_window_size
);
5966 pool_peer
.SetStreamInitialRecvWindowSize(stream_max_recv_window_size
);
5968 HttpNetworkTransaction
* trans
= helper
.trans();
5969 TestCompletionCallback callback
;
5970 int rv
= trans
->Start(&helper
.request(), callback
.callback(), BoundNetLog());
5972 EXPECT_EQ(ERR_IO_PENDING
, rv
);
5973 rv
= callback
.WaitForResult();
5976 SpdyHttpStream
* stream
=
5977 static_cast<SpdyHttpStream
*>(trans
->stream_
.get());
5978 ASSERT_TRUE(stream
!= NULL
);
5979 ASSERT_TRUE(stream
->stream() != NULL
);
5981 // All data has been read, but not consumed. The window reflects this.
5982 EXPECT_EQ(static_cast<int>(stream_max_recv_window_size
- kTargetSize
),
5983 stream
->stream()->recv_window_size());
5985 const HttpResponseInfo
* response
= trans
->GetResponseInfo();
5986 ASSERT_TRUE(response
!= NULL
);
5987 ASSERT_TRUE(response
->headers
.get() != NULL
);
5988 EXPECT_EQ("HTTP/1.1 200 OK", response
->headers
->GetStatusLine());
5989 EXPECT_TRUE(response
->was_fetched_via_spdy
);
5991 // Issue a read which will cause a WINDOW_UPDATE to be sent and window
5992 // size increased to default.
5993 scoped_refptr
<IOBuffer
> buf(new IOBuffer(kTargetSize
));
5994 EXPECT_EQ(static_cast<int>(kTargetSize
),
5995 trans
->Read(buf
.get(), kTargetSize
, CompletionCallback()));
5996 EXPECT_EQ(static_cast<int>(stream_max_recv_window_size
),
5997 stream
->stream()->recv_window_size());
5998 EXPECT_THAT(base::StringPiece(buf
->data(), kTargetSize
), Each(Eq('x')));
6000 // Allow scheduled WINDOW_UPDATE frames to write.
6001 base::RunLoop().RunUntilIdle();
6002 helper
.VerifyDataConsumed();
6005 // Test that WINDOW_UPDATE frame causing overflow is handled correctly.
6006 TEST_P(SpdyNetworkTransactionTest
, WindowUpdateOverflow
) {
6007 // Number of full frames we hope to write (but will not, used to
6008 // set content-length header correctly)
6009 static int kFrameCount
= 3;
6011 scoped_ptr
<std::string
> content(
6012 new std::string(kMaxSpdyFrameChunkSize
, 'a'));
6013 scoped_ptr
<SpdyFrame
> req(spdy_util_
.ConstructSpdyPost(
6014 GetDefaultUrl(), 1, kMaxSpdyFrameChunkSize
* kFrameCount
, LOWEST
, NULL
,
6016 scoped_ptr
<SpdyFrame
> body(
6017 spdy_util_
.ConstructSpdyBodyFrame(
6018 1, content
->c_str(), content
->size(), false));
6019 scoped_ptr
<SpdyFrame
> rst(
6020 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_FLOW_CONTROL_ERROR
));
6022 // We're not going to write a data frame with FIN, we'll receive a bad
6023 // WINDOW_UPDATE while sending a request and will send a RST_STREAM frame.
6024 MockWrite writes
[] = {
6025 CreateMockWrite(*req
, 0),
6026 CreateMockWrite(*body
, 2),
6027 CreateMockWrite(*rst
, 3),
6030 static const int32 kDeltaWindowSize
= 0x7fffffff; // cause an overflow
6031 scoped_ptr
<SpdyFrame
> window_update(
6032 spdy_util_
.ConstructSpdyWindowUpdate(1, kDeltaWindowSize
));
6033 MockRead reads
[] = {
6034 CreateMockRead(*window_update
, 1),
6035 MockRead(ASYNC
, 0, 4) // EOF
6038 DeterministicSocketData
data(reads
, arraysize(reads
),
6039 writes
, arraysize(writes
));
6041 ScopedVector
<UploadElementReader
> element_readers
;
6042 for (int i
= 0; i
< kFrameCount
; ++i
) {
6043 element_readers
.push_back(
6044 new UploadBytesElementReader(content
->c_str(), content
->size()));
6046 ElementsUploadDataStream
upload_data_stream(element_readers
.Pass(), 0);
6048 // Setup the request
6049 HttpRequestInfo request
;
6050 request
.method
= "POST";
6051 request
.url
= GURL(GetDefaultUrl());
6052 request
.upload_data_stream
= &upload_data_stream
;
6054 NormalSpdyTransactionHelper
helper(request
, DEFAULT_PRIORITY
,
6055 BoundNetLog(), GetParam(), NULL
);
6056 helper
.SetDeterministic();
6057 helper
.RunPreTestSetup();
6058 helper
.AddDeterministicData(&data
);
6059 HttpNetworkTransaction
* trans
= helper
.trans();
6061 TestCompletionCallback callback
;
6062 int rv
= trans
->Start(&helper
.request(), callback
.callback(), BoundNetLog());
6063 ASSERT_EQ(ERR_IO_PENDING
, rv
);
6066 ASSERT_TRUE(callback
.have_result());
6067 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR
, callback
.WaitForResult());
6068 helper
.VerifyDataConsumed();
6071 // Test that after hitting a send window size of 0, the write process
6072 // stalls and upon receiving WINDOW_UPDATE frame write resumes.
6074 // This test constructs a POST request followed by enough data frames
6075 // containing 'a' that would make the window size 0, followed by another
6076 // data frame containing default content (which is "hello!") and this frame
6077 // also contains a FIN flag. SequencedSocketData is used to enforce all
6078 // writes, save the last, go through before a read could happen. The last frame
6079 // ("hello!") is not permitted to go through since by the time its turn
6080 // arrives, window size is 0. At this point MessageLoop::Run() called via
6081 // callback would block. Therefore we call MessageLoop::RunUntilIdle()
6082 // which returns after performing all possible writes. We use DCHECKS to
6083 // ensure that last data frame is still there and stream has stalled.
6084 // After that, next read is artifically enforced, which causes a
6085 // WINDOW_UPDATE to be read and I/O process resumes.
6086 TEST_P(SpdyNetworkTransactionTest
, FlowControlStallResume
) {
6087 const int32 initial_window_size
=
6088 SpdySession::GetDefaultInitialWindowSize(GetParam().protocol
);
6089 // Number of frames we need to send to zero out the window size: data
6090 // frames plus SYN_STREAM plus the last data frame; also we need another
6091 // data frame that we will send once the WINDOW_UPDATE is received,
6093 size_t num_writes
= initial_window_size
/ kMaxSpdyFrameChunkSize
+ 3;
6095 // Calculate last frame's size; 0 size data frame is legal.
6096 size_t last_frame_size
= initial_window_size
% kMaxSpdyFrameChunkSize
;
6098 // Construct content for a data frame of maximum size.
6099 std::string
content(kMaxSpdyFrameChunkSize
, 'a');
6101 scoped_ptr
<SpdyFrame
> req(spdy_util_
.ConstructSpdyPost(
6102 GetDefaultUrl(), 1, initial_window_size
+ kUploadDataSize
, LOWEST
, NULL
,
6106 scoped_ptr
<SpdyFrame
> body1(
6107 spdy_util_
.ConstructSpdyBodyFrame(
6108 1, content
.c_str(), content
.size(), false));
6110 // Last frame to zero out the window size.
6111 scoped_ptr
<SpdyFrame
> body2(
6112 spdy_util_
.ConstructSpdyBodyFrame(
6113 1, content
.c_str(), last_frame_size
, false));
6115 // Data frame to be sent once WINDOW_UPDATE frame is received.
6116 scoped_ptr
<SpdyFrame
> body3(spdy_util_
.ConstructSpdyBodyFrame(1, true));
6118 // Fill in mock writes.
6119 scoped_ptr
<MockWrite
[]> writes(new MockWrite
[num_writes
]);
6121 writes
[i
] = CreateMockWrite(*req
, i
);
6122 for (i
= 1; i
< num_writes
- 2; i
++)
6123 writes
[i
] = CreateMockWrite(*body1
, i
);
6124 writes
[i
] = CreateMockWrite(*body2
, i
);
6125 // The last write must not be attempted until after the WINDOW_UPDATES
6126 // have been received.
6127 writes
[i
+ 1] = CreateMockWrite(*body3
, i
+ 4, SYNCHRONOUS
);
6129 // Construct read frame, give enough space to upload the rest of the
6131 scoped_ptr
<SpdyFrame
> session_window_update(
6132 spdy_util_
.ConstructSpdyWindowUpdate(0, kUploadDataSize
));
6133 scoped_ptr
<SpdyFrame
> window_update(
6134 spdy_util_
.ConstructSpdyWindowUpdate(1, kUploadDataSize
));
6135 scoped_ptr
<SpdyFrame
> reply(spdy_util_
.ConstructSpdyPostSynReply(NULL
, 0));
6136 MockRead reads
[] = {
6137 MockRead(ASYNC
, ERR_IO_PENDING
, i
+ 1), // Force a pause
6138 CreateMockRead(*session_window_update
, i
+ 2),
6139 CreateMockRead(*window_update
, i
+ 3),
6140 // Now the last write will occur.
6141 CreateMockRead(*reply
, i
+ 5),
6142 CreateMockRead(*body2
, i
+ 6),
6143 CreateMockRead(*body3
, i
+ 7),
6144 MockRead(ASYNC
, 0, i
+ 8) // EOF
6147 SequencedSocketData
data(reads
, arraysize(reads
), writes
.get(), num_writes
);
6149 ScopedVector
<UploadElementReader
> element_readers
;
6150 std::string
upload_data_string(initial_window_size
, 'a');
6151 upload_data_string
.append(kUploadData
, kUploadDataSize
);
6152 element_readers
.push_back(new UploadBytesElementReader(
6153 upload_data_string
.c_str(), upload_data_string
.size()));
6154 ElementsUploadDataStream
upload_data_stream(element_readers
.Pass(), 0);
6156 HttpRequestInfo request
;
6157 request
.method
= "POST";
6158 request
.url
= GURL(GetDefaultUrl());
6159 request
.upload_data_stream
= &upload_data_stream
;
6160 NormalSpdyTransactionHelper
helper(request
, DEFAULT_PRIORITY
,
6161 BoundNetLog(), GetParam(), NULL
);
6162 helper
.AddData(&data
);
6163 helper
.RunPreTestSetup();
6165 HttpNetworkTransaction
* trans
= helper
.trans();
6167 TestCompletionCallback callback
;
6168 int rv
= trans
->Start(&helper
.request(), callback
.callback(), BoundNetLog());
6169 EXPECT_EQ(ERR_IO_PENDING
, rv
);
6171 base::RunLoop().RunUntilIdle(); // Write as much as we can.
6173 SpdyHttpStream
* stream
= static_cast<SpdyHttpStream
*>(trans
->stream_
.get());
6174 ASSERT_TRUE(stream
!= NULL
);
6175 ASSERT_TRUE(stream
->stream() != NULL
);
6176 EXPECT_EQ(0, stream
->stream()->send_window_size());
6177 // All the body data should have been read.
6178 // TODO(satorux): This is because of the weirdness in reading the request
6179 // body in OnSendBodyComplete(). See crbug.com/113107.
6180 EXPECT_TRUE(upload_data_stream
.IsEOF());
6181 // But the body is not yet fully sent (kUploadData is not yet sent)
6182 // since we're send-stalled.
6183 EXPECT_TRUE(stream
->stream()->send_stalled_by_flow_control());
6185 data
.CompleteRead(); // Read in WINDOW_UPDATE frame.
6186 rv
= callback
.WaitForResult();
6187 helper
.VerifyDataConsumed();
6190 // Test we correctly handle the case where the SETTINGS frame results in
6191 // unstalling the send window.
6192 TEST_P(SpdyNetworkTransactionTest
, FlowControlStallResumeAfterSettings
) {
6193 const int32 initial_window_size
=
6194 SpdySession::GetDefaultInitialWindowSize(GetParam().protocol
);
6196 // Number of frames we need to send to zero out the window size: data
6197 // frames plus SYN_STREAM plus the last data frame; also we need another
6198 // data frame that we will send once the SETTING is received, therefore +3.
6199 size_t num_writes
= initial_window_size
/ kMaxSpdyFrameChunkSize
+ 3;
6201 // Calculate last frame's size; 0 size data frame is legal.
6202 size_t last_frame_size
= initial_window_size
% kMaxSpdyFrameChunkSize
;
6204 // Construct content for a data frame of maximum size.
6205 std::string
content(kMaxSpdyFrameChunkSize
, 'a');
6207 scoped_ptr
<SpdyFrame
> req(spdy_util_
.ConstructSpdyPost(
6208 GetDefaultUrl(), 1, initial_window_size
+ kUploadDataSize
, LOWEST
, NULL
,
6212 scoped_ptr
<SpdyFrame
> body1(
6213 spdy_util_
.ConstructSpdyBodyFrame(
6214 1, content
.c_str(), content
.size(), false));
6216 // Last frame to zero out the window size.
6217 scoped_ptr
<SpdyFrame
> body2(
6218 spdy_util_
.ConstructSpdyBodyFrame(
6219 1, content
.c_str(), last_frame_size
, false));
6221 // Data frame to be sent once SETTINGS frame is received.
6222 scoped_ptr
<SpdyFrame
> body3(spdy_util_
.ConstructSpdyBodyFrame(1, true));
6224 // Fill in mock reads/writes.
6225 std::vector
<MockRead
> reads
;
6226 std::vector
<MockWrite
> writes
;
6228 writes
.push_back(CreateMockWrite(*req
, i
++));
6229 while (i
< num_writes
- 2)
6230 writes
.push_back(CreateMockWrite(*body1
, i
++));
6231 writes
.push_back(CreateMockWrite(*body2
, i
++));
6233 // Construct read frame for SETTINGS that gives enough space to upload the
6234 // rest of the data.
6235 SettingsMap settings
;
6236 settings
[SETTINGS_INITIAL_WINDOW_SIZE
] =
6237 SettingsFlagsAndValue(SETTINGS_FLAG_NONE
, initial_window_size
* 2);
6238 scoped_ptr
<SpdyFrame
> settings_frame_large(
6239 spdy_util_
.ConstructSpdySettings(settings
));
6241 reads
.push_back(CreateMockRead(*settings_frame_large
, i
++));
6243 scoped_ptr
<SpdyFrame
> session_window_update(
6244 spdy_util_
.ConstructSpdyWindowUpdate(0, kUploadDataSize
));
6245 if (GetParam().protocol
>= kProtoSPDY31
)
6246 reads
.push_back(CreateMockRead(*session_window_update
, i
++));
6248 scoped_ptr
<SpdyFrame
> settings_ack(spdy_util_
.ConstructSpdySettingsAck());
6249 writes
.push_back(CreateMockWrite(*settings_ack
, i
++));
6251 writes
.push_back(CreateMockWrite(*body3
, i
++));
6253 scoped_ptr
<SpdyFrame
> reply(spdy_util_
.ConstructSpdyPostSynReply(NULL
, 0));
6254 reads
.push_back(CreateMockRead(*reply
, i
++));
6255 reads
.push_back(CreateMockRead(*body2
, i
++));
6256 reads
.push_back(CreateMockRead(*body3
, i
++));
6257 reads
.push_back(MockRead(ASYNC
, 0, i
++)); // EOF
6259 // Force all writes to happen before any read, last write will not
6260 // actually queue a frame, due to window size being 0.
6261 DeterministicSocketData
data(vector_as_array(&reads
), reads
.size(),
6262 vector_as_array(&writes
), writes
.size());
6264 ScopedVector
<UploadElementReader
> element_readers
;
6265 std::string
upload_data_string(initial_window_size
, 'a');
6266 upload_data_string
.append(kUploadData
, kUploadDataSize
);
6267 element_readers
.push_back(new UploadBytesElementReader(
6268 upload_data_string
.c_str(), upload_data_string
.size()));
6269 ElementsUploadDataStream
upload_data_stream(element_readers
.Pass(), 0);
6271 HttpRequestInfo request
;
6272 request
.method
= "POST";
6273 request
.url
= GURL(GetDefaultUrl());
6274 request
.upload_data_stream
= &upload_data_stream
;
6275 NormalSpdyTransactionHelper
helper(request
, DEFAULT_PRIORITY
,
6276 BoundNetLog(), GetParam(), NULL
);
6277 helper
.SetDeterministic();
6278 helper
.RunPreTestSetup();
6279 helper
.AddDeterministicData(&data
);
6281 HttpNetworkTransaction
* trans
= helper
.trans();
6283 TestCompletionCallback callback
;
6284 int rv
= trans
->Start(&helper
.request(), callback
.callback(), BoundNetLog());
6285 EXPECT_EQ(ERR_IO_PENDING
, rv
);
6287 data
.RunFor(num_writes
- 1); // Write as much as we can.
6289 SpdyHttpStream
* stream
= static_cast<SpdyHttpStream
*>(trans
->stream_
.get());
6290 ASSERT_TRUE(stream
!= NULL
);
6291 ASSERT_TRUE(stream
->stream() != NULL
);
6292 EXPECT_EQ(0, stream
->stream()->send_window_size());
6294 // All the body data should have been read.
6295 // TODO(satorux): This is because of the weirdness in reading the request
6296 // body in OnSendBodyComplete(). See crbug.com/113107.
6297 EXPECT_TRUE(upload_data_stream
.IsEOF());
6298 // But the body is not yet fully sent (kUploadData is not yet sent)
6299 // since we're send-stalled.
6300 EXPECT_TRUE(stream
->stream()->send_stalled_by_flow_control());
6302 data
.RunFor(7); // Read in SETTINGS frame to unstall.
6303 rv
= callback
.WaitForResult();
6304 helper
.VerifyDataConsumed();
6305 // If stream is NULL, that means it was unstalled and closed.
6306 EXPECT_TRUE(stream
->stream() == NULL
);
6309 // Test we correctly handle the case where the SETTINGS frame results in a
6310 // negative send window size.
6311 TEST_P(SpdyNetworkTransactionTest
, FlowControlNegativeSendWindowSize
) {
6312 const int32 initial_window_size
=
6313 SpdySession::GetDefaultInitialWindowSize(GetParam().protocol
);
6314 // Number of frames we need to send to zero out the window size: data
6315 // frames plus SYN_STREAM plus the last data frame; also we need another
6316 // data frame that we will send once the SETTING is received, therefore +3.
6317 size_t num_writes
= initial_window_size
/ kMaxSpdyFrameChunkSize
+ 3;
6319 // Calculate last frame's size; 0 size data frame is legal.
6320 size_t last_frame_size
= initial_window_size
% kMaxSpdyFrameChunkSize
;
6322 // Construct content for a data frame of maximum size.
6323 std::string
content(kMaxSpdyFrameChunkSize
, 'a');
6325 scoped_ptr
<SpdyFrame
> req(spdy_util_
.ConstructSpdyPost(
6326 GetDefaultUrl(), 1, initial_window_size
+ kUploadDataSize
, LOWEST
, NULL
,
6330 scoped_ptr
<SpdyFrame
> body1(
6331 spdy_util_
.ConstructSpdyBodyFrame(
6332 1, content
.c_str(), content
.size(), false));
6334 // Last frame to zero out the window size.
6335 scoped_ptr
<SpdyFrame
> body2(
6336 spdy_util_
.ConstructSpdyBodyFrame(
6337 1, content
.c_str(), last_frame_size
, false));
6339 // Data frame to be sent once SETTINGS frame is received.
6340 scoped_ptr
<SpdyFrame
> body3(spdy_util_
.ConstructSpdyBodyFrame(1, true));
6342 // Fill in mock reads/writes.
6343 std::vector
<MockRead
> reads
;
6344 std::vector
<MockWrite
> writes
;
6346 writes
.push_back(CreateMockWrite(*req
, i
++));
6347 while (i
< num_writes
- 2)
6348 writes
.push_back(CreateMockWrite(*body1
, i
++));
6349 writes
.push_back(CreateMockWrite(*body2
, i
++));
6351 // Construct read frame for SETTINGS that makes the send_window_size
6353 SettingsMap new_settings
;
6354 new_settings
[SETTINGS_INITIAL_WINDOW_SIZE
] =
6355 SettingsFlagsAndValue(SETTINGS_FLAG_NONE
, initial_window_size
/ 2);
6356 scoped_ptr
<SpdyFrame
> settings_frame_small(
6357 spdy_util_
.ConstructSpdySettings(new_settings
));
6358 // Construct read frames for WINDOW_UPDATE that makes the send_window_size
6360 scoped_ptr
<SpdyFrame
> session_window_update_init_size(
6361 spdy_util_
.ConstructSpdyWindowUpdate(0, initial_window_size
));
6362 scoped_ptr
<SpdyFrame
> window_update_init_size(
6363 spdy_util_
.ConstructSpdyWindowUpdate(1, initial_window_size
));
6365 reads
.push_back(CreateMockRead(*settings_frame_small
, i
++));
6366 reads
.push_back(CreateMockRead(*session_window_update_init_size
, i
++));
6367 reads
.push_back(CreateMockRead(*window_update_init_size
, i
++));
6369 scoped_ptr
<SpdyFrame
> settings_ack(spdy_util_
.ConstructSpdySettingsAck());
6370 writes
.push_back(CreateMockWrite(*settings_ack
, i
++));
6372 writes
.push_back(CreateMockWrite(*body3
, i
++));
6374 scoped_ptr
<SpdyFrame
> reply(spdy_util_
.ConstructSpdyPostSynReply(NULL
, 0));
6375 reads
.push_back(CreateMockRead(*reply
, i
++));
6376 reads
.push_back(CreateMockRead(*body2
, i
++));
6377 reads
.push_back(CreateMockRead(*body3
, i
++));
6378 reads
.push_back(MockRead(ASYNC
, 0, i
++)); // EOF
6380 // Force all writes to happen before any read, last write will not
6381 // actually queue a frame, due to window size being 0.
6382 DeterministicSocketData
data(vector_as_array(&reads
), reads
.size(),
6383 vector_as_array(&writes
), writes
.size());
6385 ScopedVector
<UploadElementReader
> element_readers
;
6386 std::string
upload_data_string(initial_window_size
, 'a');
6387 upload_data_string
.append(kUploadData
, kUploadDataSize
);
6388 element_readers
.push_back(new UploadBytesElementReader(
6389 upload_data_string
.c_str(), upload_data_string
.size()));
6390 ElementsUploadDataStream
upload_data_stream(element_readers
.Pass(), 0);
6392 HttpRequestInfo request
;
6393 request
.method
= "POST";
6394 request
.url
= GURL(GetDefaultUrl());
6395 request
.upload_data_stream
= &upload_data_stream
;
6396 NormalSpdyTransactionHelper
helper(request
, DEFAULT_PRIORITY
,
6397 BoundNetLog(), GetParam(), NULL
);
6398 helper
.SetDeterministic();
6399 helper
.RunPreTestSetup();
6400 helper
.AddDeterministicData(&data
);
6402 HttpNetworkTransaction
* trans
= helper
.trans();
6404 TestCompletionCallback callback
;
6405 int rv
= trans
->Start(&helper
.request(), callback
.callback(), BoundNetLog());
6406 EXPECT_EQ(ERR_IO_PENDING
, rv
);
6408 data
.RunFor(num_writes
- 1); // Write as much as we can.
6410 SpdyHttpStream
* stream
= static_cast<SpdyHttpStream
*>(trans
->stream_
.get());
6411 ASSERT_TRUE(stream
!= NULL
);
6412 ASSERT_TRUE(stream
->stream() != NULL
);
6413 EXPECT_EQ(0, stream
->stream()->send_window_size());
6415 // All the body data should have been read.
6416 // TODO(satorux): This is because of the weirdness in reading the request
6417 // body in OnSendBodyComplete(). See crbug.com/113107.
6418 EXPECT_TRUE(upload_data_stream
.IsEOF());
6419 // But the body is not yet fully sent (kUploadData is not yet sent)
6420 // since we're send-stalled.
6421 EXPECT_TRUE(stream
->stream()->send_stalled_by_flow_control());
6423 // Read in WINDOW_UPDATE or SETTINGS frame.
6424 data
.RunFor((GetParam().protocol
>= kProtoSPDY31
) ? 9 : 8);
6425 rv
= callback
.WaitForResult();
6426 helper
.VerifyDataConsumed();
6429 TEST_P(SpdyNetworkTransactionTest
, GoAwayOnOddPushStreamId
) {
6430 if (spdy_util_
.spdy_version() < SPDY3
)
6433 scoped_ptr
<SpdyHeaderBlock
> push_headers(new SpdyHeaderBlock
);
6434 spdy_util_
.AddUrlToHeaderBlock("http://www.example.org/a.dat",
6435 push_headers
.get());
6436 scoped_ptr
<SpdyFrame
> push(
6437 spdy_util_
.ConstructInitialSpdyPushFrame(push_headers
.Pass(), 3, 1));
6438 MockRead reads
[] = {CreateMockRead(*push
, 1)};
6440 scoped_ptr
<SpdyFrame
> req(
6441 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
6442 scoped_ptr
<SpdyFrame
> goaway(spdy_util_
.ConstructSpdyGoAway(
6443 0, GOAWAY_PROTOCOL_ERROR
, "Odd push stream id."));
6444 MockWrite writes
[] = {
6445 CreateMockWrite(*req
, 0), CreateMockWrite(*goaway
, 2),
6448 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
6449 NormalSpdyTransactionHelper
helper(
6450 CreateGetRequest(), DEFAULT_PRIORITY
, BoundNetLog(), GetParam(), NULL
);
6451 helper
.RunToCompletion(&data
);
6452 TransactionHelperResult out
= helper
.output();
6453 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR
, out
.rv
);
6456 TEST_P(SpdyNetworkTransactionTest
,
6457 GoAwayOnPushStreamIdLesserOrEqualThanLastAccepted
) {
6458 if (spdy_util_
.spdy_version() < SPDY3
)
6461 scoped_ptr
<SpdyFrame
> push_a(spdy_util_
.ConstructSpdyPush(
6462 NULL
, 0, 4, 1, GetDefaultUrlWithPath("/a.dat").c_str()));
6463 scoped_ptr
<SpdyHeaderBlock
> push_b_headers(new SpdyHeaderBlock
);
6464 spdy_util_
.AddUrlToHeaderBlock(GetDefaultUrlWithPath("/b.dat"),
6465 push_b_headers
.get());
6466 scoped_ptr
<SpdyFrame
> push_b(
6467 spdy_util_
.ConstructInitialSpdyPushFrame(push_b_headers
.Pass(), 2, 1));
6468 MockRead reads
[] = {
6469 CreateMockRead(*push_a
, 1), CreateMockRead(*push_b
, 2),
6472 scoped_ptr
<SpdyFrame
> req(
6473 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
6474 scoped_ptr
<SpdyFrame
> goaway(spdy_util_
.ConstructSpdyGoAway(
6476 GOAWAY_PROTOCOL_ERROR
,
6477 "New push stream id must be greater than the last accepted."));
6478 MockWrite writes
[] = {
6479 CreateMockWrite(*req
, 0), CreateMockWrite(*goaway
, 3),
6482 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
6483 NormalSpdyTransactionHelper
helper(
6484 CreateGetRequest(), DEFAULT_PRIORITY
, BoundNetLog(), GetParam(), NULL
);
6485 helper
.RunToCompletion(&data
);
6486 TransactionHelperResult out
= helper
.output();
6487 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR
, out
.rv
);
6490 // Regression test for https://crbug.com/493348: request header exceeds 16 kB
6491 // and thus sent in multiple frames when using HTTP/2.
6492 TEST_P(SpdyNetworkTransactionTest
, LargeRequest
) {
6493 const std::string
kKey("foo");
6494 const std::string
kValue(1 << 15, 'z');
6496 HttpRequestInfo request
;
6497 request
.method
= "GET";
6498 request
.url
= GURL(GetDefaultUrl());
6499 request
.extra_headers
.SetHeader(kKey
, kValue
);
6501 scoped_ptr
<SpdyHeaderBlock
> headers(
6502 spdy_util_
.ConstructGetHeaderBlock(GetDefaultUrl()));
6503 (*headers
)[kKey
] = kValue
;
6504 scoped_ptr
<SpdyFrame
> req(
6505 spdy_util_
.ConstructSpdySyn(1, *headers
, LOWEST
, false, true));
6506 MockWrite writes
[] = {
6507 CreateMockWrite(*req
, 0),
6510 scoped_ptr
<SpdyFrame
> resp(
6511 spdy_util_
.ConstructSpdyGetSynReply(nullptr, 0, 1));
6512 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
6513 MockRead reads
[] = {
6514 CreateMockRead(*resp
, 1),
6515 CreateMockRead(*body
, 2),
6516 MockRead(ASYNC
, 0, 3) // EOF
6519 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
6520 NormalSpdyTransactionHelper
helper(request
, DEFAULT_PRIORITY
, BoundNetLog(),
6521 GetParam(), nullptr);
6522 helper
.RunToCompletion(&data
);
6523 TransactionHelperResult out
= helper
.output();
6525 EXPECT_EQ(OK
, out
.rv
);
6526 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
6527 EXPECT_EQ("hello!", out
.response_data
);
6530 class SpdyNetworkTransactionNoTLSUsageCheckTest
6531 : public SpdyNetworkTransactionTest
{
6533 void RunNoTLSUsageCheckTest(scoped_ptr
<SSLSocketDataProvider
> ssl_provider
) {
6534 // Construct the request.
6535 scoped_ptr
<SpdyFrame
> req(
6536 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
6537 MockWrite writes
[] = {CreateMockWrite(*req
, 0)};
6539 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
6540 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
6541 MockRead reads
[] = {
6542 CreateMockRead(*resp
, 1),
6543 CreateMockRead(*body
, 2),
6544 MockRead(ASYNC
, 0, 3) // EOF
6547 SequencedSocketData
data(reads
, arraysize(reads
), writes
,
6549 HttpRequestInfo request
;
6550 request
.method
= "GET";
6551 request
.url
= GURL("https://www.example.org/");
6552 NormalSpdyTransactionHelper
helper(
6553 request
, DEFAULT_PRIORITY
, BoundNetLog(), GetParam(), NULL
);
6554 helper
.RunToCompletionWithSSLData(&data
, ssl_provider
.Pass());
6555 TransactionHelperResult out
= helper
.output();
6556 EXPECT_EQ(OK
, out
.rv
);
6557 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
6558 EXPECT_EQ("hello!", out
.response_data
);
6562 //-----------------------------------------------------------------------------
6563 // All tests are run with three different connection types: SPDY after NPN
6564 // negotiation, SPDY without SSL, and SPDY with SSL.
6566 // TODO(akalin): Use ::testing::Combine() when we are able to use
6568 INSTANTIATE_TEST_CASE_P(
6570 SpdyNetworkTransactionNoTLSUsageCheckTest
,
6571 ::testing::Values(SpdyNetworkTransactionTestParams(kProtoSPDY31
,
6572 HTTPS_SPDY_VIA_NPN
)));
6574 TEST_P(SpdyNetworkTransactionNoTLSUsageCheckTest
, TLSVersionTooOld
) {
6575 scoped_ptr
<SSLSocketDataProvider
> ssl_provider(
6576 new SSLSocketDataProvider(ASYNC
, OK
));
6577 SSLConnectionStatusSetVersion(SSL_CONNECTION_VERSION_SSL3
,
6578 &ssl_provider
->connection_status
);
6580 RunNoTLSUsageCheckTest(ssl_provider
.Pass());
6583 TEST_P(SpdyNetworkTransactionNoTLSUsageCheckTest
, TLSCipherSuiteSucky
) {
6584 scoped_ptr
<SSLSocketDataProvider
> ssl_provider(
6585 new SSLSocketDataProvider(ASYNC
, OK
));
6586 // Set to TLS_RSA_WITH_NULL_MD5
6587 SSLConnectionStatusSetCipherSuite(0x1, &ssl_provider
->connection_status
);
6589 RunNoTLSUsageCheckTest(ssl_provider
.Pass());
6592 class SpdyNetworkTransactionTLSUsageCheckTest
6593 : public SpdyNetworkTransactionTest
{
6595 void RunTLSUsageCheckTest(scoped_ptr
<SSLSocketDataProvider
> ssl_provider
) {
6596 scoped_ptr
<SpdyFrame
> goaway(
6597 spdy_util_
.ConstructSpdyGoAway(0, GOAWAY_INADEQUATE_SECURITY
, ""));
6598 MockWrite writes
[] = {CreateMockWrite(*goaway
)};
6600 StaticSocketDataProvider
data(NULL
, 0, writes
, arraysize(writes
));
6601 HttpRequestInfo request
;
6602 request
.method
= "GET";
6603 request
.url
= GURL("https://www.example.org/");
6604 NormalSpdyTransactionHelper
helper(
6605 request
, DEFAULT_PRIORITY
, BoundNetLog(), GetParam(), NULL
);
6606 helper
.RunToCompletionWithSSLData(&data
, ssl_provider
.Pass());
6607 TransactionHelperResult out
= helper
.output();
6608 EXPECT_EQ(ERR_SPDY_INADEQUATE_TRANSPORT_SECURITY
, out
.rv
);
6612 INSTANTIATE_TEST_CASE_P(
6614 SpdyNetworkTransactionTLSUsageCheckTest
,
6616 SpdyNetworkTransactionTestParams(kProtoHTTP2_14
, HTTPS_SPDY_VIA_NPN
),
6617 SpdyNetworkTransactionTestParams(kProtoHTTP2
, HTTPS_SPDY_VIA_NPN
)));
6619 TEST_P(SpdyNetworkTransactionTLSUsageCheckTest
, TLSVersionTooOld
) {
6620 scoped_ptr
<SSLSocketDataProvider
> ssl_provider(
6621 new SSLSocketDataProvider(ASYNC
, OK
));
6622 SSLConnectionStatusSetVersion(SSL_CONNECTION_VERSION_SSL3
,
6623 &ssl_provider
->connection_status
);
6625 RunTLSUsageCheckTest(ssl_provider
.Pass());
6628 TEST_P(SpdyNetworkTransactionTLSUsageCheckTest
, TLSCipherSuiteSucky
) {
6629 scoped_ptr
<SSLSocketDataProvider
> ssl_provider(
6630 new SSLSocketDataProvider(ASYNC
, OK
));
6631 // Set to TLS_RSA_WITH_NULL_MD5
6632 SSLConnectionStatusSetCipherSuite(0x1, &ssl_provider
->connection_status
);
6634 RunTLSUsageCheckTest(ssl_provider
.Pass());