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 base::Time expiration
= base::Time::Now() + base::TimeDelta::FromDays(1);
100 session_deps
->http_server_properties
.SetAlternativeService(
101 HostPortPair("www.example.org", 80),
102 AlternativeService(AlternateProtocolFromNextProto(test_params
.protocol
),
103 "www.example.org", 443),
108 SpdySessionDependencies
* CreateSpdySessionDependencies(
109 SpdyNetworkTransactionTestParams test_params
) {
110 SpdySessionDependencies
* session_deps
=
111 new SpdySessionDependencies(test_params
.protocol
);
112 UpdateSpdySessionDependencies(test_params
, session_deps
);
116 SpdySessionDependencies
* CreateSpdySessionDependencies(
117 SpdyNetworkTransactionTestParams test_params
,
118 ProxyService
* proxy_service
) {
119 SpdySessionDependencies
* session_deps
=
120 new SpdySessionDependencies(test_params
.protocol
, proxy_service
);
121 UpdateSpdySessionDependencies(test_params
, session_deps
);
127 class SpdyNetworkTransactionTest
128 : public ::testing::TestWithParam
<SpdyNetworkTransactionTestParams
> {
130 SpdyNetworkTransactionTest() : spdy_util_(GetParam().protocol
) {
131 spdy_util_
.set_default_url(GURL(GetDefaultUrl()));
134 virtual ~SpdyNetworkTransactionTest() {
135 // UploadDataStream may post a deletion tasks back to the message loop on
137 upload_data_stream_
.reset();
138 base::RunLoop().RunUntilIdle();
141 void SetUp() override
{
142 get_request_initialized_
= false;
143 post_request_initialized_
= false;
144 chunked_post_request_initialized_
= false;
145 ASSERT_TRUE(temp_dir_
.CreateUniqueTempDir());
148 struct TransactionHelperResult
{
150 std::string status_line
;
151 std::string response_data
;
152 HttpResponseInfo response_info
;
155 // A helper class that handles all the initial npn/ssl setup.
156 class NormalSpdyTransactionHelper
{
158 NormalSpdyTransactionHelper(const HttpRequestInfo
& request
,
159 RequestPriority priority
,
160 const BoundNetLog
& log
,
161 SpdyNetworkTransactionTestParams test_params
,
162 SpdySessionDependencies
* session_deps
)
165 session_deps_(session_deps
== NULL
166 ? CreateSpdySessionDependencies(test_params
)
169 SpdySessionDependencies::SpdyCreateSession(session_deps_
.get())),
171 test_params_(test_params
),
173 deterministic_(false),
174 spdy_enabled_(true) {}
176 ~NormalSpdyTransactionHelper() {
177 // Any test which doesn't close the socket by sending it an EOF will
178 // have a valid session left open, which leaks the entire session pool.
179 // This is just fine - in fact, some of our tests intentionally do this
180 // so that we can check consistency of the SpdySessionPool as the test
181 // finishes. If we had put an EOF on the socket, the SpdySession would
182 // have closed and we wouldn't be able to check the consistency.
184 // Forcefully close existing sessions here.
185 session()->spdy_session_pool()->CloseAllSessions();
188 void SetDeterministic() {
189 session_
= SpdySessionDependencies::SpdyCreateSessionDeterministic(
190 session_deps_
.get());
191 deterministic_
= true;
194 void SetSpdyDisabled() {
195 spdy_enabled_
= false;
196 port_
= test_params_
.ssl_type
== HTTP_SPDY_VIA_ALT_SVC
? 80 : 443;
199 void RunPreTestSetup() {
200 if (!session_deps_
.get())
201 session_deps_
.reset(CreateSpdySessionDependencies(test_params_
));
202 if (!session_
.get()) {
203 session_
= SpdySessionDependencies::SpdyCreateSession(
204 session_deps_
.get());
207 // We're now ready to use SSL-npn SPDY.
208 trans_
.reset(new HttpNetworkTransaction(priority_
, session_
.get()));
211 // Start the transaction, read some data, finish.
212 void RunDefaultTest() {
213 if (!StartDefaultTest())
218 bool StartDefaultTest() {
219 output_
.rv
= trans_
->Start(&request_
, callback_
.callback(), log_
);
221 // We expect an IO Pending or some sort of error.
222 EXPECT_LT(output_
.rv
, 0);
223 return output_
.rv
== ERR_IO_PENDING
;
226 void FinishDefaultTest() {
227 output_
.rv
= callback_
.WaitForResult();
228 if (output_
.rv
!= OK
) {
229 session_
->spdy_session_pool()->CloseCurrentSessions(ERR_ABORTED
);
234 const HttpResponseInfo
* response
= trans_
->GetResponseInfo();
235 ASSERT_TRUE(response
!= NULL
);
236 ASSERT_TRUE(response
->headers
.get() != NULL
);
237 EXPECT_EQ("HTTP/1.1 200 OK", response
->headers
->GetStatusLine());
238 EXPECT_EQ(spdy_enabled_
, response
->was_fetched_via_spdy
);
239 if (HttpStreamFactory::spdy_enabled()) {
241 HttpResponseInfo::ConnectionInfoFromNextProto(
242 test_params_
.protocol
),
243 response
->connection_info
);
245 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP1
,
246 response
->connection_info
);
249 EXPECT_TRUE(response
->was_npn_negotiated
);
251 // If SPDY is disabled, an HTTP request should not be diverted
252 // over an SSL session.
253 EXPECT_EQ(request_
.url
.SchemeIs("https"),
254 response
->was_npn_negotiated
);
256 EXPECT_EQ("127.0.0.1", response
->socket_address
.host());
257 EXPECT_EQ(port_
, response
->socket_address
.port());
258 output_
.status_line
= response
->headers
->GetStatusLine();
259 output_
.response_info
= *response
; // Make a copy so we can verify.
260 output_
.rv
= ReadTransaction(trans_
.get(), &output_
.response_data
);
263 void FinishDefaultTestWithoutVerification() {
264 output_
.rv
= callback_
.WaitForResult();
265 if (output_
.rv
!= OK
)
266 session_
->spdy_session_pool()->CloseCurrentSessions(ERR_ABORTED
);
269 // Most tests will want to call this function. In particular, the MockReads
270 // should end with an empty read, and that read needs to be processed to
271 // ensure proper deletion of the spdy_session_pool.
272 void VerifyDataConsumed() {
273 for (const SocketDataProvider
* provider
: data_vector_
) {
274 EXPECT_TRUE(provider
->AllReadDataConsumed());
275 EXPECT_TRUE(provider
->AllWriteDataConsumed());
277 for (const DeterministicSocketData
* provider
:
278 deterministic_data_vector_
) {
279 EXPECT_TRUE(provider
->AllReadDataConsumed());
280 EXPECT_TRUE(provider
->AllWriteDataConsumed());
284 // Occasionally a test will expect to error out before certain reads are
285 // processed. In that case we want to explicitly ensure that the reads were
287 void VerifyDataNotConsumed() {
288 for (const SocketDataProvider
* provider
: data_vector_
) {
289 EXPECT_FALSE(provider
->AllReadDataConsumed());
290 EXPECT_FALSE(provider
->AllWriteDataConsumed());
292 for (const DeterministicSocketData
* provider
:
293 deterministic_data_vector_
) {
294 EXPECT_FALSE(provider
->AllReadDataConsumed());
295 EXPECT_FALSE(provider
->AllWriteDataConsumed());
299 void RunToCompletion(SocketDataProvider
* data
) {
303 VerifyDataConsumed();
306 void RunToCompletionWithSSLData(
307 SocketDataProvider
* data
,
308 scoped_ptr
<SSLSocketDataProvider
> ssl_provider
) {
310 AddDataWithSSLSocketDataProvider(data
, ssl_provider
.Pass());
312 VerifyDataConsumed();
315 void AddData(SocketDataProvider
* data
) {
316 scoped_ptr
<SSLSocketDataProvider
> ssl_provider(
317 new SSLSocketDataProvider(ASYNC
, OK
));
319 ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem");
320 AddDataWithSSLSocketDataProvider(data
, ssl_provider
.Pass());
323 void AddDataWithSSLSocketDataProvider(
324 SocketDataProvider
* data
,
325 scoped_ptr
<SSLSocketDataProvider
> ssl_provider
) {
326 DCHECK(!deterministic_
);
327 data_vector_
.push_back(data
);
328 if (ssl_provider
->next_proto_status
==
329 SSLClientSocket::kNextProtoUnsupported
) {
330 ssl_provider
->SetNextProto(test_params_
.protocol
);
333 session_deps_
->socket_factory
->AddSSLSocketDataProvider(
335 ssl_vector_
.push_back(ssl_provider
.release());
337 session_deps_
->socket_factory
->AddSocketDataProvider(data
);
338 if (test_params_
.ssl_type
== HTTP_SPDY_VIA_ALT_SVC
) {
339 MockConnect
hanging_connect(SYNCHRONOUS
, ERR_IO_PENDING
);
340 StaticSocketDataProvider
* hanging_non_alt_svc_socket
=
341 new StaticSocketDataProvider(NULL
, 0, NULL
, 0);
342 hanging_non_alt_svc_socket
->set_connect_data(hanging_connect
);
343 session_deps_
->socket_factory
->AddSocketDataProvider(
344 hanging_non_alt_svc_socket
);
345 alternate_vector_
.push_back(hanging_non_alt_svc_socket
);
349 void AddDeterministicData(DeterministicSocketData
* data
) {
350 DCHECK(deterministic_
);
351 deterministic_data_vector_
.push_back(data
);
352 SSLSocketDataProvider
* ssl_provider
=
353 new SSLSocketDataProvider(ASYNC
, OK
);
354 ssl_provider
->SetNextProto(test_params_
.protocol
);
356 ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem");
357 ssl_vector_
.push_back(ssl_provider
);
358 session_deps_
->deterministic_socket_factory
->AddSSLSocketDataProvider(
361 session_deps_
->deterministic_socket_factory
->AddSocketDataProvider(data
);
362 if (test_params_
.ssl_type
== HTTP_SPDY_VIA_ALT_SVC
) {
363 MockConnect
hanging_connect(SYNCHRONOUS
, ERR_IO_PENDING
);
364 DeterministicSocketData
* hanging_non_alt_svc_socket
=
365 new DeterministicSocketData(NULL
, 0, NULL
, 0);
366 hanging_non_alt_svc_socket
->set_connect_data(hanging_connect
);
367 session_deps_
->deterministic_socket_factory
->AddSocketDataProvider(
368 hanging_non_alt_svc_socket
);
369 alternate_deterministic_vector_
.push_back(hanging_non_alt_svc_socket
);
373 void SetSession(const scoped_refptr
<HttpNetworkSession
>& session
) {
376 HttpNetworkTransaction
* trans() { return trans_
.get(); }
377 void ResetTrans() { trans_
.reset(); }
378 TransactionHelperResult
& output() { return output_
; }
379 const HttpRequestInfo
& request() const { return request_
; }
380 const scoped_refptr
<HttpNetworkSession
>& session() const {
383 scoped_ptr
<SpdySessionDependencies
>& session_deps() {
384 return session_deps_
;
386 int port() const { return port_
; }
387 SpdyNetworkTransactionTestParams
test_params() const {
392 typedef std::vector
<SocketDataProvider
*> DataVector
;
393 typedef std::vector
<DeterministicSocketData
*> DeterministicDataVector
;
394 typedef ScopedVector
<SSLSocketDataProvider
> SSLVector
;
395 typedef ScopedVector
<SocketDataProvider
> AlternateVector
;
396 typedef ScopedVector
<DeterministicSocketData
> AlternateDeterministicVector
;
397 HttpRequestInfo request_
;
398 RequestPriority priority_
;
399 scoped_ptr
<SpdySessionDependencies
> session_deps_
;
400 scoped_refptr
<HttpNetworkSession
> session_
;
401 TransactionHelperResult output_
;
402 scoped_ptr
<SocketDataProvider
> first_transaction_
;
403 SSLVector ssl_vector_
;
404 TestCompletionCallback callback_
;
405 scoped_ptr
<HttpNetworkTransaction
> trans_
;
406 scoped_ptr
<HttpNetworkTransaction
> trans_http_
;
407 DataVector data_vector_
;
408 DeterministicDataVector deterministic_data_vector_
;
409 AlternateVector alternate_vector_
;
410 AlternateDeterministicVector alternate_deterministic_vector_
;
411 const BoundNetLog log_
;
412 SpdyNetworkTransactionTestParams test_params_
;
418 void ConnectStatusHelperWithExpectedStatus(const MockRead
& status
,
419 int expected_status
);
421 void ConnectStatusHelper(const MockRead
& status
);
423 const HttpRequestInfo
& CreateGetPushRequest() {
424 get_push_request_
.method
= "GET";
425 get_push_request_
.url
= GURL(GetDefaultUrlWithPath("/foo.dat"));
426 get_push_request_
.load_flags
= 0;
427 return get_push_request_
;
430 const HttpRequestInfo
& CreateGetRequest() {
431 if (!get_request_initialized_
) {
432 get_request_
.method
= "GET";
433 get_request_
.url
= GURL(GetDefaultUrl());
434 get_request_
.load_flags
= 0;
435 get_request_initialized_
= true;
440 const HttpRequestInfo
& CreateGetRequestWithUserAgent() {
441 if (!get_request_initialized_
) {
442 get_request_
.method
= "GET";
443 get_request_
.url
= GURL(GetDefaultUrl());
444 get_request_
.load_flags
= 0;
445 get_request_
.extra_headers
.SetHeader("User-Agent", "Chrome");
446 get_request_initialized_
= true;
451 const HttpRequestInfo
& CreatePostRequest() {
452 if (!post_request_initialized_
) {
453 ScopedVector
<UploadElementReader
> element_readers
;
454 element_readers
.push_back(
455 new UploadBytesElementReader(kUploadData
, kUploadDataSize
));
456 upload_data_stream_
.reset(
457 new ElementsUploadDataStream(element_readers
.Pass(), 0));
459 post_request_
.method
= "POST";
460 post_request_
.url
= GURL(GetDefaultUrl());
461 post_request_
.upload_data_stream
= upload_data_stream_
.get();
462 post_request_initialized_
= true;
464 return post_request_
;
467 const HttpRequestInfo
& CreateFilePostRequest() {
468 if (!post_request_initialized_
) {
469 base::FilePath file_path
;
470 CHECK(base::CreateTemporaryFileInDir(temp_dir_
.path(), &file_path
));
471 CHECK_EQ(static_cast<int>(kUploadDataSize
),
472 base::WriteFile(file_path
, kUploadData
, kUploadDataSize
));
474 ScopedVector
<UploadElementReader
> element_readers
;
475 element_readers
.push_back(new UploadFileElementReader(
476 base::ThreadTaskRunnerHandle::Get().get(), file_path
, 0,
477 kUploadDataSize
, base::Time()));
478 upload_data_stream_
.reset(
479 new ElementsUploadDataStream(element_readers
.Pass(), 0));
481 post_request_
.method
= "POST";
482 post_request_
.url
= GURL(GetDefaultUrl());
483 post_request_
.upload_data_stream
= upload_data_stream_
.get();
484 post_request_initialized_
= true;
486 return post_request_
;
489 const HttpRequestInfo
& CreateUnreadableFilePostRequest() {
490 if (post_request_initialized_
)
491 return post_request_
;
493 base::FilePath file_path
;
494 CHECK(base::CreateTemporaryFileInDir(temp_dir_
.path(), &file_path
));
495 CHECK_EQ(static_cast<int>(kUploadDataSize
),
496 base::WriteFile(file_path
, kUploadData
, kUploadDataSize
));
497 CHECK(base::MakeFileUnreadable(file_path
));
499 ScopedVector
<UploadElementReader
> element_readers
;
500 element_readers
.push_back(new UploadFileElementReader(
501 base::ThreadTaskRunnerHandle::Get().get(), file_path
, 0,
502 kUploadDataSize
, base::Time()));
503 upload_data_stream_
.reset(
504 new ElementsUploadDataStream(element_readers
.Pass(), 0));
506 post_request_
.method
= "POST";
507 post_request_
.url
= GURL(GetDefaultUrl());
508 post_request_
.upload_data_stream
= upload_data_stream_
.get();
509 post_request_initialized_
= true;
510 return post_request_
;
513 const HttpRequestInfo
& CreateComplexPostRequest() {
514 if (!post_request_initialized_
) {
515 const int kFileRangeOffset
= 1;
516 const int kFileRangeLength
= 3;
517 CHECK_LT(kFileRangeOffset
+ kFileRangeLength
, kUploadDataSize
);
519 base::FilePath file_path
;
520 CHECK(base::CreateTemporaryFileInDir(temp_dir_
.path(), &file_path
));
521 CHECK_EQ(static_cast<int>(kUploadDataSize
),
522 base::WriteFile(file_path
, kUploadData
, kUploadDataSize
));
524 ScopedVector
<UploadElementReader
> element_readers
;
525 element_readers
.push_back(
526 new UploadBytesElementReader(kUploadData
, kFileRangeOffset
));
527 element_readers
.push_back(new UploadFileElementReader(
528 base::ThreadTaskRunnerHandle::Get().get(), file_path
,
529 kFileRangeOffset
, kFileRangeLength
, base::Time()));
530 element_readers
.push_back(new UploadBytesElementReader(
531 kUploadData
+ kFileRangeOffset
+ kFileRangeLength
,
532 kUploadDataSize
- (kFileRangeOffset
+ kFileRangeLength
)));
533 upload_data_stream_
.reset(
534 new ElementsUploadDataStream(element_readers
.Pass(), 0));
536 post_request_
.method
= "POST";
537 post_request_
.url
= GURL(GetDefaultUrl());
538 post_request_
.upload_data_stream
= upload_data_stream_
.get();
539 post_request_initialized_
= true;
541 return post_request_
;
544 const HttpRequestInfo
& CreateChunkedPostRequest() {
545 if (!chunked_post_request_initialized_
) {
546 upload_chunked_data_stream_
.reset(new ChunkedUploadDataStream(0));
547 chunked_post_request_
.method
= "POST";
548 chunked_post_request_
.url
= GURL(GetDefaultUrl());
549 chunked_post_request_
.upload_data_stream
=
550 upload_chunked_data_stream_
.get();
551 chunked_post_request_initialized_
= true;
553 return chunked_post_request_
;
556 // Read the result of a particular transaction, knowing that we've got
557 // multiple transactions in the read pipeline; so as we read, we may have
558 // to skip over data destined for other transactions while we consume
559 // the data for |trans|.
560 int ReadResult(HttpNetworkTransaction
* trans
,
561 std::string
* result
) {
562 const int kSize
= 3000;
565 scoped_refptr
<IOBufferWithSize
> buf(new IOBufferWithSize(kSize
));
566 TestCompletionCallback callback
;
568 int rv
= trans
->Read(buf
.get(), kSize
, callback
.callback());
569 if (rv
== ERR_IO_PENDING
) {
570 rv
= callback
.WaitForResult();
571 } else if (rv
<= 0) {
574 result
->append(buf
->data(), rv
);
580 void VerifyStreamsClosed(const NormalSpdyTransactionHelper
& helper
) {
581 // This lengthy block is reaching into the pool to dig out the active
582 // session. Once we have the session, we verify that the streams are
583 // all closed and not leaked at this point.
584 const GURL
& url
= helper
.request().url
;
585 HostPortPair
host_port_pair(url
.host(), 443);
586 SpdySessionKey
key(host_port_pair
, ProxyServer::Direct(),
587 PRIVACY_MODE_DISABLED
);
589 const scoped_refptr
<HttpNetworkSession
>& session
= helper
.session();
590 base::WeakPtr
<SpdySession
> spdy_session
=
591 session
->spdy_session_pool()->FindAvailableSession(key
, log
);
592 ASSERT_TRUE(spdy_session
!= NULL
);
593 EXPECT_EQ(0u, spdy_session
->num_active_streams());
594 EXPECT_EQ(0u, spdy_session
->num_unclaimed_pushed_streams());
597 void RunServerPushTest(SequencedSocketData
* data
,
598 HttpResponseInfo
* response
,
599 HttpResponseInfo
* push_response
,
600 const std::string
& expected
) {
601 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
602 BoundNetLog(), GetParam(), NULL
);
603 helper
.RunPreTestSetup();
604 helper
.AddData(data
);
606 HttpNetworkTransaction
* trans
= helper
.trans();
608 // Start the transaction with basic parameters.
609 TestCompletionCallback callback
;
610 int rv
= trans
->Start(
611 &CreateGetRequest(), callback
.callback(), BoundNetLog());
612 EXPECT_EQ(ERR_IO_PENDING
, rv
);
613 rv
= callback
.WaitForResult();
615 // Request the pushed path.
616 scoped_ptr
<HttpNetworkTransaction
> trans2(
617 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
619 &CreateGetPushRequest(), callback
.callback(), BoundNetLog());
620 EXPECT_EQ(ERR_IO_PENDING
, rv
);
621 base::RunLoop().RunUntilIdle();
623 // The data for the pushed path may be coming in more than 1 frame. Compile
624 // the results into a single string.
626 // Read the server push body.
628 ReadResult(trans2
.get(), &result2
);
629 // Read the response body.
631 ReadResult(trans
, &result
);
633 // Verify that we consumed all test data.
634 EXPECT_TRUE(data
->AllReadDataConsumed());
635 EXPECT_TRUE(data
->AllWriteDataConsumed());
637 // Verify that the received push data is same as the expected push data.
638 EXPECT_EQ(result2
.compare(expected
), 0) << "Received data: "
640 << "||||| Expected data: "
643 // Verify the SYN_REPLY.
644 // Copy the response info, because trans goes away.
645 *response
= *trans
->GetResponseInfo();
646 *push_response
= *trans2
->GetResponseInfo();
648 VerifyStreamsClosed(helper
);
651 static void DeleteSessionCallback(NormalSpdyTransactionHelper
* helper
,
653 helper
->ResetTrans();
656 static void StartTransactionCallback(
657 const scoped_refptr
<HttpNetworkSession
>& session
,
660 scoped_ptr
<HttpNetworkTransaction
> trans(
661 new HttpNetworkTransaction(DEFAULT_PRIORITY
, session
.get()));
662 TestCompletionCallback callback
;
663 HttpRequestInfo request
;
664 request
.method
= "GET";
666 request
.load_flags
= 0;
667 int rv
= trans
->Start(&request
, callback
.callback(), BoundNetLog());
668 EXPECT_EQ(ERR_IO_PENDING
, rv
);
669 callback
.WaitForResult();
672 ChunkedUploadDataStream
* upload_chunked_data_stream() const {
673 return upload_chunked_data_stream_
.get();
676 const char* GetDefaultUrl() {
677 switch (GetParam().ssl_type
) {
678 case HTTP_SPDY_VIA_ALT_SVC
:
679 return "http://www.example.org";
680 case HTTPS_SPDY_VIA_NPN
:
681 return "https://www.example.org";
688 std::string
GetDefaultUrlWithPath(const char* path
) {
689 return std::string(GetDefaultUrl()) + path
;
692 SpdyTestUtil spdy_util_
;
695 scoped_ptr
<ChunkedUploadDataStream
> upload_chunked_data_stream_
;
696 scoped_ptr
<UploadDataStream
> upload_data_stream_
;
697 bool get_request_initialized_
;
698 bool post_request_initialized_
;
699 bool chunked_post_request_initialized_
;
700 HttpRequestInfo get_request_
;
701 HttpRequestInfo post_request_
;
702 HttpRequestInfo chunked_post_request_
;
703 HttpRequestInfo get_push_request_
;
704 base::ScopedTempDir temp_dir_
;
707 //-----------------------------------------------------------------------------
708 // All tests are run with three different connection types: SPDY after NPN
709 // negotiation, SPDY without SSL, and SPDY with SSL.
711 // TODO(akalin): Use ::testing::Combine() when we are able to use
713 INSTANTIATE_TEST_CASE_P(
715 SpdyNetworkTransactionTest
,
717 SpdyNetworkTransactionTestParams(kProtoSPDY31
, HTTPS_SPDY_VIA_NPN
),
718 SpdyNetworkTransactionTestParams(kProtoSPDY31
, HTTP_SPDY_VIA_ALT_SVC
),
719 SpdyNetworkTransactionTestParams(kProtoHTTP2_14
, HTTPS_SPDY_VIA_NPN
),
720 SpdyNetworkTransactionTestParams(kProtoHTTP2_14
, HTTP_SPDY_VIA_ALT_SVC
),
721 SpdyNetworkTransactionTestParams(kProtoHTTP2
, HTTPS_SPDY_VIA_NPN
),
722 SpdyNetworkTransactionTestParams(kProtoHTTP2
, HTTP_SPDY_VIA_ALT_SVC
)));
724 // Verify HttpNetworkTransaction constructor.
725 TEST_P(SpdyNetworkTransactionTest
, Constructor
) {
726 scoped_ptr
<SpdySessionDependencies
> session_deps(
727 CreateSpdySessionDependencies(GetParam()));
728 scoped_refptr
<HttpNetworkSession
> session(
729 SpdySessionDependencies::SpdyCreateSession(session_deps
.get()));
730 scoped_ptr
<HttpTransaction
> trans(
731 new HttpNetworkTransaction(DEFAULT_PRIORITY
, session
.get()));
734 TEST_P(SpdyNetworkTransactionTest
, Get
) {
735 // Construct the request.
736 scoped_ptr
<SpdyFrame
> req(
737 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
738 MockWrite writes
[] = {CreateMockWrite(*req
, 0)};
740 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
741 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
743 CreateMockRead(*resp
, 1),
744 CreateMockRead(*body
, 2),
745 MockRead(ASYNC
, 0, 3) // EOF
748 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
749 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
750 BoundNetLog(), GetParam(), NULL
);
751 helper
.RunToCompletion(&data
);
752 TransactionHelperResult out
= helper
.output();
753 EXPECT_EQ(OK
, out
.rv
);
754 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
755 EXPECT_EQ("hello!", out
.response_data
);
758 TEST_P(SpdyNetworkTransactionTest
, GetAtEachPriority
) {
759 for (RequestPriority p
= MINIMUM_PRIORITY
; p
<= MAXIMUM_PRIORITY
;
760 p
= RequestPriority(p
+ 1)) {
761 // Construct the request.
762 scoped_ptr
<SpdyFrame
> req(
763 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, p
, true));
764 MockWrite writes
[] = {CreateMockWrite(*req
, 0)};
766 SpdyPriority spdy_prio
= 0;
767 EXPECT_TRUE(GetSpdyPriority(spdy_util_
.spdy_version(), *req
, &spdy_prio
));
768 // this repeats the RequestPriority-->SpdyPriority mapping from
769 // SpdyFramer::ConvertRequestPriorityToSpdyPriority to make
770 // sure it's being done right.
771 if (spdy_util_
.spdy_version() < SPDY3
) {
774 EXPECT_EQ(0, spdy_prio
);
777 EXPECT_EQ(1, spdy_prio
);
781 EXPECT_EQ(2, spdy_prio
);
784 EXPECT_EQ(3, spdy_prio
);
792 EXPECT_EQ(0, spdy_prio
);
795 EXPECT_EQ(1, spdy_prio
);
798 EXPECT_EQ(2, spdy_prio
);
801 EXPECT_EQ(3, spdy_prio
);
804 EXPECT_EQ(4, spdy_prio
);
811 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
812 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
814 CreateMockRead(*resp
, 1),
815 CreateMockRead(*body
, 2),
816 MockRead(ASYNC
, 0, 3) // EOF
819 SequencedSocketData
data(reads
, arraysize(reads
), writes
,
821 HttpRequestInfo http_req
= CreateGetRequest();
823 NormalSpdyTransactionHelper
helper(http_req
, p
, BoundNetLog(),
825 helper
.RunToCompletion(&data
);
826 TransactionHelperResult out
= helper
.output();
827 EXPECT_EQ(OK
, out
.rv
);
828 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
829 EXPECT_EQ("hello!", out
.response_data
);
833 // Start three gets simultaniously; making sure that multiplexed
834 // streams work properly.
836 // This can't use the TransactionHelper method, since it only
837 // handles a single transaction, and finishes them as soon
838 // as it launches them.
840 // TODO(gavinp): create a working generalized TransactionHelper that
841 // can allow multiple streams in flight.
843 TEST_P(SpdyNetworkTransactionTest
, ThreeGets
) {
844 scoped_ptr
<SpdyFrame
> req(
845 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
846 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
847 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, false));
848 scoped_ptr
<SpdyFrame
> fbody(spdy_util_
.ConstructSpdyBodyFrame(1, true));
850 scoped_ptr
<SpdyFrame
> req2(
851 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 3, LOWEST
, true));
852 scoped_ptr
<SpdyFrame
> resp2(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 3));
853 scoped_ptr
<SpdyFrame
> body2(spdy_util_
.ConstructSpdyBodyFrame(3, false));
854 scoped_ptr
<SpdyFrame
> fbody2(spdy_util_
.ConstructSpdyBodyFrame(3, true));
856 scoped_ptr
<SpdyFrame
> req3(
857 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 5, LOWEST
, true));
858 scoped_ptr
<SpdyFrame
> resp3(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 5));
859 scoped_ptr
<SpdyFrame
> body3(spdy_util_
.ConstructSpdyBodyFrame(5, false));
860 scoped_ptr
<SpdyFrame
> fbody3(spdy_util_
.ConstructSpdyBodyFrame(5, true));
862 MockWrite writes
[] = {
863 CreateMockWrite(*req
, 0),
864 CreateMockWrite(*req2
, 3),
865 CreateMockWrite(*req3
, 6),
868 CreateMockRead(*resp
, 1),
869 CreateMockRead(*body
, 2),
870 CreateMockRead(*resp2
, 4),
871 CreateMockRead(*body2
, 5),
872 CreateMockRead(*resp3
, 7),
873 CreateMockRead(*body3
, 8),
875 CreateMockRead(*fbody
, 9),
876 CreateMockRead(*fbody2
, 10),
877 CreateMockRead(*fbody3
, 11),
879 MockRead(ASYNC
, 0, 12), // EOF
881 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
882 SequencedSocketData
data_placeholder(NULL
, 0, NULL
, 0);
885 TransactionHelperResult out
;
886 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
887 BoundNetLog(), GetParam(), NULL
);
888 helper
.RunPreTestSetup();
889 helper
.AddData(&data
);
890 // We require placeholder data because three get requests are sent out at
891 // the same time which results in three sockets being connected. The first
892 // on will negotiate SPDY and will be used for all requests.
893 helper
.AddData(&data_placeholder
);
894 helper
.AddData(&data_placeholder
);
895 scoped_ptr
<HttpNetworkTransaction
> trans1(
896 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
897 scoped_ptr
<HttpNetworkTransaction
> trans2(
898 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
899 scoped_ptr
<HttpNetworkTransaction
> trans3(
900 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
902 TestCompletionCallback callback1
;
903 TestCompletionCallback callback2
;
904 TestCompletionCallback callback3
;
906 HttpRequestInfo httpreq1
= CreateGetRequest();
907 HttpRequestInfo httpreq2
= CreateGetRequest();
908 HttpRequestInfo httpreq3
= CreateGetRequest();
910 out
.rv
= trans1
->Start(&httpreq1
, callback1
.callback(), log
);
911 ASSERT_EQ(ERR_IO_PENDING
, out
.rv
);
912 out
.rv
= trans2
->Start(&httpreq2
, callback2
.callback(), log
);
913 ASSERT_EQ(ERR_IO_PENDING
, out
.rv
);
914 out
.rv
= trans3
->Start(&httpreq3
, callback3
.callback(), log
);
915 ASSERT_EQ(ERR_IO_PENDING
, out
.rv
);
917 out
.rv
= callback1
.WaitForResult();
918 ASSERT_EQ(OK
, out
.rv
);
919 out
.rv
= callback3
.WaitForResult();
920 ASSERT_EQ(OK
, out
.rv
);
922 const HttpResponseInfo
* response1
= trans1
->GetResponseInfo();
923 EXPECT_TRUE(response1
->headers
.get() != NULL
);
924 EXPECT_TRUE(response1
->was_fetched_via_spdy
);
925 out
.status_line
= response1
->headers
->GetStatusLine();
926 out
.response_info
= *response1
;
928 trans2
->GetResponseInfo();
930 out
.rv
= ReadTransaction(trans1
.get(), &out
.response_data
);
931 helper
.VerifyDataConsumed();
932 EXPECT_EQ(OK
, out
.rv
);
934 EXPECT_EQ(OK
, out
.rv
);
935 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
936 EXPECT_EQ("hello!hello!", out
.response_data
);
939 TEST_P(SpdyNetworkTransactionTest
, TwoGetsLateBinding
) {
940 scoped_ptr
<SpdyFrame
> req(
941 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
942 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
943 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, false));
944 scoped_ptr
<SpdyFrame
> fbody(spdy_util_
.ConstructSpdyBodyFrame(1, true));
946 scoped_ptr
<SpdyFrame
> req2(
947 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 3, LOWEST
, true));
948 scoped_ptr
<SpdyFrame
> resp2(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 3));
949 scoped_ptr
<SpdyFrame
> body2(spdy_util_
.ConstructSpdyBodyFrame(3, false));
950 scoped_ptr
<SpdyFrame
> fbody2(spdy_util_
.ConstructSpdyBodyFrame(3, true));
952 MockWrite writes
[] = {
953 CreateMockWrite(*req
, 0), CreateMockWrite(*req2
, 3),
956 CreateMockRead(*resp
, 1),
957 CreateMockRead(*body
, 2),
958 CreateMockRead(*resp2
, 4),
959 CreateMockRead(*body2
, 5),
960 CreateMockRead(*fbody
, 6),
961 CreateMockRead(*fbody2
, 7),
962 MockRead(ASYNC
, 0, 8), // EOF
964 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
966 MockConnect
never_finishing_connect(SYNCHRONOUS
, ERR_IO_PENDING
);
967 SequencedSocketData
data_placeholder(NULL
, 0, NULL
, 0);
968 data_placeholder
.set_connect_data(never_finishing_connect
);
971 TransactionHelperResult out
;
972 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
973 BoundNetLog(), GetParam(), NULL
);
974 helper
.RunPreTestSetup();
975 helper
.AddData(&data
);
976 // We require placeholder data because two requests are sent out at
977 // the same time which results in two sockets being connected. The first
978 // on will negotiate SPDY and will be used for all requests.
979 helper
.AddData(&data_placeholder
);
980 scoped_ptr
<HttpNetworkTransaction
> trans1(
981 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
982 scoped_ptr
<HttpNetworkTransaction
> trans2(
983 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
985 TestCompletionCallback callback1
;
986 TestCompletionCallback callback2
;
988 HttpRequestInfo httpreq1
= CreateGetRequest();
989 HttpRequestInfo httpreq2
= CreateGetRequest();
991 out
.rv
= trans1
->Start(&httpreq1
, callback1
.callback(), log
);
992 ASSERT_EQ(ERR_IO_PENDING
, out
.rv
);
993 out
.rv
= trans2
->Start(&httpreq2
, callback2
.callback(), log
);
994 ASSERT_EQ(ERR_IO_PENDING
, out
.rv
);
996 out
.rv
= callback1
.WaitForResult();
997 ASSERT_EQ(OK
, out
.rv
);
998 out
.rv
= callback2
.WaitForResult();
999 ASSERT_EQ(OK
, out
.rv
);
1001 const HttpResponseInfo
* response1
= trans1
->GetResponseInfo();
1002 EXPECT_TRUE(response1
->headers
.get() != NULL
);
1003 EXPECT_TRUE(response1
->was_fetched_via_spdy
);
1004 out
.status_line
= response1
->headers
->GetStatusLine();
1005 out
.response_info
= *response1
;
1006 out
.rv
= ReadTransaction(trans1
.get(), &out
.response_data
);
1007 EXPECT_EQ(OK
, out
.rv
);
1008 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1009 EXPECT_EQ("hello!hello!", out
.response_data
);
1011 const HttpResponseInfo
* response2
= trans2
->GetResponseInfo();
1012 EXPECT_TRUE(response2
->headers
.get() != NULL
);
1013 EXPECT_TRUE(response2
->was_fetched_via_spdy
);
1014 out
.status_line
= response2
->headers
->GetStatusLine();
1015 out
.response_info
= *response2
;
1016 out
.rv
= ReadTransaction(trans2
.get(), &out
.response_data
);
1017 EXPECT_EQ(OK
, out
.rv
);
1018 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1019 EXPECT_EQ("hello!hello!", out
.response_data
);
1021 helper
.VerifyDataConsumed();
1024 TEST_P(SpdyNetworkTransactionTest
, TwoGetsLateBindingFromPreconnect
) {
1025 scoped_ptr
<SpdyFrame
> req(
1026 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
1027 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
1028 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, false));
1029 scoped_ptr
<SpdyFrame
> fbody(spdy_util_
.ConstructSpdyBodyFrame(1, true));
1031 scoped_ptr
<SpdyFrame
> req2(
1032 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 3, LOWEST
, true));
1033 scoped_ptr
<SpdyFrame
> resp2(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 3));
1034 scoped_ptr
<SpdyFrame
> body2(spdy_util_
.ConstructSpdyBodyFrame(3, false));
1035 scoped_ptr
<SpdyFrame
> fbody2(spdy_util_
.ConstructSpdyBodyFrame(3, true));
1037 MockWrite writes
[] = {
1038 CreateMockWrite(*req
, 0), CreateMockWrite(*req2
, 3),
1040 MockRead reads
[] = {
1041 CreateMockRead(*resp
, 1),
1042 CreateMockRead(*body
, 2),
1043 CreateMockRead(*resp2
, 4),
1044 CreateMockRead(*body2
, 5),
1045 CreateMockRead(*fbody
, 6),
1046 CreateMockRead(*fbody2
, 7),
1047 MockRead(ASYNC
, 0, 8), // EOF
1049 SequencedSocketData
preconnect_data(reads
, arraysize(reads
), writes
,
1052 MockConnect
never_finishing_connect(ASYNC
, ERR_IO_PENDING
);
1054 SequencedSocketData
data_placeholder(NULL
, 0, NULL
, 0);
1055 data_placeholder
.set_connect_data(never_finishing_connect
);
1058 TransactionHelperResult out
;
1059 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
1060 BoundNetLog(), GetParam(), NULL
);
1061 helper
.RunPreTestSetup();
1062 helper
.AddData(&preconnect_data
);
1063 // We require placeholder data because 3 connections are attempted (first is
1064 // the preconnect, 2nd and 3rd are the never finished connections.
1065 helper
.AddData(&data_placeholder
);
1066 helper
.AddData(&data_placeholder
);
1068 scoped_ptr
<HttpNetworkTransaction
> trans1(
1069 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
1070 scoped_ptr
<HttpNetworkTransaction
> trans2(
1071 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
1073 TestCompletionCallback callback1
;
1074 TestCompletionCallback callback2
;
1076 HttpRequestInfo httpreq
= CreateGetRequest();
1078 // Preconnect the first.
1079 SSLConfig preconnect_ssl_config
;
1080 helper
.session()->ssl_config_service()->GetSSLConfig(&preconnect_ssl_config
);
1081 HttpStreamFactory
* http_stream_factory
=
1082 helper
.session()->http_stream_factory();
1083 helper
.session()->GetNextProtos(&preconnect_ssl_config
.next_protos
);
1085 http_stream_factory
->PreconnectStreams(1, httpreq
, preconnect_ssl_config
,
1086 preconnect_ssl_config
);
1088 out
.rv
= trans1
->Start(&httpreq
, callback1
.callback(), log
);
1089 ASSERT_EQ(ERR_IO_PENDING
, out
.rv
);
1090 out
.rv
= trans2
->Start(&httpreq
, callback2
.callback(), log
);
1091 ASSERT_EQ(ERR_IO_PENDING
, out
.rv
);
1093 out
.rv
= callback1
.WaitForResult();
1094 ASSERT_EQ(OK
, out
.rv
);
1095 out
.rv
= callback2
.WaitForResult();
1096 ASSERT_EQ(OK
, out
.rv
);
1098 const HttpResponseInfo
* response1
= trans1
->GetResponseInfo();
1099 EXPECT_TRUE(response1
->headers
.get() != NULL
);
1100 EXPECT_TRUE(response1
->was_fetched_via_spdy
);
1101 out
.status_line
= response1
->headers
->GetStatusLine();
1102 out
.response_info
= *response1
;
1103 out
.rv
= ReadTransaction(trans1
.get(), &out
.response_data
);
1104 EXPECT_EQ(OK
, out
.rv
);
1105 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1106 EXPECT_EQ("hello!hello!", out
.response_data
);
1108 const HttpResponseInfo
* response2
= trans2
->GetResponseInfo();
1109 EXPECT_TRUE(response2
->headers
.get() != NULL
);
1110 EXPECT_TRUE(response2
->was_fetched_via_spdy
);
1111 out
.status_line
= response2
->headers
->GetStatusLine();
1112 out
.response_info
= *response2
;
1113 out
.rv
= ReadTransaction(trans2
.get(), &out
.response_data
);
1114 EXPECT_EQ(OK
, out
.rv
);
1115 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1116 EXPECT_EQ("hello!hello!", out
.response_data
);
1118 helper
.VerifyDataConsumed();
1121 // Similar to ThreeGets above, however this test adds a SETTINGS
1122 // frame. The SETTINGS frame is read during the IO loop waiting on
1123 // the first transaction completion, and sets a maximum concurrent
1124 // stream limit of 1. This means that our IO loop exists after the
1125 // second transaction completes, so we can assert on read_index().
1126 TEST_P(SpdyNetworkTransactionTest
, ThreeGetsWithMaxConcurrent
) {
1127 // Construct the request.
1128 scoped_ptr
<SpdyFrame
> req(
1129 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
1130 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
1131 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, false));
1132 scoped_ptr
<SpdyFrame
> fbody(spdy_util_
.ConstructSpdyBodyFrame(1, true));
1134 scoped_ptr
<SpdyFrame
> req2(
1135 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 3, LOWEST
, true));
1136 scoped_ptr
<SpdyFrame
> resp2(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 3));
1137 scoped_ptr
<SpdyFrame
> body2(spdy_util_
.ConstructSpdyBodyFrame(3, false));
1138 scoped_ptr
<SpdyFrame
> fbody2(spdy_util_
.ConstructSpdyBodyFrame(3, true));
1140 scoped_ptr
<SpdyFrame
> req3(
1141 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 5, LOWEST
, true));
1142 scoped_ptr
<SpdyFrame
> resp3(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 5));
1143 scoped_ptr
<SpdyFrame
> body3(spdy_util_
.ConstructSpdyBodyFrame(5, false));
1144 scoped_ptr
<SpdyFrame
> fbody3(spdy_util_
.ConstructSpdyBodyFrame(5, true));
1146 SettingsMap settings
;
1147 const uint32 max_concurrent_streams
= 1;
1148 settings
[SETTINGS_MAX_CONCURRENT_STREAMS
] =
1149 SettingsFlagsAndValue(SETTINGS_FLAG_NONE
, max_concurrent_streams
);
1150 scoped_ptr
<SpdyFrame
> settings_frame(
1151 spdy_util_
.ConstructSpdySettings(settings
));
1152 scoped_ptr
<SpdyFrame
> settings_ack(spdy_util_
.ConstructSpdySettingsAck());
1154 MockWrite writes
[] = {
1155 CreateMockWrite(*req
, 0),
1156 CreateMockWrite(*settings_ack
, 5),
1157 CreateMockWrite(*req2
, 6),
1158 CreateMockWrite(*req3
, 10),
1161 MockRead reads
[] = {
1162 CreateMockRead(*settings_frame
, 1),
1163 CreateMockRead(*resp
, 2),
1164 CreateMockRead(*body
, 3),
1165 CreateMockRead(*fbody
, 4),
1166 CreateMockRead(*resp2
, 7),
1167 CreateMockRead(*body2
, 8),
1168 CreateMockRead(*fbody2
, 9),
1169 CreateMockRead(*resp3
, 11),
1170 CreateMockRead(*body3
, 12),
1171 CreateMockRead(*fbody3
, 13),
1173 MockRead(ASYNC
, 0, 14), // EOF
1176 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
1179 TransactionHelperResult out
;
1181 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
1182 BoundNetLog(), GetParam(), NULL
);
1183 helper
.RunPreTestSetup();
1184 helper
.AddData(&data
);
1185 scoped_ptr
<HttpNetworkTransaction
> trans1(
1186 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
1187 scoped_ptr
<HttpNetworkTransaction
> trans2(
1188 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
1189 scoped_ptr
<HttpNetworkTransaction
> trans3(
1190 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
1192 TestCompletionCallback callback1
;
1193 TestCompletionCallback callback2
;
1194 TestCompletionCallback callback3
;
1196 HttpRequestInfo httpreq1
= CreateGetRequest();
1197 HttpRequestInfo httpreq2
= CreateGetRequest();
1198 HttpRequestInfo httpreq3
= CreateGetRequest();
1200 out
.rv
= trans1
->Start(&httpreq1
, callback1
.callback(), log
);
1201 ASSERT_EQ(out
.rv
, ERR_IO_PENDING
);
1202 // Run transaction 1 through quickly to force a read of our SETTINGS
1204 out
.rv
= callback1
.WaitForResult();
1205 ASSERT_EQ(OK
, out
.rv
);
1207 out
.rv
= trans2
->Start(&httpreq2
, callback2
.callback(), log
);
1208 ASSERT_EQ(out
.rv
, ERR_IO_PENDING
);
1209 out
.rv
= trans3
->Start(&httpreq3
, callback3
.callback(), log
);
1210 ASSERT_EQ(out
.rv
, ERR_IO_PENDING
);
1211 out
.rv
= callback2
.WaitForResult();
1212 ASSERT_EQ(OK
, out
.rv
);
1214 out
.rv
= callback3
.WaitForResult();
1215 ASSERT_EQ(OK
, out
.rv
);
1217 const HttpResponseInfo
* response1
= trans1
->GetResponseInfo();
1218 ASSERT_TRUE(response1
!= NULL
);
1219 EXPECT_TRUE(response1
->headers
.get() != NULL
);
1220 EXPECT_TRUE(response1
->was_fetched_via_spdy
);
1221 out
.status_line
= response1
->headers
->GetStatusLine();
1222 out
.response_info
= *response1
;
1223 out
.rv
= ReadTransaction(trans1
.get(), &out
.response_data
);
1224 EXPECT_EQ(OK
, out
.rv
);
1225 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1226 EXPECT_EQ("hello!hello!", out
.response_data
);
1228 const HttpResponseInfo
* response2
= trans2
->GetResponseInfo();
1229 out
.status_line
= response2
->headers
->GetStatusLine();
1230 out
.response_info
= *response2
;
1231 out
.rv
= ReadTransaction(trans2
.get(), &out
.response_data
);
1232 EXPECT_EQ(OK
, out
.rv
);
1233 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1234 EXPECT_EQ("hello!hello!", out
.response_data
);
1236 const HttpResponseInfo
* response3
= trans3
->GetResponseInfo();
1237 out
.status_line
= response3
->headers
->GetStatusLine();
1238 out
.response_info
= *response3
;
1239 out
.rv
= ReadTransaction(trans3
.get(), &out
.response_data
);
1240 EXPECT_EQ(OK
, out
.rv
);
1241 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1242 EXPECT_EQ("hello!hello!", out
.response_data
);
1244 helper
.VerifyDataConsumed();
1246 EXPECT_EQ(OK
, out
.rv
);
1249 // Similar to ThreeGetsWithMaxConcurrent above, however this test adds
1250 // a fourth transaction. The third and fourth transactions have
1251 // different data ("hello!" vs "hello!hello!") and because of the
1252 // user specified priority, we expect to see them inverted in
1253 // the response from the server.
1254 TEST_P(SpdyNetworkTransactionTest
, FourGetsWithMaxConcurrentPriority
) {
1255 // Construct the request.
1256 scoped_ptr
<SpdyFrame
> req(
1257 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
1258 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
1259 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, false));
1260 scoped_ptr
<SpdyFrame
> fbody(spdy_util_
.ConstructSpdyBodyFrame(1, true));
1262 scoped_ptr
<SpdyFrame
> req2(
1263 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 3, LOWEST
, true));
1264 scoped_ptr
<SpdyFrame
> resp2(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 3));
1265 scoped_ptr
<SpdyFrame
> body2(spdy_util_
.ConstructSpdyBodyFrame(3, false));
1266 scoped_ptr
<SpdyFrame
> fbody2(spdy_util_
.ConstructSpdyBodyFrame(3, true));
1268 scoped_ptr
<SpdyFrame
> req4(
1269 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 5, HIGHEST
, true));
1270 scoped_ptr
<SpdyFrame
> resp4(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 5));
1271 scoped_ptr
<SpdyFrame
> fbody4(spdy_util_
.ConstructSpdyBodyFrame(5, true));
1273 scoped_ptr
<SpdyFrame
> req3(
1274 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 7, LOWEST
, true));
1275 scoped_ptr
<SpdyFrame
> resp3(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 7));
1276 scoped_ptr
<SpdyFrame
> body3(spdy_util_
.ConstructSpdyBodyFrame(7, false));
1277 scoped_ptr
<SpdyFrame
> fbody3(spdy_util_
.ConstructSpdyBodyFrame(7, true));
1279 SettingsMap settings
;
1280 const uint32 max_concurrent_streams
= 1;
1281 settings
[SETTINGS_MAX_CONCURRENT_STREAMS
] =
1282 SettingsFlagsAndValue(SETTINGS_FLAG_NONE
, max_concurrent_streams
);
1283 scoped_ptr
<SpdyFrame
> settings_frame(
1284 spdy_util_
.ConstructSpdySettings(settings
));
1285 scoped_ptr
<SpdyFrame
> settings_ack(spdy_util_
.ConstructSpdySettingsAck());
1286 MockWrite writes
[] = {
1287 CreateMockWrite(*req
, 0),
1288 CreateMockWrite(*settings_ack
, 5),
1289 // By making these synchronous, it guarantees that they are not *started*
1290 // before their sequence number, which in turn verifies that only a single
1291 // request is in-flight at a time.
1292 CreateMockWrite(*req2
, 6, SYNCHRONOUS
),
1293 CreateMockWrite(*req4
, 10, SYNCHRONOUS
),
1294 CreateMockWrite(*req3
, 13, SYNCHRONOUS
),
1296 MockRead reads
[] = {
1297 CreateMockRead(*settings_frame
, 1),
1298 CreateMockRead(*resp
, 2),
1299 CreateMockRead(*body
, 3),
1300 CreateMockRead(*fbody
, 4),
1301 CreateMockRead(*resp2
, 7),
1302 CreateMockRead(*body2
, 8),
1303 CreateMockRead(*fbody2
, 9),
1304 CreateMockRead(*resp4
, 11),
1305 CreateMockRead(*fbody4
, 12),
1306 CreateMockRead(*resp3
, 14),
1307 CreateMockRead(*body3
, 15),
1308 CreateMockRead(*fbody3
, 16),
1310 MockRead(ASYNC
, 0, 17), // EOF
1312 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
1314 TransactionHelperResult out
;
1315 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
1316 BoundNetLog(), GetParam(), NULL
);
1317 helper
.RunPreTestSetup();
1318 helper
.AddData(&data
);
1320 scoped_ptr
<HttpNetworkTransaction
> trans1(
1321 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
1322 scoped_ptr
<HttpNetworkTransaction
> trans2(
1323 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
1324 scoped_ptr
<HttpNetworkTransaction
> trans3(
1325 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
1326 scoped_ptr
<HttpNetworkTransaction
> trans4(
1327 new HttpNetworkTransaction(HIGHEST
, helper
.session().get()));
1329 TestCompletionCallback callback1
;
1330 TestCompletionCallback callback2
;
1331 TestCompletionCallback callback3
;
1332 TestCompletionCallback callback4
;
1334 HttpRequestInfo httpreq1
= CreateGetRequest();
1335 HttpRequestInfo httpreq2
= CreateGetRequest();
1336 HttpRequestInfo httpreq3
= CreateGetRequest();
1337 HttpRequestInfo httpreq4
= CreateGetRequest();
1339 out
.rv
= trans1
->Start(&httpreq1
, callback1
.callback(), log
);
1340 ASSERT_EQ(ERR_IO_PENDING
, out
.rv
);
1341 // Run transaction 1 through quickly to force a read of our SETTINGS frame.
1342 out
.rv
= callback1
.WaitForResult();
1343 ASSERT_EQ(OK
, out
.rv
);
1345 out
.rv
= trans2
->Start(&httpreq2
, callback2
.callback(), log
);
1346 ASSERT_EQ(ERR_IO_PENDING
, out
.rv
);
1347 out
.rv
= trans3
->Start(&httpreq3
, callback3
.callback(), log
);
1348 ASSERT_EQ(ERR_IO_PENDING
, out
.rv
);
1349 out
.rv
= trans4
->Start(&httpreq4
, callback4
.callback(), log
);
1350 ASSERT_EQ(ERR_IO_PENDING
, out
.rv
);
1352 out
.rv
= callback2
.WaitForResult();
1353 ASSERT_EQ(OK
, out
.rv
);
1355 out
.rv
= callback3
.WaitForResult();
1356 ASSERT_EQ(OK
, out
.rv
);
1358 const HttpResponseInfo
* response1
= trans1
->GetResponseInfo();
1359 EXPECT_TRUE(response1
->headers
.get() != NULL
);
1360 EXPECT_TRUE(response1
->was_fetched_via_spdy
);
1361 out
.status_line
= response1
->headers
->GetStatusLine();
1362 out
.response_info
= *response1
;
1363 out
.rv
= ReadTransaction(trans1
.get(), &out
.response_data
);
1364 EXPECT_EQ(OK
, out
.rv
);
1365 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1366 EXPECT_EQ("hello!hello!", out
.response_data
);
1368 const HttpResponseInfo
* response2
= trans2
->GetResponseInfo();
1369 out
.status_line
= response2
->headers
->GetStatusLine();
1370 out
.response_info
= *response2
;
1371 out
.rv
= ReadTransaction(trans2
.get(), &out
.response_data
);
1372 EXPECT_EQ(OK
, out
.rv
);
1373 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1374 EXPECT_EQ("hello!hello!", out
.response_data
);
1376 // notice: response3 gets two hellos, response4 gets one
1377 // hello, so we know dequeuing priority was respected.
1378 const HttpResponseInfo
* response3
= trans3
->GetResponseInfo();
1379 out
.status_line
= response3
->headers
->GetStatusLine();
1380 out
.response_info
= *response3
;
1381 out
.rv
= ReadTransaction(trans3
.get(), &out
.response_data
);
1382 EXPECT_EQ(OK
, out
.rv
);
1383 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1384 EXPECT_EQ("hello!hello!", out
.response_data
);
1386 out
.rv
= callback4
.WaitForResult();
1387 EXPECT_EQ(OK
, out
.rv
);
1388 const HttpResponseInfo
* response4
= trans4
->GetResponseInfo();
1389 out
.status_line
= response4
->headers
->GetStatusLine();
1390 out
.response_info
= *response4
;
1391 out
.rv
= ReadTransaction(trans4
.get(), &out
.response_data
);
1392 EXPECT_EQ(OK
, out
.rv
);
1393 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1394 EXPECT_EQ("hello!", out
.response_data
);
1395 helper
.VerifyDataConsumed();
1396 EXPECT_EQ(OK
, out
.rv
);
1399 // Similar to ThreeGetsMaxConcurrrent above, however, this test
1400 // deletes a session in the middle of the transaction to ensure
1401 // that we properly remove pendingcreatestream objects from
1403 TEST_P(SpdyNetworkTransactionTest
, ThreeGetsWithMaxConcurrentDelete
) {
1404 // Construct the request.
1405 scoped_ptr
<SpdyFrame
> req(
1406 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
1407 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
1408 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, false));
1409 scoped_ptr
<SpdyFrame
> fbody(spdy_util_
.ConstructSpdyBodyFrame(1, true));
1411 scoped_ptr
<SpdyFrame
> req2(
1412 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 3, LOWEST
, true));
1413 scoped_ptr
<SpdyFrame
> resp2(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 3));
1414 scoped_ptr
<SpdyFrame
> body2(spdy_util_
.ConstructSpdyBodyFrame(3, false));
1415 scoped_ptr
<SpdyFrame
> fbody2(spdy_util_
.ConstructSpdyBodyFrame(3, true));
1417 SettingsMap settings
;
1418 const uint32 max_concurrent_streams
= 1;
1419 settings
[SETTINGS_MAX_CONCURRENT_STREAMS
] =
1420 SettingsFlagsAndValue(SETTINGS_FLAG_NONE
, max_concurrent_streams
);
1421 scoped_ptr
<SpdyFrame
> settings_frame(
1422 spdy_util_
.ConstructSpdySettings(settings
));
1423 scoped_ptr
<SpdyFrame
> settings_ack(spdy_util_
.ConstructSpdySettingsAck());
1425 MockWrite writes
[] = {
1426 CreateMockWrite(*req
, 0),
1427 CreateMockWrite(*settings_ack
, 5),
1428 CreateMockWrite(*req2
, 6),
1430 MockRead reads
[] = {
1431 CreateMockRead(*settings_frame
, 1),
1432 CreateMockRead(*resp
, 2),
1433 CreateMockRead(*body
, 3),
1434 CreateMockRead(*fbody
, 4),
1435 CreateMockRead(*resp2
, 7),
1436 CreateMockRead(*body2
, 8),
1437 CreateMockRead(*fbody2
, 9),
1438 MockRead(ASYNC
, 0, 10), // EOF
1441 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
1444 TransactionHelperResult out
;
1445 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
1446 BoundNetLog(), GetParam(), NULL
);
1447 helper
.RunPreTestSetup();
1448 helper
.AddData(&data
);
1449 scoped_ptr
<HttpNetworkTransaction
> trans1(
1450 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
1451 scoped_ptr
<HttpNetworkTransaction
> trans2(
1452 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
1453 scoped_ptr
<HttpNetworkTransaction
> trans3(
1454 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
1456 TestCompletionCallback callback1
;
1457 TestCompletionCallback callback2
;
1458 TestCompletionCallback callback3
;
1460 HttpRequestInfo httpreq1
= CreateGetRequest();
1461 HttpRequestInfo httpreq2
= CreateGetRequest();
1462 HttpRequestInfo httpreq3
= CreateGetRequest();
1464 out
.rv
= trans1
->Start(&httpreq1
, callback1
.callback(), log
);
1465 ASSERT_EQ(out
.rv
, ERR_IO_PENDING
);
1466 // Run transaction 1 through quickly to force a read of our SETTINGS frame.
1467 out
.rv
= callback1
.WaitForResult();
1468 ASSERT_EQ(OK
, out
.rv
);
1470 out
.rv
= trans2
->Start(&httpreq2
, callback2
.callback(), log
);
1471 ASSERT_EQ(out
.rv
, ERR_IO_PENDING
);
1472 out
.rv
= trans3
->Start(&httpreq3
, callback3
.callback(), log
);
1473 delete trans3
.release();
1474 ASSERT_EQ(out
.rv
, ERR_IO_PENDING
);
1475 out
.rv
= callback2
.WaitForResult();
1476 ASSERT_EQ(OK
, out
.rv
);
1478 const HttpResponseInfo
* response1
= trans1
->GetResponseInfo();
1479 ASSERT_TRUE(response1
!= NULL
);
1480 EXPECT_TRUE(response1
->headers
.get() != NULL
);
1481 EXPECT_TRUE(response1
->was_fetched_via_spdy
);
1482 out
.status_line
= response1
->headers
->GetStatusLine();
1483 out
.response_info
= *response1
;
1484 out
.rv
= ReadTransaction(trans1
.get(), &out
.response_data
);
1485 EXPECT_EQ(OK
, out
.rv
);
1486 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1487 EXPECT_EQ("hello!hello!", out
.response_data
);
1489 const HttpResponseInfo
* response2
= trans2
->GetResponseInfo();
1490 ASSERT_TRUE(response2
!= NULL
);
1491 out
.status_line
= response2
->headers
->GetStatusLine();
1492 out
.response_info
= *response2
;
1493 out
.rv
= ReadTransaction(trans2
.get(), &out
.response_data
);
1494 EXPECT_EQ(OK
, out
.rv
);
1495 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1496 EXPECT_EQ("hello!hello!", out
.response_data
);
1497 helper
.VerifyDataConsumed();
1498 EXPECT_EQ(OK
, out
.rv
);
1503 // The KillerCallback will delete the transaction on error as part of the
1505 class KillerCallback
: public TestCompletionCallbackBase
{
1507 explicit KillerCallback(HttpNetworkTransaction
* transaction
)
1508 : transaction_(transaction
),
1509 callback_(base::Bind(&KillerCallback::OnComplete
,
1510 base::Unretained(this))) {
1513 ~KillerCallback() override
{}
1515 const CompletionCallback
& callback() const { return callback_
; }
1518 void OnComplete(int result
) {
1520 delete transaction_
;
1525 HttpNetworkTransaction
* transaction_
;
1526 CompletionCallback callback_
;
1531 // Similar to ThreeGetsMaxConcurrrentDelete above, however, this test
1532 // closes the socket while we have a pending transaction waiting for
1533 // a pending stream creation. http://crbug.com/52901
1534 TEST_P(SpdyNetworkTransactionTest
, ThreeGetsWithMaxConcurrentSocketClose
) {
1535 // Construct the request.
1536 scoped_ptr
<SpdyFrame
> req(
1537 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
1538 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
1539 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, false));
1540 scoped_ptr
<SpdyFrame
> fin_body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
1542 scoped_ptr
<SpdyFrame
> req2(
1543 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 3, LOWEST
, true));
1544 scoped_ptr
<SpdyFrame
> resp2(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 3));
1546 SettingsMap settings
;
1547 const uint32 max_concurrent_streams
= 1;
1548 settings
[SETTINGS_MAX_CONCURRENT_STREAMS
] =
1549 SettingsFlagsAndValue(SETTINGS_FLAG_NONE
, max_concurrent_streams
);
1550 scoped_ptr
<SpdyFrame
> settings_frame(
1551 spdy_util_
.ConstructSpdySettings(settings
));
1552 scoped_ptr
<SpdyFrame
> settings_ack(spdy_util_
.ConstructSpdySettingsAck());
1554 MockWrite writes
[] = {
1555 CreateMockWrite(*req
, 0),
1556 CreateMockWrite(*settings_ack
, 5),
1557 CreateMockWrite(*req2
, 6),
1559 MockRead reads
[] = {
1560 CreateMockRead(*settings_frame
, 1),
1561 CreateMockRead(*resp
, 2),
1562 CreateMockRead(*body
, 3),
1563 CreateMockRead(*fin_body
, 4),
1564 CreateMockRead(*resp2
, 7),
1565 MockRead(ASYNC
, ERR_CONNECTION_RESET
, 8), // Abort!
1568 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
1569 SequencedSocketData
data_placeholder(NULL
, 0, NULL
, 0);
1572 TransactionHelperResult out
;
1573 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
1574 BoundNetLog(), GetParam(), NULL
);
1575 helper
.RunPreTestSetup();
1576 helper
.AddData(&data
);
1577 // We require placeholder data because three get requests are sent out, so
1578 // there needs to be three sets of SSL connection data.
1579 helper
.AddData(&data_placeholder
);
1580 helper
.AddData(&data_placeholder
);
1581 HttpNetworkTransaction
trans1(DEFAULT_PRIORITY
, helper
.session().get());
1582 HttpNetworkTransaction
trans2(DEFAULT_PRIORITY
, helper
.session().get());
1583 HttpNetworkTransaction
* trans3(
1584 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
1586 TestCompletionCallback callback1
;
1587 TestCompletionCallback callback2
;
1588 KillerCallback
callback3(trans3
);
1590 HttpRequestInfo httpreq1
= CreateGetRequest();
1591 HttpRequestInfo httpreq2
= CreateGetRequest();
1592 HttpRequestInfo httpreq3
= CreateGetRequest();
1594 out
.rv
= trans1
.Start(&httpreq1
, callback1
.callback(), log
);
1595 ASSERT_EQ(out
.rv
, ERR_IO_PENDING
);
1596 // Run transaction 1 through quickly to force a read of our SETTINGS frame.
1597 out
.rv
= callback1
.WaitForResult();
1598 ASSERT_EQ(OK
, out
.rv
);
1600 out
.rv
= trans2
.Start(&httpreq2
, callback2
.callback(), log
);
1601 ASSERT_EQ(out
.rv
, ERR_IO_PENDING
);
1602 out
.rv
= trans3
->Start(&httpreq3
, callback3
.callback(), log
);
1603 ASSERT_EQ(out
.rv
, ERR_IO_PENDING
);
1604 out
.rv
= callback3
.WaitForResult();
1605 ASSERT_EQ(ERR_ABORTED
, out
.rv
);
1607 const HttpResponseInfo
* response1
= trans1
.GetResponseInfo();
1608 ASSERT_TRUE(response1
!= NULL
);
1609 EXPECT_TRUE(response1
->headers
.get() != NULL
);
1610 EXPECT_TRUE(response1
->was_fetched_via_spdy
);
1611 out
.status_line
= response1
->headers
->GetStatusLine();
1612 out
.response_info
= *response1
;
1613 out
.rv
= ReadTransaction(&trans1
, &out
.response_data
);
1614 EXPECT_EQ(OK
, out
.rv
);
1616 const HttpResponseInfo
* response2
= trans2
.GetResponseInfo();
1617 ASSERT_TRUE(response2
!= NULL
);
1618 out
.status_line
= response2
->headers
->GetStatusLine();
1619 out
.response_info
= *response2
;
1620 out
.rv
= ReadTransaction(&trans2
, &out
.response_data
);
1621 EXPECT_EQ(ERR_CONNECTION_RESET
, out
.rv
);
1623 helper
.VerifyDataConsumed();
1626 // Test that a simple PUT request works.
1627 TEST_P(SpdyNetworkTransactionTest
, Put
) {
1628 // Setup the request
1629 HttpRequestInfo request
;
1630 request
.method
= "PUT";
1631 request
.url
= GURL(GetDefaultUrl());
1633 scoped_ptr
<SpdyHeaderBlock
> put_headers(
1634 spdy_util_
.ConstructPutHeaderBlock(GetDefaultUrl(), 0));
1635 scoped_ptr
<SpdyFrame
> req(
1636 spdy_util_
.ConstructSpdySyn(1, *put_headers
, LOWEST
, false, true));
1637 MockWrite writes
[] = {
1638 CreateMockWrite(*req
, 0),
1641 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
1642 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
1643 MockRead reads
[] = {
1644 CreateMockRead(*resp
, 1),
1645 CreateMockRead(*body
, 2),
1646 MockRead(ASYNC
, 0, 3) // EOF
1649 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
1650 NormalSpdyTransactionHelper
helper(request
, DEFAULT_PRIORITY
,
1651 BoundNetLog(), GetParam(), NULL
);
1652 helper
.RunToCompletion(&data
);
1653 TransactionHelperResult out
= helper
.output();
1655 EXPECT_EQ(OK
, out
.rv
);
1656 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1659 // Test that a simple HEAD request works.
1660 TEST_P(SpdyNetworkTransactionTest
, Head
) {
1661 // Setup the request
1662 HttpRequestInfo request
;
1663 request
.method
= "HEAD";
1664 request
.url
= GURL(GetDefaultUrl());
1666 scoped_ptr
<SpdyHeaderBlock
> head_headers(
1667 spdy_util_
.ConstructHeadHeaderBlock(GetDefaultUrl(), 0));
1668 scoped_ptr
<SpdyFrame
> req(
1669 spdy_util_
.ConstructSpdySyn(1, *head_headers
, LOWEST
, false, true));
1670 MockWrite writes
[] = {
1671 CreateMockWrite(*req
, 0),
1674 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
1675 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
1676 MockRead reads
[] = {
1677 CreateMockRead(*resp
, 1),
1678 CreateMockRead(*body
, 2),
1679 MockRead(ASYNC
, 0, 3) // EOF
1682 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
1683 NormalSpdyTransactionHelper
helper(request
, DEFAULT_PRIORITY
,
1684 BoundNetLog(), GetParam(), NULL
);
1685 helper
.RunToCompletion(&data
);
1686 TransactionHelperResult out
= helper
.output();
1688 EXPECT_EQ(OK
, out
.rv
);
1689 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1692 // Test that a simple POST works.
1693 TEST_P(SpdyNetworkTransactionTest
, Post
) {
1694 scoped_ptr
<SpdyFrame
> req(spdy_util_
.ConstructSpdyPost(
1695 GetDefaultUrl(), 1, kUploadDataSize
, LOWEST
, NULL
, 0));
1696 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
1697 MockWrite writes
[] = {
1698 CreateMockWrite(*req
, 0), CreateMockWrite(*body
, 1), // POST upload frame
1701 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyPostSynReply(NULL
, 0));
1702 MockRead reads
[] = {
1703 CreateMockRead(*resp
, 2),
1704 CreateMockRead(*body
, 3),
1705 MockRead(ASYNC
, 0, 4) // EOF
1708 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
1709 NormalSpdyTransactionHelper
helper(CreatePostRequest(), DEFAULT_PRIORITY
,
1710 BoundNetLog(), GetParam(), NULL
);
1711 helper
.RunToCompletion(&data
);
1712 TransactionHelperResult out
= helper
.output();
1713 EXPECT_EQ(OK
, out
.rv
);
1714 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1715 EXPECT_EQ("hello!", out
.response_data
);
1718 // Test that a POST with a file works.
1719 TEST_P(SpdyNetworkTransactionTest
, FilePost
) {
1720 scoped_ptr
<SpdyFrame
> req(spdy_util_
.ConstructSpdyPost(
1721 GetDefaultUrl(), 1, kUploadDataSize
, LOWEST
, NULL
, 0));
1722 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
1723 MockWrite writes
[] = {
1724 CreateMockWrite(*req
, 0), CreateMockWrite(*body
, 1), // POST upload frame
1727 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyPostSynReply(NULL
, 0));
1728 MockRead reads
[] = {
1729 CreateMockRead(*resp
, 2),
1730 CreateMockRead(*body
, 3),
1731 MockRead(ASYNC
, 0, 4) // EOF
1734 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
1735 NormalSpdyTransactionHelper
helper(CreateFilePostRequest(), DEFAULT_PRIORITY
,
1736 BoundNetLog(), GetParam(), NULL
);
1737 helper
.RunToCompletion(&data
);
1738 TransactionHelperResult out
= helper
.output();
1739 EXPECT_EQ(OK
, out
.rv
);
1740 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1741 EXPECT_EQ("hello!", out
.response_data
);
1744 // Test that a POST with a unreadable file fails.
1745 TEST_P(SpdyNetworkTransactionTest
, UnreadableFilePost
) {
1746 MockWrite writes
[] = {
1747 MockWrite(ASYNC
, 0, 0) // EOF
1749 MockRead reads
[] = {
1750 MockRead(ASYNC
, 0, 1) // EOF
1753 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
1754 NormalSpdyTransactionHelper
helper(CreateUnreadableFilePostRequest(),
1756 BoundNetLog(), GetParam(), NULL
);
1757 helper
.RunPreTestSetup();
1758 helper
.AddData(&data
);
1759 helper
.RunDefaultTest();
1761 base::RunLoop().RunUntilIdle();
1762 helper
.VerifyDataNotConsumed();
1763 EXPECT_EQ(ERR_ACCESS_DENIED
, helper
.output().rv
);
1766 // Test that a complex POST works.
1767 TEST_P(SpdyNetworkTransactionTest
, ComplexPost
) {
1768 scoped_ptr
<SpdyFrame
> req(spdy_util_
.ConstructSpdyPost(
1769 GetDefaultUrl(), 1, kUploadDataSize
, LOWEST
, NULL
, 0));
1770 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
1771 MockWrite writes
[] = {
1772 CreateMockWrite(*req
, 0), CreateMockWrite(*body
, 1), // POST upload frame
1775 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyPostSynReply(NULL
, 0));
1776 MockRead reads
[] = {
1777 CreateMockRead(*resp
, 2),
1778 CreateMockRead(*body
, 3),
1779 MockRead(ASYNC
, 0, 4) // EOF
1782 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
1783 NormalSpdyTransactionHelper
helper(CreateComplexPostRequest(),
1785 BoundNetLog(), GetParam(), NULL
);
1786 helper
.RunToCompletion(&data
);
1787 TransactionHelperResult out
= helper
.output();
1788 EXPECT_EQ(OK
, out
.rv
);
1789 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1790 EXPECT_EQ("hello!", out
.response_data
);
1793 // Test that a chunked POST works.
1794 TEST_P(SpdyNetworkTransactionTest
, ChunkedPost
) {
1795 scoped_ptr
<SpdyFrame
> req(spdy_util_
.ConstructChunkedSpdyPost(NULL
, 0));
1796 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
1797 MockWrite writes
[] = {
1798 CreateMockWrite(*req
, 0), CreateMockWrite(*body
, 1),
1801 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyPostSynReply(NULL
, 0));
1802 MockRead reads
[] = {
1803 CreateMockRead(*resp
, 2),
1804 CreateMockRead(*body
, 3),
1805 MockRead(ASYNC
, 0, 4) // EOF
1808 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
1809 NormalSpdyTransactionHelper
helper(CreateChunkedPostRequest(),
1811 BoundNetLog(), GetParam(), NULL
);
1813 // These chunks get merged into a single frame when being sent.
1814 const int kFirstChunkSize
= kUploadDataSize
/2;
1815 upload_chunked_data_stream()->AppendData(kUploadData
, kFirstChunkSize
, false);
1816 upload_chunked_data_stream()->AppendData(
1817 kUploadData
+ kFirstChunkSize
, kUploadDataSize
- kFirstChunkSize
, true);
1819 helper
.RunToCompletion(&data
);
1820 TransactionHelperResult out
= helper
.output();
1821 EXPECT_EQ(OK
, out
.rv
);
1822 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1823 EXPECT_EQ(kUploadData
, out
.response_data
);
1826 // Test that a chunked POST works with chunks appended after transaction starts.
1827 TEST_P(SpdyNetworkTransactionTest
, DelayedChunkedPost
) {
1828 scoped_ptr
<SpdyFrame
> req(spdy_util_
.ConstructChunkedSpdyPost(NULL
, 0));
1829 scoped_ptr
<SpdyFrame
> chunk1(spdy_util_
.ConstructSpdyBodyFrame(1, false));
1830 scoped_ptr
<SpdyFrame
> chunk2(spdy_util_
.ConstructSpdyBodyFrame(1, false));
1831 scoped_ptr
<SpdyFrame
> chunk3(spdy_util_
.ConstructSpdyBodyFrame(1, true));
1832 MockWrite writes
[] = {
1833 CreateMockWrite(*req
, 0),
1834 CreateMockWrite(*chunk1
, 1),
1835 CreateMockWrite(*chunk2
, 2),
1836 CreateMockWrite(*chunk3
, 3),
1839 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyPostSynReply(NULL
, 0));
1840 MockRead reads
[] = {
1841 CreateMockRead(*resp
, 4),
1842 CreateMockRead(*chunk1
, 5),
1843 CreateMockRead(*chunk2
, 6),
1844 CreateMockRead(*chunk3
, 7),
1845 MockRead(ASYNC
, 0, 8) // EOF
1848 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
1849 NormalSpdyTransactionHelper
helper(CreateChunkedPostRequest(),
1851 BoundNetLog(), GetParam(), NULL
);
1853 upload_chunked_data_stream()->AppendData(kUploadData
, kUploadDataSize
, false);
1855 helper
.RunPreTestSetup();
1856 helper
.AddData(&data
);
1857 ASSERT_TRUE(helper
.StartDefaultTest());
1859 base::RunLoop().RunUntilIdle();
1860 upload_chunked_data_stream()->AppendData(kUploadData
, kUploadDataSize
, false);
1861 base::RunLoop().RunUntilIdle();
1862 upload_chunked_data_stream()->AppendData(kUploadData
, kUploadDataSize
, true);
1864 helper
.FinishDefaultTest();
1865 helper
.VerifyDataConsumed();
1867 std::string expected_response
;
1868 expected_response
+= kUploadData
;
1869 expected_response
+= kUploadData
;
1870 expected_response
+= kUploadData
;
1872 TransactionHelperResult out
= helper
.output();
1873 EXPECT_EQ(OK
, out
.rv
);
1874 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1875 EXPECT_EQ(expected_response
, out
.response_data
);
1878 // Test that a POST without any post data works.
1879 TEST_P(SpdyNetworkTransactionTest
, NullPost
) {
1880 BufferedSpdyFramer
framer(spdy_util_
.spdy_version(), false);
1881 // Setup the request
1882 HttpRequestInfo request
;
1883 request
.method
= "POST";
1884 request
.url
= GURL(GetDefaultUrl());
1885 // Create an empty UploadData.
1886 request
.upload_data_stream
= NULL
;
1888 // When request.upload_data_stream is NULL for post, content-length is
1889 // expected to be 0.
1890 scoped_ptr
<SpdyHeaderBlock
> req_block(
1891 spdy_util_
.ConstructPostHeaderBlock(GetDefaultUrl(), 0));
1892 scoped_ptr
<SpdyFrame
> req(
1893 spdy_util_
.ConstructSpdySyn(1, *req_block
, LOWEST
, false, true));
1895 MockWrite writes
[] = {
1896 CreateMockWrite(*req
, 0),
1899 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyPostSynReply(NULL
, 0));
1900 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
1901 MockRead reads
[] = {
1902 CreateMockRead(*resp
, 1),
1903 CreateMockRead(*body
, 2),
1904 MockRead(ASYNC
, 0, 3) // EOF
1907 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
1909 NormalSpdyTransactionHelper
helper(request
, DEFAULT_PRIORITY
,
1910 BoundNetLog(), GetParam(), NULL
);
1911 helper
.RunToCompletion(&data
);
1912 TransactionHelperResult out
= helper
.output();
1913 EXPECT_EQ(OK
, out
.rv
);
1914 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1915 EXPECT_EQ("hello!", out
.response_data
);
1918 // Test that a simple POST works.
1919 TEST_P(SpdyNetworkTransactionTest
, EmptyPost
) {
1920 BufferedSpdyFramer
framer(spdy_util_
.spdy_version(), false);
1921 // Create an empty UploadDataStream.
1922 ScopedVector
<UploadElementReader
> element_readers
;
1923 ElementsUploadDataStream
stream(element_readers
.Pass(), 0);
1925 // Setup the request
1926 HttpRequestInfo request
;
1927 request
.method
= "POST";
1928 request
.url
= GURL(GetDefaultUrl());
1929 request
.upload_data_stream
= &stream
;
1931 const uint64 kContentLength
= 0;
1933 scoped_ptr
<SpdyHeaderBlock
> req_block(
1934 spdy_util_
.ConstructPostHeaderBlock(GetDefaultUrl(), kContentLength
));
1935 scoped_ptr
<SpdyFrame
> req(
1936 spdy_util_
.ConstructSpdySyn(1, *req_block
, LOWEST
, false, true));
1938 MockWrite writes
[] = {
1939 CreateMockWrite(*req
, 0),
1942 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyPostSynReply(NULL
, 0));
1943 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
1944 MockRead reads
[] = {
1945 CreateMockRead(*resp
, 1),
1946 CreateMockRead(*body
, 2),
1947 MockRead(ASYNC
, 0, 3) // EOF
1950 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
1952 NormalSpdyTransactionHelper
helper(request
, DEFAULT_PRIORITY
,
1953 BoundNetLog(), GetParam(), NULL
);
1954 helper
.RunToCompletion(&data
);
1955 TransactionHelperResult out
= helper
.output();
1956 EXPECT_EQ(OK
, out
.rv
);
1957 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1958 EXPECT_EQ("hello!", out
.response_data
);
1961 // While we're doing a post, the server sends the reply before upload completes.
1962 TEST_P(SpdyNetworkTransactionTest
, ResponseBeforePostCompletes
) {
1963 scoped_ptr
<SpdyFrame
> req(spdy_util_
.ConstructChunkedSpdyPost(NULL
, 0));
1964 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
1965 MockWrite writes
[] = {
1966 CreateMockWrite(*req
, 0),
1967 CreateMockWrite(*body
, 3),
1969 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyPostSynReply(NULL
, 0));
1970 MockRead reads
[] = {
1971 CreateMockRead(*resp
, 1),
1972 CreateMockRead(*body
, 2),
1973 MockRead(ASYNC
, 0, 4) // EOF
1976 // Write the request headers, and read the complete response
1977 // while still waiting for chunked request data.
1978 DeterministicSocketData
data(reads
, arraysize(reads
),
1979 writes
, arraysize(writes
));
1980 NormalSpdyTransactionHelper
helper(CreateChunkedPostRequest(),
1982 BoundNetLog(), GetParam(), NULL
);
1983 helper
.SetDeterministic();
1984 helper
.RunPreTestSetup();
1985 helper
.AddDeterministicData(&data
);
1987 ASSERT_TRUE(helper
.StartDefaultTest());
1989 // Process the request headers, SYN_REPLY, and response body.
1990 // The request body is still in flight.
1993 const HttpResponseInfo
* response
= helper
.trans()->GetResponseInfo();
1994 EXPECT_EQ("HTTP/1.1 200 OK", response
->headers
->GetStatusLine());
1996 // Finish sending the request body.
1997 upload_chunked_data_stream()->AppendData(kUploadData
, kUploadDataSize
, true);
2000 std::string response_body
;
2001 EXPECT_EQ(OK
, ReadTransaction(helper
.trans(), &response_body
));
2002 EXPECT_EQ(kUploadData
, response_body
);
2003 helper
.VerifyDataConsumed();
2006 // The client upon cancellation tries to send a RST_STREAM frame. The mock
2007 // socket causes the TCP write to return zero. This test checks that the client
2008 // tries to queue up the RST_STREAM frame again.
2009 TEST_P(SpdyNetworkTransactionTest
, SocketWriteReturnsZero
) {
2010 scoped_ptr
<SpdyFrame
> req(
2011 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2012 scoped_ptr
<SpdyFrame
> rst(
2013 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_CANCEL
));
2014 MockWrite writes
[] = {
2015 CreateMockWrite(*req
.get(), 0, SYNCHRONOUS
),
2016 MockWrite(SYNCHRONOUS
, 0, 0, 2),
2017 CreateMockWrite(*rst
.get(), 3, SYNCHRONOUS
),
2020 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2021 MockRead reads
[] = {
2022 CreateMockRead(*resp
.get(), 1, ASYNC
),
2023 MockRead(ASYNC
, 0, 0, 4) // EOF
2026 DeterministicSocketData
data(reads
, arraysize(reads
),
2027 writes
, arraysize(writes
));
2028 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
2029 BoundNetLog(), GetParam(), NULL
);
2030 helper
.SetDeterministic();
2031 helper
.RunPreTestSetup();
2032 helper
.AddDeterministicData(&data
);
2033 HttpNetworkTransaction
* trans
= helper
.trans();
2035 TestCompletionCallback callback
;
2036 int rv
= trans
->Start(
2037 &CreateGetRequest(), callback
.callback(), BoundNetLog());
2038 EXPECT_EQ(ERR_IO_PENDING
, rv
);
2042 helper
.ResetTrans();
2046 helper
.VerifyDataConsumed();
2049 // Test that the transaction doesn't crash when we don't have a reply.
2050 TEST_P(SpdyNetworkTransactionTest
, ResponseWithoutSynReply
) {
2051 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
2052 MockRead reads
[] = {
2053 CreateMockRead(*body
, 1), MockRead(ASYNC
, 0, 3) // EOF
2056 scoped_ptr
<SpdyFrame
> req(
2057 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2058 scoped_ptr
<SpdyFrame
> rst(
2059 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR
));
2060 MockWrite writes
[] = {
2061 CreateMockWrite(*req
, 0), CreateMockWrite(*rst
, 2),
2063 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
2064 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
2065 BoundNetLog(), GetParam(), NULL
);
2066 helper
.RunToCompletion(&data
);
2067 TransactionHelperResult out
= helper
.output();
2068 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR
, out
.rv
);
2071 // Test that the transaction doesn't crash when we get two replies on the same
2072 // stream ID. See http://crbug.com/45639.
2073 TEST_P(SpdyNetworkTransactionTest
, ResponseWithTwoSynReplies
) {
2074 scoped_ptr
<SpdyFrame
> req(
2075 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2076 scoped_ptr
<SpdyFrame
> rst(
2077 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR
));
2078 MockWrite writes
[] = {
2079 CreateMockWrite(*req
, 0), CreateMockWrite(*rst
, 4),
2082 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2083 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
2084 MockRead reads
[] = {
2085 CreateMockRead(*resp
, 1),
2086 CreateMockRead(*resp
, 2),
2087 CreateMockRead(*body
, 3),
2088 MockRead(ASYNC
, 0, 5) // EOF
2091 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
2093 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
2094 BoundNetLog(), GetParam(), NULL
);
2095 helper
.RunPreTestSetup();
2096 helper
.AddData(&data
);
2098 HttpNetworkTransaction
* trans
= helper
.trans();
2100 TestCompletionCallback callback
;
2101 int rv
= trans
->Start(&helper
.request(), callback
.callback(), BoundNetLog());
2102 EXPECT_EQ(ERR_IO_PENDING
, rv
);
2103 rv
= callback
.WaitForResult();
2106 const HttpResponseInfo
* response
= trans
->GetResponseInfo();
2107 ASSERT_TRUE(response
!= NULL
);
2108 EXPECT_TRUE(response
->headers
.get() != NULL
);
2109 EXPECT_TRUE(response
->was_fetched_via_spdy
);
2110 std::string response_data
;
2111 rv
= ReadTransaction(trans
, &response_data
);
2112 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR
, rv
);
2114 helper
.VerifyDataConsumed();
2117 TEST_P(SpdyNetworkTransactionTest
, ResetReplyWithTransferEncoding
) {
2118 // Construct the request.
2119 scoped_ptr
<SpdyFrame
> req(
2120 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2121 scoped_ptr
<SpdyFrame
> rst(
2122 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR
));
2123 MockWrite writes
[] = {
2124 CreateMockWrite(*req
, 0), CreateMockWrite(*rst
, 2),
2127 const char* const headers
[] = {
2128 "transfer-encoding", "chunked"
2130 scoped_ptr
<SpdyFrame
> resp(
2131 spdy_util_
.ConstructSpdyGetSynReply(headers
, 1, 1));
2132 scoped_ptr
<SpdyFrame
> body(
2133 spdy_util_
.ConstructSpdyBodyFrame(1, true));
2134 MockRead reads
[] = {
2135 CreateMockRead(*resp
, 1),
2136 CreateMockRead(*body
, 3),
2137 MockRead(ASYNC
, 0, 4) // EOF
2140 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
2141 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
2142 BoundNetLog(), GetParam(), NULL
);
2143 helper
.RunToCompletion(&data
);
2144 TransactionHelperResult out
= helper
.output();
2145 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR
, out
.rv
);
2147 helper
.session()->spdy_session_pool()->CloseAllSessions();
2148 helper
.VerifyDataConsumed();
2151 TEST_P(SpdyNetworkTransactionTest
, ResetPushWithTransferEncoding
) {
2152 // Construct the request.
2153 scoped_ptr
<SpdyFrame
> req(
2154 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2155 scoped_ptr
<SpdyFrame
> rst(
2156 spdy_util_
.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR
));
2157 MockWrite writes
[] = {
2158 CreateMockWrite(*req
, 0), CreateMockWrite(*rst
, 4),
2161 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2162 const char* const headers
[] = {
2163 "transfer-encoding", "chunked"
2165 scoped_ptr
<SpdyFrame
> push(
2166 spdy_util_
.ConstructSpdyPush(headers
, arraysize(headers
) / 2, 2, 1,
2167 GetDefaultUrlWithPath("/1").c_str()));
2168 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
2169 MockRead reads
[] = {
2170 CreateMockRead(*resp
, 1),
2171 CreateMockRead(*push
, 2),
2172 CreateMockRead(*body
, 3),
2173 MockRead(ASYNC
, 0, 5) // EOF
2176 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
2177 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
2178 BoundNetLog(), GetParam(), NULL
);
2179 helper
.RunToCompletion(&data
);
2180 TransactionHelperResult out
= helper
.output();
2181 EXPECT_EQ(OK
, out
.rv
);
2182 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
2183 EXPECT_EQ("hello!", out
.response_data
);
2185 helper
.session()->spdy_session_pool()->CloseAllSessions();
2186 helper
.VerifyDataConsumed();
2189 TEST_P(SpdyNetworkTransactionTest
, CancelledTransaction
) {
2190 // Construct the request.
2191 scoped_ptr
<SpdyFrame
> req(
2192 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2193 MockWrite writes
[] = {
2194 CreateMockWrite(*req
),
2197 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2198 MockRead reads
[] = {
2199 CreateMockRead(*resp
),
2200 // This following read isn't used by the test, except during the
2201 // RunUntilIdle() call at the end since the SpdySession survives the
2202 // HttpNetworkTransaction and still tries to continue Read()'ing. Any
2203 // MockRead will do here.
2204 MockRead(ASYNC
, 0, 0) // EOF
2207 StaticSocketDataProvider
data(reads
, arraysize(reads
),
2208 writes
, arraysize(writes
));
2210 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
2211 BoundNetLog(), GetParam(), NULL
);
2212 helper
.RunPreTestSetup();
2213 helper
.AddData(&data
);
2214 HttpNetworkTransaction
* trans
= helper
.trans();
2216 TestCompletionCallback callback
;
2217 int rv
= trans
->Start(
2218 &CreateGetRequest(), callback
.callback(), BoundNetLog());
2219 EXPECT_EQ(ERR_IO_PENDING
, rv
);
2220 helper
.ResetTrans(); // Cancel the transaction.
2222 // Flush the MessageLoop while the SpdySessionDependencies (in particular, the
2223 // MockClientSocketFactory) are still alive.
2224 base::RunLoop().RunUntilIdle();
2225 helper
.VerifyDataNotConsumed();
2228 // Verify that the client sends a Rst Frame upon cancelling the stream.
2229 TEST_P(SpdyNetworkTransactionTest
, CancelledTransactionSendRst
) {
2230 scoped_ptr
<SpdyFrame
> req(
2231 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2232 scoped_ptr
<SpdyFrame
> rst(
2233 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_CANCEL
));
2234 MockWrite writes
[] = {
2235 CreateMockWrite(*req
, 0, SYNCHRONOUS
),
2236 CreateMockWrite(*rst
, 2, SYNCHRONOUS
),
2239 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2240 MockRead reads
[] = {
2241 CreateMockRead(*resp
, 1, ASYNC
),
2242 MockRead(ASYNC
, 0, 0, 3) // EOF
2245 DeterministicSocketData
data(reads
, arraysize(reads
),
2246 writes
, arraysize(writes
));
2248 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
2251 helper
.SetDeterministic();
2252 helper
.RunPreTestSetup();
2253 helper
.AddDeterministicData(&data
);
2254 HttpNetworkTransaction
* trans
= helper
.trans();
2256 TestCompletionCallback callback
;
2258 int rv
= trans
->Start(
2259 &CreateGetRequest(), callback
.callback(), BoundNetLog());
2260 EXPECT_EQ(ERR_IO_PENDING
, rv
);
2264 helper
.ResetTrans();
2268 helper
.VerifyDataConsumed();
2271 // Verify that the client can correctly deal with the user callback attempting
2272 // to start another transaction on a session that is closing down. See
2273 // http://crbug.com/47455
2274 TEST_P(SpdyNetworkTransactionTest
, StartTransactionOnReadCallback
) {
2275 scoped_ptr
<SpdyFrame
> req(
2276 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2277 MockWrite writes
[] = {CreateMockWrite(*req
)};
2278 MockWrite writes2
[] = {CreateMockWrite(*req
, 0)};
2280 // The indicated length of this frame is longer than its actual length. When
2281 // the session receives an empty frame after this one, it shuts down the
2282 // session, and calls the read callback with the incomplete data.
2283 const uint8 kGetBodyFrame2
[] = {
2284 0x00, 0x00, 0x00, 0x01,
2285 0x01, 0x00, 0x00, 0x07,
2286 'h', 'e', 'l', 'l', 'o', '!',
2289 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2290 MockRead reads
[] = {
2291 CreateMockRead(*resp
, 1),
2292 MockRead(ASYNC
, ERR_IO_PENDING
, 2), // Force a pause
2293 MockRead(ASYNC
, reinterpret_cast<const char*>(kGetBodyFrame2
),
2294 arraysize(kGetBodyFrame2
), 3),
2295 MockRead(ASYNC
, ERR_IO_PENDING
, 4), // Force a pause
2296 MockRead(ASYNC
, 0, 0, 5), // EOF
2298 MockRead reads2
[] = {
2299 CreateMockRead(*resp
, 1), MockRead(ASYNC
, 0, 0, 2), // EOF
2302 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
2303 SequencedSocketData
data2(reads2
, arraysize(reads2
), writes2
,
2304 arraysize(writes2
));
2306 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
2307 BoundNetLog(), GetParam(), NULL
);
2308 helper
.RunPreTestSetup();
2309 helper
.AddData(&data
);
2310 helper
.AddData(&data2
);
2311 HttpNetworkTransaction
* trans
= helper
.trans();
2313 // Start the transaction with basic parameters.
2314 TestCompletionCallback callback
;
2315 int rv
= trans
->Start(&helper
.request(), callback
.callback(), BoundNetLog());
2316 EXPECT_EQ(ERR_IO_PENDING
, rv
);
2317 rv
= callback
.WaitForResult();
2319 const int kSize
= 3000;
2320 scoped_refptr
<IOBuffer
> buf(new IOBuffer(kSize
));
2323 base::Bind(&SpdyNetworkTransactionTest::StartTransactionCallback
,
2324 helper
.session(), GURL(GetDefaultUrl())));
2325 ASSERT_EQ(ERR_IO_PENDING
, rv
);
2326 // This forces an err_IO_pending, which sets the callback.
2327 data
.CompleteRead();
2328 // This finishes the read.
2329 data
.CompleteRead();
2330 helper
.VerifyDataConsumed();
2333 // Verify that the client can correctly deal with the user callback deleting the
2334 // transaction. Failures will usually be valgrind errors. See
2335 // http://crbug.com/46925
2336 TEST_P(SpdyNetworkTransactionTest
, DeleteSessionOnReadCallback
) {
2337 scoped_ptr
<SpdyFrame
> req(
2338 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2339 MockWrite writes
[] = {CreateMockWrite(*req
, 0)};
2341 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2342 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
2343 MockRead reads
[] = {
2344 CreateMockRead(*resp
.get(), 1),
2345 MockRead(ASYNC
, ERR_IO_PENDING
, 2), // Force a pause
2346 CreateMockRead(*body
.get(), 3),
2347 MockRead(ASYNC
, 0, 0, 4), // EOF
2350 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
2352 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
2353 BoundNetLog(), GetParam(), NULL
);
2354 helper
.RunPreTestSetup();
2355 helper
.AddData(&data
);
2356 HttpNetworkTransaction
* trans
= helper
.trans();
2358 // Start the transaction with basic parameters.
2359 TestCompletionCallback callback
;
2360 int rv
= trans
->Start(&helper
.request(), callback
.callback(), BoundNetLog());
2361 EXPECT_EQ(ERR_IO_PENDING
, rv
);
2362 rv
= callback
.WaitForResult();
2364 // Setup a user callback which will delete the session, and clear out the
2365 // memory holding the stream object. Note that the callback deletes trans.
2366 const int kSize
= 3000;
2367 scoped_refptr
<IOBuffer
> buf(new IOBuffer(kSize
));
2371 base::Bind(&SpdyNetworkTransactionTest::DeleteSessionCallback
,
2372 base::Unretained(&helper
)));
2373 ASSERT_EQ(ERR_IO_PENDING
, rv
);
2374 data
.CompleteRead();
2376 // Finish running rest of tasks.
2377 base::RunLoop().RunUntilIdle();
2378 helper
.VerifyDataConsumed();
2381 // Send a spdy request to www.example.org that gets redirected to www.foo.com.
2382 TEST_P(SpdyNetworkTransactionTest
, DISABLED_RedirectGetRequest
) {
2383 scoped_ptr
<SpdyHeaderBlock
> headers(
2384 spdy_util_
.ConstructGetHeaderBlock(GetDefaultUrl()));
2385 (*headers
)["user-agent"] = "";
2386 (*headers
)["accept-encoding"] = "gzip, deflate";
2387 scoped_ptr
<SpdyHeaderBlock
> headers2(
2388 spdy_util_
.ConstructGetHeaderBlock("http://www.foo.com/index.php"));
2389 (*headers2
)["user-agent"] = "";
2390 (*headers2
)["accept-encoding"] = "gzip, deflate";
2392 // Setup writes/reads to www.example.org
2393 scoped_ptr
<SpdyFrame
> req(
2394 spdy_util_
.ConstructSpdySyn(1, *headers
, LOWEST
, false, true));
2395 scoped_ptr
<SpdyFrame
> req2(
2396 spdy_util_
.ConstructSpdySyn(1, *headers2
, LOWEST
, false, true));
2397 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReplyRedirect(1));
2398 MockWrite writes
[] = {
2399 CreateMockWrite(*req
, 1),
2401 MockRead reads
[] = {
2402 CreateMockRead(*resp
, 2),
2403 MockRead(ASYNC
, 0, 0, 3) // EOF
2406 // Setup writes/reads to www.foo.com
2407 scoped_ptr
<SpdyFrame
> resp2(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2408 scoped_ptr
<SpdyFrame
> body2(spdy_util_
.ConstructSpdyBodyFrame(1, true));
2409 MockWrite writes2
[] = {
2410 CreateMockWrite(*req2
, 1),
2412 MockRead reads2
[] = {
2413 CreateMockRead(*resp2
, 2),
2414 CreateMockRead(*body2
, 3),
2415 MockRead(ASYNC
, 0, 0, 4) // EOF
2417 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
2418 SequencedSocketData
data2(reads2
, arraysize(reads2
), writes2
,
2419 arraysize(writes2
));
2421 // TODO(erikchen): Make test support SPDYSSL, SPDYNPN
2424 SpdyURLRequestContext
spdy_url_request_context(GetParam().protocol
);
2425 scoped_ptr
<URLRequest
> r(spdy_url_request_context
.CreateRequest(
2426 GURL(GetDefaultUrl()), DEFAULT_PRIORITY
, &d
));
2427 spdy_url_request_context
.socket_factory().
2428 AddSocketDataProvider(&data
);
2429 spdy_url_request_context
.socket_factory().
2430 AddSocketDataProvider(&data2
);
2432 d
.set_quit_on_redirect(true);
2434 base::RunLoop().Run();
2436 EXPECT_EQ(1, d
.received_redirect_count());
2438 r
->FollowDeferredRedirect();
2439 base::RunLoop().Run();
2440 EXPECT_EQ(1, d
.response_started_count());
2441 EXPECT_FALSE(d
.received_data_before_response());
2442 EXPECT_EQ(URLRequestStatus::SUCCESS
, r
->status().status());
2443 std::string
contents("hello!");
2444 EXPECT_EQ(contents
, d
.data_received());
2446 EXPECT_TRUE(data
.AllReadDataConsumed());
2447 EXPECT_TRUE(data
.AllWriteDataConsumed());
2448 EXPECT_TRUE(data2
.AllReadDataConsumed());
2449 EXPECT_TRUE(data2
.AllWriteDataConsumed());
2452 // Send a spdy request to www.example.org. Get a pushed stream that redirects to
2454 TEST_P(SpdyNetworkTransactionTest
, DISABLED_RedirectServerPush
) {
2455 scoped_ptr
<SpdyHeaderBlock
> headers(
2456 spdy_util_
.ConstructGetHeaderBlock(GetDefaultUrl()));
2457 (*headers
)["user-agent"] = "";
2458 (*headers
)["accept-encoding"] = "gzip, deflate";
2460 // Setup writes/reads to www.example.org
2461 scoped_ptr
<SpdyFrame
> req(
2462 spdy_util_
.ConstructSpdySyn(1, *headers
, LOWEST
, false, true));
2463 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2464 scoped_ptr
<SpdyFrame
> rep(spdy_util_
.ConstructSpdyPush(
2465 NULL
, 0, 2, 1, GetDefaultUrlWithPath("/foo.dat").c_str(),
2466 "301 Moved Permanently", "http://www.foo.com/index.php"));
2467 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
2468 scoped_ptr
<SpdyFrame
> rst(
2469 spdy_util_
.ConstructSpdyRstStream(2, RST_STREAM_CANCEL
));
2470 MockWrite writes
[] = {
2471 CreateMockWrite(*req
, 1),
2472 CreateMockWrite(*rst
, 6),
2474 MockRead reads
[] = {
2475 CreateMockRead(*resp
, 2),
2476 CreateMockRead(*rep
, 3),
2477 CreateMockRead(*body
, 4),
2478 MockRead(ASYNC
, ERR_IO_PENDING
, 5), // Force a pause
2479 MockRead(ASYNC
, 0, 0, 7) // EOF
2482 // Setup writes/reads to www.foo.com
2483 scoped_ptr
<SpdyHeaderBlock
> headers2(
2484 spdy_util_
.ConstructGetHeaderBlock("http://www.foo.com/index.php"));
2485 (*headers2
)["user-agent"] = "";
2486 (*headers2
)["accept-encoding"] = "gzip, deflate";
2487 scoped_ptr
<SpdyFrame
> req2(
2488 spdy_util_
.ConstructSpdySyn(1, *headers2
, LOWEST
, false, true));
2489 scoped_ptr
<SpdyFrame
> resp2(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2490 scoped_ptr
<SpdyFrame
> body2(spdy_util_
.ConstructSpdyBodyFrame(1, true));
2491 MockWrite writes2
[] = {
2492 CreateMockWrite(*req2
, 1),
2494 MockRead reads2
[] = {
2495 CreateMockRead(*resp2
, 2),
2496 CreateMockRead(*body2
, 3),
2497 MockRead(ASYNC
, 0, 0, 5) // EOF
2499 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
2500 SequencedSocketData
data2(reads2
, arraysize(reads2
), writes2
,
2501 arraysize(writes2
));
2503 // TODO(erikchen): Make test support SPDYSSL, SPDYNPN
2506 SpdyURLRequestContext
spdy_url_request_context(GetParam().protocol
);
2508 scoped_ptr
<URLRequest
> r(spdy_url_request_context
.CreateRequest(
2509 GURL(GetDefaultUrl()), DEFAULT_PRIORITY
, &d
));
2510 spdy_url_request_context
.socket_factory().
2511 AddSocketDataProvider(&data
);
2514 base::RunLoop().Run();
2516 EXPECT_EQ(0, d
.received_redirect_count());
2517 std::string
contents("hello!");
2518 EXPECT_EQ(contents
, d
.data_received());
2520 scoped_ptr
<URLRequest
> r2(spdy_url_request_context
.CreateRequest(
2521 GURL(GetDefaultUrlWithPath("/foo.dat")), DEFAULT_PRIORITY
, &d2
));
2522 spdy_url_request_context
.socket_factory().
2523 AddSocketDataProvider(&data2
);
2525 d2
.set_quit_on_redirect(true);
2527 base::RunLoop().Run();
2528 EXPECT_EQ(1, d2
.received_redirect_count());
2530 r2
->FollowDeferredRedirect();
2531 base::RunLoop().Run();
2532 EXPECT_EQ(1, d2
.response_started_count());
2533 EXPECT_FALSE(d2
.received_data_before_response());
2534 EXPECT_EQ(URLRequestStatus::SUCCESS
, r2
->status().status());
2535 std::string
contents2("hello!");
2536 EXPECT_EQ(contents2
, d2
.data_received());
2538 EXPECT_TRUE(data
.AllReadDataConsumed());
2539 EXPECT_TRUE(data
.AllWriteDataConsumed());
2540 EXPECT_TRUE(data2
.AllReadDataConsumed());
2541 EXPECT_TRUE(data2
.AllWriteDataConsumed());
2544 TEST_P(SpdyNetworkTransactionTest
, ServerPushSingleDataFrame
) {
2545 scoped_ptr
<SpdyFrame
> stream1_syn(
2546 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2547 scoped_ptr
<SpdyFrame
> stream1_body(
2548 spdy_util_
.ConstructSpdyBodyFrame(1, true));
2549 MockWrite writes
[] = {
2550 CreateMockWrite(*stream1_syn
, 0),
2553 scoped_ptr
<SpdyFrame
>
2554 stream1_reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2555 scoped_ptr
<SpdyFrame
> stream2_syn(spdy_util_
.ConstructSpdyPush(
2556 NULL
, 0, 2, 1, GetDefaultUrlWithPath("/foo.dat").c_str()));
2557 const char kPushedData
[] = "pushed";
2558 scoped_ptr
<SpdyFrame
> stream2_body(
2559 spdy_util_
.ConstructSpdyBodyFrame(
2560 2, kPushedData
, strlen(kPushedData
), true));
2561 MockRead reads
[] = {
2562 CreateMockRead(*stream1_reply
, 1),
2563 CreateMockRead(*stream2_syn
, 2),
2564 CreateMockRead(*stream1_body
, 3, SYNCHRONOUS
),
2565 CreateMockRead(*stream2_body
, 4),
2566 MockRead(SYNCHRONOUS
, ERR_IO_PENDING
, 5), // Force a pause
2569 HttpResponseInfo response
;
2570 HttpResponseInfo response2
;
2571 std::string
expected_push_result("pushed");
2572 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
2573 RunServerPushTest(&data
,
2576 expected_push_result
);
2578 // Verify the SYN_REPLY.
2579 EXPECT_TRUE(response
.headers
.get() != NULL
);
2580 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
2582 // Verify the pushed stream.
2583 EXPECT_TRUE(response2
.headers
.get() != NULL
);
2584 EXPECT_EQ("HTTP/1.1 200 OK", response2
.headers
->GetStatusLine());
2587 TEST_P(SpdyNetworkTransactionTest
, ServerPushBeforeSynReply
) {
2588 scoped_ptr
<SpdyFrame
> stream1_syn(
2589 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2590 scoped_ptr
<SpdyFrame
> stream1_body(
2591 spdy_util_
.ConstructSpdyBodyFrame(1, true));
2592 MockWrite writes
[] = {
2593 CreateMockWrite(*stream1_syn
, 0),
2596 scoped_ptr
<SpdyFrame
>
2597 stream1_reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2598 scoped_ptr
<SpdyFrame
> stream2_syn(spdy_util_
.ConstructSpdyPush(
2599 NULL
, 0, 2, 1, GetDefaultUrlWithPath("/foo.dat").c_str()));
2600 const char kPushedData
[] = "pushed";
2601 scoped_ptr
<SpdyFrame
> stream2_body(
2602 spdy_util_
.ConstructSpdyBodyFrame(
2603 2, kPushedData
, strlen(kPushedData
), true));
2604 MockRead reads
[] = {
2605 CreateMockRead(*stream2_syn
, 1),
2606 CreateMockRead(*stream1_reply
, 2),
2607 CreateMockRead(*stream1_body
, 3, SYNCHRONOUS
),
2608 CreateMockRead(*stream2_body
, 4),
2609 MockRead(SYNCHRONOUS
, ERR_IO_PENDING
, 5), // Force a pause
2612 HttpResponseInfo response
;
2613 HttpResponseInfo response2
;
2614 std::string
expected_push_result("pushed");
2615 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
2616 RunServerPushTest(&data
,
2619 expected_push_result
);
2621 // Verify the SYN_REPLY.
2622 EXPECT_TRUE(response
.headers
.get() != NULL
);
2623 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
2625 // Verify the pushed stream.
2626 EXPECT_TRUE(response2
.headers
.get() != NULL
);
2627 EXPECT_EQ("HTTP/1.1 200 OK", response2
.headers
->GetStatusLine());
2630 TEST_P(SpdyNetworkTransactionTest
, ServerPushSingleDataFrame2
) {
2631 scoped_ptr
<SpdyFrame
> stream1_syn(
2632 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2633 MockWrite writes
[] = {
2634 CreateMockWrite(*stream1_syn
, 0),
2637 scoped_ptr
<SpdyFrame
>
2638 stream1_reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2639 scoped_ptr
<SpdyFrame
> stream2_syn(spdy_util_
.ConstructSpdyPush(
2640 NULL
, 0, 2, 1, GetDefaultUrlWithPath("/foo.dat").c_str()));
2641 const char kPushedData
[] = "pushed";
2642 scoped_ptr
<SpdyFrame
> stream2_body(
2643 spdy_util_
.ConstructSpdyBodyFrame(
2644 2, kPushedData
, strlen(kPushedData
), true));
2645 scoped_ptr
<SpdyFrame
>
2646 stream1_body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
2647 MockRead reads
[] = {
2648 CreateMockRead(*stream1_reply
, 1),
2649 CreateMockRead(*stream2_syn
, 2),
2650 CreateMockRead(*stream2_body
, 3),
2651 CreateMockRead(*stream1_body
, 4, SYNCHRONOUS
),
2652 MockRead(SYNCHRONOUS
, ERR_IO_PENDING
, 5), // Force a pause
2655 HttpResponseInfo response
;
2656 HttpResponseInfo response2
;
2657 std::string
expected_push_result("pushed");
2658 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
2659 RunServerPushTest(&data
,
2662 expected_push_result
);
2664 // Verify the SYN_REPLY.
2665 EXPECT_TRUE(response
.headers
.get() != NULL
);
2666 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
2668 // Verify the pushed stream.
2669 EXPECT_TRUE(response2
.headers
.get() != NULL
);
2670 EXPECT_EQ("HTTP/1.1 200 OK", response2
.headers
->GetStatusLine());
2673 TEST_P(SpdyNetworkTransactionTest
, ServerPushServerAborted
) {
2674 scoped_ptr
<SpdyFrame
> stream1_syn(
2675 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2676 scoped_ptr
<SpdyFrame
> stream1_body(
2677 spdy_util_
.ConstructSpdyBodyFrame(1, true));
2678 MockWrite writes
[] = {
2679 CreateMockWrite(*stream1_syn
, 0),
2682 scoped_ptr
<SpdyFrame
>
2683 stream1_reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2684 scoped_ptr
<SpdyFrame
> stream2_syn(spdy_util_
.ConstructSpdyPush(
2685 NULL
, 0, 2, 1, GetDefaultUrlWithPath("/foo.dat").c_str()));
2686 scoped_ptr
<SpdyFrame
> stream2_rst(
2687 spdy_util_
.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR
));
2688 MockRead reads
[] = {
2689 CreateMockRead(*stream1_reply
, 1),
2690 CreateMockRead(*stream2_syn
, 2),
2691 CreateMockRead(*stream2_rst
, 3),
2692 CreateMockRead(*stream1_body
, 4, SYNCHRONOUS
),
2693 MockRead(SYNCHRONOUS
, ERR_IO_PENDING
, 5), // Force a pause
2696 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
2697 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
2698 BoundNetLog(), GetParam(), NULL
);
2700 helper
.RunPreTestSetup();
2701 helper
.AddData(&data
);
2703 HttpNetworkTransaction
* trans
= helper
.trans();
2705 // Start the transaction with basic parameters.
2706 TestCompletionCallback callback
;
2707 int rv
= trans
->Start(
2708 &CreateGetRequest(), callback
.callback(), BoundNetLog());
2709 EXPECT_EQ(ERR_IO_PENDING
, rv
);
2710 rv
= callback
.WaitForResult();
2713 // Verify that we consumed all test data.
2714 EXPECT_TRUE(data
.AllReadDataConsumed());
2715 EXPECT_TRUE(data
.AllWriteDataConsumed());
2717 // Verify the SYN_REPLY.
2718 HttpResponseInfo response
= *trans
->GetResponseInfo();
2719 EXPECT_TRUE(response
.headers
.get() != NULL
);
2720 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
2723 // Verify that we don't leak streams and that we properly send a reset
2724 // if the server pushes the same stream twice.
2725 TEST_P(SpdyNetworkTransactionTest
, ServerPushDuplicate
) {
2726 scoped_ptr
<SpdyFrame
> stream1_syn(
2727 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2728 scoped_ptr
<SpdyFrame
> stream1_body(
2729 spdy_util_
.ConstructSpdyBodyFrame(1, true));
2730 scoped_ptr
<SpdyFrame
> stream3_rst(
2731 spdy_util_
.ConstructSpdyRstStream(4, RST_STREAM_PROTOCOL_ERROR
));
2732 MockWrite writes
[] = {
2733 CreateMockWrite(*stream1_syn
, 0), CreateMockWrite(*stream3_rst
, 4),
2736 scoped_ptr
<SpdyFrame
>
2737 stream1_reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2738 scoped_ptr
<SpdyFrame
> stream2_syn(spdy_util_
.ConstructSpdyPush(
2739 NULL
, 0, 2, 1, GetDefaultUrlWithPath("/foo.dat").c_str()));
2740 const char kPushedData
[] = "pushed";
2741 scoped_ptr
<SpdyFrame
> stream2_body(
2742 spdy_util_
.ConstructSpdyBodyFrame(
2743 2, kPushedData
, strlen(kPushedData
), true));
2744 scoped_ptr
<SpdyFrame
> stream3_syn(spdy_util_
.ConstructSpdyPush(
2745 NULL
, 0, 4, 1, GetDefaultUrlWithPath("/foo.dat").c_str()));
2746 MockRead reads
[] = {
2747 CreateMockRead(*stream1_reply
, 1),
2748 CreateMockRead(*stream2_syn
, 2),
2749 CreateMockRead(*stream3_syn
, 3),
2750 CreateMockRead(*stream1_body
, 5),
2751 CreateMockRead(*stream2_body
, 6),
2752 MockRead(SYNCHRONOUS
, ERR_IO_PENDING
, 7), // Force a pause
2755 HttpResponseInfo response
;
2756 HttpResponseInfo response2
;
2757 std::string
expected_push_result("pushed");
2758 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
2759 RunServerPushTest(&data
,
2762 expected_push_result
);
2764 // Verify the SYN_REPLY.
2765 EXPECT_TRUE(response
.headers
.get() != NULL
);
2766 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
2768 // Verify the pushed stream.
2769 EXPECT_TRUE(response2
.headers
.get() != NULL
);
2770 EXPECT_EQ("HTTP/1.1 200 OK", response2
.headers
->GetStatusLine());
2773 TEST_P(SpdyNetworkTransactionTest
, ServerPushMultipleDataFrame
) {
2774 scoped_ptr
<SpdyFrame
> stream1_syn(
2775 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2776 scoped_ptr
<SpdyFrame
> stream1_body(
2777 spdy_util_
.ConstructSpdyBodyFrame(1, true));
2778 MockWrite writes
[] = {
2779 CreateMockWrite(*stream1_syn
, 0),
2782 scoped_ptr
<SpdyFrame
>
2783 stream1_reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2784 scoped_ptr
<SpdyFrame
> stream2_syn(spdy_util_
.ConstructSpdyPush(
2785 NULL
, 0, 2, 1, GetDefaultUrlWithPath("/foo.dat").c_str()));
2786 static const char kPushedData
[] = "pushed my darling hello my baby";
2787 scoped_ptr
<SpdyFrame
> stream2_body_base(
2788 spdy_util_
.ConstructSpdyBodyFrame(
2789 2, kPushedData
, strlen(kPushedData
), true));
2790 const size_t kChunkSize
= strlen(kPushedData
) / 4;
2791 scoped_ptr
<SpdyFrame
> stream2_body1(
2792 new SpdyFrame(stream2_body_base
->data(), kChunkSize
, false));
2793 scoped_ptr
<SpdyFrame
> stream2_body2(
2794 new SpdyFrame(stream2_body_base
->data() + kChunkSize
, kChunkSize
, false));
2795 scoped_ptr
<SpdyFrame
> stream2_body3(
2796 new SpdyFrame(stream2_body_base
->data() + 2 * kChunkSize
,
2797 kChunkSize
, false));
2798 scoped_ptr
<SpdyFrame
> stream2_body4(
2799 new SpdyFrame(stream2_body_base
->data() + 3 * kChunkSize
,
2800 stream2_body_base
->size() - 3 * kChunkSize
, false));
2801 MockRead reads
[] = {
2802 CreateMockRead(*stream1_reply
, 1),
2803 CreateMockRead(*stream2_syn
, 2),
2804 CreateMockRead(*stream2_body1
, 3),
2805 CreateMockRead(*stream2_body2
, 4),
2806 CreateMockRead(*stream2_body3
, 5),
2807 CreateMockRead(*stream2_body4
, 6),
2808 CreateMockRead(*stream1_body
, 7, SYNCHRONOUS
),
2809 MockRead(SYNCHRONOUS
, ERR_IO_PENDING
, 8), // Force a pause
2812 HttpResponseInfo response
;
2813 HttpResponseInfo response2
;
2814 std::string
expected_push_result("pushed my darling hello my baby");
2815 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
2816 RunServerPushTest(&data
, &response
, &response2
, kPushedData
);
2818 // Verify the SYN_REPLY.
2819 EXPECT_TRUE(response
.headers
.get() != NULL
);
2820 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
2822 // Verify the pushed stream.
2823 EXPECT_TRUE(response2
.headers
.get() != NULL
);
2824 EXPECT_EQ("HTTP/1.1 200 OK", response2
.headers
->GetStatusLine());
2827 TEST_P(SpdyNetworkTransactionTest
, ServerPushMultipleDataFrameInterrupted
) {
2828 scoped_ptr
<SpdyFrame
> stream1_syn(
2829 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2830 scoped_ptr
<SpdyFrame
> stream1_body(
2831 spdy_util_
.ConstructSpdyBodyFrame(1, true));
2832 MockWrite writes
[] = {
2833 CreateMockWrite(*stream1_syn
, 0),
2836 scoped_ptr
<SpdyFrame
>
2837 stream1_reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2838 scoped_ptr
<SpdyFrame
> stream2_syn(spdy_util_
.ConstructSpdyPush(
2839 NULL
, 0, 2, 1, GetDefaultUrlWithPath("/foo.dat").c_str()));
2840 static const char kPushedData
[] = "pushed my darling hello my baby";
2841 scoped_ptr
<SpdyFrame
> stream2_body_base(
2842 spdy_util_
.ConstructSpdyBodyFrame(
2843 2, kPushedData
, strlen(kPushedData
), true));
2844 const size_t kChunkSize
= strlen(kPushedData
) / 4;
2845 scoped_ptr
<SpdyFrame
> stream2_body1(
2846 new SpdyFrame(stream2_body_base
->data(), kChunkSize
, false));
2847 scoped_ptr
<SpdyFrame
> stream2_body2(
2848 new SpdyFrame(stream2_body_base
->data() + kChunkSize
, kChunkSize
, false));
2849 scoped_ptr
<SpdyFrame
> stream2_body3(
2850 new SpdyFrame(stream2_body_base
->data() + 2 * kChunkSize
,
2851 kChunkSize
, false));
2852 scoped_ptr
<SpdyFrame
> stream2_body4(
2853 new SpdyFrame(stream2_body_base
->data() + 3 * kChunkSize
,
2854 stream2_body_base
->size() - 3 * kChunkSize
, false));
2855 MockRead reads
[] = {
2856 CreateMockRead(*stream1_reply
, 1),
2857 CreateMockRead(*stream2_syn
, 2),
2858 CreateMockRead(*stream2_body1
, 3),
2859 CreateMockRead(*stream2_body2
, 4),
2860 CreateMockRead(*stream2_body3
, 5),
2861 CreateMockRead(*stream2_body4
, 6),
2862 CreateMockRead(*stream1_body
.get(), 7, SYNCHRONOUS
),
2863 MockRead(SYNCHRONOUS
, ERR_IO_PENDING
, 8) // Force a pause.
2866 HttpResponseInfo response
;
2867 HttpResponseInfo response2
;
2868 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
2869 RunServerPushTest(&data
, &response
, &response2
, kPushedData
);
2871 // Verify the SYN_REPLY.
2872 EXPECT_TRUE(response
.headers
.get() != NULL
);
2873 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
2875 // Verify the pushed stream.
2876 EXPECT_TRUE(response2
.headers
.get() != NULL
);
2877 EXPECT_EQ("HTTP/1.1 200 OK", response2
.headers
->GetStatusLine());
2880 TEST_P(SpdyNetworkTransactionTest
, ServerPushInvalidAssociatedStreamID0
) {
2881 if (spdy_util_
.spdy_version() == HTTP2
) {
2882 // PUSH_PROMISE with stream id 0 is connection-level error.
2883 // TODO(baranovich): Test session going away.
2887 scoped_ptr
<SpdyFrame
> stream1_syn(
2888 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2889 scoped_ptr
<SpdyFrame
> stream1_body(
2890 spdy_util_
.ConstructSpdyBodyFrame(1, true));
2891 scoped_ptr
<SpdyFrame
> stream2_rst(
2892 spdy_util_
.ConstructSpdyRstStream(2, RST_STREAM_REFUSED_STREAM
));
2893 MockWrite writes
[] = {
2894 CreateMockWrite(*stream1_syn
, 0), CreateMockWrite(*stream2_rst
, 3),
2897 scoped_ptr
<SpdyFrame
>
2898 stream1_reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2899 scoped_ptr
<SpdyFrame
> stream2_syn(spdy_util_
.ConstructSpdyPush(
2900 NULL
, 0, 2, 0, GetDefaultUrlWithPath("/foo.dat").c_str()));
2901 MockRead reads
[] = {
2902 CreateMockRead(*stream1_reply
, 1),
2903 CreateMockRead(*stream2_syn
, 2),
2904 CreateMockRead(*stream1_body
, 4),
2905 MockRead(SYNCHRONOUS
, ERR_IO_PENDING
, 5) // Force a pause
2908 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
2909 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
2910 BoundNetLog(), GetParam(), NULL
);
2912 helper
.RunPreTestSetup();
2913 helper
.AddData(&data
);
2915 HttpNetworkTransaction
* trans
= helper
.trans();
2917 // Start the transaction with basic parameters.
2918 TestCompletionCallback callback
;
2919 int rv
= trans
->Start(
2920 &CreateGetRequest(), callback
.callback(), BoundNetLog());
2921 EXPECT_EQ(ERR_IO_PENDING
, rv
);
2922 rv
= callback
.WaitForResult();
2925 // Verify that we consumed all test data.
2926 EXPECT_TRUE(data
.AllReadDataConsumed());
2927 EXPECT_TRUE(data
.AllWriteDataConsumed());
2929 // Verify the SYN_REPLY.
2930 HttpResponseInfo response
= *trans
->GetResponseInfo();
2931 EXPECT_TRUE(response
.headers
.get() != NULL
);
2932 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
2935 TEST_P(SpdyNetworkTransactionTest
, ServerPushInvalidAssociatedStreamID9
) {
2936 scoped_ptr
<SpdyFrame
> stream1_syn(
2937 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2938 scoped_ptr
<SpdyFrame
> stream1_body(
2939 spdy_util_
.ConstructSpdyBodyFrame(1, true));
2940 scoped_ptr
<SpdyFrame
> stream2_rst(
2941 spdy_util_
.ConstructSpdyRstStream(2, RST_STREAM_INVALID_STREAM
));
2942 MockWrite writes
[] = {
2943 CreateMockWrite(*stream1_syn
, 0), CreateMockWrite(*stream2_rst
, 3),
2946 scoped_ptr
<SpdyFrame
>
2947 stream1_reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2948 scoped_ptr
<SpdyFrame
> stream2_syn(spdy_util_
.ConstructSpdyPush(
2949 NULL
, 0, 2, 9, GetDefaultUrlWithPath("/foo.dat").c_str()));
2950 MockRead reads
[] = {
2951 CreateMockRead(*stream1_reply
, 1),
2952 CreateMockRead(*stream2_syn
, 2),
2953 CreateMockRead(*stream1_body
, 4),
2954 MockRead(SYNCHRONOUS
, ERR_IO_PENDING
, 5), // Force a pause
2957 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
2958 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
2959 BoundNetLog(), GetParam(), NULL
);
2961 helper
.RunPreTestSetup();
2962 helper
.AddData(&data
);
2964 HttpNetworkTransaction
* trans
= helper
.trans();
2966 // Start the transaction with basic parameters.
2967 TestCompletionCallback callback
;
2968 int rv
= trans
->Start(
2969 &CreateGetRequest(), callback
.callback(), BoundNetLog());
2970 EXPECT_EQ(ERR_IO_PENDING
, rv
);
2971 rv
= callback
.WaitForResult();
2974 // Verify that we consumed all test data.
2975 EXPECT_TRUE(data
.AllReadDataConsumed());
2976 EXPECT_TRUE(data
.AllWriteDataConsumed());
2978 // Verify the SYN_REPLY.
2979 HttpResponseInfo response
= *trans
->GetResponseInfo();
2980 EXPECT_TRUE(response
.headers
.get() != NULL
);
2981 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
2984 TEST_P(SpdyNetworkTransactionTest
, ServerPushNoURL
) {
2985 scoped_ptr
<SpdyFrame
> stream1_syn(
2986 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2987 scoped_ptr
<SpdyFrame
> stream1_body(
2988 spdy_util_
.ConstructSpdyBodyFrame(1, true));
2989 scoped_ptr
<SpdyFrame
> stream2_rst(
2990 spdy_util_
.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR
));
2991 MockWrite writes
[] = {
2992 CreateMockWrite(*stream1_syn
, 0), CreateMockWrite(*stream2_rst
, 3),
2995 scoped_ptr
<SpdyFrame
>
2996 stream1_reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2997 scoped_ptr
<SpdyHeaderBlock
> incomplete_headers(new SpdyHeaderBlock());
2998 (*incomplete_headers
)["hello"] = "bye";
2999 (*incomplete_headers
)[spdy_util_
.GetStatusKey()] = "200 OK";
3000 (*incomplete_headers
)[spdy_util_
.GetVersionKey()] = "HTTP/1.1";
3001 scoped_ptr
<SpdyFrame
> stream2_syn(spdy_util_
.ConstructInitialSpdyPushFrame(
3002 incomplete_headers
.Pass(), 2, 1));
3003 MockRead reads
[] = {
3004 CreateMockRead(*stream1_reply
, 1),
3005 CreateMockRead(*stream2_syn
, 2),
3006 CreateMockRead(*stream1_body
, 4),
3007 MockRead(SYNCHRONOUS
, ERR_IO_PENDING
, 5) // Force a pause
3010 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
3011 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
3012 BoundNetLog(), GetParam(), NULL
);
3014 helper
.RunPreTestSetup();
3015 helper
.AddData(&data
);
3017 HttpNetworkTransaction
* trans
= helper
.trans();
3019 // Start the transaction with basic parameters.
3020 TestCompletionCallback callback
;
3021 int rv
= trans
->Start(
3022 &CreateGetRequest(), callback
.callback(), BoundNetLog());
3023 EXPECT_EQ(ERR_IO_PENDING
, rv
);
3024 rv
= callback
.WaitForResult();
3027 // Verify that we consumed all test data.
3028 EXPECT_TRUE(data
.AllReadDataConsumed());
3029 EXPECT_TRUE(data
.AllWriteDataConsumed());
3031 // Verify the SYN_REPLY.
3032 HttpResponseInfo response
= *trans
->GetResponseInfo();
3033 EXPECT_TRUE(response
.headers
.get() != NULL
);
3034 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
3037 // Verify that various SynReply headers parse correctly through the
3039 TEST_P(SpdyNetworkTransactionTest
, SynReplyHeaders
) {
3040 struct SynReplyHeadersTests
{
3042 const char* extra_headers
[5];
3043 SpdyHeaderBlock expected_headers
;
3045 // This uses a multi-valued cookie header.
3048 "cookie", "val2", // will get appended separated by NULL
3052 // This is the minimalist set of headers.
3056 // Headers with a comma separated list.
3058 { "cookie", "val1,val2",
3064 test_cases
[0].expected_headers
["cookie"] = "val1";
3065 test_cases
[0].expected_headers
["cookie"] += '\0';
3066 test_cases
[0].expected_headers
["cookie"] += "val2";
3067 test_cases
[0].expected_headers
["hello"] = "bye";
3068 test_cases
[0].expected_headers
["status"] = "200";
3070 test_cases
[1].expected_headers
["hello"] = "bye";
3071 test_cases
[1].expected_headers
["status"] = "200";
3073 test_cases
[2].expected_headers
["cookie"] = "val1,val2";
3074 test_cases
[2].expected_headers
["hello"] = "bye";
3075 test_cases
[2].expected_headers
["status"] = "200";
3077 if (spdy_util_
.spdy_version() < HTTP2
) {
3078 // HTTP/2 eliminates use of the :version header.
3079 test_cases
[0].expected_headers
["version"] = "HTTP/1.1";
3080 test_cases
[1].expected_headers
["version"] = "HTTP/1.1";
3081 test_cases
[2].expected_headers
["version"] = "HTTP/1.1";
3084 for (size_t i
= 0; i
< arraysize(test_cases
); ++i
) {
3085 scoped_ptr
<SpdyFrame
> req(
3086 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
3087 MockWrite writes
[] = {CreateMockWrite(*req
, 0)};
3089 scoped_ptr
<SpdyFrame
> resp(
3090 spdy_util_
.ConstructSpdyGetSynReply(test_cases
[i
].extra_headers
,
3091 test_cases
[i
].num_headers
,
3093 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
3094 MockRead reads
[] = {
3095 CreateMockRead(*resp
, 1),
3096 CreateMockRead(*body
, 2),
3097 MockRead(ASYNC
, 0, 3) // EOF
3100 SequencedSocketData
data(reads
, arraysize(reads
), writes
,
3102 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
3103 BoundNetLog(), GetParam(), NULL
);
3104 helper
.RunToCompletion(&data
);
3105 TransactionHelperResult out
= helper
.output();
3107 EXPECT_EQ(OK
, out
.rv
);
3108 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
3109 EXPECT_EQ("hello!", out
.response_data
);
3111 scoped_refptr
<HttpResponseHeaders
> headers
= out
.response_info
.headers
;
3112 EXPECT_TRUE(headers
.get() != NULL
);
3114 std::string name
, value
;
3115 SpdyHeaderBlock header_block
;
3116 while (headers
->EnumerateHeaderLines(&iter
, &name
, &value
)) {
3117 if (header_block
[name
].empty()) {
3118 header_block
[name
] = value
;
3120 header_block
[name
] += '\0';
3121 header_block
[name
] += value
;
3124 EXPECT_EQ(test_cases
[i
].expected_headers
, header_block
);
3128 // Verify that various SynReply headers parse vary fields correctly
3129 // through the HTTP layer, and the response matches the request.
3130 TEST_P(SpdyNetworkTransactionTest
, SynReplyHeadersVary
) {
3131 // Modify the following data to change/add test cases:
3132 struct SynReplyTests
{
3135 const char* extra_headers
[2][16];
3137 // Test the case of a multi-valued cookie. When the value is delimited
3138 // with NUL characters, it needs to be unfolded into multiple headers.
3142 { { "cookie", "val1,val2",
3146 spdy_util_
.GetStatusKey(), "200",
3147 spdy_util_
.GetPathKey(), "/index.php",
3148 spdy_util_
.GetVersionKey(), "HTTP/1.1",
3152 }, { // Multiple vary fields.
3155 { { "friend", "barney",
3156 "enemy", "snaggletooth",
3161 spdy_util_
.GetStatusKey(), "200",
3162 spdy_util_
.GetPathKey(), "/index.php",
3163 spdy_util_
.GetVersionKey(), "HTTP/1.1",
3167 }, { // Test a '*' vary field.
3170 { { "cookie", "val1,val2",
3174 spdy_util_
.GetStatusKey(), "200",
3175 spdy_util_
.GetPathKey(), "/index.php",
3176 spdy_util_
.GetVersionKey(), "HTTP/1.1",
3180 }, { // Multiple comma-separated vary fields.
3183 { { "friend", "barney",
3184 "enemy", "snaggletooth",
3187 { "vary", "friend,enemy",
3188 spdy_util_
.GetStatusKey(), "200",
3189 spdy_util_
.GetPathKey(), "/index.php",
3190 spdy_util_
.GetVersionKey(), "HTTP/1.1",
3197 for (size_t i
= 0; i
< arraysize(test_cases
); ++i
) {
3198 // Construct the request.
3199 scoped_ptr
<SpdyFrame
> frame_req(
3200 spdy_util_
.ConstructSpdyGet(test_cases
[i
].extra_headers
[0],
3201 test_cases
[i
].num_headers
[0],
3202 false, 1, LOWEST
, true));
3204 MockWrite writes
[] = {
3205 CreateMockWrite(*frame_req
, 0),
3208 // Construct the reply.
3209 SpdyHeaderBlock reply_headers
;
3210 AppendToHeaderBlock(test_cases
[i
].extra_headers
[1],
3211 test_cases
[i
].num_headers
[1],
3213 scoped_ptr
<SpdyFrame
> frame_reply(
3214 spdy_util_
.ConstructSpdyReply(1, reply_headers
));
3216 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
3217 MockRead reads
[] = {
3218 CreateMockRead(*frame_reply
, 1),
3219 CreateMockRead(*body
, 2),
3220 MockRead(ASYNC
, 0, 3) // EOF
3223 // Attach the headers to the request.
3224 int header_count
= test_cases
[i
].num_headers
[0];
3226 HttpRequestInfo request
= CreateGetRequest();
3227 for (int ct
= 0; ct
< header_count
; ct
++) {
3228 const char* header_key
= test_cases
[i
].extra_headers
[0][ct
* 2];
3229 const char* header_value
= test_cases
[i
].extra_headers
[0][ct
* 2 + 1];
3230 request
.extra_headers
.SetHeader(header_key
, header_value
);
3233 SequencedSocketData
data(reads
, arraysize(reads
), writes
,
3235 NormalSpdyTransactionHelper
helper(request
, DEFAULT_PRIORITY
,
3236 BoundNetLog(), GetParam(), NULL
);
3237 helper
.RunToCompletion(&data
);
3238 TransactionHelperResult out
= helper
.output();
3240 EXPECT_EQ(OK
, out
.rv
) << i
;
3241 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
) << i
;
3242 EXPECT_EQ("hello!", out
.response_data
) << i
;
3244 // Test the response information.
3245 EXPECT_EQ(out
.response_info
.vary_data
.is_valid(),
3246 test_cases
[i
].vary_matches
) << i
;
3248 // Check the headers.
3249 scoped_refptr
<HttpResponseHeaders
> headers
= out
.response_info
.headers
;
3250 ASSERT_TRUE(headers
.get() != NULL
) << i
;
3252 std::string name
, value
, lines
;
3253 while (headers
->EnumerateHeaderLines(&iter
, &name
, &value
)) {
3256 lines
.append(value
);
3260 // Construct the expected header reply string.
3261 std::string expected_reply
=
3262 spdy_util_
.ConstructSpdyReplyString(reply_headers
);
3263 EXPECT_EQ(expected_reply
, lines
) << i
;
3267 // Verify that we don't crash on invalid SynReply responses.
3268 TEST_P(SpdyNetworkTransactionTest
, InvalidSynReply
) {
3269 struct InvalidSynReplyTests
{
3271 const char* headers
[10];
3273 // SYN_REPLY missing status header
3277 spdy_util_
.GetPathKey(), "/index.php",
3278 spdy_util_
.GetVersionKey(), "HTTP/1.1",
3282 // SYN_REPLY missing version header
3285 spdy_util_
.GetPathKey(), "/index.php",
3289 // SYN_REPLY with no headers
3293 for (size_t i
= 0; i
< arraysize(test_cases
); ++i
) {
3294 scoped_ptr
<SpdyFrame
> req(
3295 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
3296 scoped_ptr
<SpdyFrame
> rst(
3297 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR
));
3298 MockWrite writes
[] = {
3299 CreateMockWrite(*req
, 0), CreateMockWrite(*rst
, 2),
3302 // Construct the reply.
3303 SpdyHeaderBlock reply_headers
;
3304 AppendToHeaderBlock(
3305 test_cases
[i
].headers
, test_cases
[i
].num_headers
, &reply_headers
);
3306 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyReply(1, reply_headers
));
3307 MockRead reads
[] = {
3308 CreateMockRead(*resp
, 1), MockRead(ASYNC
, 0, 3) // EOF
3311 SequencedSocketData
data(reads
, arraysize(reads
), writes
,
3313 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
3314 BoundNetLog(), GetParam(), NULL
);
3315 helper
.RunToCompletion(&data
);
3316 TransactionHelperResult out
= helper
.output();
3317 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR
, out
.rv
);
3321 // Verify that we don't crash on some corrupt frames.
3322 // TODO(jgraettinger): HTTP/2 treats a header decompression failure as a
3323 // connection error. I'd like to backport this behavior to SPDY3 as well.
3324 TEST_P(SpdyNetworkTransactionTest
, CorruptFrameSessionError
) {
3325 if (spdy_util_
.spdy_version() >= HTTP2
) {
3328 // This is the length field that's too short.
3329 scoped_ptr
<SpdyFrame
> syn_reply_wrong_length(
3330 spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
3331 BufferedSpdyFramer
framer(spdy_util_
.spdy_version(), false);
3333 (spdy_util_
.spdy_version() < HTTP2
)
3334 ? syn_reply_wrong_length
->size() - framer
.GetControlFrameHeaderSize()
3335 : syn_reply_wrong_length
->size();
3336 size_t wrong_size
= right_size
- 4;
3337 test::SetFrameLength(syn_reply_wrong_length
.get(),
3339 spdy_util_
.spdy_version());
3341 struct SynReplyTests
{
3342 const SpdyFrame
* syn_reply
;
3344 { syn_reply_wrong_length
.get(), },
3347 for (size_t i
= 0; i
< arraysize(test_cases
); ++i
) {
3348 scoped_ptr
<SpdyFrame
> req(
3349 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
3350 scoped_ptr
<SpdyFrame
> rst(
3351 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR
));
3352 MockWrite writes
[] = {
3353 CreateMockWrite(*req
, 0), CreateMockWrite(*rst
, 3),
3356 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
3357 MockRead reads
[] = {
3358 MockRead(ASYNC
, test_cases
[i
].syn_reply
->data(), wrong_size
, 1),
3359 CreateMockRead(*body
, 2),
3360 MockRead(ASYNC
, 0, 4) // EOF
3363 SequencedSocketData
data(reads
, arraysize(reads
), writes
,
3365 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
3366 BoundNetLog(), GetParam(), NULL
);
3367 helper
.RunToCompletion(&data
);
3368 TransactionHelperResult out
= helper
.output();
3369 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR
, out
.rv
);
3373 // HTTP/2 treats a header decompression failure as a connection-level error.
3374 TEST_P(SpdyNetworkTransactionTest
, CorruptFrameSessionErrorSpdy4
) {
3375 if (spdy_util_
.spdy_version() < HTTP2
) {
3378 // This is the length field that's too short.
3379 scoped_ptr
<SpdyFrame
> syn_reply_wrong_length(
3380 spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
3381 BufferedSpdyFramer
framer(spdy_util_
.spdy_version(), false);
3383 syn_reply_wrong_length
->size() - framer
.GetControlFrameHeaderSize();
3384 size_t wrong_size
= right_size
- 4;
3385 test::SetFrameLength(syn_reply_wrong_length
.get(),
3387 spdy_util_
.spdy_version());
3389 scoped_ptr
<SpdyFrame
> req(
3390 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
3391 scoped_ptr
<SpdyFrame
> goaway(spdy_util_
.ConstructSpdyGoAway(
3392 0, GOAWAY_COMPRESSION_ERROR
, "Framer error: 5 (DECOMPRESS_FAILURE)."));
3393 MockWrite writes
[] = {CreateMockWrite(*req
, 0), CreateMockWrite(*goaway
, 2)};
3395 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
3396 MockRead reads
[] = {
3397 MockRead(ASYNC
, syn_reply_wrong_length
->data(),
3398 syn_reply_wrong_length
->size() - 4, 1),
3401 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
3402 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
3403 BoundNetLog(), GetParam(), NULL
);
3404 helper
.RunToCompletion(&data
);
3405 TransactionHelperResult out
= helper
.output();
3406 EXPECT_EQ(ERR_SPDY_COMPRESSION_ERROR
, out
.rv
);
3409 TEST_P(SpdyNetworkTransactionTest
, GoAwayOnDecompressionFailure
) {
3410 if (GetParam().protocol
< kProtoHTTP2MinimumVersion
) {
3411 // Decompression failures are a stream error in SPDY3 and above.
3414 scoped_ptr
<SpdyFrame
> req(
3415 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
3416 scoped_ptr
<SpdyFrame
> goaway(spdy_util_
.ConstructSpdyGoAway(
3417 0, GOAWAY_COMPRESSION_ERROR
, "Framer error: 5 (DECOMPRESS_FAILURE)."));
3418 MockWrite writes
[] = {CreateMockWrite(*req
, 0), CreateMockWrite(*goaway
, 2)};
3420 // Read HEADERS with corrupted payload.
3421 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
3422 memset(resp
->data() + 12, 0xff, resp
->size() - 12);
3423 MockRead reads
[] = {CreateMockRead(*resp
, 1)};
3425 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
3426 NormalSpdyTransactionHelper
helper(
3427 CreateGetRequest(), DEFAULT_PRIORITY
, BoundNetLog(), GetParam(), NULL
);
3428 helper
.RunToCompletion(&data
);
3429 TransactionHelperResult out
= helper
.output();
3430 EXPECT_EQ(ERR_SPDY_COMPRESSION_ERROR
, out
.rv
);
3433 TEST_P(SpdyNetworkTransactionTest
, GoAwayOnFrameSizeError
) {
3434 scoped_ptr
<SpdyFrame
> req(
3435 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
3436 scoped_ptr
<SpdyFrame
> goaway(spdy_util_
.ConstructSpdyGoAway(
3437 0, GOAWAY_PROTOCOL_ERROR
, "Framer error: 1 (INVALID_CONTROL_FRAME)."));
3438 MockWrite writes
[] = {CreateMockWrite(*req
, 0), CreateMockWrite(*goaway
, 2)};
3440 // Read WINDOW_UPDATE with incorrectly-sized payload.
3441 // TODO(jgraettinger): SpdyFramer signals this as an INVALID_CONTROL_FRAME,
3442 // which is mapped to a protocol error, and not a frame size error.
3443 scoped_ptr
<SpdyFrame
> bad_window_update(
3444 spdy_util_
.ConstructSpdyWindowUpdate(1, 1));
3445 test::SetFrameLength(bad_window_update
.get(),
3446 bad_window_update
->size() - 1,
3447 spdy_util_
.spdy_version());
3448 MockRead reads
[] = {CreateMockRead(*bad_window_update
, 1)};
3450 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
3451 NormalSpdyTransactionHelper
helper(
3452 CreateGetRequest(), DEFAULT_PRIORITY
, BoundNetLog(), GetParam(), NULL
);
3453 helper
.RunToCompletion(&data
);
3454 TransactionHelperResult out
= helper
.output();
3455 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR
, out
.rv
);
3458 // Test that we shutdown correctly on write errors.
3459 TEST_P(SpdyNetworkTransactionTest
, WriteError
) {
3460 scoped_ptr
<SpdyFrame
> req(
3461 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
3462 MockWrite writes
[] = {
3463 // We'll write 10 bytes successfully
3464 MockWrite(ASYNC
, req
->data(), 10, 0),
3465 // Followed by ERROR!
3466 MockWrite(ASYNC
, ERR_FAILED
, 1),
3467 // Session drains and attempts to write a GOAWAY: Another ERROR!
3468 MockWrite(ASYNC
, ERR_FAILED
, 2),
3471 MockRead reads
[] = {
3472 MockRead(ASYNC
, 0, 3) // EOF
3475 DeterministicSocketData
data(reads
, arraysize(reads
),
3476 writes
, arraysize(writes
));
3478 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
3479 BoundNetLog(), GetParam(), NULL
);
3480 helper
.SetDeterministic();
3481 helper
.RunPreTestSetup();
3482 helper
.AddDeterministicData(&data
);
3483 EXPECT_TRUE(helper
.StartDefaultTest());
3485 helper
.FinishDefaultTest();
3486 EXPECT_TRUE(data
.AllWriteDataConsumed());
3487 EXPECT_TRUE(!data
.AllReadDataConsumed());
3488 TransactionHelperResult out
= helper
.output();
3489 EXPECT_EQ(ERR_FAILED
, out
.rv
);
3492 // Test that partial writes work.
3493 TEST_P(SpdyNetworkTransactionTest
, PartialWrite
) {
3494 // Chop the SYN_STREAM frame into 5 chunks.
3495 scoped_ptr
<SpdyFrame
> req(
3496 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
3497 const int kChunks
= 5;
3498 scoped_ptr
<MockWrite
[]> writes(ChopWriteFrame(*req
.get(), kChunks
));
3499 for (int i
= 0; i
< kChunks
; ++i
) {
3500 writes
[i
].sequence_number
= i
;
3503 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
3504 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
3505 MockRead reads
[] = {
3506 CreateMockRead(*resp
, kChunks
),
3507 CreateMockRead(*body
, kChunks
+ 1),
3508 MockRead(ASYNC
, 0, kChunks
+ 2) // EOF
3511 SequencedSocketData
data(reads
, arraysize(reads
), writes
.get(), kChunks
);
3512 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
3513 BoundNetLog(), GetParam(), NULL
);
3514 helper
.RunToCompletion(&data
);
3515 TransactionHelperResult out
= helper
.output();
3516 EXPECT_EQ(OK
, out
.rv
);
3517 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
3518 EXPECT_EQ("hello!", out
.response_data
);
3521 // In this test, we enable compression, but get a uncompressed SynReply from
3522 // the server. Verify that teardown is all clean.
3523 TEST_P(SpdyNetworkTransactionTest
, DecompressFailureOnSynReply
) {
3524 if (spdy_util_
.spdy_version() >= HTTP2
) {
3525 // HPACK doesn't use deflate compression.
3528 scoped_ptr
<SpdyFrame
> compressed(
3529 spdy_util_
.ConstructSpdyGet(NULL
, 0, true, 1, LOWEST
, true));
3530 scoped_ptr
<SpdyFrame
> goaway(spdy_util_
.ConstructSpdyGoAway(
3531 0, GOAWAY_COMPRESSION_ERROR
, "Framer error: 5 (DECOMPRESS_FAILURE)."));
3532 MockWrite writes
[] = {CreateMockWrite(*compressed
, 0),
3533 CreateMockWrite(*goaway
, 2)};
3535 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
3536 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
3537 MockRead reads
[] = {
3538 CreateMockRead(*resp
, 1),
3541 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
3542 SpdySessionDependencies
* session_deps
=
3543 CreateSpdySessionDependencies(GetParam());
3544 session_deps
->enable_compression
= true;
3545 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
3546 BoundNetLog(), GetParam(), session_deps
);
3547 helper
.RunToCompletion(&data
);
3548 TransactionHelperResult out
= helper
.output();
3549 EXPECT_EQ(ERR_SPDY_COMPRESSION_ERROR
, out
.rv
);
3553 // Test that the NetLog contains good data for a simple GET request.
3554 TEST_P(SpdyNetworkTransactionTest
, NetLog
) {
3555 static const char* const kExtraHeaders
[] = {
3556 "user-agent", "Chrome",
3558 scoped_ptr
<SpdyFrame
> req(
3559 spdy_util_
.ConstructSpdyGet(kExtraHeaders
, 1, false, 1, LOWEST
, true));
3560 MockWrite writes
[] = {CreateMockWrite(*req
, 0)};
3562 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
3563 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
3564 MockRead reads
[] = {
3565 CreateMockRead(*resp
, 1),
3566 CreateMockRead(*body
, 2),
3567 MockRead(ASYNC
, 0, 3) // EOF
3570 BoundTestNetLog log
;
3572 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
3573 NormalSpdyTransactionHelper
helper(CreateGetRequestWithUserAgent(),
3575 log
.bound(), GetParam(), NULL
);
3576 helper
.RunToCompletion(&data
);
3577 TransactionHelperResult out
= helper
.output();
3578 EXPECT_EQ(OK
, out
.rv
);
3579 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
3580 EXPECT_EQ("hello!", out
.response_data
);
3582 // Check that the NetLog was filled reasonably.
3583 // This test is intentionally non-specific about the exact ordering of the
3584 // log; instead we just check to make sure that certain events exist, and that
3585 // they are in the right order.
3586 TestNetLogEntry::List entries
;
3587 log
.GetEntries(&entries
);
3589 EXPECT_LT(0u, entries
.size());
3591 pos
= ExpectLogContainsSomewhere(entries
, 0,
3592 NetLog::TYPE_HTTP_TRANSACTION_SEND_REQUEST
,
3593 NetLog::PHASE_BEGIN
);
3594 pos
= ExpectLogContainsSomewhere(entries
, pos
+ 1,
3595 NetLog::TYPE_HTTP_TRANSACTION_SEND_REQUEST
,
3597 pos
= ExpectLogContainsSomewhere(entries
, pos
+ 1,
3598 NetLog::TYPE_HTTP_TRANSACTION_READ_HEADERS
,
3599 NetLog::PHASE_BEGIN
);
3600 pos
= ExpectLogContainsSomewhere(entries
, pos
+ 1,
3601 NetLog::TYPE_HTTP_TRANSACTION_READ_HEADERS
,
3603 pos
= ExpectLogContainsSomewhere(entries
, pos
+ 1,
3604 NetLog::TYPE_HTTP_TRANSACTION_READ_BODY
,
3605 NetLog::PHASE_BEGIN
);
3606 pos
= ExpectLogContainsSomewhere(entries
, pos
+ 1,
3607 NetLog::TYPE_HTTP_TRANSACTION_READ_BODY
,
3610 // Check that we logged all the headers correctly
3611 const NetLog::EventType type
= (GetParam().protocol
<= kProtoSPDY31
)
3612 ? NetLog::TYPE_HTTP2_SESSION_SYN_STREAM
3613 : NetLog::TYPE_HTTP2_SESSION_SEND_HEADERS
;
3614 pos
= ExpectLogContainsSomewhere(entries
, 0, type
, NetLog::PHASE_NONE
);
3616 base::ListValue
* header_list
;
3617 ASSERT_TRUE(entries
[pos
].params
.get());
3618 ASSERT_TRUE(entries
[pos
].params
->GetList("headers", &header_list
));
3620 std::vector
<std::string
> expected
;
3621 expected
.push_back(std::string(spdy_util_
.GetHostKey()) +
3622 ": www.example.org");
3623 expected
.push_back(std::string(spdy_util_
.GetPathKey()) + ": /");
3624 expected
.push_back(std::string(spdy_util_
.GetSchemeKey()) + ": " +
3625 spdy_util_
.default_url().scheme());
3626 expected
.push_back(std::string(spdy_util_
.GetMethodKey()) + ": GET");
3627 expected
.push_back("user-agent: Chrome");
3628 if (spdy_util_
.spdy_version() < HTTP2
) {
3629 // HTTP/2 eliminates use of the :version header.
3630 expected
.push_back(std::string(spdy_util_
.GetVersionKey()) + ": HTTP/1.1");
3632 EXPECT_EQ(expected
.size(), header_list
->GetSize());
3633 for (std::vector
<std::string
>::const_iterator it
= expected
.begin();
3634 it
!= expected
.end();
3636 base::StringValue
header(*it
);
3637 EXPECT_NE(header_list
->end(), header_list
->Find(header
)) <<
3638 "Header not found: " << *it
;
3642 // Since we buffer the IO from the stream to the renderer, this test verifies
3643 // that when we read out the maximum amount of data (e.g. we received 50 bytes
3644 // on the network, but issued a Read for only 5 of those bytes) that the data
3645 // flow still works correctly.
3646 TEST_P(SpdyNetworkTransactionTest
, BufferFull
) {
3647 BufferedSpdyFramer
framer(spdy_util_
.spdy_version(), false);
3649 scoped_ptr
<SpdyFrame
> req(
3650 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
3651 MockWrite writes
[] = {CreateMockWrite(*req
, 0)};
3653 // 2 data frames in a single read.
3654 scoped_ptr
<SpdyFrame
> data_frame_1(
3655 framer
.CreateDataFrame(1, "goodby", 6, DATA_FLAG_NONE
));
3656 scoped_ptr
<SpdyFrame
> data_frame_2(
3657 framer
.CreateDataFrame(1, "e worl", 6, DATA_FLAG_NONE
));
3658 const SpdyFrame
* data_frames
[2] = {
3662 char combined_data_frames
[100];
3663 int combined_data_frames_len
=
3664 CombineFrames(data_frames
, arraysize(data_frames
),
3665 combined_data_frames
, arraysize(combined_data_frames
));
3666 scoped_ptr
<SpdyFrame
> last_frame(
3667 framer
.CreateDataFrame(1, "d", 1, DATA_FLAG_FIN
));
3669 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
3670 MockRead reads
[] = {
3671 CreateMockRead(*resp
, 1),
3672 MockRead(ASYNC
, ERR_IO_PENDING
, 2), // Force a pause
3673 MockRead(ASYNC
, combined_data_frames
, combined_data_frames_len
, 3),
3674 MockRead(ASYNC
, ERR_IO_PENDING
, 4), // Force a pause
3675 CreateMockRead(*last_frame
, 5),
3676 MockRead(ASYNC
, 0, 6) // EOF
3679 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
3681 TestCompletionCallback callback
;
3683 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
3684 BoundNetLog(), GetParam(), NULL
);
3685 helper
.RunPreTestSetup();
3686 helper
.AddData(&data
);
3687 HttpNetworkTransaction
* trans
= helper
.trans();
3688 int rv
= trans
->Start(
3689 &CreateGetRequest(), callback
.callback(), BoundNetLog());
3690 EXPECT_EQ(ERR_IO_PENDING
, rv
);
3692 TransactionHelperResult out
= helper
.output();
3693 out
.rv
= callback
.WaitForResult();
3694 EXPECT_EQ(out
.rv
, OK
);
3696 const HttpResponseInfo
* response
= trans
->GetResponseInfo();
3697 EXPECT_TRUE(response
->headers
.get() != NULL
);
3698 EXPECT_TRUE(response
->was_fetched_via_spdy
);
3699 out
.status_line
= response
->headers
->GetStatusLine();
3700 out
.response_info
= *response
; // Make a copy so we can verify.
3703 TestCompletionCallback read_callback
;
3705 std::string content
;
3707 // Read small chunks at a time.
3708 const int kSmallReadSize
= 3;
3709 scoped_refptr
<IOBuffer
> buf(new IOBuffer(kSmallReadSize
));
3710 rv
= trans
->Read(buf
.get(), kSmallReadSize
, read_callback
.callback());
3711 if (rv
== ERR_IO_PENDING
) {
3712 data
.CompleteRead();
3713 rv
= read_callback
.WaitForResult();
3716 content
.append(buf
->data(), rv
);
3717 } else if (rv
< 0) {
3722 out
.response_data
.swap(content
);
3724 // Flush the MessageLoop while the SpdySessionDependencies (in particular, the
3725 // MockClientSocketFactory) are still alive.
3726 base::RunLoop().RunUntilIdle();
3728 // Verify that we consumed all test data.
3729 helper
.VerifyDataConsumed();
3731 EXPECT_EQ(OK
, out
.rv
);
3732 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
3733 EXPECT_EQ("goodbye world", out
.response_data
);
3736 // Verify that basic buffering works; when multiple data frames arrive
3737 // at the same time, ensure that we don't notify a read completion for
3738 // each data frame individually.
3739 TEST_P(SpdyNetworkTransactionTest
, Buffering
) {
3740 BufferedSpdyFramer
framer(spdy_util_
.spdy_version(), false);
3742 scoped_ptr
<SpdyFrame
> req(
3743 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
3744 MockWrite writes
[] = {CreateMockWrite(*req
, 0)};
3746 // 4 data frames in a single read.
3747 scoped_ptr
<SpdyFrame
> data_frame(
3748 framer
.CreateDataFrame(1, "message", 7, DATA_FLAG_NONE
));
3749 scoped_ptr
<SpdyFrame
> data_frame_fin(
3750 framer
.CreateDataFrame(1, "message", 7, DATA_FLAG_FIN
));
3751 const SpdyFrame
* data_frames
[4] = {
3755 data_frame_fin
.get()
3757 char combined_data_frames
[100];
3758 int combined_data_frames_len
=
3759 CombineFrames(data_frames
, arraysize(data_frames
),
3760 combined_data_frames
, arraysize(combined_data_frames
));
3762 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
3763 MockRead reads
[] = {
3764 CreateMockRead(*resp
, 1),
3765 MockRead(ASYNC
, ERR_IO_PENDING
, 2), // Force a pause
3766 MockRead(ASYNC
, combined_data_frames
, combined_data_frames_len
, 3),
3767 MockRead(ASYNC
, 0, 4) // EOF
3770 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
3772 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
3773 BoundNetLog(), GetParam(), NULL
);
3774 helper
.RunPreTestSetup();
3775 helper
.AddData(&data
);
3776 HttpNetworkTransaction
* trans
= helper
.trans();
3778 TestCompletionCallback callback
;
3779 int rv
= trans
->Start(
3780 &CreateGetRequest(), callback
.callback(), BoundNetLog());
3781 EXPECT_EQ(ERR_IO_PENDING
, rv
);
3783 TransactionHelperResult out
= helper
.output();
3784 out
.rv
= callback
.WaitForResult();
3785 EXPECT_EQ(out
.rv
, OK
);
3787 const HttpResponseInfo
* response
= trans
->GetResponseInfo();
3788 EXPECT_TRUE(response
->headers
.get() != NULL
);
3789 EXPECT_TRUE(response
->was_fetched_via_spdy
);
3790 out
.status_line
= response
->headers
->GetStatusLine();
3791 out
.response_info
= *response
; // Make a copy so we can verify.
3794 TestCompletionCallback read_callback
;
3796 std::string content
;
3797 int reads_completed
= 0;
3799 // Read small chunks at a time.
3800 const int kSmallReadSize
= 14;
3801 scoped_refptr
<IOBuffer
> buf(new IOBuffer(kSmallReadSize
));
3802 rv
= trans
->Read(buf
.get(), kSmallReadSize
, read_callback
.callback());
3803 if (rv
== ERR_IO_PENDING
) {
3804 data
.CompleteRead();
3805 rv
= read_callback
.WaitForResult();
3808 EXPECT_EQ(kSmallReadSize
, rv
);
3809 content
.append(buf
->data(), rv
);
3810 } else if (rv
< 0) {
3811 FAIL() << "Unexpected read error: " << rv
;
3816 EXPECT_EQ(3, reads_completed
); // Reads are: 14 bytes, 14 bytes, 0 bytes.
3818 out
.response_data
.swap(content
);
3820 // Flush the MessageLoop while the SpdySessionDependencies (in particular, the
3821 // MockClientSocketFactory) are still alive.
3822 base::RunLoop().RunUntilIdle();
3824 // Verify that we consumed all test data.
3825 helper
.VerifyDataConsumed();
3827 EXPECT_EQ(OK
, out
.rv
);
3828 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
3829 EXPECT_EQ("messagemessagemessagemessage", out
.response_data
);
3832 // Verify the case where we buffer data but read it after it has been buffered.
3833 TEST_P(SpdyNetworkTransactionTest
, BufferedAll
) {
3834 BufferedSpdyFramer
framer(spdy_util_
.spdy_version(), false);
3836 scoped_ptr
<SpdyFrame
> req(
3837 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
3838 MockWrite writes
[] = {CreateMockWrite(*req
, 0)};
3840 // 5 data frames in a single read.
3841 scoped_ptr
<SpdyFrame
> reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
3842 scoped_ptr
<SpdyFrame
> data_frame(
3843 framer
.CreateDataFrame(1, "message", 7, DATA_FLAG_NONE
));
3844 scoped_ptr
<SpdyFrame
> data_frame_fin(
3845 framer
.CreateDataFrame(1, "message", 7, DATA_FLAG_FIN
));
3846 const SpdyFrame
* frames
[5] = {reply
.get(), data_frame
.get(), data_frame
.get(),
3847 data_frame
.get(), data_frame_fin
.get()};
3848 char combined_frames
[200];
3849 int combined_frames_len
=
3850 CombineFrames(frames
, arraysize(frames
),
3851 combined_frames
, arraysize(combined_frames
));
3853 MockRead reads
[] = {
3854 MockRead(ASYNC
, combined_frames
, combined_frames_len
, 1),
3855 MockRead(ASYNC
, 0, 2) // EOF
3858 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
3860 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
3861 BoundNetLog(), GetParam(), NULL
);
3862 helper
.RunPreTestSetup();
3863 helper
.AddData(&data
);
3864 HttpNetworkTransaction
* trans
= helper
.trans();
3866 TestCompletionCallback callback
;
3867 int rv
= trans
->Start(
3868 &CreateGetRequest(), callback
.callback(), BoundNetLog());
3869 EXPECT_EQ(ERR_IO_PENDING
, rv
);
3871 TransactionHelperResult out
= helper
.output();
3872 out
.rv
= callback
.WaitForResult();
3873 EXPECT_EQ(out
.rv
, OK
);
3875 const HttpResponseInfo
* response
= trans
->GetResponseInfo();
3876 EXPECT_TRUE(response
->headers
.get() != NULL
);
3877 EXPECT_TRUE(response
->was_fetched_via_spdy
);
3878 out
.status_line
= response
->headers
->GetStatusLine();
3879 out
.response_info
= *response
; // Make a copy so we can verify.
3882 TestCompletionCallback read_callback
;
3884 std::string content
;
3885 int reads_completed
= 0;
3887 // Read small chunks at a time.
3888 const int kSmallReadSize
= 14;
3889 scoped_refptr
<IOBuffer
> buf(new IOBuffer(kSmallReadSize
));
3890 rv
= trans
->Read(buf
.get(), kSmallReadSize
, read_callback
.callback());
3892 EXPECT_EQ(kSmallReadSize
, rv
);
3893 content
.append(buf
->data(), rv
);
3894 } else if (rv
< 0) {
3895 FAIL() << "Unexpected read error: " << rv
;
3900 EXPECT_EQ(3, reads_completed
);
3902 out
.response_data
.swap(content
);
3904 // Flush the MessageLoop while the SpdySessionDependencies (in particular, the
3905 // MockClientSocketFactory) are still alive.
3906 base::RunLoop().RunUntilIdle();
3908 // Verify that we consumed all test data.
3909 helper
.VerifyDataConsumed();
3911 EXPECT_EQ(OK
, out
.rv
);
3912 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
3913 EXPECT_EQ("messagemessagemessagemessage", out
.response_data
);
3916 // Verify the case where we buffer data and close the connection.
3917 TEST_P(SpdyNetworkTransactionTest
, BufferedClosed
) {
3918 BufferedSpdyFramer
framer(spdy_util_
.spdy_version(), false);
3920 scoped_ptr
<SpdyFrame
> req(
3921 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
3922 MockWrite writes
[] = {CreateMockWrite(*req
, 0)};
3924 // All data frames in a single read.
3925 // NOTE: We don't FIN the stream.
3926 scoped_ptr
<SpdyFrame
> data_frame(
3927 framer
.CreateDataFrame(1, "message", 7, DATA_FLAG_NONE
));
3928 const SpdyFrame
* data_frames
[4] = {
3934 char combined_data_frames
[100];
3935 int combined_data_frames_len
=
3936 CombineFrames(data_frames
, arraysize(data_frames
),
3937 combined_data_frames
, arraysize(combined_data_frames
));
3938 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
3939 MockRead reads
[] = {
3940 CreateMockRead(*resp
, 1),
3941 MockRead(ASYNC
, ERR_IO_PENDING
, 2), // Force a wait
3942 MockRead(ASYNC
, combined_data_frames
, combined_data_frames_len
, 3),
3943 MockRead(ASYNC
, 0, 4) // EOF
3946 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
3948 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
3949 BoundNetLog(), GetParam(), NULL
);
3950 helper
.RunPreTestSetup();
3951 helper
.AddData(&data
);
3952 HttpNetworkTransaction
* trans
= helper
.trans();
3954 TestCompletionCallback callback
;
3956 int rv
= trans
->Start(
3957 &CreateGetRequest(), callback
.callback(), BoundNetLog());
3958 EXPECT_EQ(ERR_IO_PENDING
, rv
);
3960 TransactionHelperResult out
= helper
.output();
3961 out
.rv
= callback
.WaitForResult();
3962 EXPECT_EQ(out
.rv
, OK
);
3964 const HttpResponseInfo
* response
= trans
->GetResponseInfo();
3965 EXPECT_TRUE(response
->headers
.get() != NULL
);
3966 EXPECT_TRUE(response
->was_fetched_via_spdy
);
3967 out
.status_line
= response
->headers
->GetStatusLine();
3968 out
.response_info
= *response
; // Make a copy so we can verify.
3971 TestCompletionCallback read_callback
;
3973 std::string content
;
3974 int reads_completed
= 0;
3976 // Read small chunks at a time.
3977 const int kSmallReadSize
= 14;
3978 scoped_refptr
<IOBuffer
> buf(new IOBuffer(kSmallReadSize
));
3979 rv
= trans
->Read(buf
.get(), kSmallReadSize
, read_callback
.callback());
3980 if (rv
== ERR_IO_PENDING
) {
3981 data
.CompleteRead();
3982 rv
= read_callback
.WaitForResult();
3985 content
.append(buf
->data(), rv
);
3986 } else if (rv
< 0) {
3987 // This test intentionally closes the connection, and will get an error.
3988 EXPECT_EQ(ERR_CONNECTION_CLOSED
, rv
);
3994 EXPECT_EQ(0, reads_completed
);
3996 out
.response_data
.swap(content
);
3998 // Flush the MessageLoop while the SpdySessionDependencies (in particular, the
3999 // MockClientSocketFactory) are still alive.
4000 base::RunLoop().RunUntilIdle();
4002 // Verify that we consumed all test data.
4003 helper
.VerifyDataConsumed();
4006 // Verify the case where we buffer data and cancel the transaction.
4007 TEST_P(SpdyNetworkTransactionTest
, BufferedCancelled
) {
4008 BufferedSpdyFramer
framer(spdy_util_
.spdy_version(), false);
4010 scoped_ptr
<SpdyFrame
> req(
4011 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
4012 scoped_ptr
<SpdyFrame
> rst(
4013 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_CANCEL
));
4014 MockWrite writes
[] = {CreateMockWrite(*req
, 0), CreateMockWrite(*rst
, 4)};
4016 // NOTE: We don't FIN the stream.
4017 scoped_ptr
<SpdyFrame
> data_frame(
4018 framer
.CreateDataFrame(1, "message", 7, DATA_FLAG_NONE
));
4020 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
4021 MockRead reads
[] = {
4022 CreateMockRead(*resp
, 1),
4023 MockRead(ASYNC
, ERR_IO_PENDING
, 2), // Force a wait
4024 CreateMockRead(*data_frame
, 3),
4025 MockRead(ASYNC
, 0, 5) // EOF
4028 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
4030 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
4031 BoundNetLog(), GetParam(), NULL
);
4032 helper
.RunPreTestSetup();
4033 helper
.AddData(&data
);
4034 HttpNetworkTransaction
* trans
= helper
.trans();
4035 TestCompletionCallback callback
;
4037 int rv
= trans
->Start(
4038 &CreateGetRequest(), callback
.callback(), BoundNetLog());
4039 EXPECT_EQ(ERR_IO_PENDING
, rv
);
4041 TransactionHelperResult out
= helper
.output();
4042 out
.rv
= callback
.WaitForResult();
4043 EXPECT_EQ(out
.rv
, OK
);
4045 const HttpResponseInfo
* response
= trans
->GetResponseInfo();
4046 EXPECT_TRUE(response
->headers
.get() != NULL
);
4047 EXPECT_TRUE(response
->was_fetched_via_spdy
);
4048 out
.status_line
= response
->headers
->GetStatusLine();
4049 out
.response_info
= *response
; // Make a copy so we can verify.
4052 TestCompletionCallback read_callback
;
4054 const int kReadSize
= 256;
4055 scoped_refptr
<IOBuffer
> buf(new IOBuffer(kReadSize
));
4056 rv
= trans
->Read(buf
.get(), kReadSize
, read_callback
.callback());
4057 ASSERT_EQ(ERR_IO_PENDING
, rv
) << "Unexpected read: " << rv
;
4059 // Complete the read now, which causes buffering to start.
4060 data
.CompleteRead();
4061 // Destroy the transaction, causing the stream to get cancelled
4062 // and orphaning the buffered IO task.
4063 helper
.ResetTrans();
4065 // Flush the MessageLoop; this will cause the buffered IO task
4066 // to run for the final time.
4067 base::RunLoop().RunUntilIdle();
4069 // Verify that we consumed all test data.
4070 helper
.VerifyDataConsumed();
4073 // Test that if the server requests persistence of settings, that we save
4074 // the settings in the HttpServerProperties.
4075 TEST_P(SpdyNetworkTransactionTest
, SettingsSaved
) {
4076 if (spdy_util_
.spdy_version() >= HTTP2
) {
4077 // HTTP/2 doesn't support settings persistence.
4080 static const SpdyHeaderInfo kSynReplyInfo
= {
4081 SYN_REPLY
, // Syn Reply
4083 0, // Associated Stream ID
4084 ConvertRequestPriorityToSpdyPriority(
4085 LOWEST
, spdy_util_
.spdy_version()),
4086 kSpdyCredentialSlotUnused
,
4087 CONTROL_FLAG_NONE
, // Control Flags
4088 false, // Compressed
4089 RST_STREAM_INVALID
, // Status
4092 DATA_FLAG_NONE
// Data Flags
4095 BoundNetLog net_log
;
4096 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
4097 net_log
, GetParam(), NULL
);
4098 helper
.RunPreTestSetup();
4100 // Verify that no settings exist initially.
4101 HostPortPair
host_port_pair("www.example.org", helper
.port());
4102 SpdySessionPool
* spdy_session_pool
= helper
.session()->spdy_session_pool();
4103 EXPECT_TRUE(spdy_session_pool
->http_server_properties()->GetSpdySettings(
4104 host_port_pair
).empty());
4106 // Construct the request.
4107 scoped_ptr
<SpdyFrame
> req(
4108 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
4109 MockWrite writes
[] = {CreateMockWrite(*req
, 0)};
4111 // Construct the reply.
4112 scoped_ptr
<SpdyHeaderBlock
> reply_headers(new SpdyHeaderBlock());
4113 (*reply_headers
)[spdy_util_
.GetStatusKey()] = "200";
4114 (*reply_headers
)[spdy_util_
.GetVersionKey()] = "HTTP/1.1";
4115 scoped_ptr
<SpdyFrame
> reply(
4116 spdy_util_
.ConstructSpdyFrame(kSynReplyInfo
, reply_headers
.Pass()));
4118 const SpdySettingsIds kSampleId1
= SETTINGS_UPLOAD_BANDWIDTH
;
4119 unsigned int kSampleValue1
= 0x0a0a0a0a;
4120 const SpdySettingsIds kSampleId2
= SETTINGS_DOWNLOAD_BANDWIDTH
;
4121 unsigned int kSampleValue2
= 0x0b0b0b0b;
4122 const SpdySettingsIds kSampleId3
= SETTINGS_ROUND_TRIP_TIME
;
4123 unsigned int kSampleValue3
= 0x0c0c0c0c;
4124 scoped_ptr
<SpdyFrame
> settings_frame
;
4126 // Construct the SETTINGS frame.
4127 SettingsMap settings
;
4128 // First add a persisted setting.
4129 settings
[kSampleId1
] =
4130 SettingsFlagsAndValue(SETTINGS_FLAG_PLEASE_PERSIST
, kSampleValue1
);
4131 // Next add a non-persisted setting.
4132 settings
[kSampleId2
] =
4133 SettingsFlagsAndValue(SETTINGS_FLAG_NONE
, kSampleValue2
);
4134 // Next add another persisted setting.
4135 settings
[kSampleId3
] =
4136 SettingsFlagsAndValue(SETTINGS_FLAG_PLEASE_PERSIST
, kSampleValue3
);
4137 settings_frame
.reset(spdy_util_
.ConstructSpdySettings(settings
));
4140 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
4141 MockRead reads
[] = {
4142 CreateMockRead(*reply
, 1),
4143 CreateMockRead(*body
, 2),
4144 CreateMockRead(*settings_frame
, 3),
4145 MockRead(ASYNC
, 0, 4) // EOF
4148 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
4149 helper
.AddData(&data
);
4150 helper
.RunDefaultTest();
4151 helper
.VerifyDataConsumed();
4152 TransactionHelperResult out
= helper
.output();
4153 EXPECT_EQ(OK
, out
.rv
);
4154 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
4155 EXPECT_EQ("hello!", out
.response_data
);
4158 // Verify we had two persisted settings.
4159 const SettingsMap
& settings_map
=
4160 spdy_session_pool
->http_server_properties()->GetSpdySettings(
4162 ASSERT_EQ(2u, settings_map
.size());
4164 // Verify the first persisted setting.
4165 SettingsMap::const_iterator it1
= settings_map
.find(kSampleId1
);
4166 EXPECT_TRUE(it1
!= settings_map
.end());
4167 SettingsFlagsAndValue flags_and_value1
= it1
->second
;
4168 EXPECT_EQ(SETTINGS_FLAG_PERSISTED
, flags_and_value1
.first
);
4169 EXPECT_EQ(kSampleValue1
, flags_and_value1
.second
);
4171 // Verify the second persisted setting.
4172 SettingsMap::const_iterator it3
= settings_map
.find(kSampleId3
);
4173 EXPECT_TRUE(it3
!= settings_map
.end());
4174 SettingsFlagsAndValue flags_and_value3
= it3
->second
;
4175 EXPECT_EQ(SETTINGS_FLAG_PERSISTED
, flags_and_value3
.first
);
4176 EXPECT_EQ(kSampleValue3
, flags_and_value3
.second
);
4180 // Test that when there are settings saved that they are sent back to the
4181 // server upon session establishment.
4182 TEST_P(SpdyNetworkTransactionTest
, SettingsPlayback
) {
4183 if (spdy_util_
.spdy_version() >= HTTP2
) {
4184 // HTTP/2 doesn't support settings persistence.
4187 static const SpdyHeaderInfo kSynReplyInfo
= {
4188 SYN_REPLY
, // Syn Reply
4190 0, // Associated Stream ID
4191 ConvertRequestPriorityToSpdyPriority(
4192 LOWEST
, spdy_util_
.spdy_version()),
4193 kSpdyCredentialSlotUnused
,
4194 CONTROL_FLAG_NONE
, // Control Flags
4195 false, // Compressed
4196 RST_STREAM_INVALID
, // Status
4199 DATA_FLAG_NONE
// Data Flags
4202 BoundNetLog net_log
;
4203 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
4204 net_log
, GetParam(), NULL
);
4205 helper
.RunPreTestSetup();
4207 SpdySessionPool
* spdy_session_pool
= helper
.session()->spdy_session_pool();
4209 SpdySessionPoolPeer
pool_peer(spdy_session_pool
);
4210 pool_peer
.SetEnableSendingInitialData(true);
4212 // Verify that no settings exist initially.
4213 HostPortPair
host_port_pair("www.example.org", helper
.port());
4214 EXPECT_TRUE(spdy_session_pool
->http_server_properties()->GetSpdySettings(
4215 host_port_pair
).empty());
4217 const SpdySettingsIds kSampleId1
= SETTINGS_MAX_CONCURRENT_STREAMS
;
4218 unsigned int kSampleValue1
= 0x0a0a0a0a;
4219 const SpdySettingsIds kSampleId2
= SETTINGS_INITIAL_WINDOW_SIZE
;
4220 unsigned int kSampleValue2
= 0x0c0c0c0c;
4222 // First add a persisted setting.
4223 spdy_session_pool
->http_server_properties()->SetSpdySetting(
4226 SETTINGS_FLAG_PLEASE_PERSIST
,
4229 // Next add another persisted setting.
4230 spdy_session_pool
->http_server_properties()->SetSpdySetting(
4233 SETTINGS_FLAG_PLEASE_PERSIST
,
4236 EXPECT_EQ(2u, spdy_session_pool
->http_server_properties()->GetSpdySettings(
4237 host_port_pair
).size());
4239 // Construct the initial SETTINGS frame.
4240 SettingsMap initial_settings
;
4241 initial_settings
[SETTINGS_MAX_CONCURRENT_STREAMS
] =
4242 SettingsFlagsAndValue(SETTINGS_FLAG_NONE
, kMaxConcurrentPushedStreams
);
4243 scoped_ptr
<SpdyFrame
> initial_settings_frame(
4244 spdy_util_
.ConstructSpdySettings(initial_settings
));
4246 // Construct the persisted SETTINGS frame.
4247 const SettingsMap
& settings
=
4248 spdy_session_pool
->http_server_properties()->GetSpdySettings(
4250 scoped_ptr
<SpdyFrame
> settings_frame(
4251 spdy_util_
.ConstructSpdySettings(settings
));
4253 // Construct the request.
4254 scoped_ptr
<SpdyFrame
> req(
4255 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
4257 MockWrite writes
[] = {
4258 CreateMockWrite(*initial_settings_frame
, 0),
4259 CreateMockWrite(*settings_frame
, 1),
4260 CreateMockWrite(*req
, 2),
4263 // Construct the reply.
4264 scoped_ptr
<SpdyHeaderBlock
> reply_headers(new SpdyHeaderBlock());
4265 (*reply_headers
)[spdy_util_
.GetStatusKey()] = "200";
4266 (*reply_headers
)[spdy_util_
.GetVersionKey()] = "HTTP/1.1";
4267 scoped_ptr
<SpdyFrame
> reply(
4268 spdy_util_
.ConstructSpdyFrame(kSynReplyInfo
, reply_headers
.Pass()));
4270 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
4271 MockRead reads
[] = {
4272 CreateMockRead(*reply
, 3),
4273 CreateMockRead(*body
, 4),
4274 MockRead(ASYNC
, 0, 5) // EOF
4277 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
4278 helper
.AddData(&data
);
4279 helper
.RunDefaultTest();
4280 helper
.VerifyDataConsumed();
4281 TransactionHelperResult out
= helper
.output();
4282 EXPECT_EQ(OK
, out
.rv
);
4283 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
4284 EXPECT_EQ("hello!", out
.response_data
);
4287 // Verify we had two persisted settings.
4288 const SettingsMap
& settings_map
=
4289 spdy_session_pool
->http_server_properties()->GetSpdySettings(
4291 ASSERT_EQ(2u, settings_map
.size());
4293 // Verify the first persisted setting.
4294 SettingsMap::const_iterator it1
= settings_map
.find(kSampleId1
);
4295 EXPECT_TRUE(it1
!= settings_map
.end());
4296 SettingsFlagsAndValue flags_and_value1
= it1
->second
;
4297 EXPECT_EQ(SETTINGS_FLAG_PERSISTED
, flags_and_value1
.first
);
4298 EXPECT_EQ(kSampleValue1
, flags_and_value1
.second
);
4300 // Verify the second persisted setting.
4301 SettingsMap::const_iterator it2
= settings_map
.find(kSampleId2
);
4302 EXPECT_TRUE(it2
!= settings_map
.end());
4303 SettingsFlagsAndValue flags_and_value2
= it2
->second
;
4304 EXPECT_EQ(SETTINGS_FLAG_PERSISTED
, flags_and_value2
.first
);
4305 EXPECT_EQ(kSampleValue2
, flags_and_value2
.second
);
4309 TEST_P(SpdyNetworkTransactionTest
, GoAwayWithActiveStream
) {
4310 scoped_ptr
<SpdyFrame
> req(
4311 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
4312 MockWrite writes
[] = {CreateMockWrite(*req
, 0)};
4314 scoped_ptr
<SpdyFrame
> go_away(spdy_util_
.ConstructSpdyGoAway());
4315 MockRead reads
[] = {
4316 CreateMockRead(*go_away
, 1),
4319 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
4320 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
4321 BoundNetLog(), GetParam(), NULL
);
4322 helper
.AddData(&data
);
4323 helper
.RunToCompletion(&data
);
4324 TransactionHelperResult out
= helper
.output();
4325 EXPECT_EQ(ERR_ABORTED
, out
.rv
);
4328 TEST_P(SpdyNetworkTransactionTest
, CloseWithActiveStream
) {
4329 scoped_ptr
<SpdyFrame
> req(
4330 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
4331 MockWrite writes
[] = {CreateMockWrite(*req
, 0)};
4333 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
4334 MockRead reads
[] = {
4335 CreateMockRead(*resp
, 1), MockRead(SYNCHRONOUS
, 0, 2) // EOF
4338 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
4340 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
4341 log
, GetParam(), NULL
);
4342 helper
.RunPreTestSetup();
4343 helper
.AddData(&data
);
4344 HttpNetworkTransaction
* trans
= helper
.trans();
4346 TestCompletionCallback callback
;
4347 TransactionHelperResult out
;
4348 out
.rv
= trans
->Start(&CreateGetRequest(), callback
.callback(), log
);
4350 EXPECT_EQ(out
.rv
, ERR_IO_PENDING
);
4351 out
.rv
= callback
.WaitForResult();
4352 EXPECT_EQ(out
.rv
, OK
);
4354 const HttpResponseInfo
* response
= trans
->GetResponseInfo();
4355 EXPECT_TRUE(response
->headers
.get() != NULL
);
4356 EXPECT_TRUE(response
->was_fetched_via_spdy
);
4357 out
.rv
= ReadTransaction(trans
, &out
.response_data
);
4358 EXPECT_EQ(ERR_CONNECTION_CLOSED
, out
.rv
);
4360 // Verify that we consumed all test data.
4361 helper
.VerifyDataConsumed();
4364 // HTTP_1_1_REQUIRED results in ERR_HTTP_1_1_REQUIRED.
4365 TEST_P(SpdyNetworkTransactionTest
, HTTP11RequiredError
) {
4366 // HTTP_1_1_REQUIRED is only supported by HTTP/2.
4367 if (spdy_util_
.spdy_version() < HTTP2
)
4370 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
4371 BoundNetLog(), GetParam(), nullptr);
4373 scoped_ptr
<SpdyFrame
> go_away(spdy_util_
.ConstructSpdyGoAway(
4374 0, GOAWAY_HTTP_1_1_REQUIRED
, "Try again using HTTP/1.1 please."));
4375 MockRead reads
[] = {
4376 CreateMockRead(*go_away
, 0),
4378 SequencedSocketData
data(reads
, arraysize(reads
), nullptr, 0);
4380 helper
.RunToCompletion(&data
);
4381 TransactionHelperResult out
= helper
.output();
4382 EXPECT_EQ(ERR_HTTP_1_1_REQUIRED
, out
.rv
);
4385 // Retry with HTTP/1.1 when receiving HTTP_1_1_REQUIRED. Note that no actual
4386 // protocol negotiation happens, instead this test forces protocols for both
4388 TEST_P(SpdyNetworkTransactionTest
, HTTP11RequiredRetry
) {
4389 // HTTP_1_1_REQUIRED is only supported by HTTP/2.
4390 if (spdy_util_
.spdy_version() < HTTP2
)
4392 // HTTP_1_1_REQUIRED implementation relies on the assumption that HTTP/2 is
4393 // only spoken over SSL.
4394 if (GetParam().ssl_type
!= HTTPS_SPDY_VIA_NPN
)
4397 HttpRequestInfo request
;
4398 request
.method
= "GET";
4399 request
.url
= GURL("https://www.example.org/");
4400 scoped_ptr
<SpdySessionDependencies
> session_deps(
4401 CreateSpdySessionDependencies(GetParam()));
4402 // Do not force SPDY so that second socket can negotiate HTTP/1.1.
4403 session_deps
->next_protos
= SpdyNextProtos();
4404 NormalSpdyTransactionHelper
helper(request
, DEFAULT_PRIORITY
, BoundNetLog(),
4405 GetParam(), session_deps
.release());
4407 // First socket: HTTP/2 request rejected with HTTP_1_1_REQUIRED.
4408 const char* url
= request
.url
.spec().c_str();
4409 scoped_ptr
<SpdyHeaderBlock
> headers(spdy_util_
.ConstructGetHeaderBlock(url
));
4410 scoped_ptr
<SpdyFrame
> req(
4411 spdy_util_
.ConstructSpdySyn(1, *headers
, LOWEST
, false, true));
4412 MockWrite writes0
[] = {CreateMockWrite(*req
, 0)};
4413 scoped_ptr
<SpdyFrame
> go_away(spdy_util_
.ConstructSpdyGoAway(
4414 0, GOAWAY_HTTP_1_1_REQUIRED
, "Try again using HTTP/1.1 please."));
4415 MockRead reads0
[] = {CreateMockRead(*go_away
, 1)};
4416 SequencedSocketData
data0(reads0
, arraysize(reads0
), writes0
,
4417 arraysize(writes0
));
4419 scoped_ptr
<SSLSocketDataProvider
> ssl_provider0(
4420 new SSLSocketDataProvider(ASYNC
, OK
));
4421 // Expect HTTP/2 protocols too in SSLConfig.
4422 ssl_provider0
->next_protos_expected_in_ssl_config
.push_back(kProtoHTTP11
);
4423 ssl_provider0
->next_protos_expected_in_ssl_config
.push_back(kProtoSPDY31
);
4424 ssl_provider0
->next_protos_expected_in_ssl_config
.push_back(kProtoHTTP2_14
);
4425 ssl_provider0
->next_protos_expected_in_ssl_config
.push_back(kProtoHTTP2
);
4427 ssl_provider0
->SetNextProto(GetParam().protocol
);
4428 helper
.AddDataWithSSLSocketDataProvider(&data0
, ssl_provider0
.Pass());
4430 // Second socket: falling back to HTTP/1.1.
4431 MockWrite writes1
[] = {MockWrite(ASYNC
, 0,
4432 "GET / HTTP/1.1\r\n"
4433 "Host: www.example.org\r\n"
4434 "Connection: keep-alive\r\n\r\n")};
4435 MockRead reads1
[] = {MockRead(ASYNC
, 1,
4436 "HTTP/1.1 200 OK\r\n"
4437 "Content-Length: 5\r\n\r\n"
4439 SequencedSocketData
data1(reads1
, arraysize(reads1
), writes1
,
4440 arraysize(writes1
));
4442 scoped_ptr
<SSLSocketDataProvider
> ssl_provider1(
4443 new SSLSocketDataProvider(ASYNC
, OK
));
4444 // Expect only HTTP/1.1 protocol in SSLConfig.
4445 ssl_provider1
->next_protos_expected_in_ssl_config
.push_back(kProtoHTTP11
);
4447 ssl_provider1
->SetNextProto(kProtoHTTP11
);
4448 helper
.AddDataWithSSLSocketDataProvider(&data1
, ssl_provider1
.Pass());
4450 base::WeakPtr
<HttpServerProperties
> http_server_properties
=
4451 helper
.session()->spdy_session_pool()->http_server_properties();
4452 const HostPortPair host_port_pair
= HostPortPair::FromURL(GURL(url
));
4453 EXPECT_FALSE(http_server_properties
->RequiresHTTP11(host_port_pair
));
4455 helper
.RunPreTestSetup();
4456 helper
.StartDefaultTest();
4457 helper
.FinishDefaultTestWithoutVerification();
4458 helper
.VerifyDataConsumed();
4459 EXPECT_TRUE(http_server_properties
->RequiresHTTP11(host_port_pair
));
4461 const HttpResponseInfo
* response
= helper
.trans()->GetResponseInfo();
4462 ASSERT_TRUE(response
!= nullptr);
4463 ASSERT_TRUE(response
->headers
.get() != nullptr);
4464 EXPECT_EQ("HTTP/1.1 200 OK", response
->headers
->GetStatusLine());
4465 EXPECT_FALSE(response
->was_fetched_via_spdy
);
4466 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP1
, response
->connection_info
);
4467 EXPECT_TRUE(response
->was_npn_negotiated
);
4468 EXPECT_TRUE(request
.url
.SchemeIs("https"));
4469 EXPECT_EQ("127.0.0.1", response
->socket_address
.host());
4470 EXPECT_EQ(443, response
->socket_address
.port());
4471 std::string response_data
;
4472 ASSERT_EQ(OK
, ReadTransaction(helper
.trans(), &response_data
));
4473 EXPECT_EQ("hello", response_data
);
4476 // Retry with HTTP/1.1 to the proxy when receiving HTTP_1_1_REQUIRED from the
4477 // proxy. Note that no actual protocol negotiation happens, instead this test
4478 // forces protocols for both sockets.
4479 TEST_P(SpdyNetworkTransactionTest
, HTTP11RequiredProxyRetry
) {
4480 // HTTP_1_1_REQUIRED is only supported by HTTP/2.
4481 if (spdy_util_
.spdy_version() < HTTP2
)
4483 // HTTP_1_1_REQUIRED implementation relies on the assumption that HTTP/2 is
4484 // only spoken over SSL.
4485 if (GetParam().ssl_type
!= HTTPS_SPDY_VIA_NPN
)
4488 HttpRequestInfo request
;
4489 request
.method
= "GET";
4490 request
.url
= GURL("https://www.example.org/");
4491 scoped_ptr
<SpdySessionDependencies
> session_deps(
4492 CreateSpdySessionDependencies(
4494 ProxyService::CreateFixedFromPacResult("HTTPS myproxy:70")));
4495 // Do not force SPDY so that second socket can negotiate HTTP/1.1.
4496 session_deps
->next_protos
= SpdyNextProtos();
4497 NormalSpdyTransactionHelper
helper(request
, DEFAULT_PRIORITY
, BoundNetLog(),
4498 GetParam(), session_deps
.release());
4500 // First socket: HTTP/2 CONNECT rejected with HTTP_1_1_REQUIRED.
4501 scoped_ptr
<SpdyFrame
> req(spdy_util_
.ConstructSpdyConnect(
4502 nullptr, 0, 1, LOWEST
, HostPortPair("www.example.org", 443)));
4503 MockWrite writes0
[] = {CreateMockWrite(*req
, 0)};
4504 scoped_ptr
<SpdyFrame
> go_away(spdy_util_
.ConstructSpdyGoAway(
4505 0, GOAWAY_HTTP_1_1_REQUIRED
, "Try again using HTTP/1.1 please."));
4506 MockRead reads0
[] = {CreateMockRead(*go_away
, 1)};
4507 SequencedSocketData
data0(reads0
, arraysize(reads0
), writes0
,
4508 arraysize(writes0
));
4510 scoped_ptr
<SSLSocketDataProvider
> ssl_provider0(
4511 new SSLSocketDataProvider(ASYNC
, OK
));
4512 // Expect HTTP/2 protocols too in SSLConfig.
4513 ssl_provider0
->next_protos_expected_in_ssl_config
.push_back(kProtoHTTP11
);
4514 ssl_provider0
->next_protos_expected_in_ssl_config
.push_back(kProtoSPDY31
);
4515 ssl_provider0
->next_protos_expected_in_ssl_config
.push_back(kProtoHTTP2_14
);
4516 ssl_provider0
->next_protos_expected_in_ssl_config
.push_back(kProtoHTTP2
);
4518 ssl_provider0
->SetNextProto(GetParam().protocol
);
4519 helper
.AddDataWithSSLSocketDataProvider(&data0
, ssl_provider0
.Pass());
4521 // Second socket: retry using HTTP/1.1.
4522 MockWrite writes1
[] = {
4524 "CONNECT www.example.org:443 HTTP/1.1\r\n"
4525 "Host: www.example.org\r\n"
4526 "Proxy-Connection: keep-alive\r\n\r\n"),
4528 "GET / HTTP/1.1\r\n"
4529 "Host: www.example.org\r\n"
4530 "Connection: keep-alive\r\n\r\n"),
4533 MockRead reads1
[] = {
4534 MockRead(ASYNC
, 1, "HTTP/1.1 200 OK\r\n\r\n"),
4536 "HTTP/1.1 200 OK\r\n"
4537 "Content-Length: 5\r\n\r\n"
4540 SequencedSocketData
data1(reads1
, arraysize(reads1
), writes1
,
4541 arraysize(writes1
));
4543 scoped_ptr
<SSLSocketDataProvider
> ssl_provider1(
4544 new SSLSocketDataProvider(ASYNC
, OK
));
4545 // Expect only HTTP/1.1 protocol in SSLConfig.
4546 ssl_provider1
->next_protos_expected_in_ssl_config
.push_back(kProtoHTTP11
);
4548 ssl_provider1
->SetNextProto(kProtoHTTP11
);
4549 helper
.AddDataWithSSLSocketDataProvider(&data1
, ssl_provider1
.Pass());
4551 // A third socket is needed for the tunnelled connection.
4552 scoped_ptr
<SSLSocketDataProvider
> ssl_provider2(
4553 new SSLSocketDataProvider(ASYNC
, OK
));
4554 helper
.session_deps()->socket_factory
->AddSSLSocketDataProvider(
4555 ssl_provider2
.get());
4557 base::WeakPtr
<HttpServerProperties
> http_server_properties
=
4558 helper
.session()->spdy_session_pool()->http_server_properties();
4559 const HostPortPair proxy_host_port_pair
= HostPortPair("myproxy", 70);
4560 EXPECT_FALSE(http_server_properties
->RequiresHTTP11(proxy_host_port_pair
));
4562 helper
.RunPreTestSetup();
4563 helper
.StartDefaultTest();
4564 helper
.FinishDefaultTestWithoutVerification();
4565 helper
.VerifyDataConsumed();
4566 EXPECT_TRUE(http_server_properties
->RequiresHTTP11(proxy_host_port_pair
));
4568 const HttpResponseInfo
* response
= helper
.trans()->GetResponseInfo();
4569 ASSERT_TRUE(response
!= nullptr);
4570 ASSERT_TRUE(response
->headers
.get() != nullptr);
4571 EXPECT_EQ("HTTP/1.1 200 OK", response
->headers
->GetStatusLine());
4572 EXPECT_FALSE(response
->was_fetched_via_spdy
);
4573 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP1
, response
->connection_info
);
4574 EXPECT_FALSE(response
->was_npn_negotiated
);
4575 EXPECT_TRUE(request
.url
.SchemeIs("https"));
4576 EXPECT_EQ("127.0.0.1", response
->socket_address
.host());
4577 EXPECT_EQ(70, response
->socket_address
.port());
4578 std::string response_data
;
4579 ASSERT_EQ(OK
, ReadTransaction(helper
.trans(), &response_data
));
4580 EXPECT_EQ("hello", response_data
);
4583 // Test to make sure we can correctly connect through a proxy.
4584 TEST_P(SpdyNetworkTransactionTest
, ProxyConnect
) {
4585 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
4586 BoundNetLog(), GetParam(), NULL
);
4587 helper
.session_deps().reset(CreateSpdySessionDependencies(
4589 ProxyService::CreateFixedFromPacResult("PROXY myproxy:70")));
4590 helper
.SetSession(make_scoped_refptr(
4591 SpdySessionDependencies::SpdyCreateSession(helper
.session_deps().get())));
4592 helper
.RunPreTestSetup();
4593 HttpNetworkTransaction
* trans
= helper
.trans();
4595 const char kConnect443
[] = {
4596 "CONNECT www.example.org:443 HTTP/1.1\r\n"
4597 "Host: www.example.org\r\n"
4598 "Proxy-Connection: keep-alive\r\n\r\n"};
4599 const char kHTTP200
[] = {"HTTP/1.1 200 OK\r\n\r\n"};
4600 scoped_ptr
<SpdyFrame
> req(
4601 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
4602 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
4603 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
4605 MockWrite writes
[] = {
4606 MockWrite(SYNCHRONOUS
, kConnect443
, arraysize(kConnect443
) - 1, 0),
4607 CreateMockWrite(*req
, 2),
4609 MockRead reads
[] = {
4610 MockRead(SYNCHRONOUS
, kHTTP200
, arraysize(kHTTP200
) - 1, 1),
4611 CreateMockRead(*resp
, 3),
4612 CreateMockRead(*body
.get(), 4),
4613 MockRead(ASYNC
, 0, 0, 5),
4615 scoped_ptr
<SequencedSocketData
> data(new SequencedSocketData(
4616 reads
, arraysize(reads
), writes
, arraysize(writes
)));
4618 helper
.AddData(data
.get());
4619 TestCompletionCallback callback
;
4621 int rv
= trans
->Start(
4622 &CreateGetRequest(), callback
.callback(), BoundNetLog());
4623 EXPECT_EQ(ERR_IO_PENDING
, rv
);
4625 rv
= callback
.WaitForResult();
4628 // Verify the SYN_REPLY.
4629 HttpResponseInfo response
= *trans
->GetResponseInfo();
4630 EXPECT_TRUE(response
.headers
.get() != NULL
);
4631 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
4633 std::string response_data
;
4634 ASSERT_EQ(OK
, ReadTransaction(trans
, &response_data
));
4635 EXPECT_EQ("hello!", response_data
);
4636 helper
.VerifyDataConsumed();
4639 // Test to make sure we can correctly connect through a proxy to
4640 // www.example.org, if there already exists a direct spdy connection to
4641 // www.example.org. See https://crbug.com/49874.
4642 TEST_P(SpdyNetworkTransactionTest
, DirectConnectProxyReconnect
) {
4643 // When setting up the first transaction, we store the SpdySessionPool so that
4644 // we can use the same pool in the second transaction.
4645 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
4646 BoundNetLog(), GetParam(), NULL
);
4648 // Use a proxy service which returns a proxy fallback list from DIRECT to
4649 // myproxy:70. For this test there will be no fallback, so it is equivalent
4650 // to simply DIRECT. The reason for appending the second proxy is to verify
4651 // that the session pool key used does is just "DIRECT".
4652 helper
.session_deps().reset(CreateSpdySessionDependencies(
4654 ProxyService::CreateFixedFromPacResult("DIRECT; PROXY myproxy:70")));
4655 helper
.SetSession(make_scoped_refptr(
4656 SpdySessionDependencies::SpdyCreateSession(helper
.session_deps().get())));
4658 SpdySessionPool
* spdy_session_pool
= helper
.session()->spdy_session_pool();
4659 helper
.RunPreTestSetup();
4661 // Construct and send a simple GET request.
4662 scoped_ptr
<SpdyFrame
> req(
4663 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
4664 MockWrite writes
[] = {
4665 CreateMockWrite(*req
, 0),
4668 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
4669 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
4670 MockRead reads
[] = {
4671 CreateMockRead(*resp
, 1),
4672 CreateMockRead(*body
, 2),
4673 MockRead(SYNCHRONOUS
, ERR_IO_PENDING
, 3), // Force a pause
4675 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
4676 helper
.AddData(&data
);
4677 HttpNetworkTransaction
* trans
= helper
.trans();
4679 TestCompletionCallback callback
;
4680 TransactionHelperResult out
;
4681 out
.rv
= trans
->Start(
4682 &CreateGetRequest(), callback
.callback(), BoundNetLog());
4684 EXPECT_EQ(out
.rv
, ERR_IO_PENDING
);
4685 out
.rv
= callback
.WaitForResult();
4686 EXPECT_EQ(out
.rv
, OK
);
4688 const HttpResponseInfo
* response
= trans
->GetResponseInfo();
4689 EXPECT_TRUE(response
->headers
.get() != NULL
);
4690 EXPECT_TRUE(response
->was_fetched_via_spdy
);
4691 out
.rv
= ReadTransaction(trans
, &out
.response_data
);
4692 EXPECT_EQ(OK
, out
.rv
);
4693 out
.status_line
= response
->headers
->GetStatusLine();
4694 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
4695 EXPECT_EQ("hello!", out
.response_data
);
4697 // Check that the SpdySession is still in the SpdySessionPool.
4698 HostPortPair
host_port_pair("www.example.org", helper
.port());
4699 SpdySessionKey
session_pool_key_direct(
4700 host_port_pair
, ProxyServer::Direct(), PRIVACY_MODE_DISABLED
);
4701 EXPECT_TRUE(HasSpdySession(spdy_session_pool
, session_pool_key_direct
));
4702 SpdySessionKey
session_pool_key_proxy(
4704 ProxyServer::FromURI("www.foo.com", ProxyServer::SCHEME_HTTP
),
4705 PRIVACY_MODE_DISABLED
);
4706 EXPECT_FALSE(HasSpdySession(spdy_session_pool
, session_pool_key_proxy
));
4708 // Set up data for the proxy connection.
4709 const char kConnect443
[] = {
4710 "CONNECT www.example.org:443 HTTP/1.1\r\n"
4711 "Host: www.example.org\r\n"
4712 "Proxy-Connection: keep-alive\r\n\r\n"};
4713 const char kHTTP200
[] = {"HTTP/1.1 200 OK\r\n\r\n"};
4714 scoped_ptr
<SpdyFrame
> req2(spdy_util_
.ConstructSpdyGet(
4715 GetDefaultUrlWithPath("/foo.dat").c_str(), false, 1, LOWEST
));
4716 scoped_ptr
<SpdyFrame
> resp2(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
4717 scoped_ptr
<SpdyFrame
> body2(spdy_util_
.ConstructSpdyBodyFrame(1, true));
4719 MockWrite writes2
[] = {
4720 MockWrite(SYNCHRONOUS
, kConnect443
, arraysize(kConnect443
) - 1, 0),
4721 CreateMockWrite(*req2
, 2),
4723 MockRead reads2
[] = {
4724 MockRead(SYNCHRONOUS
, kHTTP200
, arraysize(kHTTP200
) - 1, 1),
4725 CreateMockRead(*resp2
, 3),
4726 CreateMockRead(*body2
, 4),
4727 MockRead(ASYNC
, 0, 5) // EOF
4730 scoped_ptr
<SequencedSocketData
> data_proxy(new SequencedSocketData(
4731 reads2
, arraysize(reads2
), writes2
, arraysize(writes2
)));
4733 // Create another request to www.example.org, but this time through a proxy.
4734 HttpRequestInfo request_proxy
;
4735 request_proxy
.method
= "GET";
4736 request_proxy
.url
= GURL(GetDefaultUrlWithPath("/foo.dat"));
4737 request_proxy
.load_flags
= 0;
4738 scoped_ptr
<SpdySessionDependencies
> ssd_proxy(
4739 CreateSpdySessionDependencies(GetParam()));
4740 // Ensure that this transaction uses the same SpdySessionPool.
4741 scoped_refptr
<HttpNetworkSession
> session_proxy(
4742 SpdySessionDependencies::SpdyCreateSession(ssd_proxy
.get()));
4743 NormalSpdyTransactionHelper
helper_proxy(request_proxy
, DEFAULT_PRIORITY
,
4744 BoundNetLog(), GetParam(), NULL
);
4745 HttpNetworkSessionPeer
session_peer(session_proxy
);
4746 scoped_ptr
<ProxyService
> proxy_service(
4747 ProxyService::CreateFixedFromPacResult("PROXY myproxy:70"));
4748 session_peer
.SetProxyService(proxy_service
.get());
4749 helper_proxy
.session_deps().swap(ssd_proxy
);
4750 helper_proxy
.SetSession(session_proxy
);
4751 helper_proxy
.RunPreTestSetup();
4752 helper_proxy
.AddData(data_proxy
.get());
4754 HttpNetworkTransaction
* trans_proxy
= helper_proxy
.trans();
4755 TestCompletionCallback callback_proxy
;
4756 int rv
= trans_proxy
->Start(
4757 &request_proxy
, callback_proxy
.callback(), BoundNetLog());
4758 EXPECT_EQ(ERR_IO_PENDING
, rv
);
4759 rv
= callback_proxy
.WaitForResult();
4762 HttpResponseInfo response_proxy
= *trans_proxy
->GetResponseInfo();
4763 EXPECT_TRUE(response_proxy
.headers
.get() != NULL
);
4764 EXPECT_EQ("HTTP/1.1 200 OK", response_proxy
.headers
->GetStatusLine());
4766 std::string response_data
;
4767 ASSERT_EQ(OK
, ReadTransaction(trans_proxy
, &response_data
));
4768 EXPECT_EQ("hello!", response_data
);
4770 helper_proxy
.VerifyDataConsumed();
4773 // When we get a TCP-level RST, we need to retry a HttpNetworkTransaction
4774 // on a new connection, if the connection was previously known to be good.
4775 // This can happen when a server reboots without saying goodbye, or when
4776 // we're behind a NAT that masked the RST.
4777 TEST_P(SpdyNetworkTransactionTest
, VerifyRetryOnConnectionReset
) {
4778 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
4779 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
4780 MockRead reads
[] = {
4781 CreateMockRead(*resp
, 1),
4782 CreateMockRead(*body
, 2),
4783 MockRead(ASYNC
, ERR_IO_PENDING
, 3),
4784 MockRead(ASYNC
, ERR_CONNECTION_RESET
, 4),
4787 MockRead reads2
[] = {
4788 CreateMockRead(*resp
, 1),
4789 CreateMockRead(*body
, 2),
4790 MockRead(ASYNC
, 0, 3) // EOF
4793 scoped_ptr
<SpdyFrame
> req(
4794 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
4795 scoped_ptr
<SpdyFrame
> req3(
4796 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 3, LOWEST
, true));
4797 MockWrite writes1
[] = {CreateMockWrite(*req
, 0), CreateMockWrite(*req3
, 5)};
4798 MockWrite writes2
[] = {CreateMockWrite(*req
, 0)};
4800 // This test has a couple of variants.
4802 // Induce the RST while waiting for our transaction to send.
4803 VARIANT_RST_DURING_SEND_COMPLETION
= 0,
4804 // Induce the RST while waiting for our transaction to read.
4805 // In this case, the send completed - everything copied into the SNDBUF.
4806 VARIANT_RST_DURING_READ_COMPLETION
= 1
4809 for (int variant
= VARIANT_RST_DURING_SEND_COMPLETION
;
4810 variant
<= VARIANT_RST_DURING_READ_COMPLETION
;
4812 SequencedSocketData
data1(reads
, arraysize(reads
), writes1
, 1 + variant
);
4814 SequencedSocketData
data2(reads2
, arraysize(reads2
), writes2
,
4815 arraysize(writes2
));
4817 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
4818 BoundNetLog(), GetParam(), NULL
);
4819 helper
.AddData(&data1
);
4820 helper
.AddData(&data2
);
4821 helper
.RunPreTestSetup();
4823 for (int i
= 0; i
< 2; ++i
) {
4824 scoped_ptr
<HttpNetworkTransaction
> trans(
4825 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
4827 TestCompletionCallback callback
;
4828 int rv
= trans
->Start(
4829 &helper
.request(), callback
.callback(), BoundNetLog());
4830 EXPECT_EQ(ERR_IO_PENDING
, rv
);
4831 // On the second transaction, we trigger the RST.
4833 if (variant
== VARIANT_RST_DURING_READ_COMPLETION
) {
4834 // Writes to the socket complete asynchronously on SPDY by running
4835 // through the message loop. Complete the write here.
4836 base::RunLoop().RunUntilIdle();
4839 // Now schedule the ERR_CONNECTION_RESET.
4840 data1
.CompleteRead();
4842 rv
= callback
.WaitForResult();
4845 const HttpResponseInfo
* response
= trans
->GetResponseInfo();
4846 ASSERT_TRUE(response
!= NULL
);
4847 EXPECT_TRUE(response
->headers
.get() != NULL
);
4848 EXPECT_TRUE(response
->was_fetched_via_spdy
);
4849 std::string response_data
;
4850 rv
= ReadTransaction(trans
.get(), &response_data
);
4852 EXPECT_EQ("HTTP/1.1 200 OK", response
->headers
->GetStatusLine());
4853 EXPECT_EQ("hello!", response_data
);
4854 base::RunLoop().RunUntilIdle();
4857 helper
.VerifyDataConsumed();
4858 base::RunLoop().RunUntilIdle();
4862 // Test that turning SPDY on and off works properly.
4863 TEST_P(SpdyNetworkTransactionTest
, SpdyOnOffToggle
) {
4864 HttpStreamFactory::set_spdy_enabled(true);
4865 scoped_ptr
<SpdyFrame
> req(
4866 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
4867 MockWrite spdy_writes
[] = {CreateMockWrite(*req
, 0)};
4869 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
4870 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
4871 MockRead spdy_reads
[] = {
4872 CreateMockRead(*resp
, 1),
4873 CreateMockRead(*body
, 2),
4874 MockRead(ASYNC
, 0, 3) // EOF
4877 SequencedSocketData
data(spdy_reads
, arraysize(spdy_reads
), spdy_writes
,
4878 arraysize(spdy_writes
));
4879 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
4880 BoundNetLog(), GetParam(), NULL
);
4881 helper
.RunToCompletion(&data
);
4882 TransactionHelperResult out
= helper
.output();
4883 EXPECT_EQ(OK
, out
.rv
);
4884 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
4885 EXPECT_EQ("hello!", out
.response_data
);
4887 HttpStreamFactory::set_spdy_enabled(false);
4888 MockWrite http_writes
[] = {
4889 MockWrite(SYNCHRONOUS
, 0,
4890 "GET / HTTP/1.1\r\n"
4891 "Host: www.example.org\r\n"
4892 "Connection: keep-alive\r\n\r\n"),
4895 MockRead http_reads
[] = {
4896 MockRead(SYNCHRONOUS
, 1, "HTTP/1.1 200 OK\r\n\r\n"),
4897 MockRead(SYNCHRONOUS
, 2, "hello from http"),
4898 MockRead(SYNCHRONOUS
, OK
, 3),
4900 SequencedSocketData
data2(http_reads
, arraysize(http_reads
), http_writes
,
4901 arraysize(http_writes
));
4902 NormalSpdyTransactionHelper
helper2(CreateGetRequest(), DEFAULT_PRIORITY
,
4903 BoundNetLog(), GetParam(), NULL
);
4904 helper2
.SetSpdyDisabled();
4905 helper2
.RunToCompletion(&data2
);
4906 TransactionHelperResult out2
= helper2
.output();
4907 EXPECT_EQ(OK
, out2
.rv
);
4908 EXPECT_EQ("HTTP/1.1 200 OK", out2
.status_line
);
4909 EXPECT_EQ("hello from http", out2
.response_data
);
4911 HttpStreamFactory::set_spdy_enabled(true);
4914 // Tests that Basic authentication works over SPDY
4915 TEST_P(SpdyNetworkTransactionTest
, SpdyBasicAuth
) {
4916 HttpStreamFactory::set_spdy_enabled(true);
4918 // The first request will be a bare GET, the second request will be a
4919 // GET with an Authorization header.
4920 scoped_ptr
<SpdyFrame
> req_get(
4921 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
4922 const char* const kExtraAuthorizationHeaders
[] = {
4923 "authorization", "Basic Zm9vOmJhcg=="
4925 scoped_ptr
<SpdyFrame
> req_get_authorization(
4926 spdy_util_
.ConstructSpdyGet(kExtraAuthorizationHeaders
,
4927 arraysize(kExtraAuthorizationHeaders
) / 2,
4928 false, 3, LOWEST
, true));
4929 MockWrite spdy_writes
[] = {
4930 CreateMockWrite(*req_get
, 0), CreateMockWrite(*req_get_authorization
, 3),
4933 // The first response is a 401 authentication challenge, and the second
4934 // response will be a 200 response since the second request includes a valid
4935 // Authorization header.
4936 const char* const kExtraAuthenticationHeaders
[] = {
4938 "Basic realm=\"MyRealm\""
4940 scoped_ptr
<SpdyFrame
> resp_authentication(
4941 spdy_util_
.ConstructSpdySynReplyError(
4942 "401 Authentication Required",
4943 kExtraAuthenticationHeaders
,
4944 arraysize(kExtraAuthenticationHeaders
) / 2,
4946 scoped_ptr
<SpdyFrame
> body_authentication(
4947 spdy_util_
.ConstructSpdyBodyFrame(1, true));
4948 scoped_ptr
<SpdyFrame
> resp_data(
4949 spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 3));
4950 scoped_ptr
<SpdyFrame
> body_data(spdy_util_
.ConstructSpdyBodyFrame(3, true));
4951 MockRead spdy_reads
[] = {
4952 CreateMockRead(*resp_authentication
, 1),
4953 CreateMockRead(*body_authentication
, 2),
4954 CreateMockRead(*resp_data
, 4),
4955 CreateMockRead(*body_data
, 5),
4956 MockRead(ASYNC
, 0, 6),
4959 SequencedSocketData
data(spdy_reads
, arraysize(spdy_reads
), spdy_writes
,
4960 arraysize(spdy_writes
));
4961 HttpRequestInfo
request(CreateGetRequest());
4962 BoundNetLog net_log
;
4963 NormalSpdyTransactionHelper
helper(request
, DEFAULT_PRIORITY
,
4964 net_log
, GetParam(), NULL
);
4966 helper
.RunPreTestSetup();
4967 helper
.AddData(&data
);
4968 HttpNetworkTransaction
* trans
= helper
.trans();
4969 TestCompletionCallback callback
;
4970 const int rv_start
= trans
->Start(&request
, callback
.callback(), net_log
);
4971 EXPECT_EQ(ERR_IO_PENDING
, rv_start
);
4972 const int rv_start_complete
= callback
.WaitForResult();
4973 EXPECT_EQ(OK
, rv_start_complete
);
4975 // Make sure the response has an auth challenge.
4976 const HttpResponseInfo
* const response_start
= trans
->GetResponseInfo();
4977 ASSERT_TRUE(response_start
!= NULL
);
4978 ASSERT_TRUE(response_start
->headers
.get() != NULL
);
4979 EXPECT_EQ(401, response_start
->headers
->response_code());
4980 EXPECT_TRUE(response_start
->was_fetched_via_spdy
);
4981 AuthChallengeInfo
* auth_challenge
= response_start
->auth_challenge
.get();
4982 ASSERT_TRUE(auth_challenge
!= NULL
);
4983 EXPECT_FALSE(auth_challenge
->is_proxy
);
4984 EXPECT_EQ("basic", auth_challenge
->scheme
);
4985 EXPECT_EQ("MyRealm", auth_challenge
->realm
);
4987 // Restart with a username/password.
4988 AuthCredentials
credentials(base::ASCIIToUTF16("foo"),
4989 base::ASCIIToUTF16("bar"));
4990 TestCompletionCallback callback_restart
;
4991 const int rv_restart
= trans
->RestartWithAuth(
4992 credentials
, callback_restart
.callback());
4993 EXPECT_EQ(ERR_IO_PENDING
, rv_restart
);
4994 const int rv_restart_complete
= callback_restart
.WaitForResult();
4995 EXPECT_EQ(OK
, rv_restart_complete
);
4996 // TODO(cbentzel): This is actually the same response object as before, but
4997 // data has changed.
4998 const HttpResponseInfo
* const response_restart
= trans
->GetResponseInfo();
4999 ASSERT_TRUE(response_restart
!= NULL
);
5000 ASSERT_TRUE(response_restart
->headers
.get() != NULL
);
5001 EXPECT_EQ(200, response_restart
->headers
->response_code());
5002 EXPECT_TRUE(response_restart
->auth_challenge
.get() == NULL
);
5005 TEST_P(SpdyNetworkTransactionTest
, ServerPushWithHeaders
) {
5006 scoped_ptr
<SpdyFrame
> stream1_syn(
5007 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
5008 scoped_ptr
<SpdyFrame
> stream1_body(
5009 spdy_util_
.ConstructSpdyBodyFrame(1, true));
5010 MockWrite writes
[] = {
5011 CreateMockWrite(*stream1_syn
, 0),
5014 scoped_ptr
<SpdyHeaderBlock
> initial_headers(new SpdyHeaderBlock());
5015 spdy_util_
.AddUrlToHeaderBlock(GetDefaultUrlWithPath("/foo.dat"),
5016 initial_headers
.get());
5017 scoped_ptr
<SpdyFrame
> stream2_syn(
5018 spdy_util_
.ConstructInitialSpdyPushFrame(initial_headers
.Pass(), 2, 1));
5020 scoped_ptr
<SpdyHeaderBlock
> late_headers(new SpdyHeaderBlock());
5021 (*late_headers
)["hello"] = "bye";
5022 (*late_headers
)[spdy_util_
.GetStatusKey()] = "200";
5023 (*late_headers
)[spdy_util_
.GetVersionKey()] = "HTTP/1.1";
5024 scoped_ptr
<SpdyFrame
> stream2_headers(
5025 spdy_util_
.ConstructSpdyControlFrame(late_headers
.Pass(),
5033 scoped_ptr
<SpdyFrame
>
5034 stream1_reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
5035 const char kPushedData
[] = "pushed";
5036 scoped_ptr
<SpdyFrame
> stream2_body(
5037 spdy_util_
.ConstructSpdyBodyFrame(
5038 2, kPushedData
, strlen(kPushedData
), true));
5039 MockRead reads
[] = {
5040 CreateMockRead(*stream1_reply
, 1),
5041 CreateMockRead(*stream2_syn
, 2),
5042 CreateMockRead(*stream2_headers
, 3),
5043 CreateMockRead(*stream1_body
, 4, SYNCHRONOUS
),
5044 CreateMockRead(*stream2_body
, 5),
5045 MockRead(SYNCHRONOUS
, ERR_IO_PENDING
, 6), // Force a pause
5048 HttpResponseInfo response
;
5049 HttpResponseInfo response2
;
5050 std::string
expected_push_result("pushed");
5051 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
5052 RunServerPushTest(&data
,
5055 expected_push_result
);
5057 // Verify the SYN_REPLY.
5058 EXPECT_TRUE(response
.headers
.get() != NULL
);
5059 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
5061 // Verify the pushed stream.
5062 EXPECT_TRUE(response2
.headers
.get() != NULL
);
5063 EXPECT_EQ("HTTP/1.1 200 OK", response2
.headers
->GetStatusLine());
5066 TEST_P(SpdyNetworkTransactionTest
, ServerPushClaimBeforeHeaders
) {
5067 // We push a stream and attempt to claim it before the headers come down.
5068 scoped_ptr
<SpdyFrame
> stream1_syn(
5069 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
5070 scoped_ptr
<SpdyFrame
> stream1_body(
5071 spdy_util_
.ConstructSpdyBodyFrame(1, true));
5072 MockWrite writes
[] = {
5073 CreateMockWrite(*stream1_syn
, 0, SYNCHRONOUS
),
5076 scoped_ptr
<SpdyHeaderBlock
> initial_headers(new SpdyHeaderBlock());
5077 spdy_util_
.AddUrlToHeaderBlock(GetDefaultUrlWithPath("/foo.dat"),
5078 initial_headers
.get());
5079 scoped_ptr
<SpdyFrame
> stream2_syn(
5080 spdy_util_
.ConstructInitialSpdyPushFrame(initial_headers
.Pass(), 2, 1));
5082 scoped_ptr
<SpdyHeaderBlock
> late_headers(new SpdyHeaderBlock());
5083 (*late_headers
)["hello"] = "bye";
5084 (*late_headers
)[spdy_util_
.GetStatusKey()] = "200";
5085 (*late_headers
)[spdy_util_
.GetVersionKey()] = "HTTP/1.1";
5086 scoped_ptr
<SpdyFrame
> stream2_headers(
5087 spdy_util_
.ConstructSpdyControlFrame(late_headers
.Pass(),
5095 scoped_ptr
<SpdyFrame
>
5096 stream1_reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
5097 const char kPushedData
[] = "pushed";
5098 scoped_ptr
<SpdyFrame
> stream2_body(
5099 spdy_util_
.ConstructSpdyBodyFrame(
5100 2, kPushedData
, strlen(kPushedData
), true));
5101 MockRead reads
[] = {
5102 CreateMockRead(*stream1_reply
, 1),
5103 CreateMockRead(*stream2_syn
, 2),
5104 CreateMockRead(*stream1_body
, 3),
5105 CreateMockRead(*stream2_headers
, 4),
5106 CreateMockRead(*stream2_body
, 5),
5107 MockRead(ASYNC
, 0, 6), // EOF
5110 HttpResponseInfo response
;
5111 HttpResponseInfo response2
;
5112 std::string
expected_push_result("pushed");
5113 DeterministicSocketData
data(reads
, arraysize(reads
),
5114 writes
, arraysize(writes
));
5116 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
5117 BoundNetLog(), GetParam(), NULL
);
5118 helper
.SetDeterministic();
5119 helper
.AddDeterministicData(&data
);
5120 helper
.RunPreTestSetup();
5122 HttpNetworkTransaction
* trans
= helper
.trans();
5124 // Run until we've received the primary SYN_STREAM, the pushed SYN_STREAM,
5125 // and the body of the primary stream, but before we've received the HEADERS
5126 // for the pushed stream.
5129 // Start the transaction.
5130 TestCompletionCallback callback
;
5131 int rv
= trans
->Start(
5132 &CreateGetRequest(), callback
.callback(), BoundNetLog());
5133 EXPECT_EQ(ERR_IO_PENDING
, rv
);
5135 rv
= callback
.WaitForResult();
5138 // Request the pushed path. At this point, we've received the push, but the
5139 // headers are not yet complete.
5140 scoped_ptr
<HttpNetworkTransaction
> trans2(
5141 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
5143 &CreateGetPushRequest(), callback
.callback(), BoundNetLog());
5144 EXPECT_EQ(ERR_IO_PENDING
, rv
);
5146 base::RunLoop().RunUntilIdle();
5148 // Read the server push body.
5149 std::string result2
;
5150 ReadResult(trans2
.get(), &result2
);
5151 // Read the response body.
5153 ReadResult(trans
, &result
);
5155 // Verify that the received push data is same as the expected push data.
5156 EXPECT_EQ(result2
.compare(expected_push_result
), 0)
5157 << "Received data: "
5159 << "||||| Expected data: "
5160 << expected_push_result
;
5162 // Verify the SYN_REPLY.
5163 // Copy the response info, because trans goes away.
5164 response
= *trans
->GetResponseInfo();
5165 response2
= *trans2
->GetResponseInfo();
5167 VerifyStreamsClosed(helper
);
5169 // Verify the SYN_REPLY.
5170 EXPECT_TRUE(response
.headers
.get() != NULL
);
5171 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
5173 // Verify the pushed stream.
5174 EXPECT_TRUE(response2
.headers
.get() != NULL
);
5175 EXPECT_EQ("HTTP/1.1 200 OK", response2
.headers
->GetStatusLine());
5177 // Read the final EOF (which will close the session)
5180 // Verify that we consumed all test data.
5181 EXPECT_TRUE(data
.AllReadDataConsumed());
5182 EXPECT_TRUE(data
.AllWriteDataConsumed());
5185 // TODO(baranovich): HTTP 2 does not allow multiple HEADERS frames
5186 TEST_P(SpdyNetworkTransactionTest
, ServerPushWithTwoHeaderFrames
) {
5187 // We push a stream and attempt to claim it before the headers come down.
5188 scoped_ptr
<SpdyFrame
> stream1_syn(
5189 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
5190 scoped_ptr
<SpdyFrame
> stream1_body(
5191 spdy_util_
.ConstructSpdyBodyFrame(1, true));
5192 MockWrite writes
[] = {
5193 CreateMockWrite(*stream1_syn
, 0, SYNCHRONOUS
),
5196 scoped_ptr
<SpdyHeaderBlock
> initial_headers(new SpdyHeaderBlock());
5197 if (spdy_util_
.spdy_version() < HTTP2
) {
5198 // In HTTP/2 PUSH_PROMISE headers won't show up in the response headers.
5199 (*initial_headers
)["alpha"] = "beta";
5201 spdy_util_
.AddUrlToHeaderBlock(GetDefaultUrlWithPath("/foo.dat"),
5202 initial_headers
.get());
5203 scoped_ptr
<SpdyFrame
> stream2_syn(
5204 spdy_util_
.ConstructInitialSpdyPushFrame(initial_headers
.Pass(), 2, 1));
5206 scoped_ptr
<SpdyHeaderBlock
> middle_headers(new SpdyHeaderBlock());
5207 (*middle_headers
)["hello"] = "bye";
5208 scoped_ptr
<SpdyFrame
> stream2_headers1(
5209 spdy_util_
.ConstructSpdyControlFrame(middle_headers
.Pass(),
5217 scoped_ptr
<SpdyHeaderBlock
> late_headers(new SpdyHeaderBlock());
5218 (*late_headers
)[spdy_util_
.GetStatusKey()] = "200";
5219 if (spdy_util_
.spdy_version() < HTTP2
) {
5220 // HTTP/2 eliminates use of the :version header.
5221 (*late_headers
)[spdy_util_
.GetVersionKey()] = "HTTP/1.1";
5223 scoped_ptr
<SpdyFrame
> stream2_headers2(
5224 spdy_util_
.ConstructSpdyControlFrame(late_headers
.Pass(),
5232 scoped_ptr
<SpdyFrame
>
5233 stream1_reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
5234 const char kPushedData
[] = "pushed";
5235 scoped_ptr
<SpdyFrame
> stream2_body(
5236 spdy_util_
.ConstructSpdyBodyFrame(
5237 2, kPushedData
, strlen(kPushedData
), true));
5238 MockRead reads
[] = {
5239 CreateMockRead(*stream1_reply
, 1),
5240 CreateMockRead(*stream2_syn
, 2),
5241 CreateMockRead(*stream1_body
, 3),
5242 CreateMockRead(*stream2_headers1
, 4),
5243 CreateMockRead(*stream2_headers2
, 5),
5244 CreateMockRead(*stream2_body
, 6),
5245 MockRead(ASYNC
, 0, 7), // EOF
5248 HttpResponseInfo response
;
5249 HttpResponseInfo response2
;
5250 std::string
expected_push_result("pushed");
5251 DeterministicSocketData
data(reads
, arraysize(reads
),
5252 writes
, arraysize(writes
));
5254 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
5255 BoundNetLog(), GetParam(), NULL
);
5256 helper
.SetDeterministic();
5257 helper
.AddDeterministicData(&data
);
5258 helper
.RunPreTestSetup();
5260 HttpNetworkTransaction
* trans
= helper
.trans();
5262 // Run until we've received the primary SYN_STREAM, the pushed SYN_STREAM,
5263 // the first HEADERS frame, and the body of the primary stream, but before
5264 // we've received the final HEADERS for the pushed stream.
5267 // Start the transaction.
5268 TestCompletionCallback callback
;
5269 int rv
= trans
->Start(
5270 &CreateGetRequest(), callback
.callback(), BoundNetLog());
5271 EXPECT_EQ(ERR_IO_PENDING
, rv
);
5273 rv
= callback
.WaitForResult();
5276 // Request the pushed path. At this point, we've received the push, but the
5277 // headers are not yet complete.
5278 scoped_ptr
<HttpNetworkTransaction
> trans2(
5279 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
5281 &CreateGetPushRequest(), callback
.callback(), BoundNetLog());
5282 EXPECT_EQ(ERR_IO_PENDING
, rv
);
5284 base::RunLoop().RunUntilIdle();
5286 // Read the server push body.
5287 std::string result2
;
5288 ReadResult(trans2
.get(), &result2
);
5289 // Read the response body.
5291 ReadResult(trans
, &result
);
5293 // Verify that the received push data is same as the expected push data.
5294 EXPECT_EQ(expected_push_result
, result2
);
5296 // Verify the SYN_REPLY.
5297 // Copy the response info, because trans goes away.
5298 response
= *trans
->GetResponseInfo();
5299 response2
= *trans2
->GetResponseInfo();
5301 VerifyStreamsClosed(helper
);
5303 // Verify the SYN_REPLY.
5304 EXPECT_TRUE(response
.headers
.get() != NULL
);
5305 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
5307 // Verify the pushed stream.
5308 EXPECT_TRUE(response2
.headers
.get() != NULL
);
5309 EXPECT_EQ("HTTP/1.1 200 OK", response2
.headers
->GetStatusLine());
5311 // Verify we got all the headers from all header blocks.
5312 if (spdy_util_
.spdy_version() < HTTP2
)
5313 EXPECT_TRUE(response2
.headers
->HasHeaderValue("alpha", "beta"));
5314 EXPECT_TRUE(response2
.headers
->HasHeaderValue("hello", "bye"));
5315 EXPECT_TRUE(response2
.headers
->HasHeaderValue("status", "200"));
5317 // Read the final EOF (which will close the session)
5320 // Verify that we consumed all test data.
5321 EXPECT_TRUE(data
.AllReadDataConsumed());
5322 EXPECT_TRUE(data
.AllWriteDataConsumed());
5325 TEST_P(SpdyNetworkTransactionTest
, ServerPushWithNoStatusHeaderFrames
) {
5326 // We push a stream and attempt to claim it before the headers come down.
5327 scoped_ptr
<SpdyFrame
> stream1_syn(
5328 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
5329 scoped_ptr
<SpdyFrame
> stream1_body(
5330 spdy_util_
.ConstructSpdyBodyFrame(1, true));
5331 MockWrite writes
[] = {
5332 CreateMockWrite(*stream1_syn
, 0, SYNCHRONOUS
),
5335 scoped_ptr
<SpdyHeaderBlock
> initial_headers(new SpdyHeaderBlock());
5336 spdy_util_
.AddUrlToHeaderBlock(GetDefaultUrlWithPath("/foo.dat"),
5337 initial_headers
.get());
5338 scoped_ptr
<SpdyFrame
> stream2_syn(
5339 spdy_util_
.ConstructInitialSpdyPushFrame(initial_headers
.Pass(), 2, 1));
5341 scoped_ptr
<SpdyHeaderBlock
> middle_headers(new SpdyHeaderBlock());
5342 (*middle_headers
)["hello"] = "bye";
5343 scoped_ptr
<SpdyFrame
> stream2_headers1(
5344 spdy_util_
.ConstructSpdyControlFrame(middle_headers
.Pass(),
5352 scoped_ptr
<SpdyFrame
>
5353 stream1_reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
5354 const char kPushedData
[] = "pushed";
5355 scoped_ptr
<SpdyFrame
> stream2_body(
5356 spdy_util_
.ConstructSpdyBodyFrame(
5357 2, kPushedData
, strlen(kPushedData
), true));
5358 MockRead reads
[] = {
5359 CreateMockRead(*stream1_reply
, 1),
5360 CreateMockRead(*stream2_syn
, 2),
5361 CreateMockRead(*stream1_body
, 3),
5362 CreateMockRead(*stream2_headers1
, 4),
5363 CreateMockRead(*stream2_body
, 5),
5364 MockRead(ASYNC
, 0, 6), // EOF
5367 DeterministicSocketData
data(reads
, arraysize(reads
),
5368 writes
, arraysize(writes
));
5370 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
5371 BoundNetLog(), GetParam(), NULL
);
5372 helper
.SetDeterministic();
5373 helper
.AddDeterministicData(&data
);
5374 helper
.RunPreTestSetup();
5376 HttpNetworkTransaction
* trans
= helper
.trans();
5378 // Run until we've received the primary SYN_STREAM, the pushed SYN_STREAM,
5379 // the first HEADERS frame, and the body of the primary stream, but before
5380 // we've received the final HEADERS for the pushed stream.
5383 // Start the transaction.
5384 TestCompletionCallback callback
;
5385 int rv
= trans
->Start(
5386 &CreateGetRequest(), callback
.callback(), BoundNetLog());
5387 EXPECT_EQ(ERR_IO_PENDING
, rv
);
5389 rv
= callback
.WaitForResult();
5392 // Request the pushed path. At this point, we've received the push, but the
5393 // headers are not yet complete.
5394 scoped_ptr
<HttpNetworkTransaction
> trans2(
5395 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
5397 &CreateGetPushRequest(), callback
.callback(), BoundNetLog());
5398 EXPECT_EQ(ERR_IO_PENDING
, rv
);
5400 base::RunLoop().RunUntilIdle();
5402 // Read the server push body.
5403 std::string result2
;
5404 ReadResult(trans2
.get(), &result2
);
5405 // Read the response body.
5407 ReadResult(trans
, &result
);
5408 EXPECT_EQ("hello!", result
);
5410 // Verify that we haven't received any push data.
5411 EXPECT_EQ("", result2
);
5413 // Verify the SYN_REPLY.
5414 // Copy the response info, because trans goes away.
5415 HttpResponseInfo response
= *trans
->GetResponseInfo();
5417 VerifyStreamsClosed(helper
);
5419 // Verify the SYN_REPLY.
5420 EXPECT_TRUE(response
.headers
.get() != NULL
);
5421 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
5423 // Read the final EOF (which will close the session).
5426 // Verify that we consumed all test data.
5427 EXPECT_TRUE(data
.AllReadDataConsumed());
5428 EXPECT_TRUE(data
.AllWriteDataConsumed());
5431 TEST_P(SpdyNetworkTransactionTest
, SynReplyWithHeaders
) {
5432 scoped_ptr
<SpdyFrame
> req(
5433 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
5434 scoped_ptr
<SpdyFrame
> rst(
5435 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR
));
5436 MockWrite writes
[] = {
5437 CreateMockWrite(*req
, 0), CreateMockWrite(*rst
, 4),
5440 scoped_ptr
<SpdyFrame
> stream1_reply(
5441 spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
5443 scoped_ptr
<SpdyHeaderBlock
> late_headers(new SpdyHeaderBlock());
5444 (*late_headers
)["hello"] = "bye";
5445 scoped_ptr
<SpdyFrame
> stream1_headers(
5446 spdy_util_
.ConstructSpdyControlFrame(late_headers
.Pass(),
5453 scoped_ptr
<SpdyFrame
> stream1_body(
5454 spdy_util_
.ConstructSpdyBodyFrame(1, true));
5455 MockRead reads
[] = {
5456 CreateMockRead(*stream1_reply
, 1),
5457 CreateMockRead(*stream1_headers
, 2),
5458 CreateMockRead(*stream1_body
, 3),
5459 MockRead(ASYNC
, 0, 5) // EOF
5462 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
5463 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
5464 BoundNetLog(), GetParam(), NULL
);
5465 helper
.RunToCompletion(&data
);
5466 TransactionHelperResult out
= helper
.output();
5467 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR
, out
.rv
);
5470 TEST_P(SpdyNetworkTransactionTest
, SynReplyWithLateHeaders
) {
5471 scoped_ptr
<SpdyFrame
> req(
5472 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
5473 scoped_ptr
<SpdyFrame
> rst(
5474 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR
));
5475 MockWrite writes
[] = {
5476 CreateMockWrite(*req
, 0), CreateMockWrite(*rst
, 4),
5479 scoped_ptr
<SpdyFrame
> stream1_reply(
5480 spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
5482 scoped_ptr
<SpdyHeaderBlock
> late_headers(new SpdyHeaderBlock());
5483 (*late_headers
)["hello"] = "bye";
5484 scoped_ptr
<SpdyFrame
> stream1_headers(
5485 spdy_util_
.ConstructSpdyControlFrame(late_headers
.Pass(),
5492 scoped_ptr
<SpdyFrame
> stream1_body(
5493 spdy_util_
.ConstructSpdyBodyFrame(1, false));
5494 scoped_ptr
<SpdyFrame
> stream1_body2(
5495 spdy_util_
.ConstructSpdyBodyFrame(1, true));
5496 MockRead reads
[] = {
5497 CreateMockRead(*stream1_reply
, 1),
5498 CreateMockRead(*stream1_body
, 2),
5499 CreateMockRead(*stream1_headers
, 3),
5500 CreateMockRead(*stream1_body2
, 5),
5501 MockRead(ASYNC
, 0, 6) // EOF
5504 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
5505 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
5506 BoundNetLog(), GetParam(), NULL
);
5507 helper
.RunToCompletion(&data
);
5508 TransactionHelperResult out
= helper
.output();
5509 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR
, out
.rv
);
5512 TEST_P(SpdyNetworkTransactionTest
, ServerPushCrossOriginCorrectness
) {
5513 // Running these tests via Alt-Svc is too complicated to be worthwhile.
5514 if (GetParam().ssl_type
!= HTTPS_SPDY_VIA_NPN
)
5517 // In this test we want to verify that we can't accidentally push content
5518 // which can't be pushed by this content server.
5519 // This test assumes that:
5520 // - if we're requesting http://www.foo.com/barbaz
5521 // - the browser has made a connection to "www.foo.com".
5523 // A list of the URL to fetch, followed by the URL being pushed.
5524 static const char* const kTestCases
[] = {
5525 "https://www.example.org/foo.html",
5526 "https://www.example.org:81/foo.js", // Bad port
5528 "https://www.example.org/foo.html",
5529 "http://www.example.org/foo.js", // Bad protocol
5531 "https://www.example.org/foo.html",
5532 "ftp://www.example.org/foo.js", // Invalid Protocol
5534 "https://www.example.org/foo.html",
5535 "https://blat.www.example.org/foo.js", // Cross subdomain
5537 "https://www.example.org/foo.html",
5538 "https://www.foo.com/foo.js", // Cross domain
5541 for (size_t index
= 0; index
< arraysize(kTestCases
); index
+= 2) {
5542 const char* url_to_fetch
= kTestCases
[index
];
5543 const char* url_to_push
= kTestCases
[index
+ 1];
5545 scoped_ptr
<SpdyFrame
> stream1_syn(
5546 spdy_util_
.ConstructSpdyGet(url_to_fetch
, false, 1, LOWEST
));
5547 scoped_ptr
<SpdyFrame
> stream1_body(
5548 spdy_util_
.ConstructSpdyBodyFrame(1, true));
5549 scoped_ptr
<SpdyFrame
> push_rst(
5550 spdy_util_
.ConstructSpdyRstStream(2, RST_STREAM_REFUSED_STREAM
));
5551 MockWrite writes
[] = {
5552 CreateMockWrite(*stream1_syn
, 0), CreateMockWrite(*push_rst
, 3),
5555 scoped_ptr
<SpdyFrame
>
5556 stream1_reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
5557 scoped_ptr
<SpdyFrame
>
5558 stream2_syn(spdy_util_
.ConstructSpdyPush(NULL
,
5563 const char kPushedData
[] = "pushed";
5564 scoped_ptr
<SpdyFrame
> stream2_body(
5565 spdy_util_
.ConstructSpdyBodyFrame(
5566 2, kPushedData
, strlen(kPushedData
), true));
5567 scoped_ptr
<SpdyFrame
> rst(
5568 spdy_util_
.ConstructSpdyRstStream(2, RST_STREAM_CANCEL
));
5570 MockRead reads
[] = {
5571 CreateMockRead(*stream1_reply
, 1),
5572 CreateMockRead(*stream2_syn
, 2),
5573 CreateMockRead(*stream1_body
, 4),
5574 CreateMockRead(*stream2_body
, 5),
5575 MockRead(SYNCHRONOUS
, ERR_IO_PENDING
, 6), // Force a pause
5578 HttpResponseInfo response
;
5579 SequencedSocketData
data(reads
, arraysize(reads
), writes
,
5582 HttpRequestInfo request
;
5583 request
.method
= "GET";
5584 request
.url
= GURL(url_to_fetch
);
5585 request
.load_flags
= 0;
5587 // Enable cross-origin push. Since we are not using a proxy, this should
5588 // not actually enable cross-origin SPDY push.
5589 scoped_ptr
<SpdySessionDependencies
> session_deps(
5590 CreateSpdySessionDependencies(GetParam()));
5591 session_deps
->trusted_spdy_proxy
= "123.45.67.89:8080";
5592 NormalSpdyTransactionHelper
helper(request
, DEFAULT_PRIORITY
,
5593 BoundNetLog(), GetParam(),
5594 session_deps
.release());
5595 helper
.RunPreTestSetup();
5596 helper
.AddData(&data
);
5598 HttpNetworkTransaction
* trans
= helper
.trans();
5600 // Start the transaction with basic parameters.
5601 TestCompletionCallback callback
;
5603 int rv
= trans
->Start(&request
, callback
.callback(), BoundNetLog());
5604 EXPECT_EQ(ERR_IO_PENDING
, rv
);
5605 rv
= callback
.WaitForResult();
5607 // Read the response body.
5609 ReadResult(trans
, &result
);
5611 // Verify that we consumed all test data.
5612 EXPECT_TRUE(data
.AllReadDataConsumed());
5613 EXPECT_TRUE(data
.AllWriteDataConsumed());
5615 // Verify the SYN_REPLY.
5616 // Copy the response info, because trans goes away.
5617 response
= *trans
->GetResponseInfo();
5619 VerifyStreamsClosed(helper
);
5621 // Verify the SYN_REPLY.
5622 EXPECT_TRUE(response
.headers
.get() != NULL
);
5623 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
5627 TEST_P(SpdyNetworkTransactionTest
, RetryAfterRefused
) {
5628 // Construct the request.
5629 scoped_ptr
<SpdyFrame
> req(
5630 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
5631 scoped_ptr
<SpdyFrame
> req2(
5632 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 3, LOWEST
, true));
5633 MockWrite writes
[] = {
5634 CreateMockWrite(*req
, 0), CreateMockWrite(*req2
, 2),
5637 scoped_ptr
<SpdyFrame
> refused(
5638 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_REFUSED_STREAM
));
5639 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 3));
5640 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(3, true));
5641 MockRead reads
[] = {
5642 CreateMockRead(*refused
, 1),
5643 CreateMockRead(*resp
, 3),
5644 CreateMockRead(*body
, 4),
5645 MockRead(ASYNC
, 0, 5) // EOF
5648 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
5649 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
5650 BoundNetLog(), GetParam(), NULL
);
5652 helper
.RunPreTestSetup();
5653 helper
.AddData(&data
);
5655 HttpNetworkTransaction
* trans
= helper
.trans();
5657 // Start the transaction with basic parameters.
5658 TestCompletionCallback callback
;
5659 int rv
= trans
->Start(
5660 &CreateGetRequest(), callback
.callback(), BoundNetLog());
5661 EXPECT_EQ(ERR_IO_PENDING
, rv
);
5662 rv
= callback
.WaitForResult();
5665 // Verify that we consumed all test data.
5666 EXPECT_TRUE(data
.AllReadDataConsumed());
5667 EXPECT_TRUE(data
.AllWriteDataConsumed());
5669 // Verify the SYN_REPLY.
5670 HttpResponseInfo response
= *trans
->GetResponseInfo();
5671 EXPECT_TRUE(response
.headers
.get() != NULL
);
5672 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
5675 TEST_P(SpdyNetworkTransactionTest
, OutOfOrderSynStream
) {
5676 // This first request will start to establish the SpdySession.
5677 // Then we will start the second (MEDIUM priority) and then third
5678 // (HIGHEST priority) request in such a way that the third will actually
5679 // start before the second, causing the second to be numbered differently
5680 // than the order they were created.
5681 scoped_ptr
<SpdyFrame
> req1(
5682 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
5683 scoped_ptr
<SpdyFrame
> req2(
5684 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 3, HIGHEST
, true));
5685 scoped_ptr
<SpdyFrame
> req3(
5686 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 5, MEDIUM
, true));
5687 MockWrite writes
[] = {
5688 CreateMockWrite(*req1
, 0),
5689 CreateMockWrite(*req2
, 3),
5690 CreateMockWrite(*req3
, 4),
5693 scoped_ptr
<SpdyFrame
> resp1(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
5694 scoped_ptr
<SpdyFrame
> body1(spdy_util_
.ConstructSpdyBodyFrame(1, true));
5695 scoped_ptr
<SpdyFrame
> resp2(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 3));
5696 scoped_ptr
<SpdyFrame
> body2(spdy_util_
.ConstructSpdyBodyFrame(3, true));
5697 scoped_ptr
<SpdyFrame
> resp3(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 5));
5698 scoped_ptr
<SpdyFrame
> body3(spdy_util_
.ConstructSpdyBodyFrame(5, true));
5699 MockRead reads
[] = {
5700 CreateMockRead(*resp1
, 1),
5701 CreateMockRead(*body1
, 2),
5702 CreateMockRead(*resp2
, 5),
5703 CreateMockRead(*body2
, 6),
5704 CreateMockRead(*resp3
, 7),
5705 CreateMockRead(*body3
, 8),
5706 MockRead(ASYNC
, 0, 9) // EOF
5709 DeterministicSocketData
data(reads
, arraysize(reads
),
5710 writes
, arraysize(writes
));
5711 NormalSpdyTransactionHelper
helper(CreateGetRequest(), LOWEST
,
5712 BoundNetLog(), GetParam(), NULL
);
5713 helper
.SetDeterministic();
5714 helper
.RunPreTestSetup();
5715 helper
.AddDeterministicData(&data
);
5717 // Start the first transaction to set up the SpdySession
5718 HttpNetworkTransaction
* trans
= helper
.trans();
5719 TestCompletionCallback callback
;
5720 HttpRequestInfo info1
= CreateGetRequest();
5721 int rv
= trans
->Start(&info1
, callback
.callback(), BoundNetLog());
5722 EXPECT_EQ(ERR_IO_PENDING
, rv
);
5724 // Run the message loop, but do not allow the write to complete.
5725 // This leaves the SpdySession with a write pending, which prevents
5726 // SpdySession from attempting subsequent writes until this write completes.
5727 base::RunLoop().RunUntilIdle();
5729 // Now, start both new transactions
5730 HttpRequestInfo info2
= CreateGetRequest();
5731 TestCompletionCallback callback2
;
5732 scoped_ptr
<HttpNetworkTransaction
> trans2(
5733 new HttpNetworkTransaction(MEDIUM
, helper
.session().get()));
5734 rv
= trans2
->Start(&info2
, callback2
.callback(), BoundNetLog());
5735 EXPECT_EQ(ERR_IO_PENDING
, rv
);
5736 base::RunLoop().RunUntilIdle();
5738 HttpRequestInfo info3
= CreateGetRequest();
5739 TestCompletionCallback callback3
;
5740 scoped_ptr
<HttpNetworkTransaction
> trans3(
5741 new HttpNetworkTransaction(HIGHEST
, helper
.session().get()));
5742 rv
= trans3
->Start(&info3
, callback3
.callback(), BoundNetLog());
5743 EXPECT_EQ(ERR_IO_PENDING
, rv
);
5744 base::RunLoop().RunUntilIdle();
5746 // We now have two SYN_STREAM frames queued up which will be
5747 // dequeued only once the first write completes, which we
5748 // now allow to happen.
5750 EXPECT_EQ(OK
, callback
.WaitForResult());
5752 // And now we can allow everything else to run to completion.
5755 EXPECT_EQ(OK
, callback2
.WaitForResult());
5756 EXPECT_EQ(OK
, callback3
.WaitForResult());
5758 helper
.VerifyDataConsumed();
5761 // The tests below are only for SPDY/3 and above.
5763 // Test that sent data frames and received WINDOW_UPDATE frames change
5764 // the send_window_size_ correctly.
5766 // WINDOW_UPDATE is different than most other frames in that it can arrive
5767 // while the client is still sending the request body. In order to enforce
5768 // this scenario, we feed a couple of dummy frames and give a delay of 0 to
5769 // socket data provider, so that initial read that is done as soon as the
5770 // stream is created, succeeds and schedules another read. This way reads
5771 // and writes are interleaved; after doing a full frame write, SpdyStream
5772 // will break out of DoLoop and will read and process a WINDOW_UPDATE.
5773 // Once our WINDOW_UPDATE is read, we cannot send SYN_REPLY right away
5774 // since request has not been completely written, therefore we feed
5775 // enough number of WINDOW_UPDATEs to finish the first read and cause a
5776 // write, leading to a complete write of request body; after that we send
5777 // a reply with a body, to cause a graceful shutdown.
5779 // TODO(agayev): develop a socket data provider where both, reads and
5780 // writes are ordered so that writing tests like these are easy and rewrite
5781 // all these tests using it. Right now we are working around the
5782 // limitations as described above and it's not deterministic, tests may
5783 // fail under specific circumstances.
5784 TEST_P(SpdyNetworkTransactionTest
, WindowUpdateReceived
) {
5785 static int kFrameCount
= 2;
5786 scoped_ptr
<std::string
> content(
5787 new std::string(kMaxSpdyFrameChunkSize
, 'a'));
5788 scoped_ptr
<SpdyFrame
> req(spdy_util_
.ConstructSpdyPost(
5789 GetDefaultUrl(), 1, kMaxSpdyFrameChunkSize
* kFrameCount
, LOWEST
, NULL
,
5791 scoped_ptr
<SpdyFrame
> body(
5792 spdy_util_
.ConstructSpdyBodyFrame(
5793 1, content
->c_str(), content
->size(), false));
5794 scoped_ptr
<SpdyFrame
> body_end(
5795 spdy_util_
.ConstructSpdyBodyFrame(
5796 1, content
->c_str(), content
->size(), true));
5798 MockWrite writes
[] = {
5799 CreateMockWrite(*req
, 0),
5800 CreateMockWrite(*body
, 1),
5801 CreateMockWrite(*body_end
, 2),
5804 static const int32 kDeltaWindowSize
= 0xff;
5805 static const int kDeltaCount
= 4;
5806 scoped_ptr
<SpdyFrame
> window_update(
5807 spdy_util_
.ConstructSpdyWindowUpdate(1, kDeltaWindowSize
));
5808 scoped_ptr
<SpdyFrame
> window_update_dummy(
5809 spdy_util_
.ConstructSpdyWindowUpdate(2, kDeltaWindowSize
));
5810 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyPostSynReply(NULL
, 0));
5811 MockRead reads
[] = {
5812 CreateMockRead(*window_update_dummy
, 3),
5813 CreateMockRead(*window_update_dummy
, 4),
5814 CreateMockRead(*window_update_dummy
, 5),
5815 CreateMockRead(*window_update
, 6), // Four updates, therefore window
5816 CreateMockRead(*window_update
, 7), // size should increase by
5817 CreateMockRead(*window_update
, 8), // kDeltaWindowSize * 4
5818 CreateMockRead(*window_update
, 9),
5819 CreateMockRead(*resp
, 10),
5820 CreateMockRead(*body_end
, 11),
5821 MockRead(ASYNC
, 0, 0, 12) // EOF
5824 DeterministicSocketData
data(reads
, arraysize(reads
),
5825 writes
, arraysize(writes
));
5827 ScopedVector
<UploadElementReader
> element_readers
;
5828 for (int i
= 0; i
< kFrameCount
; ++i
) {
5829 element_readers
.push_back(
5830 new UploadBytesElementReader(content
->c_str(), content
->size()));
5832 ElementsUploadDataStream
upload_data_stream(element_readers
.Pass(), 0);
5834 // Setup the request
5835 HttpRequestInfo request
;
5836 request
.method
= "POST";
5837 request
.url
= GURL(GetDefaultUrl());
5838 request
.upload_data_stream
= &upload_data_stream
;
5840 NormalSpdyTransactionHelper
helper(request
, DEFAULT_PRIORITY
,
5841 BoundNetLog(), GetParam(), NULL
);
5842 helper
.SetDeterministic();
5843 helper
.AddDeterministicData(&data
);
5844 helper
.RunPreTestSetup();
5846 HttpNetworkTransaction
* trans
= helper
.trans();
5848 TestCompletionCallback callback
;
5849 int rv
= trans
->Start(&helper
.request(), callback
.callback(), BoundNetLog());
5851 EXPECT_EQ(ERR_IO_PENDING
, rv
);
5855 SpdyHttpStream
* stream
= static_cast<SpdyHttpStream
*>(trans
->stream_
.get());
5856 ASSERT_TRUE(stream
!= NULL
);
5857 ASSERT_TRUE(stream
->stream() != NULL
);
5858 EXPECT_EQ(static_cast<int>(
5859 SpdySession::GetDefaultInitialWindowSize(GetParam().protocol
)) +
5860 kDeltaWindowSize
* kDeltaCount
-
5861 kMaxSpdyFrameChunkSize
* kFrameCount
,
5862 stream
->stream()->send_window_size());
5866 rv
= callback
.WaitForResult();
5869 helper
.VerifyDataConsumed();
5872 // Test that received data frames and sent WINDOW_UPDATE frames change
5873 // the recv_window_size_ correctly.
5874 TEST_P(SpdyNetworkTransactionTest
, WindowUpdateSent
) {
5875 const int32 default_initial_window_size
=
5876 SpdySession::GetDefaultInitialWindowSize(GetParam().protocol
);
5877 // Session level maximum window size that is more than twice the default
5878 // initial window size so that an initial window update is sent.
5879 const int32 session_max_recv_window_size
= 5 * 64 * 1024;
5880 ASSERT_LT(2 * default_initial_window_size
, session_max_recv_window_size
);
5881 // Stream level maximum window size that is less than the session level
5882 // maximum window size so that we test for confusion between the two.
5883 const int32 stream_max_recv_window_size
= 4 * 64 * 1024;
5884 ASSERT_GT(session_max_recv_window_size
, stream_max_recv_window_size
);
5885 // Size of body to be sent. Has to be less than or equal to both window sizes
5886 // so that we do not run out of receiving window. Also has to be greater than
5887 // half of them so that it triggers both a session level and a stream level
5888 // window update frame.
5889 const int32 kTargetSize
= 3 * 64 * 1024;
5890 ASSERT_GE(session_max_recv_window_size
, kTargetSize
);
5891 ASSERT_GE(stream_max_recv_window_size
, kTargetSize
);
5892 ASSERT_LT(session_max_recv_window_size
/ 2, kTargetSize
);
5893 ASSERT_LT(stream_max_recv_window_size
/ 2, kTargetSize
);
5894 // Size of each DATA frame.
5895 const int32 kChunkSize
= 4096;
5896 // Size of window updates.
5897 ASSERT_EQ(0, session_max_recv_window_size
/ 2 % kChunkSize
);
5898 const int32 session_window_update_delta
=
5899 session_max_recv_window_size
/ 2 + kChunkSize
;
5900 ASSERT_EQ(0, stream_max_recv_window_size
/ 2 % kChunkSize
);
5901 const int32 stream_window_update_delta
=
5902 stream_max_recv_window_size
/ 2 + kChunkSize
;
5904 SettingsMap initial_settings
;
5905 initial_settings
[SETTINGS_MAX_CONCURRENT_STREAMS
] =
5906 SettingsFlagsAndValue(SETTINGS_FLAG_NONE
, kMaxConcurrentPushedStreams
);
5907 initial_settings
[SETTINGS_INITIAL_WINDOW_SIZE
] =
5908 SettingsFlagsAndValue(SETTINGS_FLAG_NONE
, stream_max_recv_window_size
);
5909 scoped_ptr
<SpdyFrame
> initial_settings_frame(
5910 spdy_util_
.ConstructSpdySettings(initial_settings
));
5911 scoped_ptr
<SpdyFrame
> initial_window_update(
5912 spdy_util_
.ConstructSpdyWindowUpdate(
5913 kSessionFlowControlStreamId
,
5914 session_max_recv_window_size
- default_initial_window_size
));
5915 scoped_ptr
<SpdyFrame
> req(
5916 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
5917 scoped_ptr
<SpdyFrame
> session_window_update(
5918 spdy_util_
.ConstructSpdyWindowUpdate(0, session_window_update_delta
));
5919 scoped_ptr
<SpdyFrame
> stream_window_update(
5920 spdy_util_
.ConstructSpdyWindowUpdate(1, stream_window_update_delta
));
5922 std::vector
<MockWrite
> writes
;
5923 if ((GetParam().protocol
>= kProtoHTTP2MinimumVersion
) &&
5924 (GetParam().protocol
<= kProtoHTTP2MaximumVersion
)) {
5925 writes
.push_back(MockWrite(ASYNC
, kHttp2ConnectionHeaderPrefix
,
5926 kHttp2ConnectionHeaderPrefixSize
, 0));
5928 writes
.push_back(CreateMockWrite(*initial_settings_frame
, writes
.size()));
5929 writes
.push_back(CreateMockWrite(*initial_window_update
, writes
.size()));
5930 writes
.push_back(CreateMockWrite(*req
, writes
.size()));
5932 std::vector
<MockRead
> reads
;
5933 scoped_ptr
<SpdyFrame
> resp(
5934 spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
5935 reads
.push_back(CreateMockRead(*resp
, writes
.size() + reads
.size()));
5937 ScopedVector
<SpdyFrame
> body_frames
;
5938 const std::string
body_data(kChunkSize
, 'x');
5939 for (size_t remaining
= kTargetSize
; remaining
!= 0;) {
5940 size_t frame_size
= std::min(remaining
, body_data
.size());
5941 body_frames
.push_back(spdy_util_
.ConstructSpdyBodyFrame(
5942 1, body_data
.data(), frame_size
, false));
5944 CreateMockRead(*body_frames
.back(), writes
.size() + reads
.size()));
5945 remaining
-= frame_size
;
5948 MockRead(ASYNC
, ERR_IO_PENDING
, writes
.size() + reads
.size())); // Yield.
5951 CreateMockWrite(*session_window_update
, writes
.size() + reads
.size()));
5953 CreateMockWrite(*stream_window_update
, writes
.size() + reads
.size()));
5955 SequencedSocketData
data(vector_as_array(&reads
), reads
.size(),
5956 vector_as_array(&writes
), writes
.size());
5958 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
5959 BoundNetLog(), GetParam(), NULL
);
5960 helper
.AddData(&data
);
5961 helper
.RunPreTestSetup();
5963 SpdySessionPool
* spdy_session_pool
= helper
.session()->spdy_session_pool();
5964 SpdySessionPoolPeer
pool_peer(spdy_session_pool
);
5965 pool_peer
.SetEnableSendingInitialData(true);
5966 pool_peer
.SetSessionMaxRecvWindowSize(session_max_recv_window_size
);
5967 pool_peer
.SetStreamInitialRecvWindowSize(stream_max_recv_window_size
);
5969 HttpNetworkTransaction
* trans
= helper
.trans();
5970 TestCompletionCallback callback
;
5971 int rv
= trans
->Start(&helper
.request(), callback
.callback(), BoundNetLog());
5973 EXPECT_EQ(ERR_IO_PENDING
, rv
);
5974 rv
= callback
.WaitForResult();
5977 SpdyHttpStream
* stream
=
5978 static_cast<SpdyHttpStream
*>(trans
->stream_
.get());
5979 ASSERT_TRUE(stream
!= NULL
);
5980 ASSERT_TRUE(stream
->stream() != NULL
);
5982 // All data has been read, but not consumed. The window reflects this.
5983 EXPECT_EQ(static_cast<int>(stream_max_recv_window_size
- kTargetSize
),
5984 stream
->stream()->recv_window_size());
5986 const HttpResponseInfo
* response
= trans
->GetResponseInfo();
5987 ASSERT_TRUE(response
!= NULL
);
5988 ASSERT_TRUE(response
->headers
.get() != NULL
);
5989 EXPECT_EQ("HTTP/1.1 200 OK", response
->headers
->GetStatusLine());
5990 EXPECT_TRUE(response
->was_fetched_via_spdy
);
5992 // Issue a read which will cause a WINDOW_UPDATE to be sent and window
5993 // size increased to default.
5994 scoped_refptr
<IOBuffer
> buf(new IOBuffer(kTargetSize
));
5995 EXPECT_EQ(static_cast<int>(kTargetSize
),
5996 trans
->Read(buf
.get(), kTargetSize
, CompletionCallback()));
5997 EXPECT_EQ(static_cast<int>(stream_max_recv_window_size
),
5998 stream
->stream()->recv_window_size());
5999 EXPECT_THAT(base::StringPiece(buf
->data(), kTargetSize
), Each(Eq('x')));
6001 // Allow scheduled WINDOW_UPDATE frames to write.
6002 base::RunLoop().RunUntilIdle();
6003 helper
.VerifyDataConsumed();
6006 // Test that WINDOW_UPDATE frame causing overflow is handled correctly.
6007 TEST_P(SpdyNetworkTransactionTest
, WindowUpdateOverflow
) {
6008 // Number of full frames we hope to write (but will not, used to
6009 // set content-length header correctly)
6010 static int kFrameCount
= 3;
6012 scoped_ptr
<std::string
> content(
6013 new std::string(kMaxSpdyFrameChunkSize
, 'a'));
6014 scoped_ptr
<SpdyFrame
> req(spdy_util_
.ConstructSpdyPost(
6015 GetDefaultUrl(), 1, kMaxSpdyFrameChunkSize
* kFrameCount
, LOWEST
, NULL
,
6017 scoped_ptr
<SpdyFrame
> body(
6018 spdy_util_
.ConstructSpdyBodyFrame(
6019 1, content
->c_str(), content
->size(), false));
6020 scoped_ptr
<SpdyFrame
> rst(
6021 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_FLOW_CONTROL_ERROR
));
6023 // We're not going to write a data frame with FIN, we'll receive a bad
6024 // WINDOW_UPDATE while sending a request and will send a RST_STREAM frame.
6025 MockWrite writes
[] = {
6026 CreateMockWrite(*req
, 0),
6027 CreateMockWrite(*body
, 2),
6028 CreateMockWrite(*rst
, 3),
6031 static const int32 kDeltaWindowSize
= 0x7fffffff; // cause an overflow
6032 scoped_ptr
<SpdyFrame
> window_update(
6033 spdy_util_
.ConstructSpdyWindowUpdate(1, kDeltaWindowSize
));
6034 MockRead reads
[] = {
6035 CreateMockRead(*window_update
, 1),
6036 MockRead(ASYNC
, 0, 4) // EOF
6039 DeterministicSocketData
data(reads
, arraysize(reads
),
6040 writes
, arraysize(writes
));
6042 ScopedVector
<UploadElementReader
> element_readers
;
6043 for (int i
= 0; i
< kFrameCount
; ++i
) {
6044 element_readers
.push_back(
6045 new UploadBytesElementReader(content
->c_str(), content
->size()));
6047 ElementsUploadDataStream
upload_data_stream(element_readers
.Pass(), 0);
6049 // Setup the request
6050 HttpRequestInfo request
;
6051 request
.method
= "POST";
6052 request
.url
= GURL(GetDefaultUrl());
6053 request
.upload_data_stream
= &upload_data_stream
;
6055 NormalSpdyTransactionHelper
helper(request
, DEFAULT_PRIORITY
,
6056 BoundNetLog(), GetParam(), NULL
);
6057 helper
.SetDeterministic();
6058 helper
.RunPreTestSetup();
6059 helper
.AddDeterministicData(&data
);
6060 HttpNetworkTransaction
* trans
= helper
.trans();
6062 TestCompletionCallback callback
;
6063 int rv
= trans
->Start(&helper
.request(), callback
.callback(), BoundNetLog());
6064 ASSERT_EQ(ERR_IO_PENDING
, rv
);
6067 ASSERT_TRUE(callback
.have_result());
6068 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR
, callback
.WaitForResult());
6069 helper
.VerifyDataConsumed();
6072 // Test that after hitting a send window size of 0, the write process
6073 // stalls and upon receiving WINDOW_UPDATE frame write resumes.
6075 // This test constructs a POST request followed by enough data frames
6076 // containing 'a' that would make the window size 0, followed by another
6077 // data frame containing default content (which is "hello!") and this frame
6078 // also contains a FIN flag. SequencedSocketData is used to enforce all
6079 // writes, save the last, go through before a read could happen. The last frame
6080 // ("hello!") is not permitted to go through since by the time its turn
6081 // arrives, window size is 0. At this point MessageLoop::Run() called via
6082 // callback would block. Therefore we call MessageLoop::RunUntilIdle()
6083 // which returns after performing all possible writes. We use DCHECKS to
6084 // ensure that last data frame is still there and stream has stalled.
6085 // After that, next read is artifically enforced, which causes a
6086 // WINDOW_UPDATE to be read and I/O process resumes.
6087 TEST_P(SpdyNetworkTransactionTest
, FlowControlStallResume
) {
6088 const int32 initial_window_size
=
6089 SpdySession::GetDefaultInitialWindowSize(GetParam().protocol
);
6090 // Number of frames we need to send to zero out the window size: data
6091 // frames plus SYN_STREAM plus the last data frame; also we need another
6092 // data frame that we will send once the WINDOW_UPDATE is received,
6094 size_t num_writes
= initial_window_size
/ kMaxSpdyFrameChunkSize
+ 3;
6096 // Calculate last frame's size; 0 size data frame is legal.
6097 size_t last_frame_size
= initial_window_size
% kMaxSpdyFrameChunkSize
;
6099 // Construct content for a data frame of maximum size.
6100 std::string
content(kMaxSpdyFrameChunkSize
, 'a');
6102 scoped_ptr
<SpdyFrame
> req(spdy_util_
.ConstructSpdyPost(
6103 GetDefaultUrl(), 1, initial_window_size
+ kUploadDataSize
, LOWEST
, NULL
,
6107 scoped_ptr
<SpdyFrame
> body1(
6108 spdy_util_
.ConstructSpdyBodyFrame(
6109 1, content
.c_str(), content
.size(), false));
6111 // Last frame to zero out the window size.
6112 scoped_ptr
<SpdyFrame
> body2(
6113 spdy_util_
.ConstructSpdyBodyFrame(
6114 1, content
.c_str(), last_frame_size
, false));
6116 // Data frame to be sent once WINDOW_UPDATE frame is received.
6117 scoped_ptr
<SpdyFrame
> body3(spdy_util_
.ConstructSpdyBodyFrame(1, true));
6119 // Fill in mock writes.
6120 scoped_ptr
<MockWrite
[]> writes(new MockWrite
[num_writes
]);
6122 writes
[i
] = CreateMockWrite(*req
, i
);
6123 for (i
= 1; i
< num_writes
- 2; i
++)
6124 writes
[i
] = CreateMockWrite(*body1
, i
);
6125 writes
[i
] = CreateMockWrite(*body2
, i
);
6126 // The last write must not be attempted until after the WINDOW_UPDATES
6127 // have been received.
6128 writes
[i
+ 1] = CreateMockWrite(*body3
, i
+ 4, SYNCHRONOUS
);
6130 // Construct read frame, give enough space to upload the rest of the
6132 scoped_ptr
<SpdyFrame
> session_window_update(
6133 spdy_util_
.ConstructSpdyWindowUpdate(0, kUploadDataSize
));
6134 scoped_ptr
<SpdyFrame
> window_update(
6135 spdy_util_
.ConstructSpdyWindowUpdate(1, kUploadDataSize
));
6136 scoped_ptr
<SpdyFrame
> reply(spdy_util_
.ConstructSpdyPostSynReply(NULL
, 0));
6137 MockRead reads
[] = {
6138 MockRead(ASYNC
, ERR_IO_PENDING
, i
+ 1), // Force a pause
6139 CreateMockRead(*session_window_update
, i
+ 2),
6140 CreateMockRead(*window_update
, i
+ 3),
6141 // Now the last write will occur.
6142 CreateMockRead(*reply
, i
+ 5),
6143 CreateMockRead(*body2
, i
+ 6),
6144 CreateMockRead(*body3
, i
+ 7),
6145 MockRead(ASYNC
, 0, i
+ 8) // EOF
6148 SequencedSocketData
data(reads
, arraysize(reads
), writes
.get(), num_writes
);
6150 ScopedVector
<UploadElementReader
> element_readers
;
6151 std::string
upload_data_string(initial_window_size
, 'a');
6152 upload_data_string
.append(kUploadData
, kUploadDataSize
);
6153 element_readers
.push_back(new UploadBytesElementReader(
6154 upload_data_string
.c_str(), upload_data_string
.size()));
6155 ElementsUploadDataStream
upload_data_stream(element_readers
.Pass(), 0);
6157 HttpRequestInfo request
;
6158 request
.method
= "POST";
6159 request
.url
= GURL(GetDefaultUrl());
6160 request
.upload_data_stream
= &upload_data_stream
;
6161 NormalSpdyTransactionHelper
helper(request
, DEFAULT_PRIORITY
,
6162 BoundNetLog(), GetParam(), NULL
);
6163 helper
.AddData(&data
);
6164 helper
.RunPreTestSetup();
6166 HttpNetworkTransaction
* trans
= helper
.trans();
6168 TestCompletionCallback callback
;
6169 int rv
= trans
->Start(&helper
.request(), callback
.callback(), BoundNetLog());
6170 EXPECT_EQ(ERR_IO_PENDING
, rv
);
6172 base::RunLoop().RunUntilIdle(); // Write as much as we can.
6174 SpdyHttpStream
* stream
= static_cast<SpdyHttpStream
*>(trans
->stream_
.get());
6175 ASSERT_TRUE(stream
!= NULL
);
6176 ASSERT_TRUE(stream
->stream() != NULL
);
6177 EXPECT_EQ(0, stream
->stream()->send_window_size());
6178 // All the body data should have been read.
6179 // TODO(satorux): This is because of the weirdness in reading the request
6180 // body in OnSendBodyComplete(). See crbug.com/113107.
6181 EXPECT_TRUE(upload_data_stream
.IsEOF());
6182 // But the body is not yet fully sent (kUploadData is not yet sent)
6183 // since we're send-stalled.
6184 EXPECT_TRUE(stream
->stream()->send_stalled_by_flow_control());
6186 data
.CompleteRead(); // Read in WINDOW_UPDATE frame.
6187 rv
= callback
.WaitForResult();
6188 helper
.VerifyDataConsumed();
6191 // Test we correctly handle the case where the SETTINGS frame results in
6192 // unstalling the send window.
6193 TEST_P(SpdyNetworkTransactionTest
, FlowControlStallResumeAfterSettings
) {
6194 const int32 initial_window_size
=
6195 SpdySession::GetDefaultInitialWindowSize(GetParam().protocol
);
6197 // Number of frames we need to send to zero out the window size: data
6198 // frames plus SYN_STREAM plus the last data frame; also we need another
6199 // data frame that we will send once the SETTING is received, therefore +3.
6200 size_t num_writes
= initial_window_size
/ kMaxSpdyFrameChunkSize
+ 3;
6202 // Calculate last frame's size; 0 size data frame is legal.
6203 size_t last_frame_size
= initial_window_size
% kMaxSpdyFrameChunkSize
;
6205 // Construct content for a data frame of maximum size.
6206 std::string
content(kMaxSpdyFrameChunkSize
, 'a');
6208 scoped_ptr
<SpdyFrame
> req(spdy_util_
.ConstructSpdyPost(
6209 GetDefaultUrl(), 1, initial_window_size
+ kUploadDataSize
, LOWEST
, NULL
,
6213 scoped_ptr
<SpdyFrame
> body1(
6214 spdy_util_
.ConstructSpdyBodyFrame(
6215 1, content
.c_str(), content
.size(), false));
6217 // Last frame to zero out the window size.
6218 scoped_ptr
<SpdyFrame
> body2(
6219 spdy_util_
.ConstructSpdyBodyFrame(
6220 1, content
.c_str(), last_frame_size
, false));
6222 // Data frame to be sent once SETTINGS frame is received.
6223 scoped_ptr
<SpdyFrame
> body3(spdy_util_
.ConstructSpdyBodyFrame(1, true));
6225 // Fill in mock reads/writes.
6226 std::vector
<MockRead
> reads
;
6227 std::vector
<MockWrite
> writes
;
6229 writes
.push_back(CreateMockWrite(*req
, i
++));
6230 while (i
< num_writes
- 2)
6231 writes
.push_back(CreateMockWrite(*body1
, i
++));
6232 writes
.push_back(CreateMockWrite(*body2
, i
++));
6234 // Construct read frame for SETTINGS that gives enough space to upload the
6235 // rest of the data.
6236 SettingsMap settings
;
6237 settings
[SETTINGS_INITIAL_WINDOW_SIZE
] =
6238 SettingsFlagsAndValue(SETTINGS_FLAG_NONE
, initial_window_size
* 2);
6239 scoped_ptr
<SpdyFrame
> settings_frame_large(
6240 spdy_util_
.ConstructSpdySettings(settings
));
6242 reads
.push_back(CreateMockRead(*settings_frame_large
, i
++));
6244 scoped_ptr
<SpdyFrame
> session_window_update(
6245 spdy_util_
.ConstructSpdyWindowUpdate(0, kUploadDataSize
));
6246 if (GetParam().protocol
>= kProtoSPDY31
)
6247 reads
.push_back(CreateMockRead(*session_window_update
, i
++));
6249 scoped_ptr
<SpdyFrame
> settings_ack(spdy_util_
.ConstructSpdySettingsAck());
6250 writes
.push_back(CreateMockWrite(*settings_ack
, i
++));
6252 writes
.push_back(CreateMockWrite(*body3
, i
++));
6254 scoped_ptr
<SpdyFrame
> reply(spdy_util_
.ConstructSpdyPostSynReply(NULL
, 0));
6255 reads
.push_back(CreateMockRead(*reply
, i
++));
6256 reads
.push_back(CreateMockRead(*body2
, i
++));
6257 reads
.push_back(CreateMockRead(*body3
, i
++));
6258 reads
.push_back(MockRead(ASYNC
, 0, i
++)); // EOF
6260 // Force all writes to happen before any read, last write will not
6261 // actually queue a frame, due to window size being 0.
6262 DeterministicSocketData
data(vector_as_array(&reads
), reads
.size(),
6263 vector_as_array(&writes
), writes
.size());
6265 ScopedVector
<UploadElementReader
> element_readers
;
6266 std::string
upload_data_string(initial_window_size
, 'a');
6267 upload_data_string
.append(kUploadData
, kUploadDataSize
);
6268 element_readers
.push_back(new UploadBytesElementReader(
6269 upload_data_string
.c_str(), upload_data_string
.size()));
6270 ElementsUploadDataStream
upload_data_stream(element_readers
.Pass(), 0);
6272 HttpRequestInfo request
;
6273 request
.method
= "POST";
6274 request
.url
= GURL(GetDefaultUrl());
6275 request
.upload_data_stream
= &upload_data_stream
;
6276 NormalSpdyTransactionHelper
helper(request
, DEFAULT_PRIORITY
,
6277 BoundNetLog(), GetParam(), NULL
);
6278 helper
.SetDeterministic();
6279 helper
.RunPreTestSetup();
6280 helper
.AddDeterministicData(&data
);
6282 HttpNetworkTransaction
* trans
= helper
.trans();
6284 TestCompletionCallback callback
;
6285 int rv
= trans
->Start(&helper
.request(), callback
.callback(), BoundNetLog());
6286 EXPECT_EQ(ERR_IO_PENDING
, rv
);
6288 data
.RunFor(num_writes
- 1); // Write as much as we can.
6290 SpdyHttpStream
* stream
= static_cast<SpdyHttpStream
*>(trans
->stream_
.get());
6291 ASSERT_TRUE(stream
!= NULL
);
6292 ASSERT_TRUE(stream
->stream() != NULL
);
6293 EXPECT_EQ(0, stream
->stream()->send_window_size());
6295 // All the body data should have been read.
6296 // TODO(satorux): This is because of the weirdness in reading the request
6297 // body in OnSendBodyComplete(). See crbug.com/113107.
6298 EXPECT_TRUE(upload_data_stream
.IsEOF());
6299 // But the body is not yet fully sent (kUploadData is not yet sent)
6300 // since we're send-stalled.
6301 EXPECT_TRUE(stream
->stream()->send_stalled_by_flow_control());
6303 data
.RunFor(7); // Read in SETTINGS frame to unstall.
6304 rv
= callback
.WaitForResult();
6305 helper
.VerifyDataConsumed();
6306 // If stream is NULL, that means it was unstalled and closed.
6307 EXPECT_TRUE(stream
->stream() == NULL
);
6310 // Test we correctly handle the case where the SETTINGS frame results in a
6311 // negative send window size.
6312 TEST_P(SpdyNetworkTransactionTest
, FlowControlNegativeSendWindowSize
) {
6313 const int32 initial_window_size
=
6314 SpdySession::GetDefaultInitialWindowSize(GetParam().protocol
);
6315 // Number of frames we need to send to zero out the window size: data
6316 // frames plus SYN_STREAM plus the last data frame; also we need another
6317 // data frame that we will send once the SETTING is received, therefore +3.
6318 size_t num_writes
= initial_window_size
/ kMaxSpdyFrameChunkSize
+ 3;
6320 // Calculate last frame's size; 0 size data frame is legal.
6321 size_t last_frame_size
= initial_window_size
% kMaxSpdyFrameChunkSize
;
6323 // Construct content for a data frame of maximum size.
6324 std::string
content(kMaxSpdyFrameChunkSize
, 'a');
6326 scoped_ptr
<SpdyFrame
> req(spdy_util_
.ConstructSpdyPost(
6327 GetDefaultUrl(), 1, initial_window_size
+ kUploadDataSize
, LOWEST
, NULL
,
6331 scoped_ptr
<SpdyFrame
> body1(
6332 spdy_util_
.ConstructSpdyBodyFrame(
6333 1, content
.c_str(), content
.size(), false));
6335 // Last frame to zero out the window size.
6336 scoped_ptr
<SpdyFrame
> body2(
6337 spdy_util_
.ConstructSpdyBodyFrame(
6338 1, content
.c_str(), last_frame_size
, false));
6340 // Data frame to be sent once SETTINGS frame is received.
6341 scoped_ptr
<SpdyFrame
> body3(spdy_util_
.ConstructSpdyBodyFrame(1, true));
6343 // Fill in mock reads/writes.
6344 std::vector
<MockRead
> reads
;
6345 std::vector
<MockWrite
> writes
;
6347 writes
.push_back(CreateMockWrite(*req
, i
++));
6348 while (i
< num_writes
- 2)
6349 writes
.push_back(CreateMockWrite(*body1
, i
++));
6350 writes
.push_back(CreateMockWrite(*body2
, i
++));
6352 // Construct read frame for SETTINGS that makes the send_window_size
6354 SettingsMap new_settings
;
6355 new_settings
[SETTINGS_INITIAL_WINDOW_SIZE
] =
6356 SettingsFlagsAndValue(SETTINGS_FLAG_NONE
, initial_window_size
/ 2);
6357 scoped_ptr
<SpdyFrame
> settings_frame_small(
6358 spdy_util_
.ConstructSpdySettings(new_settings
));
6359 // Construct read frames for WINDOW_UPDATE that makes the send_window_size
6361 scoped_ptr
<SpdyFrame
> session_window_update_init_size(
6362 spdy_util_
.ConstructSpdyWindowUpdate(0, initial_window_size
));
6363 scoped_ptr
<SpdyFrame
> window_update_init_size(
6364 spdy_util_
.ConstructSpdyWindowUpdate(1, initial_window_size
));
6366 reads
.push_back(CreateMockRead(*settings_frame_small
, i
++));
6367 reads
.push_back(CreateMockRead(*session_window_update_init_size
, i
++));
6368 reads
.push_back(CreateMockRead(*window_update_init_size
, i
++));
6370 scoped_ptr
<SpdyFrame
> settings_ack(spdy_util_
.ConstructSpdySettingsAck());
6371 writes
.push_back(CreateMockWrite(*settings_ack
, i
++));
6373 writes
.push_back(CreateMockWrite(*body3
, i
++));
6375 scoped_ptr
<SpdyFrame
> reply(spdy_util_
.ConstructSpdyPostSynReply(NULL
, 0));
6376 reads
.push_back(CreateMockRead(*reply
, i
++));
6377 reads
.push_back(CreateMockRead(*body2
, i
++));
6378 reads
.push_back(CreateMockRead(*body3
, i
++));
6379 reads
.push_back(MockRead(ASYNC
, 0, i
++)); // EOF
6381 // Force all writes to happen before any read, last write will not
6382 // actually queue a frame, due to window size being 0.
6383 DeterministicSocketData
data(vector_as_array(&reads
), reads
.size(),
6384 vector_as_array(&writes
), writes
.size());
6386 ScopedVector
<UploadElementReader
> element_readers
;
6387 std::string
upload_data_string(initial_window_size
, 'a');
6388 upload_data_string
.append(kUploadData
, kUploadDataSize
);
6389 element_readers
.push_back(new UploadBytesElementReader(
6390 upload_data_string
.c_str(), upload_data_string
.size()));
6391 ElementsUploadDataStream
upload_data_stream(element_readers
.Pass(), 0);
6393 HttpRequestInfo request
;
6394 request
.method
= "POST";
6395 request
.url
= GURL(GetDefaultUrl());
6396 request
.upload_data_stream
= &upload_data_stream
;
6397 NormalSpdyTransactionHelper
helper(request
, DEFAULT_PRIORITY
,
6398 BoundNetLog(), GetParam(), NULL
);
6399 helper
.SetDeterministic();
6400 helper
.RunPreTestSetup();
6401 helper
.AddDeterministicData(&data
);
6403 HttpNetworkTransaction
* trans
= helper
.trans();
6405 TestCompletionCallback callback
;
6406 int rv
= trans
->Start(&helper
.request(), callback
.callback(), BoundNetLog());
6407 EXPECT_EQ(ERR_IO_PENDING
, rv
);
6409 data
.RunFor(num_writes
- 1); // Write as much as we can.
6411 SpdyHttpStream
* stream
= static_cast<SpdyHttpStream
*>(trans
->stream_
.get());
6412 ASSERT_TRUE(stream
!= NULL
);
6413 ASSERT_TRUE(stream
->stream() != NULL
);
6414 EXPECT_EQ(0, stream
->stream()->send_window_size());
6416 // All the body data should have been read.
6417 // TODO(satorux): This is because of the weirdness in reading the request
6418 // body in OnSendBodyComplete(). See crbug.com/113107.
6419 EXPECT_TRUE(upload_data_stream
.IsEOF());
6420 // But the body is not yet fully sent (kUploadData is not yet sent)
6421 // since we're send-stalled.
6422 EXPECT_TRUE(stream
->stream()->send_stalled_by_flow_control());
6424 // Read in WINDOW_UPDATE or SETTINGS frame.
6425 data
.RunFor((GetParam().protocol
>= kProtoSPDY31
) ? 9 : 8);
6426 rv
= callback
.WaitForResult();
6427 helper
.VerifyDataConsumed();
6430 TEST_P(SpdyNetworkTransactionTest
, GoAwayOnOddPushStreamId
) {
6431 if (spdy_util_
.spdy_version() < SPDY3
)
6434 scoped_ptr
<SpdyHeaderBlock
> push_headers(new SpdyHeaderBlock
);
6435 spdy_util_
.AddUrlToHeaderBlock("http://www.example.org/a.dat",
6436 push_headers
.get());
6437 scoped_ptr
<SpdyFrame
> push(
6438 spdy_util_
.ConstructInitialSpdyPushFrame(push_headers
.Pass(), 3, 1));
6439 MockRead reads
[] = {CreateMockRead(*push
, 1)};
6441 scoped_ptr
<SpdyFrame
> req(
6442 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
6443 scoped_ptr
<SpdyFrame
> goaway(spdy_util_
.ConstructSpdyGoAway(
6444 0, GOAWAY_PROTOCOL_ERROR
, "Odd push stream id."));
6445 MockWrite writes
[] = {
6446 CreateMockWrite(*req
, 0), CreateMockWrite(*goaway
, 2),
6449 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
6450 NormalSpdyTransactionHelper
helper(
6451 CreateGetRequest(), DEFAULT_PRIORITY
, BoundNetLog(), GetParam(), NULL
);
6452 helper
.RunToCompletion(&data
);
6453 TransactionHelperResult out
= helper
.output();
6454 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR
, out
.rv
);
6457 TEST_P(SpdyNetworkTransactionTest
,
6458 GoAwayOnPushStreamIdLesserOrEqualThanLastAccepted
) {
6459 if (spdy_util_
.spdy_version() < SPDY3
)
6462 scoped_ptr
<SpdyFrame
> push_a(spdy_util_
.ConstructSpdyPush(
6463 NULL
, 0, 4, 1, GetDefaultUrlWithPath("/a.dat").c_str()));
6464 scoped_ptr
<SpdyHeaderBlock
> push_b_headers(new SpdyHeaderBlock
);
6465 spdy_util_
.AddUrlToHeaderBlock(GetDefaultUrlWithPath("/b.dat"),
6466 push_b_headers
.get());
6467 scoped_ptr
<SpdyFrame
> push_b(
6468 spdy_util_
.ConstructInitialSpdyPushFrame(push_b_headers
.Pass(), 2, 1));
6469 MockRead reads
[] = {
6470 CreateMockRead(*push_a
, 1), CreateMockRead(*push_b
, 2),
6473 scoped_ptr
<SpdyFrame
> req(
6474 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
6475 scoped_ptr
<SpdyFrame
> goaway(spdy_util_
.ConstructSpdyGoAway(
6477 GOAWAY_PROTOCOL_ERROR
,
6478 "New push stream id must be greater than the last accepted."));
6479 MockWrite writes
[] = {
6480 CreateMockWrite(*req
, 0), CreateMockWrite(*goaway
, 3),
6483 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
6484 NormalSpdyTransactionHelper
helper(
6485 CreateGetRequest(), DEFAULT_PRIORITY
, BoundNetLog(), GetParam(), NULL
);
6486 helper
.RunToCompletion(&data
);
6487 TransactionHelperResult out
= helper
.output();
6488 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR
, out
.rv
);
6491 // Regression test for https://crbug.com/493348: request header exceeds 16 kB
6492 // and thus sent in multiple frames when using HTTP/2.
6493 TEST_P(SpdyNetworkTransactionTest
, LargeRequest
) {
6494 const std::string
kKey("foo");
6495 const std::string
kValue(1 << 15, 'z');
6497 HttpRequestInfo request
;
6498 request
.method
= "GET";
6499 request
.url
= GURL(GetDefaultUrl());
6500 request
.extra_headers
.SetHeader(kKey
, kValue
);
6502 scoped_ptr
<SpdyHeaderBlock
> headers(
6503 spdy_util_
.ConstructGetHeaderBlock(GetDefaultUrl()));
6504 (*headers
)[kKey
] = kValue
;
6505 scoped_ptr
<SpdyFrame
> req(
6506 spdy_util_
.ConstructSpdySyn(1, *headers
, LOWEST
, false, true));
6507 MockWrite writes
[] = {
6508 CreateMockWrite(*req
, 0),
6511 scoped_ptr
<SpdyFrame
> resp(
6512 spdy_util_
.ConstructSpdyGetSynReply(nullptr, 0, 1));
6513 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
6514 MockRead reads
[] = {
6515 CreateMockRead(*resp
, 1),
6516 CreateMockRead(*body
, 2),
6517 MockRead(ASYNC
, 0, 3) // EOF
6520 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
6521 NormalSpdyTransactionHelper
helper(request
, DEFAULT_PRIORITY
, BoundNetLog(),
6522 GetParam(), nullptr);
6523 helper
.RunToCompletion(&data
);
6524 TransactionHelperResult out
= helper
.output();
6526 EXPECT_EQ(OK
, out
.rv
);
6527 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
6528 EXPECT_EQ("hello!", out
.response_data
);
6531 class SpdyNetworkTransactionNoTLSUsageCheckTest
6532 : public SpdyNetworkTransactionTest
{
6534 void RunNoTLSUsageCheckTest(scoped_ptr
<SSLSocketDataProvider
> ssl_provider
) {
6535 // Construct the request.
6536 scoped_ptr
<SpdyFrame
> req(
6537 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
6538 MockWrite writes
[] = {CreateMockWrite(*req
, 0)};
6540 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
6541 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
6542 MockRead reads
[] = {
6543 CreateMockRead(*resp
, 1),
6544 CreateMockRead(*body
, 2),
6545 MockRead(ASYNC
, 0, 3) // EOF
6548 SequencedSocketData
data(reads
, arraysize(reads
), writes
,
6550 HttpRequestInfo request
;
6551 request
.method
= "GET";
6552 request
.url
= GURL("https://www.example.org/");
6553 NormalSpdyTransactionHelper
helper(
6554 request
, DEFAULT_PRIORITY
, BoundNetLog(), GetParam(), NULL
);
6555 helper
.RunToCompletionWithSSLData(&data
, ssl_provider
.Pass());
6556 TransactionHelperResult out
= helper
.output();
6557 EXPECT_EQ(OK
, out
.rv
);
6558 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
6559 EXPECT_EQ("hello!", out
.response_data
);
6563 //-----------------------------------------------------------------------------
6564 // All tests are run with three different connection types: SPDY after NPN
6565 // negotiation, SPDY without SSL, and SPDY with SSL.
6567 // TODO(akalin): Use ::testing::Combine() when we are able to use
6569 INSTANTIATE_TEST_CASE_P(
6571 SpdyNetworkTransactionNoTLSUsageCheckTest
,
6572 ::testing::Values(SpdyNetworkTransactionTestParams(kProtoSPDY31
,
6573 HTTPS_SPDY_VIA_NPN
)));
6575 TEST_P(SpdyNetworkTransactionNoTLSUsageCheckTest
, TLSVersionTooOld
) {
6576 scoped_ptr
<SSLSocketDataProvider
> ssl_provider(
6577 new SSLSocketDataProvider(ASYNC
, OK
));
6578 SSLConnectionStatusSetVersion(SSL_CONNECTION_VERSION_SSL3
,
6579 &ssl_provider
->connection_status
);
6581 RunNoTLSUsageCheckTest(ssl_provider
.Pass());
6584 TEST_P(SpdyNetworkTransactionNoTLSUsageCheckTest
, TLSCipherSuiteSucky
) {
6585 scoped_ptr
<SSLSocketDataProvider
> ssl_provider(
6586 new SSLSocketDataProvider(ASYNC
, OK
));
6587 // Set to TLS_RSA_WITH_NULL_MD5
6588 SSLConnectionStatusSetCipherSuite(0x1, &ssl_provider
->connection_status
);
6590 RunNoTLSUsageCheckTest(ssl_provider
.Pass());
6593 class SpdyNetworkTransactionTLSUsageCheckTest
6594 : public SpdyNetworkTransactionTest
{
6596 void RunTLSUsageCheckTest(scoped_ptr
<SSLSocketDataProvider
> ssl_provider
) {
6597 scoped_ptr
<SpdyFrame
> goaway(
6598 spdy_util_
.ConstructSpdyGoAway(0, GOAWAY_INADEQUATE_SECURITY
, ""));
6599 MockWrite writes
[] = {CreateMockWrite(*goaway
)};
6601 StaticSocketDataProvider
data(NULL
, 0, writes
, arraysize(writes
));
6602 HttpRequestInfo request
;
6603 request
.method
= "GET";
6604 request
.url
= GURL("https://www.example.org/");
6605 NormalSpdyTransactionHelper
helper(
6606 request
, DEFAULT_PRIORITY
, BoundNetLog(), GetParam(), NULL
);
6607 helper
.RunToCompletionWithSSLData(&data
, ssl_provider
.Pass());
6608 TransactionHelperResult out
= helper
.output();
6609 EXPECT_EQ(ERR_SPDY_INADEQUATE_TRANSPORT_SECURITY
, out
.rv
);
6613 INSTANTIATE_TEST_CASE_P(
6615 SpdyNetworkTransactionTLSUsageCheckTest
,
6617 SpdyNetworkTransactionTestParams(kProtoHTTP2_14
, HTTPS_SPDY_VIA_NPN
),
6618 SpdyNetworkTransactionTestParams(kProtoHTTP2
, HTTPS_SPDY_VIA_NPN
)));
6620 TEST_P(SpdyNetworkTransactionTLSUsageCheckTest
, TLSVersionTooOld
) {
6621 scoped_ptr
<SSLSocketDataProvider
> ssl_provider(
6622 new SSLSocketDataProvider(ASYNC
, OK
));
6623 SSLConnectionStatusSetVersion(SSL_CONNECTION_VERSION_SSL3
,
6624 &ssl_provider
->connection_status
);
6626 RunTLSUsageCheckTest(ssl_provider
.Pass());
6629 TEST_P(SpdyNetworkTransactionTLSUsageCheckTest
, TLSCipherSuiteSucky
) {
6630 scoped_ptr
<SSLSocketDataProvider
> ssl_provider(
6631 new SSLSocketDataProvider(ASYNC
, OK
));
6632 // Set to TLS_RSA_WITH_NULL_MD5
6633 SSLConnectionStatusSetCipherSuite(0x1, &ssl_provider
->connection_status
);
6635 RunTLSUsageCheckTest(ssl_provider
.Pass());