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_alternative_services
= 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
, HTTPS_SPDY_VIA_NPN
),
720 SpdyNetworkTransactionTestParams(kProtoHTTP2
, HTTP_SPDY_VIA_ALT_SVC
)));
722 // Verify HttpNetworkTransaction constructor.
723 TEST_P(SpdyNetworkTransactionTest
, Constructor
) {
724 scoped_ptr
<SpdySessionDependencies
> session_deps(
725 CreateSpdySessionDependencies(GetParam()));
726 scoped_refptr
<HttpNetworkSession
> session(
727 SpdySessionDependencies::SpdyCreateSession(session_deps
.get()));
728 scoped_ptr
<HttpTransaction
> trans(
729 new HttpNetworkTransaction(DEFAULT_PRIORITY
, session
.get()));
732 TEST_P(SpdyNetworkTransactionTest
, Get
) {
733 // Construct the request.
734 scoped_ptr
<SpdyFrame
> req(
735 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
736 MockWrite writes
[] = {CreateMockWrite(*req
, 0)};
738 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
739 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
741 CreateMockRead(*resp
, 1),
742 CreateMockRead(*body
, 2),
743 MockRead(ASYNC
, 0, 3) // EOF
746 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
747 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
748 BoundNetLog(), GetParam(), NULL
);
749 helper
.RunToCompletion(&data
);
750 TransactionHelperResult out
= helper
.output();
751 EXPECT_EQ(OK
, out
.rv
);
752 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
753 EXPECT_EQ("hello!", out
.response_data
);
756 TEST_P(SpdyNetworkTransactionTest
, GetAtEachPriority
) {
757 for (RequestPriority p
= MINIMUM_PRIORITY
; p
<= MAXIMUM_PRIORITY
;
758 p
= RequestPriority(p
+ 1)) {
759 // Construct the request.
760 scoped_ptr
<SpdyFrame
> req(
761 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, p
, true));
762 MockWrite writes
[] = {CreateMockWrite(*req
, 0)};
764 SpdyPriority spdy_prio
= 0;
765 EXPECT_TRUE(GetSpdyPriority(spdy_util_
.spdy_version(), *req
, &spdy_prio
));
766 // this repeats the RequestPriority-->SpdyPriority mapping from
767 // SpdyFramer::ConvertRequestPriorityToSpdyPriority to make
768 // sure it's being done right.
769 if (spdy_util_
.spdy_version() < SPDY3
) {
772 EXPECT_EQ(0, spdy_prio
);
775 EXPECT_EQ(1, spdy_prio
);
779 EXPECT_EQ(2, spdy_prio
);
782 EXPECT_EQ(3, spdy_prio
);
790 EXPECT_EQ(0, spdy_prio
);
793 EXPECT_EQ(1, spdy_prio
);
796 EXPECT_EQ(2, spdy_prio
);
799 EXPECT_EQ(3, spdy_prio
);
802 EXPECT_EQ(4, spdy_prio
);
809 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
810 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
812 CreateMockRead(*resp
, 1),
813 CreateMockRead(*body
, 2),
814 MockRead(ASYNC
, 0, 3) // EOF
817 SequencedSocketData
data(reads
, arraysize(reads
), writes
,
819 HttpRequestInfo http_req
= CreateGetRequest();
821 NormalSpdyTransactionHelper
helper(http_req
, p
, BoundNetLog(),
823 helper
.RunToCompletion(&data
);
824 TransactionHelperResult out
= helper
.output();
825 EXPECT_EQ(OK
, out
.rv
);
826 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
827 EXPECT_EQ("hello!", out
.response_data
);
831 // Start three gets simultaniously; making sure that multiplexed
832 // streams work properly.
834 // This can't use the TransactionHelper method, since it only
835 // handles a single transaction, and finishes them as soon
836 // as it launches them.
838 // TODO(gavinp): create a working generalized TransactionHelper that
839 // can allow multiple streams in flight.
841 TEST_P(SpdyNetworkTransactionTest
, ThreeGets
) {
842 scoped_ptr
<SpdyFrame
> req(
843 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
844 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
845 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, false));
846 scoped_ptr
<SpdyFrame
> fbody(spdy_util_
.ConstructSpdyBodyFrame(1, true));
848 scoped_ptr
<SpdyFrame
> req2(
849 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 3, LOWEST
, true));
850 scoped_ptr
<SpdyFrame
> resp2(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 3));
851 scoped_ptr
<SpdyFrame
> body2(spdy_util_
.ConstructSpdyBodyFrame(3, false));
852 scoped_ptr
<SpdyFrame
> fbody2(spdy_util_
.ConstructSpdyBodyFrame(3, true));
854 scoped_ptr
<SpdyFrame
> req3(
855 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 5, LOWEST
, true));
856 scoped_ptr
<SpdyFrame
> resp3(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 5));
857 scoped_ptr
<SpdyFrame
> body3(spdy_util_
.ConstructSpdyBodyFrame(5, false));
858 scoped_ptr
<SpdyFrame
> fbody3(spdy_util_
.ConstructSpdyBodyFrame(5, true));
860 MockWrite writes
[] = {
861 CreateMockWrite(*req
, 0),
862 CreateMockWrite(*req2
, 3),
863 CreateMockWrite(*req3
, 6),
866 CreateMockRead(*resp
, 1),
867 CreateMockRead(*body
, 2),
868 CreateMockRead(*resp2
, 4),
869 CreateMockRead(*body2
, 5),
870 CreateMockRead(*resp3
, 7),
871 CreateMockRead(*body3
, 8),
873 CreateMockRead(*fbody
, 9),
874 CreateMockRead(*fbody2
, 10),
875 CreateMockRead(*fbody3
, 11),
877 MockRead(ASYNC
, 0, 12), // EOF
879 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
880 SequencedSocketData
data_placeholder(NULL
, 0, NULL
, 0);
883 TransactionHelperResult out
;
884 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
885 BoundNetLog(), GetParam(), NULL
);
886 helper
.RunPreTestSetup();
887 helper
.AddData(&data
);
888 // We require placeholder data because three get requests are sent out at
889 // the same time which results in three sockets being connected. The first
890 // on will negotiate SPDY and will be used for all requests.
891 helper
.AddData(&data_placeholder
);
892 helper
.AddData(&data_placeholder
);
893 scoped_ptr
<HttpNetworkTransaction
> trans1(
894 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
895 scoped_ptr
<HttpNetworkTransaction
> trans2(
896 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
897 scoped_ptr
<HttpNetworkTransaction
> trans3(
898 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
900 TestCompletionCallback callback1
;
901 TestCompletionCallback callback2
;
902 TestCompletionCallback callback3
;
904 HttpRequestInfo httpreq1
= CreateGetRequest();
905 HttpRequestInfo httpreq2
= CreateGetRequest();
906 HttpRequestInfo httpreq3
= CreateGetRequest();
908 out
.rv
= trans1
->Start(&httpreq1
, callback1
.callback(), log
);
909 ASSERT_EQ(ERR_IO_PENDING
, out
.rv
);
910 out
.rv
= trans2
->Start(&httpreq2
, callback2
.callback(), log
);
911 ASSERT_EQ(ERR_IO_PENDING
, out
.rv
);
912 out
.rv
= trans3
->Start(&httpreq3
, callback3
.callback(), log
);
913 ASSERT_EQ(ERR_IO_PENDING
, out
.rv
);
915 out
.rv
= callback1
.WaitForResult();
916 ASSERT_EQ(OK
, out
.rv
);
917 out
.rv
= callback3
.WaitForResult();
918 ASSERT_EQ(OK
, out
.rv
);
920 const HttpResponseInfo
* response1
= trans1
->GetResponseInfo();
921 EXPECT_TRUE(response1
->headers
.get() != NULL
);
922 EXPECT_TRUE(response1
->was_fetched_via_spdy
);
923 out
.status_line
= response1
->headers
->GetStatusLine();
924 out
.response_info
= *response1
;
926 trans2
->GetResponseInfo();
928 out
.rv
= ReadTransaction(trans1
.get(), &out
.response_data
);
929 helper
.VerifyDataConsumed();
930 EXPECT_EQ(OK
, out
.rv
);
932 EXPECT_EQ(OK
, out
.rv
);
933 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
934 EXPECT_EQ("hello!hello!", out
.response_data
);
937 TEST_P(SpdyNetworkTransactionTest
, TwoGetsLateBinding
) {
938 scoped_ptr
<SpdyFrame
> req(
939 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
940 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
941 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, false));
942 scoped_ptr
<SpdyFrame
> fbody(spdy_util_
.ConstructSpdyBodyFrame(1, true));
944 scoped_ptr
<SpdyFrame
> req2(
945 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 3, LOWEST
, true));
946 scoped_ptr
<SpdyFrame
> resp2(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 3));
947 scoped_ptr
<SpdyFrame
> body2(spdy_util_
.ConstructSpdyBodyFrame(3, false));
948 scoped_ptr
<SpdyFrame
> fbody2(spdy_util_
.ConstructSpdyBodyFrame(3, true));
950 MockWrite writes
[] = {
951 CreateMockWrite(*req
, 0), CreateMockWrite(*req2
, 3),
954 CreateMockRead(*resp
, 1),
955 CreateMockRead(*body
, 2),
956 CreateMockRead(*resp2
, 4),
957 CreateMockRead(*body2
, 5),
958 CreateMockRead(*fbody
, 6),
959 CreateMockRead(*fbody2
, 7),
960 MockRead(ASYNC
, 0, 8), // EOF
962 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
964 MockConnect
never_finishing_connect(SYNCHRONOUS
, ERR_IO_PENDING
);
965 SequencedSocketData
data_placeholder(NULL
, 0, NULL
, 0);
966 data_placeholder
.set_connect_data(never_finishing_connect
);
969 TransactionHelperResult out
;
970 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
971 BoundNetLog(), GetParam(), NULL
);
972 helper
.RunPreTestSetup();
973 helper
.AddData(&data
);
974 // We require placeholder data because two requests are sent out at
975 // the same time which results in two sockets being connected. The first
976 // on will negotiate SPDY and will be used for all requests.
977 helper
.AddData(&data_placeholder
);
978 scoped_ptr
<HttpNetworkTransaction
> trans1(
979 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
980 scoped_ptr
<HttpNetworkTransaction
> trans2(
981 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
983 TestCompletionCallback callback1
;
984 TestCompletionCallback callback2
;
986 HttpRequestInfo httpreq1
= CreateGetRequest();
987 HttpRequestInfo httpreq2
= CreateGetRequest();
989 out
.rv
= trans1
->Start(&httpreq1
, callback1
.callback(), log
);
990 ASSERT_EQ(ERR_IO_PENDING
, out
.rv
);
991 out
.rv
= trans2
->Start(&httpreq2
, callback2
.callback(), log
);
992 ASSERT_EQ(ERR_IO_PENDING
, out
.rv
);
994 out
.rv
= callback1
.WaitForResult();
995 ASSERT_EQ(OK
, out
.rv
);
996 out
.rv
= callback2
.WaitForResult();
997 ASSERT_EQ(OK
, out
.rv
);
999 const HttpResponseInfo
* response1
= trans1
->GetResponseInfo();
1000 EXPECT_TRUE(response1
->headers
.get() != NULL
);
1001 EXPECT_TRUE(response1
->was_fetched_via_spdy
);
1002 out
.status_line
= response1
->headers
->GetStatusLine();
1003 out
.response_info
= *response1
;
1004 out
.rv
= ReadTransaction(trans1
.get(), &out
.response_data
);
1005 EXPECT_EQ(OK
, out
.rv
);
1006 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1007 EXPECT_EQ("hello!hello!", out
.response_data
);
1009 const HttpResponseInfo
* response2
= trans2
->GetResponseInfo();
1010 EXPECT_TRUE(response2
->headers
.get() != NULL
);
1011 EXPECT_TRUE(response2
->was_fetched_via_spdy
);
1012 out
.status_line
= response2
->headers
->GetStatusLine();
1013 out
.response_info
= *response2
;
1014 out
.rv
= ReadTransaction(trans2
.get(), &out
.response_data
);
1015 EXPECT_EQ(OK
, out
.rv
);
1016 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1017 EXPECT_EQ("hello!hello!", out
.response_data
);
1019 helper
.VerifyDataConsumed();
1022 TEST_P(SpdyNetworkTransactionTest
, TwoGetsLateBindingFromPreconnect
) {
1023 scoped_ptr
<SpdyFrame
> req(
1024 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
1025 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
1026 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, false));
1027 scoped_ptr
<SpdyFrame
> fbody(spdy_util_
.ConstructSpdyBodyFrame(1, true));
1029 scoped_ptr
<SpdyFrame
> req2(
1030 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 3, LOWEST
, true));
1031 scoped_ptr
<SpdyFrame
> resp2(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 3));
1032 scoped_ptr
<SpdyFrame
> body2(spdy_util_
.ConstructSpdyBodyFrame(3, false));
1033 scoped_ptr
<SpdyFrame
> fbody2(spdy_util_
.ConstructSpdyBodyFrame(3, true));
1035 MockWrite writes
[] = {
1036 CreateMockWrite(*req
, 0), CreateMockWrite(*req2
, 3),
1038 MockRead reads
[] = {
1039 CreateMockRead(*resp
, 1),
1040 CreateMockRead(*body
, 2),
1041 CreateMockRead(*resp2
, 4),
1042 CreateMockRead(*body2
, 5),
1043 CreateMockRead(*fbody
, 6),
1044 CreateMockRead(*fbody2
, 7),
1045 MockRead(ASYNC
, 0, 8), // EOF
1047 SequencedSocketData
preconnect_data(reads
, arraysize(reads
), writes
,
1050 MockConnect
never_finishing_connect(ASYNC
, ERR_IO_PENDING
);
1052 SequencedSocketData
data_placeholder(NULL
, 0, NULL
, 0);
1053 data_placeholder
.set_connect_data(never_finishing_connect
);
1056 TransactionHelperResult out
;
1057 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
1058 BoundNetLog(), GetParam(), NULL
);
1059 helper
.RunPreTestSetup();
1060 helper
.AddData(&preconnect_data
);
1061 // We require placeholder data because 3 connections are attempted (first is
1062 // the preconnect, 2nd and 3rd are the never finished connections.
1063 helper
.AddData(&data_placeholder
);
1064 helper
.AddData(&data_placeholder
);
1066 scoped_ptr
<HttpNetworkTransaction
> trans1(
1067 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
1068 scoped_ptr
<HttpNetworkTransaction
> trans2(
1069 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
1071 TestCompletionCallback callback1
;
1072 TestCompletionCallback callback2
;
1074 HttpRequestInfo httpreq
= CreateGetRequest();
1076 // Preconnect the first.
1077 SSLConfig preconnect_ssl_config
;
1078 helper
.session()->ssl_config_service()->GetSSLConfig(&preconnect_ssl_config
);
1079 HttpStreamFactory
* http_stream_factory
=
1080 helper
.session()->http_stream_factory();
1081 helper
.session()->GetNextProtos(&preconnect_ssl_config
.next_protos
);
1083 http_stream_factory
->PreconnectStreams(1, httpreq
, preconnect_ssl_config
,
1084 preconnect_ssl_config
);
1086 out
.rv
= trans1
->Start(&httpreq
, callback1
.callback(), log
);
1087 ASSERT_EQ(ERR_IO_PENDING
, out
.rv
);
1088 out
.rv
= trans2
->Start(&httpreq
, callback2
.callback(), log
);
1089 ASSERT_EQ(ERR_IO_PENDING
, out
.rv
);
1091 out
.rv
= callback1
.WaitForResult();
1092 ASSERT_EQ(OK
, out
.rv
);
1093 out
.rv
= callback2
.WaitForResult();
1094 ASSERT_EQ(OK
, out
.rv
);
1096 const HttpResponseInfo
* response1
= trans1
->GetResponseInfo();
1097 EXPECT_TRUE(response1
->headers
.get() != NULL
);
1098 EXPECT_TRUE(response1
->was_fetched_via_spdy
);
1099 out
.status_line
= response1
->headers
->GetStatusLine();
1100 out
.response_info
= *response1
;
1101 out
.rv
= ReadTransaction(trans1
.get(), &out
.response_data
);
1102 EXPECT_EQ(OK
, out
.rv
);
1103 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1104 EXPECT_EQ("hello!hello!", out
.response_data
);
1106 const HttpResponseInfo
* response2
= trans2
->GetResponseInfo();
1107 EXPECT_TRUE(response2
->headers
.get() != NULL
);
1108 EXPECT_TRUE(response2
->was_fetched_via_spdy
);
1109 out
.status_line
= response2
->headers
->GetStatusLine();
1110 out
.response_info
= *response2
;
1111 out
.rv
= ReadTransaction(trans2
.get(), &out
.response_data
);
1112 EXPECT_EQ(OK
, out
.rv
);
1113 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1114 EXPECT_EQ("hello!hello!", out
.response_data
);
1116 helper
.VerifyDataConsumed();
1119 // Similar to ThreeGets above, however this test adds a SETTINGS
1120 // frame. The SETTINGS frame is read during the IO loop waiting on
1121 // the first transaction completion, and sets a maximum concurrent
1122 // stream limit of 1. This means that our IO loop exists after the
1123 // second transaction completes, so we can assert on read_index().
1124 TEST_P(SpdyNetworkTransactionTest
, ThreeGetsWithMaxConcurrent
) {
1125 // Construct the request.
1126 scoped_ptr
<SpdyFrame
> req(
1127 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
1128 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
1129 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, false));
1130 scoped_ptr
<SpdyFrame
> fbody(spdy_util_
.ConstructSpdyBodyFrame(1, true));
1132 scoped_ptr
<SpdyFrame
> req2(
1133 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 3, LOWEST
, true));
1134 scoped_ptr
<SpdyFrame
> resp2(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 3));
1135 scoped_ptr
<SpdyFrame
> body2(spdy_util_
.ConstructSpdyBodyFrame(3, false));
1136 scoped_ptr
<SpdyFrame
> fbody2(spdy_util_
.ConstructSpdyBodyFrame(3, true));
1138 scoped_ptr
<SpdyFrame
> req3(
1139 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 5, LOWEST
, true));
1140 scoped_ptr
<SpdyFrame
> resp3(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 5));
1141 scoped_ptr
<SpdyFrame
> body3(spdy_util_
.ConstructSpdyBodyFrame(5, false));
1142 scoped_ptr
<SpdyFrame
> fbody3(spdy_util_
.ConstructSpdyBodyFrame(5, true));
1144 SettingsMap settings
;
1145 const uint32 max_concurrent_streams
= 1;
1146 settings
[SETTINGS_MAX_CONCURRENT_STREAMS
] =
1147 SettingsFlagsAndValue(SETTINGS_FLAG_NONE
, max_concurrent_streams
);
1148 scoped_ptr
<SpdyFrame
> settings_frame(
1149 spdy_util_
.ConstructSpdySettings(settings
));
1150 scoped_ptr
<SpdyFrame
> settings_ack(spdy_util_
.ConstructSpdySettingsAck());
1152 MockWrite writes
[] = {
1153 CreateMockWrite(*req
, 0),
1154 CreateMockWrite(*settings_ack
, 5),
1155 CreateMockWrite(*req2
, 6),
1156 CreateMockWrite(*req3
, 10),
1159 MockRead reads
[] = {
1160 CreateMockRead(*settings_frame
, 1),
1161 CreateMockRead(*resp
, 2),
1162 CreateMockRead(*body
, 3),
1163 CreateMockRead(*fbody
, 4),
1164 CreateMockRead(*resp2
, 7),
1165 CreateMockRead(*body2
, 8),
1166 CreateMockRead(*fbody2
, 9),
1167 CreateMockRead(*resp3
, 11),
1168 CreateMockRead(*body3
, 12),
1169 CreateMockRead(*fbody3
, 13),
1171 MockRead(ASYNC
, 0, 14), // EOF
1174 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
1177 TransactionHelperResult out
;
1179 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
1180 BoundNetLog(), GetParam(), NULL
);
1181 helper
.RunPreTestSetup();
1182 helper
.AddData(&data
);
1183 scoped_ptr
<HttpNetworkTransaction
> trans1(
1184 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
1185 scoped_ptr
<HttpNetworkTransaction
> trans2(
1186 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
1187 scoped_ptr
<HttpNetworkTransaction
> trans3(
1188 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
1190 TestCompletionCallback callback1
;
1191 TestCompletionCallback callback2
;
1192 TestCompletionCallback callback3
;
1194 HttpRequestInfo httpreq1
= CreateGetRequest();
1195 HttpRequestInfo httpreq2
= CreateGetRequest();
1196 HttpRequestInfo httpreq3
= CreateGetRequest();
1198 out
.rv
= trans1
->Start(&httpreq1
, callback1
.callback(), log
);
1199 ASSERT_EQ(out
.rv
, ERR_IO_PENDING
);
1200 // Run transaction 1 through quickly to force a read of our SETTINGS
1202 out
.rv
= callback1
.WaitForResult();
1203 ASSERT_EQ(OK
, out
.rv
);
1205 out
.rv
= trans2
->Start(&httpreq2
, callback2
.callback(), log
);
1206 ASSERT_EQ(out
.rv
, ERR_IO_PENDING
);
1207 out
.rv
= trans3
->Start(&httpreq3
, callback3
.callback(), log
);
1208 ASSERT_EQ(out
.rv
, ERR_IO_PENDING
);
1209 out
.rv
= callback2
.WaitForResult();
1210 ASSERT_EQ(OK
, out
.rv
);
1212 out
.rv
= callback3
.WaitForResult();
1213 ASSERT_EQ(OK
, out
.rv
);
1215 const HttpResponseInfo
* response1
= trans1
->GetResponseInfo();
1216 ASSERT_TRUE(response1
!= NULL
);
1217 EXPECT_TRUE(response1
->headers
.get() != NULL
);
1218 EXPECT_TRUE(response1
->was_fetched_via_spdy
);
1219 out
.status_line
= response1
->headers
->GetStatusLine();
1220 out
.response_info
= *response1
;
1221 out
.rv
= ReadTransaction(trans1
.get(), &out
.response_data
);
1222 EXPECT_EQ(OK
, out
.rv
);
1223 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1224 EXPECT_EQ("hello!hello!", out
.response_data
);
1226 const HttpResponseInfo
* response2
= trans2
->GetResponseInfo();
1227 out
.status_line
= response2
->headers
->GetStatusLine();
1228 out
.response_info
= *response2
;
1229 out
.rv
= ReadTransaction(trans2
.get(), &out
.response_data
);
1230 EXPECT_EQ(OK
, out
.rv
);
1231 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1232 EXPECT_EQ("hello!hello!", out
.response_data
);
1234 const HttpResponseInfo
* response3
= trans3
->GetResponseInfo();
1235 out
.status_line
= response3
->headers
->GetStatusLine();
1236 out
.response_info
= *response3
;
1237 out
.rv
= ReadTransaction(trans3
.get(), &out
.response_data
);
1238 EXPECT_EQ(OK
, out
.rv
);
1239 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1240 EXPECT_EQ("hello!hello!", out
.response_data
);
1242 helper
.VerifyDataConsumed();
1244 EXPECT_EQ(OK
, out
.rv
);
1247 // Similar to ThreeGetsWithMaxConcurrent above, however this test adds
1248 // a fourth transaction. The third and fourth transactions have
1249 // different data ("hello!" vs "hello!hello!") and because of the
1250 // user specified priority, we expect to see them inverted in
1251 // the response from the server.
1252 TEST_P(SpdyNetworkTransactionTest
, FourGetsWithMaxConcurrentPriority
) {
1253 // Construct the request.
1254 scoped_ptr
<SpdyFrame
> req(
1255 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
1256 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
1257 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, false));
1258 scoped_ptr
<SpdyFrame
> fbody(spdy_util_
.ConstructSpdyBodyFrame(1, true));
1260 scoped_ptr
<SpdyFrame
> req2(
1261 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 3, LOWEST
, true));
1262 scoped_ptr
<SpdyFrame
> resp2(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 3));
1263 scoped_ptr
<SpdyFrame
> body2(spdy_util_
.ConstructSpdyBodyFrame(3, false));
1264 scoped_ptr
<SpdyFrame
> fbody2(spdy_util_
.ConstructSpdyBodyFrame(3, true));
1266 scoped_ptr
<SpdyFrame
> req4(
1267 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 5, HIGHEST
, true));
1268 scoped_ptr
<SpdyFrame
> resp4(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 5));
1269 scoped_ptr
<SpdyFrame
> fbody4(spdy_util_
.ConstructSpdyBodyFrame(5, true));
1271 scoped_ptr
<SpdyFrame
> req3(
1272 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 7, LOWEST
, true));
1273 scoped_ptr
<SpdyFrame
> resp3(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 7));
1274 scoped_ptr
<SpdyFrame
> body3(spdy_util_
.ConstructSpdyBodyFrame(7, false));
1275 scoped_ptr
<SpdyFrame
> fbody3(spdy_util_
.ConstructSpdyBodyFrame(7, true));
1277 SettingsMap settings
;
1278 const uint32 max_concurrent_streams
= 1;
1279 settings
[SETTINGS_MAX_CONCURRENT_STREAMS
] =
1280 SettingsFlagsAndValue(SETTINGS_FLAG_NONE
, max_concurrent_streams
);
1281 scoped_ptr
<SpdyFrame
> settings_frame(
1282 spdy_util_
.ConstructSpdySettings(settings
));
1283 scoped_ptr
<SpdyFrame
> settings_ack(spdy_util_
.ConstructSpdySettingsAck());
1284 MockWrite writes
[] = {
1285 CreateMockWrite(*req
, 0),
1286 CreateMockWrite(*settings_ack
, 5),
1287 // By making these synchronous, it guarantees that they are not *started*
1288 // before their sequence number, which in turn verifies that only a single
1289 // request is in-flight at a time.
1290 CreateMockWrite(*req2
, 6, SYNCHRONOUS
),
1291 CreateMockWrite(*req4
, 10, SYNCHRONOUS
),
1292 CreateMockWrite(*req3
, 13, SYNCHRONOUS
),
1294 MockRead reads
[] = {
1295 CreateMockRead(*settings_frame
, 1),
1296 CreateMockRead(*resp
, 2),
1297 CreateMockRead(*body
, 3),
1298 CreateMockRead(*fbody
, 4),
1299 CreateMockRead(*resp2
, 7),
1300 CreateMockRead(*body2
, 8),
1301 CreateMockRead(*fbody2
, 9),
1302 CreateMockRead(*resp4
, 11),
1303 CreateMockRead(*fbody4
, 12),
1304 CreateMockRead(*resp3
, 14),
1305 CreateMockRead(*body3
, 15),
1306 CreateMockRead(*fbody3
, 16),
1308 MockRead(ASYNC
, 0, 17), // EOF
1310 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
1312 TransactionHelperResult out
;
1313 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
1314 BoundNetLog(), GetParam(), NULL
);
1315 helper
.RunPreTestSetup();
1316 helper
.AddData(&data
);
1318 scoped_ptr
<HttpNetworkTransaction
> trans1(
1319 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
1320 scoped_ptr
<HttpNetworkTransaction
> trans2(
1321 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
1322 scoped_ptr
<HttpNetworkTransaction
> trans3(
1323 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
1324 scoped_ptr
<HttpNetworkTransaction
> trans4(
1325 new HttpNetworkTransaction(HIGHEST
, helper
.session().get()));
1327 TestCompletionCallback callback1
;
1328 TestCompletionCallback callback2
;
1329 TestCompletionCallback callback3
;
1330 TestCompletionCallback callback4
;
1332 HttpRequestInfo httpreq1
= CreateGetRequest();
1333 HttpRequestInfo httpreq2
= CreateGetRequest();
1334 HttpRequestInfo httpreq3
= CreateGetRequest();
1335 HttpRequestInfo httpreq4
= CreateGetRequest();
1337 out
.rv
= trans1
->Start(&httpreq1
, callback1
.callback(), log
);
1338 ASSERT_EQ(ERR_IO_PENDING
, out
.rv
);
1339 // Run transaction 1 through quickly to force a read of our SETTINGS frame.
1340 out
.rv
= callback1
.WaitForResult();
1341 ASSERT_EQ(OK
, out
.rv
);
1343 out
.rv
= trans2
->Start(&httpreq2
, callback2
.callback(), log
);
1344 ASSERT_EQ(ERR_IO_PENDING
, out
.rv
);
1345 out
.rv
= trans3
->Start(&httpreq3
, callback3
.callback(), log
);
1346 ASSERT_EQ(ERR_IO_PENDING
, out
.rv
);
1347 out
.rv
= trans4
->Start(&httpreq4
, callback4
.callback(), log
);
1348 ASSERT_EQ(ERR_IO_PENDING
, out
.rv
);
1350 out
.rv
= callback2
.WaitForResult();
1351 ASSERT_EQ(OK
, out
.rv
);
1353 out
.rv
= callback3
.WaitForResult();
1354 ASSERT_EQ(OK
, out
.rv
);
1356 const HttpResponseInfo
* response1
= trans1
->GetResponseInfo();
1357 EXPECT_TRUE(response1
->headers
.get() != NULL
);
1358 EXPECT_TRUE(response1
->was_fetched_via_spdy
);
1359 out
.status_line
= response1
->headers
->GetStatusLine();
1360 out
.response_info
= *response1
;
1361 out
.rv
= ReadTransaction(trans1
.get(), &out
.response_data
);
1362 EXPECT_EQ(OK
, out
.rv
);
1363 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1364 EXPECT_EQ("hello!hello!", out
.response_data
);
1366 const HttpResponseInfo
* response2
= trans2
->GetResponseInfo();
1367 out
.status_line
= response2
->headers
->GetStatusLine();
1368 out
.response_info
= *response2
;
1369 out
.rv
= ReadTransaction(trans2
.get(), &out
.response_data
);
1370 EXPECT_EQ(OK
, out
.rv
);
1371 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1372 EXPECT_EQ("hello!hello!", out
.response_data
);
1374 // notice: response3 gets two hellos, response4 gets one
1375 // hello, so we know dequeuing priority was respected.
1376 const HttpResponseInfo
* response3
= trans3
->GetResponseInfo();
1377 out
.status_line
= response3
->headers
->GetStatusLine();
1378 out
.response_info
= *response3
;
1379 out
.rv
= ReadTransaction(trans3
.get(), &out
.response_data
);
1380 EXPECT_EQ(OK
, out
.rv
);
1381 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1382 EXPECT_EQ("hello!hello!", out
.response_data
);
1384 out
.rv
= callback4
.WaitForResult();
1385 EXPECT_EQ(OK
, out
.rv
);
1386 const HttpResponseInfo
* response4
= trans4
->GetResponseInfo();
1387 out
.status_line
= response4
->headers
->GetStatusLine();
1388 out
.response_info
= *response4
;
1389 out
.rv
= ReadTransaction(trans4
.get(), &out
.response_data
);
1390 EXPECT_EQ(OK
, out
.rv
);
1391 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1392 EXPECT_EQ("hello!", out
.response_data
);
1393 helper
.VerifyDataConsumed();
1394 EXPECT_EQ(OK
, out
.rv
);
1397 // Similar to ThreeGetsMaxConcurrrent above, however, this test
1398 // deletes a session in the middle of the transaction to ensure
1399 // that we properly remove pendingcreatestream objects from
1401 TEST_P(SpdyNetworkTransactionTest
, ThreeGetsWithMaxConcurrentDelete
) {
1402 // Construct the request.
1403 scoped_ptr
<SpdyFrame
> req(
1404 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
1405 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
1406 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, false));
1407 scoped_ptr
<SpdyFrame
> fbody(spdy_util_
.ConstructSpdyBodyFrame(1, true));
1409 scoped_ptr
<SpdyFrame
> req2(
1410 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 3, LOWEST
, true));
1411 scoped_ptr
<SpdyFrame
> resp2(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 3));
1412 scoped_ptr
<SpdyFrame
> body2(spdy_util_
.ConstructSpdyBodyFrame(3, false));
1413 scoped_ptr
<SpdyFrame
> fbody2(spdy_util_
.ConstructSpdyBodyFrame(3, true));
1415 SettingsMap settings
;
1416 const uint32 max_concurrent_streams
= 1;
1417 settings
[SETTINGS_MAX_CONCURRENT_STREAMS
] =
1418 SettingsFlagsAndValue(SETTINGS_FLAG_NONE
, max_concurrent_streams
);
1419 scoped_ptr
<SpdyFrame
> settings_frame(
1420 spdy_util_
.ConstructSpdySettings(settings
));
1421 scoped_ptr
<SpdyFrame
> settings_ack(spdy_util_
.ConstructSpdySettingsAck());
1423 MockWrite writes
[] = {
1424 CreateMockWrite(*req
, 0),
1425 CreateMockWrite(*settings_ack
, 5),
1426 CreateMockWrite(*req2
, 6),
1428 MockRead reads
[] = {
1429 CreateMockRead(*settings_frame
, 1),
1430 CreateMockRead(*resp
, 2),
1431 CreateMockRead(*body
, 3),
1432 CreateMockRead(*fbody
, 4),
1433 CreateMockRead(*resp2
, 7),
1434 CreateMockRead(*body2
, 8),
1435 CreateMockRead(*fbody2
, 9),
1436 MockRead(ASYNC
, 0, 10), // EOF
1439 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
1442 TransactionHelperResult out
;
1443 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
1444 BoundNetLog(), GetParam(), NULL
);
1445 helper
.RunPreTestSetup();
1446 helper
.AddData(&data
);
1447 scoped_ptr
<HttpNetworkTransaction
> trans1(
1448 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
1449 scoped_ptr
<HttpNetworkTransaction
> trans2(
1450 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
1451 scoped_ptr
<HttpNetworkTransaction
> trans3(
1452 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
1454 TestCompletionCallback callback1
;
1455 TestCompletionCallback callback2
;
1456 TestCompletionCallback callback3
;
1458 HttpRequestInfo httpreq1
= CreateGetRequest();
1459 HttpRequestInfo httpreq2
= CreateGetRequest();
1460 HttpRequestInfo httpreq3
= CreateGetRequest();
1462 out
.rv
= trans1
->Start(&httpreq1
, callback1
.callback(), log
);
1463 ASSERT_EQ(out
.rv
, ERR_IO_PENDING
);
1464 // Run transaction 1 through quickly to force a read of our SETTINGS frame.
1465 out
.rv
= callback1
.WaitForResult();
1466 ASSERT_EQ(OK
, out
.rv
);
1468 out
.rv
= trans2
->Start(&httpreq2
, callback2
.callback(), log
);
1469 ASSERT_EQ(out
.rv
, ERR_IO_PENDING
);
1470 out
.rv
= trans3
->Start(&httpreq3
, callback3
.callback(), log
);
1471 delete trans3
.release();
1472 ASSERT_EQ(out
.rv
, ERR_IO_PENDING
);
1473 out
.rv
= callback2
.WaitForResult();
1474 ASSERT_EQ(OK
, out
.rv
);
1476 const HttpResponseInfo
* response1
= trans1
->GetResponseInfo();
1477 ASSERT_TRUE(response1
!= NULL
);
1478 EXPECT_TRUE(response1
->headers
.get() != NULL
);
1479 EXPECT_TRUE(response1
->was_fetched_via_spdy
);
1480 out
.status_line
= response1
->headers
->GetStatusLine();
1481 out
.response_info
= *response1
;
1482 out
.rv
= ReadTransaction(trans1
.get(), &out
.response_data
);
1483 EXPECT_EQ(OK
, out
.rv
);
1484 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1485 EXPECT_EQ("hello!hello!", out
.response_data
);
1487 const HttpResponseInfo
* response2
= trans2
->GetResponseInfo();
1488 ASSERT_TRUE(response2
!= NULL
);
1489 out
.status_line
= response2
->headers
->GetStatusLine();
1490 out
.response_info
= *response2
;
1491 out
.rv
= ReadTransaction(trans2
.get(), &out
.response_data
);
1492 EXPECT_EQ(OK
, out
.rv
);
1493 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1494 EXPECT_EQ("hello!hello!", out
.response_data
);
1495 helper
.VerifyDataConsumed();
1496 EXPECT_EQ(OK
, out
.rv
);
1501 // The KillerCallback will delete the transaction on error as part of the
1503 class KillerCallback
: public TestCompletionCallbackBase
{
1505 explicit KillerCallback(HttpNetworkTransaction
* transaction
)
1506 : transaction_(transaction
),
1507 callback_(base::Bind(&KillerCallback::OnComplete
,
1508 base::Unretained(this))) {
1511 ~KillerCallback() override
{}
1513 const CompletionCallback
& callback() const { return callback_
; }
1516 void OnComplete(int result
) {
1518 delete transaction_
;
1523 HttpNetworkTransaction
* transaction_
;
1524 CompletionCallback callback_
;
1529 // Similar to ThreeGetsMaxConcurrrentDelete above, however, this test
1530 // closes the socket while we have a pending transaction waiting for
1531 // a pending stream creation. http://crbug.com/52901
1532 TEST_P(SpdyNetworkTransactionTest
, ThreeGetsWithMaxConcurrentSocketClose
) {
1533 // Construct the request.
1534 scoped_ptr
<SpdyFrame
> req(
1535 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
1536 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
1537 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, false));
1538 scoped_ptr
<SpdyFrame
> fin_body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
1540 scoped_ptr
<SpdyFrame
> req2(
1541 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 3, LOWEST
, true));
1542 scoped_ptr
<SpdyFrame
> resp2(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 3));
1544 SettingsMap settings
;
1545 const uint32 max_concurrent_streams
= 1;
1546 settings
[SETTINGS_MAX_CONCURRENT_STREAMS
] =
1547 SettingsFlagsAndValue(SETTINGS_FLAG_NONE
, max_concurrent_streams
);
1548 scoped_ptr
<SpdyFrame
> settings_frame(
1549 spdy_util_
.ConstructSpdySettings(settings
));
1550 scoped_ptr
<SpdyFrame
> settings_ack(spdy_util_
.ConstructSpdySettingsAck());
1552 MockWrite writes
[] = {
1553 CreateMockWrite(*req
, 0),
1554 CreateMockWrite(*settings_ack
, 5),
1555 CreateMockWrite(*req2
, 6),
1557 MockRead reads
[] = {
1558 CreateMockRead(*settings_frame
, 1),
1559 CreateMockRead(*resp
, 2),
1560 CreateMockRead(*body
, 3),
1561 CreateMockRead(*fin_body
, 4),
1562 CreateMockRead(*resp2
, 7),
1563 MockRead(ASYNC
, ERR_CONNECTION_RESET
, 8), // Abort!
1566 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
1567 SequencedSocketData
data_placeholder(NULL
, 0, NULL
, 0);
1570 TransactionHelperResult out
;
1571 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
1572 BoundNetLog(), GetParam(), NULL
);
1573 helper
.RunPreTestSetup();
1574 helper
.AddData(&data
);
1575 // We require placeholder data because three get requests are sent out, so
1576 // there needs to be three sets of SSL connection data.
1577 helper
.AddData(&data_placeholder
);
1578 helper
.AddData(&data_placeholder
);
1579 HttpNetworkTransaction
trans1(DEFAULT_PRIORITY
, helper
.session().get());
1580 HttpNetworkTransaction
trans2(DEFAULT_PRIORITY
, helper
.session().get());
1581 HttpNetworkTransaction
* trans3(
1582 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
1584 TestCompletionCallback callback1
;
1585 TestCompletionCallback callback2
;
1586 KillerCallback
callback3(trans3
);
1588 HttpRequestInfo httpreq1
= CreateGetRequest();
1589 HttpRequestInfo httpreq2
= CreateGetRequest();
1590 HttpRequestInfo httpreq3
= CreateGetRequest();
1592 out
.rv
= trans1
.Start(&httpreq1
, callback1
.callback(), log
);
1593 ASSERT_EQ(out
.rv
, ERR_IO_PENDING
);
1594 // Run transaction 1 through quickly to force a read of our SETTINGS frame.
1595 out
.rv
= callback1
.WaitForResult();
1596 ASSERT_EQ(OK
, out
.rv
);
1598 out
.rv
= trans2
.Start(&httpreq2
, callback2
.callback(), log
);
1599 ASSERT_EQ(out
.rv
, ERR_IO_PENDING
);
1600 out
.rv
= trans3
->Start(&httpreq3
, callback3
.callback(), log
);
1601 ASSERT_EQ(out
.rv
, ERR_IO_PENDING
);
1602 out
.rv
= callback3
.WaitForResult();
1603 ASSERT_EQ(ERR_ABORTED
, out
.rv
);
1605 const HttpResponseInfo
* response1
= trans1
.GetResponseInfo();
1606 ASSERT_TRUE(response1
!= NULL
);
1607 EXPECT_TRUE(response1
->headers
.get() != NULL
);
1608 EXPECT_TRUE(response1
->was_fetched_via_spdy
);
1609 out
.status_line
= response1
->headers
->GetStatusLine();
1610 out
.response_info
= *response1
;
1611 out
.rv
= ReadTransaction(&trans1
, &out
.response_data
);
1612 EXPECT_EQ(OK
, out
.rv
);
1614 const HttpResponseInfo
* response2
= trans2
.GetResponseInfo();
1615 ASSERT_TRUE(response2
!= NULL
);
1616 out
.status_line
= response2
->headers
->GetStatusLine();
1617 out
.response_info
= *response2
;
1618 out
.rv
= ReadTransaction(&trans2
, &out
.response_data
);
1619 EXPECT_EQ(ERR_CONNECTION_RESET
, out
.rv
);
1621 helper
.VerifyDataConsumed();
1624 // Test that a simple PUT request works.
1625 TEST_P(SpdyNetworkTransactionTest
, Put
) {
1626 // Setup the request
1627 HttpRequestInfo request
;
1628 request
.method
= "PUT";
1629 request
.url
= GURL(GetDefaultUrl());
1631 scoped_ptr
<SpdyHeaderBlock
> put_headers(
1632 spdy_util_
.ConstructPutHeaderBlock(GetDefaultUrl(), 0));
1633 scoped_ptr
<SpdyFrame
> req(
1634 spdy_util_
.ConstructSpdySyn(1, *put_headers
, LOWEST
, false, true));
1635 MockWrite writes
[] = {
1636 CreateMockWrite(*req
, 0),
1639 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
1640 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
1641 MockRead reads
[] = {
1642 CreateMockRead(*resp
, 1),
1643 CreateMockRead(*body
, 2),
1644 MockRead(ASYNC
, 0, 3) // EOF
1647 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
1648 NormalSpdyTransactionHelper
helper(request
, DEFAULT_PRIORITY
,
1649 BoundNetLog(), GetParam(), NULL
);
1650 helper
.RunToCompletion(&data
);
1651 TransactionHelperResult out
= helper
.output();
1653 EXPECT_EQ(OK
, out
.rv
);
1654 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1657 // Test that a simple HEAD request works.
1658 TEST_P(SpdyNetworkTransactionTest
, Head
) {
1659 // Setup the request
1660 HttpRequestInfo request
;
1661 request
.method
= "HEAD";
1662 request
.url
= GURL(GetDefaultUrl());
1664 scoped_ptr
<SpdyHeaderBlock
> head_headers(
1665 spdy_util_
.ConstructHeadHeaderBlock(GetDefaultUrl(), 0));
1666 scoped_ptr
<SpdyFrame
> req(
1667 spdy_util_
.ConstructSpdySyn(1, *head_headers
, LOWEST
, false, true));
1668 MockWrite writes
[] = {
1669 CreateMockWrite(*req
, 0),
1672 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
1673 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
1674 MockRead reads
[] = {
1675 CreateMockRead(*resp
, 1),
1676 CreateMockRead(*body
, 2),
1677 MockRead(ASYNC
, 0, 3) // EOF
1680 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
1681 NormalSpdyTransactionHelper
helper(request
, DEFAULT_PRIORITY
,
1682 BoundNetLog(), GetParam(), NULL
);
1683 helper
.RunToCompletion(&data
);
1684 TransactionHelperResult out
= helper
.output();
1686 EXPECT_EQ(OK
, out
.rv
);
1687 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1690 // Test that a simple POST works.
1691 TEST_P(SpdyNetworkTransactionTest
, Post
) {
1692 scoped_ptr
<SpdyFrame
> req(spdy_util_
.ConstructSpdyPost(
1693 GetDefaultUrl(), 1, kUploadDataSize
, LOWEST
, NULL
, 0));
1694 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
1695 MockWrite writes
[] = {
1696 CreateMockWrite(*req
, 0), CreateMockWrite(*body
, 1), // POST upload frame
1699 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyPostSynReply(NULL
, 0));
1700 MockRead reads
[] = {
1701 CreateMockRead(*resp
, 2),
1702 CreateMockRead(*body
, 3),
1703 MockRead(ASYNC
, 0, 4) // EOF
1706 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
1707 NormalSpdyTransactionHelper
helper(CreatePostRequest(), DEFAULT_PRIORITY
,
1708 BoundNetLog(), GetParam(), NULL
);
1709 helper
.RunToCompletion(&data
);
1710 TransactionHelperResult out
= helper
.output();
1711 EXPECT_EQ(OK
, out
.rv
);
1712 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1713 EXPECT_EQ("hello!", out
.response_data
);
1716 // Test that a POST with a file works.
1717 TEST_P(SpdyNetworkTransactionTest
, FilePost
) {
1718 scoped_ptr
<SpdyFrame
> req(spdy_util_
.ConstructSpdyPost(
1719 GetDefaultUrl(), 1, kUploadDataSize
, LOWEST
, NULL
, 0));
1720 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
1721 MockWrite writes
[] = {
1722 CreateMockWrite(*req
, 0), CreateMockWrite(*body
, 1), // POST upload frame
1725 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyPostSynReply(NULL
, 0));
1726 MockRead reads
[] = {
1727 CreateMockRead(*resp
, 2),
1728 CreateMockRead(*body
, 3),
1729 MockRead(ASYNC
, 0, 4) // EOF
1732 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
1733 NormalSpdyTransactionHelper
helper(CreateFilePostRequest(), DEFAULT_PRIORITY
,
1734 BoundNetLog(), GetParam(), NULL
);
1735 helper
.RunToCompletion(&data
);
1736 TransactionHelperResult out
= helper
.output();
1737 EXPECT_EQ(OK
, out
.rv
);
1738 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1739 EXPECT_EQ("hello!", out
.response_data
);
1742 // Test that a POST with a unreadable file fails.
1743 TEST_P(SpdyNetworkTransactionTest
, UnreadableFilePost
) {
1744 MockWrite writes
[] = {
1745 MockWrite(ASYNC
, 0, 0) // EOF
1747 MockRead reads
[] = {
1748 MockRead(ASYNC
, 0, 1) // EOF
1751 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
1752 NormalSpdyTransactionHelper
helper(CreateUnreadableFilePostRequest(),
1754 BoundNetLog(), GetParam(), NULL
);
1755 helper
.RunPreTestSetup();
1756 helper
.AddData(&data
);
1757 helper
.RunDefaultTest();
1759 base::RunLoop().RunUntilIdle();
1760 helper
.VerifyDataNotConsumed();
1761 EXPECT_EQ(ERR_ACCESS_DENIED
, helper
.output().rv
);
1764 // Test that a complex POST works.
1765 TEST_P(SpdyNetworkTransactionTest
, ComplexPost
) {
1766 scoped_ptr
<SpdyFrame
> req(spdy_util_
.ConstructSpdyPost(
1767 GetDefaultUrl(), 1, kUploadDataSize
, LOWEST
, NULL
, 0));
1768 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
1769 MockWrite writes
[] = {
1770 CreateMockWrite(*req
, 0), CreateMockWrite(*body
, 1), // POST upload frame
1773 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyPostSynReply(NULL
, 0));
1774 MockRead reads
[] = {
1775 CreateMockRead(*resp
, 2),
1776 CreateMockRead(*body
, 3),
1777 MockRead(ASYNC
, 0, 4) // EOF
1780 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
1781 NormalSpdyTransactionHelper
helper(CreateComplexPostRequest(),
1783 BoundNetLog(), GetParam(), NULL
);
1784 helper
.RunToCompletion(&data
);
1785 TransactionHelperResult out
= helper
.output();
1786 EXPECT_EQ(OK
, out
.rv
);
1787 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1788 EXPECT_EQ("hello!", out
.response_data
);
1791 // Test that a chunked POST works.
1792 TEST_P(SpdyNetworkTransactionTest
, ChunkedPost
) {
1793 scoped_ptr
<SpdyFrame
> req(spdy_util_
.ConstructChunkedSpdyPost(NULL
, 0));
1794 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
1795 MockWrite writes
[] = {
1796 CreateMockWrite(*req
, 0), CreateMockWrite(*body
, 1),
1799 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyPostSynReply(NULL
, 0));
1800 MockRead reads
[] = {
1801 CreateMockRead(*resp
, 2),
1802 CreateMockRead(*body
, 3),
1803 MockRead(ASYNC
, 0, 4) // EOF
1806 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
1807 NormalSpdyTransactionHelper
helper(CreateChunkedPostRequest(),
1809 BoundNetLog(), GetParam(), NULL
);
1811 // These chunks get merged into a single frame when being sent.
1812 const int kFirstChunkSize
= kUploadDataSize
/2;
1813 upload_chunked_data_stream()->AppendData(kUploadData
, kFirstChunkSize
, false);
1814 upload_chunked_data_stream()->AppendData(
1815 kUploadData
+ kFirstChunkSize
, kUploadDataSize
- kFirstChunkSize
, true);
1817 helper
.RunToCompletion(&data
);
1818 TransactionHelperResult out
= helper
.output();
1819 EXPECT_EQ(OK
, out
.rv
);
1820 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1821 EXPECT_EQ(kUploadData
, out
.response_data
);
1824 // Test that a chunked POST works with chunks appended after transaction starts.
1825 TEST_P(SpdyNetworkTransactionTest
, DelayedChunkedPost
) {
1826 scoped_ptr
<SpdyFrame
> req(spdy_util_
.ConstructChunkedSpdyPost(NULL
, 0));
1827 scoped_ptr
<SpdyFrame
> chunk1(spdy_util_
.ConstructSpdyBodyFrame(1, false));
1828 scoped_ptr
<SpdyFrame
> chunk2(spdy_util_
.ConstructSpdyBodyFrame(1, false));
1829 scoped_ptr
<SpdyFrame
> chunk3(spdy_util_
.ConstructSpdyBodyFrame(1, true));
1830 MockWrite writes
[] = {
1831 CreateMockWrite(*req
, 0),
1832 CreateMockWrite(*chunk1
, 1),
1833 CreateMockWrite(*chunk2
, 2),
1834 CreateMockWrite(*chunk3
, 3),
1837 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyPostSynReply(NULL
, 0));
1838 MockRead reads
[] = {
1839 CreateMockRead(*resp
, 4),
1840 CreateMockRead(*chunk1
, 5),
1841 CreateMockRead(*chunk2
, 6),
1842 CreateMockRead(*chunk3
, 7),
1843 MockRead(ASYNC
, 0, 8) // EOF
1846 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
1847 NormalSpdyTransactionHelper
helper(CreateChunkedPostRequest(),
1849 BoundNetLog(), GetParam(), NULL
);
1851 upload_chunked_data_stream()->AppendData(kUploadData
, kUploadDataSize
, false);
1853 helper
.RunPreTestSetup();
1854 helper
.AddData(&data
);
1855 ASSERT_TRUE(helper
.StartDefaultTest());
1857 base::RunLoop().RunUntilIdle();
1858 upload_chunked_data_stream()->AppendData(kUploadData
, kUploadDataSize
, false);
1859 base::RunLoop().RunUntilIdle();
1860 upload_chunked_data_stream()->AppendData(kUploadData
, kUploadDataSize
, true);
1862 helper
.FinishDefaultTest();
1863 helper
.VerifyDataConsumed();
1865 std::string expected_response
;
1866 expected_response
+= kUploadData
;
1867 expected_response
+= kUploadData
;
1868 expected_response
+= kUploadData
;
1870 TransactionHelperResult out
= helper
.output();
1871 EXPECT_EQ(OK
, out
.rv
);
1872 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1873 EXPECT_EQ(expected_response
, out
.response_data
);
1876 // Test that a POST without any post data works.
1877 TEST_P(SpdyNetworkTransactionTest
, NullPost
) {
1878 BufferedSpdyFramer
framer(spdy_util_
.spdy_version(), false);
1879 // Setup the request
1880 HttpRequestInfo request
;
1881 request
.method
= "POST";
1882 request
.url
= GURL(GetDefaultUrl());
1883 // Create an empty UploadData.
1884 request
.upload_data_stream
= NULL
;
1886 // When request.upload_data_stream is NULL for post, content-length is
1887 // expected to be 0.
1888 scoped_ptr
<SpdyHeaderBlock
> req_block(
1889 spdy_util_
.ConstructPostHeaderBlock(GetDefaultUrl(), 0));
1890 scoped_ptr
<SpdyFrame
> req(
1891 spdy_util_
.ConstructSpdySyn(1, *req_block
, LOWEST
, false, true));
1893 MockWrite writes
[] = {
1894 CreateMockWrite(*req
, 0),
1897 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyPostSynReply(NULL
, 0));
1898 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
1899 MockRead reads
[] = {
1900 CreateMockRead(*resp
, 1),
1901 CreateMockRead(*body
, 2),
1902 MockRead(ASYNC
, 0, 3) // EOF
1905 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
1907 NormalSpdyTransactionHelper
helper(request
, DEFAULT_PRIORITY
,
1908 BoundNetLog(), GetParam(), NULL
);
1909 helper
.RunToCompletion(&data
);
1910 TransactionHelperResult out
= helper
.output();
1911 EXPECT_EQ(OK
, out
.rv
);
1912 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1913 EXPECT_EQ("hello!", out
.response_data
);
1916 // Test that a simple POST works.
1917 TEST_P(SpdyNetworkTransactionTest
, EmptyPost
) {
1918 BufferedSpdyFramer
framer(spdy_util_
.spdy_version(), false);
1919 // Create an empty UploadDataStream.
1920 ScopedVector
<UploadElementReader
> element_readers
;
1921 ElementsUploadDataStream
stream(element_readers
.Pass(), 0);
1923 // Setup the request
1924 HttpRequestInfo request
;
1925 request
.method
= "POST";
1926 request
.url
= GURL(GetDefaultUrl());
1927 request
.upload_data_stream
= &stream
;
1929 const uint64 kContentLength
= 0;
1931 scoped_ptr
<SpdyHeaderBlock
> req_block(
1932 spdy_util_
.ConstructPostHeaderBlock(GetDefaultUrl(), kContentLength
));
1933 scoped_ptr
<SpdyFrame
> req(
1934 spdy_util_
.ConstructSpdySyn(1, *req_block
, LOWEST
, false, true));
1936 MockWrite writes
[] = {
1937 CreateMockWrite(*req
, 0),
1940 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyPostSynReply(NULL
, 0));
1941 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
1942 MockRead reads
[] = {
1943 CreateMockRead(*resp
, 1),
1944 CreateMockRead(*body
, 2),
1945 MockRead(ASYNC
, 0, 3) // EOF
1948 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
1950 NormalSpdyTransactionHelper
helper(request
, DEFAULT_PRIORITY
,
1951 BoundNetLog(), GetParam(), NULL
);
1952 helper
.RunToCompletion(&data
);
1953 TransactionHelperResult out
= helper
.output();
1954 EXPECT_EQ(OK
, out
.rv
);
1955 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1956 EXPECT_EQ("hello!", out
.response_data
);
1959 // While we're doing a post, the server sends the reply before upload completes.
1960 TEST_P(SpdyNetworkTransactionTest
, ResponseBeforePostCompletes
) {
1961 scoped_ptr
<SpdyFrame
> req(spdy_util_
.ConstructChunkedSpdyPost(NULL
, 0));
1962 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
1963 MockWrite writes
[] = {
1964 CreateMockWrite(*req
, 0),
1965 CreateMockWrite(*body
, 3),
1967 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyPostSynReply(NULL
, 0));
1968 MockRead reads
[] = {
1969 CreateMockRead(*resp
, 1),
1970 CreateMockRead(*body
, 2),
1971 MockRead(ASYNC
, 0, 4) // EOF
1974 // Write the request headers, and read the complete response
1975 // while still waiting for chunked request data.
1976 DeterministicSocketData
data(reads
, arraysize(reads
),
1977 writes
, arraysize(writes
));
1978 NormalSpdyTransactionHelper
helper(CreateChunkedPostRequest(),
1980 BoundNetLog(), GetParam(), NULL
);
1981 helper
.SetDeterministic();
1982 helper
.RunPreTestSetup();
1983 helper
.AddDeterministicData(&data
);
1985 ASSERT_TRUE(helper
.StartDefaultTest());
1987 // Process the request headers, SYN_REPLY, and response body.
1988 // The request body is still in flight.
1991 const HttpResponseInfo
* response
= helper
.trans()->GetResponseInfo();
1992 EXPECT_EQ("HTTP/1.1 200 OK", response
->headers
->GetStatusLine());
1994 // Finish sending the request body.
1995 upload_chunked_data_stream()->AppendData(kUploadData
, kUploadDataSize
, true);
1998 std::string response_body
;
1999 EXPECT_EQ(OK
, ReadTransaction(helper
.trans(), &response_body
));
2000 EXPECT_EQ(kUploadData
, response_body
);
2001 helper
.VerifyDataConsumed();
2004 // The client upon cancellation tries to send a RST_STREAM frame. The mock
2005 // socket causes the TCP write to return zero. This test checks that the client
2006 // tries to queue up the RST_STREAM frame again.
2007 TEST_P(SpdyNetworkTransactionTest
, SocketWriteReturnsZero
) {
2008 scoped_ptr
<SpdyFrame
> req(
2009 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2010 scoped_ptr
<SpdyFrame
> rst(
2011 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_CANCEL
));
2012 MockWrite writes
[] = {
2013 CreateMockWrite(*req
.get(), 0, SYNCHRONOUS
),
2014 MockWrite(SYNCHRONOUS
, 0, 0, 2),
2015 CreateMockWrite(*rst
.get(), 3, SYNCHRONOUS
),
2018 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2019 MockRead reads
[] = {
2020 CreateMockRead(*resp
.get(), 1, ASYNC
),
2021 MockRead(ASYNC
, 0, 0, 4) // EOF
2024 DeterministicSocketData
data(reads
, arraysize(reads
),
2025 writes
, arraysize(writes
));
2026 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
2027 BoundNetLog(), GetParam(), NULL
);
2028 helper
.SetDeterministic();
2029 helper
.RunPreTestSetup();
2030 helper
.AddDeterministicData(&data
);
2031 HttpNetworkTransaction
* trans
= helper
.trans();
2033 TestCompletionCallback callback
;
2034 int rv
= trans
->Start(
2035 &CreateGetRequest(), callback
.callback(), BoundNetLog());
2036 EXPECT_EQ(ERR_IO_PENDING
, rv
);
2040 helper
.ResetTrans();
2044 helper
.VerifyDataConsumed();
2047 // Test that the transaction doesn't crash when we don't have a reply.
2048 TEST_P(SpdyNetworkTransactionTest
, ResponseWithoutSynReply
) {
2049 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
2050 MockRead reads
[] = {
2051 CreateMockRead(*body
, 1), MockRead(ASYNC
, 0, 3) // EOF
2054 scoped_ptr
<SpdyFrame
> req(
2055 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2056 scoped_ptr
<SpdyFrame
> rst(
2057 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR
));
2058 MockWrite writes
[] = {
2059 CreateMockWrite(*req
, 0), CreateMockWrite(*rst
, 2),
2061 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
2062 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
2063 BoundNetLog(), GetParam(), NULL
);
2064 helper
.RunToCompletion(&data
);
2065 TransactionHelperResult out
= helper
.output();
2066 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR
, out
.rv
);
2069 // Test that the transaction doesn't crash when we get two replies on the same
2070 // stream ID. See http://crbug.com/45639.
2071 TEST_P(SpdyNetworkTransactionTest
, ResponseWithTwoSynReplies
) {
2072 scoped_ptr
<SpdyFrame
> req(
2073 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2074 scoped_ptr
<SpdyFrame
> rst(
2075 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR
));
2076 MockWrite writes
[] = {
2077 CreateMockWrite(*req
, 0), CreateMockWrite(*rst
, 4),
2080 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2081 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
2082 MockRead reads
[] = {
2083 CreateMockRead(*resp
, 1),
2084 CreateMockRead(*resp
, 2),
2085 CreateMockRead(*body
, 3),
2086 MockRead(ASYNC
, 0, 5) // EOF
2089 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
2091 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
2092 BoundNetLog(), GetParam(), NULL
);
2093 helper
.RunPreTestSetup();
2094 helper
.AddData(&data
);
2096 HttpNetworkTransaction
* trans
= helper
.trans();
2098 TestCompletionCallback callback
;
2099 int rv
= trans
->Start(&helper
.request(), callback
.callback(), BoundNetLog());
2100 EXPECT_EQ(ERR_IO_PENDING
, rv
);
2101 rv
= callback
.WaitForResult();
2104 const HttpResponseInfo
* response
= trans
->GetResponseInfo();
2105 ASSERT_TRUE(response
!= NULL
);
2106 EXPECT_TRUE(response
->headers
.get() != NULL
);
2107 EXPECT_TRUE(response
->was_fetched_via_spdy
);
2108 std::string response_data
;
2109 rv
= ReadTransaction(trans
, &response_data
);
2110 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR
, rv
);
2112 helper
.VerifyDataConsumed();
2115 TEST_P(SpdyNetworkTransactionTest
, ResetReplyWithTransferEncoding
) {
2116 // Construct the request.
2117 scoped_ptr
<SpdyFrame
> req(
2118 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2119 scoped_ptr
<SpdyFrame
> rst(
2120 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR
));
2121 MockWrite writes
[] = {
2122 CreateMockWrite(*req
, 0), CreateMockWrite(*rst
, 2),
2125 const char* const headers
[] = {
2126 "transfer-encoding", "chunked"
2128 scoped_ptr
<SpdyFrame
> resp(
2129 spdy_util_
.ConstructSpdyGetSynReply(headers
, 1, 1));
2130 scoped_ptr
<SpdyFrame
> body(
2131 spdy_util_
.ConstructSpdyBodyFrame(1, true));
2132 MockRead reads
[] = {
2133 CreateMockRead(*resp
, 1),
2134 CreateMockRead(*body
, 3),
2135 MockRead(ASYNC
, 0, 4) // EOF
2138 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
2139 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
2140 BoundNetLog(), GetParam(), NULL
);
2141 helper
.RunToCompletion(&data
);
2142 TransactionHelperResult out
= helper
.output();
2143 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR
, out
.rv
);
2145 helper
.session()->spdy_session_pool()->CloseAllSessions();
2146 helper
.VerifyDataConsumed();
2149 TEST_P(SpdyNetworkTransactionTest
, ResetPushWithTransferEncoding
) {
2150 // Construct the request.
2151 scoped_ptr
<SpdyFrame
> req(
2152 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2153 scoped_ptr
<SpdyFrame
> rst(
2154 spdy_util_
.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR
));
2155 MockWrite writes
[] = {
2156 CreateMockWrite(*req
, 0), CreateMockWrite(*rst
, 4),
2159 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2160 const char* const headers
[] = {
2161 "transfer-encoding", "chunked"
2163 scoped_ptr
<SpdyFrame
> push(
2164 spdy_util_
.ConstructSpdyPush(headers
, arraysize(headers
) / 2, 2, 1,
2165 GetDefaultUrlWithPath("/1").c_str()));
2166 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
2167 MockRead reads
[] = {
2168 CreateMockRead(*resp
, 1),
2169 CreateMockRead(*push
, 2),
2170 CreateMockRead(*body
, 3),
2171 MockRead(ASYNC
, 0, 5) // EOF
2174 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
2175 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
2176 BoundNetLog(), GetParam(), NULL
);
2177 helper
.RunToCompletion(&data
);
2178 TransactionHelperResult out
= helper
.output();
2179 EXPECT_EQ(OK
, out
.rv
);
2180 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
2181 EXPECT_EQ("hello!", out
.response_data
);
2183 helper
.session()->spdy_session_pool()->CloseAllSessions();
2184 helper
.VerifyDataConsumed();
2187 TEST_P(SpdyNetworkTransactionTest
, CancelledTransaction
) {
2188 // Construct the request.
2189 scoped_ptr
<SpdyFrame
> req(
2190 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2191 MockWrite writes
[] = {
2192 CreateMockWrite(*req
),
2195 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2196 MockRead reads
[] = {
2197 CreateMockRead(*resp
),
2198 // This following read isn't used by the test, except during the
2199 // RunUntilIdle() call at the end since the SpdySession survives the
2200 // HttpNetworkTransaction and still tries to continue Read()'ing. Any
2201 // MockRead will do here.
2202 MockRead(ASYNC
, 0, 0) // EOF
2205 StaticSocketDataProvider
data(reads
, arraysize(reads
),
2206 writes
, arraysize(writes
));
2208 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
2209 BoundNetLog(), GetParam(), NULL
);
2210 helper
.RunPreTestSetup();
2211 helper
.AddData(&data
);
2212 HttpNetworkTransaction
* trans
= helper
.trans();
2214 TestCompletionCallback callback
;
2215 int rv
= trans
->Start(
2216 &CreateGetRequest(), callback
.callback(), BoundNetLog());
2217 EXPECT_EQ(ERR_IO_PENDING
, rv
);
2218 helper
.ResetTrans(); // Cancel the transaction.
2220 // Flush the MessageLoop while the SpdySessionDependencies (in particular, the
2221 // MockClientSocketFactory) are still alive.
2222 base::RunLoop().RunUntilIdle();
2223 helper
.VerifyDataNotConsumed();
2226 // Verify that the client sends a Rst Frame upon cancelling the stream.
2227 TEST_P(SpdyNetworkTransactionTest
, CancelledTransactionSendRst
) {
2228 scoped_ptr
<SpdyFrame
> req(
2229 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2230 scoped_ptr
<SpdyFrame
> rst(
2231 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_CANCEL
));
2232 MockWrite writes
[] = {
2233 CreateMockWrite(*req
, 0, SYNCHRONOUS
),
2234 CreateMockWrite(*rst
, 2, SYNCHRONOUS
),
2237 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2238 MockRead reads
[] = {
2239 CreateMockRead(*resp
, 1, ASYNC
),
2240 MockRead(ASYNC
, 0, 0, 3) // EOF
2243 DeterministicSocketData
data(reads
, arraysize(reads
),
2244 writes
, arraysize(writes
));
2246 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
2249 helper
.SetDeterministic();
2250 helper
.RunPreTestSetup();
2251 helper
.AddDeterministicData(&data
);
2252 HttpNetworkTransaction
* trans
= helper
.trans();
2254 TestCompletionCallback callback
;
2256 int rv
= trans
->Start(
2257 &CreateGetRequest(), callback
.callback(), BoundNetLog());
2258 EXPECT_EQ(ERR_IO_PENDING
, rv
);
2262 helper
.ResetTrans();
2266 helper
.VerifyDataConsumed();
2269 // Verify that the client can correctly deal with the user callback attempting
2270 // to start another transaction on a session that is closing down. See
2271 // http://crbug.com/47455
2272 TEST_P(SpdyNetworkTransactionTest
, StartTransactionOnReadCallback
) {
2273 scoped_ptr
<SpdyFrame
> req(
2274 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2275 MockWrite writes
[] = {CreateMockWrite(*req
)};
2276 MockWrite writes2
[] = {CreateMockWrite(*req
, 0)};
2278 // The indicated length of this frame is longer than its actual length. When
2279 // the session receives an empty frame after this one, it shuts down the
2280 // session, and calls the read callback with the incomplete data.
2281 const uint8 kGetBodyFrame2
[] = {
2282 0x00, 0x00, 0x00, 0x01,
2283 0x01, 0x00, 0x00, 0x07,
2284 'h', 'e', 'l', 'l', 'o', '!',
2287 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2288 MockRead reads
[] = {
2289 CreateMockRead(*resp
, 1),
2290 MockRead(ASYNC
, ERR_IO_PENDING
, 2), // Force a pause
2291 MockRead(ASYNC
, reinterpret_cast<const char*>(kGetBodyFrame2
),
2292 arraysize(kGetBodyFrame2
), 3),
2293 MockRead(ASYNC
, ERR_IO_PENDING
, 4), // Force a pause
2294 MockRead(ASYNC
, 0, 0, 5), // EOF
2296 MockRead reads2
[] = {
2297 CreateMockRead(*resp
, 1), MockRead(ASYNC
, 0, 0, 2), // EOF
2300 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
2301 SequencedSocketData
data2(reads2
, arraysize(reads2
), writes2
,
2302 arraysize(writes2
));
2304 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
2305 BoundNetLog(), GetParam(), NULL
);
2306 helper
.RunPreTestSetup();
2307 helper
.AddData(&data
);
2308 helper
.AddData(&data2
);
2309 HttpNetworkTransaction
* trans
= helper
.trans();
2311 // Start the transaction with basic parameters.
2312 TestCompletionCallback callback
;
2313 int rv
= trans
->Start(&helper
.request(), callback
.callback(), BoundNetLog());
2314 EXPECT_EQ(ERR_IO_PENDING
, rv
);
2315 rv
= callback
.WaitForResult();
2317 const int kSize
= 3000;
2318 scoped_refptr
<IOBuffer
> buf(new IOBuffer(kSize
));
2321 base::Bind(&SpdyNetworkTransactionTest::StartTransactionCallback
,
2322 helper
.session(), GURL(GetDefaultUrl())));
2323 ASSERT_EQ(ERR_IO_PENDING
, rv
);
2324 // This forces an err_IO_pending, which sets the callback.
2325 data
.CompleteRead();
2326 // This finishes the read.
2327 data
.CompleteRead();
2328 helper
.VerifyDataConsumed();
2331 // Verify that the client can correctly deal with the user callback deleting the
2332 // transaction. Failures will usually be valgrind errors. See
2333 // http://crbug.com/46925
2334 TEST_P(SpdyNetworkTransactionTest
, DeleteSessionOnReadCallback
) {
2335 scoped_ptr
<SpdyFrame
> req(
2336 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2337 MockWrite writes
[] = {CreateMockWrite(*req
, 0)};
2339 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2340 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
2341 MockRead reads
[] = {
2342 CreateMockRead(*resp
.get(), 1),
2343 MockRead(ASYNC
, ERR_IO_PENDING
, 2), // Force a pause
2344 CreateMockRead(*body
.get(), 3),
2345 MockRead(ASYNC
, 0, 0, 4), // EOF
2348 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
2350 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
2351 BoundNetLog(), GetParam(), NULL
);
2352 helper
.RunPreTestSetup();
2353 helper
.AddData(&data
);
2354 HttpNetworkTransaction
* trans
= helper
.trans();
2356 // Start the transaction with basic parameters.
2357 TestCompletionCallback callback
;
2358 int rv
= trans
->Start(&helper
.request(), callback
.callback(), BoundNetLog());
2359 EXPECT_EQ(ERR_IO_PENDING
, rv
);
2360 rv
= callback
.WaitForResult();
2362 // Setup a user callback which will delete the session, and clear out the
2363 // memory holding the stream object. Note that the callback deletes trans.
2364 const int kSize
= 3000;
2365 scoped_refptr
<IOBuffer
> buf(new IOBuffer(kSize
));
2369 base::Bind(&SpdyNetworkTransactionTest::DeleteSessionCallback
,
2370 base::Unretained(&helper
)));
2371 ASSERT_EQ(ERR_IO_PENDING
, rv
);
2372 data
.CompleteRead();
2374 // Finish running rest of tasks.
2375 base::RunLoop().RunUntilIdle();
2376 helper
.VerifyDataConsumed();
2379 // Send a spdy request to www.example.org that gets redirected to www.foo.com.
2380 TEST_P(SpdyNetworkTransactionTest
, DISABLED_RedirectGetRequest
) {
2381 scoped_ptr
<SpdyHeaderBlock
> headers(
2382 spdy_util_
.ConstructGetHeaderBlock(GetDefaultUrl()));
2383 (*headers
)["user-agent"] = "";
2384 (*headers
)["accept-encoding"] = "gzip, deflate";
2385 scoped_ptr
<SpdyHeaderBlock
> headers2(
2386 spdy_util_
.ConstructGetHeaderBlock("http://www.foo.com/index.php"));
2387 (*headers2
)["user-agent"] = "";
2388 (*headers2
)["accept-encoding"] = "gzip, deflate";
2390 // Setup writes/reads to www.example.org
2391 scoped_ptr
<SpdyFrame
> req(
2392 spdy_util_
.ConstructSpdySyn(1, *headers
, LOWEST
, false, true));
2393 scoped_ptr
<SpdyFrame
> req2(
2394 spdy_util_
.ConstructSpdySyn(1, *headers2
, LOWEST
, false, true));
2395 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReplyRedirect(1));
2396 MockWrite writes
[] = {
2397 CreateMockWrite(*req
, 1),
2399 MockRead reads
[] = {
2400 CreateMockRead(*resp
, 2),
2401 MockRead(ASYNC
, 0, 0, 3) // EOF
2404 // Setup writes/reads to www.foo.com
2405 scoped_ptr
<SpdyFrame
> resp2(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2406 scoped_ptr
<SpdyFrame
> body2(spdy_util_
.ConstructSpdyBodyFrame(1, true));
2407 MockWrite writes2
[] = {
2408 CreateMockWrite(*req2
, 1),
2410 MockRead reads2
[] = {
2411 CreateMockRead(*resp2
, 2),
2412 CreateMockRead(*body2
, 3),
2413 MockRead(ASYNC
, 0, 0, 4) // EOF
2415 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
2416 SequencedSocketData
data2(reads2
, arraysize(reads2
), writes2
,
2417 arraysize(writes2
));
2419 // TODO(erikchen): Make test support SPDYSSL, SPDYNPN
2422 SpdyURLRequestContext
spdy_url_request_context(GetParam().protocol
);
2423 scoped_ptr
<URLRequest
> r(spdy_url_request_context
.CreateRequest(
2424 GURL(GetDefaultUrl()), DEFAULT_PRIORITY
, &d
));
2425 spdy_url_request_context
.socket_factory().
2426 AddSocketDataProvider(&data
);
2427 spdy_url_request_context
.socket_factory().
2428 AddSocketDataProvider(&data2
);
2430 d
.set_quit_on_redirect(true);
2432 base::RunLoop().Run();
2434 EXPECT_EQ(1, d
.received_redirect_count());
2436 r
->FollowDeferredRedirect();
2437 base::RunLoop().Run();
2438 EXPECT_EQ(1, d
.response_started_count());
2439 EXPECT_FALSE(d
.received_data_before_response());
2440 EXPECT_EQ(URLRequestStatus::SUCCESS
, r
->status().status());
2441 std::string
contents("hello!");
2442 EXPECT_EQ(contents
, d
.data_received());
2444 EXPECT_TRUE(data
.AllReadDataConsumed());
2445 EXPECT_TRUE(data
.AllWriteDataConsumed());
2446 EXPECT_TRUE(data2
.AllReadDataConsumed());
2447 EXPECT_TRUE(data2
.AllWriteDataConsumed());
2450 // Send a spdy request to www.example.org. Get a pushed stream that redirects to
2452 TEST_P(SpdyNetworkTransactionTest
, DISABLED_RedirectServerPush
) {
2453 scoped_ptr
<SpdyHeaderBlock
> headers(
2454 spdy_util_
.ConstructGetHeaderBlock(GetDefaultUrl()));
2455 (*headers
)["user-agent"] = "";
2456 (*headers
)["accept-encoding"] = "gzip, deflate";
2458 // Setup writes/reads to www.example.org
2459 scoped_ptr
<SpdyFrame
> req(
2460 spdy_util_
.ConstructSpdySyn(1, *headers
, LOWEST
, false, true));
2461 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2462 scoped_ptr
<SpdyFrame
> rep(spdy_util_
.ConstructSpdyPush(
2463 NULL
, 0, 2, 1, GetDefaultUrlWithPath("/foo.dat").c_str(),
2464 "301 Moved Permanently", "http://www.foo.com/index.php"));
2465 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
2466 scoped_ptr
<SpdyFrame
> rst(
2467 spdy_util_
.ConstructSpdyRstStream(2, RST_STREAM_CANCEL
));
2468 MockWrite writes
[] = {
2469 CreateMockWrite(*req
, 1),
2470 CreateMockWrite(*rst
, 6),
2472 MockRead reads
[] = {
2473 CreateMockRead(*resp
, 2),
2474 CreateMockRead(*rep
, 3),
2475 CreateMockRead(*body
, 4),
2476 MockRead(ASYNC
, ERR_IO_PENDING
, 5), // Force a pause
2477 MockRead(ASYNC
, 0, 0, 7) // EOF
2480 // Setup writes/reads to www.foo.com
2481 scoped_ptr
<SpdyHeaderBlock
> headers2(
2482 spdy_util_
.ConstructGetHeaderBlock("http://www.foo.com/index.php"));
2483 (*headers2
)["user-agent"] = "";
2484 (*headers2
)["accept-encoding"] = "gzip, deflate";
2485 scoped_ptr
<SpdyFrame
> req2(
2486 spdy_util_
.ConstructSpdySyn(1, *headers2
, LOWEST
, false, true));
2487 scoped_ptr
<SpdyFrame
> resp2(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2488 scoped_ptr
<SpdyFrame
> body2(spdy_util_
.ConstructSpdyBodyFrame(1, true));
2489 MockWrite writes2
[] = {
2490 CreateMockWrite(*req2
, 1),
2492 MockRead reads2
[] = {
2493 CreateMockRead(*resp2
, 2),
2494 CreateMockRead(*body2
, 3),
2495 MockRead(ASYNC
, 0, 0, 5) // EOF
2497 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
2498 SequencedSocketData
data2(reads2
, arraysize(reads2
), writes2
,
2499 arraysize(writes2
));
2501 // TODO(erikchen): Make test support SPDYSSL, SPDYNPN
2504 SpdyURLRequestContext
spdy_url_request_context(GetParam().protocol
);
2506 scoped_ptr
<URLRequest
> r(spdy_url_request_context
.CreateRequest(
2507 GURL(GetDefaultUrl()), DEFAULT_PRIORITY
, &d
));
2508 spdy_url_request_context
.socket_factory().
2509 AddSocketDataProvider(&data
);
2512 base::RunLoop().Run();
2514 EXPECT_EQ(0, d
.received_redirect_count());
2515 std::string
contents("hello!");
2516 EXPECT_EQ(contents
, d
.data_received());
2518 scoped_ptr
<URLRequest
> r2(spdy_url_request_context
.CreateRequest(
2519 GURL(GetDefaultUrlWithPath("/foo.dat")), DEFAULT_PRIORITY
, &d2
));
2520 spdy_url_request_context
.socket_factory().
2521 AddSocketDataProvider(&data2
);
2523 d2
.set_quit_on_redirect(true);
2525 base::RunLoop().Run();
2526 EXPECT_EQ(1, d2
.received_redirect_count());
2528 r2
->FollowDeferredRedirect();
2529 base::RunLoop().Run();
2530 EXPECT_EQ(1, d2
.response_started_count());
2531 EXPECT_FALSE(d2
.received_data_before_response());
2532 EXPECT_EQ(URLRequestStatus::SUCCESS
, r2
->status().status());
2533 std::string
contents2("hello!");
2534 EXPECT_EQ(contents2
, d2
.data_received());
2536 EXPECT_TRUE(data
.AllReadDataConsumed());
2537 EXPECT_TRUE(data
.AllWriteDataConsumed());
2538 EXPECT_TRUE(data2
.AllReadDataConsumed());
2539 EXPECT_TRUE(data2
.AllWriteDataConsumed());
2542 TEST_P(SpdyNetworkTransactionTest
, ServerPushSingleDataFrame
) {
2543 scoped_ptr
<SpdyFrame
> stream1_syn(
2544 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2545 scoped_ptr
<SpdyFrame
> stream1_body(
2546 spdy_util_
.ConstructSpdyBodyFrame(1, true));
2547 MockWrite writes
[] = {
2548 CreateMockWrite(*stream1_syn
, 0),
2551 scoped_ptr
<SpdyFrame
>
2552 stream1_reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2553 scoped_ptr
<SpdyFrame
> stream2_syn(spdy_util_
.ConstructSpdyPush(
2554 NULL
, 0, 2, 1, GetDefaultUrlWithPath("/foo.dat").c_str()));
2555 const char kPushedData
[] = "pushed";
2556 scoped_ptr
<SpdyFrame
> stream2_body(
2557 spdy_util_
.ConstructSpdyBodyFrame(
2558 2, kPushedData
, strlen(kPushedData
), true));
2559 MockRead reads
[] = {
2560 CreateMockRead(*stream1_reply
, 1),
2561 CreateMockRead(*stream2_syn
, 2),
2562 CreateMockRead(*stream1_body
, 3, SYNCHRONOUS
),
2563 CreateMockRead(*stream2_body
, 4),
2564 MockRead(SYNCHRONOUS
, ERR_IO_PENDING
, 5), // Force a pause
2567 HttpResponseInfo response
;
2568 HttpResponseInfo response2
;
2569 std::string
expected_push_result("pushed");
2570 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
2571 RunServerPushTest(&data
,
2574 expected_push_result
);
2576 // Verify the SYN_REPLY.
2577 EXPECT_TRUE(response
.headers
.get() != NULL
);
2578 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
2580 // Verify the pushed stream.
2581 EXPECT_TRUE(response2
.headers
.get() != NULL
);
2582 EXPECT_EQ("HTTP/1.1 200 OK", response2
.headers
->GetStatusLine());
2585 TEST_P(SpdyNetworkTransactionTest
, ServerPushBeforeSynReply
) {
2586 scoped_ptr
<SpdyFrame
> stream1_syn(
2587 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2588 scoped_ptr
<SpdyFrame
> stream1_body(
2589 spdy_util_
.ConstructSpdyBodyFrame(1, true));
2590 MockWrite writes
[] = {
2591 CreateMockWrite(*stream1_syn
, 0),
2594 scoped_ptr
<SpdyFrame
>
2595 stream1_reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2596 scoped_ptr
<SpdyFrame
> stream2_syn(spdy_util_
.ConstructSpdyPush(
2597 NULL
, 0, 2, 1, GetDefaultUrlWithPath("/foo.dat").c_str()));
2598 const char kPushedData
[] = "pushed";
2599 scoped_ptr
<SpdyFrame
> stream2_body(
2600 spdy_util_
.ConstructSpdyBodyFrame(
2601 2, kPushedData
, strlen(kPushedData
), true));
2602 MockRead reads
[] = {
2603 CreateMockRead(*stream2_syn
, 1),
2604 CreateMockRead(*stream1_reply
, 2),
2605 CreateMockRead(*stream1_body
, 3, SYNCHRONOUS
),
2606 CreateMockRead(*stream2_body
, 4),
2607 MockRead(SYNCHRONOUS
, ERR_IO_PENDING
, 5), // Force a pause
2610 HttpResponseInfo response
;
2611 HttpResponseInfo response2
;
2612 std::string
expected_push_result("pushed");
2613 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
2614 RunServerPushTest(&data
,
2617 expected_push_result
);
2619 // Verify the SYN_REPLY.
2620 EXPECT_TRUE(response
.headers
.get() != NULL
);
2621 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
2623 // Verify the pushed stream.
2624 EXPECT_TRUE(response2
.headers
.get() != NULL
);
2625 EXPECT_EQ("HTTP/1.1 200 OK", response2
.headers
->GetStatusLine());
2628 TEST_P(SpdyNetworkTransactionTest
, ServerPushSingleDataFrame2
) {
2629 scoped_ptr
<SpdyFrame
> stream1_syn(
2630 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2631 MockWrite writes
[] = {
2632 CreateMockWrite(*stream1_syn
, 0),
2635 scoped_ptr
<SpdyFrame
>
2636 stream1_reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2637 scoped_ptr
<SpdyFrame
> stream2_syn(spdy_util_
.ConstructSpdyPush(
2638 NULL
, 0, 2, 1, GetDefaultUrlWithPath("/foo.dat").c_str()));
2639 const char kPushedData
[] = "pushed";
2640 scoped_ptr
<SpdyFrame
> stream2_body(
2641 spdy_util_
.ConstructSpdyBodyFrame(
2642 2, kPushedData
, strlen(kPushedData
), true));
2643 scoped_ptr
<SpdyFrame
>
2644 stream1_body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
2645 MockRead reads
[] = {
2646 CreateMockRead(*stream1_reply
, 1),
2647 CreateMockRead(*stream2_syn
, 2),
2648 CreateMockRead(*stream2_body
, 3),
2649 CreateMockRead(*stream1_body
, 4, SYNCHRONOUS
),
2650 MockRead(SYNCHRONOUS
, ERR_IO_PENDING
, 5), // Force a pause
2653 HttpResponseInfo response
;
2654 HttpResponseInfo response2
;
2655 std::string
expected_push_result("pushed");
2656 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
2657 RunServerPushTest(&data
,
2660 expected_push_result
);
2662 // Verify the SYN_REPLY.
2663 EXPECT_TRUE(response
.headers
.get() != NULL
);
2664 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
2666 // Verify the pushed stream.
2667 EXPECT_TRUE(response2
.headers
.get() != NULL
);
2668 EXPECT_EQ("HTTP/1.1 200 OK", response2
.headers
->GetStatusLine());
2671 TEST_P(SpdyNetworkTransactionTest
, ServerPushServerAborted
) {
2672 scoped_ptr
<SpdyFrame
> stream1_syn(
2673 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2674 scoped_ptr
<SpdyFrame
> stream1_body(
2675 spdy_util_
.ConstructSpdyBodyFrame(1, true));
2676 MockWrite writes
[] = {
2677 CreateMockWrite(*stream1_syn
, 0),
2680 scoped_ptr
<SpdyFrame
>
2681 stream1_reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2682 scoped_ptr
<SpdyFrame
> stream2_syn(spdy_util_
.ConstructSpdyPush(
2683 NULL
, 0, 2, 1, GetDefaultUrlWithPath("/foo.dat").c_str()));
2684 scoped_ptr
<SpdyFrame
> stream2_rst(
2685 spdy_util_
.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR
));
2686 MockRead reads
[] = {
2687 CreateMockRead(*stream1_reply
, 1),
2688 CreateMockRead(*stream2_syn
, 2),
2689 CreateMockRead(*stream2_rst
, 3),
2690 CreateMockRead(*stream1_body
, 4, SYNCHRONOUS
),
2691 MockRead(SYNCHRONOUS
, ERR_IO_PENDING
, 5), // Force a pause
2694 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
2695 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
2696 BoundNetLog(), GetParam(), NULL
);
2698 helper
.RunPreTestSetup();
2699 helper
.AddData(&data
);
2701 HttpNetworkTransaction
* trans
= helper
.trans();
2703 // Start the transaction with basic parameters.
2704 TestCompletionCallback callback
;
2705 int rv
= trans
->Start(
2706 &CreateGetRequest(), callback
.callback(), BoundNetLog());
2707 EXPECT_EQ(ERR_IO_PENDING
, rv
);
2708 rv
= callback
.WaitForResult();
2711 // Verify that we consumed all test data.
2712 EXPECT_TRUE(data
.AllReadDataConsumed());
2713 EXPECT_TRUE(data
.AllWriteDataConsumed());
2715 // Verify the SYN_REPLY.
2716 HttpResponseInfo response
= *trans
->GetResponseInfo();
2717 EXPECT_TRUE(response
.headers
.get() != NULL
);
2718 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
2721 // Verify that we don't leak streams and that we properly send a reset
2722 // if the server pushes the same stream twice.
2723 TEST_P(SpdyNetworkTransactionTest
, ServerPushDuplicate
) {
2724 scoped_ptr
<SpdyFrame
> stream1_syn(
2725 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2726 scoped_ptr
<SpdyFrame
> stream1_body(
2727 spdy_util_
.ConstructSpdyBodyFrame(1, true));
2728 scoped_ptr
<SpdyFrame
> stream3_rst(
2729 spdy_util_
.ConstructSpdyRstStream(4, RST_STREAM_PROTOCOL_ERROR
));
2730 MockWrite writes
[] = {
2731 CreateMockWrite(*stream1_syn
, 0), CreateMockWrite(*stream3_rst
, 4),
2734 scoped_ptr
<SpdyFrame
>
2735 stream1_reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2736 scoped_ptr
<SpdyFrame
> stream2_syn(spdy_util_
.ConstructSpdyPush(
2737 NULL
, 0, 2, 1, GetDefaultUrlWithPath("/foo.dat").c_str()));
2738 const char kPushedData
[] = "pushed";
2739 scoped_ptr
<SpdyFrame
> stream2_body(
2740 spdy_util_
.ConstructSpdyBodyFrame(
2741 2, kPushedData
, strlen(kPushedData
), true));
2742 scoped_ptr
<SpdyFrame
> stream3_syn(spdy_util_
.ConstructSpdyPush(
2743 NULL
, 0, 4, 1, GetDefaultUrlWithPath("/foo.dat").c_str()));
2744 MockRead reads
[] = {
2745 CreateMockRead(*stream1_reply
, 1),
2746 CreateMockRead(*stream2_syn
, 2),
2747 CreateMockRead(*stream3_syn
, 3),
2748 CreateMockRead(*stream1_body
, 5),
2749 CreateMockRead(*stream2_body
, 6),
2750 MockRead(SYNCHRONOUS
, ERR_IO_PENDING
, 7), // Force a pause
2753 HttpResponseInfo response
;
2754 HttpResponseInfo response2
;
2755 std::string
expected_push_result("pushed");
2756 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
2757 RunServerPushTest(&data
,
2760 expected_push_result
);
2762 // Verify the SYN_REPLY.
2763 EXPECT_TRUE(response
.headers
.get() != NULL
);
2764 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
2766 // Verify the pushed stream.
2767 EXPECT_TRUE(response2
.headers
.get() != NULL
);
2768 EXPECT_EQ("HTTP/1.1 200 OK", response2
.headers
->GetStatusLine());
2771 TEST_P(SpdyNetworkTransactionTest
, ServerPushMultipleDataFrame
) {
2772 scoped_ptr
<SpdyFrame
> stream1_syn(
2773 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2774 scoped_ptr
<SpdyFrame
> stream1_body(
2775 spdy_util_
.ConstructSpdyBodyFrame(1, true));
2776 MockWrite writes
[] = {
2777 CreateMockWrite(*stream1_syn
, 0),
2780 scoped_ptr
<SpdyFrame
>
2781 stream1_reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2782 scoped_ptr
<SpdyFrame
> stream2_syn(spdy_util_
.ConstructSpdyPush(
2783 NULL
, 0, 2, 1, GetDefaultUrlWithPath("/foo.dat").c_str()));
2784 static const char kPushedData
[] = "pushed my darling hello my baby";
2785 scoped_ptr
<SpdyFrame
> stream2_body_base(
2786 spdy_util_
.ConstructSpdyBodyFrame(
2787 2, kPushedData
, strlen(kPushedData
), true));
2788 const size_t kChunkSize
= strlen(kPushedData
) / 4;
2789 scoped_ptr
<SpdyFrame
> stream2_body1(
2790 new SpdyFrame(stream2_body_base
->data(), kChunkSize
, false));
2791 scoped_ptr
<SpdyFrame
> stream2_body2(
2792 new SpdyFrame(stream2_body_base
->data() + kChunkSize
, kChunkSize
, false));
2793 scoped_ptr
<SpdyFrame
> stream2_body3(
2794 new SpdyFrame(stream2_body_base
->data() + 2 * kChunkSize
,
2795 kChunkSize
, false));
2796 scoped_ptr
<SpdyFrame
> stream2_body4(
2797 new SpdyFrame(stream2_body_base
->data() + 3 * kChunkSize
,
2798 stream2_body_base
->size() - 3 * kChunkSize
, false));
2799 MockRead reads
[] = {
2800 CreateMockRead(*stream1_reply
, 1),
2801 CreateMockRead(*stream2_syn
, 2),
2802 CreateMockRead(*stream2_body1
, 3),
2803 CreateMockRead(*stream2_body2
, 4),
2804 CreateMockRead(*stream2_body3
, 5),
2805 CreateMockRead(*stream2_body4
, 6),
2806 CreateMockRead(*stream1_body
, 7, SYNCHRONOUS
),
2807 MockRead(SYNCHRONOUS
, ERR_IO_PENDING
, 8), // Force a pause
2810 HttpResponseInfo response
;
2811 HttpResponseInfo response2
;
2812 std::string
expected_push_result("pushed my darling hello my baby");
2813 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
2814 RunServerPushTest(&data
, &response
, &response2
, kPushedData
);
2816 // Verify the SYN_REPLY.
2817 EXPECT_TRUE(response
.headers
.get() != NULL
);
2818 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
2820 // Verify the pushed stream.
2821 EXPECT_TRUE(response2
.headers
.get() != NULL
);
2822 EXPECT_EQ("HTTP/1.1 200 OK", response2
.headers
->GetStatusLine());
2825 TEST_P(SpdyNetworkTransactionTest
, ServerPushMultipleDataFrameInterrupted
) {
2826 scoped_ptr
<SpdyFrame
> stream1_syn(
2827 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2828 scoped_ptr
<SpdyFrame
> stream1_body(
2829 spdy_util_
.ConstructSpdyBodyFrame(1, true));
2830 MockWrite writes
[] = {
2831 CreateMockWrite(*stream1_syn
, 0),
2834 scoped_ptr
<SpdyFrame
>
2835 stream1_reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2836 scoped_ptr
<SpdyFrame
> stream2_syn(spdy_util_
.ConstructSpdyPush(
2837 NULL
, 0, 2, 1, GetDefaultUrlWithPath("/foo.dat").c_str()));
2838 static const char kPushedData
[] = "pushed my darling hello my baby";
2839 scoped_ptr
<SpdyFrame
> stream2_body_base(
2840 spdy_util_
.ConstructSpdyBodyFrame(
2841 2, kPushedData
, strlen(kPushedData
), true));
2842 const size_t kChunkSize
= strlen(kPushedData
) / 4;
2843 scoped_ptr
<SpdyFrame
> stream2_body1(
2844 new SpdyFrame(stream2_body_base
->data(), kChunkSize
, false));
2845 scoped_ptr
<SpdyFrame
> stream2_body2(
2846 new SpdyFrame(stream2_body_base
->data() + kChunkSize
, kChunkSize
, false));
2847 scoped_ptr
<SpdyFrame
> stream2_body3(
2848 new SpdyFrame(stream2_body_base
->data() + 2 * kChunkSize
,
2849 kChunkSize
, false));
2850 scoped_ptr
<SpdyFrame
> stream2_body4(
2851 new SpdyFrame(stream2_body_base
->data() + 3 * kChunkSize
,
2852 stream2_body_base
->size() - 3 * kChunkSize
, false));
2853 MockRead reads
[] = {
2854 CreateMockRead(*stream1_reply
, 1),
2855 CreateMockRead(*stream2_syn
, 2),
2856 CreateMockRead(*stream2_body1
, 3),
2857 CreateMockRead(*stream2_body2
, 4),
2858 CreateMockRead(*stream2_body3
, 5),
2859 CreateMockRead(*stream2_body4
, 6),
2860 CreateMockRead(*stream1_body
.get(), 7, SYNCHRONOUS
),
2861 MockRead(SYNCHRONOUS
, ERR_IO_PENDING
, 8) // Force a pause.
2864 HttpResponseInfo response
;
2865 HttpResponseInfo response2
;
2866 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
2867 RunServerPushTest(&data
, &response
, &response2
, kPushedData
);
2869 // Verify the SYN_REPLY.
2870 EXPECT_TRUE(response
.headers
.get() != NULL
);
2871 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
2873 // Verify the pushed stream.
2874 EXPECT_TRUE(response2
.headers
.get() != NULL
);
2875 EXPECT_EQ("HTTP/1.1 200 OK", response2
.headers
->GetStatusLine());
2878 TEST_P(SpdyNetworkTransactionTest
, ServerPushInvalidAssociatedStreamID0
) {
2879 if (spdy_util_
.spdy_version() == HTTP2
) {
2880 // PUSH_PROMISE with stream id 0 is connection-level error.
2881 // TODO(baranovich): Test session going away.
2885 scoped_ptr
<SpdyFrame
> stream1_syn(
2886 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2887 scoped_ptr
<SpdyFrame
> stream1_body(
2888 spdy_util_
.ConstructSpdyBodyFrame(1, true));
2889 scoped_ptr
<SpdyFrame
> stream2_rst(
2890 spdy_util_
.ConstructSpdyRstStream(2, RST_STREAM_REFUSED_STREAM
));
2891 MockWrite writes
[] = {
2892 CreateMockWrite(*stream1_syn
, 0), CreateMockWrite(*stream2_rst
, 3),
2895 scoped_ptr
<SpdyFrame
>
2896 stream1_reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2897 scoped_ptr
<SpdyFrame
> stream2_syn(spdy_util_
.ConstructSpdyPush(
2898 NULL
, 0, 2, 0, GetDefaultUrlWithPath("/foo.dat").c_str()));
2899 MockRead reads
[] = {
2900 CreateMockRead(*stream1_reply
, 1),
2901 CreateMockRead(*stream2_syn
, 2),
2902 CreateMockRead(*stream1_body
, 4),
2903 MockRead(SYNCHRONOUS
, ERR_IO_PENDING
, 5) // Force a pause
2906 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
2907 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
2908 BoundNetLog(), GetParam(), NULL
);
2910 helper
.RunPreTestSetup();
2911 helper
.AddData(&data
);
2913 HttpNetworkTransaction
* trans
= helper
.trans();
2915 // Start the transaction with basic parameters.
2916 TestCompletionCallback callback
;
2917 int rv
= trans
->Start(
2918 &CreateGetRequest(), callback
.callback(), BoundNetLog());
2919 EXPECT_EQ(ERR_IO_PENDING
, rv
);
2920 rv
= callback
.WaitForResult();
2923 // Verify that we consumed all test data.
2924 EXPECT_TRUE(data
.AllReadDataConsumed());
2925 EXPECT_TRUE(data
.AllWriteDataConsumed());
2927 // Verify the SYN_REPLY.
2928 HttpResponseInfo response
= *trans
->GetResponseInfo();
2929 EXPECT_TRUE(response
.headers
.get() != NULL
);
2930 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
2933 TEST_P(SpdyNetworkTransactionTest
, ServerPushInvalidAssociatedStreamID9
) {
2934 scoped_ptr
<SpdyFrame
> stream1_syn(
2935 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2936 scoped_ptr
<SpdyFrame
> stream1_body(
2937 spdy_util_
.ConstructSpdyBodyFrame(1, true));
2938 scoped_ptr
<SpdyFrame
> stream2_rst(
2939 spdy_util_
.ConstructSpdyRstStream(2, RST_STREAM_INVALID_STREAM
));
2940 MockWrite writes
[] = {
2941 CreateMockWrite(*stream1_syn
, 0), CreateMockWrite(*stream2_rst
, 3),
2944 scoped_ptr
<SpdyFrame
>
2945 stream1_reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2946 scoped_ptr
<SpdyFrame
> stream2_syn(spdy_util_
.ConstructSpdyPush(
2947 NULL
, 0, 2, 9, GetDefaultUrlWithPath("/foo.dat").c_str()));
2948 MockRead reads
[] = {
2949 CreateMockRead(*stream1_reply
, 1),
2950 CreateMockRead(*stream2_syn
, 2),
2951 CreateMockRead(*stream1_body
, 4),
2952 MockRead(SYNCHRONOUS
, ERR_IO_PENDING
, 5), // Force a pause
2955 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
2956 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
2957 BoundNetLog(), GetParam(), NULL
);
2959 helper
.RunPreTestSetup();
2960 helper
.AddData(&data
);
2962 HttpNetworkTransaction
* trans
= helper
.trans();
2964 // Start the transaction with basic parameters.
2965 TestCompletionCallback callback
;
2966 int rv
= trans
->Start(
2967 &CreateGetRequest(), callback
.callback(), BoundNetLog());
2968 EXPECT_EQ(ERR_IO_PENDING
, rv
);
2969 rv
= callback
.WaitForResult();
2972 // Verify that we consumed all test data.
2973 EXPECT_TRUE(data
.AllReadDataConsumed());
2974 EXPECT_TRUE(data
.AllWriteDataConsumed());
2976 // Verify the SYN_REPLY.
2977 HttpResponseInfo response
= *trans
->GetResponseInfo();
2978 EXPECT_TRUE(response
.headers
.get() != NULL
);
2979 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
2982 TEST_P(SpdyNetworkTransactionTest
, ServerPushNoURL
) {
2983 scoped_ptr
<SpdyFrame
> stream1_syn(
2984 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2985 scoped_ptr
<SpdyFrame
> stream1_body(
2986 spdy_util_
.ConstructSpdyBodyFrame(1, true));
2987 scoped_ptr
<SpdyFrame
> stream2_rst(
2988 spdy_util_
.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR
));
2989 MockWrite writes
[] = {
2990 CreateMockWrite(*stream1_syn
, 0), CreateMockWrite(*stream2_rst
, 3),
2993 scoped_ptr
<SpdyFrame
>
2994 stream1_reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2995 scoped_ptr
<SpdyHeaderBlock
> incomplete_headers(new SpdyHeaderBlock());
2996 (*incomplete_headers
)["hello"] = "bye";
2997 (*incomplete_headers
)[spdy_util_
.GetStatusKey()] = "200 OK";
2998 (*incomplete_headers
)[spdy_util_
.GetVersionKey()] = "HTTP/1.1";
2999 scoped_ptr
<SpdyFrame
> stream2_syn(spdy_util_
.ConstructInitialSpdyPushFrame(
3000 incomplete_headers
.Pass(), 2, 1));
3001 MockRead reads
[] = {
3002 CreateMockRead(*stream1_reply
, 1),
3003 CreateMockRead(*stream2_syn
, 2),
3004 CreateMockRead(*stream1_body
, 4),
3005 MockRead(SYNCHRONOUS
, ERR_IO_PENDING
, 5) // Force a pause
3008 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
3009 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
3010 BoundNetLog(), GetParam(), NULL
);
3012 helper
.RunPreTestSetup();
3013 helper
.AddData(&data
);
3015 HttpNetworkTransaction
* trans
= helper
.trans();
3017 // Start the transaction with basic parameters.
3018 TestCompletionCallback callback
;
3019 int rv
= trans
->Start(
3020 &CreateGetRequest(), callback
.callback(), BoundNetLog());
3021 EXPECT_EQ(ERR_IO_PENDING
, rv
);
3022 rv
= callback
.WaitForResult();
3025 // Verify that we consumed all test data.
3026 EXPECT_TRUE(data
.AllReadDataConsumed());
3027 EXPECT_TRUE(data
.AllWriteDataConsumed());
3029 // Verify the SYN_REPLY.
3030 HttpResponseInfo response
= *trans
->GetResponseInfo();
3031 EXPECT_TRUE(response
.headers
.get() != NULL
);
3032 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
3035 // Verify that various SynReply headers parse correctly through the
3037 TEST_P(SpdyNetworkTransactionTest
, SynReplyHeaders
) {
3038 struct SynReplyHeadersTests
{
3040 const char* extra_headers
[5];
3041 SpdyHeaderBlock expected_headers
;
3043 // This uses a multi-valued cookie header.
3046 "cookie", "val2", // will get appended separated by NULL
3050 // This is the minimalist set of headers.
3054 // Headers with a comma separated list.
3056 { "cookie", "val1,val2",
3062 test_cases
[0].expected_headers
["cookie"] = "val1";
3063 test_cases
[0].expected_headers
["cookie"] += '\0';
3064 test_cases
[0].expected_headers
["cookie"] += "val2";
3065 test_cases
[0].expected_headers
["hello"] = "bye";
3066 test_cases
[0].expected_headers
["status"] = "200";
3068 test_cases
[1].expected_headers
["hello"] = "bye";
3069 test_cases
[1].expected_headers
["status"] = "200";
3071 test_cases
[2].expected_headers
["cookie"] = "val1,val2";
3072 test_cases
[2].expected_headers
["hello"] = "bye";
3073 test_cases
[2].expected_headers
["status"] = "200";
3075 if (spdy_util_
.spdy_version() < HTTP2
) {
3076 // HTTP/2 eliminates use of the :version header.
3077 test_cases
[0].expected_headers
["version"] = "HTTP/1.1";
3078 test_cases
[1].expected_headers
["version"] = "HTTP/1.1";
3079 test_cases
[2].expected_headers
["version"] = "HTTP/1.1";
3082 for (size_t i
= 0; i
< arraysize(test_cases
); ++i
) {
3083 scoped_ptr
<SpdyFrame
> req(
3084 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
3085 MockWrite writes
[] = {CreateMockWrite(*req
, 0)};
3087 scoped_ptr
<SpdyFrame
> resp(
3088 spdy_util_
.ConstructSpdyGetSynReply(test_cases
[i
].extra_headers
,
3089 test_cases
[i
].num_headers
,
3091 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
3092 MockRead reads
[] = {
3093 CreateMockRead(*resp
, 1),
3094 CreateMockRead(*body
, 2),
3095 MockRead(ASYNC
, 0, 3) // EOF
3098 SequencedSocketData
data(reads
, arraysize(reads
), writes
,
3100 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
3101 BoundNetLog(), GetParam(), NULL
);
3102 helper
.RunToCompletion(&data
);
3103 TransactionHelperResult out
= helper
.output();
3105 EXPECT_EQ(OK
, out
.rv
);
3106 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
3107 EXPECT_EQ("hello!", out
.response_data
);
3109 scoped_refptr
<HttpResponseHeaders
> headers
= out
.response_info
.headers
;
3110 EXPECT_TRUE(headers
.get() != NULL
);
3112 std::string name
, value
;
3113 SpdyHeaderBlock header_block
;
3114 while (headers
->EnumerateHeaderLines(&iter
, &name
, &value
)) {
3115 if (header_block
[name
].empty()) {
3116 header_block
[name
] = value
;
3118 header_block
[name
] += '\0';
3119 header_block
[name
] += value
;
3122 EXPECT_EQ(test_cases
[i
].expected_headers
, header_block
);
3126 // Verify that various SynReply headers parse vary fields correctly
3127 // through the HTTP layer, and the response matches the request.
3128 TEST_P(SpdyNetworkTransactionTest
, SynReplyHeadersVary
) {
3129 // Modify the following data to change/add test cases:
3130 struct SynReplyTests
{
3133 const char* extra_headers
[2][16];
3135 // Test the case of a multi-valued cookie. When the value is delimited
3136 // with NUL characters, it needs to be unfolded into multiple headers.
3140 { { "cookie", "val1,val2",
3144 spdy_util_
.GetStatusKey(), "200",
3145 spdy_util_
.GetPathKey(), "/index.php",
3146 spdy_util_
.GetVersionKey(), "HTTP/1.1",
3150 }, { // Multiple vary fields.
3153 { { "friend", "barney",
3154 "enemy", "snaggletooth",
3159 spdy_util_
.GetStatusKey(), "200",
3160 spdy_util_
.GetPathKey(), "/index.php",
3161 spdy_util_
.GetVersionKey(), "HTTP/1.1",
3165 }, { // Test a '*' vary field.
3168 { { "cookie", "val1,val2",
3172 spdy_util_
.GetStatusKey(), "200",
3173 spdy_util_
.GetPathKey(), "/index.php",
3174 spdy_util_
.GetVersionKey(), "HTTP/1.1",
3178 }, { // Multiple comma-separated vary fields.
3181 { { "friend", "barney",
3182 "enemy", "snaggletooth",
3185 { "vary", "friend,enemy",
3186 spdy_util_
.GetStatusKey(), "200",
3187 spdy_util_
.GetPathKey(), "/index.php",
3188 spdy_util_
.GetVersionKey(), "HTTP/1.1",
3195 for (size_t i
= 0; i
< arraysize(test_cases
); ++i
) {
3196 // Construct the request.
3197 scoped_ptr
<SpdyFrame
> frame_req(
3198 spdy_util_
.ConstructSpdyGet(test_cases
[i
].extra_headers
[0],
3199 test_cases
[i
].num_headers
[0],
3200 false, 1, LOWEST
, true));
3202 MockWrite writes
[] = {
3203 CreateMockWrite(*frame_req
, 0),
3206 // Construct the reply.
3207 SpdyHeaderBlock reply_headers
;
3208 AppendToHeaderBlock(test_cases
[i
].extra_headers
[1],
3209 test_cases
[i
].num_headers
[1],
3211 scoped_ptr
<SpdyFrame
> frame_reply(
3212 spdy_util_
.ConstructSpdyReply(1, reply_headers
));
3214 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
3215 MockRead reads
[] = {
3216 CreateMockRead(*frame_reply
, 1),
3217 CreateMockRead(*body
, 2),
3218 MockRead(ASYNC
, 0, 3) // EOF
3221 // Attach the headers to the request.
3222 int header_count
= test_cases
[i
].num_headers
[0];
3224 HttpRequestInfo request
= CreateGetRequest();
3225 for (int ct
= 0; ct
< header_count
; ct
++) {
3226 const char* header_key
= test_cases
[i
].extra_headers
[0][ct
* 2];
3227 const char* header_value
= test_cases
[i
].extra_headers
[0][ct
* 2 + 1];
3228 request
.extra_headers
.SetHeader(header_key
, header_value
);
3231 SequencedSocketData
data(reads
, arraysize(reads
), writes
,
3233 NormalSpdyTransactionHelper
helper(request
, DEFAULT_PRIORITY
,
3234 BoundNetLog(), GetParam(), NULL
);
3235 helper
.RunToCompletion(&data
);
3236 TransactionHelperResult out
= helper
.output();
3238 EXPECT_EQ(OK
, out
.rv
) << i
;
3239 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
) << i
;
3240 EXPECT_EQ("hello!", out
.response_data
) << i
;
3242 // Test the response information.
3243 EXPECT_EQ(out
.response_info
.vary_data
.is_valid(),
3244 test_cases
[i
].vary_matches
) << i
;
3246 // Check the headers.
3247 scoped_refptr
<HttpResponseHeaders
> headers
= out
.response_info
.headers
;
3248 ASSERT_TRUE(headers
.get() != NULL
) << i
;
3250 std::string name
, value
, lines
;
3251 while (headers
->EnumerateHeaderLines(&iter
, &name
, &value
)) {
3254 lines
.append(value
);
3258 // Construct the expected header reply string.
3259 std::string expected_reply
=
3260 spdy_util_
.ConstructSpdyReplyString(reply_headers
);
3261 EXPECT_EQ(expected_reply
, lines
) << i
;
3265 // Verify that we don't crash on invalid SynReply responses.
3266 TEST_P(SpdyNetworkTransactionTest
, InvalidSynReply
) {
3267 struct InvalidSynReplyTests
{
3269 const char* headers
[10];
3271 // SYN_REPLY missing status header
3275 spdy_util_
.GetPathKey(), "/index.php",
3276 spdy_util_
.GetVersionKey(), "HTTP/1.1",
3280 // SYN_REPLY missing version header
3283 spdy_util_
.GetPathKey(), "/index.php",
3287 // SYN_REPLY with no headers
3291 for (size_t i
= 0; i
< arraysize(test_cases
); ++i
) {
3292 scoped_ptr
<SpdyFrame
> req(
3293 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
3294 scoped_ptr
<SpdyFrame
> rst(
3295 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR
));
3296 MockWrite writes
[] = {
3297 CreateMockWrite(*req
, 0), CreateMockWrite(*rst
, 2),
3300 // Construct the reply.
3301 SpdyHeaderBlock reply_headers
;
3302 AppendToHeaderBlock(
3303 test_cases
[i
].headers
, test_cases
[i
].num_headers
, &reply_headers
);
3304 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyReply(1, reply_headers
));
3305 MockRead reads
[] = {
3306 CreateMockRead(*resp
, 1), MockRead(ASYNC
, 0, 3) // EOF
3309 SequencedSocketData
data(reads
, arraysize(reads
), writes
,
3311 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
3312 BoundNetLog(), GetParam(), NULL
);
3313 helper
.RunToCompletion(&data
);
3314 TransactionHelperResult out
= helper
.output();
3315 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR
, out
.rv
);
3319 // Verify that we don't crash on some corrupt frames.
3320 // TODO(jgraettinger): HTTP/2 treats a header decompression failure as a
3321 // connection error. I'd like to backport this behavior to SPDY3 as well.
3322 TEST_P(SpdyNetworkTransactionTest
, CorruptFrameSessionError
) {
3323 if (spdy_util_
.spdy_version() >= HTTP2
) {
3326 // This is the length field that's too short.
3327 scoped_ptr
<SpdyFrame
> syn_reply_wrong_length(
3328 spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
3329 BufferedSpdyFramer
framer(spdy_util_
.spdy_version(), false);
3331 (spdy_util_
.spdy_version() < HTTP2
)
3332 ? syn_reply_wrong_length
->size() - framer
.GetControlFrameHeaderSize()
3333 : syn_reply_wrong_length
->size();
3334 size_t wrong_size
= right_size
- 4;
3335 test::SetFrameLength(syn_reply_wrong_length
.get(),
3337 spdy_util_
.spdy_version());
3339 struct SynReplyTests
{
3340 const SpdyFrame
* syn_reply
;
3342 { syn_reply_wrong_length
.get(), },
3345 for (size_t i
= 0; i
< arraysize(test_cases
); ++i
) {
3346 scoped_ptr
<SpdyFrame
> req(
3347 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
3348 scoped_ptr
<SpdyFrame
> rst(
3349 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR
));
3350 MockWrite writes
[] = {
3351 CreateMockWrite(*req
, 0), CreateMockWrite(*rst
, 3),
3354 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
3355 MockRead reads
[] = {
3356 MockRead(ASYNC
, test_cases
[i
].syn_reply
->data(), wrong_size
, 1),
3357 CreateMockRead(*body
, 2),
3358 MockRead(ASYNC
, 0, 4) // EOF
3361 SequencedSocketData
data(reads
, arraysize(reads
), writes
,
3363 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
3364 BoundNetLog(), GetParam(), NULL
);
3365 helper
.RunToCompletion(&data
);
3366 TransactionHelperResult out
= helper
.output();
3367 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR
, out
.rv
);
3371 // HTTP/2 treats a header decompression failure as a connection-level error.
3372 TEST_P(SpdyNetworkTransactionTest
, CorruptFrameSessionErrorSpdy4
) {
3373 if (spdy_util_
.spdy_version() < HTTP2
) {
3376 // This is the length field that's too short.
3377 scoped_ptr
<SpdyFrame
> syn_reply_wrong_length(
3378 spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
3379 BufferedSpdyFramer
framer(spdy_util_
.spdy_version(), false);
3381 syn_reply_wrong_length
->size() - framer
.GetControlFrameHeaderSize();
3382 size_t wrong_size
= right_size
- 4;
3383 test::SetFrameLength(syn_reply_wrong_length
.get(),
3385 spdy_util_
.spdy_version());
3387 scoped_ptr
<SpdyFrame
> req(
3388 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
3389 scoped_ptr
<SpdyFrame
> goaway(spdy_util_
.ConstructSpdyGoAway(
3390 0, GOAWAY_COMPRESSION_ERROR
, "Framer error: 5 (DECOMPRESS_FAILURE)."));
3391 MockWrite writes
[] = {CreateMockWrite(*req
, 0), CreateMockWrite(*goaway
, 2)};
3393 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
3394 MockRead reads
[] = {
3395 MockRead(ASYNC
, syn_reply_wrong_length
->data(),
3396 syn_reply_wrong_length
->size() - 4, 1),
3399 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
3400 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
3401 BoundNetLog(), GetParam(), NULL
);
3402 helper
.RunToCompletion(&data
);
3403 TransactionHelperResult out
= helper
.output();
3404 EXPECT_EQ(ERR_SPDY_COMPRESSION_ERROR
, out
.rv
);
3407 TEST_P(SpdyNetworkTransactionTest
, GoAwayOnDecompressionFailure
) {
3408 if (GetParam().protocol
< kProtoHTTP2MinimumVersion
) {
3409 // Decompression failures are a stream error in SPDY3 and above.
3412 scoped_ptr
<SpdyFrame
> req(
3413 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
3414 scoped_ptr
<SpdyFrame
> goaway(spdy_util_
.ConstructSpdyGoAway(
3415 0, GOAWAY_COMPRESSION_ERROR
, "Framer error: 5 (DECOMPRESS_FAILURE)."));
3416 MockWrite writes
[] = {CreateMockWrite(*req
, 0), CreateMockWrite(*goaway
, 2)};
3418 // Read HEADERS with corrupted payload.
3419 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
3420 memset(resp
->data() + 12, 0xff, resp
->size() - 12);
3421 MockRead reads
[] = {CreateMockRead(*resp
, 1)};
3423 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
3424 NormalSpdyTransactionHelper
helper(
3425 CreateGetRequest(), DEFAULT_PRIORITY
, BoundNetLog(), GetParam(), NULL
);
3426 helper
.RunToCompletion(&data
);
3427 TransactionHelperResult out
= helper
.output();
3428 EXPECT_EQ(ERR_SPDY_COMPRESSION_ERROR
, out
.rv
);
3431 TEST_P(SpdyNetworkTransactionTest
, GoAwayOnFrameSizeError
) {
3432 scoped_ptr
<SpdyFrame
> req(
3433 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
3434 scoped_ptr
<SpdyFrame
> goaway(spdy_util_
.ConstructSpdyGoAway(
3435 0, GOAWAY_PROTOCOL_ERROR
, "Framer error: 1 (INVALID_CONTROL_FRAME)."));
3436 MockWrite writes
[] = {CreateMockWrite(*req
, 0), CreateMockWrite(*goaway
, 2)};
3438 // Read WINDOW_UPDATE with incorrectly-sized payload.
3439 // TODO(jgraettinger): SpdyFramer signals this as an INVALID_CONTROL_FRAME,
3440 // which is mapped to a protocol error, and not a frame size error.
3441 scoped_ptr
<SpdyFrame
> bad_window_update(
3442 spdy_util_
.ConstructSpdyWindowUpdate(1, 1));
3443 test::SetFrameLength(bad_window_update
.get(),
3444 bad_window_update
->size() - 1,
3445 spdy_util_
.spdy_version());
3446 MockRead reads
[] = {CreateMockRead(*bad_window_update
, 1)};
3448 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
3449 NormalSpdyTransactionHelper
helper(
3450 CreateGetRequest(), DEFAULT_PRIORITY
, BoundNetLog(), GetParam(), NULL
);
3451 helper
.RunToCompletion(&data
);
3452 TransactionHelperResult out
= helper
.output();
3453 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR
, out
.rv
);
3456 // Test that we shutdown correctly on write errors.
3457 TEST_P(SpdyNetworkTransactionTest
, WriteError
) {
3458 scoped_ptr
<SpdyFrame
> req(
3459 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
3460 MockWrite writes
[] = {
3461 // We'll write 10 bytes successfully
3462 MockWrite(ASYNC
, req
->data(), 10, 0),
3463 // Followed by ERROR!
3464 MockWrite(ASYNC
, ERR_FAILED
, 1),
3465 // Session drains and attempts to write a GOAWAY: Another ERROR!
3466 MockWrite(ASYNC
, ERR_FAILED
, 2),
3469 MockRead reads
[] = {
3470 MockRead(ASYNC
, 0, 3) // EOF
3473 DeterministicSocketData
data(reads
, arraysize(reads
),
3474 writes
, arraysize(writes
));
3476 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
3477 BoundNetLog(), GetParam(), NULL
);
3478 helper
.SetDeterministic();
3479 helper
.RunPreTestSetup();
3480 helper
.AddDeterministicData(&data
);
3481 EXPECT_TRUE(helper
.StartDefaultTest());
3483 helper
.FinishDefaultTest();
3484 EXPECT_TRUE(data
.AllWriteDataConsumed());
3485 EXPECT_TRUE(!data
.AllReadDataConsumed());
3486 TransactionHelperResult out
= helper
.output();
3487 EXPECT_EQ(ERR_FAILED
, out
.rv
);
3490 // Test that partial writes work.
3491 TEST_P(SpdyNetworkTransactionTest
, PartialWrite
) {
3492 // Chop the SYN_STREAM frame into 5 chunks.
3493 scoped_ptr
<SpdyFrame
> req(
3494 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
3495 const int kChunks
= 5;
3496 scoped_ptr
<MockWrite
[]> writes(ChopWriteFrame(*req
.get(), kChunks
));
3497 for (int i
= 0; i
< kChunks
; ++i
) {
3498 writes
[i
].sequence_number
= i
;
3501 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
3502 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
3503 MockRead reads
[] = {
3504 CreateMockRead(*resp
, kChunks
),
3505 CreateMockRead(*body
, kChunks
+ 1),
3506 MockRead(ASYNC
, 0, kChunks
+ 2) // EOF
3509 SequencedSocketData
data(reads
, arraysize(reads
), writes
.get(), kChunks
);
3510 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
3511 BoundNetLog(), GetParam(), NULL
);
3512 helper
.RunToCompletion(&data
);
3513 TransactionHelperResult out
= helper
.output();
3514 EXPECT_EQ(OK
, out
.rv
);
3515 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
3516 EXPECT_EQ("hello!", out
.response_data
);
3519 // In this test, we enable compression, but get a uncompressed SynReply from
3520 // the server. Verify that teardown is all clean.
3521 TEST_P(SpdyNetworkTransactionTest
, DecompressFailureOnSynReply
) {
3522 if (spdy_util_
.spdy_version() >= HTTP2
) {
3523 // HPACK doesn't use deflate compression.
3526 scoped_ptr
<SpdyFrame
> compressed(
3527 spdy_util_
.ConstructSpdyGet(NULL
, 0, true, 1, LOWEST
, true));
3528 scoped_ptr
<SpdyFrame
> goaway(spdy_util_
.ConstructSpdyGoAway(
3529 0, GOAWAY_COMPRESSION_ERROR
, "Framer error: 5 (DECOMPRESS_FAILURE)."));
3530 MockWrite writes
[] = {CreateMockWrite(*compressed
, 0),
3531 CreateMockWrite(*goaway
, 2)};
3533 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
3534 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
3535 MockRead reads
[] = {
3536 CreateMockRead(*resp
, 1),
3539 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
3540 SpdySessionDependencies
* session_deps
=
3541 CreateSpdySessionDependencies(GetParam());
3542 session_deps
->enable_compression
= true;
3543 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
3544 BoundNetLog(), GetParam(), session_deps
);
3545 helper
.RunToCompletion(&data
);
3546 TransactionHelperResult out
= helper
.output();
3547 EXPECT_EQ(ERR_SPDY_COMPRESSION_ERROR
, out
.rv
);
3551 // Test that the NetLog contains good data for a simple GET request.
3552 TEST_P(SpdyNetworkTransactionTest
, NetLog
) {
3553 static const char* const kExtraHeaders
[] = {
3554 "user-agent", "Chrome",
3556 scoped_ptr
<SpdyFrame
> req(
3557 spdy_util_
.ConstructSpdyGet(kExtraHeaders
, 1, false, 1, LOWEST
, true));
3558 MockWrite writes
[] = {CreateMockWrite(*req
, 0)};
3560 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
3561 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
3562 MockRead reads
[] = {
3563 CreateMockRead(*resp
, 1),
3564 CreateMockRead(*body
, 2),
3565 MockRead(ASYNC
, 0, 3) // EOF
3568 BoundTestNetLog log
;
3570 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
3571 NormalSpdyTransactionHelper
helper(CreateGetRequestWithUserAgent(),
3573 log
.bound(), GetParam(), NULL
);
3574 helper
.RunToCompletion(&data
);
3575 TransactionHelperResult out
= helper
.output();
3576 EXPECT_EQ(OK
, out
.rv
);
3577 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
3578 EXPECT_EQ("hello!", out
.response_data
);
3580 // Check that the NetLog was filled reasonably.
3581 // This test is intentionally non-specific about the exact ordering of the
3582 // log; instead we just check to make sure that certain events exist, and that
3583 // they are in the right order.
3584 TestNetLogEntry::List entries
;
3585 log
.GetEntries(&entries
);
3587 EXPECT_LT(0u, entries
.size());
3589 pos
= ExpectLogContainsSomewhere(entries
, 0,
3590 NetLog::TYPE_HTTP_TRANSACTION_SEND_REQUEST
,
3591 NetLog::PHASE_BEGIN
);
3592 pos
= ExpectLogContainsSomewhere(entries
, pos
+ 1,
3593 NetLog::TYPE_HTTP_TRANSACTION_SEND_REQUEST
,
3595 pos
= ExpectLogContainsSomewhere(entries
, pos
+ 1,
3596 NetLog::TYPE_HTTP_TRANSACTION_READ_HEADERS
,
3597 NetLog::PHASE_BEGIN
);
3598 pos
= ExpectLogContainsSomewhere(entries
, pos
+ 1,
3599 NetLog::TYPE_HTTP_TRANSACTION_READ_HEADERS
,
3601 pos
= ExpectLogContainsSomewhere(entries
, pos
+ 1,
3602 NetLog::TYPE_HTTP_TRANSACTION_READ_BODY
,
3603 NetLog::PHASE_BEGIN
);
3604 pos
= ExpectLogContainsSomewhere(entries
, pos
+ 1,
3605 NetLog::TYPE_HTTP_TRANSACTION_READ_BODY
,
3608 // Check that we logged all the headers correctly
3609 const NetLog::EventType type
= (GetParam().protocol
<= kProtoSPDY31
)
3610 ? NetLog::TYPE_HTTP2_SESSION_SYN_STREAM
3611 : NetLog::TYPE_HTTP2_SESSION_SEND_HEADERS
;
3612 pos
= ExpectLogContainsSomewhere(entries
, 0, type
, NetLog::PHASE_NONE
);
3614 base::ListValue
* header_list
;
3615 ASSERT_TRUE(entries
[pos
].params
.get());
3616 ASSERT_TRUE(entries
[pos
].params
->GetList("headers", &header_list
));
3618 std::vector
<std::string
> expected
;
3619 expected
.push_back(std::string(spdy_util_
.GetHostKey()) +
3620 ": www.example.org");
3621 expected
.push_back(std::string(spdy_util_
.GetPathKey()) + ": /");
3622 expected
.push_back(std::string(spdy_util_
.GetSchemeKey()) + ": " +
3623 spdy_util_
.default_url().scheme());
3624 expected
.push_back(std::string(spdy_util_
.GetMethodKey()) + ": GET");
3625 expected
.push_back("user-agent: Chrome");
3626 if (spdy_util_
.spdy_version() < HTTP2
) {
3627 // HTTP/2 eliminates use of the :version header.
3628 expected
.push_back(std::string(spdy_util_
.GetVersionKey()) + ": HTTP/1.1");
3630 EXPECT_EQ(expected
.size(), header_list
->GetSize());
3631 for (std::vector
<std::string
>::const_iterator it
= expected
.begin();
3632 it
!= expected
.end();
3634 base::StringValue
header(*it
);
3635 EXPECT_NE(header_list
->end(), header_list
->Find(header
)) <<
3636 "Header not found: " << *it
;
3640 // Since we buffer the IO from the stream to the renderer, this test verifies
3641 // that when we read out the maximum amount of data (e.g. we received 50 bytes
3642 // on the network, but issued a Read for only 5 of those bytes) that the data
3643 // flow still works correctly.
3644 TEST_P(SpdyNetworkTransactionTest
, BufferFull
) {
3645 BufferedSpdyFramer
framer(spdy_util_
.spdy_version(), false);
3647 scoped_ptr
<SpdyFrame
> req(
3648 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
3649 MockWrite writes
[] = {CreateMockWrite(*req
, 0)};
3651 // 2 data frames in a single read.
3652 scoped_ptr
<SpdyFrame
> data_frame_1(
3653 framer
.CreateDataFrame(1, "goodby", 6, DATA_FLAG_NONE
));
3654 scoped_ptr
<SpdyFrame
> data_frame_2(
3655 framer
.CreateDataFrame(1, "e worl", 6, DATA_FLAG_NONE
));
3656 const SpdyFrame
* data_frames
[2] = {
3660 char combined_data_frames
[100];
3661 int combined_data_frames_len
=
3662 CombineFrames(data_frames
, arraysize(data_frames
),
3663 combined_data_frames
, arraysize(combined_data_frames
));
3664 scoped_ptr
<SpdyFrame
> last_frame(
3665 framer
.CreateDataFrame(1, "d", 1, DATA_FLAG_FIN
));
3667 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
3668 MockRead reads
[] = {
3669 CreateMockRead(*resp
, 1),
3670 MockRead(ASYNC
, ERR_IO_PENDING
, 2), // Force a pause
3671 MockRead(ASYNC
, combined_data_frames
, combined_data_frames_len
, 3),
3672 MockRead(ASYNC
, ERR_IO_PENDING
, 4), // Force a pause
3673 CreateMockRead(*last_frame
, 5),
3674 MockRead(ASYNC
, 0, 6) // EOF
3677 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
3679 TestCompletionCallback callback
;
3681 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
3682 BoundNetLog(), GetParam(), NULL
);
3683 helper
.RunPreTestSetup();
3684 helper
.AddData(&data
);
3685 HttpNetworkTransaction
* trans
= helper
.trans();
3686 int rv
= trans
->Start(
3687 &CreateGetRequest(), callback
.callback(), BoundNetLog());
3688 EXPECT_EQ(ERR_IO_PENDING
, rv
);
3690 TransactionHelperResult out
= helper
.output();
3691 out
.rv
= callback
.WaitForResult();
3692 EXPECT_EQ(out
.rv
, OK
);
3694 const HttpResponseInfo
* response
= trans
->GetResponseInfo();
3695 EXPECT_TRUE(response
->headers
.get() != NULL
);
3696 EXPECT_TRUE(response
->was_fetched_via_spdy
);
3697 out
.status_line
= response
->headers
->GetStatusLine();
3698 out
.response_info
= *response
; // Make a copy so we can verify.
3701 TestCompletionCallback read_callback
;
3703 std::string content
;
3705 // Read small chunks at a time.
3706 const int kSmallReadSize
= 3;
3707 scoped_refptr
<IOBuffer
> buf(new IOBuffer(kSmallReadSize
));
3708 rv
= trans
->Read(buf
.get(), kSmallReadSize
, read_callback
.callback());
3709 if (rv
== ERR_IO_PENDING
) {
3710 data
.CompleteRead();
3711 rv
= read_callback
.WaitForResult();
3714 content
.append(buf
->data(), rv
);
3715 } else if (rv
< 0) {
3720 out
.response_data
.swap(content
);
3722 // Flush the MessageLoop while the SpdySessionDependencies (in particular, the
3723 // MockClientSocketFactory) are still alive.
3724 base::RunLoop().RunUntilIdle();
3726 // Verify that we consumed all test data.
3727 helper
.VerifyDataConsumed();
3729 EXPECT_EQ(OK
, out
.rv
);
3730 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
3731 EXPECT_EQ("goodbye world", out
.response_data
);
3734 // Verify that basic buffering works; when multiple data frames arrive
3735 // at the same time, ensure that we don't notify a read completion for
3736 // each data frame individually.
3737 TEST_P(SpdyNetworkTransactionTest
, Buffering
) {
3738 BufferedSpdyFramer
framer(spdy_util_
.spdy_version(), false);
3740 scoped_ptr
<SpdyFrame
> req(
3741 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
3742 MockWrite writes
[] = {CreateMockWrite(*req
, 0)};
3744 // 4 data frames in a single read.
3745 scoped_ptr
<SpdyFrame
> data_frame(
3746 framer
.CreateDataFrame(1, "message", 7, DATA_FLAG_NONE
));
3747 scoped_ptr
<SpdyFrame
> data_frame_fin(
3748 framer
.CreateDataFrame(1, "message", 7, DATA_FLAG_FIN
));
3749 const SpdyFrame
* data_frames
[4] = {
3753 data_frame_fin
.get()
3755 char combined_data_frames
[100];
3756 int combined_data_frames_len
=
3757 CombineFrames(data_frames
, arraysize(data_frames
),
3758 combined_data_frames
, arraysize(combined_data_frames
));
3760 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
3761 MockRead reads
[] = {
3762 CreateMockRead(*resp
, 1),
3763 MockRead(ASYNC
, ERR_IO_PENDING
, 2), // Force a pause
3764 MockRead(ASYNC
, combined_data_frames
, combined_data_frames_len
, 3),
3765 MockRead(ASYNC
, 0, 4) // EOF
3768 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
3770 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
3771 BoundNetLog(), GetParam(), NULL
);
3772 helper
.RunPreTestSetup();
3773 helper
.AddData(&data
);
3774 HttpNetworkTransaction
* trans
= helper
.trans();
3776 TestCompletionCallback callback
;
3777 int rv
= trans
->Start(
3778 &CreateGetRequest(), callback
.callback(), BoundNetLog());
3779 EXPECT_EQ(ERR_IO_PENDING
, rv
);
3781 TransactionHelperResult out
= helper
.output();
3782 out
.rv
= callback
.WaitForResult();
3783 EXPECT_EQ(out
.rv
, OK
);
3785 const HttpResponseInfo
* response
= trans
->GetResponseInfo();
3786 EXPECT_TRUE(response
->headers
.get() != NULL
);
3787 EXPECT_TRUE(response
->was_fetched_via_spdy
);
3788 out
.status_line
= response
->headers
->GetStatusLine();
3789 out
.response_info
= *response
; // Make a copy so we can verify.
3792 TestCompletionCallback read_callback
;
3794 std::string content
;
3795 int reads_completed
= 0;
3797 // Read small chunks at a time.
3798 const int kSmallReadSize
= 14;
3799 scoped_refptr
<IOBuffer
> buf(new IOBuffer(kSmallReadSize
));
3800 rv
= trans
->Read(buf
.get(), kSmallReadSize
, read_callback
.callback());
3801 if (rv
== ERR_IO_PENDING
) {
3802 data
.CompleteRead();
3803 rv
= read_callback
.WaitForResult();
3806 EXPECT_EQ(kSmallReadSize
, rv
);
3807 content
.append(buf
->data(), rv
);
3808 } else if (rv
< 0) {
3809 FAIL() << "Unexpected read error: " << rv
;
3814 EXPECT_EQ(3, reads_completed
); // Reads are: 14 bytes, 14 bytes, 0 bytes.
3816 out
.response_data
.swap(content
);
3818 // Flush the MessageLoop while the SpdySessionDependencies (in particular, the
3819 // MockClientSocketFactory) are still alive.
3820 base::RunLoop().RunUntilIdle();
3822 // Verify that we consumed all test data.
3823 helper
.VerifyDataConsumed();
3825 EXPECT_EQ(OK
, out
.rv
);
3826 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
3827 EXPECT_EQ("messagemessagemessagemessage", out
.response_data
);
3830 // Verify the case where we buffer data but read it after it has been buffered.
3831 TEST_P(SpdyNetworkTransactionTest
, BufferedAll
) {
3832 BufferedSpdyFramer
framer(spdy_util_
.spdy_version(), false);
3834 scoped_ptr
<SpdyFrame
> req(
3835 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
3836 MockWrite writes
[] = {CreateMockWrite(*req
, 0)};
3838 // 5 data frames in a single read.
3839 scoped_ptr
<SpdyFrame
> reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
3840 scoped_ptr
<SpdyFrame
> data_frame(
3841 framer
.CreateDataFrame(1, "message", 7, DATA_FLAG_NONE
));
3842 scoped_ptr
<SpdyFrame
> data_frame_fin(
3843 framer
.CreateDataFrame(1, "message", 7, DATA_FLAG_FIN
));
3844 const SpdyFrame
* frames
[5] = {reply
.get(), data_frame
.get(), data_frame
.get(),
3845 data_frame
.get(), data_frame_fin
.get()};
3846 char combined_frames
[200];
3847 int combined_frames_len
=
3848 CombineFrames(frames
, arraysize(frames
),
3849 combined_frames
, arraysize(combined_frames
));
3851 MockRead reads
[] = {
3852 MockRead(ASYNC
, combined_frames
, combined_frames_len
, 1),
3853 MockRead(ASYNC
, 0, 2) // EOF
3856 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
3858 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
3859 BoundNetLog(), GetParam(), NULL
);
3860 helper
.RunPreTestSetup();
3861 helper
.AddData(&data
);
3862 HttpNetworkTransaction
* trans
= helper
.trans();
3864 TestCompletionCallback callback
;
3865 int rv
= trans
->Start(
3866 &CreateGetRequest(), callback
.callback(), BoundNetLog());
3867 EXPECT_EQ(ERR_IO_PENDING
, rv
);
3869 TransactionHelperResult out
= helper
.output();
3870 out
.rv
= callback
.WaitForResult();
3871 EXPECT_EQ(out
.rv
, OK
);
3873 const HttpResponseInfo
* response
= trans
->GetResponseInfo();
3874 EXPECT_TRUE(response
->headers
.get() != NULL
);
3875 EXPECT_TRUE(response
->was_fetched_via_spdy
);
3876 out
.status_line
= response
->headers
->GetStatusLine();
3877 out
.response_info
= *response
; // Make a copy so we can verify.
3880 TestCompletionCallback read_callback
;
3882 std::string content
;
3883 int reads_completed
= 0;
3885 // Read small chunks at a time.
3886 const int kSmallReadSize
= 14;
3887 scoped_refptr
<IOBuffer
> buf(new IOBuffer(kSmallReadSize
));
3888 rv
= trans
->Read(buf
.get(), kSmallReadSize
, read_callback
.callback());
3890 EXPECT_EQ(kSmallReadSize
, rv
);
3891 content
.append(buf
->data(), rv
);
3892 } else if (rv
< 0) {
3893 FAIL() << "Unexpected read error: " << rv
;
3898 EXPECT_EQ(3, reads_completed
);
3900 out
.response_data
.swap(content
);
3902 // Flush the MessageLoop while the SpdySessionDependencies (in particular, the
3903 // MockClientSocketFactory) are still alive.
3904 base::RunLoop().RunUntilIdle();
3906 // Verify that we consumed all test data.
3907 helper
.VerifyDataConsumed();
3909 EXPECT_EQ(OK
, out
.rv
);
3910 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
3911 EXPECT_EQ("messagemessagemessagemessage", out
.response_data
);
3914 // Verify the case where we buffer data and close the connection.
3915 TEST_P(SpdyNetworkTransactionTest
, BufferedClosed
) {
3916 BufferedSpdyFramer
framer(spdy_util_
.spdy_version(), false);
3918 scoped_ptr
<SpdyFrame
> req(
3919 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
3920 MockWrite writes
[] = {CreateMockWrite(*req
, 0)};
3922 // All data frames in a single read.
3923 // NOTE: We don't FIN the stream.
3924 scoped_ptr
<SpdyFrame
> data_frame(
3925 framer
.CreateDataFrame(1, "message", 7, DATA_FLAG_NONE
));
3926 const SpdyFrame
* data_frames
[4] = {
3932 char combined_data_frames
[100];
3933 int combined_data_frames_len
=
3934 CombineFrames(data_frames
, arraysize(data_frames
),
3935 combined_data_frames
, arraysize(combined_data_frames
));
3936 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
3937 MockRead reads
[] = {
3938 CreateMockRead(*resp
, 1),
3939 MockRead(ASYNC
, ERR_IO_PENDING
, 2), // Force a wait
3940 MockRead(ASYNC
, combined_data_frames
, combined_data_frames_len
, 3),
3941 MockRead(ASYNC
, 0, 4) // EOF
3944 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
3946 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
3947 BoundNetLog(), GetParam(), NULL
);
3948 helper
.RunPreTestSetup();
3949 helper
.AddData(&data
);
3950 HttpNetworkTransaction
* trans
= helper
.trans();
3952 TestCompletionCallback callback
;
3954 int rv
= trans
->Start(
3955 &CreateGetRequest(), callback
.callback(), BoundNetLog());
3956 EXPECT_EQ(ERR_IO_PENDING
, rv
);
3958 TransactionHelperResult out
= helper
.output();
3959 out
.rv
= callback
.WaitForResult();
3960 EXPECT_EQ(out
.rv
, OK
);
3962 const HttpResponseInfo
* response
= trans
->GetResponseInfo();
3963 EXPECT_TRUE(response
->headers
.get() != NULL
);
3964 EXPECT_TRUE(response
->was_fetched_via_spdy
);
3965 out
.status_line
= response
->headers
->GetStatusLine();
3966 out
.response_info
= *response
; // Make a copy so we can verify.
3969 TestCompletionCallback read_callback
;
3971 std::string content
;
3972 int reads_completed
= 0;
3974 // Read small chunks at a time.
3975 const int kSmallReadSize
= 14;
3976 scoped_refptr
<IOBuffer
> buf(new IOBuffer(kSmallReadSize
));
3977 rv
= trans
->Read(buf
.get(), kSmallReadSize
, read_callback
.callback());
3978 if (rv
== ERR_IO_PENDING
) {
3979 data
.CompleteRead();
3980 rv
= read_callback
.WaitForResult();
3983 content
.append(buf
->data(), rv
);
3984 } else if (rv
< 0) {
3985 // This test intentionally closes the connection, and will get an error.
3986 EXPECT_EQ(ERR_CONNECTION_CLOSED
, rv
);
3992 EXPECT_EQ(0, reads_completed
);
3994 out
.response_data
.swap(content
);
3996 // Flush the MessageLoop while the SpdySessionDependencies (in particular, the
3997 // MockClientSocketFactory) are still alive.
3998 base::RunLoop().RunUntilIdle();
4000 // Verify that we consumed all test data.
4001 helper
.VerifyDataConsumed();
4004 // Verify the case where we buffer data and cancel the transaction.
4005 TEST_P(SpdyNetworkTransactionTest
, BufferedCancelled
) {
4006 BufferedSpdyFramer
framer(spdy_util_
.spdy_version(), false);
4008 scoped_ptr
<SpdyFrame
> req(
4009 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
4010 scoped_ptr
<SpdyFrame
> rst(
4011 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_CANCEL
));
4012 MockWrite writes
[] = {CreateMockWrite(*req
, 0), CreateMockWrite(*rst
, 4)};
4014 // NOTE: We don't FIN the stream.
4015 scoped_ptr
<SpdyFrame
> data_frame(
4016 framer
.CreateDataFrame(1, "message", 7, DATA_FLAG_NONE
));
4018 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
4019 MockRead reads
[] = {
4020 CreateMockRead(*resp
, 1),
4021 MockRead(ASYNC
, ERR_IO_PENDING
, 2), // Force a wait
4022 CreateMockRead(*data_frame
, 3),
4023 MockRead(ASYNC
, 0, 5) // EOF
4026 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
4028 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
4029 BoundNetLog(), GetParam(), NULL
);
4030 helper
.RunPreTestSetup();
4031 helper
.AddData(&data
);
4032 HttpNetworkTransaction
* trans
= helper
.trans();
4033 TestCompletionCallback callback
;
4035 int rv
= trans
->Start(
4036 &CreateGetRequest(), callback
.callback(), BoundNetLog());
4037 EXPECT_EQ(ERR_IO_PENDING
, rv
);
4039 TransactionHelperResult out
= helper
.output();
4040 out
.rv
= callback
.WaitForResult();
4041 EXPECT_EQ(out
.rv
, OK
);
4043 const HttpResponseInfo
* response
= trans
->GetResponseInfo();
4044 EXPECT_TRUE(response
->headers
.get() != NULL
);
4045 EXPECT_TRUE(response
->was_fetched_via_spdy
);
4046 out
.status_line
= response
->headers
->GetStatusLine();
4047 out
.response_info
= *response
; // Make a copy so we can verify.
4050 TestCompletionCallback read_callback
;
4052 const int kReadSize
= 256;
4053 scoped_refptr
<IOBuffer
> buf(new IOBuffer(kReadSize
));
4054 rv
= trans
->Read(buf
.get(), kReadSize
, read_callback
.callback());
4055 ASSERT_EQ(ERR_IO_PENDING
, rv
) << "Unexpected read: " << rv
;
4057 // Complete the read now, which causes buffering to start.
4058 data
.CompleteRead();
4059 // Destroy the transaction, causing the stream to get cancelled
4060 // and orphaning the buffered IO task.
4061 helper
.ResetTrans();
4063 // Flush the MessageLoop; this will cause the buffered IO task
4064 // to run for the final time.
4065 base::RunLoop().RunUntilIdle();
4067 // Verify that we consumed all test data.
4068 helper
.VerifyDataConsumed();
4071 // Test that if the server requests persistence of settings, that we save
4072 // the settings in the HttpServerProperties.
4073 TEST_P(SpdyNetworkTransactionTest
, SettingsSaved
) {
4074 if (spdy_util_
.spdy_version() >= HTTP2
) {
4075 // HTTP/2 doesn't support settings persistence.
4078 static const SpdyHeaderInfo kSynReplyInfo
= {
4079 SYN_REPLY
, // Syn Reply
4081 0, // Associated Stream ID
4082 ConvertRequestPriorityToSpdyPriority(
4083 LOWEST
, spdy_util_
.spdy_version()),
4084 kSpdyCredentialSlotUnused
,
4085 CONTROL_FLAG_NONE
, // Control Flags
4086 false, // Compressed
4087 RST_STREAM_INVALID
, // Status
4090 DATA_FLAG_NONE
// Data Flags
4093 BoundNetLog net_log
;
4094 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
4095 net_log
, GetParam(), NULL
);
4096 helper
.RunPreTestSetup();
4098 // Verify that no settings exist initially.
4099 HostPortPair
host_port_pair("www.example.org", helper
.port());
4100 SpdySessionPool
* spdy_session_pool
= helper
.session()->spdy_session_pool();
4101 EXPECT_TRUE(spdy_session_pool
->http_server_properties()->GetSpdySettings(
4102 host_port_pair
).empty());
4104 // Construct the request.
4105 scoped_ptr
<SpdyFrame
> req(
4106 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
4107 MockWrite writes
[] = {CreateMockWrite(*req
, 0)};
4109 // Construct the reply.
4110 scoped_ptr
<SpdyHeaderBlock
> reply_headers(new SpdyHeaderBlock());
4111 (*reply_headers
)[spdy_util_
.GetStatusKey()] = "200";
4112 (*reply_headers
)[spdy_util_
.GetVersionKey()] = "HTTP/1.1";
4113 scoped_ptr
<SpdyFrame
> reply(
4114 spdy_util_
.ConstructSpdyFrame(kSynReplyInfo
, reply_headers
.Pass()));
4116 const SpdySettingsIds kSampleId1
= SETTINGS_UPLOAD_BANDWIDTH
;
4117 unsigned int kSampleValue1
= 0x0a0a0a0a;
4118 const SpdySettingsIds kSampleId2
= SETTINGS_DOWNLOAD_BANDWIDTH
;
4119 unsigned int kSampleValue2
= 0x0b0b0b0b;
4120 const SpdySettingsIds kSampleId3
= SETTINGS_ROUND_TRIP_TIME
;
4121 unsigned int kSampleValue3
= 0x0c0c0c0c;
4122 scoped_ptr
<SpdyFrame
> settings_frame
;
4124 // Construct the SETTINGS frame.
4125 SettingsMap settings
;
4126 // First add a persisted setting.
4127 settings
[kSampleId1
] =
4128 SettingsFlagsAndValue(SETTINGS_FLAG_PLEASE_PERSIST
, kSampleValue1
);
4129 // Next add a non-persisted setting.
4130 settings
[kSampleId2
] =
4131 SettingsFlagsAndValue(SETTINGS_FLAG_NONE
, kSampleValue2
);
4132 // Next add another persisted setting.
4133 settings
[kSampleId3
] =
4134 SettingsFlagsAndValue(SETTINGS_FLAG_PLEASE_PERSIST
, kSampleValue3
);
4135 settings_frame
.reset(spdy_util_
.ConstructSpdySettings(settings
));
4138 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
4139 MockRead reads
[] = {
4140 CreateMockRead(*reply
, 1),
4141 CreateMockRead(*body
, 2),
4142 CreateMockRead(*settings_frame
, 3),
4143 MockRead(ASYNC
, 0, 4) // EOF
4146 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
4147 helper
.AddData(&data
);
4148 helper
.RunDefaultTest();
4149 helper
.VerifyDataConsumed();
4150 TransactionHelperResult out
= helper
.output();
4151 EXPECT_EQ(OK
, out
.rv
);
4152 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
4153 EXPECT_EQ("hello!", out
.response_data
);
4156 // Verify we had two persisted settings.
4157 const SettingsMap
& settings_map
=
4158 spdy_session_pool
->http_server_properties()->GetSpdySettings(
4160 ASSERT_EQ(2u, settings_map
.size());
4162 // Verify the first persisted setting.
4163 SettingsMap::const_iterator it1
= settings_map
.find(kSampleId1
);
4164 EXPECT_TRUE(it1
!= settings_map
.end());
4165 SettingsFlagsAndValue flags_and_value1
= it1
->second
;
4166 EXPECT_EQ(SETTINGS_FLAG_PERSISTED
, flags_and_value1
.first
);
4167 EXPECT_EQ(kSampleValue1
, flags_and_value1
.second
);
4169 // Verify the second persisted setting.
4170 SettingsMap::const_iterator it3
= settings_map
.find(kSampleId3
);
4171 EXPECT_TRUE(it3
!= settings_map
.end());
4172 SettingsFlagsAndValue flags_and_value3
= it3
->second
;
4173 EXPECT_EQ(SETTINGS_FLAG_PERSISTED
, flags_and_value3
.first
);
4174 EXPECT_EQ(kSampleValue3
, flags_and_value3
.second
);
4178 // Test that when there are settings saved that they are sent back to the
4179 // server upon session establishment.
4180 TEST_P(SpdyNetworkTransactionTest
, SettingsPlayback
) {
4181 if (spdy_util_
.spdy_version() >= HTTP2
) {
4182 // HTTP/2 doesn't support settings persistence.
4185 static const SpdyHeaderInfo kSynReplyInfo
= {
4186 SYN_REPLY
, // Syn Reply
4188 0, // Associated Stream ID
4189 ConvertRequestPriorityToSpdyPriority(
4190 LOWEST
, spdy_util_
.spdy_version()),
4191 kSpdyCredentialSlotUnused
,
4192 CONTROL_FLAG_NONE
, // Control Flags
4193 false, // Compressed
4194 RST_STREAM_INVALID
, // Status
4197 DATA_FLAG_NONE
// Data Flags
4200 BoundNetLog net_log
;
4201 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
4202 net_log
, GetParam(), NULL
);
4203 helper
.RunPreTestSetup();
4205 SpdySessionPool
* spdy_session_pool
= helper
.session()->spdy_session_pool();
4207 SpdySessionPoolPeer
pool_peer(spdy_session_pool
);
4208 pool_peer
.SetEnableSendingInitialData(true);
4210 // Verify that no settings exist initially.
4211 HostPortPair
host_port_pair("www.example.org", helper
.port());
4212 EXPECT_TRUE(spdy_session_pool
->http_server_properties()->GetSpdySettings(
4213 host_port_pair
).empty());
4215 const SpdySettingsIds kSampleId1
= SETTINGS_MAX_CONCURRENT_STREAMS
;
4216 unsigned int kSampleValue1
= 0x0a0a0a0a;
4217 const SpdySettingsIds kSampleId2
= SETTINGS_INITIAL_WINDOW_SIZE
;
4218 unsigned int kSampleValue2
= 0x0c0c0c0c;
4220 // First add a persisted setting.
4221 spdy_session_pool
->http_server_properties()->SetSpdySetting(
4224 SETTINGS_FLAG_PLEASE_PERSIST
,
4227 // Next add another persisted setting.
4228 spdy_session_pool
->http_server_properties()->SetSpdySetting(
4231 SETTINGS_FLAG_PLEASE_PERSIST
,
4234 EXPECT_EQ(2u, spdy_session_pool
->http_server_properties()->GetSpdySettings(
4235 host_port_pair
).size());
4237 // Construct the initial SETTINGS frame.
4238 SettingsMap initial_settings
;
4239 initial_settings
[SETTINGS_MAX_CONCURRENT_STREAMS
] =
4240 SettingsFlagsAndValue(SETTINGS_FLAG_NONE
, kMaxConcurrentPushedStreams
);
4241 scoped_ptr
<SpdyFrame
> initial_settings_frame(
4242 spdy_util_
.ConstructSpdySettings(initial_settings
));
4244 // Construct the persisted SETTINGS frame.
4245 const SettingsMap
& settings
=
4246 spdy_session_pool
->http_server_properties()->GetSpdySettings(
4248 scoped_ptr
<SpdyFrame
> settings_frame(
4249 spdy_util_
.ConstructSpdySettings(settings
));
4251 // Construct the request.
4252 scoped_ptr
<SpdyFrame
> req(
4253 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
4255 MockWrite writes
[] = {
4256 CreateMockWrite(*initial_settings_frame
, 0),
4257 CreateMockWrite(*settings_frame
, 1),
4258 CreateMockWrite(*req
, 2),
4261 // Construct the reply.
4262 scoped_ptr
<SpdyHeaderBlock
> reply_headers(new SpdyHeaderBlock());
4263 (*reply_headers
)[spdy_util_
.GetStatusKey()] = "200";
4264 (*reply_headers
)[spdy_util_
.GetVersionKey()] = "HTTP/1.1";
4265 scoped_ptr
<SpdyFrame
> reply(
4266 spdy_util_
.ConstructSpdyFrame(kSynReplyInfo
, reply_headers
.Pass()));
4268 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
4269 MockRead reads
[] = {
4270 CreateMockRead(*reply
, 3),
4271 CreateMockRead(*body
, 4),
4272 MockRead(ASYNC
, 0, 5) // EOF
4275 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
4276 helper
.AddData(&data
);
4277 helper
.RunDefaultTest();
4278 helper
.VerifyDataConsumed();
4279 TransactionHelperResult out
= helper
.output();
4280 EXPECT_EQ(OK
, out
.rv
);
4281 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
4282 EXPECT_EQ("hello!", out
.response_data
);
4285 // Verify we had two persisted settings.
4286 const SettingsMap
& settings_map
=
4287 spdy_session_pool
->http_server_properties()->GetSpdySettings(
4289 ASSERT_EQ(2u, settings_map
.size());
4291 // Verify the first persisted setting.
4292 SettingsMap::const_iterator it1
= settings_map
.find(kSampleId1
);
4293 EXPECT_TRUE(it1
!= settings_map
.end());
4294 SettingsFlagsAndValue flags_and_value1
= it1
->second
;
4295 EXPECT_EQ(SETTINGS_FLAG_PERSISTED
, flags_and_value1
.first
);
4296 EXPECT_EQ(kSampleValue1
, flags_and_value1
.second
);
4298 // Verify the second persisted setting.
4299 SettingsMap::const_iterator it2
= settings_map
.find(kSampleId2
);
4300 EXPECT_TRUE(it2
!= settings_map
.end());
4301 SettingsFlagsAndValue flags_and_value2
= it2
->second
;
4302 EXPECT_EQ(SETTINGS_FLAG_PERSISTED
, flags_and_value2
.first
);
4303 EXPECT_EQ(kSampleValue2
, flags_and_value2
.second
);
4307 TEST_P(SpdyNetworkTransactionTest
, GoAwayWithActiveStream
) {
4308 scoped_ptr
<SpdyFrame
> req(
4309 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
4310 MockWrite writes
[] = {CreateMockWrite(*req
, 0)};
4312 scoped_ptr
<SpdyFrame
> go_away(spdy_util_
.ConstructSpdyGoAway());
4313 MockRead reads
[] = {
4314 CreateMockRead(*go_away
, 1),
4317 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
4318 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
4319 BoundNetLog(), GetParam(), NULL
);
4320 helper
.AddData(&data
);
4321 helper
.RunToCompletion(&data
);
4322 TransactionHelperResult out
= helper
.output();
4323 EXPECT_EQ(ERR_ABORTED
, out
.rv
);
4326 TEST_P(SpdyNetworkTransactionTest
, CloseWithActiveStream
) {
4327 scoped_ptr
<SpdyFrame
> req(
4328 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
4329 MockWrite writes
[] = {CreateMockWrite(*req
, 0)};
4331 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
4332 MockRead reads
[] = {
4333 CreateMockRead(*resp
, 1), MockRead(SYNCHRONOUS
, 0, 2) // EOF
4336 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
4338 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
4339 log
, GetParam(), NULL
);
4340 helper
.RunPreTestSetup();
4341 helper
.AddData(&data
);
4342 HttpNetworkTransaction
* trans
= helper
.trans();
4344 TestCompletionCallback callback
;
4345 TransactionHelperResult out
;
4346 out
.rv
= trans
->Start(&CreateGetRequest(), callback
.callback(), log
);
4348 EXPECT_EQ(out
.rv
, ERR_IO_PENDING
);
4349 out
.rv
= callback
.WaitForResult();
4350 EXPECT_EQ(out
.rv
, OK
);
4352 const HttpResponseInfo
* response
= trans
->GetResponseInfo();
4353 EXPECT_TRUE(response
->headers
.get() != NULL
);
4354 EXPECT_TRUE(response
->was_fetched_via_spdy
);
4355 out
.rv
= ReadTransaction(trans
, &out
.response_data
);
4356 EXPECT_EQ(ERR_CONNECTION_CLOSED
, out
.rv
);
4358 // Verify that we consumed all test data.
4359 helper
.VerifyDataConsumed();
4362 // HTTP_1_1_REQUIRED results in ERR_HTTP_1_1_REQUIRED.
4363 TEST_P(SpdyNetworkTransactionTest
, HTTP11RequiredError
) {
4364 // HTTP_1_1_REQUIRED is only supported by HTTP/2.
4365 if (spdy_util_
.spdy_version() < HTTP2
)
4368 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
4369 BoundNetLog(), GetParam(), nullptr);
4371 scoped_ptr
<SpdyFrame
> go_away(spdy_util_
.ConstructSpdyGoAway(
4372 0, GOAWAY_HTTP_1_1_REQUIRED
, "Try again using HTTP/1.1 please."));
4373 MockRead reads
[] = {
4374 CreateMockRead(*go_away
, 0),
4376 SequencedSocketData
data(reads
, arraysize(reads
), nullptr, 0);
4378 helper
.RunToCompletion(&data
);
4379 TransactionHelperResult out
= helper
.output();
4380 EXPECT_EQ(ERR_HTTP_1_1_REQUIRED
, out
.rv
);
4383 // Retry with HTTP/1.1 when receiving HTTP_1_1_REQUIRED. Note that no actual
4384 // protocol negotiation happens, instead this test forces protocols for both
4386 TEST_P(SpdyNetworkTransactionTest
, HTTP11RequiredRetry
) {
4387 // HTTP_1_1_REQUIRED is only supported by HTTP/2.
4388 if (spdy_util_
.spdy_version() < HTTP2
)
4390 // HTTP_1_1_REQUIRED implementation relies on the assumption that HTTP/2 is
4391 // only spoken over SSL.
4392 if (GetParam().ssl_type
!= HTTPS_SPDY_VIA_NPN
)
4395 HttpRequestInfo request
;
4396 request
.method
= "GET";
4397 request
.url
= GURL("https://www.example.org/");
4398 scoped_ptr
<SpdySessionDependencies
> session_deps(
4399 CreateSpdySessionDependencies(GetParam()));
4400 // Do not force SPDY so that second socket can negotiate HTTP/1.1.
4401 session_deps
->next_protos
= SpdyNextProtos();
4402 NormalSpdyTransactionHelper
helper(request
, DEFAULT_PRIORITY
, BoundNetLog(),
4403 GetParam(), session_deps
.release());
4405 // First socket: HTTP/2 request rejected with HTTP_1_1_REQUIRED.
4406 const char* url
= request
.url
.spec().c_str();
4407 scoped_ptr
<SpdyHeaderBlock
> headers(spdy_util_
.ConstructGetHeaderBlock(url
));
4408 scoped_ptr
<SpdyFrame
> req(
4409 spdy_util_
.ConstructSpdySyn(1, *headers
, LOWEST
, false, true));
4410 MockWrite writes0
[] = {CreateMockWrite(*req
, 0)};
4411 scoped_ptr
<SpdyFrame
> go_away(spdy_util_
.ConstructSpdyGoAway(
4412 0, GOAWAY_HTTP_1_1_REQUIRED
, "Try again using HTTP/1.1 please."));
4413 MockRead reads0
[] = {CreateMockRead(*go_away
, 1)};
4414 SequencedSocketData
data0(reads0
, arraysize(reads0
), writes0
,
4415 arraysize(writes0
));
4417 scoped_ptr
<SSLSocketDataProvider
> ssl_provider0(
4418 new SSLSocketDataProvider(ASYNC
, OK
));
4419 // Expect HTTP/2 protocols too in SSLConfig.
4420 ssl_provider0
->next_protos_expected_in_ssl_config
.push_back(kProtoHTTP11
);
4421 ssl_provider0
->next_protos_expected_in_ssl_config
.push_back(kProtoSPDY31
);
4422 ssl_provider0
->next_protos_expected_in_ssl_config
.push_back(kProtoHTTP2
);
4424 ssl_provider0
->SetNextProto(GetParam().protocol
);
4425 helper
.AddDataWithSSLSocketDataProvider(&data0
, ssl_provider0
.Pass());
4427 // Second socket: falling back to HTTP/1.1.
4428 MockWrite writes1
[] = {MockWrite(ASYNC
, 0,
4429 "GET / HTTP/1.1\r\n"
4430 "Host: www.example.org\r\n"
4431 "Connection: keep-alive\r\n\r\n")};
4432 MockRead reads1
[] = {MockRead(ASYNC
, 1,
4433 "HTTP/1.1 200 OK\r\n"
4434 "Content-Length: 5\r\n\r\n"
4436 SequencedSocketData
data1(reads1
, arraysize(reads1
), writes1
,
4437 arraysize(writes1
));
4439 scoped_ptr
<SSLSocketDataProvider
> ssl_provider1(
4440 new SSLSocketDataProvider(ASYNC
, OK
));
4441 // Expect only HTTP/1.1 protocol in SSLConfig.
4442 ssl_provider1
->next_protos_expected_in_ssl_config
.push_back(kProtoHTTP11
);
4444 ssl_provider1
->SetNextProto(kProtoHTTP11
);
4445 helper
.AddDataWithSSLSocketDataProvider(&data1
, ssl_provider1
.Pass());
4447 base::WeakPtr
<HttpServerProperties
> http_server_properties
=
4448 helper
.session()->spdy_session_pool()->http_server_properties();
4449 const HostPortPair host_port_pair
= HostPortPair::FromURL(GURL(url
));
4450 EXPECT_FALSE(http_server_properties
->RequiresHTTP11(host_port_pair
));
4452 helper
.RunPreTestSetup();
4453 helper
.StartDefaultTest();
4454 helper
.FinishDefaultTestWithoutVerification();
4455 helper
.VerifyDataConsumed();
4456 EXPECT_TRUE(http_server_properties
->RequiresHTTP11(host_port_pair
));
4458 const HttpResponseInfo
* response
= helper
.trans()->GetResponseInfo();
4459 ASSERT_TRUE(response
!= nullptr);
4460 ASSERT_TRUE(response
->headers
.get() != nullptr);
4461 EXPECT_EQ("HTTP/1.1 200 OK", response
->headers
->GetStatusLine());
4462 EXPECT_FALSE(response
->was_fetched_via_spdy
);
4463 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP1
, response
->connection_info
);
4464 EXPECT_TRUE(response
->was_npn_negotiated
);
4465 EXPECT_TRUE(request
.url
.SchemeIs("https"));
4466 EXPECT_EQ("127.0.0.1", response
->socket_address
.host());
4467 EXPECT_EQ(443, response
->socket_address
.port());
4468 std::string response_data
;
4469 ASSERT_EQ(OK
, ReadTransaction(helper
.trans(), &response_data
));
4470 EXPECT_EQ("hello", response_data
);
4473 // Retry with HTTP/1.1 to the proxy when receiving HTTP_1_1_REQUIRED from the
4474 // proxy. Note that no actual protocol negotiation happens, instead this test
4475 // forces protocols for both sockets.
4476 TEST_P(SpdyNetworkTransactionTest
, HTTP11RequiredProxyRetry
) {
4477 // HTTP_1_1_REQUIRED is only supported by HTTP/2.
4478 if (spdy_util_
.spdy_version() < HTTP2
)
4480 // HTTP_1_1_REQUIRED implementation relies on the assumption that HTTP/2 is
4481 // only spoken over SSL.
4482 if (GetParam().ssl_type
!= HTTPS_SPDY_VIA_NPN
)
4485 HttpRequestInfo request
;
4486 request
.method
= "GET";
4487 request
.url
= GURL("https://www.example.org/");
4488 scoped_ptr
<SpdySessionDependencies
> session_deps(
4489 CreateSpdySessionDependencies(
4491 ProxyService::CreateFixedFromPacResult("HTTPS myproxy:70")));
4492 // Do not force SPDY so that second socket can negotiate HTTP/1.1.
4493 session_deps
->next_protos
= SpdyNextProtos();
4494 NormalSpdyTransactionHelper
helper(request
, DEFAULT_PRIORITY
, BoundNetLog(),
4495 GetParam(), session_deps
.release());
4497 // First socket: HTTP/2 CONNECT rejected with HTTP_1_1_REQUIRED.
4498 scoped_ptr
<SpdyFrame
> req(spdy_util_
.ConstructSpdyConnect(
4499 nullptr, 0, 1, LOWEST
, HostPortPair("www.example.org", 443)));
4500 MockWrite writes0
[] = {CreateMockWrite(*req
, 0)};
4501 scoped_ptr
<SpdyFrame
> go_away(spdy_util_
.ConstructSpdyGoAway(
4502 0, GOAWAY_HTTP_1_1_REQUIRED
, "Try again using HTTP/1.1 please."));
4503 MockRead reads0
[] = {CreateMockRead(*go_away
, 1)};
4504 SequencedSocketData
data0(reads0
, arraysize(reads0
), writes0
,
4505 arraysize(writes0
));
4507 scoped_ptr
<SSLSocketDataProvider
> ssl_provider0(
4508 new SSLSocketDataProvider(ASYNC
, OK
));
4509 // Expect HTTP/2 protocols too in SSLConfig.
4510 ssl_provider0
->next_protos_expected_in_ssl_config
.push_back(kProtoHTTP11
);
4511 ssl_provider0
->next_protos_expected_in_ssl_config
.push_back(kProtoSPDY31
);
4512 ssl_provider0
->next_protos_expected_in_ssl_config
.push_back(kProtoHTTP2
);
4514 ssl_provider0
->SetNextProto(GetParam().protocol
);
4515 helper
.AddDataWithSSLSocketDataProvider(&data0
, ssl_provider0
.Pass());
4517 // Second socket: retry using HTTP/1.1.
4518 MockWrite writes1
[] = {
4520 "CONNECT www.example.org:443 HTTP/1.1\r\n"
4521 "Host: www.example.org\r\n"
4522 "Proxy-Connection: keep-alive\r\n\r\n"),
4524 "GET / HTTP/1.1\r\n"
4525 "Host: www.example.org\r\n"
4526 "Connection: keep-alive\r\n\r\n"),
4529 MockRead reads1
[] = {
4530 MockRead(ASYNC
, 1, "HTTP/1.1 200 OK\r\n\r\n"),
4532 "HTTP/1.1 200 OK\r\n"
4533 "Content-Length: 5\r\n\r\n"
4536 SequencedSocketData
data1(reads1
, arraysize(reads1
), writes1
,
4537 arraysize(writes1
));
4539 scoped_ptr
<SSLSocketDataProvider
> ssl_provider1(
4540 new SSLSocketDataProvider(ASYNC
, OK
));
4541 // Expect only HTTP/1.1 protocol in SSLConfig.
4542 ssl_provider1
->next_protos_expected_in_ssl_config
.push_back(kProtoHTTP11
);
4544 ssl_provider1
->SetNextProto(kProtoHTTP11
);
4545 helper
.AddDataWithSSLSocketDataProvider(&data1
, ssl_provider1
.Pass());
4547 // A third socket is needed for the tunnelled connection.
4548 scoped_ptr
<SSLSocketDataProvider
> ssl_provider2(
4549 new SSLSocketDataProvider(ASYNC
, OK
));
4550 helper
.session_deps()->socket_factory
->AddSSLSocketDataProvider(
4551 ssl_provider2
.get());
4553 base::WeakPtr
<HttpServerProperties
> http_server_properties
=
4554 helper
.session()->spdy_session_pool()->http_server_properties();
4555 const HostPortPair proxy_host_port_pair
= HostPortPair("myproxy", 70);
4556 EXPECT_FALSE(http_server_properties
->RequiresHTTP11(proxy_host_port_pair
));
4558 helper
.RunPreTestSetup();
4559 helper
.StartDefaultTest();
4560 helper
.FinishDefaultTestWithoutVerification();
4561 helper
.VerifyDataConsumed();
4562 EXPECT_TRUE(http_server_properties
->RequiresHTTP11(proxy_host_port_pair
));
4564 const HttpResponseInfo
* response
= helper
.trans()->GetResponseInfo();
4565 ASSERT_TRUE(response
!= nullptr);
4566 ASSERT_TRUE(response
->headers
.get() != nullptr);
4567 EXPECT_EQ("HTTP/1.1 200 OK", response
->headers
->GetStatusLine());
4568 EXPECT_FALSE(response
->was_fetched_via_spdy
);
4569 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP1
, response
->connection_info
);
4570 EXPECT_FALSE(response
->was_npn_negotiated
);
4571 EXPECT_TRUE(request
.url
.SchemeIs("https"));
4572 EXPECT_EQ("127.0.0.1", response
->socket_address
.host());
4573 EXPECT_EQ(70, response
->socket_address
.port());
4574 std::string response_data
;
4575 ASSERT_EQ(OK
, ReadTransaction(helper
.trans(), &response_data
));
4576 EXPECT_EQ("hello", response_data
);
4579 // Test to make sure we can correctly connect through a proxy.
4580 TEST_P(SpdyNetworkTransactionTest
, ProxyConnect
) {
4581 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
4582 BoundNetLog(), GetParam(), NULL
);
4583 helper
.session_deps().reset(CreateSpdySessionDependencies(
4585 ProxyService::CreateFixedFromPacResult("PROXY myproxy:70")));
4586 helper
.SetSession(make_scoped_refptr(
4587 SpdySessionDependencies::SpdyCreateSession(helper
.session_deps().get())));
4588 helper
.RunPreTestSetup();
4589 HttpNetworkTransaction
* trans
= helper
.trans();
4591 const char kConnect443
[] = {
4592 "CONNECT www.example.org:443 HTTP/1.1\r\n"
4593 "Host: www.example.org\r\n"
4594 "Proxy-Connection: keep-alive\r\n\r\n"};
4595 const char kHTTP200
[] = {"HTTP/1.1 200 OK\r\n\r\n"};
4596 scoped_ptr
<SpdyFrame
> req(
4597 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
4598 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
4599 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
4601 MockWrite writes
[] = {
4602 MockWrite(SYNCHRONOUS
, kConnect443
, arraysize(kConnect443
) - 1, 0),
4603 CreateMockWrite(*req
, 2),
4605 MockRead reads
[] = {
4606 MockRead(SYNCHRONOUS
, kHTTP200
, arraysize(kHTTP200
) - 1, 1),
4607 CreateMockRead(*resp
, 3),
4608 CreateMockRead(*body
.get(), 4),
4609 MockRead(ASYNC
, 0, 0, 5),
4611 scoped_ptr
<SequencedSocketData
> data(new SequencedSocketData(
4612 reads
, arraysize(reads
), writes
, arraysize(writes
)));
4614 helper
.AddData(data
.get());
4615 TestCompletionCallback callback
;
4617 int rv
= trans
->Start(
4618 &CreateGetRequest(), callback
.callback(), BoundNetLog());
4619 EXPECT_EQ(ERR_IO_PENDING
, rv
);
4621 rv
= callback
.WaitForResult();
4624 // Verify the SYN_REPLY.
4625 HttpResponseInfo response
= *trans
->GetResponseInfo();
4626 EXPECT_TRUE(response
.headers
.get() != NULL
);
4627 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
4629 std::string response_data
;
4630 ASSERT_EQ(OK
, ReadTransaction(trans
, &response_data
));
4631 EXPECT_EQ("hello!", response_data
);
4632 helper
.VerifyDataConsumed();
4635 // Test to make sure we can correctly connect through a proxy to
4636 // www.example.org, if there already exists a direct spdy connection to
4637 // www.example.org. See https://crbug.com/49874.
4638 TEST_P(SpdyNetworkTransactionTest
, DirectConnectProxyReconnect
) {
4639 // When setting up the first transaction, we store the SpdySessionPool so that
4640 // we can use the same pool in the second transaction.
4641 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
4642 BoundNetLog(), GetParam(), NULL
);
4644 // Use a proxy service which returns a proxy fallback list from DIRECT to
4645 // myproxy:70. For this test there will be no fallback, so it is equivalent
4646 // to simply DIRECT. The reason for appending the second proxy is to verify
4647 // that the session pool key used does is just "DIRECT".
4648 helper
.session_deps().reset(CreateSpdySessionDependencies(
4650 ProxyService::CreateFixedFromPacResult("DIRECT; PROXY myproxy:70")));
4651 helper
.SetSession(make_scoped_refptr(
4652 SpdySessionDependencies::SpdyCreateSession(helper
.session_deps().get())));
4654 SpdySessionPool
* spdy_session_pool
= helper
.session()->spdy_session_pool();
4655 helper
.RunPreTestSetup();
4657 // Construct and send a simple GET request.
4658 scoped_ptr
<SpdyFrame
> req(
4659 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
4660 MockWrite writes
[] = {
4661 CreateMockWrite(*req
, 0),
4664 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
4665 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
4666 MockRead reads
[] = {
4667 CreateMockRead(*resp
, 1),
4668 CreateMockRead(*body
, 2),
4669 MockRead(SYNCHRONOUS
, ERR_IO_PENDING
, 3), // Force a pause
4671 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
4672 helper
.AddData(&data
);
4673 HttpNetworkTransaction
* trans
= helper
.trans();
4675 TestCompletionCallback callback
;
4676 TransactionHelperResult out
;
4677 out
.rv
= trans
->Start(
4678 &CreateGetRequest(), callback
.callback(), BoundNetLog());
4680 EXPECT_EQ(out
.rv
, ERR_IO_PENDING
);
4681 out
.rv
= callback
.WaitForResult();
4682 EXPECT_EQ(out
.rv
, OK
);
4684 const HttpResponseInfo
* response
= trans
->GetResponseInfo();
4685 EXPECT_TRUE(response
->headers
.get() != NULL
);
4686 EXPECT_TRUE(response
->was_fetched_via_spdy
);
4687 out
.rv
= ReadTransaction(trans
, &out
.response_data
);
4688 EXPECT_EQ(OK
, out
.rv
);
4689 out
.status_line
= response
->headers
->GetStatusLine();
4690 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
4691 EXPECT_EQ("hello!", out
.response_data
);
4693 // Check that the SpdySession is still in the SpdySessionPool.
4694 HostPortPair
host_port_pair("www.example.org", helper
.port());
4695 SpdySessionKey
session_pool_key_direct(
4696 host_port_pair
, ProxyServer::Direct(), PRIVACY_MODE_DISABLED
);
4697 EXPECT_TRUE(HasSpdySession(spdy_session_pool
, session_pool_key_direct
));
4698 SpdySessionKey
session_pool_key_proxy(
4700 ProxyServer::FromURI("www.foo.com", ProxyServer::SCHEME_HTTP
),
4701 PRIVACY_MODE_DISABLED
);
4702 EXPECT_FALSE(HasSpdySession(spdy_session_pool
, session_pool_key_proxy
));
4704 // Set up data for the proxy connection.
4705 const char kConnect443
[] = {
4706 "CONNECT www.example.org:443 HTTP/1.1\r\n"
4707 "Host: www.example.org\r\n"
4708 "Proxy-Connection: keep-alive\r\n\r\n"};
4709 const char kHTTP200
[] = {"HTTP/1.1 200 OK\r\n\r\n"};
4710 scoped_ptr
<SpdyFrame
> req2(spdy_util_
.ConstructSpdyGet(
4711 GetDefaultUrlWithPath("/foo.dat").c_str(), false, 1, LOWEST
));
4712 scoped_ptr
<SpdyFrame
> resp2(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
4713 scoped_ptr
<SpdyFrame
> body2(spdy_util_
.ConstructSpdyBodyFrame(1, true));
4715 MockWrite writes2
[] = {
4716 MockWrite(SYNCHRONOUS
, kConnect443
, arraysize(kConnect443
) - 1, 0),
4717 CreateMockWrite(*req2
, 2),
4719 MockRead reads2
[] = {
4720 MockRead(SYNCHRONOUS
, kHTTP200
, arraysize(kHTTP200
) - 1, 1),
4721 CreateMockRead(*resp2
, 3),
4722 CreateMockRead(*body2
, 4),
4723 MockRead(ASYNC
, 0, 5) // EOF
4726 scoped_ptr
<SequencedSocketData
> data_proxy(new SequencedSocketData(
4727 reads2
, arraysize(reads2
), writes2
, arraysize(writes2
)));
4729 // Create another request to www.example.org, but this time through a proxy.
4730 HttpRequestInfo request_proxy
;
4731 request_proxy
.method
= "GET";
4732 request_proxy
.url
= GURL(GetDefaultUrlWithPath("/foo.dat"));
4733 request_proxy
.load_flags
= 0;
4734 scoped_ptr
<SpdySessionDependencies
> ssd_proxy(
4735 CreateSpdySessionDependencies(GetParam()));
4736 // Ensure that this transaction uses the same SpdySessionPool.
4737 scoped_refptr
<HttpNetworkSession
> session_proxy(
4738 SpdySessionDependencies::SpdyCreateSession(ssd_proxy
.get()));
4739 NormalSpdyTransactionHelper
helper_proxy(request_proxy
, DEFAULT_PRIORITY
,
4740 BoundNetLog(), GetParam(), NULL
);
4741 HttpNetworkSessionPeer
session_peer(session_proxy
);
4742 scoped_ptr
<ProxyService
> proxy_service(
4743 ProxyService::CreateFixedFromPacResult("PROXY myproxy:70"));
4744 session_peer
.SetProxyService(proxy_service
.get());
4745 helper_proxy
.session_deps().swap(ssd_proxy
);
4746 helper_proxy
.SetSession(session_proxy
);
4747 helper_proxy
.RunPreTestSetup();
4748 helper_proxy
.AddData(data_proxy
.get());
4750 HttpNetworkTransaction
* trans_proxy
= helper_proxy
.trans();
4751 TestCompletionCallback callback_proxy
;
4752 int rv
= trans_proxy
->Start(
4753 &request_proxy
, callback_proxy
.callback(), BoundNetLog());
4754 EXPECT_EQ(ERR_IO_PENDING
, rv
);
4755 rv
= callback_proxy
.WaitForResult();
4758 HttpResponseInfo response_proxy
= *trans_proxy
->GetResponseInfo();
4759 EXPECT_TRUE(response_proxy
.headers
.get() != NULL
);
4760 EXPECT_EQ("HTTP/1.1 200 OK", response_proxy
.headers
->GetStatusLine());
4762 std::string response_data
;
4763 ASSERT_EQ(OK
, ReadTransaction(trans_proxy
, &response_data
));
4764 EXPECT_EQ("hello!", response_data
);
4766 helper_proxy
.VerifyDataConsumed();
4769 // When we get a TCP-level RST, we need to retry a HttpNetworkTransaction
4770 // on a new connection, if the connection was previously known to be good.
4771 // This can happen when a server reboots without saying goodbye, or when
4772 // we're behind a NAT that masked the RST.
4773 TEST_P(SpdyNetworkTransactionTest
, VerifyRetryOnConnectionReset
) {
4774 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
4775 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
4776 MockRead reads
[] = {
4777 CreateMockRead(*resp
, 1),
4778 CreateMockRead(*body
, 2),
4779 MockRead(ASYNC
, ERR_IO_PENDING
, 3),
4780 MockRead(ASYNC
, ERR_CONNECTION_RESET
, 4),
4783 MockRead reads2
[] = {
4784 CreateMockRead(*resp
, 1),
4785 CreateMockRead(*body
, 2),
4786 MockRead(ASYNC
, 0, 3) // EOF
4789 scoped_ptr
<SpdyFrame
> req(
4790 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
4791 scoped_ptr
<SpdyFrame
> req3(
4792 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 3, LOWEST
, true));
4793 MockWrite writes1
[] = {CreateMockWrite(*req
, 0), CreateMockWrite(*req3
, 5)};
4794 MockWrite writes2
[] = {CreateMockWrite(*req
, 0)};
4796 // This test has a couple of variants.
4798 // Induce the RST while waiting for our transaction to send.
4799 VARIANT_RST_DURING_SEND_COMPLETION
= 0,
4800 // Induce the RST while waiting for our transaction to read.
4801 // In this case, the send completed - everything copied into the SNDBUF.
4802 VARIANT_RST_DURING_READ_COMPLETION
= 1
4805 for (int variant
= VARIANT_RST_DURING_SEND_COMPLETION
;
4806 variant
<= VARIANT_RST_DURING_READ_COMPLETION
;
4808 SequencedSocketData
data1(reads
, arraysize(reads
), writes1
, 1 + variant
);
4810 SequencedSocketData
data2(reads2
, arraysize(reads2
), writes2
,
4811 arraysize(writes2
));
4813 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
4814 BoundNetLog(), GetParam(), NULL
);
4815 helper
.AddData(&data1
);
4816 helper
.AddData(&data2
);
4817 helper
.RunPreTestSetup();
4819 for (int i
= 0; i
< 2; ++i
) {
4820 scoped_ptr
<HttpNetworkTransaction
> trans(
4821 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
4823 TestCompletionCallback callback
;
4824 int rv
= trans
->Start(
4825 &helper
.request(), callback
.callback(), BoundNetLog());
4826 EXPECT_EQ(ERR_IO_PENDING
, rv
);
4827 // On the second transaction, we trigger the RST.
4829 if (variant
== VARIANT_RST_DURING_READ_COMPLETION
) {
4830 // Writes to the socket complete asynchronously on SPDY by running
4831 // through the message loop. Complete the write here.
4832 base::RunLoop().RunUntilIdle();
4835 // Now schedule the ERR_CONNECTION_RESET.
4836 data1
.CompleteRead();
4838 rv
= callback
.WaitForResult();
4841 const HttpResponseInfo
* response
= trans
->GetResponseInfo();
4842 ASSERT_TRUE(response
!= NULL
);
4843 EXPECT_TRUE(response
->headers
.get() != NULL
);
4844 EXPECT_TRUE(response
->was_fetched_via_spdy
);
4845 std::string response_data
;
4846 rv
= ReadTransaction(trans
.get(), &response_data
);
4848 EXPECT_EQ("HTTP/1.1 200 OK", response
->headers
->GetStatusLine());
4849 EXPECT_EQ("hello!", response_data
);
4850 base::RunLoop().RunUntilIdle();
4853 helper
.VerifyDataConsumed();
4854 base::RunLoop().RunUntilIdle();
4858 // Test that turning SPDY on and off works properly.
4859 TEST_P(SpdyNetworkTransactionTest
, SpdyOnOffToggle
) {
4860 HttpStreamFactory::set_spdy_enabled(true);
4861 scoped_ptr
<SpdyFrame
> req(
4862 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
4863 MockWrite spdy_writes
[] = {CreateMockWrite(*req
, 0)};
4865 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
4866 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
4867 MockRead spdy_reads
[] = {
4868 CreateMockRead(*resp
, 1),
4869 CreateMockRead(*body
, 2),
4870 MockRead(ASYNC
, 0, 3) // EOF
4873 SequencedSocketData
data(spdy_reads
, arraysize(spdy_reads
), spdy_writes
,
4874 arraysize(spdy_writes
));
4875 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
4876 BoundNetLog(), GetParam(), NULL
);
4877 helper
.RunToCompletion(&data
);
4878 TransactionHelperResult out
= helper
.output();
4879 EXPECT_EQ(OK
, out
.rv
);
4880 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
4881 EXPECT_EQ("hello!", out
.response_data
);
4883 HttpStreamFactory::set_spdy_enabled(false);
4884 MockWrite http_writes
[] = {
4885 MockWrite(SYNCHRONOUS
, 0,
4886 "GET / HTTP/1.1\r\n"
4887 "Host: www.example.org\r\n"
4888 "Connection: keep-alive\r\n\r\n"),
4891 MockRead http_reads
[] = {
4892 MockRead(SYNCHRONOUS
, 1, "HTTP/1.1 200 OK\r\n\r\n"),
4893 MockRead(SYNCHRONOUS
, 2, "hello from http"),
4894 MockRead(SYNCHRONOUS
, OK
, 3),
4896 SequencedSocketData
data2(http_reads
, arraysize(http_reads
), http_writes
,
4897 arraysize(http_writes
));
4898 NormalSpdyTransactionHelper
helper2(CreateGetRequest(), DEFAULT_PRIORITY
,
4899 BoundNetLog(), GetParam(), NULL
);
4900 helper2
.SetSpdyDisabled();
4901 helper2
.RunToCompletion(&data2
);
4902 TransactionHelperResult out2
= helper2
.output();
4903 EXPECT_EQ(OK
, out2
.rv
);
4904 EXPECT_EQ("HTTP/1.1 200 OK", out2
.status_line
);
4905 EXPECT_EQ("hello from http", out2
.response_data
);
4907 HttpStreamFactory::set_spdy_enabled(true);
4910 // Tests that Basic authentication works over SPDY
4911 TEST_P(SpdyNetworkTransactionTest
, SpdyBasicAuth
) {
4912 HttpStreamFactory::set_spdy_enabled(true);
4914 // The first request will be a bare GET, the second request will be a
4915 // GET with an Authorization header.
4916 scoped_ptr
<SpdyFrame
> req_get(
4917 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
4918 const char* const kExtraAuthorizationHeaders
[] = {
4919 "authorization", "Basic Zm9vOmJhcg=="
4921 scoped_ptr
<SpdyFrame
> req_get_authorization(
4922 spdy_util_
.ConstructSpdyGet(kExtraAuthorizationHeaders
,
4923 arraysize(kExtraAuthorizationHeaders
) / 2,
4924 false, 3, LOWEST
, true));
4925 MockWrite spdy_writes
[] = {
4926 CreateMockWrite(*req_get
, 0), CreateMockWrite(*req_get_authorization
, 3),
4929 // The first response is a 401 authentication challenge, and the second
4930 // response will be a 200 response since the second request includes a valid
4931 // Authorization header.
4932 const char* const kExtraAuthenticationHeaders
[] = {
4934 "Basic realm=\"MyRealm\""
4936 scoped_ptr
<SpdyFrame
> resp_authentication(
4937 spdy_util_
.ConstructSpdySynReplyError(
4938 "401 Authentication Required",
4939 kExtraAuthenticationHeaders
,
4940 arraysize(kExtraAuthenticationHeaders
) / 2,
4942 scoped_ptr
<SpdyFrame
> body_authentication(
4943 spdy_util_
.ConstructSpdyBodyFrame(1, true));
4944 scoped_ptr
<SpdyFrame
> resp_data(
4945 spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 3));
4946 scoped_ptr
<SpdyFrame
> body_data(spdy_util_
.ConstructSpdyBodyFrame(3, true));
4947 MockRead spdy_reads
[] = {
4948 CreateMockRead(*resp_authentication
, 1),
4949 CreateMockRead(*body_authentication
, 2),
4950 CreateMockRead(*resp_data
, 4),
4951 CreateMockRead(*body_data
, 5),
4952 MockRead(ASYNC
, 0, 6),
4955 SequencedSocketData
data(spdy_reads
, arraysize(spdy_reads
), spdy_writes
,
4956 arraysize(spdy_writes
));
4957 HttpRequestInfo
request(CreateGetRequest());
4958 BoundNetLog net_log
;
4959 NormalSpdyTransactionHelper
helper(request
, DEFAULT_PRIORITY
,
4960 net_log
, GetParam(), NULL
);
4962 helper
.RunPreTestSetup();
4963 helper
.AddData(&data
);
4964 HttpNetworkTransaction
* trans
= helper
.trans();
4965 TestCompletionCallback callback
;
4966 const int rv_start
= trans
->Start(&request
, callback
.callback(), net_log
);
4967 EXPECT_EQ(ERR_IO_PENDING
, rv_start
);
4968 const int rv_start_complete
= callback
.WaitForResult();
4969 EXPECT_EQ(OK
, rv_start_complete
);
4971 // Make sure the response has an auth challenge.
4972 const HttpResponseInfo
* const response_start
= trans
->GetResponseInfo();
4973 ASSERT_TRUE(response_start
!= NULL
);
4974 ASSERT_TRUE(response_start
->headers
.get() != NULL
);
4975 EXPECT_EQ(401, response_start
->headers
->response_code());
4976 EXPECT_TRUE(response_start
->was_fetched_via_spdy
);
4977 AuthChallengeInfo
* auth_challenge
= response_start
->auth_challenge
.get();
4978 ASSERT_TRUE(auth_challenge
!= NULL
);
4979 EXPECT_FALSE(auth_challenge
->is_proxy
);
4980 EXPECT_EQ("basic", auth_challenge
->scheme
);
4981 EXPECT_EQ("MyRealm", auth_challenge
->realm
);
4983 // Restart with a username/password.
4984 AuthCredentials
credentials(base::ASCIIToUTF16("foo"),
4985 base::ASCIIToUTF16("bar"));
4986 TestCompletionCallback callback_restart
;
4987 const int rv_restart
= trans
->RestartWithAuth(
4988 credentials
, callback_restart
.callback());
4989 EXPECT_EQ(ERR_IO_PENDING
, rv_restart
);
4990 const int rv_restart_complete
= callback_restart
.WaitForResult();
4991 EXPECT_EQ(OK
, rv_restart_complete
);
4992 // TODO(cbentzel): This is actually the same response object as before, but
4993 // data has changed.
4994 const HttpResponseInfo
* const response_restart
= trans
->GetResponseInfo();
4995 ASSERT_TRUE(response_restart
!= NULL
);
4996 ASSERT_TRUE(response_restart
->headers
.get() != NULL
);
4997 EXPECT_EQ(200, response_restart
->headers
->response_code());
4998 EXPECT_TRUE(response_restart
->auth_challenge
.get() == NULL
);
5001 TEST_P(SpdyNetworkTransactionTest
, ServerPushWithHeaders
) {
5002 scoped_ptr
<SpdyFrame
> stream1_syn(
5003 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
5004 scoped_ptr
<SpdyFrame
> stream1_body(
5005 spdy_util_
.ConstructSpdyBodyFrame(1, true));
5006 MockWrite writes
[] = {
5007 CreateMockWrite(*stream1_syn
, 0),
5010 scoped_ptr
<SpdyHeaderBlock
> initial_headers(new SpdyHeaderBlock());
5011 spdy_util_
.AddUrlToHeaderBlock(GetDefaultUrlWithPath("/foo.dat"),
5012 initial_headers
.get());
5013 scoped_ptr
<SpdyFrame
> stream2_syn(
5014 spdy_util_
.ConstructInitialSpdyPushFrame(initial_headers
.Pass(), 2, 1));
5016 scoped_ptr
<SpdyHeaderBlock
> late_headers(new SpdyHeaderBlock());
5017 (*late_headers
)["hello"] = "bye";
5018 (*late_headers
)[spdy_util_
.GetStatusKey()] = "200";
5019 (*late_headers
)[spdy_util_
.GetVersionKey()] = "HTTP/1.1";
5020 scoped_ptr
<SpdyFrame
> stream2_headers(
5021 spdy_util_
.ConstructSpdyControlFrame(late_headers
.Pass(),
5029 scoped_ptr
<SpdyFrame
>
5030 stream1_reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
5031 const char kPushedData
[] = "pushed";
5032 scoped_ptr
<SpdyFrame
> stream2_body(
5033 spdy_util_
.ConstructSpdyBodyFrame(
5034 2, kPushedData
, strlen(kPushedData
), true));
5035 MockRead reads
[] = {
5036 CreateMockRead(*stream1_reply
, 1),
5037 CreateMockRead(*stream2_syn
, 2),
5038 CreateMockRead(*stream2_headers
, 3),
5039 CreateMockRead(*stream1_body
, 4, SYNCHRONOUS
),
5040 CreateMockRead(*stream2_body
, 5),
5041 MockRead(SYNCHRONOUS
, ERR_IO_PENDING
, 6), // Force a pause
5044 HttpResponseInfo response
;
5045 HttpResponseInfo response2
;
5046 std::string
expected_push_result("pushed");
5047 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
5048 RunServerPushTest(&data
,
5051 expected_push_result
);
5053 // Verify the SYN_REPLY.
5054 EXPECT_TRUE(response
.headers
.get() != NULL
);
5055 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
5057 // Verify the pushed stream.
5058 EXPECT_TRUE(response2
.headers
.get() != NULL
);
5059 EXPECT_EQ("HTTP/1.1 200 OK", response2
.headers
->GetStatusLine());
5062 TEST_P(SpdyNetworkTransactionTest
, ServerPushClaimBeforeHeaders
) {
5063 // We push a stream and attempt to claim it before the headers come down.
5064 scoped_ptr
<SpdyFrame
> stream1_syn(
5065 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
5066 scoped_ptr
<SpdyFrame
> stream1_body(
5067 spdy_util_
.ConstructSpdyBodyFrame(1, true));
5068 MockWrite writes
[] = {
5069 CreateMockWrite(*stream1_syn
, 0, SYNCHRONOUS
),
5072 scoped_ptr
<SpdyHeaderBlock
> initial_headers(new SpdyHeaderBlock());
5073 spdy_util_
.AddUrlToHeaderBlock(GetDefaultUrlWithPath("/foo.dat"),
5074 initial_headers
.get());
5075 scoped_ptr
<SpdyFrame
> stream2_syn(
5076 spdy_util_
.ConstructInitialSpdyPushFrame(initial_headers
.Pass(), 2, 1));
5078 scoped_ptr
<SpdyHeaderBlock
> late_headers(new SpdyHeaderBlock());
5079 (*late_headers
)["hello"] = "bye";
5080 (*late_headers
)[spdy_util_
.GetStatusKey()] = "200";
5081 (*late_headers
)[spdy_util_
.GetVersionKey()] = "HTTP/1.1";
5082 scoped_ptr
<SpdyFrame
> stream2_headers(
5083 spdy_util_
.ConstructSpdyControlFrame(late_headers
.Pass(),
5091 scoped_ptr
<SpdyFrame
>
5092 stream1_reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
5093 const char kPushedData
[] = "pushed";
5094 scoped_ptr
<SpdyFrame
> stream2_body(
5095 spdy_util_
.ConstructSpdyBodyFrame(
5096 2, kPushedData
, strlen(kPushedData
), true));
5097 MockRead reads
[] = {
5098 CreateMockRead(*stream1_reply
, 1),
5099 CreateMockRead(*stream2_syn
, 2),
5100 CreateMockRead(*stream1_body
, 3),
5101 CreateMockRead(*stream2_headers
, 4),
5102 CreateMockRead(*stream2_body
, 5),
5103 MockRead(ASYNC
, 0, 6), // EOF
5106 HttpResponseInfo response
;
5107 HttpResponseInfo response2
;
5108 std::string
expected_push_result("pushed");
5109 DeterministicSocketData
data(reads
, arraysize(reads
),
5110 writes
, arraysize(writes
));
5112 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
5113 BoundNetLog(), GetParam(), NULL
);
5114 helper
.SetDeterministic();
5115 helper
.AddDeterministicData(&data
);
5116 helper
.RunPreTestSetup();
5118 HttpNetworkTransaction
* trans
= helper
.trans();
5120 // Run until we've received the primary SYN_STREAM, the pushed SYN_STREAM,
5121 // and the body of the primary stream, but before we've received the HEADERS
5122 // for the pushed stream.
5125 // Start the transaction.
5126 TestCompletionCallback callback
;
5127 int rv
= trans
->Start(
5128 &CreateGetRequest(), callback
.callback(), BoundNetLog());
5129 EXPECT_EQ(ERR_IO_PENDING
, rv
);
5131 rv
= callback
.WaitForResult();
5134 // Request the pushed path. At this point, we've received the push, but the
5135 // headers are not yet complete.
5136 scoped_ptr
<HttpNetworkTransaction
> trans2(
5137 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
5139 &CreateGetPushRequest(), callback
.callback(), BoundNetLog());
5140 EXPECT_EQ(ERR_IO_PENDING
, rv
);
5142 base::RunLoop().RunUntilIdle();
5144 // Read the server push body.
5145 std::string result2
;
5146 ReadResult(trans2
.get(), &result2
);
5147 // Read the response body.
5149 ReadResult(trans
, &result
);
5151 // Verify that the received push data is same as the expected push data.
5152 EXPECT_EQ(result2
.compare(expected_push_result
), 0)
5153 << "Received data: "
5155 << "||||| Expected data: "
5156 << expected_push_result
;
5158 // Verify the SYN_REPLY.
5159 // Copy the response info, because trans goes away.
5160 response
= *trans
->GetResponseInfo();
5161 response2
= *trans2
->GetResponseInfo();
5163 VerifyStreamsClosed(helper
);
5165 // Verify the SYN_REPLY.
5166 EXPECT_TRUE(response
.headers
.get() != NULL
);
5167 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
5169 // Verify the pushed stream.
5170 EXPECT_TRUE(response2
.headers
.get() != NULL
);
5171 EXPECT_EQ("HTTP/1.1 200 OK", response2
.headers
->GetStatusLine());
5173 // Read the final EOF (which will close the session)
5176 // Verify that we consumed all test data.
5177 EXPECT_TRUE(data
.AllReadDataConsumed());
5178 EXPECT_TRUE(data
.AllWriteDataConsumed());
5181 // TODO(baranovich): HTTP 2 does not allow multiple HEADERS frames
5182 TEST_P(SpdyNetworkTransactionTest
, ServerPushWithTwoHeaderFrames
) {
5183 // We push a stream and attempt to claim it before the headers come down.
5184 scoped_ptr
<SpdyFrame
> stream1_syn(
5185 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
5186 scoped_ptr
<SpdyFrame
> stream1_body(
5187 spdy_util_
.ConstructSpdyBodyFrame(1, true));
5188 MockWrite writes
[] = {
5189 CreateMockWrite(*stream1_syn
, 0, SYNCHRONOUS
),
5192 scoped_ptr
<SpdyHeaderBlock
> initial_headers(new SpdyHeaderBlock());
5193 if (spdy_util_
.spdy_version() < HTTP2
) {
5194 // In HTTP/2 PUSH_PROMISE headers won't show up in the response headers.
5195 (*initial_headers
)["alpha"] = "beta";
5197 spdy_util_
.AddUrlToHeaderBlock(GetDefaultUrlWithPath("/foo.dat"),
5198 initial_headers
.get());
5199 scoped_ptr
<SpdyFrame
> stream2_syn(
5200 spdy_util_
.ConstructInitialSpdyPushFrame(initial_headers
.Pass(), 2, 1));
5202 scoped_ptr
<SpdyHeaderBlock
> middle_headers(new SpdyHeaderBlock());
5203 (*middle_headers
)["hello"] = "bye";
5204 scoped_ptr
<SpdyFrame
> stream2_headers1(
5205 spdy_util_
.ConstructSpdyControlFrame(middle_headers
.Pass(),
5213 scoped_ptr
<SpdyHeaderBlock
> late_headers(new SpdyHeaderBlock());
5214 (*late_headers
)[spdy_util_
.GetStatusKey()] = "200";
5215 if (spdy_util_
.spdy_version() < HTTP2
) {
5216 // HTTP/2 eliminates use of the :version header.
5217 (*late_headers
)[spdy_util_
.GetVersionKey()] = "HTTP/1.1";
5219 scoped_ptr
<SpdyFrame
> stream2_headers2(
5220 spdy_util_
.ConstructSpdyControlFrame(late_headers
.Pass(),
5228 scoped_ptr
<SpdyFrame
>
5229 stream1_reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
5230 const char kPushedData
[] = "pushed";
5231 scoped_ptr
<SpdyFrame
> stream2_body(
5232 spdy_util_
.ConstructSpdyBodyFrame(
5233 2, kPushedData
, strlen(kPushedData
), true));
5234 MockRead reads
[] = {
5235 CreateMockRead(*stream1_reply
, 1),
5236 CreateMockRead(*stream2_syn
, 2),
5237 CreateMockRead(*stream1_body
, 3),
5238 CreateMockRead(*stream2_headers1
, 4),
5239 CreateMockRead(*stream2_headers2
, 5),
5240 CreateMockRead(*stream2_body
, 6),
5241 MockRead(ASYNC
, 0, 7), // EOF
5244 HttpResponseInfo response
;
5245 HttpResponseInfo response2
;
5246 std::string
expected_push_result("pushed");
5247 DeterministicSocketData
data(reads
, arraysize(reads
),
5248 writes
, arraysize(writes
));
5250 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
5251 BoundNetLog(), GetParam(), NULL
);
5252 helper
.SetDeterministic();
5253 helper
.AddDeterministicData(&data
);
5254 helper
.RunPreTestSetup();
5256 HttpNetworkTransaction
* trans
= helper
.trans();
5258 // Run until we've received the primary SYN_STREAM, the pushed SYN_STREAM,
5259 // the first HEADERS frame, and the body of the primary stream, but before
5260 // we've received the final HEADERS for the pushed stream.
5263 // Start the transaction.
5264 TestCompletionCallback callback
;
5265 int rv
= trans
->Start(
5266 &CreateGetRequest(), callback
.callback(), BoundNetLog());
5267 EXPECT_EQ(ERR_IO_PENDING
, rv
);
5269 rv
= callback
.WaitForResult();
5272 // Request the pushed path. At this point, we've received the push, but the
5273 // headers are not yet complete.
5274 scoped_ptr
<HttpNetworkTransaction
> trans2(
5275 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
5277 &CreateGetPushRequest(), callback
.callback(), BoundNetLog());
5278 EXPECT_EQ(ERR_IO_PENDING
, rv
);
5280 base::RunLoop().RunUntilIdle();
5282 // Read the server push body.
5283 std::string result2
;
5284 ReadResult(trans2
.get(), &result2
);
5285 // Read the response body.
5287 ReadResult(trans
, &result
);
5289 // Verify that the received push data is same as the expected push data.
5290 EXPECT_EQ(expected_push_result
, result2
);
5292 // Verify the SYN_REPLY.
5293 // Copy the response info, because trans goes away.
5294 response
= *trans
->GetResponseInfo();
5295 response2
= *trans2
->GetResponseInfo();
5297 VerifyStreamsClosed(helper
);
5299 // Verify the SYN_REPLY.
5300 EXPECT_TRUE(response
.headers
.get() != NULL
);
5301 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
5303 // Verify the pushed stream.
5304 EXPECT_TRUE(response2
.headers
.get() != NULL
);
5305 EXPECT_EQ("HTTP/1.1 200 OK", response2
.headers
->GetStatusLine());
5307 // Verify we got all the headers from all header blocks.
5308 if (spdy_util_
.spdy_version() < HTTP2
)
5309 EXPECT_TRUE(response2
.headers
->HasHeaderValue("alpha", "beta"));
5310 EXPECT_TRUE(response2
.headers
->HasHeaderValue("hello", "bye"));
5311 EXPECT_TRUE(response2
.headers
->HasHeaderValue("status", "200"));
5313 // Read the final EOF (which will close the session)
5316 // Verify that we consumed all test data.
5317 EXPECT_TRUE(data
.AllReadDataConsumed());
5318 EXPECT_TRUE(data
.AllWriteDataConsumed());
5321 TEST_P(SpdyNetworkTransactionTest
, ServerPushWithNoStatusHeaderFrames
) {
5322 // We push a stream and attempt to claim it before the headers come down.
5323 scoped_ptr
<SpdyFrame
> stream1_syn(
5324 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
5325 scoped_ptr
<SpdyFrame
> stream1_body(
5326 spdy_util_
.ConstructSpdyBodyFrame(1, true));
5327 MockWrite writes
[] = {
5328 CreateMockWrite(*stream1_syn
, 0, SYNCHRONOUS
),
5331 scoped_ptr
<SpdyHeaderBlock
> initial_headers(new SpdyHeaderBlock());
5332 spdy_util_
.AddUrlToHeaderBlock(GetDefaultUrlWithPath("/foo.dat"),
5333 initial_headers
.get());
5334 scoped_ptr
<SpdyFrame
> stream2_syn(
5335 spdy_util_
.ConstructInitialSpdyPushFrame(initial_headers
.Pass(), 2, 1));
5337 scoped_ptr
<SpdyHeaderBlock
> middle_headers(new SpdyHeaderBlock());
5338 (*middle_headers
)["hello"] = "bye";
5339 scoped_ptr
<SpdyFrame
> stream2_headers1(
5340 spdy_util_
.ConstructSpdyControlFrame(middle_headers
.Pass(),
5348 scoped_ptr
<SpdyFrame
>
5349 stream1_reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
5350 const char kPushedData
[] = "pushed";
5351 scoped_ptr
<SpdyFrame
> stream2_body(
5352 spdy_util_
.ConstructSpdyBodyFrame(
5353 2, kPushedData
, strlen(kPushedData
), true));
5354 MockRead reads
[] = {
5355 CreateMockRead(*stream1_reply
, 1),
5356 CreateMockRead(*stream2_syn
, 2),
5357 CreateMockRead(*stream1_body
, 3),
5358 CreateMockRead(*stream2_headers1
, 4),
5359 CreateMockRead(*stream2_body
, 5),
5360 MockRead(ASYNC
, 0, 6), // EOF
5363 DeterministicSocketData
data(reads
, arraysize(reads
),
5364 writes
, arraysize(writes
));
5366 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
5367 BoundNetLog(), GetParam(), NULL
);
5368 helper
.SetDeterministic();
5369 helper
.AddDeterministicData(&data
);
5370 helper
.RunPreTestSetup();
5372 HttpNetworkTransaction
* trans
= helper
.trans();
5374 // Run until we've received the primary SYN_STREAM, the pushed SYN_STREAM,
5375 // the first HEADERS frame, and the body of the primary stream, but before
5376 // we've received the final HEADERS for the pushed stream.
5379 // Start the transaction.
5380 TestCompletionCallback callback
;
5381 int rv
= trans
->Start(
5382 &CreateGetRequest(), callback
.callback(), BoundNetLog());
5383 EXPECT_EQ(ERR_IO_PENDING
, rv
);
5385 rv
= callback
.WaitForResult();
5388 // Request the pushed path. At this point, we've received the push, but the
5389 // headers are not yet complete.
5390 scoped_ptr
<HttpNetworkTransaction
> trans2(
5391 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
5393 &CreateGetPushRequest(), callback
.callback(), BoundNetLog());
5394 EXPECT_EQ(ERR_IO_PENDING
, rv
);
5396 base::RunLoop().RunUntilIdle();
5398 // Read the server push body.
5399 std::string result2
;
5400 ReadResult(trans2
.get(), &result2
);
5401 // Read the response body.
5403 ReadResult(trans
, &result
);
5404 EXPECT_EQ("hello!", result
);
5406 // Verify that we haven't received any push data.
5407 EXPECT_EQ("", result2
);
5409 // Verify the SYN_REPLY.
5410 // Copy the response info, because trans goes away.
5411 HttpResponseInfo response
= *trans
->GetResponseInfo();
5413 VerifyStreamsClosed(helper
);
5415 // Verify the SYN_REPLY.
5416 EXPECT_TRUE(response
.headers
.get() != NULL
);
5417 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
5419 // Read the final EOF (which will close the session).
5422 // Verify that we consumed all test data.
5423 EXPECT_TRUE(data
.AllReadDataConsumed());
5424 EXPECT_TRUE(data
.AllWriteDataConsumed());
5427 TEST_P(SpdyNetworkTransactionTest
, SynReplyWithHeaders
) {
5428 scoped_ptr
<SpdyFrame
> req(
5429 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
5430 scoped_ptr
<SpdyFrame
> rst(
5431 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR
));
5432 MockWrite writes
[] = {
5433 CreateMockWrite(*req
, 0), CreateMockWrite(*rst
, 4),
5436 scoped_ptr
<SpdyFrame
> stream1_reply(
5437 spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
5439 scoped_ptr
<SpdyHeaderBlock
> late_headers(new SpdyHeaderBlock());
5440 (*late_headers
)["hello"] = "bye";
5441 scoped_ptr
<SpdyFrame
> stream1_headers(
5442 spdy_util_
.ConstructSpdyControlFrame(late_headers
.Pass(),
5449 scoped_ptr
<SpdyFrame
> stream1_body(
5450 spdy_util_
.ConstructSpdyBodyFrame(1, true));
5451 MockRead reads
[] = {
5452 CreateMockRead(*stream1_reply
, 1),
5453 CreateMockRead(*stream1_headers
, 2),
5454 CreateMockRead(*stream1_body
, 3),
5455 MockRead(ASYNC
, 0, 5) // EOF
5458 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
5459 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
5460 BoundNetLog(), GetParam(), NULL
);
5461 helper
.RunToCompletion(&data
);
5462 TransactionHelperResult out
= helper
.output();
5463 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR
, out
.rv
);
5466 // Tests that receiving HEADERS, DATA, HEADERS, and DATA in that sequence will
5467 // trigger a ERR_SPDY_PROTOCOL_ERROR because trailing HEADERS must not be
5468 // followed by any DATA frames.
5469 TEST_P(SpdyNetworkTransactionTest
, SyncReplyDataAfterTrailers
) {
5470 scoped_ptr
<SpdyFrame
> req(
5471 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
5472 scoped_ptr
<SpdyFrame
> rst(
5473 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR
));
5474 MockWrite writes
[] = {
5475 CreateMockWrite(*req
, 0), CreateMockWrite(*rst
, 5),
5478 scoped_ptr
<SpdyFrame
> stream1_reply(
5479 spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
5481 scoped_ptr
<SpdyHeaderBlock
> late_headers(new SpdyHeaderBlock());
5482 (*late_headers
)["hello"] = "bye";
5483 scoped_ptr
<SpdyFrame
> stream1_headers(
5484 spdy_util_
.ConstructSpdyControlFrame(late_headers
.Pass(),
5491 scoped_ptr
<SpdyFrame
> stream1_body(
5492 spdy_util_
.ConstructSpdyBodyFrame(1, false));
5493 scoped_ptr
<SpdyFrame
> stream1_body2(
5494 spdy_util_
.ConstructSpdyBodyFrame(1, true));
5495 MockRead reads
[] = {
5496 CreateMockRead(*stream1_reply
, 1), CreateMockRead(*stream1_body
, 2),
5497 CreateMockRead(*stream1_headers
, 3), CreateMockRead(*stream1_body2
, 4),
5498 MockRead(ASYNC
, 0, 6) // EOF
5501 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
5502 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
5503 BoundNetLog(), GetParam(), NULL
);
5504 helper
.RunToCompletion(&data
);
5505 TransactionHelperResult out
= helper
.output();
5506 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR
, out
.rv
);
5509 TEST_P(SpdyNetworkTransactionTest
, ServerPushCrossOriginCorrectness
) {
5510 // Running these tests via Alt-Svc is too complicated to be worthwhile.
5511 if (GetParam().ssl_type
!= HTTPS_SPDY_VIA_NPN
)
5514 // In this test we want to verify that we can't accidentally push content
5515 // which can't be pushed by this content server.
5516 // This test assumes that:
5517 // - if we're requesting http://www.foo.com/barbaz
5518 // - the browser has made a connection to "www.foo.com".
5520 // A list of the URL to fetch, followed by the URL being pushed.
5521 static const char* const kTestCases
[] = {
5522 "https://www.example.org/foo.html",
5523 "https://www.example.org:81/foo.js", // Bad port
5525 "https://www.example.org/foo.html",
5526 "http://www.example.org/foo.js", // Bad protocol
5528 "https://www.example.org/foo.html",
5529 "ftp://www.example.org/foo.js", // Invalid Protocol
5531 "https://www.example.org/foo.html",
5532 "https://blat.www.example.org/foo.js", // Cross subdomain
5534 "https://www.example.org/foo.html",
5535 "https://www.foo.com/foo.js", // Cross domain
5538 for (size_t index
= 0; index
< arraysize(kTestCases
); index
+= 2) {
5539 const char* url_to_fetch
= kTestCases
[index
];
5540 const char* url_to_push
= kTestCases
[index
+ 1];
5542 scoped_ptr
<SpdyFrame
> stream1_syn(
5543 spdy_util_
.ConstructSpdyGet(url_to_fetch
, false, 1, LOWEST
));
5544 scoped_ptr
<SpdyFrame
> stream1_body(
5545 spdy_util_
.ConstructSpdyBodyFrame(1, true));
5546 scoped_ptr
<SpdyFrame
> push_rst(
5547 spdy_util_
.ConstructSpdyRstStream(2, RST_STREAM_REFUSED_STREAM
));
5548 MockWrite writes
[] = {
5549 CreateMockWrite(*stream1_syn
, 0), CreateMockWrite(*push_rst
, 3),
5552 scoped_ptr
<SpdyFrame
>
5553 stream1_reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
5554 scoped_ptr
<SpdyFrame
>
5555 stream2_syn(spdy_util_
.ConstructSpdyPush(NULL
,
5560 const char kPushedData
[] = "pushed";
5561 scoped_ptr
<SpdyFrame
> stream2_body(
5562 spdy_util_
.ConstructSpdyBodyFrame(
5563 2, kPushedData
, strlen(kPushedData
), true));
5564 scoped_ptr
<SpdyFrame
> rst(
5565 spdy_util_
.ConstructSpdyRstStream(2, RST_STREAM_CANCEL
));
5567 MockRead reads
[] = {
5568 CreateMockRead(*stream1_reply
, 1),
5569 CreateMockRead(*stream2_syn
, 2),
5570 CreateMockRead(*stream1_body
, 4),
5571 CreateMockRead(*stream2_body
, 5),
5572 MockRead(SYNCHRONOUS
, ERR_IO_PENDING
, 6), // Force a pause
5575 HttpResponseInfo response
;
5576 SequencedSocketData
data(reads
, arraysize(reads
), writes
,
5579 HttpRequestInfo request
;
5580 request
.method
= "GET";
5581 request
.url
= GURL(url_to_fetch
);
5582 request
.load_flags
= 0;
5584 // Enable cross-origin push. Since we are not using a proxy, this should
5585 // not actually enable cross-origin SPDY push.
5586 scoped_ptr
<SpdySessionDependencies
> session_deps(
5587 CreateSpdySessionDependencies(GetParam()));
5588 session_deps
->trusted_spdy_proxy
= "123.45.67.89:8080";
5589 NormalSpdyTransactionHelper
helper(request
, DEFAULT_PRIORITY
,
5590 BoundNetLog(), GetParam(),
5591 session_deps
.release());
5592 helper
.RunPreTestSetup();
5593 helper
.AddData(&data
);
5595 HttpNetworkTransaction
* trans
= helper
.trans();
5597 // Start the transaction with basic parameters.
5598 TestCompletionCallback callback
;
5600 int rv
= trans
->Start(&request
, callback
.callback(), BoundNetLog());
5601 EXPECT_EQ(ERR_IO_PENDING
, rv
);
5602 rv
= callback
.WaitForResult();
5604 // Read the response body.
5606 ReadResult(trans
, &result
);
5608 // Verify that we consumed all test data.
5609 EXPECT_TRUE(data
.AllReadDataConsumed());
5610 EXPECT_TRUE(data
.AllWriteDataConsumed());
5612 // Verify the SYN_REPLY.
5613 // Copy the response info, because trans goes away.
5614 response
= *trans
->GetResponseInfo();
5616 VerifyStreamsClosed(helper
);
5618 // Verify the SYN_REPLY.
5619 EXPECT_TRUE(response
.headers
.get() != NULL
);
5620 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
5624 TEST_P(SpdyNetworkTransactionTest
, RetryAfterRefused
) {
5625 // Construct the request.
5626 scoped_ptr
<SpdyFrame
> req(
5627 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
5628 scoped_ptr
<SpdyFrame
> req2(
5629 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 3, LOWEST
, true));
5630 MockWrite writes
[] = {
5631 CreateMockWrite(*req
, 0), CreateMockWrite(*req2
, 2),
5634 scoped_ptr
<SpdyFrame
> refused(
5635 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_REFUSED_STREAM
));
5636 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 3));
5637 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(3, true));
5638 MockRead reads
[] = {
5639 CreateMockRead(*refused
, 1),
5640 CreateMockRead(*resp
, 3),
5641 CreateMockRead(*body
, 4),
5642 MockRead(ASYNC
, 0, 5) // EOF
5645 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
5646 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
5647 BoundNetLog(), GetParam(), NULL
);
5649 helper
.RunPreTestSetup();
5650 helper
.AddData(&data
);
5652 HttpNetworkTransaction
* trans
= helper
.trans();
5654 // Start the transaction with basic parameters.
5655 TestCompletionCallback callback
;
5656 int rv
= trans
->Start(
5657 &CreateGetRequest(), callback
.callback(), BoundNetLog());
5658 EXPECT_EQ(ERR_IO_PENDING
, rv
);
5659 rv
= callback
.WaitForResult();
5662 // Verify that we consumed all test data.
5663 EXPECT_TRUE(data
.AllReadDataConsumed());
5664 EXPECT_TRUE(data
.AllWriteDataConsumed());
5666 // Verify the SYN_REPLY.
5667 HttpResponseInfo response
= *trans
->GetResponseInfo();
5668 EXPECT_TRUE(response
.headers
.get() != NULL
);
5669 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
5672 TEST_P(SpdyNetworkTransactionTest
, OutOfOrderSynStream
) {
5673 // This first request will start to establish the SpdySession.
5674 // Then we will start the second (MEDIUM priority) and then third
5675 // (HIGHEST priority) request in such a way that the third will actually
5676 // start before the second, causing the second to be numbered differently
5677 // than the order they were created.
5678 scoped_ptr
<SpdyFrame
> req1(
5679 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
5680 scoped_ptr
<SpdyFrame
> req2(
5681 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 3, HIGHEST
, true));
5682 scoped_ptr
<SpdyFrame
> req3(
5683 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 5, MEDIUM
, true));
5684 MockWrite writes
[] = {
5685 CreateMockWrite(*req1
, 0),
5686 CreateMockWrite(*req2
, 3),
5687 CreateMockWrite(*req3
, 4),
5690 scoped_ptr
<SpdyFrame
> resp1(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
5691 scoped_ptr
<SpdyFrame
> body1(spdy_util_
.ConstructSpdyBodyFrame(1, true));
5692 scoped_ptr
<SpdyFrame
> resp2(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 3));
5693 scoped_ptr
<SpdyFrame
> body2(spdy_util_
.ConstructSpdyBodyFrame(3, true));
5694 scoped_ptr
<SpdyFrame
> resp3(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 5));
5695 scoped_ptr
<SpdyFrame
> body3(spdy_util_
.ConstructSpdyBodyFrame(5, true));
5696 MockRead reads
[] = {
5697 CreateMockRead(*resp1
, 1),
5698 CreateMockRead(*body1
, 2),
5699 CreateMockRead(*resp2
, 5),
5700 CreateMockRead(*body2
, 6),
5701 CreateMockRead(*resp3
, 7),
5702 CreateMockRead(*body3
, 8),
5703 MockRead(ASYNC
, 0, 9) // EOF
5706 DeterministicSocketData
data(reads
, arraysize(reads
),
5707 writes
, arraysize(writes
));
5708 NormalSpdyTransactionHelper
helper(CreateGetRequest(), LOWEST
,
5709 BoundNetLog(), GetParam(), NULL
);
5710 helper
.SetDeterministic();
5711 helper
.RunPreTestSetup();
5712 helper
.AddDeterministicData(&data
);
5714 // Start the first transaction to set up the SpdySession
5715 HttpNetworkTransaction
* trans
= helper
.trans();
5716 TestCompletionCallback callback
;
5717 HttpRequestInfo info1
= CreateGetRequest();
5718 int rv
= trans
->Start(&info1
, callback
.callback(), BoundNetLog());
5719 EXPECT_EQ(ERR_IO_PENDING
, rv
);
5721 // Run the message loop, but do not allow the write to complete.
5722 // This leaves the SpdySession with a write pending, which prevents
5723 // SpdySession from attempting subsequent writes until this write completes.
5724 base::RunLoop().RunUntilIdle();
5726 // Now, start both new transactions
5727 HttpRequestInfo info2
= CreateGetRequest();
5728 TestCompletionCallback callback2
;
5729 scoped_ptr
<HttpNetworkTransaction
> trans2(
5730 new HttpNetworkTransaction(MEDIUM
, helper
.session().get()));
5731 rv
= trans2
->Start(&info2
, callback2
.callback(), BoundNetLog());
5732 EXPECT_EQ(ERR_IO_PENDING
, rv
);
5733 base::RunLoop().RunUntilIdle();
5735 HttpRequestInfo info3
= CreateGetRequest();
5736 TestCompletionCallback callback3
;
5737 scoped_ptr
<HttpNetworkTransaction
> trans3(
5738 new HttpNetworkTransaction(HIGHEST
, helper
.session().get()));
5739 rv
= trans3
->Start(&info3
, callback3
.callback(), BoundNetLog());
5740 EXPECT_EQ(ERR_IO_PENDING
, rv
);
5741 base::RunLoop().RunUntilIdle();
5743 // We now have two SYN_STREAM frames queued up which will be
5744 // dequeued only once the first write completes, which we
5745 // now allow to happen.
5747 EXPECT_EQ(OK
, callback
.WaitForResult());
5749 // And now we can allow everything else to run to completion.
5752 EXPECT_EQ(OK
, callback2
.WaitForResult());
5753 EXPECT_EQ(OK
, callback3
.WaitForResult());
5755 helper
.VerifyDataConsumed();
5758 // The tests below are only for SPDY/3 and above.
5760 // Test that sent data frames and received WINDOW_UPDATE frames change
5761 // the send_window_size_ correctly.
5763 // WINDOW_UPDATE is different than most other frames in that it can arrive
5764 // while the client is still sending the request body. In order to enforce
5765 // this scenario, we feed a couple of dummy frames and give a delay of 0 to
5766 // socket data provider, so that initial read that is done as soon as the
5767 // stream is created, succeeds and schedules another read. This way reads
5768 // and writes are interleaved; after doing a full frame write, SpdyStream
5769 // will break out of DoLoop and will read and process a WINDOW_UPDATE.
5770 // Once our WINDOW_UPDATE is read, we cannot send SYN_REPLY right away
5771 // since request has not been completely written, therefore we feed
5772 // enough number of WINDOW_UPDATEs to finish the first read and cause a
5773 // write, leading to a complete write of request body; after that we send
5774 // a reply with a body, to cause a graceful shutdown.
5776 // TODO(agayev): develop a socket data provider where both, reads and
5777 // writes are ordered so that writing tests like these are easy and rewrite
5778 // all these tests using it. Right now we are working around the
5779 // limitations as described above and it's not deterministic, tests may
5780 // fail under specific circumstances.
5781 TEST_P(SpdyNetworkTransactionTest
, WindowUpdateReceived
) {
5782 static int kFrameCount
= 2;
5783 scoped_ptr
<std::string
> content(
5784 new std::string(kMaxSpdyFrameChunkSize
, 'a'));
5785 scoped_ptr
<SpdyFrame
> req(spdy_util_
.ConstructSpdyPost(
5786 GetDefaultUrl(), 1, kMaxSpdyFrameChunkSize
* kFrameCount
, LOWEST
, NULL
,
5788 scoped_ptr
<SpdyFrame
> body(
5789 spdy_util_
.ConstructSpdyBodyFrame(
5790 1, content
->c_str(), content
->size(), false));
5791 scoped_ptr
<SpdyFrame
> body_end(
5792 spdy_util_
.ConstructSpdyBodyFrame(
5793 1, content
->c_str(), content
->size(), true));
5795 MockWrite writes
[] = {
5796 CreateMockWrite(*req
, 0),
5797 CreateMockWrite(*body
, 1),
5798 CreateMockWrite(*body_end
, 2),
5801 static const int32 kDeltaWindowSize
= 0xff;
5802 static const int kDeltaCount
= 4;
5803 scoped_ptr
<SpdyFrame
> window_update(
5804 spdy_util_
.ConstructSpdyWindowUpdate(1, kDeltaWindowSize
));
5805 scoped_ptr
<SpdyFrame
> window_update_dummy(
5806 spdy_util_
.ConstructSpdyWindowUpdate(2, kDeltaWindowSize
));
5807 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyPostSynReply(NULL
, 0));
5808 MockRead reads
[] = {
5809 CreateMockRead(*window_update_dummy
, 3),
5810 CreateMockRead(*window_update_dummy
, 4),
5811 CreateMockRead(*window_update_dummy
, 5),
5812 CreateMockRead(*window_update
, 6), // Four updates, therefore window
5813 CreateMockRead(*window_update
, 7), // size should increase by
5814 CreateMockRead(*window_update
, 8), // kDeltaWindowSize * 4
5815 CreateMockRead(*window_update
, 9),
5816 CreateMockRead(*resp
, 10),
5817 CreateMockRead(*body_end
, 11),
5818 MockRead(ASYNC
, 0, 0, 12) // EOF
5821 DeterministicSocketData
data(reads
, arraysize(reads
),
5822 writes
, arraysize(writes
));
5824 ScopedVector
<UploadElementReader
> element_readers
;
5825 for (int i
= 0; i
< kFrameCount
; ++i
) {
5826 element_readers
.push_back(
5827 new UploadBytesElementReader(content
->c_str(), content
->size()));
5829 ElementsUploadDataStream
upload_data_stream(element_readers
.Pass(), 0);
5831 // Setup the request
5832 HttpRequestInfo request
;
5833 request
.method
= "POST";
5834 request
.url
= GURL(GetDefaultUrl());
5835 request
.upload_data_stream
= &upload_data_stream
;
5837 NormalSpdyTransactionHelper
helper(request
, DEFAULT_PRIORITY
,
5838 BoundNetLog(), GetParam(), NULL
);
5839 helper
.SetDeterministic();
5840 helper
.AddDeterministicData(&data
);
5841 helper
.RunPreTestSetup();
5843 HttpNetworkTransaction
* trans
= helper
.trans();
5845 TestCompletionCallback callback
;
5846 int rv
= trans
->Start(&helper
.request(), callback
.callback(), BoundNetLog());
5848 EXPECT_EQ(ERR_IO_PENDING
, rv
);
5852 SpdyHttpStream
* stream
= static_cast<SpdyHttpStream
*>(trans
->stream_
.get());
5853 ASSERT_TRUE(stream
!= NULL
);
5854 ASSERT_TRUE(stream
->stream() != NULL
);
5855 EXPECT_EQ(static_cast<int>(
5856 SpdySession::GetDefaultInitialWindowSize(GetParam().protocol
)) +
5857 kDeltaWindowSize
* kDeltaCount
-
5858 kMaxSpdyFrameChunkSize
* kFrameCount
,
5859 stream
->stream()->send_window_size());
5863 rv
= callback
.WaitForResult();
5866 helper
.VerifyDataConsumed();
5869 // Test that received data frames and sent WINDOW_UPDATE frames change
5870 // the recv_window_size_ correctly.
5871 TEST_P(SpdyNetworkTransactionTest
, WindowUpdateSent
) {
5872 const int32 default_initial_window_size
=
5873 SpdySession::GetDefaultInitialWindowSize(GetParam().protocol
);
5874 // Session level maximum window size that is more than twice the default
5875 // initial window size so that an initial window update is sent.
5876 const int32 session_max_recv_window_size
= 5 * 64 * 1024;
5877 ASSERT_LT(2 * default_initial_window_size
, session_max_recv_window_size
);
5878 // Stream level maximum window size that is less than the session level
5879 // maximum window size so that we test for confusion between the two.
5880 const int32 stream_max_recv_window_size
= 4 * 64 * 1024;
5881 ASSERT_GT(session_max_recv_window_size
, stream_max_recv_window_size
);
5882 // Size of body to be sent. Has to be less than or equal to both window sizes
5883 // so that we do not run out of receiving window. Also has to be greater than
5884 // half of them so that it triggers both a session level and a stream level
5885 // window update frame.
5886 const int32 kTargetSize
= 3 * 64 * 1024;
5887 ASSERT_GE(session_max_recv_window_size
, kTargetSize
);
5888 ASSERT_GE(stream_max_recv_window_size
, kTargetSize
);
5889 ASSERT_LT(session_max_recv_window_size
/ 2, kTargetSize
);
5890 ASSERT_LT(stream_max_recv_window_size
/ 2, kTargetSize
);
5891 // Size of each DATA frame.
5892 const int32 kChunkSize
= 4096;
5893 // Size of window updates.
5894 ASSERT_EQ(0, session_max_recv_window_size
/ 2 % kChunkSize
);
5895 const int32 session_window_update_delta
=
5896 session_max_recv_window_size
/ 2 + kChunkSize
;
5897 ASSERT_EQ(0, stream_max_recv_window_size
/ 2 % kChunkSize
);
5898 const int32 stream_window_update_delta
=
5899 stream_max_recv_window_size
/ 2 + kChunkSize
;
5901 SettingsMap initial_settings
;
5902 initial_settings
[SETTINGS_MAX_CONCURRENT_STREAMS
] =
5903 SettingsFlagsAndValue(SETTINGS_FLAG_NONE
, kMaxConcurrentPushedStreams
);
5904 initial_settings
[SETTINGS_INITIAL_WINDOW_SIZE
] =
5905 SettingsFlagsAndValue(SETTINGS_FLAG_NONE
, stream_max_recv_window_size
);
5906 scoped_ptr
<SpdyFrame
> initial_settings_frame(
5907 spdy_util_
.ConstructSpdySettings(initial_settings
));
5908 scoped_ptr
<SpdyFrame
> initial_window_update(
5909 spdy_util_
.ConstructSpdyWindowUpdate(
5910 kSessionFlowControlStreamId
,
5911 session_max_recv_window_size
- default_initial_window_size
));
5912 scoped_ptr
<SpdyFrame
> req(
5913 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
5914 scoped_ptr
<SpdyFrame
> session_window_update(
5915 spdy_util_
.ConstructSpdyWindowUpdate(0, session_window_update_delta
));
5916 scoped_ptr
<SpdyFrame
> stream_window_update(
5917 spdy_util_
.ConstructSpdyWindowUpdate(1, stream_window_update_delta
));
5919 std::vector
<MockWrite
> writes
;
5920 if ((GetParam().protocol
>= kProtoHTTP2MinimumVersion
) &&
5921 (GetParam().protocol
<= kProtoHTTP2MaximumVersion
)) {
5922 writes
.push_back(MockWrite(ASYNC
, kHttp2ConnectionHeaderPrefix
,
5923 kHttp2ConnectionHeaderPrefixSize
, 0));
5925 writes
.push_back(CreateMockWrite(*initial_settings_frame
, writes
.size()));
5926 writes
.push_back(CreateMockWrite(*initial_window_update
, writes
.size()));
5927 writes
.push_back(CreateMockWrite(*req
, writes
.size()));
5929 std::vector
<MockRead
> reads
;
5930 scoped_ptr
<SpdyFrame
> resp(
5931 spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
5932 reads
.push_back(CreateMockRead(*resp
, writes
.size() + reads
.size()));
5934 ScopedVector
<SpdyFrame
> body_frames
;
5935 const std::string
body_data(kChunkSize
, 'x');
5936 for (size_t remaining
= kTargetSize
; remaining
!= 0;) {
5937 size_t frame_size
= std::min(remaining
, body_data
.size());
5938 body_frames
.push_back(spdy_util_
.ConstructSpdyBodyFrame(
5939 1, body_data
.data(), frame_size
, false));
5941 CreateMockRead(*body_frames
.back(), writes
.size() + reads
.size()));
5942 remaining
-= frame_size
;
5945 MockRead(ASYNC
, ERR_IO_PENDING
, writes
.size() + reads
.size())); // Yield.
5948 CreateMockWrite(*session_window_update
, writes
.size() + reads
.size()));
5950 CreateMockWrite(*stream_window_update
, writes
.size() + reads
.size()));
5952 SequencedSocketData
data(vector_as_array(&reads
), reads
.size(),
5953 vector_as_array(&writes
), writes
.size());
5955 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
5956 BoundNetLog(), GetParam(), NULL
);
5957 helper
.AddData(&data
);
5958 helper
.RunPreTestSetup();
5960 SpdySessionPool
* spdy_session_pool
= helper
.session()->spdy_session_pool();
5961 SpdySessionPoolPeer
pool_peer(spdy_session_pool
);
5962 pool_peer
.SetEnableSendingInitialData(true);
5963 pool_peer
.SetSessionMaxRecvWindowSize(session_max_recv_window_size
);
5964 pool_peer
.SetStreamInitialRecvWindowSize(stream_max_recv_window_size
);
5966 HttpNetworkTransaction
* trans
= helper
.trans();
5967 TestCompletionCallback callback
;
5968 int rv
= trans
->Start(&helper
.request(), callback
.callback(), BoundNetLog());
5970 EXPECT_EQ(ERR_IO_PENDING
, rv
);
5971 rv
= callback
.WaitForResult();
5974 SpdyHttpStream
* stream
=
5975 static_cast<SpdyHttpStream
*>(trans
->stream_
.get());
5976 ASSERT_TRUE(stream
!= NULL
);
5977 ASSERT_TRUE(stream
->stream() != NULL
);
5979 // All data has been read, but not consumed. The window reflects this.
5980 EXPECT_EQ(static_cast<int>(stream_max_recv_window_size
- kTargetSize
),
5981 stream
->stream()->recv_window_size());
5983 const HttpResponseInfo
* response
= trans
->GetResponseInfo();
5984 ASSERT_TRUE(response
!= NULL
);
5985 ASSERT_TRUE(response
->headers
.get() != NULL
);
5986 EXPECT_EQ("HTTP/1.1 200 OK", response
->headers
->GetStatusLine());
5987 EXPECT_TRUE(response
->was_fetched_via_spdy
);
5989 // Issue a read which will cause a WINDOW_UPDATE to be sent and window
5990 // size increased to default.
5991 scoped_refptr
<IOBuffer
> buf(new IOBuffer(kTargetSize
));
5992 EXPECT_EQ(static_cast<int>(kTargetSize
),
5993 trans
->Read(buf
.get(), kTargetSize
, CompletionCallback()));
5994 EXPECT_EQ(static_cast<int>(stream_max_recv_window_size
),
5995 stream
->stream()->recv_window_size());
5996 EXPECT_THAT(base::StringPiece(buf
->data(), kTargetSize
), Each(Eq('x')));
5998 // Allow scheduled WINDOW_UPDATE frames to write.
5999 base::RunLoop().RunUntilIdle();
6000 helper
.VerifyDataConsumed();
6003 // Test that WINDOW_UPDATE frame causing overflow is handled correctly.
6004 TEST_P(SpdyNetworkTransactionTest
, WindowUpdateOverflow
) {
6005 // Number of full frames we hope to write (but will not, used to
6006 // set content-length header correctly)
6007 static int kFrameCount
= 3;
6009 scoped_ptr
<std::string
> content(
6010 new std::string(kMaxSpdyFrameChunkSize
, 'a'));
6011 scoped_ptr
<SpdyFrame
> req(spdy_util_
.ConstructSpdyPost(
6012 GetDefaultUrl(), 1, kMaxSpdyFrameChunkSize
* kFrameCount
, LOWEST
, NULL
,
6014 scoped_ptr
<SpdyFrame
> body(
6015 spdy_util_
.ConstructSpdyBodyFrame(
6016 1, content
->c_str(), content
->size(), false));
6017 scoped_ptr
<SpdyFrame
> rst(
6018 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_FLOW_CONTROL_ERROR
));
6020 // We're not going to write a data frame with FIN, we'll receive a bad
6021 // WINDOW_UPDATE while sending a request and will send a RST_STREAM frame.
6022 MockWrite writes
[] = {
6023 CreateMockWrite(*req
, 0),
6024 CreateMockWrite(*body
, 2),
6025 CreateMockWrite(*rst
, 3),
6028 static const int32 kDeltaWindowSize
= 0x7fffffff; // cause an overflow
6029 scoped_ptr
<SpdyFrame
> window_update(
6030 spdy_util_
.ConstructSpdyWindowUpdate(1, kDeltaWindowSize
));
6031 MockRead reads
[] = {
6032 CreateMockRead(*window_update
, 1),
6033 MockRead(ASYNC
, 0, 4) // EOF
6036 DeterministicSocketData
data(reads
, arraysize(reads
),
6037 writes
, arraysize(writes
));
6039 ScopedVector
<UploadElementReader
> element_readers
;
6040 for (int i
= 0; i
< kFrameCount
; ++i
) {
6041 element_readers
.push_back(
6042 new UploadBytesElementReader(content
->c_str(), content
->size()));
6044 ElementsUploadDataStream
upload_data_stream(element_readers
.Pass(), 0);
6046 // Setup the request
6047 HttpRequestInfo request
;
6048 request
.method
= "POST";
6049 request
.url
= GURL(GetDefaultUrl());
6050 request
.upload_data_stream
= &upload_data_stream
;
6052 NormalSpdyTransactionHelper
helper(request
, DEFAULT_PRIORITY
,
6053 BoundNetLog(), GetParam(), NULL
);
6054 helper
.SetDeterministic();
6055 helper
.RunPreTestSetup();
6056 helper
.AddDeterministicData(&data
);
6057 HttpNetworkTransaction
* trans
= helper
.trans();
6059 TestCompletionCallback callback
;
6060 int rv
= trans
->Start(&helper
.request(), callback
.callback(), BoundNetLog());
6061 ASSERT_EQ(ERR_IO_PENDING
, rv
);
6064 ASSERT_TRUE(callback
.have_result());
6065 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR
, callback
.WaitForResult());
6066 helper
.VerifyDataConsumed();
6069 // Test that after hitting a send window size of 0, the write process
6070 // stalls and upon receiving WINDOW_UPDATE frame write resumes.
6072 // This test constructs a POST request followed by enough data frames
6073 // containing 'a' that would make the window size 0, followed by another
6074 // data frame containing default content (which is "hello!") and this frame
6075 // also contains a FIN flag. SequencedSocketData is used to enforce all
6076 // writes, save the last, go through before a read could happen. The last frame
6077 // ("hello!") is not permitted to go through since by the time its turn
6078 // arrives, window size is 0. At this point MessageLoop::Run() called via
6079 // callback would block. Therefore we call MessageLoop::RunUntilIdle()
6080 // which returns after performing all possible writes. We use DCHECKS to
6081 // ensure that last data frame is still there and stream has stalled.
6082 // After that, next read is artifically enforced, which causes a
6083 // WINDOW_UPDATE to be read and I/O process resumes.
6084 TEST_P(SpdyNetworkTransactionTest
, FlowControlStallResume
) {
6085 const int32 initial_window_size
=
6086 SpdySession::GetDefaultInitialWindowSize(GetParam().protocol
);
6087 // Number of frames we need to send to zero out the window size: data
6088 // frames plus SYN_STREAM plus the last data frame; also we need another
6089 // data frame that we will send once the WINDOW_UPDATE is received,
6091 size_t num_writes
= initial_window_size
/ kMaxSpdyFrameChunkSize
+ 3;
6093 // Calculate last frame's size; 0 size data frame is legal.
6094 size_t last_frame_size
= initial_window_size
% kMaxSpdyFrameChunkSize
;
6096 // Construct content for a data frame of maximum size.
6097 std::string
content(kMaxSpdyFrameChunkSize
, 'a');
6099 scoped_ptr
<SpdyFrame
> req(spdy_util_
.ConstructSpdyPost(
6100 GetDefaultUrl(), 1, initial_window_size
+ kUploadDataSize
, LOWEST
, NULL
,
6104 scoped_ptr
<SpdyFrame
> body1(
6105 spdy_util_
.ConstructSpdyBodyFrame(
6106 1, content
.c_str(), content
.size(), false));
6108 // Last frame to zero out the window size.
6109 scoped_ptr
<SpdyFrame
> body2(
6110 spdy_util_
.ConstructSpdyBodyFrame(
6111 1, content
.c_str(), last_frame_size
, false));
6113 // Data frame to be sent once WINDOW_UPDATE frame is received.
6114 scoped_ptr
<SpdyFrame
> body3(spdy_util_
.ConstructSpdyBodyFrame(1, true));
6116 // Fill in mock writes.
6117 scoped_ptr
<MockWrite
[]> writes(new MockWrite
[num_writes
]);
6119 writes
[i
] = CreateMockWrite(*req
, i
);
6120 for (i
= 1; i
< num_writes
- 2; i
++)
6121 writes
[i
] = CreateMockWrite(*body1
, i
);
6122 writes
[i
] = CreateMockWrite(*body2
, i
);
6123 // The last write must not be attempted until after the WINDOW_UPDATES
6124 // have been received.
6125 writes
[i
+ 1] = CreateMockWrite(*body3
, i
+ 4, SYNCHRONOUS
);
6127 // Construct read frame, give enough space to upload the rest of the
6129 scoped_ptr
<SpdyFrame
> session_window_update(
6130 spdy_util_
.ConstructSpdyWindowUpdate(0, kUploadDataSize
));
6131 scoped_ptr
<SpdyFrame
> window_update(
6132 spdy_util_
.ConstructSpdyWindowUpdate(1, kUploadDataSize
));
6133 scoped_ptr
<SpdyFrame
> reply(spdy_util_
.ConstructSpdyPostSynReply(NULL
, 0));
6134 MockRead reads
[] = {
6135 MockRead(ASYNC
, ERR_IO_PENDING
, i
+ 1), // Force a pause
6136 CreateMockRead(*session_window_update
, i
+ 2),
6137 CreateMockRead(*window_update
, i
+ 3),
6138 // Now the last write will occur.
6139 CreateMockRead(*reply
, i
+ 5),
6140 CreateMockRead(*body2
, i
+ 6),
6141 CreateMockRead(*body3
, i
+ 7),
6142 MockRead(ASYNC
, 0, i
+ 8) // EOF
6145 SequencedSocketData
data(reads
, arraysize(reads
), writes
.get(), num_writes
);
6147 ScopedVector
<UploadElementReader
> element_readers
;
6148 std::string
upload_data_string(initial_window_size
, 'a');
6149 upload_data_string
.append(kUploadData
, kUploadDataSize
);
6150 element_readers
.push_back(new UploadBytesElementReader(
6151 upload_data_string
.c_str(), upload_data_string
.size()));
6152 ElementsUploadDataStream
upload_data_stream(element_readers
.Pass(), 0);
6154 HttpRequestInfo request
;
6155 request
.method
= "POST";
6156 request
.url
= GURL(GetDefaultUrl());
6157 request
.upload_data_stream
= &upload_data_stream
;
6158 NormalSpdyTransactionHelper
helper(request
, DEFAULT_PRIORITY
,
6159 BoundNetLog(), GetParam(), NULL
);
6160 helper
.AddData(&data
);
6161 helper
.RunPreTestSetup();
6163 HttpNetworkTransaction
* trans
= helper
.trans();
6165 TestCompletionCallback callback
;
6166 int rv
= trans
->Start(&helper
.request(), callback
.callback(), BoundNetLog());
6167 EXPECT_EQ(ERR_IO_PENDING
, rv
);
6169 base::RunLoop().RunUntilIdle(); // Write as much as we can.
6171 SpdyHttpStream
* stream
= static_cast<SpdyHttpStream
*>(trans
->stream_
.get());
6172 ASSERT_TRUE(stream
!= NULL
);
6173 ASSERT_TRUE(stream
->stream() != NULL
);
6174 EXPECT_EQ(0, stream
->stream()->send_window_size());
6175 // All the body data should have been read.
6176 // TODO(satorux): This is because of the weirdness in reading the request
6177 // body in OnSendBodyComplete(). See crbug.com/113107.
6178 EXPECT_TRUE(upload_data_stream
.IsEOF());
6179 // But the body is not yet fully sent (kUploadData is not yet sent)
6180 // since we're send-stalled.
6181 EXPECT_TRUE(stream
->stream()->send_stalled_by_flow_control());
6183 data
.CompleteRead(); // Read in WINDOW_UPDATE frame.
6184 rv
= callback
.WaitForResult();
6185 helper
.VerifyDataConsumed();
6188 // Test we correctly handle the case where the SETTINGS frame results in
6189 // unstalling the send window.
6190 TEST_P(SpdyNetworkTransactionTest
, FlowControlStallResumeAfterSettings
) {
6191 const int32 initial_window_size
=
6192 SpdySession::GetDefaultInitialWindowSize(GetParam().protocol
);
6194 // Number of frames we need to send to zero out the window size: data
6195 // frames plus SYN_STREAM plus the last data frame; also we need another
6196 // data frame that we will send once the SETTING is received, therefore +3.
6197 size_t num_writes
= initial_window_size
/ kMaxSpdyFrameChunkSize
+ 3;
6199 // Calculate last frame's size; 0 size data frame is legal.
6200 size_t last_frame_size
= initial_window_size
% kMaxSpdyFrameChunkSize
;
6202 // Construct content for a data frame of maximum size.
6203 std::string
content(kMaxSpdyFrameChunkSize
, 'a');
6205 scoped_ptr
<SpdyFrame
> req(spdy_util_
.ConstructSpdyPost(
6206 GetDefaultUrl(), 1, initial_window_size
+ kUploadDataSize
, LOWEST
, NULL
,
6210 scoped_ptr
<SpdyFrame
> body1(
6211 spdy_util_
.ConstructSpdyBodyFrame(
6212 1, content
.c_str(), content
.size(), false));
6214 // Last frame to zero out the window size.
6215 scoped_ptr
<SpdyFrame
> body2(
6216 spdy_util_
.ConstructSpdyBodyFrame(
6217 1, content
.c_str(), last_frame_size
, false));
6219 // Data frame to be sent once SETTINGS frame is received.
6220 scoped_ptr
<SpdyFrame
> body3(spdy_util_
.ConstructSpdyBodyFrame(1, true));
6222 // Fill in mock reads/writes.
6223 std::vector
<MockRead
> reads
;
6224 std::vector
<MockWrite
> writes
;
6226 writes
.push_back(CreateMockWrite(*req
, i
++));
6227 while (i
< num_writes
- 2)
6228 writes
.push_back(CreateMockWrite(*body1
, i
++));
6229 writes
.push_back(CreateMockWrite(*body2
, i
++));
6231 // Construct read frame for SETTINGS that gives enough space to upload the
6232 // rest of the data.
6233 SettingsMap settings
;
6234 settings
[SETTINGS_INITIAL_WINDOW_SIZE
] =
6235 SettingsFlagsAndValue(SETTINGS_FLAG_NONE
, initial_window_size
* 2);
6236 scoped_ptr
<SpdyFrame
> settings_frame_large(
6237 spdy_util_
.ConstructSpdySettings(settings
));
6239 reads
.push_back(CreateMockRead(*settings_frame_large
, i
++));
6241 scoped_ptr
<SpdyFrame
> session_window_update(
6242 spdy_util_
.ConstructSpdyWindowUpdate(0, kUploadDataSize
));
6243 if (GetParam().protocol
>= kProtoSPDY31
)
6244 reads
.push_back(CreateMockRead(*session_window_update
, i
++));
6246 scoped_ptr
<SpdyFrame
> settings_ack(spdy_util_
.ConstructSpdySettingsAck());
6247 writes
.push_back(CreateMockWrite(*settings_ack
, i
++));
6249 writes
.push_back(CreateMockWrite(*body3
, i
++));
6251 scoped_ptr
<SpdyFrame
> reply(spdy_util_
.ConstructSpdyPostSynReply(NULL
, 0));
6252 reads
.push_back(CreateMockRead(*reply
, i
++));
6253 reads
.push_back(CreateMockRead(*body2
, i
++));
6254 reads
.push_back(CreateMockRead(*body3
, i
++));
6255 reads
.push_back(MockRead(ASYNC
, 0, i
++)); // EOF
6257 // Force all writes to happen before any read, last write will not
6258 // actually queue a frame, due to window size being 0.
6259 DeterministicSocketData
data(vector_as_array(&reads
), reads
.size(),
6260 vector_as_array(&writes
), writes
.size());
6262 ScopedVector
<UploadElementReader
> element_readers
;
6263 std::string
upload_data_string(initial_window_size
, 'a');
6264 upload_data_string
.append(kUploadData
, kUploadDataSize
);
6265 element_readers
.push_back(new UploadBytesElementReader(
6266 upload_data_string
.c_str(), upload_data_string
.size()));
6267 ElementsUploadDataStream
upload_data_stream(element_readers
.Pass(), 0);
6269 HttpRequestInfo request
;
6270 request
.method
= "POST";
6271 request
.url
= GURL(GetDefaultUrl());
6272 request
.upload_data_stream
= &upload_data_stream
;
6273 NormalSpdyTransactionHelper
helper(request
, DEFAULT_PRIORITY
,
6274 BoundNetLog(), GetParam(), NULL
);
6275 helper
.SetDeterministic();
6276 helper
.RunPreTestSetup();
6277 helper
.AddDeterministicData(&data
);
6279 HttpNetworkTransaction
* trans
= helper
.trans();
6281 TestCompletionCallback callback
;
6282 int rv
= trans
->Start(&helper
.request(), callback
.callback(), BoundNetLog());
6283 EXPECT_EQ(ERR_IO_PENDING
, rv
);
6285 data
.RunFor(num_writes
- 1); // Write as much as we can.
6287 SpdyHttpStream
* stream
= static_cast<SpdyHttpStream
*>(trans
->stream_
.get());
6288 ASSERT_TRUE(stream
!= NULL
);
6289 ASSERT_TRUE(stream
->stream() != NULL
);
6290 EXPECT_EQ(0, stream
->stream()->send_window_size());
6292 // All the body data should have been read.
6293 // TODO(satorux): This is because of the weirdness in reading the request
6294 // body in OnSendBodyComplete(). See crbug.com/113107.
6295 EXPECT_TRUE(upload_data_stream
.IsEOF());
6296 // But the body is not yet fully sent (kUploadData is not yet sent)
6297 // since we're send-stalled.
6298 EXPECT_TRUE(stream
->stream()->send_stalled_by_flow_control());
6300 data
.RunFor(7); // Read in SETTINGS frame to unstall.
6301 rv
= callback
.WaitForResult();
6302 helper
.VerifyDataConsumed();
6303 // If stream is NULL, that means it was unstalled and closed.
6304 EXPECT_TRUE(stream
->stream() == NULL
);
6307 // Test we correctly handle the case where the SETTINGS frame results in a
6308 // negative send window size.
6309 TEST_P(SpdyNetworkTransactionTest
, FlowControlNegativeSendWindowSize
) {
6310 const int32 initial_window_size
=
6311 SpdySession::GetDefaultInitialWindowSize(GetParam().protocol
);
6312 // Number of frames we need to send to zero out the window size: data
6313 // frames plus SYN_STREAM plus the last data frame; also we need another
6314 // data frame that we will send once the SETTING is received, therefore +3.
6315 size_t num_writes
= initial_window_size
/ kMaxSpdyFrameChunkSize
+ 3;
6317 // Calculate last frame's size; 0 size data frame is legal.
6318 size_t last_frame_size
= initial_window_size
% kMaxSpdyFrameChunkSize
;
6320 // Construct content for a data frame of maximum size.
6321 std::string
content(kMaxSpdyFrameChunkSize
, 'a');
6323 scoped_ptr
<SpdyFrame
> req(spdy_util_
.ConstructSpdyPost(
6324 GetDefaultUrl(), 1, initial_window_size
+ kUploadDataSize
, LOWEST
, NULL
,
6328 scoped_ptr
<SpdyFrame
> body1(
6329 spdy_util_
.ConstructSpdyBodyFrame(
6330 1, content
.c_str(), content
.size(), false));
6332 // Last frame to zero out the window size.
6333 scoped_ptr
<SpdyFrame
> body2(
6334 spdy_util_
.ConstructSpdyBodyFrame(
6335 1, content
.c_str(), last_frame_size
, false));
6337 // Data frame to be sent once SETTINGS frame is received.
6338 scoped_ptr
<SpdyFrame
> body3(spdy_util_
.ConstructSpdyBodyFrame(1, true));
6340 // Fill in mock reads/writes.
6341 std::vector
<MockRead
> reads
;
6342 std::vector
<MockWrite
> writes
;
6344 writes
.push_back(CreateMockWrite(*req
, i
++));
6345 while (i
< num_writes
- 2)
6346 writes
.push_back(CreateMockWrite(*body1
, i
++));
6347 writes
.push_back(CreateMockWrite(*body2
, i
++));
6349 // Construct read frame for SETTINGS that makes the send_window_size
6351 SettingsMap new_settings
;
6352 new_settings
[SETTINGS_INITIAL_WINDOW_SIZE
] =
6353 SettingsFlagsAndValue(SETTINGS_FLAG_NONE
, initial_window_size
/ 2);
6354 scoped_ptr
<SpdyFrame
> settings_frame_small(
6355 spdy_util_
.ConstructSpdySettings(new_settings
));
6356 // Construct read frames for WINDOW_UPDATE that makes the send_window_size
6358 scoped_ptr
<SpdyFrame
> session_window_update_init_size(
6359 spdy_util_
.ConstructSpdyWindowUpdate(0, initial_window_size
));
6360 scoped_ptr
<SpdyFrame
> window_update_init_size(
6361 spdy_util_
.ConstructSpdyWindowUpdate(1, initial_window_size
));
6363 reads
.push_back(CreateMockRead(*settings_frame_small
, i
++));
6364 reads
.push_back(CreateMockRead(*session_window_update_init_size
, i
++));
6365 reads
.push_back(CreateMockRead(*window_update_init_size
, i
++));
6367 scoped_ptr
<SpdyFrame
> settings_ack(spdy_util_
.ConstructSpdySettingsAck());
6368 writes
.push_back(CreateMockWrite(*settings_ack
, i
++));
6370 writes
.push_back(CreateMockWrite(*body3
, i
++));
6372 scoped_ptr
<SpdyFrame
> reply(spdy_util_
.ConstructSpdyPostSynReply(NULL
, 0));
6373 reads
.push_back(CreateMockRead(*reply
, i
++));
6374 reads
.push_back(CreateMockRead(*body2
, i
++));
6375 reads
.push_back(CreateMockRead(*body3
, i
++));
6376 reads
.push_back(MockRead(ASYNC
, 0, i
++)); // EOF
6378 // Force all writes to happen before any read, last write will not
6379 // actually queue a frame, due to window size being 0.
6380 DeterministicSocketData
data(vector_as_array(&reads
), reads
.size(),
6381 vector_as_array(&writes
), writes
.size());
6383 ScopedVector
<UploadElementReader
> element_readers
;
6384 std::string
upload_data_string(initial_window_size
, 'a');
6385 upload_data_string
.append(kUploadData
, kUploadDataSize
);
6386 element_readers
.push_back(new UploadBytesElementReader(
6387 upload_data_string
.c_str(), upload_data_string
.size()));
6388 ElementsUploadDataStream
upload_data_stream(element_readers
.Pass(), 0);
6390 HttpRequestInfo request
;
6391 request
.method
= "POST";
6392 request
.url
= GURL(GetDefaultUrl());
6393 request
.upload_data_stream
= &upload_data_stream
;
6394 NormalSpdyTransactionHelper
helper(request
, DEFAULT_PRIORITY
,
6395 BoundNetLog(), GetParam(), NULL
);
6396 helper
.SetDeterministic();
6397 helper
.RunPreTestSetup();
6398 helper
.AddDeterministicData(&data
);
6400 HttpNetworkTransaction
* trans
= helper
.trans();
6402 TestCompletionCallback callback
;
6403 int rv
= trans
->Start(&helper
.request(), callback
.callback(), BoundNetLog());
6404 EXPECT_EQ(ERR_IO_PENDING
, rv
);
6406 data
.RunFor(num_writes
- 1); // Write as much as we can.
6408 SpdyHttpStream
* stream
= static_cast<SpdyHttpStream
*>(trans
->stream_
.get());
6409 ASSERT_TRUE(stream
!= NULL
);
6410 ASSERT_TRUE(stream
->stream() != NULL
);
6411 EXPECT_EQ(0, stream
->stream()->send_window_size());
6413 // All the body data should have been read.
6414 // TODO(satorux): This is because of the weirdness in reading the request
6415 // body in OnSendBodyComplete(). See crbug.com/113107.
6416 EXPECT_TRUE(upload_data_stream
.IsEOF());
6417 // But the body is not yet fully sent (kUploadData is not yet sent)
6418 // since we're send-stalled.
6419 EXPECT_TRUE(stream
->stream()->send_stalled_by_flow_control());
6421 // Read in WINDOW_UPDATE or SETTINGS frame.
6422 data
.RunFor((GetParam().protocol
>= kProtoSPDY31
) ? 9 : 8);
6423 rv
= callback
.WaitForResult();
6424 helper
.VerifyDataConsumed();
6427 TEST_P(SpdyNetworkTransactionTest
, GoAwayOnOddPushStreamId
) {
6428 if (spdy_util_
.spdy_version() < SPDY3
)
6431 scoped_ptr
<SpdyHeaderBlock
> push_headers(new SpdyHeaderBlock
);
6432 spdy_util_
.AddUrlToHeaderBlock("http://www.example.org/a.dat",
6433 push_headers
.get());
6434 scoped_ptr
<SpdyFrame
> push(
6435 spdy_util_
.ConstructInitialSpdyPushFrame(push_headers
.Pass(), 3, 1));
6436 MockRead reads
[] = {CreateMockRead(*push
, 1)};
6438 scoped_ptr
<SpdyFrame
> req(
6439 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
6440 scoped_ptr
<SpdyFrame
> goaway(spdy_util_
.ConstructSpdyGoAway(
6441 0, GOAWAY_PROTOCOL_ERROR
, "Odd push stream id."));
6442 MockWrite writes
[] = {
6443 CreateMockWrite(*req
, 0), CreateMockWrite(*goaway
, 2),
6446 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
6447 NormalSpdyTransactionHelper
helper(
6448 CreateGetRequest(), DEFAULT_PRIORITY
, BoundNetLog(), GetParam(), NULL
);
6449 helper
.RunToCompletion(&data
);
6450 TransactionHelperResult out
= helper
.output();
6451 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR
, out
.rv
);
6454 TEST_P(SpdyNetworkTransactionTest
,
6455 GoAwayOnPushStreamIdLesserOrEqualThanLastAccepted
) {
6456 if (spdy_util_
.spdy_version() < SPDY3
)
6459 scoped_ptr
<SpdyFrame
> push_a(spdy_util_
.ConstructSpdyPush(
6460 NULL
, 0, 4, 1, GetDefaultUrlWithPath("/a.dat").c_str()));
6461 scoped_ptr
<SpdyHeaderBlock
> push_b_headers(new SpdyHeaderBlock
);
6462 spdy_util_
.AddUrlToHeaderBlock(GetDefaultUrlWithPath("/b.dat"),
6463 push_b_headers
.get());
6464 scoped_ptr
<SpdyFrame
> push_b(
6465 spdy_util_
.ConstructInitialSpdyPushFrame(push_b_headers
.Pass(), 2, 1));
6466 MockRead reads
[] = {
6467 CreateMockRead(*push_a
, 1), CreateMockRead(*push_b
, 2),
6470 scoped_ptr
<SpdyFrame
> req(
6471 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
6472 scoped_ptr
<SpdyFrame
> goaway(spdy_util_
.ConstructSpdyGoAway(
6474 GOAWAY_PROTOCOL_ERROR
,
6475 "New push stream id must be greater than the last accepted."));
6476 MockWrite writes
[] = {
6477 CreateMockWrite(*req
, 0), CreateMockWrite(*goaway
, 3),
6480 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
6481 NormalSpdyTransactionHelper
helper(
6482 CreateGetRequest(), DEFAULT_PRIORITY
, BoundNetLog(), GetParam(), NULL
);
6483 helper
.RunToCompletion(&data
);
6484 TransactionHelperResult out
= helper
.output();
6485 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR
, out
.rv
);
6488 // Regression test for https://crbug.com/493348: request header exceeds 16 kB
6489 // and thus sent in multiple frames when using HTTP/2.
6490 TEST_P(SpdyNetworkTransactionTest
, LargeRequest
) {
6491 const std::string
kKey("foo");
6492 const std::string
kValue(1 << 15, 'z');
6494 HttpRequestInfo request
;
6495 request
.method
= "GET";
6496 request
.url
= GURL(GetDefaultUrl());
6497 request
.extra_headers
.SetHeader(kKey
, kValue
);
6499 scoped_ptr
<SpdyHeaderBlock
> headers(
6500 spdy_util_
.ConstructGetHeaderBlock(GetDefaultUrl()));
6501 (*headers
)[kKey
] = kValue
;
6502 scoped_ptr
<SpdyFrame
> req(
6503 spdy_util_
.ConstructSpdySyn(1, *headers
, LOWEST
, false, true));
6504 MockWrite writes
[] = {
6505 CreateMockWrite(*req
, 0),
6508 scoped_ptr
<SpdyFrame
> resp(
6509 spdy_util_
.ConstructSpdyGetSynReply(nullptr, 0, 1));
6510 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
6511 MockRead reads
[] = {
6512 CreateMockRead(*resp
, 1),
6513 CreateMockRead(*body
, 2),
6514 MockRead(ASYNC
, 0, 3) // EOF
6517 SequencedSocketData
data(reads
, arraysize(reads
), writes
, arraysize(writes
));
6518 NormalSpdyTransactionHelper
helper(request
, DEFAULT_PRIORITY
, BoundNetLog(),
6519 GetParam(), nullptr);
6520 helper
.RunToCompletion(&data
);
6521 TransactionHelperResult out
= helper
.output();
6523 EXPECT_EQ(OK
, out
.rv
);
6524 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
6525 EXPECT_EQ("hello!", out
.response_data
);
6528 class SpdyNetworkTransactionNoTLSUsageCheckTest
6529 : public SpdyNetworkTransactionTest
{
6531 void RunNoTLSUsageCheckTest(scoped_ptr
<SSLSocketDataProvider
> ssl_provider
) {
6532 // Construct the request.
6533 scoped_ptr
<SpdyFrame
> req(
6534 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
6535 MockWrite writes
[] = {CreateMockWrite(*req
, 0)};
6537 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
6538 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
6539 MockRead reads
[] = {
6540 CreateMockRead(*resp
, 1),
6541 CreateMockRead(*body
, 2),
6542 MockRead(ASYNC
, 0, 3) // EOF
6545 SequencedSocketData
data(reads
, arraysize(reads
), writes
,
6547 HttpRequestInfo request
;
6548 request
.method
= "GET";
6549 request
.url
= GURL("https://www.example.org/");
6550 NormalSpdyTransactionHelper
helper(
6551 request
, DEFAULT_PRIORITY
, BoundNetLog(), GetParam(), NULL
);
6552 helper
.RunToCompletionWithSSLData(&data
, ssl_provider
.Pass());
6553 TransactionHelperResult out
= helper
.output();
6554 EXPECT_EQ(OK
, out
.rv
);
6555 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
6556 EXPECT_EQ("hello!", out
.response_data
);
6560 //-----------------------------------------------------------------------------
6561 // All tests are run with three different connection types: SPDY after NPN
6562 // negotiation, SPDY without SSL, and SPDY with SSL.
6564 // TODO(akalin): Use ::testing::Combine() when we are able to use
6566 INSTANTIATE_TEST_CASE_P(
6568 SpdyNetworkTransactionNoTLSUsageCheckTest
,
6569 ::testing::Values(SpdyNetworkTransactionTestParams(kProtoSPDY31
,
6570 HTTPS_SPDY_VIA_NPN
)));
6572 TEST_P(SpdyNetworkTransactionNoTLSUsageCheckTest
, TLSVersionTooOld
) {
6573 scoped_ptr
<SSLSocketDataProvider
> ssl_provider(
6574 new SSLSocketDataProvider(ASYNC
, OK
));
6575 SSLConnectionStatusSetVersion(SSL_CONNECTION_VERSION_SSL3
,
6576 &ssl_provider
->connection_status
);
6578 RunNoTLSUsageCheckTest(ssl_provider
.Pass());
6581 TEST_P(SpdyNetworkTransactionNoTLSUsageCheckTest
, TLSCipherSuiteSucky
) {
6582 scoped_ptr
<SSLSocketDataProvider
> ssl_provider(
6583 new SSLSocketDataProvider(ASYNC
, OK
));
6584 // Set to TLS_RSA_WITH_NULL_MD5
6585 SSLConnectionStatusSetCipherSuite(0x1, &ssl_provider
->connection_status
);
6587 RunNoTLSUsageCheckTest(ssl_provider
.Pass());
6590 class SpdyNetworkTransactionTLSUsageCheckTest
6591 : public SpdyNetworkTransactionTest
{
6593 void RunTLSUsageCheckTest(scoped_ptr
<SSLSocketDataProvider
> ssl_provider
) {
6594 scoped_ptr
<SpdyFrame
> goaway(
6595 spdy_util_
.ConstructSpdyGoAway(0, GOAWAY_INADEQUATE_SECURITY
, ""));
6596 MockWrite writes
[] = {CreateMockWrite(*goaway
)};
6598 StaticSocketDataProvider
data(NULL
, 0, writes
, arraysize(writes
));
6599 HttpRequestInfo request
;
6600 request
.method
= "GET";
6601 request
.url
= GURL("https://www.example.org/");
6602 NormalSpdyTransactionHelper
helper(
6603 request
, DEFAULT_PRIORITY
, BoundNetLog(), GetParam(), NULL
);
6604 helper
.RunToCompletionWithSSLData(&data
, ssl_provider
.Pass());
6605 TransactionHelperResult out
= helper
.output();
6606 EXPECT_EQ(ERR_SPDY_INADEQUATE_TRANSPORT_SECURITY
, out
.rv
);
6610 INSTANTIATE_TEST_CASE_P(
6612 SpdyNetworkTransactionTLSUsageCheckTest
,
6614 SpdyNetworkTransactionTestParams(kProtoHTTP2
, HTTPS_SPDY_VIA_NPN
)));
6616 TEST_P(SpdyNetworkTransactionTLSUsageCheckTest
, TLSVersionTooOld
) {
6617 scoped_ptr
<SSLSocketDataProvider
> ssl_provider(
6618 new SSLSocketDataProvider(ASYNC
, OK
));
6619 SSLConnectionStatusSetVersion(SSL_CONNECTION_VERSION_SSL3
,
6620 &ssl_provider
->connection_status
);
6622 RunTLSUsageCheckTest(ssl_provider
.Pass());
6625 TEST_P(SpdyNetworkTransactionTLSUsageCheckTest
, TLSCipherSuiteSucky
) {
6626 scoped_ptr
<SSLSocketDataProvider
> ssl_provider(
6627 new SSLSocketDataProvider(ASYNC
, OK
));
6628 // Set to TLS_RSA_WITH_NULL_MD5
6629 SSLConnectionStatusSetCipherSuite(0x1, &ssl_provider
->connection_status
);
6631 RunTLSUsageCheckTest(ssl_provider
.Pass());