1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
9 #include "base/bind_helpers.h"
10 #include "base/files/file_util.h"
11 #include "base/files/scoped_temp_dir.h"
12 #include "base/memory/scoped_vector.h"
13 #include "base/run_loop.h"
14 #include "base/stl_util.h"
15 #include "base/strings/string_piece.h"
16 #include "base/test/test_file_util.h"
17 #include "net/base/auth.h"
18 #include "net/base/chunked_upload_data_stream.h"
19 #include "net/base/elements_upload_data_stream.h"
20 #include "net/base/request_priority.h"
21 #include "net/base/upload_bytes_element_reader.h"
22 #include "net/base/upload_file_element_reader.h"
23 #include "net/http/http_network_session_peer.h"
24 #include "net/http/http_network_transaction.h"
25 #include "net/http/http_server_properties.h"
26 #include "net/http/http_transaction_test_util.h"
27 #include "net/log/net_log_unittest.h"
28 #include "net/socket/client_socket_pool_base.h"
29 #include "net/socket/next_proto.h"
30 #include "net/spdy/buffered_spdy_framer.h"
31 #include "net/spdy/spdy_http_stream.h"
32 #include "net/spdy/spdy_http_utils.h"
33 #include "net/spdy/spdy_session.h"
34 #include "net/spdy/spdy_session_pool.h"
35 #include "net/spdy/spdy_test_util_common.h"
36 #include "net/spdy/spdy_test_utils.h"
37 #include "net/ssl/ssl_connection_status_flags.h"
38 #include "net/url_request/url_request_test_util.h"
39 #include "testing/gmock/include/gmock/gmock.h"
40 #include "testing/platform_test.h"
42 //-----------------------------------------------------------------------------
51 enum SpdyNetworkTransactionTestSSLType
{
52 // Request an https:// URL and use NPN (or ALPN) to negotiate SPDY during
55 // Request and http:// URL to a server that supports SPDY via Alternative
56 // Service on port 443.
57 // See: https//tools.ietf.org/id/draft-ietf-httpbis-alt-svc-06.html
58 HTTP_SPDY_VIA_ALT_SVC
,
61 struct SpdyNetworkTransactionTestParams
{
62 SpdyNetworkTransactionTestParams()
63 : protocol(kProtoSPDY31
), ssl_type(HTTPS_SPDY_VIA_NPN
) {}
65 SpdyNetworkTransactionTestParams(NextProto protocol
,
66 SpdyNetworkTransactionTestSSLType ssl_type
)
67 : protocol(protocol
), ssl_type(ssl_type
) {}
69 friend std::ostream
& operator<<(std::ostream
& os
,
70 const SpdyNetworkTransactionTestParams
& p
) {
73 case HTTP_SPDY_VIA_ALT_SVC
:
74 type_str
= "HTTP_SPDY_VIA_ALT_SVC";
76 case HTTPS_SPDY_VIA_NPN
:
77 type_str
= "HTTPS_SPDY_VIA_NPN";
80 os
<< "{ protocol: " << SSLClientSocket::NextProtoToString(p
.protocol
)
81 << ", ssl_type: " << type_str
<< " }";
86 SpdyNetworkTransactionTestSSLType ssl_type
;
89 void UpdateSpdySessionDependencies(SpdyNetworkTransactionTestParams test_params
,
90 SpdySessionDependencies
* session_deps
) {
91 session_deps
->use_alternate_protocols
= true;
92 session_deps
->next_protos
= SpdyNextProtos();
93 if (test_params
.ssl_type
== HTTP_SPDY_VIA_ALT_SVC
) {
94 session_deps
->http_server_properties
.SetAlternativeService(
95 HostPortPair("www.google.com", 80),
96 AlternativeService(AlternateProtocolFromNextProto(test_params
.protocol
),
97 "www.google.com", 443),
102 SpdySessionDependencies
* CreateSpdySessionDependencies(
103 SpdyNetworkTransactionTestParams test_params
) {
104 SpdySessionDependencies
* session_deps
=
105 new SpdySessionDependencies(test_params
.protocol
);
106 UpdateSpdySessionDependencies(test_params
, session_deps
);
110 SpdySessionDependencies
* CreateSpdySessionDependencies(
111 SpdyNetworkTransactionTestParams test_params
,
112 ProxyService
* proxy_service
) {
113 SpdySessionDependencies
* session_deps
=
114 new SpdySessionDependencies(test_params
.protocol
, proxy_service
);
115 UpdateSpdySessionDependencies(test_params
, session_deps
);
121 class SpdyNetworkTransactionTest
122 : public ::testing::TestWithParam
<SpdyNetworkTransactionTestParams
> {
124 SpdyNetworkTransactionTest() : spdy_util_(GetParam().protocol
) {
125 spdy_util_
.set_default_url(GURL(GetDefaultUrl()));
128 virtual ~SpdyNetworkTransactionTest() {
129 // UploadDataStream may post a deletion tasks back to the message loop on
131 upload_data_stream_
.reset();
132 base::RunLoop().RunUntilIdle();
135 void SetUp() override
{
136 google_get_request_initialized_
= false;
137 google_post_request_initialized_
= false;
138 google_chunked_post_request_initialized_
= false;
139 ASSERT_TRUE(temp_dir_
.CreateUniqueTempDir());
142 struct TransactionHelperResult
{
144 std::string status_line
;
145 std::string response_data
;
146 HttpResponseInfo response_info
;
149 // A helper class that handles all the initial npn/ssl setup.
150 class NormalSpdyTransactionHelper
{
152 NormalSpdyTransactionHelper(const HttpRequestInfo
& request
,
153 RequestPriority priority
,
154 const BoundNetLog
& log
,
155 SpdyNetworkTransactionTestParams test_params
,
156 SpdySessionDependencies
* session_deps
)
159 session_deps_(session_deps
== NULL
160 ? CreateSpdySessionDependencies(test_params
)
163 SpdySessionDependencies::SpdyCreateSession(session_deps_
.get())),
165 test_params_(test_params
),
167 deterministic_(false),
168 spdy_enabled_(true) {}
170 ~NormalSpdyTransactionHelper() {
171 // Any test which doesn't close the socket by sending it an EOF will
172 // have a valid session left open, which leaks the entire session pool.
173 // This is just fine - in fact, some of our tests intentionally do this
174 // so that we can check consistency of the SpdySessionPool as the test
175 // finishes. If we had put an EOF on the socket, the SpdySession would
176 // have closed and we wouldn't be able to check the consistency.
178 // Forcefully close existing sessions here.
179 session()->spdy_session_pool()->CloseAllSessions();
182 void SetDeterministic() {
183 session_
= SpdySessionDependencies::SpdyCreateSessionDeterministic(
184 session_deps_
.get());
185 deterministic_
= true;
188 void SetSpdyDisabled() {
189 spdy_enabled_
= false;
190 port_
= test_params_
.ssl_type
== HTTP_SPDY_VIA_ALT_SVC
? 80 : 443;
193 void RunPreTestSetup() {
194 if (!session_deps_
.get())
195 session_deps_
.reset(CreateSpdySessionDependencies(test_params_
));
196 if (!session_
.get()) {
197 session_
= SpdySessionDependencies::SpdyCreateSession(
198 session_deps_
.get());
201 // We're now ready to use SSL-npn SPDY.
202 trans_
.reset(new HttpNetworkTransaction(priority_
, session_
.get()));
205 // Start the transaction, read some data, finish.
206 void RunDefaultTest() {
207 if (!StartDefaultTest())
212 bool StartDefaultTest() {
213 output_
.rv
= trans_
->Start(&request_
, callback_
.callback(), log_
);
215 // We expect an IO Pending or some sort of error.
216 EXPECT_LT(output_
.rv
, 0);
217 return output_
.rv
== ERR_IO_PENDING
;
220 void FinishDefaultTest() {
221 output_
.rv
= callback_
.WaitForResult();
222 if (output_
.rv
!= OK
) {
223 session_
->spdy_session_pool()->CloseCurrentSessions(ERR_ABORTED
);
228 const HttpResponseInfo
* response
= trans_
->GetResponseInfo();
229 ASSERT_TRUE(response
!= NULL
);
230 ASSERT_TRUE(response
->headers
.get() != NULL
);
231 EXPECT_EQ("HTTP/1.1 200 OK", response
->headers
->GetStatusLine());
232 EXPECT_EQ(spdy_enabled_
, response
->was_fetched_via_spdy
);
233 if (HttpStreamFactory::spdy_enabled()) {
235 HttpResponseInfo::ConnectionInfoFromNextProto(
236 test_params_
.protocol
),
237 response
->connection_info
);
239 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP1
,
240 response
->connection_info
);
243 EXPECT_TRUE(response
->was_npn_negotiated
);
245 // If SPDY is disabled, an HTTP request should not be diverted
246 // over an SSL session.
247 EXPECT_EQ(request_
.url
.SchemeIs("https"),
248 response
->was_npn_negotiated
);
250 EXPECT_EQ("127.0.0.1", response
->socket_address
.host());
251 EXPECT_EQ(port_
, response
->socket_address
.port());
252 output_
.status_line
= response
->headers
->GetStatusLine();
253 output_
.response_info
= *response
; // Make a copy so we can verify.
254 output_
.rv
= ReadTransaction(trans_
.get(), &output_
.response_data
);
257 void FinishDefaultTestWithoutVerification() {
258 output_
.rv
= callback_
.WaitForResult();
259 if (output_
.rv
!= OK
)
260 session_
->spdy_session_pool()->CloseCurrentSessions(ERR_ABORTED
);
263 // Most tests will want to call this function. In particular, the MockReads
264 // should end with an empty read, and that read needs to be processed to
265 // ensure proper deletion of the spdy_session_pool.
266 void VerifyDataConsumed() {
267 for (DataVector::iterator it
= data_vector_
.begin();
268 it
!= data_vector_
.end(); ++it
) {
269 EXPECT_TRUE((*it
)->at_read_eof()) << "Read count: "
270 << (*it
)->read_count()
272 << (*it
)->read_index();
273 EXPECT_TRUE((*it
)->at_write_eof()) << "Write count: "
274 << (*it
)->write_count()
276 << (*it
)->write_index();
280 // Occasionally a test will expect to error out before certain reads are
281 // processed. In that case we want to explicitly ensure that the reads were
283 void VerifyDataNotConsumed() {
284 for (DataVector::iterator it
= data_vector_
.begin();
285 it
!= data_vector_
.end(); ++it
) {
286 EXPECT_TRUE(!(*it
)->at_read_eof()) << "Read count: "
287 << (*it
)->read_count()
289 << (*it
)->read_index();
290 EXPECT_TRUE(!(*it
)->at_write_eof()) << "Write count: "
291 << (*it
)->write_count()
293 << (*it
)->write_index();
297 void RunToCompletion(StaticSocketDataProvider
* data
) {
301 VerifyDataConsumed();
304 void RunToCompletionWithSSLData(
305 StaticSocketDataProvider
* data
,
306 scoped_ptr
<SSLSocketDataProvider
> ssl_provider
) {
308 AddDataWithSSLSocketDataProvider(data
, ssl_provider
.Pass());
310 VerifyDataConsumed();
313 void AddData(StaticSocketDataProvider
* data
) {
314 scoped_ptr
<SSLSocketDataProvider
> ssl_provider(
315 new SSLSocketDataProvider(ASYNC
, OK
));
316 AddDataWithSSLSocketDataProvider(data
, ssl_provider
.Pass());
319 void AddDataWithSSLSocketDataProvider(
320 StaticSocketDataProvider
* data
,
321 scoped_ptr
<SSLSocketDataProvider
> ssl_provider
) {
322 DCHECK(!deterministic_
);
323 data_vector_
.push_back(data
);
324 if (ssl_provider
->next_proto_status
==
325 SSLClientSocket::kNextProtoUnsupported
) {
326 ssl_provider
->SetNextProto(test_params_
.protocol
);
329 session_deps_
->socket_factory
->AddSSLSocketDataProvider(
331 ssl_vector_
.push_back(ssl_provider
.release());
333 session_deps_
->socket_factory
->AddSocketDataProvider(data
);
334 if (test_params_
.ssl_type
== HTTP_SPDY_VIA_ALT_SVC
) {
335 MockConnect
hanging_connect(SYNCHRONOUS
, ERR_IO_PENDING
);
336 StaticSocketDataProvider
* hanging_non_alt_svc_socket
=
337 new StaticSocketDataProvider(NULL
, 0, NULL
, 0);
338 hanging_non_alt_svc_socket
->set_connect_data(hanging_connect
);
339 session_deps_
->socket_factory
->AddSocketDataProvider(
340 hanging_non_alt_svc_socket
);
341 alternate_vector_
.push_back(hanging_non_alt_svc_socket
);
345 void AddDeterministicData(DeterministicSocketData
* data
) {
346 DCHECK(deterministic_
);
347 data_vector_
.push_back(data
);
348 SSLSocketDataProvider
* ssl_provider
=
349 new SSLSocketDataProvider(ASYNC
, OK
);
350 ssl_provider
->SetNextProto(test_params_
.protocol
);
351 ssl_vector_
.push_back(ssl_provider
);
352 session_deps_
->deterministic_socket_factory
->AddSSLSocketDataProvider(
355 session_deps_
->deterministic_socket_factory
->AddSocketDataProvider(data
);
356 if (test_params_
.ssl_type
== HTTP_SPDY_VIA_ALT_SVC
) {
357 MockConnect
hanging_connect(SYNCHRONOUS
, ERR_IO_PENDING
);
358 DeterministicSocketData
* hanging_non_alt_svc_socket
=
359 new DeterministicSocketData(NULL
, 0, NULL
, 0);
360 hanging_non_alt_svc_socket
->set_connect_data(hanging_connect
);
361 session_deps_
->deterministic_socket_factory
->AddSocketDataProvider(
362 hanging_non_alt_svc_socket
);
363 alternate_vector_
.push_back(hanging_non_alt_svc_socket
);
367 void SetSession(const scoped_refptr
<HttpNetworkSession
>& session
) {
370 HttpNetworkTransaction
* trans() { return trans_
.get(); }
371 void ResetTrans() { trans_
.reset(); }
372 TransactionHelperResult
& output() { return output_
; }
373 const HttpRequestInfo
& request() const { return request_
; }
374 const scoped_refptr
<HttpNetworkSession
>& session() const {
377 scoped_ptr
<SpdySessionDependencies
>& session_deps() {
378 return session_deps_
;
380 int port() const { return port_
; }
381 SpdyNetworkTransactionTestParams
test_params() const {
386 typedef std::vector
<StaticSocketDataProvider
*> DataVector
;
387 typedef ScopedVector
<SSLSocketDataProvider
> SSLVector
;
388 typedef ScopedVector
<StaticSocketDataProvider
> AlternateVector
;
389 typedef ScopedVector
<DeterministicSocketData
> AlternateDeterministicVector
;
390 HttpRequestInfo request_
;
391 RequestPriority priority_
;
392 scoped_ptr
<SpdySessionDependencies
> session_deps_
;
393 scoped_refptr
<HttpNetworkSession
> session_
;
394 TransactionHelperResult output_
;
395 scoped_ptr
<StaticSocketDataProvider
> first_transaction_
;
396 SSLVector ssl_vector_
;
397 TestCompletionCallback callback_
;
398 scoped_ptr
<HttpNetworkTransaction
> trans_
;
399 scoped_ptr
<HttpNetworkTransaction
> trans_http_
;
400 DataVector data_vector_
;
401 AlternateVector alternate_vector_
;
402 AlternateDeterministicVector alternate_deterministic_vector_
;
403 const BoundNetLog log_
;
404 SpdyNetworkTransactionTestParams test_params_
;
410 void ConnectStatusHelperWithExpectedStatus(const MockRead
& status
,
411 int expected_status
);
413 void ConnectStatusHelper(const MockRead
& status
);
415 const HttpRequestInfo
& CreateGetPushRequest() {
416 google_get_push_request_
.method
= "GET";
417 google_get_push_request_
.url
= GURL(GetDefaultUrlWithPath("/foo.dat"));
418 google_get_push_request_
.load_flags
= 0;
419 return google_get_push_request_
;
422 const HttpRequestInfo
& CreateGetRequest() {
423 if (!google_get_request_initialized_
) {
424 google_get_request_
.method
= "GET";
425 google_get_request_
.url
= GURL(GetDefaultUrl());
426 google_get_request_
.load_flags
= 0;
427 google_get_request_initialized_
= true;
429 return google_get_request_
;
432 const HttpRequestInfo
& CreateGetRequestWithUserAgent() {
433 if (!google_get_request_initialized_
) {
434 google_get_request_
.method
= "GET";
435 google_get_request_
.url
= GURL(GetDefaultUrl());
436 google_get_request_
.load_flags
= 0;
437 google_get_request_
.extra_headers
.SetHeader("User-Agent", "Chrome");
438 google_get_request_initialized_
= true;
440 return google_get_request_
;
443 const HttpRequestInfo
& CreatePostRequest() {
444 if (!google_post_request_initialized_
) {
445 ScopedVector
<UploadElementReader
> element_readers
;
446 element_readers
.push_back(
447 new UploadBytesElementReader(kUploadData
, kUploadDataSize
));
448 upload_data_stream_
.reset(
449 new ElementsUploadDataStream(element_readers
.Pass(), 0));
451 google_post_request_
.method
= "POST";
452 google_post_request_
.url
= GURL(GetDefaultUrl());
453 google_post_request_
.upload_data_stream
= upload_data_stream_
.get();
454 google_post_request_initialized_
= true;
456 return google_post_request_
;
459 const HttpRequestInfo
& CreateFilePostRequest() {
460 if (!google_post_request_initialized_
) {
461 base::FilePath file_path
;
462 CHECK(base::CreateTemporaryFileInDir(temp_dir_
.path(), &file_path
));
463 CHECK_EQ(static_cast<int>(kUploadDataSize
),
464 base::WriteFile(file_path
, kUploadData
, kUploadDataSize
));
466 ScopedVector
<UploadElementReader
> element_readers
;
467 element_readers
.push_back(
468 new UploadFileElementReader(base::MessageLoopProxy::current().get(),
473 upload_data_stream_
.reset(
474 new ElementsUploadDataStream(element_readers
.Pass(), 0));
476 google_post_request_
.method
= "POST";
477 google_post_request_
.url
= GURL(GetDefaultUrl());
478 google_post_request_
.upload_data_stream
= upload_data_stream_
.get();
479 google_post_request_initialized_
= true;
481 return google_post_request_
;
484 const HttpRequestInfo
& CreateUnreadableFilePostRequest() {
485 if (google_post_request_initialized_
)
486 return google_post_request_
;
488 base::FilePath file_path
;
489 CHECK(base::CreateTemporaryFileInDir(temp_dir_
.path(), &file_path
));
490 CHECK_EQ(static_cast<int>(kUploadDataSize
),
491 base::WriteFile(file_path
, kUploadData
, kUploadDataSize
));
492 CHECK(base::MakeFileUnreadable(file_path
));
494 ScopedVector
<UploadElementReader
> element_readers
;
495 element_readers
.push_back(
496 new UploadFileElementReader(base::MessageLoopProxy::current().get(),
501 upload_data_stream_
.reset(
502 new ElementsUploadDataStream(element_readers
.Pass(), 0));
504 google_post_request_
.method
= "POST";
505 google_post_request_
.url
= GURL(GetDefaultUrl());
506 google_post_request_
.upload_data_stream
= upload_data_stream_
.get();
507 google_post_request_initialized_
= true;
508 return google_post_request_
;
511 const HttpRequestInfo
& CreateComplexPostRequest() {
512 if (!google_post_request_initialized_
) {
513 const int kFileRangeOffset
= 1;
514 const int kFileRangeLength
= 3;
515 CHECK_LT(kFileRangeOffset
+ kFileRangeLength
, kUploadDataSize
);
517 base::FilePath file_path
;
518 CHECK(base::CreateTemporaryFileInDir(temp_dir_
.path(), &file_path
));
519 CHECK_EQ(static_cast<int>(kUploadDataSize
),
520 base::WriteFile(file_path
, kUploadData
, kUploadDataSize
));
522 ScopedVector
<UploadElementReader
> element_readers
;
523 element_readers
.push_back(
524 new UploadBytesElementReader(kUploadData
, kFileRangeOffset
));
525 element_readers
.push_back(
526 new UploadFileElementReader(base::MessageLoopProxy::current().get(),
531 element_readers
.push_back(new UploadBytesElementReader(
532 kUploadData
+ kFileRangeOffset
+ kFileRangeLength
,
533 kUploadDataSize
- (kFileRangeOffset
+ kFileRangeLength
)));
534 upload_data_stream_
.reset(
535 new ElementsUploadDataStream(element_readers
.Pass(), 0));
537 google_post_request_
.method
= "POST";
538 google_post_request_
.url
= GURL(GetDefaultUrl());
539 google_post_request_
.upload_data_stream
= upload_data_stream_
.get();
540 google_post_request_initialized_
= true;
542 return google_post_request_
;
545 const HttpRequestInfo
& CreateChunkedPostRequest() {
546 if (!google_chunked_post_request_initialized_
) {
547 upload_chunked_data_stream_
.reset(new ChunkedUploadDataStream(0));
548 google_chunked_post_request_
.method
= "POST";
549 google_chunked_post_request_
.url
= GURL(GetDefaultUrl());
550 google_chunked_post_request_
.upload_data_stream
=
551 upload_chunked_data_stream_
.get();
552 google_chunked_post_request_initialized_
= true;
554 return google_chunked_post_request_
;
557 // Read the result of a particular transaction, knowing that we've got
558 // multiple transactions in the read pipeline; so as we read, we may have
559 // to skip over data destined for other transactions while we consume
560 // the data for |trans|.
561 int ReadResult(HttpNetworkTransaction
* trans
,
562 StaticSocketDataProvider
* data
,
563 std::string
* result
) {
564 const int kSize
= 3000;
567 scoped_refptr
<IOBufferWithSize
> buf(new IOBufferWithSize(kSize
));
568 TestCompletionCallback callback
;
570 int rv
= trans
->Read(buf
.get(), kSize
, callback
.callback());
571 if (rv
== ERR_IO_PENDING
) {
572 // Multiple transactions may be in the data set. Keep pulling off
573 // reads until we complete our callback.
574 while (!callback
.have_result()) {
575 data
->CompleteRead();
576 base::RunLoop().RunUntilIdle();
578 rv
= callback
.WaitForResult();
579 } else if (rv
<= 0) {
582 result
->append(buf
->data(), rv
);
588 void VerifyStreamsClosed(const NormalSpdyTransactionHelper
& helper
) {
589 // This lengthy block is reaching into the pool to dig out the active
590 // session. Once we have the session, we verify that the streams are
591 // all closed and not leaked at this point.
592 const GURL
& url
= helper
.request().url
;
593 HostPortPair
host_port_pair(url
.host(), 443);
594 SpdySessionKey
key(host_port_pair
, ProxyServer::Direct(),
595 PRIVACY_MODE_DISABLED
);
597 const scoped_refptr
<HttpNetworkSession
>& session
= helper
.session();
598 base::WeakPtr
<SpdySession
> spdy_session
=
599 session
->spdy_session_pool()->FindAvailableSession(key
, log
);
600 ASSERT_TRUE(spdy_session
!= NULL
);
601 EXPECT_EQ(0u, spdy_session
->num_active_streams());
602 EXPECT_EQ(0u, spdy_session
->num_unclaimed_pushed_streams());
605 void RunServerPushTest(OrderedSocketData
* data
,
606 HttpResponseInfo
* response
,
607 HttpResponseInfo
* push_response
,
608 const std::string
& expected
) {
609 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
610 BoundNetLog(), GetParam(), NULL
);
611 helper
.RunPreTestSetup();
612 helper
.AddData(data
);
614 HttpNetworkTransaction
* trans
= helper
.trans();
616 // Start the transaction with basic parameters.
617 TestCompletionCallback callback
;
618 int rv
= trans
->Start(
619 &CreateGetRequest(), callback
.callback(), BoundNetLog());
620 EXPECT_EQ(ERR_IO_PENDING
, rv
);
621 rv
= callback
.WaitForResult();
623 // Request the pushed path.
624 scoped_ptr
<HttpNetworkTransaction
> trans2(
625 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
627 &CreateGetPushRequest(), callback
.callback(), BoundNetLog());
628 EXPECT_EQ(ERR_IO_PENDING
, rv
);
629 base::RunLoop().RunUntilIdle();
631 // The data for the pushed path may be coming in more than 1 frame. Compile
632 // the results into a single string.
634 // Read the server push body.
636 ReadResult(trans2
.get(), data
, &result2
);
637 // Read the response body.
639 ReadResult(trans
, data
, &result
);
641 // Verify that we consumed all test data.
642 EXPECT_TRUE(data
->at_read_eof());
643 EXPECT_TRUE(data
->at_write_eof());
645 // Verify that the received push data is same as the expected push data.
646 EXPECT_EQ(result2
.compare(expected
), 0) << "Received data: "
648 << "||||| Expected data: "
651 // Verify the SYN_REPLY.
652 // Copy the response info, because trans goes away.
653 *response
= *trans
->GetResponseInfo();
654 *push_response
= *trans2
->GetResponseInfo();
656 VerifyStreamsClosed(helper
);
659 static void DeleteSessionCallback(NormalSpdyTransactionHelper
* helper
,
661 helper
->ResetTrans();
664 static void StartTransactionCallback(
665 const scoped_refptr
<HttpNetworkSession
>& session
,
668 scoped_ptr
<HttpNetworkTransaction
> trans(
669 new HttpNetworkTransaction(DEFAULT_PRIORITY
, session
.get()));
670 TestCompletionCallback callback
;
671 HttpRequestInfo request
;
672 request
.method
= "GET";
674 request
.load_flags
= 0;
675 int rv
= trans
->Start(&request
, callback
.callback(), BoundNetLog());
676 EXPECT_EQ(ERR_IO_PENDING
, rv
);
677 callback
.WaitForResult();
680 ChunkedUploadDataStream
* upload_chunked_data_stream() const {
681 return upload_chunked_data_stream_
.get();
684 const char* GetDefaultUrl() {
685 switch (GetParam().ssl_type
) {
686 case HTTP_SPDY_VIA_ALT_SVC
:
687 return "http://www.google.com";
688 case HTTPS_SPDY_VIA_NPN
:
689 return "https://www.google.com";
696 std::string
GetDefaultUrlWithPath(const char* path
) {
697 return std::string(GetDefaultUrl()) + path
;
700 SpdyTestUtil spdy_util_
;
703 scoped_ptr
<ChunkedUploadDataStream
> upload_chunked_data_stream_
;
704 scoped_ptr
<UploadDataStream
> upload_data_stream_
;
705 bool google_get_request_initialized_
;
706 bool google_post_request_initialized_
;
707 bool google_chunked_post_request_initialized_
;
708 HttpRequestInfo google_get_request_
;
709 HttpRequestInfo google_post_request_
;
710 HttpRequestInfo google_chunked_post_request_
;
711 HttpRequestInfo google_get_push_request_
;
712 base::ScopedTempDir temp_dir_
;
715 //-----------------------------------------------------------------------------
716 // All tests are run with three different connection types: SPDY after NPN
717 // negotiation, SPDY without SSL, and SPDY with SSL.
719 // TODO(akalin): Use ::testing::Combine() when we are able to use
721 INSTANTIATE_TEST_CASE_P(
723 SpdyNetworkTransactionTest
,
725 SpdyNetworkTransactionTestParams(kProtoSPDY31
, HTTPS_SPDY_VIA_NPN
),
726 SpdyNetworkTransactionTestParams(kProtoSPDY31
, HTTP_SPDY_VIA_ALT_SVC
),
727 SpdyNetworkTransactionTestParams(kProtoSPDY4_14
, HTTPS_SPDY_VIA_NPN
),
728 SpdyNetworkTransactionTestParams(kProtoSPDY4_14
, HTTP_SPDY_VIA_ALT_SVC
),
729 SpdyNetworkTransactionTestParams(kProtoSPDY4
, HTTPS_SPDY_VIA_NPN
),
730 SpdyNetworkTransactionTestParams(kProtoSPDY4
, HTTP_SPDY_VIA_ALT_SVC
)));
732 // Verify HttpNetworkTransaction constructor.
733 TEST_P(SpdyNetworkTransactionTest
, Constructor
) {
734 scoped_ptr
<SpdySessionDependencies
> session_deps(
735 CreateSpdySessionDependencies(GetParam()));
736 scoped_refptr
<HttpNetworkSession
> session(
737 SpdySessionDependencies::SpdyCreateSession(session_deps
.get()));
738 scoped_ptr
<HttpTransaction
> trans(
739 new HttpNetworkTransaction(DEFAULT_PRIORITY
, session
.get()));
742 TEST_P(SpdyNetworkTransactionTest
, Get
) {
743 // Construct the request.
744 scoped_ptr
<SpdyFrame
> req(
745 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
746 MockWrite writes
[] = { CreateMockWrite(*req
) };
748 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
749 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
751 CreateMockRead(*resp
),
752 CreateMockRead(*body
),
753 MockRead(ASYNC
, 0, 0) // EOF
756 DelayedSocketData
data(1, reads
, arraysize(reads
),
757 writes
, arraysize(writes
));
758 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
759 BoundNetLog(), GetParam(), NULL
);
760 helper
.RunToCompletion(&data
);
761 TransactionHelperResult out
= helper
.output();
762 EXPECT_EQ(OK
, out
.rv
);
763 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
764 EXPECT_EQ("hello!", out
.response_data
);
767 TEST_P(SpdyNetworkTransactionTest
, GetAtEachPriority
) {
768 for (RequestPriority p
= MINIMUM_PRIORITY
; p
<= MAXIMUM_PRIORITY
;
769 p
= RequestPriority(p
+ 1)) {
770 // Construct the request.
771 scoped_ptr
<SpdyFrame
> req(
772 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, p
, true));
773 MockWrite writes
[] = { CreateMockWrite(*req
) };
775 SpdyPriority spdy_prio
= 0;
776 EXPECT_TRUE(GetSpdyPriority(spdy_util_
.spdy_version(), *req
, &spdy_prio
));
777 // this repeats the RequestPriority-->SpdyPriority mapping from
778 // SpdyFramer::ConvertRequestPriorityToSpdyPriority to make
779 // sure it's being done right.
780 if (spdy_util_
.spdy_version() < SPDY3
) {
783 EXPECT_EQ(0, spdy_prio
);
786 EXPECT_EQ(1, spdy_prio
);
790 EXPECT_EQ(2, spdy_prio
);
793 EXPECT_EQ(3, spdy_prio
);
801 EXPECT_EQ(0, spdy_prio
);
804 EXPECT_EQ(1, spdy_prio
);
807 EXPECT_EQ(2, spdy_prio
);
810 EXPECT_EQ(3, spdy_prio
);
813 EXPECT_EQ(4, spdy_prio
);
820 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
821 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
823 CreateMockRead(*resp
),
824 CreateMockRead(*body
),
825 MockRead(ASYNC
, 0, 0) // EOF
828 DelayedSocketData
data(1, reads
, arraysize(reads
),
829 writes
, arraysize(writes
));
830 HttpRequestInfo http_req
= CreateGetRequest();
832 NormalSpdyTransactionHelper
helper(http_req
, p
, BoundNetLog(),
834 helper
.RunToCompletion(&data
);
835 TransactionHelperResult out
= helper
.output();
836 EXPECT_EQ(OK
, out
.rv
);
837 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
838 EXPECT_EQ("hello!", out
.response_data
);
842 // Start three gets simultaniously; making sure that multiplexed
843 // streams work properly.
845 // This can't use the TransactionHelper method, since it only
846 // handles a single transaction, and finishes them as soon
847 // as it launches them.
849 // TODO(gavinp): create a working generalized TransactionHelper that
850 // can allow multiple streams in flight.
852 TEST_P(SpdyNetworkTransactionTest
, ThreeGets
) {
853 scoped_ptr
<SpdyFrame
> req(
854 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
855 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
856 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, false));
857 scoped_ptr
<SpdyFrame
> fbody(spdy_util_
.ConstructSpdyBodyFrame(1, true));
859 scoped_ptr
<SpdyFrame
> req2(
860 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 3, LOWEST
, true));
861 scoped_ptr
<SpdyFrame
> resp2(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 3));
862 scoped_ptr
<SpdyFrame
> body2(spdy_util_
.ConstructSpdyBodyFrame(3, false));
863 scoped_ptr
<SpdyFrame
> fbody2(spdy_util_
.ConstructSpdyBodyFrame(3, true));
865 scoped_ptr
<SpdyFrame
> req3(
866 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 5, LOWEST
, true));
867 scoped_ptr
<SpdyFrame
> resp3(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 5));
868 scoped_ptr
<SpdyFrame
> body3(spdy_util_
.ConstructSpdyBodyFrame(5, false));
869 scoped_ptr
<SpdyFrame
> fbody3(spdy_util_
.ConstructSpdyBodyFrame(5, true));
871 MockWrite writes
[] = {
872 CreateMockWrite(*req
),
873 CreateMockWrite(*req2
),
874 CreateMockWrite(*req3
),
877 CreateMockRead(*resp
, 1),
878 CreateMockRead(*body
),
879 CreateMockRead(*resp2
, 4),
880 CreateMockRead(*body2
),
881 CreateMockRead(*resp3
, 7),
882 CreateMockRead(*body3
),
884 CreateMockRead(*fbody
),
885 CreateMockRead(*fbody2
),
886 CreateMockRead(*fbody3
),
888 MockRead(ASYNC
, 0, 0), // EOF
890 OrderedSocketData
data(reads
, arraysize(reads
),
891 writes
, arraysize(writes
));
892 OrderedSocketData
data_placeholder(NULL
, 0, NULL
, 0);
895 TransactionHelperResult out
;
896 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
897 BoundNetLog(), GetParam(), NULL
);
898 helper
.RunPreTestSetup();
899 helper
.AddData(&data
);
900 // We require placeholder data because three get requests are sent out at
901 // the same time which results in three sockets being connected. The first
902 // on will negotiate SPDY and will be used for all requests.
903 helper
.AddData(&data_placeholder
);
904 helper
.AddData(&data_placeholder
);
905 scoped_ptr
<HttpNetworkTransaction
> trans1(
906 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
907 scoped_ptr
<HttpNetworkTransaction
> trans2(
908 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
909 scoped_ptr
<HttpNetworkTransaction
> trans3(
910 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
912 TestCompletionCallback callback1
;
913 TestCompletionCallback callback2
;
914 TestCompletionCallback callback3
;
916 HttpRequestInfo httpreq1
= CreateGetRequest();
917 HttpRequestInfo httpreq2
= CreateGetRequest();
918 HttpRequestInfo httpreq3
= CreateGetRequest();
920 out
.rv
= trans1
->Start(&httpreq1
, callback1
.callback(), log
);
921 ASSERT_EQ(ERR_IO_PENDING
, out
.rv
);
922 out
.rv
= trans2
->Start(&httpreq2
, callback2
.callback(), log
);
923 ASSERT_EQ(ERR_IO_PENDING
, out
.rv
);
924 out
.rv
= trans3
->Start(&httpreq3
, callback3
.callback(), log
);
925 ASSERT_EQ(ERR_IO_PENDING
, out
.rv
);
927 out
.rv
= callback1
.WaitForResult();
928 ASSERT_EQ(OK
, out
.rv
);
929 out
.rv
= callback3
.WaitForResult();
930 ASSERT_EQ(OK
, out
.rv
);
932 const HttpResponseInfo
* response1
= trans1
->GetResponseInfo();
933 EXPECT_TRUE(response1
->headers
.get() != NULL
);
934 EXPECT_TRUE(response1
->was_fetched_via_spdy
);
935 out
.status_line
= response1
->headers
->GetStatusLine();
936 out
.response_info
= *response1
;
938 trans2
->GetResponseInfo();
940 out
.rv
= ReadTransaction(trans1
.get(), &out
.response_data
);
941 helper
.VerifyDataConsumed();
942 EXPECT_EQ(OK
, out
.rv
);
944 EXPECT_EQ(OK
, out
.rv
);
945 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
946 EXPECT_EQ("hello!hello!", out
.response_data
);
949 TEST_P(SpdyNetworkTransactionTest
, TwoGetsLateBinding
) {
950 scoped_ptr
<SpdyFrame
> req(
951 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
952 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
953 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, false));
954 scoped_ptr
<SpdyFrame
> fbody(spdy_util_
.ConstructSpdyBodyFrame(1, true));
956 scoped_ptr
<SpdyFrame
> req2(
957 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 3, LOWEST
, true));
958 scoped_ptr
<SpdyFrame
> resp2(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 3));
959 scoped_ptr
<SpdyFrame
> body2(spdy_util_
.ConstructSpdyBodyFrame(3, false));
960 scoped_ptr
<SpdyFrame
> fbody2(spdy_util_
.ConstructSpdyBodyFrame(3, true));
962 MockWrite writes
[] = {
963 CreateMockWrite(*req
),
964 CreateMockWrite(*req2
),
967 CreateMockRead(*resp
, 1),
968 CreateMockRead(*body
),
969 CreateMockRead(*resp2
, 4),
970 CreateMockRead(*body2
),
971 CreateMockRead(*fbody
),
972 CreateMockRead(*fbody2
),
973 MockRead(ASYNC
, 0, 0), // EOF
975 OrderedSocketData
data(reads
, arraysize(reads
),
976 writes
, arraysize(writes
));
978 MockConnect
never_finishing_connect(SYNCHRONOUS
, ERR_IO_PENDING
);
979 OrderedSocketData
data_placeholder(NULL
, 0, NULL
, 0);
980 data_placeholder
.set_connect_data(never_finishing_connect
);
983 TransactionHelperResult out
;
984 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
985 BoundNetLog(), GetParam(), NULL
);
986 helper
.RunPreTestSetup();
987 helper
.AddData(&data
);
988 // We require placeholder data because two requests are sent out at
989 // the same time which results in two sockets being connected. The first
990 // on will negotiate SPDY and will be used for all requests.
991 helper
.AddData(&data_placeholder
);
992 scoped_ptr
<HttpNetworkTransaction
> trans1(
993 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
994 scoped_ptr
<HttpNetworkTransaction
> trans2(
995 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
997 TestCompletionCallback callback1
;
998 TestCompletionCallback callback2
;
1000 HttpRequestInfo httpreq1
= CreateGetRequest();
1001 HttpRequestInfo httpreq2
= CreateGetRequest();
1003 out
.rv
= trans1
->Start(&httpreq1
, callback1
.callback(), log
);
1004 ASSERT_EQ(ERR_IO_PENDING
, out
.rv
);
1005 out
.rv
= trans2
->Start(&httpreq2
, callback2
.callback(), log
);
1006 ASSERT_EQ(ERR_IO_PENDING
, out
.rv
);
1008 out
.rv
= callback1
.WaitForResult();
1009 ASSERT_EQ(OK
, out
.rv
);
1010 out
.rv
= callback2
.WaitForResult();
1011 ASSERT_EQ(OK
, out
.rv
);
1013 const HttpResponseInfo
* response1
= trans1
->GetResponseInfo();
1014 EXPECT_TRUE(response1
->headers
.get() != NULL
);
1015 EXPECT_TRUE(response1
->was_fetched_via_spdy
);
1016 out
.status_line
= response1
->headers
->GetStatusLine();
1017 out
.response_info
= *response1
;
1018 out
.rv
= ReadTransaction(trans1
.get(), &out
.response_data
);
1019 EXPECT_EQ(OK
, out
.rv
);
1020 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1021 EXPECT_EQ("hello!hello!", out
.response_data
);
1023 const HttpResponseInfo
* response2
= trans2
->GetResponseInfo();
1024 EXPECT_TRUE(response2
->headers
.get() != NULL
);
1025 EXPECT_TRUE(response2
->was_fetched_via_spdy
);
1026 out
.status_line
= response2
->headers
->GetStatusLine();
1027 out
.response_info
= *response2
;
1028 out
.rv
= ReadTransaction(trans2
.get(), &out
.response_data
);
1029 EXPECT_EQ(OK
, out
.rv
);
1030 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1031 EXPECT_EQ("hello!hello!", out
.response_data
);
1033 helper
.VerifyDataConsumed();
1036 TEST_P(SpdyNetworkTransactionTest
, TwoGetsLateBindingFromPreconnect
) {
1037 scoped_ptr
<SpdyFrame
> req(
1038 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
1039 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
1040 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, false));
1041 scoped_ptr
<SpdyFrame
> fbody(spdy_util_
.ConstructSpdyBodyFrame(1, true));
1043 scoped_ptr
<SpdyFrame
> req2(
1044 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 3, LOWEST
, true));
1045 scoped_ptr
<SpdyFrame
> resp2(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 3));
1046 scoped_ptr
<SpdyFrame
> body2(spdy_util_
.ConstructSpdyBodyFrame(3, false));
1047 scoped_ptr
<SpdyFrame
> fbody2(spdy_util_
.ConstructSpdyBodyFrame(3, true));
1049 MockWrite writes
[] = {
1050 CreateMockWrite(*req
),
1051 CreateMockWrite(*req2
),
1053 MockRead reads
[] = {
1054 CreateMockRead(*resp
, 1),
1055 CreateMockRead(*body
),
1056 CreateMockRead(*resp2
, 4),
1057 CreateMockRead(*body2
),
1058 CreateMockRead(*fbody
),
1059 CreateMockRead(*fbody2
),
1060 MockRead(ASYNC
, 0, 0), // EOF
1062 OrderedSocketData
preconnect_data(reads
, arraysize(reads
),
1063 writes
, arraysize(writes
));
1065 MockConnect
never_finishing_connect(ASYNC
, ERR_IO_PENDING
);
1067 OrderedSocketData
data_placeholder(NULL
, 0, NULL
, 0);
1068 data_placeholder
.set_connect_data(never_finishing_connect
);
1071 TransactionHelperResult out
;
1072 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
1073 BoundNetLog(), GetParam(), NULL
);
1074 helper
.RunPreTestSetup();
1075 helper
.AddData(&preconnect_data
);
1076 // We require placeholder data because 3 connections are attempted (first is
1077 // the preconnect, 2nd and 3rd are the never finished connections.
1078 helper
.AddData(&data_placeholder
);
1079 helper
.AddData(&data_placeholder
);
1081 scoped_ptr
<HttpNetworkTransaction
> trans1(
1082 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
1083 scoped_ptr
<HttpNetworkTransaction
> trans2(
1084 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
1086 TestCompletionCallback callback1
;
1087 TestCompletionCallback callback2
;
1089 HttpRequestInfo httpreq
= CreateGetRequest();
1091 // Preconnect the first.
1092 SSLConfig preconnect_ssl_config
;
1093 helper
.session()->ssl_config_service()->GetSSLConfig(&preconnect_ssl_config
);
1094 HttpStreamFactory
* http_stream_factory
=
1095 helper
.session()->http_stream_factory();
1096 helper
.session()->GetNextProtos(&preconnect_ssl_config
.next_protos
);
1098 http_stream_factory
->PreconnectStreams(
1099 1, httpreq
, DEFAULT_PRIORITY
,
1100 preconnect_ssl_config
, preconnect_ssl_config
);
1102 out
.rv
= trans1
->Start(&httpreq
, callback1
.callback(), log
);
1103 ASSERT_EQ(ERR_IO_PENDING
, out
.rv
);
1104 out
.rv
= trans2
->Start(&httpreq
, callback2
.callback(), log
);
1105 ASSERT_EQ(ERR_IO_PENDING
, out
.rv
);
1107 out
.rv
= callback1
.WaitForResult();
1108 ASSERT_EQ(OK
, out
.rv
);
1109 out
.rv
= callback2
.WaitForResult();
1110 ASSERT_EQ(OK
, out
.rv
);
1112 const HttpResponseInfo
* response1
= trans1
->GetResponseInfo();
1113 EXPECT_TRUE(response1
->headers
.get() != NULL
);
1114 EXPECT_TRUE(response1
->was_fetched_via_spdy
);
1115 out
.status_line
= response1
->headers
->GetStatusLine();
1116 out
.response_info
= *response1
;
1117 out
.rv
= ReadTransaction(trans1
.get(), &out
.response_data
);
1118 EXPECT_EQ(OK
, out
.rv
);
1119 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1120 EXPECT_EQ("hello!hello!", out
.response_data
);
1122 const HttpResponseInfo
* response2
= trans2
->GetResponseInfo();
1123 EXPECT_TRUE(response2
->headers
.get() != NULL
);
1124 EXPECT_TRUE(response2
->was_fetched_via_spdy
);
1125 out
.status_line
= response2
->headers
->GetStatusLine();
1126 out
.response_info
= *response2
;
1127 out
.rv
= ReadTransaction(trans2
.get(), &out
.response_data
);
1128 EXPECT_EQ(OK
, out
.rv
);
1129 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1130 EXPECT_EQ("hello!hello!", out
.response_data
);
1132 helper
.VerifyDataConsumed();
1135 // Similar to ThreeGets above, however this test adds a SETTINGS
1136 // frame. The SETTINGS frame is read during the IO loop waiting on
1137 // the first transaction completion, and sets a maximum concurrent
1138 // stream limit of 1. This means that our IO loop exists after the
1139 // second transaction completes, so we can assert on read_index().
1140 TEST_P(SpdyNetworkTransactionTest
, ThreeGetsWithMaxConcurrent
) {
1141 // Construct the request.
1142 scoped_ptr
<SpdyFrame
> req(
1143 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
1144 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
1145 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, false));
1146 scoped_ptr
<SpdyFrame
> fbody(spdy_util_
.ConstructSpdyBodyFrame(1, true));
1148 scoped_ptr
<SpdyFrame
> req2(
1149 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 3, LOWEST
, true));
1150 scoped_ptr
<SpdyFrame
> resp2(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 3));
1151 scoped_ptr
<SpdyFrame
> body2(spdy_util_
.ConstructSpdyBodyFrame(3, false));
1152 scoped_ptr
<SpdyFrame
> fbody2(spdy_util_
.ConstructSpdyBodyFrame(3, true));
1154 scoped_ptr
<SpdyFrame
> req3(
1155 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 5, LOWEST
, true));
1156 scoped_ptr
<SpdyFrame
> resp3(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 5));
1157 scoped_ptr
<SpdyFrame
> body3(spdy_util_
.ConstructSpdyBodyFrame(5, false));
1158 scoped_ptr
<SpdyFrame
> fbody3(spdy_util_
.ConstructSpdyBodyFrame(5, true));
1160 SettingsMap settings
;
1161 const uint32 max_concurrent_streams
= 1;
1162 settings
[SETTINGS_MAX_CONCURRENT_STREAMS
] =
1163 SettingsFlagsAndValue(SETTINGS_FLAG_NONE
, max_concurrent_streams
);
1164 scoped_ptr
<SpdyFrame
> settings_frame(
1165 spdy_util_
.ConstructSpdySettings(settings
));
1166 scoped_ptr
<SpdyFrame
> settings_ack(spdy_util_
.ConstructSpdySettingsAck());
1168 MockWrite writes
[] = {
1169 CreateMockWrite(*req
),
1170 CreateMockWrite(*settings_ack
, 2),
1171 CreateMockWrite(*req2
),
1172 CreateMockWrite(*req3
),
1175 MockRead reads
[] = {
1176 CreateMockRead(*settings_frame
, 1),
1177 CreateMockRead(*resp
),
1178 CreateMockRead(*body
),
1179 CreateMockRead(*fbody
),
1180 CreateMockRead(*resp2
, 8),
1181 CreateMockRead(*body2
),
1182 CreateMockRead(*fbody2
),
1183 CreateMockRead(*resp3
, 13),
1184 CreateMockRead(*body3
),
1185 CreateMockRead(*fbody3
),
1187 MockRead(ASYNC
, 0, 0), // EOF
1190 OrderedSocketData
data(reads
, arraysize(reads
),
1191 writes
, arraysize(writes
));
1194 TransactionHelperResult out
;
1196 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
1197 BoundNetLog(), GetParam(), NULL
);
1198 helper
.RunPreTestSetup();
1199 helper
.AddData(&data
);
1200 scoped_ptr
<HttpNetworkTransaction
> trans1(
1201 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
1202 scoped_ptr
<HttpNetworkTransaction
> trans2(
1203 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
1204 scoped_ptr
<HttpNetworkTransaction
> trans3(
1205 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
1207 TestCompletionCallback callback1
;
1208 TestCompletionCallback callback2
;
1209 TestCompletionCallback callback3
;
1211 HttpRequestInfo httpreq1
= CreateGetRequest();
1212 HttpRequestInfo httpreq2
= CreateGetRequest();
1213 HttpRequestInfo httpreq3
= CreateGetRequest();
1215 out
.rv
= trans1
->Start(&httpreq1
, callback1
.callback(), log
);
1216 ASSERT_EQ(out
.rv
, ERR_IO_PENDING
);
1217 // Run transaction 1 through quickly to force a read of our SETTINGS
1219 out
.rv
= callback1
.WaitForResult();
1220 ASSERT_EQ(OK
, out
.rv
);
1222 out
.rv
= trans2
->Start(&httpreq2
, callback2
.callback(), log
);
1223 ASSERT_EQ(out
.rv
, ERR_IO_PENDING
);
1224 out
.rv
= trans3
->Start(&httpreq3
, callback3
.callback(), log
);
1225 ASSERT_EQ(out
.rv
, ERR_IO_PENDING
);
1226 out
.rv
= callback2
.WaitForResult();
1227 ASSERT_EQ(OK
, out
.rv
);
1228 EXPECT_EQ(7U, data
.read_index()); // i.e. the third trans was queued
1230 out
.rv
= callback3
.WaitForResult();
1231 ASSERT_EQ(OK
, out
.rv
);
1233 const HttpResponseInfo
* response1
= trans1
->GetResponseInfo();
1234 ASSERT_TRUE(response1
!= NULL
);
1235 EXPECT_TRUE(response1
->headers
.get() != NULL
);
1236 EXPECT_TRUE(response1
->was_fetched_via_spdy
);
1237 out
.status_line
= response1
->headers
->GetStatusLine();
1238 out
.response_info
= *response1
;
1239 out
.rv
= ReadTransaction(trans1
.get(), &out
.response_data
);
1240 EXPECT_EQ(OK
, out
.rv
);
1241 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1242 EXPECT_EQ("hello!hello!", out
.response_data
);
1244 const HttpResponseInfo
* response2
= trans2
->GetResponseInfo();
1245 out
.status_line
= response2
->headers
->GetStatusLine();
1246 out
.response_info
= *response2
;
1247 out
.rv
= ReadTransaction(trans2
.get(), &out
.response_data
);
1248 EXPECT_EQ(OK
, out
.rv
);
1249 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1250 EXPECT_EQ("hello!hello!", out
.response_data
);
1252 const HttpResponseInfo
* response3
= trans3
->GetResponseInfo();
1253 out
.status_line
= response3
->headers
->GetStatusLine();
1254 out
.response_info
= *response3
;
1255 out
.rv
= ReadTransaction(trans3
.get(), &out
.response_data
);
1256 EXPECT_EQ(OK
, out
.rv
);
1257 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1258 EXPECT_EQ("hello!hello!", out
.response_data
);
1260 helper
.VerifyDataConsumed();
1262 EXPECT_EQ(OK
, out
.rv
);
1265 // Similar to ThreeGetsWithMaxConcurrent above, however this test adds
1266 // a fourth transaction. The third and fourth transactions have
1267 // different data ("hello!" vs "hello!hello!") and because of the
1268 // user specified priority, we expect to see them inverted in
1269 // the response from the server.
1270 TEST_P(SpdyNetworkTransactionTest
, FourGetsWithMaxConcurrentPriority
) {
1271 // Construct the request.
1272 scoped_ptr
<SpdyFrame
> req(
1273 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
1274 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
1275 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, false));
1276 scoped_ptr
<SpdyFrame
> fbody(spdy_util_
.ConstructSpdyBodyFrame(1, true));
1278 scoped_ptr
<SpdyFrame
> req2(
1279 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 3, LOWEST
, true));
1280 scoped_ptr
<SpdyFrame
> resp2(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 3));
1281 scoped_ptr
<SpdyFrame
> body2(spdy_util_
.ConstructSpdyBodyFrame(3, false));
1282 scoped_ptr
<SpdyFrame
> fbody2(spdy_util_
.ConstructSpdyBodyFrame(3, true));
1284 scoped_ptr
<SpdyFrame
> req4(
1285 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 5, HIGHEST
, true));
1286 scoped_ptr
<SpdyFrame
> resp4(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 5));
1287 scoped_ptr
<SpdyFrame
> fbody4(spdy_util_
.ConstructSpdyBodyFrame(5, true));
1289 scoped_ptr
<SpdyFrame
> req3(
1290 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 7, LOWEST
, true));
1291 scoped_ptr
<SpdyFrame
> resp3(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 7));
1292 scoped_ptr
<SpdyFrame
> body3(spdy_util_
.ConstructSpdyBodyFrame(7, false));
1293 scoped_ptr
<SpdyFrame
> fbody3(spdy_util_
.ConstructSpdyBodyFrame(7, true));
1295 SettingsMap settings
;
1296 const uint32 max_concurrent_streams
= 1;
1297 settings
[SETTINGS_MAX_CONCURRENT_STREAMS
] =
1298 SettingsFlagsAndValue(SETTINGS_FLAG_NONE
, max_concurrent_streams
);
1299 scoped_ptr
<SpdyFrame
> settings_frame(
1300 spdy_util_
.ConstructSpdySettings(settings
));
1301 scoped_ptr
<SpdyFrame
> settings_ack(spdy_util_
.ConstructSpdySettingsAck());
1303 MockWrite writes
[] = { CreateMockWrite(*req
),
1304 CreateMockWrite(*settings_ack
, 2),
1305 CreateMockWrite(*req2
),
1306 CreateMockWrite(*req4
),
1307 CreateMockWrite(*req3
),
1309 MockRead reads
[] = {
1310 CreateMockRead(*settings_frame
, 1),
1311 CreateMockRead(*resp
),
1312 CreateMockRead(*body
),
1313 CreateMockRead(*fbody
),
1314 CreateMockRead(*resp2
, 8),
1315 CreateMockRead(*body2
),
1316 CreateMockRead(*fbody2
),
1317 CreateMockRead(*resp4
, 14),
1318 CreateMockRead(*fbody4
),
1319 CreateMockRead(*resp3
, 17),
1320 CreateMockRead(*body3
),
1321 CreateMockRead(*fbody3
),
1323 MockRead(ASYNC
, 0, 0), // EOF
1326 OrderedSocketData
data(reads
, arraysize(reads
),
1327 writes
, arraysize(writes
));
1330 TransactionHelperResult out
;
1331 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
1332 BoundNetLog(), GetParam(), NULL
);
1333 helper
.RunPreTestSetup();
1334 helper
.AddData(&data
);
1335 scoped_ptr
<HttpNetworkTransaction
> trans1(
1336 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
1337 scoped_ptr
<HttpNetworkTransaction
> trans2(
1338 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
1339 scoped_ptr
<HttpNetworkTransaction
> trans3(
1340 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
1341 scoped_ptr
<HttpNetworkTransaction
> trans4(
1342 new HttpNetworkTransaction(HIGHEST
, helper
.session().get()));
1344 TestCompletionCallback callback1
;
1345 TestCompletionCallback callback2
;
1346 TestCompletionCallback callback3
;
1347 TestCompletionCallback callback4
;
1349 HttpRequestInfo httpreq1
= CreateGetRequest();
1350 HttpRequestInfo httpreq2
= CreateGetRequest();
1351 HttpRequestInfo httpreq3
= CreateGetRequest();
1352 HttpRequestInfo httpreq4
= CreateGetRequest();
1354 out
.rv
= trans1
->Start(&httpreq1
, callback1
.callback(), log
);
1355 ASSERT_EQ(ERR_IO_PENDING
, out
.rv
);
1356 // Run transaction 1 through quickly to force a read of our SETTINGS frame.
1357 out
.rv
= callback1
.WaitForResult();
1358 ASSERT_EQ(OK
, out
.rv
);
1360 out
.rv
= trans2
->Start(&httpreq2
, callback2
.callback(), log
);
1361 ASSERT_EQ(ERR_IO_PENDING
, out
.rv
);
1362 out
.rv
= trans3
->Start(&httpreq3
, callback3
.callback(), log
);
1363 ASSERT_EQ(ERR_IO_PENDING
, out
.rv
);
1364 out
.rv
= trans4
->Start(&httpreq4
, callback4
.callback(), log
);
1365 ASSERT_EQ(ERR_IO_PENDING
, out
.rv
);
1367 out
.rv
= callback2
.WaitForResult();
1368 ASSERT_EQ(OK
, out
.rv
);
1369 EXPECT_EQ(data
.read_index(), 7U); // i.e. the third & fourth trans queued
1371 out
.rv
= callback3
.WaitForResult();
1372 ASSERT_EQ(OK
, out
.rv
);
1374 const HttpResponseInfo
* response1
= trans1
->GetResponseInfo();
1375 EXPECT_TRUE(response1
->headers
.get() != NULL
);
1376 EXPECT_TRUE(response1
->was_fetched_via_spdy
);
1377 out
.status_line
= response1
->headers
->GetStatusLine();
1378 out
.response_info
= *response1
;
1379 out
.rv
= ReadTransaction(trans1
.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 const HttpResponseInfo
* response2
= trans2
->GetResponseInfo();
1385 out
.status_line
= response2
->headers
->GetStatusLine();
1386 out
.response_info
= *response2
;
1387 out
.rv
= ReadTransaction(trans2
.get(), &out
.response_data
);
1388 EXPECT_EQ(OK
, out
.rv
);
1389 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1390 EXPECT_EQ("hello!hello!", out
.response_data
);
1392 // notice: response3 gets two hellos, response4 gets one
1393 // hello, so we know dequeuing priority was respected.
1394 const HttpResponseInfo
* response3
= trans3
->GetResponseInfo();
1395 out
.status_line
= response3
->headers
->GetStatusLine();
1396 out
.response_info
= *response3
;
1397 out
.rv
= ReadTransaction(trans3
.get(), &out
.response_data
);
1398 EXPECT_EQ(OK
, out
.rv
);
1399 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1400 EXPECT_EQ("hello!hello!", out
.response_data
);
1402 out
.rv
= callback4
.WaitForResult();
1403 EXPECT_EQ(OK
, out
.rv
);
1404 const HttpResponseInfo
* response4
= trans4
->GetResponseInfo();
1405 out
.status_line
= response4
->headers
->GetStatusLine();
1406 out
.response_info
= *response4
;
1407 out
.rv
= ReadTransaction(trans4
.get(), &out
.response_data
);
1408 EXPECT_EQ(OK
, out
.rv
);
1409 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1410 EXPECT_EQ("hello!", out
.response_data
);
1411 helper
.VerifyDataConsumed();
1412 EXPECT_EQ(OK
, out
.rv
);
1415 // Similar to ThreeGetsMaxConcurrrent above, however, this test
1416 // deletes a session in the middle of the transaction to insure
1417 // that we properly remove pendingcreatestream objects from
1419 TEST_P(SpdyNetworkTransactionTest
, ThreeGetsWithMaxConcurrentDelete
) {
1420 // Construct the request.
1421 scoped_ptr
<SpdyFrame
> req(
1422 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
1423 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
1424 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, false));
1425 scoped_ptr
<SpdyFrame
> fbody(spdy_util_
.ConstructSpdyBodyFrame(1, true));
1427 scoped_ptr
<SpdyFrame
> req2(
1428 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 3, LOWEST
, true));
1429 scoped_ptr
<SpdyFrame
> resp2(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 3));
1430 scoped_ptr
<SpdyFrame
> body2(spdy_util_
.ConstructSpdyBodyFrame(3, false));
1431 scoped_ptr
<SpdyFrame
> fbody2(spdy_util_
.ConstructSpdyBodyFrame(3, true));
1433 SettingsMap settings
;
1434 const uint32 max_concurrent_streams
= 1;
1435 settings
[SETTINGS_MAX_CONCURRENT_STREAMS
] =
1436 SettingsFlagsAndValue(SETTINGS_FLAG_NONE
, max_concurrent_streams
);
1437 scoped_ptr
<SpdyFrame
> settings_frame(
1438 spdy_util_
.ConstructSpdySettings(settings
));
1439 scoped_ptr
<SpdyFrame
> settings_ack(spdy_util_
.ConstructSpdySettingsAck());
1441 MockWrite writes
[] = {
1442 CreateMockWrite(*req
),
1443 CreateMockWrite(*settings_ack
, 2),
1444 CreateMockWrite(*req2
),
1446 MockRead reads
[] = {
1447 CreateMockRead(*settings_frame
, 1),
1448 CreateMockRead(*resp
),
1449 CreateMockRead(*body
),
1450 CreateMockRead(*fbody
),
1451 CreateMockRead(*resp2
, 8),
1452 CreateMockRead(*body2
),
1453 CreateMockRead(*fbody2
),
1454 MockRead(ASYNC
, 0, 0), // EOF
1457 OrderedSocketData
data(reads
, arraysize(reads
),
1458 writes
, arraysize(writes
));
1461 TransactionHelperResult out
;
1462 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
1463 BoundNetLog(), GetParam(), NULL
);
1464 helper
.RunPreTestSetup();
1465 helper
.AddData(&data
);
1466 scoped_ptr
<HttpNetworkTransaction
> trans1(
1467 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
1468 scoped_ptr
<HttpNetworkTransaction
> trans2(
1469 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
1470 scoped_ptr
<HttpNetworkTransaction
> trans3(
1471 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
1473 TestCompletionCallback callback1
;
1474 TestCompletionCallback callback2
;
1475 TestCompletionCallback callback3
;
1477 HttpRequestInfo httpreq1
= CreateGetRequest();
1478 HttpRequestInfo httpreq2
= CreateGetRequest();
1479 HttpRequestInfo httpreq3
= CreateGetRequest();
1481 out
.rv
= trans1
->Start(&httpreq1
, callback1
.callback(), log
);
1482 ASSERT_EQ(out
.rv
, ERR_IO_PENDING
);
1483 // Run transaction 1 through quickly to force a read of our SETTINGS frame.
1484 out
.rv
= callback1
.WaitForResult();
1485 ASSERT_EQ(OK
, out
.rv
);
1487 out
.rv
= trans2
->Start(&httpreq2
, callback2
.callback(), log
);
1488 ASSERT_EQ(out
.rv
, ERR_IO_PENDING
);
1489 out
.rv
= trans3
->Start(&httpreq3
, callback3
.callback(), log
);
1490 delete trans3
.release();
1491 ASSERT_EQ(out
.rv
, ERR_IO_PENDING
);
1492 out
.rv
= callback2
.WaitForResult();
1493 ASSERT_EQ(OK
, out
.rv
);
1495 EXPECT_EQ(8U, data
.read_index());
1497 const HttpResponseInfo
* response1
= trans1
->GetResponseInfo();
1498 ASSERT_TRUE(response1
!= NULL
);
1499 EXPECT_TRUE(response1
->headers
.get() != NULL
);
1500 EXPECT_TRUE(response1
->was_fetched_via_spdy
);
1501 out
.status_line
= response1
->headers
->GetStatusLine();
1502 out
.response_info
= *response1
;
1503 out
.rv
= ReadTransaction(trans1
.get(), &out
.response_data
);
1504 EXPECT_EQ(OK
, out
.rv
);
1505 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1506 EXPECT_EQ("hello!hello!", out
.response_data
);
1508 const HttpResponseInfo
* response2
= trans2
->GetResponseInfo();
1509 ASSERT_TRUE(response2
!= NULL
);
1510 out
.status_line
= response2
->headers
->GetStatusLine();
1511 out
.response_info
= *response2
;
1512 out
.rv
= ReadTransaction(trans2
.get(), &out
.response_data
);
1513 EXPECT_EQ(OK
, out
.rv
);
1514 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1515 EXPECT_EQ("hello!hello!", out
.response_data
);
1516 helper
.VerifyDataConsumed();
1517 EXPECT_EQ(OK
, out
.rv
);
1522 // The KillerCallback will delete the transaction on error as part of the
1524 class KillerCallback
: public TestCompletionCallbackBase
{
1526 explicit KillerCallback(HttpNetworkTransaction
* transaction
)
1527 : transaction_(transaction
),
1528 callback_(base::Bind(&KillerCallback::OnComplete
,
1529 base::Unretained(this))) {
1532 ~KillerCallback() override
{}
1534 const CompletionCallback
& callback() const { return callback_
; }
1537 void OnComplete(int result
) {
1539 delete transaction_
;
1544 HttpNetworkTransaction
* transaction_
;
1545 CompletionCallback callback_
;
1550 // Similar to ThreeGetsMaxConcurrrentDelete above, however, this test
1551 // closes the socket while we have a pending transaction waiting for
1552 // a pending stream creation. http://crbug.com/52901
1553 TEST_P(SpdyNetworkTransactionTest
, ThreeGetsWithMaxConcurrentSocketClose
) {
1554 // Construct the request.
1555 scoped_ptr
<SpdyFrame
> req(
1556 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
1557 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
1558 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, false));
1559 scoped_ptr
<SpdyFrame
> fin_body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
1561 scoped_ptr
<SpdyFrame
> req2(
1562 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 3, LOWEST
, true));
1563 scoped_ptr
<SpdyFrame
> resp2(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 3));
1565 SettingsMap settings
;
1566 const uint32 max_concurrent_streams
= 1;
1567 settings
[SETTINGS_MAX_CONCURRENT_STREAMS
] =
1568 SettingsFlagsAndValue(SETTINGS_FLAG_NONE
, max_concurrent_streams
);
1569 scoped_ptr
<SpdyFrame
> settings_frame(
1570 spdy_util_
.ConstructSpdySettings(settings
));
1571 scoped_ptr
<SpdyFrame
> settings_ack(spdy_util_
.ConstructSpdySettingsAck());
1573 MockWrite writes
[] = {
1574 CreateMockWrite(*req
),
1575 CreateMockWrite(*settings_ack
, 2),
1576 CreateMockWrite(*req2
),
1578 MockRead reads
[] = {
1579 CreateMockRead(*settings_frame
, 1),
1580 CreateMockRead(*resp
),
1581 CreateMockRead(*body
),
1582 CreateMockRead(*fin_body
),
1583 CreateMockRead(*resp2
, 8),
1584 MockRead(ASYNC
, ERR_CONNECTION_RESET
, 0), // Abort!
1587 OrderedSocketData
data(reads
, arraysize(reads
),
1588 writes
, arraysize(writes
));
1589 OrderedSocketData
data_placeholder(NULL
, 0, NULL
, 0);
1592 TransactionHelperResult out
;
1593 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
1594 BoundNetLog(), GetParam(), NULL
);
1595 helper
.RunPreTestSetup();
1596 helper
.AddData(&data
);
1597 // We require placeholder data because three get requests are sent out, so
1598 // there needs to be three sets of SSL connection data.
1599 helper
.AddData(&data_placeholder
);
1600 helper
.AddData(&data_placeholder
);
1601 HttpNetworkTransaction
trans1(DEFAULT_PRIORITY
, helper
.session().get());
1602 HttpNetworkTransaction
trans2(DEFAULT_PRIORITY
, helper
.session().get());
1603 HttpNetworkTransaction
* trans3(
1604 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
1606 TestCompletionCallback callback1
;
1607 TestCompletionCallback callback2
;
1608 KillerCallback
callback3(trans3
);
1610 HttpRequestInfo httpreq1
= CreateGetRequest();
1611 HttpRequestInfo httpreq2
= CreateGetRequest();
1612 HttpRequestInfo httpreq3
= CreateGetRequest();
1614 out
.rv
= trans1
.Start(&httpreq1
, callback1
.callback(), log
);
1615 ASSERT_EQ(out
.rv
, ERR_IO_PENDING
);
1616 // Run transaction 1 through quickly to force a read of our SETTINGS frame.
1617 out
.rv
= callback1
.WaitForResult();
1618 ASSERT_EQ(OK
, out
.rv
);
1620 out
.rv
= trans2
.Start(&httpreq2
, callback2
.callback(), log
);
1621 ASSERT_EQ(out
.rv
, ERR_IO_PENDING
);
1622 out
.rv
= trans3
->Start(&httpreq3
, callback3
.callback(), log
);
1623 ASSERT_EQ(out
.rv
, ERR_IO_PENDING
);
1624 out
.rv
= callback3
.WaitForResult();
1625 ASSERT_EQ(ERR_ABORTED
, out
.rv
);
1627 EXPECT_EQ(6U, data
.read_index());
1629 const HttpResponseInfo
* response1
= trans1
.GetResponseInfo();
1630 ASSERT_TRUE(response1
!= NULL
);
1631 EXPECT_TRUE(response1
->headers
.get() != NULL
);
1632 EXPECT_TRUE(response1
->was_fetched_via_spdy
);
1633 out
.status_line
= response1
->headers
->GetStatusLine();
1634 out
.response_info
= *response1
;
1635 out
.rv
= ReadTransaction(&trans1
, &out
.response_data
);
1636 EXPECT_EQ(OK
, out
.rv
);
1638 const HttpResponseInfo
* response2
= trans2
.GetResponseInfo();
1639 ASSERT_TRUE(response2
!= NULL
);
1640 out
.status_line
= response2
->headers
->GetStatusLine();
1641 out
.response_info
= *response2
;
1642 out
.rv
= ReadTransaction(&trans2
, &out
.response_data
);
1643 EXPECT_EQ(ERR_CONNECTION_RESET
, out
.rv
);
1645 helper
.VerifyDataConsumed();
1648 // Test that a simple PUT request works.
1649 TEST_P(SpdyNetworkTransactionTest
, Put
) {
1650 // Setup the request
1651 HttpRequestInfo request
;
1652 request
.method
= "PUT";
1653 request
.url
= GURL(GetDefaultUrl());
1655 scoped_ptr
<SpdyHeaderBlock
> put_headers(
1656 spdy_util_
.ConstructPutHeaderBlock(GetDefaultUrl(), 0));
1657 scoped_ptr
<SpdyFrame
> req(
1658 spdy_util_
.ConstructSpdySyn(1, *put_headers
, LOWEST
, false, true));
1659 MockWrite writes
[] = {
1660 CreateMockWrite(*req
),
1663 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
1664 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
1665 MockRead reads
[] = {
1666 CreateMockRead(*resp
),
1667 CreateMockRead(*body
),
1668 MockRead(ASYNC
, 0, 0) // EOF
1671 DelayedSocketData
data(1, reads
, arraysize(reads
),
1672 writes
, arraysize(writes
));
1673 NormalSpdyTransactionHelper
helper(request
, DEFAULT_PRIORITY
,
1674 BoundNetLog(), GetParam(), NULL
);
1675 helper
.RunToCompletion(&data
);
1676 TransactionHelperResult out
= helper
.output();
1678 EXPECT_EQ(OK
, out
.rv
);
1679 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1682 // Test that a simple HEAD request works.
1683 TEST_P(SpdyNetworkTransactionTest
, Head
) {
1684 // Setup the request
1685 HttpRequestInfo request
;
1686 request
.method
= "HEAD";
1687 request
.url
= GURL(GetDefaultUrl());
1689 scoped_ptr
<SpdyHeaderBlock
> head_headers(
1690 spdy_util_
.ConstructHeadHeaderBlock(GetDefaultUrl(), 0));
1691 scoped_ptr
<SpdyFrame
> req(
1692 spdy_util_
.ConstructSpdySyn(1, *head_headers
, LOWEST
, false, true));
1693 MockWrite writes
[] = {
1694 CreateMockWrite(*req
),
1697 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
1698 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
1699 MockRead reads
[] = {
1700 CreateMockRead(*resp
),
1701 CreateMockRead(*body
),
1702 MockRead(ASYNC
, 0, 0) // EOF
1705 DelayedSocketData
data(1, reads
, arraysize(reads
),
1706 writes
, arraysize(writes
));
1707 NormalSpdyTransactionHelper
helper(request
, DEFAULT_PRIORITY
,
1708 BoundNetLog(), GetParam(), NULL
);
1709 helper
.RunToCompletion(&data
);
1710 TransactionHelperResult out
= helper
.output();
1712 EXPECT_EQ(OK
, out
.rv
);
1713 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1716 // Test that a simple POST works.
1717 TEST_P(SpdyNetworkTransactionTest
, Post
) {
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
),
1723 CreateMockWrite(*body
), // POST upload frame
1726 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyPostSynReply(NULL
, 0));
1727 MockRead reads
[] = {
1728 CreateMockRead(*resp
),
1729 CreateMockRead(*body
),
1730 MockRead(ASYNC
, 0, 0) // EOF
1733 DelayedSocketData
data(2, reads
, arraysize(reads
),
1734 writes
, arraysize(writes
));
1735 NormalSpdyTransactionHelper
helper(CreatePostRequest(), DEFAULT_PRIORITY
,
1736 BoundNetLog(), GetParam(), NULL
);
1737 helper
.RunToCompletion(&data
);
1738 TransactionHelperResult out
= helper
.output();
1739 EXPECT_EQ(OK
, out
.rv
);
1740 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1741 EXPECT_EQ("hello!", out
.response_data
);
1744 // Test that a POST with a file works.
1745 TEST_P(SpdyNetworkTransactionTest
, FilePost
) {
1746 scoped_ptr
<SpdyFrame
> req(spdy_util_
.ConstructSpdyPost(
1747 GetDefaultUrl(), 1, kUploadDataSize
, LOWEST
, NULL
, 0));
1748 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
1749 MockWrite writes
[] = {
1750 CreateMockWrite(*req
),
1751 CreateMockWrite(*body
), // POST upload frame
1754 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyPostSynReply(NULL
, 0));
1755 MockRead reads
[] = {
1756 CreateMockRead(*resp
),
1757 CreateMockRead(*body
),
1758 MockRead(ASYNC
, 0, 0) // EOF
1761 DelayedSocketData
data(2, reads
, arraysize(reads
),
1762 writes
, arraysize(writes
));
1763 NormalSpdyTransactionHelper
helper(CreateFilePostRequest(), DEFAULT_PRIORITY
,
1764 BoundNetLog(), GetParam(), NULL
);
1765 helper
.RunToCompletion(&data
);
1766 TransactionHelperResult out
= helper
.output();
1767 EXPECT_EQ(OK
, out
.rv
);
1768 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1769 EXPECT_EQ("hello!", out
.response_data
);
1772 // Test that a POST with a unreadable file fails.
1773 TEST_P(SpdyNetworkTransactionTest
, UnreadableFilePost
) {
1774 MockWrite writes
[] = {
1775 MockWrite(ASYNC
, 0, 0) // EOF
1777 MockRead reads
[] = {
1778 MockRead(ASYNC
, 0, 0) // EOF
1781 DelayedSocketData
data(1, reads
, arraysize(reads
), writes
, arraysize(writes
));
1782 NormalSpdyTransactionHelper
helper(CreateUnreadableFilePostRequest(),
1784 BoundNetLog(), GetParam(), NULL
);
1785 helper
.RunPreTestSetup();
1786 helper
.AddData(&data
);
1787 helper
.RunDefaultTest();
1789 base::RunLoop().RunUntilIdle();
1790 helper
.VerifyDataNotConsumed();
1791 EXPECT_EQ(ERR_ACCESS_DENIED
, helper
.output().rv
);
1794 // Test that a complex POST works.
1795 TEST_P(SpdyNetworkTransactionTest
, ComplexPost
) {
1796 scoped_ptr
<SpdyFrame
> req(spdy_util_
.ConstructSpdyPost(
1797 GetDefaultUrl(), 1, kUploadDataSize
, LOWEST
, NULL
, 0));
1798 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
1799 MockWrite writes
[] = {
1800 CreateMockWrite(*req
),
1801 CreateMockWrite(*body
), // POST upload frame
1804 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyPostSynReply(NULL
, 0));
1805 MockRead reads
[] = {
1806 CreateMockRead(*resp
),
1807 CreateMockRead(*body
),
1808 MockRead(ASYNC
, 0, 0) // EOF
1811 DelayedSocketData
data(2, reads
, arraysize(reads
),
1812 writes
, arraysize(writes
));
1813 NormalSpdyTransactionHelper
helper(CreateComplexPostRequest(),
1815 BoundNetLog(), GetParam(), NULL
);
1816 helper
.RunToCompletion(&data
);
1817 TransactionHelperResult out
= helper
.output();
1818 EXPECT_EQ(OK
, out
.rv
);
1819 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1820 EXPECT_EQ("hello!", out
.response_data
);
1823 // Test that a chunked POST works.
1824 TEST_P(SpdyNetworkTransactionTest
, ChunkedPost
) {
1825 scoped_ptr
<SpdyFrame
> req(spdy_util_
.ConstructChunkedSpdyPost(NULL
, 0));
1826 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
1827 MockWrite writes
[] = {
1828 CreateMockWrite(*req
),
1829 CreateMockWrite(*body
),
1832 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyPostSynReply(NULL
, 0));
1833 MockRead reads
[] = {
1834 CreateMockRead(*resp
),
1835 CreateMockRead(*body
),
1836 MockRead(ASYNC
, 0, 0) // EOF
1839 DelayedSocketData
data(2, reads
, arraysize(reads
),
1840 writes
, arraysize(writes
));
1841 NormalSpdyTransactionHelper
helper(CreateChunkedPostRequest(),
1843 BoundNetLog(), GetParam(), NULL
);
1845 // These chunks get merged into a single frame when being sent.
1846 const int kFirstChunkSize
= kUploadDataSize
/2;
1847 upload_chunked_data_stream()->AppendData(kUploadData
, kFirstChunkSize
, false);
1848 upload_chunked_data_stream()->AppendData(
1849 kUploadData
+ kFirstChunkSize
, kUploadDataSize
- kFirstChunkSize
, true);
1851 helper
.RunToCompletion(&data
);
1852 TransactionHelperResult out
= helper
.output();
1853 EXPECT_EQ(OK
, out
.rv
);
1854 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1855 EXPECT_EQ(kUploadData
, out
.response_data
);
1858 // Test that a chunked POST works with chunks appended after transaction starts.
1859 TEST_P(SpdyNetworkTransactionTest
, DelayedChunkedPost
) {
1860 scoped_ptr
<SpdyFrame
> req(spdy_util_
.ConstructChunkedSpdyPost(NULL
, 0));
1861 scoped_ptr
<SpdyFrame
> chunk1(spdy_util_
.ConstructSpdyBodyFrame(1, false));
1862 scoped_ptr
<SpdyFrame
> chunk2(spdy_util_
.ConstructSpdyBodyFrame(1, false));
1863 scoped_ptr
<SpdyFrame
> chunk3(spdy_util_
.ConstructSpdyBodyFrame(1, true));
1864 MockWrite writes
[] = {
1865 CreateMockWrite(*req
),
1866 CreateMockWrite(*chunk1
),
1867 CreateMockWrite(*chunk2
),
1868 CreateMockWrite(*chunk3
),
1871 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyPostSynReply(NULL
, 0));
1872 MockRead reads
[] = {
1873 CreateMockRead(*resp
),
1874 CreateMockRead(*chunk1
),
1875 CreateMockRead(*chunk2
),
1876 CreateMockRead(*chunk3
),
1877 MockRead(ASYNC
, 0, 0) // EOF
1880 DelayedSocketData
data(4, reads
, arraysize(reads
),
1881 writes
, arraysize(writes
));
1882 NormalSpdyTransactionHelper
helper(CreateChunkedPostRequest(),
1884 BoundNetLog(), GetParam(), NULL
);
1886 upload_chunked_data_stream()->AppendData(kUploadData
, kUploadDataSize
, false);
1888 helper
.RunPreTestSetup();
1889 helper
.AddData(&data
);
1890 ASSERT_TRUE(helper
.StartDefaultTest());
1892 base::RunLoop().RunUntilIdle();
1893 upload_chunked_data_stream()->AppendData(kUploadData
, kUploadDataSize
, false);
1894 base::RunLoop().RunUntilIdle();
1895 upload_chunked_data_stream()->AppendData(kUploadData
, kUploadDataSize
, true);
1897 helper
.FinishDefaultTest();
1898 helper
.VerifyDataConsumed();
1900 std::string expected_response
;
1901 expected_response
+= kUploadData
;
1902 expected_response
+= kUploadData
;
1903 expected_response
+= kUploadData
;
1905 TransactionHelperResult out
= helper
.output();
1906 EXPECT_EQ(OK
, out
.rv
);
1907 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1908 EXPECT_EQ(expected_response
, out
.response_data
);
1911 // Test that a POST without any post data works.
1912 TEST_P(SpdyNetworkTransactionTest
, NullPost
) {
1913 BufferedSpdyFramer
framer(spdy_util_
.spdy_version(), false);
1914 // Setup the request
1915 HttpRequestInfo request
;
1916 request
.method
= "POST";
1917 request
.url
= GURL(GetDefaultUrl());
1918 // Create an empty UploadData.
1919 request
.upload_data_stream
= NULL
;
1921 // When request.upload_data_stream is NULL for post, content-length is
1922 // expected to be 0.
1923 scoped_ptr
<SpdyHeaderBlock
> req_block(
1924 spdy_util_
.ConstructPostHeaderBlock(GetDefaultUrl(), 0));
1925 scoped_ptr
<SpdyFrame
> req(
1926 spdy_util_
.ConstructSpdySyn(1, *req_block
, LOWEST
, false, true));
1928 MockWrite writes
[] = {
1929 CreateMockWrite(*req
),
1932 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyPostSynReply(NULL
, 0));
1933 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
1934 MockRead reads
[] = {
1935 CreateMockRead(*resp
),
1936 CreateMockRead(*body
),
1937 MockRead(ASYNC
, 0, 0) // EOF
1940 DelayedSocketData
data(1, reads
, arraysize(reads
),
1941 writes
, arraysize(writes
));
1943 NormalSpdyTransactionHelper
helper(request
, DEFAULT_PRIORITY
,
1944 BoundNetLog(), GetParam(), NULL
);
1945 helper
.RunToCompletion(&data
);
1946 TransactionHelperResult out
= helper
.output();
1947 EXPECT_EQ(OK
, out
.rv
);
1948 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1949 EXPECT_EQ("hello!", out
.response_data
);
1952 // Test that a simple POST works.
1953 TEST_P(SpdyNetworkTransactionTest
, EmptyPost
) {
1954 BufferedSpdyFramer
framer(spdy_util_
.spdy_version(), false);
1955 // Create an empty UploadDataStream.
1956 ScopedVector
<UploadElementReader
> element_readers
;
1957 ElementsUploadDataStream
stream(element_readers
.Pass(), 0);
1959 // Setup the request
1960 HttpRequestInfo request
;
1961 request
.method
= "POST";
1962 request
.url
= GURL(GetDefaultUrl());
1963 request
.upload_data_stream
= &stream
;
1965 const uint64 kContentLength
= 0;
1967 scoped_ptr
<SpdyHeaderBlock
> req_block(
1968 spdy_util_
.ConstructPostHeaderBlock(GetDefaultUrl(), kContentLength
));
1969 scoped_ptr
<SpdyFrame
> req(
1970 spdy_util_
.ConstructSpdySyn(1, *req_block
, LOWEST
, false, true));
1972 MockWrite writes
[] = {
1973 CreateMockWrite(*req
),
1976 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyPostSynReply(NULL
, 0));
1977 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
1978 MockRead reads
[] = {
1979 CreateMockRead(*resp
),
1980 CreateMockRead(*body
),
1981 MockRead(ASYNC
, 0, 0) // EOF
1984 DelayedSocketData
data(1, reads
, arraysize(reads
), writes
, arraysize(writes
));
1986 NormalSpdyTransactionHelper
helper(request
, DEFAULT_PRIORITY
,
1987 BoundNetLog(), GetParam(), NULL
);
1988 helper
.RunToCompletion(&data
);
1989 TransactionHelperResult out
= helper
.output();
1990 EXPECT_EQ(OK
, out
.rv
);
1991 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1992 EXPECT_EQ("hello!", out
.response_data
);
1995 // While we're doing a post, the server sends the reply before upload completes.
1996 TEST_P(SpdyNetworkTransactionTest
, ResponseBeforePostCompletes
) {
1997 scoped_ptr
<SpdyFrame
> req(spdy_util_
.ConstructChunkedSpdyPost(NULL
, 0));
1998 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
1999 MockWrite writes
[] = {
2000 CreateMockWrite(*req
, 0),
2001 CreateMockWrite(*body
, 3),
2003 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyPostSynReply(NULL
, 0));
2004 MockRead reads
[] = {
2005 CreateMockRead(*resp
, 1),
2006 CreateMockRead(*body
, 2),
2007 MockRead(ASYNC
, 0, 4) // EOF
2010 // Write the request headers, and read the complete response
2011 // while still waiting for chunked request data.
2012 DeterministicSocketData
data(reads
, arraysize(reads
),
2013 writes
, arraysize(writes
));
2014 NormalSpdyTransactionHelper
helper(CreateChunkedPostRequest(),
2016 BoundNetLog(), GetParam(), NULL
);
2017 helper
.SetDeterministic();
2018 helper
.RunPreTestSetup();
2019 helper
.AddDeterministicData(&data
);
2021 ASSERT_TRUE(helper
.StartDefaultTest());
2023 // Process the request headers, SYN_REPLY, and response body.
2024 // The request body is still in flight.
2027 const HttpResponseInfo
* response
= helper
.trans()->GetResponseInfo();
2028 EXPECT_EQ("HTTP/1.1 200 OK", response
->headers
->GetStatusLine());
2030 // Finish sending the request body.
2031 upload_chunked_data_stream()->AppendData(kUploadData
, kUploadDataSize
, true);
2034 std::string response_body
;
2035 EXPECT_EQ(OK
, ReadTransaction(helper
.trans(), &response_body
));
2036 EXPECT_EQ(kUploadData
, response_body
);
2037 helper
.VerifyDataConsumed();
2040 // The client upon cancellation tries to send a RST_STREAM frame. The mock
2041 // socket causes the TCP write to return zero. This test checks that the client
2042 // tries to queue up the RST_STREAM frame again.
2043 TEST_P(SpdyNetworkTransactionTest
, SocketWriteReturnsZero
) {
2044 scoped_ptr
<SpdyFrame
> req(
2045 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2046 scoped_ptr
<SpdyFrame
> rst(
2047 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_CANCEL
));
2048 MockWrite writes
[] = {
2049 CreateMockWrite(*req
.get(), 0, SYNCHRONOUS
),
2050 MockWrite(SYNCHRONOUS
, 0, 0, 2),
2051 CreateMockWrite(*rst
.get(), 3, SYNCHRONOUS
),
2054 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2055 MockRead reads
[] = {
2056 CreateMockRead(*resp
.get(), 1, ASYNC
),
2057 MockRead(ASYNC
, 0, 0, 4) // EOF
2060 DeterministicSocketData
data(reads
, arraysize(reads
),
2061 writes
, arraysize(writes
));
2062 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
2063 BoundNetLog(), GetParam(), NULL
);
2064 helper
.SetDeterministic();
2065 helper
.RunPreTestSetup();
2066 helper
.AddDeterministicData(&data
);
2067 HttpNetworkTransaction
* trans
= helper
.trans();
2069 TestCompletionCallback callback
;
2070 int rv
= trans
->Start(
2071 &CreateGetRequest(), callback
.callback(), BoundNetLog());
2072 EXPECT_EQ(ERR_IO_PENDING
, rv
);
2076 helper
.ResetTrans();
2080 helper
.VerifyDataConsumed();
2083 // Test that the transaction doesn't crash when we don't have a reply.
2084 TEST_P(SpdyNetworkTransactionTest
, ResponseWithoutSynReply
) {
2085 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
2086 MockRead reads
[] = {
2087 CreateMockRead(*body
),
2088 MockRead(ASYNC
, 0, 0) // EOF
2091 DelayedSocketData
data(1, reads
, arraysize(reads
), NULL
, 0);
2092 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
2093 BoundNetLog(), GetParam(), NULL
);
2094 helper
.RunToCompletion(&data
);
2095 TransactionHelperResult out
= helper
.output();
2096 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR
, out
.rv
);
2099 // Test that the transaction doesn't crash when we get two replies on the same
2100 // stream ID. See http://crbug.com/45639.
2101 TEST_P(SpdyNetworkTransactionTest
, ResponseWithTwoSynReplies
) {
2102 scoped_ptr
<SpdyFrame
> req(
2103 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2104 scoped_ptr
<SpdyFrame
> rst(
2105 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR
));
2106 MockWrite writes
[] = {
2107 CreateMockWrite(*req
),
2108 CreateMockWrite(*rst
),
2111 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2112 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
2113 MockRead reads
[] = {
2114 CreateMockRead(*resp
),
2115 CreateMockRead(*resp
),
2116 CreateMockRead(*body
),
2117 MockRead(ASYNC
, 0, 0) // EOF
2120 DelayedSocketData
data(1, reads
, arraysize(reads
),
2121 writes
, arraysize(writes
));
2123 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
2124 BoundNetLog(), GetParam(), NULL
);
2125 helper
.RunPreTestSetup();
2126 helper
.AddData(&data
);
2128 HttpNetworkTransaction
* trans
= helper
.trans();
2130 TestCompletionCallback callback
;
2131 int rv
= trans
->Start(&helper
.request(), callback
.callback(), BoundNetLog());
2132 EXPECT_EQ(ERR_IO_PENDING
, rv
);
2133 rv
= callback
.WaitForResult();
2136 const HttpResponseInfo
* response
= trans
->GetResponseInfo();
2137 ASSERT_TRUE(response
!= NULL
);
2138 EXPECT_TRUE(response
->headers
.get() != NULL
);
2139 EXPECT_TRUE(response
->was_fetched_via_spdy
);
2140 std::string response_data
;
2141 rv
= ReadTransaction(trans
, &response_data
);
2142 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR
, rv
);
2144 helper
.VerifyDataConsumed();
2147 TEST_P(SpdyNetworkTransactionTest
, ResetReplyWithTransferEncoding
) {
2148 // Construct the request.
2149 scoped_ptr
<SpdyFrame
> req(
2150 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2151 scoped_ptr
<SpdyFrame
> rst(
2152 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR
));
2153 MockWrite writes
[] = {
2154 CreateMockWrite(*req
),
2155 CreateMockWrite(*rst
),
2158 const char* const headers
[] = {
2159 "transfer-encoding", "chunked"
2161 scoped_ptr
<SpdyFrame
> resp(
2162 spdy_util_
.ConstructSpdyGetSynReply(headers
, 1, 1));
2163 scoped_ptr
<SpdyFrame
> body(
2164 spdy_util_
.ConstructSpdyBodyFrame(1, true));
2165 MockRead reads
[] = {
2166 CreateMockRead(*resp
),
2167 CreateMockRead(*body
),
2168 MockRead(ASYNC
, 0, 0) // EOF
2171 DelayedSocketData
data(1, reads
, arraysize(reads
),
2172 writes
, arraysize(writes
));
2173 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
2174 BoundNetLog(), GetParam(), NULL
);
2175 helper
.RunToCompletion(&data
);
2176 TransactionHelperResult out
= helper
.output();
2177 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR
, out
.rv
);
2179 helper
.session()->spdy_session_pool()->CloseAllSessions();
2180 helper
.VerifyDataConsumed();
2183 TEST_P(SpdyNetworkTransactionTest
, ResetPushWithTransferEncoding
) {
2184 // Construct the request.
2185 scoped_ptr
<SpdyFrame
> req(
2186 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2187 scoped_ptr
<SpdyFrame
> rst(
2188 spdy_util_
.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR
));
2189 MockWrite writes
[] = {
2190 CreateMockWrite(*req
),
2191 CreateMockWrite(*rst
),
2194 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2195 const char* const headers
[] = {
2196 "transfer-encoding", "chunked"
2198 scoped_ptr
<SpdyFrame
> push(
2199 spdy_util_
.ConstructSpdyPush(headers
, arraysize(headers
) / 2, 2, 1,
2200 GetDefaultUrlWithPath("/1").c_str()));
2201 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
2202 MockRead reads
[] = {
2203 CreateMockRead(*resp
),
2204 CreateMockRead(*push
),
2205 CreateMockRead(*body
),
2206 MockRead(ASYNC
, 0, 0) // EOF
2209 DelayedSocketData
data(1, reads
, arraysize(reads
),
2210 writes
, arraysize(writes
));
2211 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
2212 BoundNetLog(), GetParam(), NULL
);
2213 helper
.RunToCompletion(&data
);
2214 TransactionHelperResult out
= helper
.output();
2215 EXPECT_EQ(OK
, out
.rv
);
2216 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
2217 EXPECT_EQ("hello!", out
.response_data
);
2219 helper
.session()->spdy_session_pool()->CloseAllSessions();
2220 helper
.VerifyDataConsumed();
2223 TEST_P(SpdyNetworkTransactionTest
, CancelledTransaction
) {
2224 // Construct the request.
2225 scoped_ptr
<SpdyFrame
> req(
2226 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2227 MockWrite writes
[] = {
2228 CreateMockWrite(*req
),
2231 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2232 MockRead reads
[] = {
2233 CreateMockRead(*resp
),
2234 // This following read isn't used by the test, except during the
2235 // RunUntilIdle() call at the end since the SpdySession survives the
2236 // HttpNetworkTransaction and still tries to continue Read()'ing. Any
2237 // MockRead will do here.
2238 MockRead(ASYNC
, 0, 0) // EOF
2241 StaticSocketDataProvider
data(reads
, arraysize(reads
),
2242 writes
, arraysize(writes
));
2244 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
2245 BoundNetLog(), GetParam(), NULL
);
2246 helper
.RunPreTestSetup();
2247 helper
.AddData(&data
);
2248 HttpNetworkTransaction
* trans
= helper
.trans();
2250 TestCompletionCallback callback
;
2251 int rv
= trans
->Start(
2252 &CreateGetRequest(), callback
.callback(), BoundNetLog());
2253 EXPECT_EQ(ERR_IO_PENDING
, rv
);
2254 helper
.ResetTrans(); // Cancel the transaction.
2256 // Flush the MessageLoop while the SpdySessionDependencies (in particular, the
2257 // MockClientSocketFactory) are still alive.
2258 base::RunLoop().RunUntilIdle();
2259 helper
.VerifyDataNotConsumed();
2262 // Verify that the client sends a Rst Frame upon cancelling the stream.
2263 TEST_P(SpdyNetworkTransactionTest
, CancelledTransactionSendRst
) {
2264 scoped_ptr
<SpdyFrame
> req(
2265 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2266 scoped_ptr
<SpdyFrame
> rst(
2267 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_CANCEL
));
2268 MockWrite writes
[] = {
2269 CreateMockWrite(*req
, 0, SYNCHRONOUS
),
2270 CreateMockWrite(*rst
, 2, SYNCHRONOUS
),
2273 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2274 MockRead reads
[] = {
2275 CreateMockRead(*resp
, 1, ASYNC
),
2276 MockRead(ASYNC
, 0, 0, 3) // EOF
2279 DeterministicSocketData
data(reads
, arraysize(reads
),
2280 writes
, arraysize(writes
));
2282 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
2285 helper
.SetDeterministic();
2286 helper
.RunPreTestSetup();
2287 helper
.AddDeterministicData(&data
);
2288 HttpNetworkTransaction
* trans
= helper
.trans();
2290 TestCompletionCallback callback
;
2292 int rv
= trans
->Start(
2293 &CreateGetRequest(), callback
.callback(), BoundNetLog());
2294 EXPECT_EQ(ERR_IO_PENDING
, rv
);
2298 helper
.ResetTrans();
2302 helper
.VerifyDataConsumed();
2305 // Verify that the client can correctly deal with the user callback attempting
2306 // to start another transaction on a session that is closing down. See
2307 // http://crbug.com/47455
2308 TEST_P(SpdyNetworkTransactionTest
, StartTransactionOnReadCallback
) {
2309 scoped_ptr
<SpdyFrame
> req(
2310 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2311 MockWrite writes
[] = { CreateMockWrite(*req
) };
2312 MockWrite writes2
[] = { CreateMockWrite(*req
) };
2314 // The indicated length of this frame is longer than its actual length. When
2315 // the session receives an empty frame after this one, it shuts down the
2316 // session, and calls the read callback with the incomplete data.
2317 const uint8 kGetBodyFrame2
[] = {
2318 0x00, 0x00, 0x00, 0x01,
2319 0x01, 0x00, 0x00, 0x07,
2320 'h', 'e', 'l', 'l', 'o', '!',
2323 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2324 MockRead reads
[] = {
2325 CreateMockRead(*resp
, 2),
2326 MockRead(ASYNC
, ERR_IO_PENDING
, 3), // Force a pause
2327 MockRead(ASYNC
, reinterpret_cast<const char*>(kGetBodyFrame2
),
2328 arraysize(kGetBodyFrame2
), 4),
2329 MockRead(ASYNC
, ERR_IO_PENDING
, 5), // Force a pause
2330 MockRead(ASYNC
, 0, 0, 6), // EOF
2332 MockRead reads2
[] = {
2333 CreateMockRead(*resp
, 2),
2334 MockRead(ASYNC
, 0, 0, 3), // EOF
2337 OrderedSocketData
data(reads
, arraysize(reads
),
2338 writes
, arraysize(writes
));
2339 DelayedSocketData
data2(1, reads2
, arraysize(reads2
),
2340 writes2
, arraysize(writes2
));
2342 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
2343 BoundNetLog(), GetParam(), NULL
);
2344 helper
.RunPreTestSetup();
2345 helper
.AddData(&data
);
2346 helper
.AddData(&data2
);
2347 HttpNetworkTransaction
* trans
= helper
.trans();
2349 // Start the transaction with basic parameters.
2350 TestCompletionCallback callback
;
2351 int rv
= trans
->Start(&helper
.request(), callback
.callback(), BoundNetLog());
2352 EXPECT_EQ(ERR_IO_PENDING
, rv
);
2353 rv
= callback
.WaitForResult();
2355 const int kSize
= 3000;
2356 scoped_refptr
<IOBuffer
> buf(new IOBuffer(kSize
));
2359 base::Bind(&SpdyNetworkTransactionTest::StartTransactionCallback
,
2360 helper
.session(), GURL(GetDefaultUrl())));
2361 // This forces an err_IO_pending, which sets the callback.
2362 data
.CompleteRead();
2363 // This finishes the read.
2364 data
.CompleteRead();
2365 helper
.VerifyDataConsumed();
2368 // Verify that the client can correctly deal with the user callback deleting the
2369 // transaction. Failures will usually be valgrind errors. See
2370 // http://crbug.com/46925
2371 TEST_P(SpdyNetworkTransactionTest
, DeleteSessionOnReadCallback
) {
2372 scoped_ptr
<SpdyFrame
> req(
2373 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2374 MockWrite writes
[] = { CreateMockWrite(*req
) };
2376 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2377 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
2378 MockRead reads
[] = {
2379 CreateMockRead(*resp
.get(), 2),
2380 MockRead(ASYNC
, ERR_IO_PENDING
, 3), // Force a pause
2381 CreateMockRead(*body
.get(), 4),
2382 MockRead(ASYNC
, 0, 0, 5), // EOF
2385 OrderedSocketData
data(reads
, arraysize(reads
),
2386 writes
, arraysize(writes
));
2388 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
2389 BoundNetLog(), GetParam(), NULL
);
2390 helper
.RunPreTestSetup();
2391 helper
.AddData(&data
);
2392 HttpNetworkTransaction
* trans
= helper
.trans();
2394 // Start the transaction with basic parameters.
2395 TestCompletionCallback callback
;
2396 int rv
= trans
->Start(&helper
.request(), callback
.callback(), BoundNetLog());
2397 EXPECT_EQ(ERR_IO_PENDING
, rv
);
2398 rv
= callback
.WaitForResult();
2400 // Setup a user callback which will delete the session, and clear out the
2401 // memory holding the stream object. Note that the callback deletes trans.
2402 const int kSize
= 3000;
2403 scoped_refptr
<IOBuffer
> buf(new IOBuffer(kSize
));
2407 base::Bind(&SpdyNetworkTransactionTest::DeleteSessionCallback
,
2408 base::Unretained(&helper
)));
2409 ASSERT_EQ(ERR_IO_PENDING
, rv
);
2410 data
.CompleteRead();
2412 // Finish running rest of tasks.
2413 base::RunLoop().RunUntilIdle();
2414 helper
.VerifyDataConsumed();
2417 // Send a spdy request to www.google.com that gets redirected to www.foo.com.
2418 TEST_P(SpdyNetworkTransactionTest
, DISABLED_RedirectGetRequest
) {
2419 scoped_ptr
<SpdyHeaderBlock
> headers(
2420 spdy_util_
.ConstructGetHeaderBlock(GetDefaultUrl()));
2421 (*headers
)["user-agent"] = "";
2422 (*headers
)["accept-encoding"] = "gzip, deflate";
2423 scoped_ptr
<SpdyHeaderBlock
> headers2(
2424 spdy_util_
.ConstructGetHeaderBlock("http://www.foo.com/index.php"));
2425 (*headers2
)["user-agent"] = "";
2426 (*headers2
)["accept-encoding"] = "gzip, deflate";
2428 // Setup writes/reads to www.google.com
2429 scoped_ptr
<SpdyFrame
> req(
2430 spdy_util_
.ConstructSpdySyn(1, *headers
, LOWEST
, false, true));
2431 scoped_ptr
<SpdyFrame
> req2(
2432 spdy_util_
.ConstructSpdySyn(1, *headers2
, LOWEST
, false, true));
2433 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReplyRedirect(1));
2434 MockWrite writes
[] = {
2435 CreateMockWrite(*req
, 1),
2437 MockRead reads
[] = {
2438 CreateMockRead(*resp
, 2),
2439 MockRead(ASYNC
, 0, 0, 3) // EOF
2442 // Setup writes/reads to www.foo.com
2443 scoped_ptr
<SpdyFrame
> resp2(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2444 scoped_ptr
<SpdyFrame
> body2(spdy_util_
.ConstructSpdyBodyFrame(1, true));
2445 MockWrite writes2
[] = {
2446 CreateMockWrite(*req2
, 1),
2448 MockRead reads2
[] = {
2449 CreateMockRead(*resp2
, 2),
2450 CreateMockRead(*body2
, 3),
2451 MockRead(ASYNC
, 0, 0, 4) // EOF
2453 OrderedSocketData
data(reads
, arraysize(reads
),
2454 writes
, arraysize(writes
));
2455 OrderedSocketData
data2(reads2
, arraysize(reads2
),
2456 writes2
, arraysize(writes2
));
2458 // TODO(erikchen): Make test support SPDYSSL, SPDYNPN
2461 SpdyURLRequestContext
spdy_url_request_context(GetParam().protocol
);
2462 scoped_ptr
<URLRequest
> r(spdy_url_request_context
.CreateRequest(
2463 GURL(GetDefaultUrl()), DEFAULT_PRIORITY
, &d
));
2464 spdy_url_request_context
.socket_factory().
2465 AddSocketDataProvider(&data
);
2466 spdy_url_request_context
.socket_factory().
2467 AddSocketDataProvider(&data2
);
2469 d
.set_quit_on_redirect(true);
2471 base::RunLoop().Run();
2473 EXPECT_EQ(1, d
.received_redirect_count());
2475 r
->FollowDeferredRedirect();
2476 base::RunLoop().Run();
2477 EXPECT_EQ(1, d
.response_started_count());
2478 EXPECT_FALSE(d
.received_data_before_response());
2479 EXPECT_EQ(URLRequestStatus::SUCCESS
, r
->status().status());
2480 std::string
contents("hello!");
2481 EXPECT_EQ(contents
, d
.data_received());
2483 EXPECT_TRUE(data
.at_read_eof());
2484 EXPECT_TRUE(data
.at_write_eof());
2485 EXPECT_TRUE(data2
.at_read_eof());
2486 EXPECT_TRUE(data2
.at_write_eof());
2489 // Send a spdy request to www.google.com. Get a pushed stream that redirects to
2491 TEST_P(SpdyNetworkTransactionTest
, DISABLED_RedirectServerPush
) {
2492 scoped_ptr
<SpdyHeaderBlock
> headers(
2493 spdy_util_
.ConstructGetHeaderBlock(GetDefaultUrl()));
2494 (*headers
)["user-agent"] = "";
2495 (*headers
)["accept-encoding"] = "gzip, deflate";
2497 // Setup writes/reads to www.google.com
2498 scoped_ptr
<SpdyFrame
> req(
2499 spdy_util_
.ConstructSpdySyn(1, *headers
, LOWEST
, false, true));
2500 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2501 scoped_ptr
<SpdyFrame
> rep(spdy_util_
.ConstructSpdyPush(
2502 NULL
, 0, 2, 1, GetDefaultUrlWithPath("/foo.dat").c_str(),
2503 "301 Moved Permanently", "http://www.foo.com/index.php"));
2504 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
2505 scoped_ptr
<SpdyFrame
> rst(
2506 spdy_util_
.ConstructSpdyRstStream(2, RST_STREAM_CANCEL
));
2507 MockWrite writes
[] = {
2508 CreateMockWrite(*req
, 1),
2509 CreateMockWrite(*rst
, 6),
2511 MockRead reads
[] = {
2512 CreateMockRead(*resp
, 2),
2513 CreateMockRead(*rep
, 3),
2514 CreateMockRead(*body
, 4),
2515 MockRead(ASYNC
, ERR_IO_PENDING
, 5), // Force a pause
2516 MockRead(ASYNC
, 0, 0, 7) // EOF
2519 // Setup writes/reads to www.foo.com
2520 scoped_ptr
<SpdyHeaderBlock
> headers2(
2521 spdy_util_
.ConstructGetHeaderBlock("http://www.foo.com/index.php"));
2522 (*headers2
)["user-agent"] = "";
2523 (*headers2
)["accept-encoding"] = "gzip, deflate";
2524 scoped_ptr
<SpdyFrame
> req2(
2525 spdy_util_
.ConstructSpdySyn(1, *headers2
, LOWEST
, false, true));
2526 scoped_ptr
<SpdyFrame
> resp2(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2527 scoped_ptr
<SpdyFrame
> body2(spdy_util_
.ConstructSpdyBodyFrame(1, true));
2528 MockWrite writes2
[] = {
2529 CreateMockWrite(*req2
, 1),
2531 MockRead reads2
[] = {
2532 CreateMockRead(*resp2
, 2),
2533 CreateMockRead(*body2
, 3),
2534 MockRead(ASYNC
, 0, 0, 5) // EOF
2536 OrderedSocketData
data(reads
, arraysize(reads
),
2537 writes
, arraysize(writes
));
2538 OrderedSocketData
data2(reads2
, arraysize(reads2
),
2539 writes2
, arraysize(writes2
));
2541 // TODO(erikchen): Make test support SPDYSSL, SPDYNPN
2544 SpdyURLRequestContext
spdy_url_request_context(GetParam().protocol
);
2546 scoped_ptr
<URLRequest
> r(spdy_url_request_context
.CreateRequest(
2547 GURL(GetDefaultUrl()), DEFAULT_PRIORITY
, &d
));
2548 spdy_url_request_context
.socket_factory().
2549 AddSocketDataProvider(&data
);
2552 base::RunLoop().Run();
2554 EXPECT_EQ(0, d
.received_redirect_count());
2555 std::string
contents("hello!");
2556 EXPECT_EQ(contents
, d
.data_received());
2558 scoped_ptr
<URLRequest
> r2(spdy_url_request_context
.CreateRequest(
2559 GURL(GetDefaultUrlWithPath("/foo.dat")), DEFAULT_PRIORITY
, &d2
));
2560 spdy_url_request_context
.socket_factory().
2561 AddSocketDataProvider(&data2
);
2563 d2
.set_quit_on_redirect(true);
2565 base::RunLoop().Run();
2566 EXPECT_EQ(1, d2
.received_redirect_count());
2568 r2
->FollowDeferredRedirect();
2569 base::RunLoop().Run();
2570 EXPECT_EQ(1, d2
.response_started_count());
2571 EXPECT_FALSE(d2
.received_data_before_response());
2572 EXPECT_EQ(URLRequestStatus::SUCCESS
, r2
->status().status());
2573 std::string
contents2("hello!");
2574 EXPECT_EQ(contents2
, d2
.data_received());
2576 data
.CompleteRead();
2577 data2
.CompleteRead();
2578 EXPECT_TRUE(data
.at_read_eof());
2579 EXPECT_TRUE(data
.at_write_eof());
2580 EXPECT_TRUE(data2
.at_read_eof());
2581 EXPECT_TRUE(data2
.at_write_eof());
2584 TEST_P(SpdyNetworkTransactionTest
, ServerPushSingleDataFrame
) {
2585 scoped_ptr
<SpdyFrame
> stream1_syn(
2586 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2587 scoped_ptr
<SpdyFrame
> stream1_body(
2588 spdy_util_
.ConstructSpdyBodyFrame(1, true));
2589 MockWrite writes
[] = {
2590 CreateMockWrite(*stream1_syn
, 1),
2593 scoped_ptr
<SpdyFrame
>
2594 stream1_reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2595 scoped_ptr
<SpdyFrame
> stream2_syn(spdy_util_
.ConstructSpdyPush(
2596 NULL
, 0, 2, 1, GetDefaultUrlWithPath("/foo.dat").c_str()));
2597 const char kPushedData
[] = "pushed";
2598 scoped_ptr
<SpdyFrame
> stream2_body(
2599 spdy_util_
.ConstructSpdyBodyFrame(
2600 2, kPushedData
, strlen(kPushedData
), true));
2601 MockRead reads
[] = {
2602 CreateMockRead(*stream1_reply
, 2),
2603 CreateMockRead(*stream2_syn
, 3),
2604 CreateMockRead(*stream1_body
, 4, SYNCHRONOUS
),
2605 CreateMockRead(*stream2_body
, 5),
2606 MockRead(ASYNC
, ERR_IO_PENDING
, 6), // Force a pause
2609 HttpResponseInfo response
;
2610 HttpResponseInfo response2
;
2611 std::string
expected_push_result("pushed");
2612 OrderedSocketData
data(reads
, arraysize(reads
),
2613 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
, ServerPushBeforeSynReply
) {
2629 scoped_ptr
<SpdyFrame
> stream1_syn(
2630 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2631 scoped_ptr
<SpdyFrame
> stream1_body(
2632 spdy_util_
.ConstructSpdyBodyFrame(1, true));
2633 MockWrite writes
[] = {
2634 CreateMockWrite(*stream1_syn
, 1),
2637 scoped_ptr
<SpdyFrame
>
2638 stream1_reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2639 scoped_ptr
<SpdyFrame
> stream2_syn(spdy_util_
.ConstructSpdyPush(
2640 NULL
, 0, 2, 1, GetDefaultUrlWithPath("/foo.dat").c_str()));
2641 const char kPushedData
[] = "pushed";
2642 scoped_ptr
<SpdyFrame
> stream2_body(
2643 spdy_util_
.ConstructSpdyBodyFrame(
2644 2, kPushedData
, strlen(kPushedData
), true));
2645 MockRead reads
[] = {
2646 CreateMockRead(*stream2_syn
, 2),
2647 CreateMockRead(*stream1_reply
, 3),
2648 CreateMockRead(*stream1_body
, 4, SYNCHRONOUS
),
2649 CreateMockRead(*stream2_body
, 5),
2650 MockRead(ASYNC
, ERR_IO_PENDING
, 6), // Force a pause
2653 HttpResponseInfo response
;
2654 HttpResponseInfo response2
;
2655 std::string
expected_push_result("pushed");
2656 OrderedSocketData
data(reads
, arraysize(reads
),
2657 writes
, arraysize(writes
));
2658 RunServerPushTest(&data
,
2661 expected_push_result
);
2663 // Verify the SYN_REPLY.
2664 EXPECT_TRUE(response
.headers
.get() != NULL
);
2665 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
2667 // Verify the pushed stream.
2668 EXPECT_TRUE(response2
.headers
.get() != NULL
);
2669 EXPECT_EQ("HTTP/1.1 200 OK", response2
.headers
->GetStatusLine());
2672 TEST_P(SpdyNetworkTransactionTest
, ServerPushSingleDataFrame2
) {
2673 scoped_ptr
<SpdyFrame
> stream1_syn(
2674 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2675 MockWrite writes
[] = { CreateMockWrite(*stream1_syn
, 1), };
2677 scoped_ptr
<SpdyFrame
>
2678 stream1_reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2679 scoped_ptr
<SpdyFrame
> stream2_syn(spdy_util_
.ConstructSpdyPush(
2680 NULL
, 0, 2, 1, GetDefaultUrlWithPath("/foo.dat").c_str()));
2681 const char kPushedData
[] = "pushed";
2682 scoped_ptr
<SpdyFrame
> stream2_body(
2683 spdy_util_
.ConstructSpdyBodyFrame(
2684 2, kPushedData
, strlen(kPushedData
), true));
2685 scoped_ptr
<SpdyFrame
>
2686 stream1_body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
2687 MockRead reads
[] = {
2688 CreateMockRead(*stream1_reply
, 2),
2689 CreateMockRead(*stream2_syn
, 3),
2690 CreateMockRead(*stream2_body
, 4),
2691 CreateMockRead(*stream1_body
, 5, SYNCHRONOUS
),
2692 MockRead(ASYNC
, ERR_IO_PENDING
, 6), // Force a pause
2695 HttpResponseInfo response
;
2696 HttpResponseInfo response2
;
2697 std::string
expected_push_result("pushed");
2698 OrderedSocketData
data(reads
, arraysize(reads
),
2699 writes
, arraysize(writes
));
2700 RunServerPushTest(&data
,
2703 expected_push_result
);
2705 // Verify the SYN_REPLY.
2706 EXPECT_TRUE(response
.headers
.get() != NULL
);
2707 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
2709 // Verify the pushed stream.
2710 EXPECT_TRUE(response2
.headers
.get() != NULL
);
2711 EXPECT_EQ("HTTP/1.1 200 OK", response2
.headers
->GetStatusLine());
2714 TEST_P(SpdyNetworkTransactionTest
, ServerPushServerAborted
) {
2715 scoped_ptr
<SpdyFrame
> stream1_syn(
2716 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2717 scoped_ptr
<SpdyFrame
> stream1_body(
2718 spdy_util_
.ConstructSpdyBodyFrame(1, true));
2719 MockWrite writes
[] = {
2720 CreateMockWrite(*stream1_syn
, 1),
2723 scoped_ptr
<SpdyFrame
>
2724 stream1_reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2725 scoped_ptr
<SpdyFrame
> stream2_syn(spdy_util_
.ConstructSpdyPush(
2726 NULL
, 0, 2, 1, GetDefaultUrlWithPath("/foo.dat").c_str()));
2727 scoped_ptr
<SpdyFrame
> stream2_rst(
2728 spdy_util_
.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR
));
2729 MockRead reads
[] = {
2730 CreateMockRead(*stream1_reply
, 2),
2731 CreateMockRead(*stream2_syn
, 3),
2732 CreateMockRead(*stream2_rst
, 4),
2733 CreateMockRead(*stream1_body
, 5, SYNCHRONOUS
),
2734 MockRead(ASYNC
, ERR_IO_PENDING
, 6), // Force a pause
2737 OrderedSocketData
data(reads
, arraysize(reads
),
2738 writes
, arraysize(writes
));
2739 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
2740 BoundNetLog(), GetParam(), NULL
);
2742 helper
.RunPreTestSetup();
2743 helper
.AddData(&data
);
2745 HttpNetworkTransaction
* trans
= helper
.trans();
2747 // Start the transaction with basic parameters.
2748 TestCompletionCallback callback
;
2749 int rv
= trans
->Start(
2750 &CreateGetRequest(), callback
.callback(), BoundNetLog());
2751 EXPECT_EQ(ERR_IO_PENDING
, rv
);
2752 rv
= callback
.WaitForResult();
2755 // Verify that we consumed all test data.
2756 EXPECT_TRUE(data
.at_read_eof()) << "Read count: "
2757 << data
.read_count()
2759 << data
.read_index();
2760 EXPECT_TRUE(data
.at_write_eof()) << "Write count: "
2761 << data
.write_count()
2763 << data
.write_index();
2765 // Verify the SYN_REPLY.
2766 HttpResponseInfo response
= *trans
->GetResponseInfo();
2767 EXPECT_TRUE(response
.headers
.get() != NULL
);
2768 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
2771 // Verify that we don't leak streams and that we properly send a reset
2772 // if the server pushes the same stream twice.
2773 TEST_P(SpdyNetworkTransactionTest
, ServerPushDuplicate
) {
2774 scoped_ptr
<SpdyFrame
> stream1_syn(
2775 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2776 scoped_ptr
<SpdyFrame
> stream1_body(
2777 spdy_util_
.ConstructSpdyBodyFrame(1, true));
2778 scoped_ptr
<SpdyFrame
> stream3_rst(
2779 spdy_util_
.ConstructSpdyRstStream(4, RST_STREAM_PROTOCOL_ERROR
));
2780 MockWrite writes
[] = {
2781 CreateMockWrite(*stream1_syn
, 1),
2782 CreateMockWrite(*stream3_rst
, 5),
2785 scoped_ptr
<SpdyFrame
>
2786 stream1_reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2787 scoped_ptr
<SpdyFrame
> stream2_syn(spdy_util_
.ConstructSpdyPush(
2788 NULL
, 0, 2, 1, GetDefaultUrlWithPath("/foo.dat").c_str()));
2789 const char kPushedData
[] = "pushed";
2790 scoped_ptr
<SpdyFrame
> stream2_body(
2791 spdy_util_
.ConstructSpdyBodyFrame(
2792 2, kPushedData
, strlen(kPushedData
), true));
2793 scoped_ptr
<SpdyFrame
> stream3_syn(spdy_util_
.ConstructSpdyPush(
2794 NULL
, 0, 4, 1, GetDefaultUrlWithPath("/foo.dat").c_str()));
2795 MockRead reads
[] = {
2796 CreateMockRead(*stream1_reply
, 2),
2797 CreateMockRead(*stream2_syn
, 3),
2798 CreateMockRead(*stream3_syn
, 4),
2799 CreateMockRead(*stream1_body
, 6, SYNCHRONOUS
),
2800 CreateMockRead(*stream2_body
, 7),
2801 MockRead(ASYNC
, ERR_IO_PENDING
, 8), // Force a pause
2804 HttpResponseInfo response
;
2805 HttpResponseInfo response2
;
2806 std::string
expected_push_result("pushed");
2807 OrderedSocketData
data(reads
, arraysize(reads
),
2808 writes
, arraysize(writes
));
2809 RunServerPushTest(&data
,
2812 expected_push_result
);
2814 // Verify the SYN_REPLY.
2815 EXPECT_TRUE(response
.headers
.get() != NULL
);
2816 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
2818 // Verify the pushed stream.
2819 EXPECT_TRUE(response2
.headers
.get() != NULL
);
2820 EXPECT_EQ("HTTP/1.1 200 OK", response2
.headers
->GetStatusLine());
2823 TEST_P(SpdyNetworkTransactionTest
, ServerPushMultipleDataFrame
) {
2824 scoped_ptr
<SpdyFrame
> stream1_syn(
2825 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2826 scoped_ptr
<SpdyFrame
> stream1_body(
2827 spdy_util_
.ConstructSpdyBodyFrame(1, true));
2828 MockWrite writes
[] = {
2829 CreateMockWrite(*stream1_syn
, 1),
2832 scoped_ptr
<SpdyFrame
>
2833 stream1_reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2834 scoped_ptr
<SpdyFrame
> stream2_syn(spdy_util_
.ConstructSpdyPush(
2835 NULL
, 0, 2, 1, GetDefaultUrlWithPath("/foo.dat").c_str()));
2836 static const char kPushedData
[] = "pushed my darling hello my baby";
2837 scoped_ptr
<SpdyFrame
> stream2_body_base(
2838 spdy_util_
.ConstructSpdyBodyFrame(
2839 2, kPushedData
, strlen(kPushedData
), true));
2840 const size_t kChunkSize
= strlen(kPushedData
) / 4;
2841 scoped_ptr
<SpdyFrame
> stream2_body1(
2842 new SpdyFrame(stream2_body_base
->data(), kChunkSize
, false));
2843 scoped_ptr
<SpdyFrame
> stream2_body2(
2844 new SpdyFrame(stream2_body_base
->data() + kChunkSize
, kChunkSize
, false));
2845 scoped_ptr
<SpdyFrame
> stream2_body3(
2846 new SpdyFrame(stream2_body_base
->data() + 2 * kChunkSize
,
2847 kChunkSize
, false));
2848 scoped_ptr
<SpdyFrame
> stream2_body4(
2849 new SpdyFrame(stream2_body_base
->data() + 3 * kChunkSize
,
2850 stream2_body_base
->size() - 3 * kChunkSize
, false));
2851 MockRead reads
[] = {
2852 CreateMockRead(*stream1_reply
, 2),
2853 CreateMockRead(*stream2_syn
, 3),
2854 CreateMockRead(*stream2_body1
, 4),
2855 CreateMockRead(*stream2_body2
, 5),
2856 CreateMockRead(*stream2_body3
, 6),
2857 CreateMockRead(*stream2_body4
, 7),
2858 CreateMockRead(*stream1_body
, 8, SYNCHRONOUS
),
2859 MockRead(ASYNC
, ERR_IO_PENDING
, 9), // Force a pause
2862 HttpResponseInfo response
;
2863 HttpResponseInfo response2
;
2864 std::string
expected_push_result("pushed my darling hello my baby");
2865 OrderedSocketData
data(reads
, arraysize(reads
),
2866 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
, ServerPushMultipleDataFrameInterrupted
) {
2879 scoped_ptr
<SpdyFrame
> stream1_syn(
2880 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2881 scoped_ptr
<SpdyFrame
> stream1_body(
2882 spdy_util_
.ConstructSpdyBodyFrame(1, true));
2883 MockWrite writes
[] = {
2884 CreateMockWrite(*stream1_syn
, 1),
2887 scoped_ptr
<SpdyFrame
>
2888 stream1_reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2889 scoped_ptr
<SpdyFrame
> stream2_syn(spdy_util_
.ConstructSpdyPush(
2890 NULL
, 0, 2, 1, GetDefaultUrlWithPath("/foo.dat").c_str()));
2891 static const char kPushedData
[] = "pushed my darling hello my baby";
2892 scoped_ptr
<SpdyFrame
> stream2_body_base(
2893 spdy_util_
.ConstructSpdyBodyFrame(
2894 2, kPushedData
, strlen(kPushedData
), true));
2895 const size_t kChunkSize
= strlen(kPushedData
) / 4;
2896 scoped_ptr
<SpdyFrame
> stream2_body1(
2897 new SpdyFrame(stream2_body_base
->data(), kChunkSize
, false));
2898 scoped_ptr
<SpdyFrame
> stream2_body2(
2899 new SpdyFrame(stream2_body_base
->data() + kChunkSize
, kChunkSize
, false));
2900 scoped_ptr
<SpdyFrame
> stream2_body3(
2901 new SpdyFrame(stream2_body_base
->data() + 2 * kChunkSize
,
2902 kChunkSize
, false));
2903 scoped_ptr
<SpdyFrame
> stream2_body4(
2904 new SpdyFrame(stream2_body_base
->data() + 3 * kChunkSize
,
2905 stream2_body_base
->size() - 3 * kChunkSize
, false));
2906 MockRead reads
[] = {
2907 CreateMockRead(*stream1_reply
, 2),
2908 CreateMockRead(*stream2_syn
, 3),
2909 CreateMockRead(*stream2_body1
, 4),
2910 CreateMockRead(*stream2_body2
, 5),
2911 MockRead(ASYNC
, ERR_IO_PENDING
, 6), // Force a pause
2912 CreateMockRead(*stream2_body3
, 7),
2913 CreateMockRead(*stream2_body4
, 8),
2914 CreateMockRead(*stream1_body
.get(), 9, SYNCHRONOUS
),
2915 MockRead(ASYNC
, ERR_IO_PENDING
, 10) // Force a pause.
2918 HttpResponseInfo response
;
2919 HttpResponseInfo response2
;
2920 OrderedSocketData
data(reads
, arraysize(reads
),
2921 writes
, arraysize(writes
));
2922 RunServerPushTest(&data
, &response
, &response2
, kPushedData
);
2924 // Verify the SYN_REPLY.
2925 EXPECT_TRUE(response
.headers
.get() != NULL
);
2926 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
2928 // Verify the pushed stream.
2929 EXPECT_TRUE(response2
.headers
.get() != NULL
);
2930 EXPECT_EQ("HTTP/1.1 200 OK", response2
.headers
->GetStatusLine());
2933 TEST_P(SpdyNetworkTransactionTest
, ServerPushInvalidAssociatedStreamID0
) {
2934 if (spdy_util_
.spdy_version() == SPDY4
) {
2935 // PUSH_PROMISE with stream id 0 is connection-level error.
2936 // TODO(baranovich): Test session going away.
2940 scoped_ptr
<SpdyFrame
> stream1_syn(
2941 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2942 scoped_ptr
<SpdyFrame
> stream1_body(
2943 spdy_util_
.ConstructSpdyBodyFrame(1, true));
2944 scoped_ptr
<SpdyFrame
> stream2_rst(
2945 spdy_util_
.ConstructSpdyRstStream(2, RST_STREAM_REFUSED_STREAM
));
2946 MockWrite writes
[] = {
2947 CreateMockWrite(*stream1_syn
, 1),
2948 CreateMockWrite(*stream2_rst
, 4),
2951 scoped_ptr
<SpdyFrame
>
2952 stream1_reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2953 scoped_ptr
<SpdyFrame
> stream2_syn(spdy_util_
.ConstructSpdyPush(
2954 NULL
, 0, 2, 0, GetDefaultUrlWithPath("/foo.dat").c_str()));
2955 MockRead reads
[] = {
2956 CreateMockRead(*stream1_reply
, 2),
2957 CreateMockRead(*stream2_syn
, 3),
2958 CreateMockRead(*stream1_body
, 4),
2959 MockRead(ASYNC
, ERR_IO_PENDING
, 5) // Force a pause
2962 OrderedSocketData
data(reads
, arraysize(reads
),
2963 writes
, arraysize(writes
));
2964 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
2965 BoundNetLog(), GetParam(), NULL
);
2967 helper
.RunPreTestSetup();
2968 helper
.AddData(&data
);
2970 HttpNetworkTransaction
* trans
= helper
.trans();
2972 // Start the transaction with basic parameters.
2973 TestCompletionCallback callback
;
2974 int rv
= trans
->Start(
2975 &CreateGetRequest(), callback
.callback(), BoundNetLog());
2976 EXPECT_EQ(ERR_IO_PENDING
, rv
);
2977 rv
= callback
.WaitForResult();
2980 // Verify that we consumed all test data.
2981 EXPECT_TRUE(data
.at_read_eof()) << "Read count: "
2982 << data
.read_count()
2984 << data
.read_index();
2985 EXPECT_TRUE(data
.at_write_eof()) << "Write count: "
2986 << data
.write_count()
2988 << data
.write_index();
2990 // Verify the SYN_REPLY.
2991 HttpResponseInfo response
= *trans
->GetResponseInfo();
2992 EXPECT_TRUE(response
.headers
.get() != NULL
);
2993 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
2996 TEST_P(SpdyNetworkTransactionTest
, ServerPushInvalidAssociatedStreamID9
) {
2997 scoped_ptr
<SpdyFrame
> stream1_syn(
2998 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2999 scoped_ptr
<SpdyFrame
> stream1_body(
3000 spdy_util_
.ConstructSpdyBodyFrame(1, true));
3001 scoped_ptr
<SpdyFrame
> stream2_rst(
3002 spdy_util_
.ConstructSpdyRstStream(2, RST_STREAM_INVALID_STREAM
));
3003 MockWrite writes
[] = {
3004 CreateMockWrite(*stream1_syn
, 1),
3005 CreateMockWrite(*stream2_rst
, 4),
3008 scoped_ptr
<SpdyFrame
>
3009 stream1_reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
3010 scoped_ptr
<SpdyFrame
> stream2_syn(spdy_util_
.ConstructSpdyPush(
3011 NULL
, 0, 2, 9, GetDefaultUrlWithPath("/foo.dat").c_str()));
3012 MockRead reads
[] = {
3013 CreateMockRead(*stream1_reply
, 2),
3014 CreateMockRead(*stream2_syn
, 3),
3015 CreateMockRead(*stream1_body
, 4),
3016 MockRead(ASYNC
, ERR_IO_PENDING
, 5), // Force a pause
3019 OrderedSocketData
data(reads
, arraysize(reads
),
3020 writes
, arraysize(writes
));
3021 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
3022 BoundNetLog(), GetParam(), NULL
);
3024 helper
.RunPreTestSetup();
3025 helper
.AddData(&data
);
3027 HttpNetworkTransaction
* trans
= helper
.trans();
3029 // Start the transaction with basic parameters.
3030 TestCompletionCallback callback
;
3031 int rv
= trans
->Start(
3032 &CreateGetRequest(), callback
.callback(), BoundNetLog());
3033 EXPECT_EQ(ERR_IO_PENDING
, rv
);
3034 rv
= callback
.WaitForResult();
3037 // Verify that we consumed all test data.
3038 EXPECT_TRUE(data
.at_read_eof()) << "Read count: "
3039 << data
.read_count()
3041 << data
.read_index();
3042 EXPECT_TRUE(data
.at_write_eof()) << "Write count: "
3043 << data
.write_count()
3045 << data
.write_index();
3047 // Verify the SYN_REPLY.
3048 HttpResponseInfo response
= *trans
->GetResponseInfo();
3049 EXPECT_TRUE(response
.headers
.get() != NULL
);
3050 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
3053 TEST_P(SpdyNetworkTransactionTest
, ServerPushNoURL
) {
3054 scoped_ptr
<SpdyFrame
> stream1_syn(
3055 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
3056 scoped_ptr
<SpdyFrame
> stream1_body(
3057 spdy_util_
.ConstructSpdyBodyFrame(1, true));
3058 scoped_ptr
<SpdyFrame
> stream2_rst(
3059 spdy_util_
.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR
));
3060 MockWrite writes
[] = {
3061 CreateMockWrite(*stream1_syn
, 1),
3062 CreateMockWrite(*stream2_rst
, 4),
3065 scoped_ptr
<SpdyFrame
>
3066 stream1_reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
3067 scoped_ptr
<SpdyHeaderBlock
> incomplete_headers(new SpdyHeaderBlock());
3068 (*incomplete_headers
)["hello"] = "bye";
3069 (*incomplete_headers
)[spdy_util_
.GetStatusKey()] = "200 OK";
3070 (*incomplete_headers
)[spdy_util_
.GetVersionKey()] = "HTTP/1.1";
3071 scoped_ptr
<SpdyFrame
> stream2_syn(spdy_util_
.ConstructInitialSpdyPushFrame(
3072 incomplete_headers
.Pass(), 2, 1));
3073 MockRead reads
[] = {
3074 CreateMockRead(*stream1_reply
, 2),
3075 CreateMockRead(*stream2_syn
, 3),
3076 CreateMockRead(*stream1_body
, 4),
3077 MockRead(ASYNC
, ERR_IO_PENDING
, 5) // Force a pause
3080 OrderedSocketData
data(reads
, arraysize(reads
),
3081 writes
, arraysize(writes
));
3082 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
3083 BoundNetLog(), GetParam(), NULL
);
3085 helper
.RunPreTestSetup();
3086 helper
.AddData(&data
);
3088 HttpNetworkTransaction
* trans
= helper
.trans();
3090 // Start the transaction with basic parameters.
3091 TestCompletionCallback callback
;
3092 int rv
= trans
->Start(
3093 &CreateGetRequest(), callback
.callback(), BoundNetLog());
3094 EXPECT_EQ(ERR_IO_PENDING
, rv
);
3095 rv
= callback
.WaitForResult();
3097 // Verify that we consumed all test data.
3098 EXPECT_TRUE(data
.at_read_eof()) << "Read count: "
3099 << data
.read_count()
3101 << data
.read_index();
3102 EXPECT_TRUE(data
.at_write_eof()) << "Write count: "
3103 << data
.write_count()
3105 << data
.write_index();
3107 // Verify the SYN_REPLY.
3108 HttpResponseInfo response
= *trans
->GetResponseInfo();
3109 EXPECT_TRUE(response
.headers
.get() != NULL
);
3110 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
3113 // Verify that various SynReply headers parse correctly through the
3115 TEST_P(SpdyNetworkTransactionTest
, SynReplyHeaders
) {
3116 struct SynReplyHeadersTests
{
3118 const char* extra_headers
[5];
3119 SpdyHeaderBlock expected_headers
;
3121 // This uses a multi-valued cookie header.
3124 "cookie", "val2", // will get appended separated by NULL
3128 // This is the minimalist set of headers.
3132 // Headers with a comma separated list.
3134 { "cookie", "val1,val2",
3140 test_cases
[0].expected_headers
["cookie"] = "val1";
3141 test_cases
[0].expected_headers
["cookie"] += '\0';
3142 test_cases
[0].expected_headers
["cookie"] += "val2";
3143 test_cases
[0].expected_headers
["hello"] = "bye";
3144 test_cases
[0].expected_headers
["status"] = "200";
3146 test_cases
[1].expected_headers
["hello"] = "bye";
3147 test_cases
[1].expected_headers
["status"] = "200";
3149 test_cases
[2].expected_headers
["cookie"] = "val1,val2";
3150 test_cases
[2].expected_headers
["hello"] = "bye";
3151 test_cases
[2].expected_headers
["status"] = "200";
3153 if (spdy_util_
.spdy_version() < SPDY4
) {
3154 // SPDY4/HTTP2 eliminates use of the :version header.
3155 test_cases
[0].expected_headers
["version"] = "HTTP/1.1";
3156 test_cases
[1].expected_headers
["version"] = "HTTP/1.1";
3157 test_cases
[2].expected_headers
["version"] = "HTTP/1.1";
3160 for (size_t i
= 0; i
< arraysize(test_cases
); ++i
) {
3161 scoped_ptr
<SpdyFrame
> req(
3162 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
3163 MockWrite writes
[] = { CreateMockWrite(*req
) };
3165 scoped_ptr
<SpdyFrame
> resp(
3166 spdy_util_
.ConstructSpdyGetSynReply(test_cases
[i
].extra_headers
,
3167 test_cases
[i
].num_headers
,
3169 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
3170 MockRead reads
[] = {
3171 CreateMockRead(*resp
),
3172 CreateMockRead(*body
),
3173 MockRead(ASYNC
, 0, 0) // EOF
3176 DelayedSocketData
data(1, reads
, arraysize(reads
),
3177 writes
, arraysize(writes
));
3178 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
3179 BoundNetLog(), GetParam(), NULL
);
3180 helper
.RunToCompletion(&data
);
3181 TransactionHelperResult out
= helper
.output();
3183 EXPECT_EQ(OK
, out
.rv
);
3184 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
3185 EXPECT_EQ("hello!", out
.response_data
);
3187 scoped_refptr
<HttpResponseHeaders
> headers
= out
.response_info
.headers
;
3188 EXPECT_TRUE(headers
.get() != NULL
);
3190 std::string name
, value
;
3191 SpdyHeaderBlock header_block
;
3192 while (headers
->EnumerateHeaderLines(&iter
, &name
, &value
)) {
3193 if (header_block
[name
].empty()) {
3194 header_block
[name
] = value
;
3196 header_block
[name
] += '\0';
3197 header_block
[name
] += value
;
3200 EXPECT_EQ(test_cases
[i
].expected_headers
, header_block
);
3204 // Verify that various SynReply headers parse vary fields correctly
3205 // through the HTTP layer, and the response matches the request.
3206 TEST_P(SpdyNetworkTransactionTest
, SynReplyHeadersVary
) {
3207 // Modify the following data to change/add test cases:
3208 struct SynReplyTests
{
3211 const char* extra_headers
[2][16];
3213 // Test the case of a multi-valued cookie. When the value is delimited
3214 // with NUL characters, it needs to be unfolded into multiple headers.
3218 { { "cookie", "val1,val2",
3222 spdy_util_
.GetStatusKey(), "200",
3223 spdy_util_
.GetPathKey(), "/index.php",
3224 spdy_util_
.GetVersionKey(), "HTTP/1.1",
3228 }, { // Multiple vary fields.
3231 { { "friend", "barney",
3232 "enemy", "snaggletooth",
3237 spdy_util_
.GetStatusKey(), "200",
3238 spdy_util_
.GetPathKey(), "/index.php",
3239 spdy_util_
.GetVersionKey(), "HTTP/1.1",
3243 }, { // Test a '*' vary field.
3246 { { "cookie", "val1,val2",
3250 spdy_util_
.GetStatusKey(), "200",
3251 spdy_util_
.GetPathKey(), "/index.php",
3252 spdy_util_
.GetVersionKey(), "HTTP/1.1",
3256 }, { // Multiple comma-separated vary fields.
3259 { { "friend", "barney",
3260 "enemy", "snaggletooth",
3263 { "vary", "friend,enemy",
3264 spdy_util_
.GetStatusKey(), "200",
3265 spdy_util_
.GetPathKey(), "/index.php",
3266 spdy_util_
.GetVersionKey(), "HTTP/1.1",
3273 for (size_t i
= 0; i
< arraysize(test_cases
); ++i
) {
3274 // Construct the request.
3275 scoped_ptr
<SpdyFrame
> frame_req(
3276 spdy_util_
.ConstructSpdyGet(test_cases
[i
].extra_headers
[0],
3277 test_cases
[i
].num_headers
[0],
3278 false, 1, LOWEST
, true));
3280 MockWrite writes
[] = {
3281 CreateMockWrite(*frame_req
),
3284 // Construct the reply.
3285 SpdyHeaderBlock reply_headers
;
3286 AppendToHeaderBlock(test_cases
[i
].extra_headers
[1],
3287 test_cases
[i
].num_headers
[1],
3289 scoped_ptr
<SpdyFrame
> frame_reply(
3290 spdy_util_
.ConstructSpdyReply(1, reply_headers
));
3292 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
3293 MockRead reads
[] = {
3294 CreateMockRead(*frame_reply
),
3295 CreateMockRead(*body
),
3296 MockRead(ASYNC
, 0, 0) // EOF
3299 // Attach the headers to the request.
3300 int header_count
= test_cases
[i
].num_headers
[0];
3302 HttpRequestInfo request
= CreateGetRequest();
3303 for (int ct
= 0; ct
< header_count
; ct
++) {
3304 const char* header_key
= test_cases
[i
].extra_headers
[0][ct
* 2];
3305 const char* header_value
= test_cases
[i
].extra_headers
[0][ct
* 2 + 1];
3306 request
.extra_headers
.SetHeader(header_key
, header_value
);
3309 DelayedSocketData
data(1, reads
, arraysize(reads
),
3310 writes
, arraysize(writes
));
3311 NormalSpdyTransactionHelper
helper(request
, DEFAULT_PRIORITY
,
3312 BoundNetLog(), GetParam(), NULL
);
3313 helper
.RunToCompletion(&data
);
3314 TransactionHelperResult out
= helper
.output();
3316 EXPECT_EQ(OK
, out
.rv
) << i
;
3317 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
) << i
;
3318 EXPECT_EQ("hello!", out
.response_data
) << i
;
3320 // Test the response information.
3321 EXPECT_TRUE(out
.response_info
.response_time
>
3322 out
.response_info
.request_time
) << i
;
3323 base::TimeDelta test_delay
= out
.response_info
.response_time
-
3324 out
.response_info
.request_time
;
3325 base::TimeDelta min_expected_delay
;
3326 min_expected_delay
.FromMilliseconds(10);
3327 EXPECT_GT(test_delay
.InMillisecondsF(),
3328 min_expected_delay
.InMillisecondsF()) << i
;
3329 EXPECT_EQ(out
.response_info
.vary_data
.is_valid(),
3330 test_cases
[i
].vary_matches
) << i
;
3332 // Check the headers.
3333 scoped_refptr
<HttpResponseHeaders
> headers
= out
.response_info
.headers
;
3334 ASSERT_TRUE(headers
.get() != NULL
) << i
;
3336 std::string name
, value
, lines
;
3337 while (headers
->EnumerateHeaderLines(&iter
, &name
, &value
)) {
3340 lines
.append(value
);
3344 // Construct the expected header reply string.
3345 std::string expected_reply
=
3346 spdy_util_
.ConstructSpdyReplyString(reply_headers
);
3347 EXPECT_EQ(expected_reply
, lines
) << i
;
3351 // Verify that we don't crash on invalid SynReply responses.
3352 TEST_P(SpdyNetworkTransactionTest
, InvalidSynReply
) {
3353 struct InvalidSynReplyTests
{
3355 const char* headers
[10];
3357 // SYN_REPLY missing status header
3361 spdy_util_
.GetPathKey(), "/index.php",
3362 spdy_util_
.GetVersionKey(), "HTTP/1.1",
3366 // SYN_REPLY missing version header
3369 spdy_util_
.GetPathKey(), "/index.php",
3373 // SYN_REPLY with no headers
3377 for (size_t i
= 0; i
< arraysize(test_cases
); ++i
) {
3378 scoped_ptr
<SpdyFrame
> req(
3379 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
3380 scoped_ptr
<SpdyFrame
> rst(
3381 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR
));
3382 MockWrite writes
[] = {
3383 CreateMockWrite(*req
),
3384 CreateMockWrite(*rst
),
3387 // Construct the reply.
3388 SpdyHeaderBlock reply_headers
;
3389 AppendToHeaderBlock(
3390 test_cases
[i
].headers
, test_cases
[i
].num_headers
, &reply_headers
);
3391 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyReply(1, reply_headers
));
3392 MockRead reads
[] = {
3393 CreateMockRead(*resp
),
3394 MockRead(ASYNC
, 0, 0) // EOF
3397 DelayedSocketData
data(1, reads
, arraysize(reads
),
3398 writes
, arraysize(writes
));
3399 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
3400 BoundNetLog(), GetParam(), NULL
);
3401 helper
.RunToCompletion(&data
);
3402 TransactionHelperResult out
= helper
.output();
3403 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR
, out
.rv
);
3407 // Verify that we don't crash on some corrupt frames.
3408 // TODO(jgraettinger): SPDY4 and up treats a header decompression failure as a
3409 // connection error. I'd like to backport this behavior to SPDY3 as well.
3410 TEST_P(SpdyNetworkTransactionTest
, CorruptFrameSessionError
) {
3411 if (spdy_util_
.spdy_version() >= SPDY4
) {
3414 // This is the length field that's too short.
3415 scoped_ptr
<SpdyFrame
> syn_reply_wrong_length(
3416 spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
3417 BufferedSpdyFramer
framer(spdy_util_
.spdy_version(), false);
3419 (spdy_util_
.spdy_version() < SPDY4
) ?
3420 syn_reply_wrong_length
->size() - framer
.GetControlFrameHeaderSize() :
3421 syn_reply_wrong_length
->size();
3422 size_t wrong_size
= right_size
- 4;
3423 test::SetFrameLength(syn_reply_wrong_length
.get(),
3425 spdy_util_
.spdy_version());
3427 struct SynReplyTests
{
3428 const SpdyFrame
* syn_reply
;
3430 { syn_reply_wrong_length
.get(), },
3433 for (size_t i
= 0; i
< arraysize(test_cases
); ++i
) {
3434 scoped_ptr
<SpdyFrame
> req(
3435 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
3436 scoped_ptr
<SpdyFrame
> rst(
3437 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR
));
3438 MockWrite writes
[] = {
3439 CreateMockWrite(*req
),
3440 CreateMockWrite(*rst
),
3443 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
3444 MockRead reads
[] = {
3445 MockRead(ASYNC
, test_cases
[i
].syn_reply
->data(), wrong_size
),
3446 CreateMockRead(*body
),
3447 MockRead(ASYNC
, 0, 0) // EOF
3450 DelayedSocketData
data(1, reads
, arraysize(reads
),
3451 writes
, arraysize(writes
));
3452 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
3453 BoundNetLog(), GetParam(), NULL
);
3454 helper
.RunToCompletion(&data
);
3455 TransactionHelperResult out
= helper
.output();
3456 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR
, out
.rv
);
3460 // SPDY4 treats a header decompression failure as a connection-level error.
3461 TEST_P(SpdyNetworkTransactionTest
, CorruptFrameSessionErrorSpdy4
) {
3462 if (spdy_util_
.spdy_version() < SPDY4
) {
3465 // This is the length field that's too short.
3466 scoped_ptr
<SpdyFrame
> syn_reply_wrong_length(
3467 spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
3468 BufferedSpdyFramer
framer(spdy_util_
.spdy_version(), false);
3470 syn_reply_wrong_length
->size() - framer
.GetControlFrameHeaderSize();
3471 size_t wrong_size
= right_size
- 4;
3472 test::SetFrameLength(syn_reply_wrong_length
.get(),
3474 spdy_util_
.spdy_version());
3476 scoped_ptr
<SpdyFrame
> req(
3477 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
3478 scoped_ptr
<SpdyFrame
> goaway(spdy_util_
.ConstructSpdyGoAway(
3479 0, GOAWAY_COMPRESSION_ERROR
, "Framer error: 5 (DECOMPRESS_FAILURE)."));
3480 MockWrite writes
[] = {CreateMockWrite(*req
), CreateMockWrite(*goaway
)};
3482 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
3483 MockRead reads
[] = {
3484 MockRead(ASYNC
, syn_reply_wrong_length
->data(),
3485 syn_reply_wrong_length
->size() - 4),
3488 DelayedSocketData
data(1, reads
, arraysize(reads
),
3489 writes
, arraysize(writes
));
3490 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
3491 BoundNetLog(), GetParam(), NULL
);
3492 helper
.RunToCompletion(&data
);
3493 TransactionHelperResult out
= helper
.output();
3494 EXPECT_EQ(ERR_SPDY_COMPRESSION_ERROR
, out
.rv
);
3497 TEST_P(SpdyNetworkTransactionTest
, GoAwayOnDecompressionFailure
) {
3498 if (GetParam().protocol
< kProtoSPDY4MinimumVersion
) {
3499 // Decompression failures are a stream error in SPDY3 and above.
3502 scoped_ptr
<SpdyFrame
> req(
3503 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
3504 scoped_ptr
<SpdyFrame
> goaway(spdy_util_
.ConstructSpdyGoAway(
3505 0, GOAWAY_COMPRESSION_ERROR
, "Framer error: 5 (DECOMPRESS_FAILURE)."));
3506 MockWrite writes
[] = {CreateMockWrite(*req
), CreateMockWrite(*goaway
)};
3508 // Read HEADERS with corrupted payload.
3509 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
3510 memset(resp
->data() + 12, 0xff, resp
->size() - 12);
3511 MockRead reads
[] = {CreateMockRead(*resp
)};
3513 DelayedSocketData
data(1, reads
, arraysize(reads
), writes
, arraysize(writes
));
3514 NormalSpdyTransactionHelper
helper(
3515 CreateGetRequest(), DEFAULT_PRIORITY
, BoundNetLog(), GetParam(), NULL
);
3516 helper
.RunToCompletion(&data
);
3517 TransactionHelperResult out
= helper
.output();
3518 EXPECT_EQ(ERR_SPDY_COMPRESSION_ERROR
, out
.rv
);
3521 TEST_P(SpdyNetworkTransactionTest
, GoAwayOnFrameSizeError
) {
3522 scoped_ptr
<SpdyFrame
> req(
3523 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
3524 scoped_ptr
<SpdyFrame
> goaway(spdy_util_
.ConstructSpdyGoAway(
3525 0, GOAWAY_PROTOCOL_ERROR
, "Framer error: 1 (INVALID_CONTROL_FRAME)."));
3526 MockWrite writes
[] = {CreateMockWrite(*req
), CreateMockWrite(*goaway
)};
3528 // Read WINDOW_UPDATE with incorrectly-sized payload.
3529 // TODO(jgraettinger): SpdyFramer signals this as an INVALID_CONTROL_FRAME,
3530 // which is mapped to a protocol error, and not a frame size error.
3531 scoped_ptr
<SpdyFrame
> bad_window_update(
3532 spdy_util_
.ConstructSpdyWindowUpdate(1, 1));
3533 test::SetFrameLength(bad_window_update
.get(),
3534 bad_window_update
->size() - 1,
3535 spdy_util_
.spdy_version());
3536 MockRead reads
[] = {CreateMockRead(*bad_window_update
)};
3538 DelayedSocketData
data(1, reads
, arraysize(reads
), writes
, arraysize(writes
));
3539 NormalSpdyTransactionHelper
helper(
3540 CreateGetRequest(), DEFAULT_PRIORITY
, BoundNetLog(), GetParam(), NULL
);
3541 helper
.RunToCompletion(&data
);
3542 TransactionHelperResult out
= helper
.output();
3543 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR
, out
.rv
);
3546 // Test that we shutdown correctly on write errors.
3547 TEST_P(SpdyNetworkTransactionTest
, WriteError
) {
3548 scoped_ptr
<SpdyFrame
> req(
3549 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
3550 MockWrite writes
[] = {
3551 // We'll write 10 bytes successfully
3552 MockWrite(ASYNC
, req
->data(), 10, 0),
3553 // Followed by ERROR!
3554 MockWrite(ASYNC
, ERR_FAILED
, 1),
3555 // Session drains and attempts to write a GOAWAY: Another ERROR!
3556 MockWrite(ASYNC
, ERR_FAILED
, 2),
3559 MockRead reads
[] = {
3560 MockRead(ASYNC
, 0, 3) // EOF
3563 DeterministicSocketData
data(reads
, arraysize(reads
),
3564 writes
, arraysize(writes
));
3566 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
3567 BoundNetLog(), GetParam(), NULL
);
3568 helper
.SetDeterministic();
3569 helper
.RunPreTestSetup();
3570 helper
.AddDeterministicData(&data
);
3571 EXPECT_TRUE(helper
.StartDefaultTest());
3573 helper
.FinishDefaultTest();
3574 EXPECT_TRUE(data
.at_write_eof());
3575 EXPECT_TRUE(!data
.at_read_eof());
3576 TransactionHelperResult out
= helper
.output();
3577 EXPECT_EQ(ERR_FAILED
, out
.rv
);
3580 // Test that partial writes work.
3581 TEST_P(SpdyNetworkTransactionTest
, PartialWrite
) {
3582 // Chop the SYN_STREAM frame into 5 chunks.
3583 scoped_ptr
<SpdyFrame
> req(
3584 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
3585 const int kChunks
= 5;
3586 scoped_ptr
<MockWrite
[]> writes(ChopWriteFrame(*req
.get(), kChunks
));
3588 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
3589 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
3590 MockRead reads
[] = {
3591 CreateMockRead(*resp
),
3592 CreateMockRead(*body
),
3593 MockRead(ASYNC
, 0, 0) // EOF
3596 DelayedSocketData
data(kChunks
, reads
, arraysize(reads
),
3597 writes
.get(), kChunks
);
3598 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
3599 BoundNetLog(), GetParam(), NULL
);
3600 helper
.RunToCompletion(&data
);
3601 TransactionHelperResult out
= helper
.output();
3602 EXPECT_EQ(OK
, out
.rv
);
3603 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
3604 EXPECT_EQ("hello!", out
.response_data
);
3607 // In this test, we enable compression, but get a uncompressed SynReply from
3608 // the server. Verify that teardown is all clean.
3609 TEST_P(SpdyNetworkTransactionTest
, DecompressFailureOnSynReply
) {
3610 if (spdy_util_
.spdy_version() >= SPDY4
) {
3611 // HPACK doesn't use deflate compression.
3614 scoped_ptr
<SpdyFrame
> compressed(
3615 spdy_util_
.ConstructSpdyGet(NULL
, 0, true, 1, LOWEST
, true));
3616 scoped_ptr
<SpdyFrame
> goaway(spdy_util_
.ConstructSpdyGoAway(
3617 0, GOAWAY_COMPRESSION_ERROR
, "Framer error: 5 (DECOMPRESS_FAILURE)."));
3618 MockWrite writes
[] = {CreateMockWrite(*compressed
), CreateMockWrite(*goaway
)};
3620 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
3621 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
3622 MockRead reads
[] = {
3623 CreateMockRead(*resp
),
3626 DelayedSocketData
data(1, reads
, arraysize(reads
),
3627 writes
, arraysize(writes
));
3628 SpdySessionDependencies
* session_deps
=
3629 CreateSpdySessionDependencies(GetParam());
3630 session_deps
->enable_compression
= true;
3631 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
3632 BoundNetLog(), GetParam(), session_deps
);
3633 helper
.RunToCompletion(&data
);
3634 TransactionHelperResult out
= helper
.output();
3635 EXPECT_EQ(ERR_SPDY_COMPRESSION_ERROR
, out
.rv
);
3639 // Test that the NetLog contains good data for a simple GET request.
3640 TEST_P(SpdyNetworkTransactionTest
, NetLog
) {
3641 static const char* const kExtraHeaders
[] = {
3642 "user-agent", "Chrome",
3644 scoped_ptr
<SpdyFrame
> req(
3645 spdy_util_
.ConstructSpdyGet(kExtraHeaders
, 1, false, 1, LOWEST
, true));
3646 MockWrite writes
[] = { CreateMockWrite(*req
) };
3648 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
3649 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
3650 MockRead reads
[] = {
3651 CreateMockRead(*resp
),
3652 CreateMockRead(*body
),
3653 MockRead(ASYNC
, 0, 0) // EOF
3656 CapturingBoundNetLog log
;
3658 DelayedSocketData
data(1, reads
, arraysize(reads
),
3659 writes
, arraysize(writes
));
3660 NormalSpdyTransactionHelper
helper(CreateGetRequestWithUserAgent(),
3662 log
.bound(), GetParam(), NULL
);
3663 helper
.RunToCompletion(&data
);
3664 TransactionHelperResult out
= helper
.output();
3665 EXPECT_EQ(OK
, out
.rv
);
3666 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
3667 EXPECT_EQ("hello!", out
.response_data
);
3669 // Check that the NetLog was filled reasonably.
3670 // This test is intentionally non-specific about the exact ordering of the
3671 // log; instead we just check to make sure that certain events exist, and that
3672 // they are in the right order.
3673 CapturingNetLog::CapturedEntryList entries
;
3674 log
.GetEntries(&entries
);
3676 EXPECT_LT(0u, entries
.size());
3678 pos
= ExpectLogContainsSomewhere(entries
, 0,
3679 NetLog::TYPE_HTTP_TRANSACTION_SEND_REQUEST
,
3680 NetLog::PHASE_BEGIN
);
3681 pos
= ExpectLogContainsSomewhere(entries
, pos
+ 1,
3682 NetLog::TYPE_HTTP_TRANSACTION_SEND_REQUEST
,
3684 pos
= ExpectLogContainsSomewhere(entries
, pos
+ 1,
3685 NetLog::TYPE_HTTP_TRANSACTION_READ_HEADERS
,
3686 NetLog::PHASE_BEGIN
);
3687 pos
= ExpectLogContainsSomewhere(entries
, pos
+ 1,
3688 NetLog::TYPE_HTTP_TRANSACTION_READ_HEADERS
,
3690 pos
= ExpectLogContainsSomewhere(entries
, pos
+ 1,
3691 NetLog::TYPE_HTTP_TRANSACTION_READ_BODY
,
3692 NetLog::PHASE_BEGIN
);
3693 pos
= ExpectLogContainsSomewhere(entries
, pos
+ 1,
3694 NetLog::TYPE_HTTP_TRANSACTION_READ_BODY
,
3697 // Check that we logged all the headers correctly
3698 const NetLog::EventType type
= (GetParam().protocol
<= kProtoSPDY31
)
3699 ? NetLog::TYPE_HTTP2_SESSION_SYN_STREAM
3700 : NetLog::TYPE_HTTP2_SESSION_SEND_HEADERS
;
3701 pos
= ExpectLogContainsSomewhere(entries
, 0, type
, NetLog::PHASE_NONE
);
3703 base::ListValue
* header_list
;
3704 ASSERT_TRUE(entries
[pos
].params
.get());
3705 ASSERT_TRUE(entries
[pos
].params
->GetList("headers", &header_list
));
3707 std::vector
<std::string
> expected
;
3708 expected
.push_back(std::string(spdy_util_
.GetHostKey()) + ": www.google.com");
3709 expected
.push_back(std::string(spdy_util_
.GetPathKey()) + ": /");
3710 expected
.push_back(std::string(spdy_util_
.GetSchemeKey()) + ": " +
3711 spdy_util_
.default_url().scheme());
3712 expected
.push_back(std::string(spdy_util_
.GetMethodKey()) + ": GET");
3713 expected
.push_back("user-agent: Chrome");
3714 if (spdy_util_
.spdy_version() < SPDY4
) {
3715 // SPDY4/HTTP2 eliminates use of the :version header.
3716 expected
.push_back(std::string(spdy_util_
.GetVersionKey()) + ": HTTP/1.1");
3718 EXPECT_EQ(expected
.size(), header_list
->GetSize());
3719 for (std::vector
<std::string
>::const_iterator it
= expected
.begin();
3720 it
!= expected
.end();
3722 base::StringValue
header(*it
);
3723 EXPECT_NE(header_list
->end(), header_list
->Find(header
)) <<
3724 "Header not found: " << *it
;
3728 // Since we buffer the IO from the stream to the renderer, this test verifies
3729 // that when we read out the maximum amount of data (e.g. we received 50 bytes
3730 // on the network, but issued a Read for only 5 of those bytes) that the data
3731 // flow still works correctly.
3732 TEST_P(SpdyNetworkTransactionTest
, BufferFull
) {
3733 BufferedSpdyFramer
framer(spdy_util_
.spdy_version(), false);
3735 scoped_ptr
<SpdyFrame
> req(
3736 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
3737 MockWrite writes
[] = { CreateMockWrite(*req
) };
3739 // 2 data frames in a single read.
3740 scoped_ptr
<SpdyFrame
> data_frame_1(
3741 framer
.CreateDataFrame(1, "goodby", 6, DATA_FLAG_NONE
));
3742 scoped_ptr
<SpdyFrame
> data_frame_2(
3743 framer
.CreateDataFrame(1, "e worl", 6, DATA_FLAG_NONE
));
3744 const SpdyFrame
* data_frames
[2] = {
3748 char combined_data_frames
[100];
3749 int combined_data_frames_len
=
3750 CombineFrames(data_frames
, arraysize(data_frames
),
3751 combined_data_frames
, arraysize(combined_data_frames
));
3752 scoped_ptr
<SpdyFrame
> last_frame(
3753 framer
.CreateDataFrame(1, "d", 1, DATA_FLAG_FIN
));
3755 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
3756 MockRead reads
[] = {
3757 CreateMockRead(*resp
),
3758 MockRead(ASYNC
, ERR_IO_PENDING
), // Force a pause
3759 MockRead(ASYNC
, combined_data_frames
, combined_data_frames_len
),
3760 MockRead(ASYNC
, ERR_IO_PENDING
), // Force a pause
3761 CreateMockRead(*last_frame
),
3762 MockRead(ASYNC
, 0, 0) // EOF
3765 DelayedSocketData
data(1, reads
, arraysize(reads
),
3766 writes
, arraysize(writes
));
3768 TestCompletionCallback callback
;
3770 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
3771 BoundNetLog(), GetParam(), NULL
);
3772 helper
.RunPreTestSetup();
3773 helper
.AddData(&data
);
3774 HttpNetworkTransaction
* trans
= helper
.trans();
3775 int rv
= trans
->Start(
3776 &CreateGetRequest(), callback
.callback(), BoundNetLog());
3777 EXPECT_EQ(ERR_IO_PENDING
, rv
);
3779 TransactionHelperResult out
= helper
.output();
3780 out
.rv
= callback
.WaitForResult();
3781 EXPECT_EQ(out
.rv
, OK
);
3783 const HttpResponseInfo
* response
= trans
->GetResponseInfo();
3784 EXPECT_TRUE(response
->headers
.get() != NULL
);
3785 EXPECT_TRUE(response
->was_fetched_via_spdy
);
3786 out
.status_line
= response
->headers
->GetStatusLine();
3787 out
.response_info
= *response
; // Make a copy so we can verify.
3790 TestCompletionCallback read_callback
;
3792 std::string content
;
3794 // Read small chunks at a time.
3795 const int kSmallReadSize
= 3;
3796 scoped_refptr
<IOBuffer
> buf(new IOBuffer(kSmallReadSize
));
3797 rv
= trans
->Read(buf
.get(), kSmallReadSize
, read_callback
.callback());
3798 if (rv
== ERR_IO_PENDING
) {
3799 data
.CompleteRead();
3800 rv
= read_callback
.WaitForResult();
3803 content
.append(buf
->data(), rv
);
3804 } else if (rv
< 0) {
3809 out
.response_data
.swap(content
);
3811 // Flush the MessageLoop while the SpdySessionDependencies (in particular, the
3812 // MockClientSocketFactory) are still alive.
3813 base::RunLoop().RunUntilIdle();
3815 // Verify that we consumed all test data.
3816 helper
.VerifyDataConsumed();
3818 EXPECT_EQ(OK
, out
.rv
);
3819 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
3820 EXPECT_EQ("goodbye world", out
.response_data
);
3823 // Verify that basic buffering works; when multiple data frames arrive
3824 // at the same time, ensure that we don't notify a read completion for
3825 // each data frame individually.
3826 TEST_P(SpdyNetworkTransactionTest
, Buffering
) {
3827 BufferedSpdyFramer
framer(spdy_util_
.spdy_version(), false);
3829 scoped_ptr
<SpdyFrame
> req(
3830 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
3831 MockWrite writes
[] = { CreateMockWrite(*req
) };
3833 // 4 data frames in a single read.
3834 scoped_ptr
<SpdyFrame
> data_frame(
3835 framer
.CreateDataFrame(1, "message", 7, DATA_FLAG_NONE
));
3836 scoped_ptr
<SpdyFrame
> data_frame_fin(
3837 framer
.CreateDataFrame(1, "message", 7, DATA_FLAG_FIN
));
3838 const SpdyFrame
* data_frames
[4] = {
3842 data_frame_fin
.get()
3844 char combined_data_frames
[100];
3845 int combined_data_frames_len
=
3846 CombineFrames(data_frames
, arraysize(data_frames
),
3847 combined_data_frames
, arraysize(combined_data_frames
));
3849 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
3850 MockRead reads
[] = {
3851 CreateMockRead(*resp
),
3852 MockRead(ASYNC
, ERR_IO_PENDING
), // Force a pause
3853 MockRead(ASYNC
, combined_data_frames
, combined_data_frames_len
),
3854 MockRead(ASYNC
, 0, 0) // EOF
3857 DelayedSocketData
data(1, reads
, arraysize(reads
),
3858 writes
, arraysize(writes
));
3860 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
3861 BoundNetLog(), GetParam(), NULL
);
3862 helper
.RunPreTestSetup();
3863 helper
.AddData(&data
);
3864 HttpNetworkTransaction
* trans
= helper
.trans();
3866 TestCompletionCallback callback
;
3867 int rv
= trans
->Start(
3868 &CreateGetRequest(), callback
.callback(), BoundNetLog());
3869 EXPECT_EQ(ERR_IO_PENDING
, rv
);
3871 TransactionHelperResult out
= helper
.output();
3872 out
.rv
= callback
.WaitForResult();
3873 EXPECT_EQ(out
.rv
, OK
);
3875 const HttpResponseInfo
* response
= trans
->GetResponseInfo();
3876 EXPECT_TRUE(response
->headers
.get() != NULL
);
3877 EXPECT_TRUE(response
->was_fetched_via_spdy
);
3878 out
.status_line
= response
->headers
->GetStatusLine();
3879 out
.response_info
= *response
; // Make a copy so we can verify.
3882 TestCompletionCallback read_callback
;
3884 std::string content
;
3885 int reads_completed
= 0;
3887 // Read small chunks at a time.
3888 const int kSmallReadSize
= 14;
3889 scoped_refptr
<IOBuffer
> buf(new IOBuffer(kSmallReadSize
));
3890 rv
= trans
->Read(buf
.get(), kSmallReadSize
, read_callback
.callback());
3891 if (rv
== ERR_IO_PENDING
) {
3892 data
.CompleteRead();
3893 rv
= read_callback
.WaitForResult();
3896 EXPECT_EQ(kSmallReadSize
, rv
);
3897 content
.append(buf
->data(), rv
);
3898 } else if (rv
< 0) {
3899 FAIL() << "Unexpected read error: " << rv
;
3904 EXPECT_EQ(3, reads_completed
); // Reads are: 14 bytes, 14 bytes, 0 bytes.
3906 out
.response_data
.swap(content
);
3908 // Flush the MessageLoop while the SpdySessionDependencies (in particular, the
3909 // MockClientSocketFactory) are still alive.
3910 base::RunLoop().RunUntilIdle();
3912 // Verify that we consumed all test data.
3913 helper
.VerifyDataConsumed();
3915 EXPECT_EQ(OK
, out
.rv
);
3916 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
3917 EXPECT_EQ("messagemessagemessagemessage", out
.response_data
);
3920 // Verify the case where we buffer data but read it after it has been buffered.
3921 TEST_P(SpdyNetworkTransactionTest
, BufferedAll
) {
3922 BufferedSpdyFramer
framer(spdy_util_
.spdy_version(), false);
3924 scoped_ptr
<SpdyFrame
> req(
3925 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
3926 MockWrite writes
[] = { CreateMockWrite(*req
) };
3928 // 5 data frames in a single read.
3929 scoped_ptr
<SpdyFrame
> reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
3930 scoped_ptr
<SpdyFrame
> data_frame(
3931 framer
.CreateDataFrame(1, "message", 7, DATA_FLAG_NONE
));
3932 scoped_ptr
<SpdyFrame
> data_frame_fin(
3933 framer
.CreateDataFrame(1, "message", 7, DATA_FLAG_FIN
));
3934 const SpdyFrame
* frames
[5] = {reply
.get(), data_frame
.get(), data_frame
.get(),
3935 data_frame
.get(), data_frame_fin
.get()};
3936 char combined_frames
[200];
3937 int combined_frames_len
=
3938 CombineFrames(frames
, arraysize(frames
),
3939 combined_frames
, arraysize(combined_frames
));
3941 MockRead reads
[] = {
3942 MockRead(ASYNC
, combined_frames
, combined_frames_len
),
3943 MockRead(ASYNC
, 0, 0) // EOF
3946 DelayedSocketData
data(1, reads
, arraysize(reads
),
3947 writes
, arraysize(writes
));
3949 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
3950 BoundNetLog(), GetParam(), NULL
);
3951 helper
.RunPreTestSetup();
3952 helper
.AddData(&data
);
3953 HttpNetworkTransaction
* trans
= helper
.trans();
3955 TestCompletionCallback callback
;
3956 int rv
= trans
->Start(
3957 &CreateGetRequest(), callback
.callback(), BoundNetLog());
3958 EXPECT_EQ(ERR_IO_PENDING
, rv
);
3960 TransactionHelperResult out
= helper
.output();
3961 out
.rv
= callback
.WaitForResult();
3962 EXPECT_EQ(out
.rv
, OK
);
3964 const HttpResponseInfo
* response
= trans
->GetResponseInfo();
3965 EXPECT_TRUE(response
->headers
.get() != NULL
);
3966 EXPECT_TRUE(response
->was_fetched_via_spdy
);
3967 out
.status_line
= response
->headers
->GetStatusLine();
3968 out
.response_info
= *response
; // Make a copy so we can verify.
3971 TestCompletionCallback read_callback
;
3973 std::string content
;
3974 int reads_completed
= 0;
3976 // Read small chunks at a time.
3977 const int kSmallReadSize
= 14;
3978 scoped_refptr
<IOBuffer
> buf(new IOBuffer(kSmallReadSize
));
3979 rv
= trans
->Read(buf
.get(), kSmallReadSize
, read_callback
.callback());
3981 EXPECT_EQ(kSmallReadSize
, rv
);
3982 content
.append(buf
->data(), rv
);
3983 } else if (rv
< 0) {
3984 FAIL() << "Unexpected read error: " << rv
;
3989 EXPECT_EQ(3, reads_completed
);
3991 out
.response_data
.swap(content
);
3993 // Flush the MessageLoop while the SpdySessionDependencies (in particular, the
3994 // MockClientSocketFactory) are still alive.
3995 base::RunLoop().RunUntilIdle();
3997 // Verify that we consumed all test data.
3998 helper
.VerifyDataConsumed();
4000 EXPECT_EQ(OK
, out
.rv
);
4001 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
4002 EXPECT_EQ("messagemessagemessagemessage", out
.response_data
);
4005 // Verify the case where we buffer data and close the connection.
4006 TEST_P(SpdyNetworkTransactionTest
, BufferedClosed
) {
4007 BufferedSpdyFramer
framer(spdy_util_
.spdy_version(), false);
4009 scoped_ptr
<SpdyFrame
> req(
4010 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
4011 MockWrite writes
[] = { CreateMockWrite(*req
) };
4013 // All data frames in a single read.
4014 // NOTE: We don't FIN the stream.
4015 scoped_ptr
<SpdyFrame
> data_frame(
4016 framer
.CreateDataFrame(1, "message", 7, DATA_FLAG_NONE
));
4017 const SpdyFrame
* data_frames
[4] = {
4023 char combined_data_frames
[100];
4024 int combined_data_frames_len
=
4025 CombineFrames(data_frames
, arraysize(data_frames
),
4026 combined_data_frames
, arraysize(combined_data_frames
));
4027 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
4028 MockRead reads
[] = {
4029 CreateMockRead(*resp
),
4030 MockRead(ASYNC
, ERR_IO_PENDING
), // Force a wait
4031 MockRead(ASYNC
, combined_data_frames
, combined_data_frames_len
),
4032 MockRead(ASYNC
, 0, 0) // EOF
4035 DelayedSocketData
data(1, reads
, arraysize(reads
),
4036 writes
, arraysize(writes
));
4038 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
4039 BoundNetLog(), GetParam(), NULL
);
4040 helper
.RunPreTestSetup();
4041 helper
.AddData(&data
);
4042 HttpNetworkTransaction
* trans
= helper
.trans();
4044 TestCompletionCallback callback
;
4046 int rv
= trans
->Start(
4047 &CreateGetRequest(), callback
.callback(), BoundNetLog());
4048 EXPECT_EQ(ERR_IO_PENDING
, rv
);
4050 TransactionHelperResult out
= helper
.output();
4051 out
.rv
= callback
.WaitForResult();
4052 EXPECT_EQ(out
.rv
, OK
);
4054 const HttpResponseInfo
* response
= trans
->GetResponseInfo();
4055 EXPECT_TRUE(response
->headers
.get() != NULL
);
4056 EXPECT_TRUE(response
->was_fetched_via_spdy
);
4057 out
.status_line
= response
->headers
->GetStatusLine();
4058 out
.response_info
= *response
; // Make a copy so we can verify.
4061 TestCompletionCallback read_callback
;
4063 std::string content
;
4064 int reads_completed
= 0;
4066 // Read small chunks at a time.
4067 const int kSmallReadSize
= 14;
4068 scoped_refptr
<IOBuffer
> buf(new IOBuffer(kSmallReadSize
));
4069 rv
= trans
->Read(buf
.get(), kSmallReadSize
, read_callback
.callback());
4070 if (rv
== ERR_IO_PENDING
) {
4071 data
.CompleteRead();
4072 rv
= read_callback
.WaitForResult();
4075 content
.append(buf
->data(), rv
);
4076 } else if (rv
< 0) {
4077 // This test intentionally closes the connection, and will get an error.
4078 EXPECT_EQ(ERR_CONNECTION_CLOSED
, rv
);
4084 EXPECT_EQ(0, reads_completed
);
4086 out
.response_data
.swap(content
);
4088 // Flush the MessageLoop while the SpdySessionDependencies (in particular, the
4089 // MockClientSocketFactory) are still alive.
4090 base::RunLoop().RunUntilIdle();
4092 // Verify that we consumed all test data.
4093 helper
.VerifyDataConsumed();
4096 // Verify the case where we buffer data and cancel the transaction.
4097 TEST_P(SpdyNetworkTransactionTest
, BufferedCancelled
) {
4098 BufferedSpdyFramer
framer(spdy_util_
.spdy_version(), false);
4100 scoped_ptr
<SpdyFrame
> req(
4101 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
4102 scoped_ptr
<SpdyFrame
> rst(
4103 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_CANCEL
));
4104 MockWrite writes
[] = {CreateMockWrite(*req
), CreateMockWrite(*rst
)};
4106 // NOTE: We don't FIN the stream.
4107 scoped_ptr
<SpdyFrame
> data_frame(
4108 framer
.CreateDataFrame(1, "message", 7, DATA_FLAG_NONE
));
4110 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
4111 MockRead reads
[] = {
4112 CreateMockRead(*resp
),
4113 MockRead(ASYNC
, ERR_IO_PENDING
), // Force a wait
4114 CreateMockRead(*data_frame
),
4115 MockRead(ASYNC
, 0, 0) // EOF
4118 DelayedSocketData
data(1, reads
, arraysize(reads
),
4119 writes
, arraysize(writes
));
4121 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
4122 BoundNetLog(), GetParam(), NULL
);
4123 helper
.RunPreTestSetup();
4124 helper
.AddData(&data
);
4125 HttpNetworkTransaction
* trans
= helper
.trans();
4126 TestCompletionCallback callback
;
4128 int rv
= trans
->Start(
4129 &CreateGetRequest(), callback
.callback(), BoundNetLog());
4130 EXPECT_EQ(ERR_IO_PENDING
, rv
);
4132 TransactionHelperResult out
= helper
.output();
4133 out
.rv
= callback
.WaitForResult();
4134 EXPECT_EQ(out
.rv
, OK
);
4136 const HttpResponseInfo
* response
= trans
->GetResponseInfo();
4137 EXPECT_TRUE(response
->headers
.get() != NULL
);
4138 EXPECT_TRUE(response
->was_fetched_via_spdy
);
4139 out
.status_line
= response
->headers
->GetStatusLine();
4140 out
.response_info
= *response
; // Make a copy so we can verify.
4143 TestCompletionCallback read_callback
;
4145 const int kReadSize
= 256;
4146 scoped_refptr
<IOBuffer
> buf(new IOBuffer(kReadSize
));
4147 rv
= trans
->Read(buf
.get(), kReadSize
, read_callback
.callback());
4148 ASSERT_EQ(ERR_IO_PENDING
, rv
) << "Unexpected read: " << rv
;
4150 // Complete the read now, which causes buffering to start.
4151 data
.CompleteRead();
4152 // Destroy the transaction, causing the stream to get cancelled
4153 // and orphaning the buffered IO task.
4154 helper
.ResetTrans();
4156 // Flush the MessageLoop; this will cause the buffered IO task
4157 // to run for the final time.
4158 base::RunLoop().RunUntilIdle();
4160 // Verify that we consumed all test data.
4161 helper
.VerifyDataConsumed();
4164 // Test that if the server requests persistence of settings, that we save
4165 // the settings in the HttpServerProperties.
4166 TEST_P(SpdyNetworkTransactionTest
, SettingsSaved
) {
4167 if (spdy_util_
.spdy_version() >= SPDY4
) {
4168 // SPDY4 doesn't support settings persistence.
4171 static const SpdyHeaderInfo kSynReplyInfo
= {
4172 SYN_REPLY
, // Syn Reply
4174 0, // Associated Stream ID
4175 ConvertRequestPriorityToSpdyPriority(
4176 LOWEST
, spdy_util_
.spdy_version()),
4177 kSpdyCredentialSlotUnused
,
4178 CONTROL_FLAG_NONE
, // Control Flags
4179 false, // Compressed
4180 RST_STREAM_INVALID
, // Status
4183 DATA_FLAG_NONE
// Data Flags
4186 BoundNetLog net_log
;
4187 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
4188 net_log
, GetParam(), NULL
);
4189 helper
.RunPreTestSetup();
4191 // Verify that no settings exist initially.
4192 HostPortPair
host_port_pair("www.google.com", helper
.port());
4193 SpdySessionPool
* spdy_session_pool
= helper
.session()->spdy_session_pool();
4194 EXPECT_TRUE(spdy_session_pool
->http_server_properties()->GetSpdySettings(
4195 host_port_pair
).empty());
4197 // Construct the request.
4198 scoped_ptr
<SpdyFrame
> req(
4199 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
4200 MockWrite writes
[] = { CreateMockWrite(*req
) };
4202 // Construct the reply.
4203 scoped_ptr
<SpdyHeaderBlock
> reply_headers(new SpdyHeaderBlock());
4204 (*reply_headers
)[spdy_util_
.GetStatusKey()] = "200";
4205 (*reply_headers
)[spdy_util_
.GetVersionKey()] = "HTTP/1.1";
4206 scoped_ptr
<SpdyFrame
> reply(
4207 spdy_util_
.ConstructSpdyFrame(kSynReplyInfo
, reply_headers
.Pass()));
4209 const SpdySettingsIds kSampleId1
= SETTINGS_UPLOAD_BANDWIDTH
;
4210 unsigned int kSampleValue1
= 0x0a0a0a0a;
4211 const SpdySettingsIds kSampleId2
= SETTINGS_DOWNLOAD_BANDWIDTH
;
4212 unsigned int kSampleValue2
= 0x0b0b0b0b;
4213 const SpdySettingsIds kSampleId3
= SETTINGS_ROUND_TRIP_TIME
;
4214 unsigned int kSampleValue3
= 0x0c0c0c0c;
4215 scoped_ptr
<SpdyFrame
> settings_frame
;
4217 // Construct the SETTINGS frame.
4218 SettingsMap settings
;
4219 // First add a persisted setting.
4220 settings
[kSampleId1
] =
4221 SettingsFlagsAndValue(SETTINGS_FLAG_PLEASE_PERSIST
, kSampleValue1
);
4222 // Next add a non-persisted setting.
4223 settings
[kSampleId2
] =
4224 SettingsFlagsAndValue(SETTINGS_FLAG_NONE
, kSampleValue2
);
4225 // Next add another persisted setting.
4226 settings
[kSampleId3
] =
4227 SettingsFlagsAndValue(SETTINGS_FLAG_PLEASE_PERSIST
, kSampleValue3
);
4228 settings_frame
.reset(spdy_util_
.ConstructSpdySettings(settings
));
4231 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
4232 MockRead reads
[] = {
4233 CreateMockRead(*reply
),
4234 CreateMockRead(*body
),
4235 CreateMockRead(*settings_frame
),
4236 MockRead(ASYNC
, 0, 0) // EOF
4239 DelayedSocketData
data(1, reads
, arraysize(reads
),
4240 writes
, arraysize(writes
));
4241 helper
.AddData(&data
);
4242 helper
.RunDefaultTest();
4243 helper
.VerifyDataConsumed();
4244 TransactionHelperResult out
= helper
.output();
4245 EXPECT_EQ(OK
, out
.rv
);
4246 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
4247 EXPECT_EQ("hello!", out
.response_data
);
4250 // Verify we had two persisted settings.
4251 const SettingsMap
& settings_map
=
4252 spdy_session_pool
->http_server_properties()->GetSpdySettings(
4254 ASSERT_EQ(2u, settings_map
.size());
4256 // Verify the first persisted setting.
4257 SettingsMap::const_iterator it1
= settings_map
.find(kSampleId1
);
4258 EXPECT_TRUE(it1
!= settings_map
.end());
4259 SettingsFlagsAndValue flags_and_value1
= it1
->second
;
4260 EXPECT_EQ(SETTINGS_FLAG_PERSISTED
, flags_and_value1
.first
);
4261 EXPECT_EQ(kSampleValue1
, flags_and_value1
.second
);
4263 // Verify the second persisted setting.
4264 SettingsMap::const_iterator it3
= settings_map
.find(kSampleId3
);
4265 EXPECT_TRUE(it3
!= settings_map
.end());
4266 SettingsFlagsAndValue flags_and_value3
= it3
->second
;
4267 EXPECT_EQ(SETTINGS_FLAG_PERSISTED
, flags_and_value3
.first
);
4268 EXPECT_EQ(kSampleValue3
, flags_and_value3
.second
);
4272 // Test that when there are settings saved that they are sent back to the
4273 // server upon session establishment.
4274 TEST_P(SpdyNetworkTransactionTest
, SettingsPlayback
) {
4275 if (spdy_util_
.spdy_version() >= SPDY4
) {
4276 // SPDY4 doesn't support settings persistence.
4279 static const SpdyHeaderInfo kSynReplyInfo
= {
4280 SYN_REPLY
, // Syn Reply
4282 0, // Associated Stream ID
4283 ConvertRequestPriorityToSpdyPriority(
4284 LOWEST
, spdy_util_
.spdy_version()),
4285 kSpdyCredentialSlotUnused
,
4286 CONTROL_FLAG_NONE
, // Control Flags
4287 false, // Compressed
4288 RST_STREAM_INVALID
, // Status
4291 DATA_FLAG_NONE
// Data Flags
4294 BoundNetLog net_log
;
4295 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
4296 net_log
, GetParam(), NULL
);
4297 helper
.RunPreTestSetup();
4299 SpdySessionPool
* spdy_session_pool
= helper
.session()->spdy_session_pool();
4301 SpdySessionPoolPeer
pool_peer(spdy_session_pool
);
4302 pool_peer
.SetEnableSendingInitialData(true);
4304 // Verify that no settings exist initially.
4305 HostPortPair
host_port_pair("www.google.com", helper
.port());
4306 EXPECT_TRUE(spdy_session_pool
->http_server_properties()->GetSpdySettings(
4307 host_port_pair
).empty());
4309 const SpdySettingsIds kSampleId1
= SETTINGS_MAX_CONCURRENT_STREAMS
;
4310 unsigned int kSampleValue1
= 0x0a0a0a0a;
4311 const SpdySettingsIds kSampleId2
= SETTINGS_INITIAL_WINDOW_SIZE
;
4312 unsigned int kSampleValue2
= 0x0c0c0c0c;
4314 // First add a persisted setting.
4315 spdy_session_pool
->http_server_properties()->SetSpdySetting(
4318 SETTINGS_FLAG_PLEASE_PERSIST
,
4321 // Next add another persisted setting.
4322 spdy_session_pool
->http_server_properties()->SetSpdySetting(
4325 SETTINGS_FLAG_PLEASE_PERSIST
,
4328 EXPECT_EQ(2u, spdy_session_pool
->http_server_properties()->GetSpdySettings(
4329 host_port_pair
).size());
4331 // Construct the initial SETTINGS frame.
4332 SettingsMap initial_settings
;
4333 initial_settings
[SETTINGS_MAX_CONCURRENT_STREAMS
] =
4334 SettingsFlagsAndValue(SETTINGS_FLAG_NONE
, kMaxConcurrentPushedStreams
);
4335 scoped_ptr
<SpdyFrame
> initial_settings_frame(
4336 spdy_util_
.ConstructSpdySettings(initial_settings
));
4338 // Construct the persisted SETTINGS frame.
4339 const SettingsMap
& settings
=
4340 spdy_session_pool
->http_server_properties()->GetSpdySettings(
4342 scoped_ptr
<SpdyFrame
> settings_frame(
4343 spdy_util_
.ConstructSpdySettings(settings
));
4345 // Construct the request.
4346 scoped_ptr
<SpdyFrame
> req(
4347 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
4349 std::vector
<MockWrite
> writes
;
4350 if ((GetParam().protocol
>= kProtoSPDY4MinimumVersion
) &&
4351 (GetParam().protocol
<= kProtoSPDY4MaximumVersion
)) {
4354 kHttp2ConnectionHeaderPrefix
,
4355 kHttp2ConnectionHeaderPrefixSize
));
4357 writes
.push_back(CreateMockWrite(*initial_settings_frame
));
4358 writes
.push_back(CreateMockWrite(*settings_frame
));
4359 writes
.push_back(CreateMockWrite(*req
));
4361 // Construct the reply.
4362 scoped_ptr
<SpdyHeaderBlock
> reply_headers(new SpdyHeaderBlock());
4363 (*reply_headers
)[spdy_util_
.GetStatusKey()] = "200";
4364 (*reply_headers
)[spdy_util_
.GetVersionKey()] = "HTTP/1.1";
4365 scoped_ptr
<SpdyFrame
> reply(
4366 spdy_util_
.ConstructSpdyFrame(kSynReplyInfo
, reply_headers
.Pass()));
4368 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
4369 MockRead reads
[] = {
4370 CreateMockRead(*reply
),
4371 CreateMockRead(*body
),
4372 MockRead(ASYNC
, 0, 0) // EOF
4375 DelayedSocketData
data(2, reads
, arraysize(reads
),
4376 vector_as_array(&writes
), writes
.size());
4377 helper
.AddData(&data
);
4378 helper
.RunDefaultTest();
4379 helper
.VerifyDataConsumed();
4380 TransactionHelperResult out
= helper
.output();
4381 EXPECT_EQ(OK
, out
.rv
);
4382 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
4383 EXPECT_EQ("hello!", out
.response_data
);
4386 // Verify we had two persisted settings.
4387 const SettingsMap
& settings_map
=
4388 spdy_session_pool
->http_server_properties()->GetSpdySettings(
4390 ASSERT_EQ(2u, settings_map
.size());
4392 // Verify the first persisted setting.
4393 SettingsMap::const_iterator it1
= settings_map
.find(kSampleId1
);
4394 EXPECT_TRUE(it1
!= settings_map
.end());
4395 SettingsFlagsAndValue flags_and_value1
= it1
->second
;
4396 EXPECT_EQ(SETTINGS_FLAG_PERSISTED
, flags_and_value1
.first
);
4397 EXPECT_EQ(kSampleValue1
, flags_and_value1
.second
);
4399 // Verify the second persisted setting.
4400 SettingsMap::const_iterator it2
= settings_map
.find(kSampleId2
);
4401 EXPECT_TRUE(it2
!= settings_map
.end());
4402 SettingsFlagsAndValue flags_and_value2
= it2
->second
;
4403 EXPECT_EQ(SETTINGS_FLAG_PERSISTED
, flags_and_value2
.first
);
4404 EXPECT_EQ(kSampleValue2
, flags_and_value2
.second
);
4408 TEST_P(SpdyNetworkTransactionTest
, GoAwayWithActiveStream
) {
4409 scoped_ptr
<SpdyFrame
> req(
4410 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
4411 MockWrite writes
[] = { CreateMockWrite(*req
) };
4413 scoped_ptr
<SpdyFrame
> go_away(spdy_util_
.ConstructSpdyGoAway());
4414 MockRead reads
[] = {
4415 CreateMockRead(*go_away
),
4418 DelayedSocketData
data(1, reads
, arraysize(reads
),
4419 writes
, arraysize(writes
));
4420 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
4421 BoundNetLog(), GetParam(), NULL
);
4422 helper
.AddData(&data
);
4423 helper
.RunToCompletion(&data
);
4424 TransactionHelperResult out
= helper
.output();
4425 EXPECT_EQ(ERR_ABORTED
, out
.rv
);
4428 TEST_P(SpdyNetworkTransactionTest
, CloseWithActiveStream
) {
4429 scoped_ptr
<SpdyFrame
> req(
4430 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
4431 MockWrite writes
[] = { CreateMockWrite(*req
) };
4433 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
4434 MockRead reads
[] = {
4435 CreateMockRead(*resp
),
4436 MockRead(SYNCHRONOUS
, 0, 0) // EOF
4439 DelayedSocketData
data(1, reads
, arraysize(reads
),
4440 writes
, arraysize(writes
));
4442 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
4443 log
, GetParam(), NULL
);
4444 helper
.RunPreTestSetup();
4445 helper
.AddData(&data
);
4446 HttpNetworkTransaction
* trans
= helper
.trans();
4448 TestCompletionCallback callback
;
4449 TransactionHelperResult out
;
4450 out
.rv
= trans
->Start(&CreateGetRequest(), callback
.callback(), log
);
4452 EXPECT_EQ(out
.rv
, ERR_IO_PENDING
);
4453 out
.rv
= callback
.WaitForResult();
4454 EXPECT_EQ(out
.rv
, OK
);
4456 const HttpResponseInfo
* response
= trans
->GetResponseInfo();
4457 EXPECT_TRUE(response
->headers
.get() != NULL
);
4458 EXPECT_TRUE(response
->was_fetched_via_spdy
);
4459 out
.rv
= ReadTransaction(trans
, &out
.response_data
);
4460 EXPECT_EQ(ERR_CONNECTION_CLOSED
, out
.rv
);
4462 // Verify that we consumed all test data.
4463 helper
.VerifyDataConsumed();
4466 // HTTP_1_1_REQUIRED results in ERR_HTTP_1_1_REQUIRED.
4467 TEST_P(SpdyNetworkTransactionTest
, HTTP11RequiredError
) {
4468 // HTTP_1_1_REQUIRED is only supported by SPDY4.
4469 if (spdy_util_
.spdy_version() < SPDY4
)
4472 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
4473 BoundNetLog(), GetParam(), nullptr);
4475 scoped_ptr
<SpdyFrame
> go_away(spdy_util_
.ConstructSpdyGoAway(
4476 0, GOAWAY_HTTP_1_1_REQUIRED
, "Try again using HTTP/1.1 please."));
4477 MockRead reads
[] = {
4478 CreateMockRead(*go_away
),
4480 DelayedSocketData
data(0, reads
, arraysize(reads
), nullptr, 0);
4482 helper
.RunToCompletion(&data
);
4483 TransactionHelperResult out
= helper
.output();
4484 EXPECT_EQ(ERR_HTTP_1_1_REQUIRED
, out
.rv
);
4487 // Retry with HTTP/1.1 when receiving HTTP_1_1_REQUIRED. Note that no actual
4488 // protocol negotiation happens, instead this test forces protocols for both
4490 TEST_P(SpdyNetworkTransactionTest
, HTTP11RequiredRetry
) {
4491 // HTTP_1_1_REQUIRED is only supported by SPDY4.
4492 if (spdy_util_
.spdy_version() < SPDY4
)
4494 // HTTP_1_1_REQUIRED implementation relies on the assumption that HTTP/2 is
4495 // only spoken over SSL.
4496 if (GetParam().ssl_type
!= HTTPS_SPDY_VIA_NPN
)
4499 HttpRequestInfo request
;
4500 request
.method
= "GET";
4501 request
.url
= GURL(GetDefaultUrl());
4502 scoped_ptr
<SpdySessionDependencies
> session_deps(
4503 CreateSpdySessionDependencies(GetParam()));
4504 // Do not force SPDY so that second socket can negotiate HTTP/1.1.
4505 session_deps
->next_protos
= SpdyNextProtos();
4506 NormalSpdyTransactionHelper
helper(request
, DEFAULT_PRIORITY
, BoundNetLog(),
4507 GetParam(), session_deps
.release());
4509 // First socket: HTTP/2 request rejected with HTTP_1_1_REQUIRED.
4510 const char* url
= request
.url
.spec().c_str();
4511 scoped_ptr
<SpdyHeaderBlock
> headers(spdy_util_
.ConstructGetHeaderBlock(url
));
4512 scoped_ptr
<SpdyFrame
> req(
4513 spdy_util_
.ConstructSpdySyn(1, *headers
, LOWEST
, false, true));
4514 MockWrite writes0
[] = {CreateMockWrite(*req
)};
4515 scoped_ptr
<SpdyFrame
> go_away(spdy_util_
.ConstructSpdyGoAway(
4516 0, GOAWAY_HTTP_1_1_REQUIRED
, "Try again using HTTP/1.1 please."));
4517 MockRead reads0
[] = {CreateMockRead(*go_away
)};
4518 DelayedSocketData
data0(1, reads0
, arraysize(reads0
), writes0
,
4519 arraysize(writes0
));
4521 scoped_ptr
<SSLSocketDataProvider
> ssl_provider0(
4522 new SSLSocketDataProvider(ASYNC
, OK
));
4523 // Expect HTTP/2 protocols too in SSLConfig.
4524 ssl_provider0
->next_protos_expected_in_ssl_config
.push_back(kProtoHTTP11
);
4525 ssl_provider0
->next_protos_expected_in_ssl_config
.push_back(kProtoSPDY31
);
4526 ssl_provider0
->next_protos_expected_in_ssl_config
.push_back(kProtoSPDY4_14
);
4527 ssl_provider0
->next_protos_expected_in_ssl_config
.push_back(kProtoSPDY4
);
4529 ssl_provider0
->SetNextProto(GetParam().protocol
);
4530 helper
.AddDataWithSSLSocketDataProvider(&data0
, ssl_provider0
.Pass());
4532 // Second socket: falling back to HTTP/1.1.
4533 MockWrite writes1
[] = {MockWrite(
4534 "GET / HTTP/1.1\r\n"
4535 "Host: www.google.com\r\n"
4536 "Connection: keep-alive\r\n\r\n")};
4537 MockRead reads1
[] = {MockRead(
4538 "HTTP/1.1 200 OK\r\n"
4539 "Content-Length: 5\r\n\r\n"
4541 DelayedSocketData
data1(1, reads1
, arraysize(reads1
), writes1
,
4542 arraysize(writes1
));
4544 scoped_ptr
<SSLSocketDataProvider
> ssl_provider1(
4545 new SSLSocketDataProvider(ASYNC
, OK
));
4546 // Expect only HTTP/1.1 protocol in SSLConfig.
4547 ssl_provider1
->next_protos_expected_in_ssl_config
.push_back(kProtoHTTP11
);
4549 ssl_provider1
->SetNextProto(kProtoHTTP11
);
4550 helper
.AddDataWithSSLSocketDataProvider(&data1
, ssl_provider1
.Pass());
4552 base::WeakPtr
<HttpServerProperties
> http_server_properties
=
4553 helper
.session()->spdy_session_pool()->http_server_properties();
4554 const HostPortPair host_port_pair
= HostPortPair::FromURL(GURL(url
));
4555 EXPECT_FALSE(http_server_properties
->RequiresHTTP11(host_port_pair
));
4557 helper
.RunPreTestSetup();
4558 helper
.StartDefaultTest();
4559 helper
.FinishDefaultTestWithoutVerification();
4560 helper
.VerifyDataConsumed();
4561 EXPECT_TRUE(http_server_properties
->RequiresHTTP11(host_port_pair
));
4563 const HttpResponseInfo
* response
= helper
.trans()->GetResponseInfo();
4564 ASSERT_TRUE(response
!= nullptr);
4565 ASSERT_TRUE(response
->headers
.get() != nullptr);
4566 EXPECT_EQ("HTTP/1.1 200 OK", response
->headers
->GetStatusLine());
4567 EXPECT_FALSE(response
->was_fetched_via_spdy
);
4568 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP1
, response
->connection_info
);
4569 EXPECT_TRUE(response
->was_npn_negotiated
);
4570 EXPECT_TRUE(request
.url
.SchemeIs("https"));
4571 EXPECT_EQ("127.0.0.1", response
->socket_address
.host());
4572 EXPECT_EQ(443, response
->socket_address
.port());
4573 std::string response_data
;
4574 ASSERT_EQ(OK
, ReadTransaction(helper
.trans(), &response_data
));
4575 EXPECT_EQ("hello", response_data
);
4578 // Retry with HTTP/1.1 to the proxy when receiving HTTP_1_1_REQUIRED from the
4579 // proxy. Note that no actual protocol negotiation happens, instead this test
4580 // forces protocols for both sockets.
4581 TEST_P(SpdyNetworkTransactionTest
, HTTP11RequiredProxyRetry
) {
4582 // HTTP_1_1_REQUIRED is only supported by SPDY4.
4583 if (spdy_util_
.spdy_version() < SPDY4
)
4585 // HTTP_1_1_REQUIRED implementation relies on the assumption that HTTP/2 is
4586 // only spoken over SSL.
4587 if (GetParam().ssl_type
!= HTTPS_SPDY_VIA_NPN
)
4590 HttpRequestInfo request
;
4591 request
.method
= "GET";
4592 request
.url
= GURL("https://www.google.com/");
4593 scoped_ptr
<SpdySessionDependencies
> session_deps(
4594 CreateSpdySessionDependencies(
4596 ProxyService::CreateFixedFromPacResult("HTTPS myproxy:70")));
4597 // Do not force SPDY so that second socket can negotiate HTTP/1.1.
4598 session_deps
->next_protos
= SpdyNextProtos();
4599 NormalSpdyTransactionHelper
helper(request
, DEFAULT_PRIORITY
, BoundNetLog(),
4600 GetParam(), session_deps
.release());
4602 // First socket: HTTP/2 CONNECT rejected with HTTP_1_1_REQUIRED.
4603 scoped_ptr
<SpdyFrame
> req(spdy_util_
.ConstructSpdyConnect(
4604 nullptr, 0, 1, LOWEST
, HostPortPair("www.google.com", 443)));
4605 MockWrite writes0
[] = {CreateMockWrite(*req
)};
4606 scoped_ptr
<SpdyFrame
> go_away(spdy_util_
.ConstructSpdyGoAway(
4607 0, GOAWAY_HTTP_1_1_REQUIRED
, "Try again using HTTP/1.1 please."));
4608 MockRead reads0
[] = {CreateMockRead(*go_away
)};
4609 DelayedSocketData
data0(1, reads0
, arraysize(reads0
), writes0
,
4610 arraysize(writes0
));
4612 scoped_ptr
<SSLSocketDataProvider
> ssl_provider0(
4613 new SSLSocketDataProvider(ASYNC
, OK
));
4614 // Expect HTTP/2 protocols too in SSLConfig.
4615 ssl_provider0
->next_protos_expected_in_ssl_config
.push_back(kProtoHTTP11
);
4616 ssl_provider0
->next_protos_expected_in_ssl_config
.push_back(kProtoSPDY31
);
4617 ssl_provider0
->next_protos_expected_in_ssl_config
.push_back(kProtoSPDY4_14
);
4618 ssl_provider0
->next_protos_expected_in_ssl_config
.push_back(kProtoSPDY4
);
4620 ssl_provider0
->SetNextProto(GetParam().protocol
);
4621 helper
.AddDataWithSSLSocketDataProvider(&data0
, ssl_provider0
.Pass());
4623 // Second socket: retry using HTTP/1.1.
4624 MockWrite writes1
[] = {
4626 "CONNECT www.google.com:443 HTTP/1.1\r\n"
4627 "Host: www.google.com\r\n"
4628 "Proxy-Connection: keep-alive\r\n\r\n"),
4630 "GET / HTTP/1.1\r\n"
4631 "Host: www.google.com\r\n"
4632 "Connection: keep-alive\r\n\r\n"),
4635 MockRead reads1
[] = {
4636 MockRead(ASYNC
, 2, "HTTP/1.1 200 OK\r\n\r\n"),
4638 "HTTP/1.1 200 OK\r\n"
4639 "Content-Length: 5\r\n\r\n"
4642 DelayedSocketData
data1(1, reads1
, arraysize(reads1
), writes1
,
4643 arraysize(writes1
));
4645 scoped_ptr
<SSLSocketDataProvider
> ssl_provider1(
4646 new SSLSocketDataProvider(ASYNC
, OK
));
4647 // Expect only HTTP/1.1 protocol in SSLConfig.
4648 ssl_provider1
->next_protos_expected_in_ssl_config
.push_back(kProtoHTTP11
);
4650 ssl_provider1
->SetNextProto(kProtoHTTP11
);
4651 helper
.AddDataWithSSLSocketDataProvider(&data1
, ssl_provider1
.Pass());
4653 // A third socket is needed for the tunnelled connection.
4654 scoped_ptr
<SSLSocketDataProvider
> ssl_provider2(
4655 new SSLSocketDataProvider(ASYNC
, OK
));
4656 helper
.session_deps()->socket_factory
->AddSSLSocketDataProvider(
4657 ssl_provider2
.get());
4659 base::WeakPtr
<HttpServerProperties
> http_server_properties
=
4660 helper
.session()->spdy_session_pool()->http_server_properties();
4661 const HostPortPair proxy_host_port_pair
= HostPortPair("myproxy", 70);
4662 EXPECT_FALSE(http_server_properties
->RequiresHTTP11(proxy_host_port_pair
));
4664 helper
.RunPreTestSetup();
4665 helper
.StartDefaultTest();
4666 helper
.FinishDefaultTestWithoutVerification();
4667 helper
.VerifyDataConsumed();
4668 EXPECT_TRUE(http_server_properties
->RequiresHTTP11(proxy_host_port_pair
));
4670 const HttpResponseInfo
* response
= helper
.trans()->GetResponseInfo();
4671 ASSERT_TRUE(response
!= nullptr);
4672 ASSERT_TRUE(response
->headers
.get() != nullptr);
4673 EXPECT_EQ("HTTP/1.1 200 OK", response
->headers
->GetStatusLine());
4674 EXPECT_FALSE(response
->was_fetched_via_spdy
);
4675 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP1
, response
->connection_info
);
4676 EXPECT_FALSE(response
->was_npn_negotiated
);
4677 EXPECT_TRUE(request
.url
.SchemeIs("https"));
4678 EXPECT_EQ("127.0.0.1", response
->socket_address
.host());
4679 EXPECT_EQ(70, response
->socket_address
.port());
4680 std::string response_data
;
4681 ASSERT_EQ(OK
, ReadTransaction(helper
.trans(), &response_data
));
4682 EXPECT_EQ("hello", response_data
);
4685 // Test to make sure we can correctly connect through a proxy.
4686 TEST_P(SpdyNetworkTransactionTest
, ProxyConnect
) {
4687 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
4688 BoundNetLog(), GetParam(), NULL
);
4689 helper
.session_deps().reset(CreateSpdySessionDependencies(
4691 ProxyService::CreateFixedFromPacResult("PROXY myproxy:70")));
4692 helper
.SetSession(make_scoped_refptr(
4693 SpdySessionDependencies::SpdyCreateSession(helper
.session_deps().get())));
4694 helper
.RunPreTestSetup();
4695 HttpNetworkTransaction
* trans
= helper
.trans();
4697 const char kConnect443
[] = {
4698 "CONNECT www.google.com:443 HTTP/1.1\r\n"
4699 "Host: www.google.com\r\n"
4700 "Proxy-Connection: keep-alive\r\n\r\n"};
4701 const char kHTTP200
[] = {"HTTP/1.1 200 OK\r\n\r\n"};
4702 scoped_ptr
<SpdyFrame
> req(
4703 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
4704 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
4705 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
4707 MockWrite writes
[] = {
4708 MockWrite(SYNCHRONOUS
, kConnect443
, arraysize(kConnect443
) - 1, 0),
4709 CreateMockWrite(*req
, 2),
4711 MockRead reads
[] = {
4712 MockRead(SYNCHRONOUS
, kHTTP200
, arraysize(kHTTP200
) - 1, 1),
4713 CreateMockRead(*resp
, 3),
4714 CreateMockRead(*body
.get(), 4),
4715 MockRead(ASYNC
, 0, 0, 5),
4717 scoped_ptr
<OrderedSocketData
> data(new OrderedSocketData(
4718 reads
, arraysize(reads
), writes
, arraysize(writes
)));
4720 helper
.AddData(data
.get());
4721 TestCompletionCallback callback
;
4723 int rv
= trans
->Start(
4724 &CreateGetRequest(), callback
.callback(), BoundNetLog());
4725 EXPECT_EQ(ERR_IO_PENDING
, rv
);
4727 rv
= callback
.WaitForResult();
4730 // Verify the SYN_REPLY.
4731 HttpResponseInfo response
= *trans
->GetResponseInfo();
4732 EXPECT_TRUE(response
.headers
.get() != NULL
);
4733 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
4735 std::string response_data
;
4736 ASSERT_EQ(OK
, ReadTransaction(trans
, &response_data
));
4737 EXPECT_EQ("hello!", response_data
);
4738 helper
.VerifyDataConsumed();
4741 // Test to make sure we can correctly connect through a proxy to www.google.com,
4742 // if there already exists a direct spdy connection to www.google.com. See
4743 // http://crbug.com/49874
4744 TEST_P(SpdyNetworkTransactionTest
, DirectConnectProxyReconnect
) {
4745 // When setting up the first transaction, we store the SpdySessionPool so that
4746 // we can use the same pool in the second transaction.
4747 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
4748 BoundNetLog(), GetParam(), NULL
);
4750 // Use a proxy service which returns a proxy fallback list from DIRECT to
4751 // myproxy:70. For this test there will be no fallback, so it is equivalent
4752 // to simply DIRECT. The reason for appending the second proxy is to verify
4753 // that the session pool key used does is just "DIRECT".
4754 helper
.session_deps().reset(CreateSpdySessionDependencies(
4756 ProxyService::CreateFixedFromPacResult("DIRECT; PROXY myproxy:70")));
4757 helper
.SetSession(make_scoped_refptr(
4758 SpdySessionDependencies::SpdyCreateSession(helper
.session_deps().get())));
4760 SpdySessionPool
* spdy_session_pool
= helper
.session()->spdy_session_pool();
4761 helper
.RunPreTestSetup();
4763 // Construct and send a simple GET request.
4764 scoped_ptr
<SpdyFrame
> req(
4765 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
4766 MockWrite writes
[] = {
4767 CreateMockWrite(*req
, 1),
4770 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
4771 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
4772 MockRead reads
[] = {
4773 CreateMockRead(*resp
, 2),
4774 CreateMockRead(*body
, 3),
4775 MockRead(ASYNC
, ERR_IO_PENDING
, 4), // Force a pause
4776 MockRead(ASYNC
, 0, 5) // EOF
4778 OrderedSocketData
data(reads
, arraysize(reads
),
4779 writes
, arraysize(writes
));
4780 helper
.AddData(&data
);
4781 HttpNetworkTransaction
* trans
= helper
.trans();
4783 TestCompletionCallback callback
;
4784 TransactionHelperResult out
;
4785 out
.rv
= trans
->Start(
4786 &CreateGetRequest(), callback
.callback(), BoundNetLog());
4788 EXPECT_EQ(out
.rv
, ERR_IO_PENDING
);
4789 out
.rv
= callback
.WaitForResult();
4790 EXPECT_EQ(out
.rv
, OK
);
4792 const HttpResponseInfo
* response
= trans
->GetResponseInfo();
4793 EXPECT_TRUE(response
->headers
.get() != NULL
);
4794 EXPECT_TRUE(response
->was_fetched_via_spdy
);
4795 out
.rv
= ReadTransaction(trans
, &out
.response_data
);
4796 EXPECT_EQ(OK
, out
.rv
);
4797 out
.status_line
= response
->headers
->GetStatusLine();
4798 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
4799 EXPECT_EQ("hello!", out
.response_data
);
4801 // Check that the SpdySession is still in the SpdySessionPool.
4802 HostPortPair
host_port_pair("www.google.com", helper
.port());
4803 SpdySessionKey
session_pool_key_direct(
4804 host_port_pair
, ProxyServer::Direct(), PRIVACY_MODE_DISABLED
);
4805 EXPECT_TRUE(HasSpdySession(spdy_session_pool
, session_pool_key_direct
));
4806 SpdySessionKey
session_pool_key_proxy(
4808 ProxyServer::FromURI("www.foo.com", ProxyServer::SCHEME_HTTP
),
4809 PRIVACY_MODE_DISABLED
);
4810 EXPECT_FALSE(HasSpdySession(spdy_session_pool
, session_pool_key_proxy
));
4812 // Set up data for the proxy connection.
4813 const char kConnect443
[] = {"CONNECT www.google.com:443 HTTP/1.1\r\n"
4814 "Host: www.google.com\r\n"
4815 "Proxy-Connection: keep-alive\r\n\r\n"};
4816 const char kHTTP200
[] = {"HTTP/1.1 200 OK\r\n\r\n"};
4817 scoped_ptr
<SpdyFrame
> req2(spdy_util_
.ConstructSpdyGet(
4818 GetDefaultUrlWithPath("/foo.dat").c_str(), false, 1, LOWEST
));
4819 scoped_ptr
<SpdyFrame
> resp2(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
4820 scoped_ptr
<SpdyFrame
> body2(spdy_util_
.ConstructSpdyBodyFrame(1, true));
4822 MockWrite writes2
[] = {
4823 MockWrite(SYNCHRONOUS
, kConnect443
, arraysize(kConnect443
) - 1, 0),
4824 CreateMockWrite(*req2
, 2),
4826 MockRead reads2
[] = {
4827 MockRead(SYNCHRONOUS
, kHTTP200
, arraysize(kHTTP200
) - 1, 1),
4828 CreateMockRead(*resp2
, 3),
4829 CreateMockRead(*body2
, 4),
4830 MockRead(ASYNC
, 0, 5) // EOF
4833 scoped_ptr
<OrderedSocketData
> data_proxy(new OrderedSocketData(
4834 reads2
, arraysize(reads2
), writes2
, arraysize(writes2
)));
4836 // Create another request to www.google.com, but this time through a proxy.
4837 HttpRequestInfo request_proxy
;
4838 request_proxy
.method
= "GET";
4839 request_proxy
.url
= GURL(GetDefaultUrlWithPath("/foo.dat"));
4840 request_proxy
.load_flags
= 0;
4841 scoped_ptr
<SpdySessionDependencies
> ssd_proxy(
4842 CreateSpdySessionDependencies(GetParam()));
4843 // Ensure that this transaction uses the same SpdySessionPool.
4844 scoped_refptr
<HttpNetworkSession
> session_proxy(
4845 SpdySessionDependencies::SpdyCreateSession(ssd_proxy
.get()));
4846 NormalSpdyTransactionHelper
helper_proxy(request_proxy
, DEFAULT_PRIORITY
,
4847 BoundNetLog(), GetParam(), NULL
);
4848 HttpNetworkSessionPeer
session_peer(session_proxy
);
4849 scoped_ptr
<ProxyService
> proxy_service(
4850 ProxyService::CreateFixedFromPacResult("PROXY myproxy:70"));
4851 session_peer
.SetProxyService(proxy_service
.get());
4852 helper_proxy
.session_deps().swap(ssd_proxy
);
4853 helper_proxy
.SetSession(session_proxy
);
4854 helper_proxy
.RunPreTestSetup();
4855 helper_proxy
.AddData(data_proxy
.get());
4857 HttpNetworkTransaction
* trans_proxy
= helper_proxy
.trans();
4858 TestCompletionCallback callback_proxy
;
4859 int rv
= trans_proxy
->Start(
4860 &request_proxy
, callback_proxy
.callback(), BoundNetLog());
4861 EXPECT_EQ(ERR_IO_PENDING
, rv
);
4862 rv
= callback_proxy
.WaitForResult();
4865 HttpResponseInfo response_proxy
= *trans_proxy
->GetResponseInfo();
4866 EXPECT_TRUE(response_proxy
.headers
.get() != NULL
);
4867 EXPECT_EQ("HTTP/1.1 200 OK", response_proxy
.headers
->GetStatusLine());
4869 std::string response_data
;
4870 ASSERT_EQ(OK
, ReadTransaction(trans_proxy
, &response_data
));
4871 EXPECT_EQ("hello!", response_data
);
4873 data
.CompleteRead();
4874 helper_proxy
.VerifyDataConsumed();
4877 // When we get a TCP-level RST, we need to retry a HttpNetworkTransaction
4878 // on a new connection, if the connection was previously known to be good.
4879 // This can happen when a server reboots without saying goodbye, or when
4880 // we're behind a NAT that masked the RST.
4881 TEST_P(SpdyNetworkTransactionTest
, VerifyRetryOnConnectionReset
) {
4882 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
4883 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
4884 MockRead reads
[] = {
4885 CreateMockRead(*resp
),
4886 CreateMockRead(*body
),
4887 MockRead(ASYNC
, ERR_IO_PENDING
),
4888 MockRead(ASYNC
, ERR_CONNECTION_RESET
),
4891 MockRead reads2
[] = {
4892 CreateMockRead(*resp
),
4893 CreateMockRead(*body
),
4894 MockRead(ASYNC
, 0, 0) // EOF
4897 // This test has a couple of variants.
4899 // Induce the RST while waiting for our transaction to send.
4900 VARIANT_RST_DURING_SEND_COMPLETION
,
4901 // Induce the RST while waiting for our transaction to read.
4902 // In this case, the send completed - everything copied into the SNDBUF.
4903 VARIANT_RST_DURING_READ_COMPLETION
4906 for (int variant
= VARIANT_RST_DURING_SEND_COMPLETION
;
4907 variant
<= VARIANT_RST_DURING_READ_COMPLETION
;
4909 DelayedSocketData
data1(1, reads
, arraysize(reads
), NULL
, 0);
4911 DelayedSocketData
data2(1, reads2
, arraysize(reads2
), NULL
, 0);
4913 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
4914 BoundNetLog(), GetParam(), NULL
);
4915 helper
.AddData(&data1
);
4916 helper
.AddData(&data2
);
4917 helper
.RunPreTestSetup();
4919 for (int i
= 0; i
< 2; ++i
) {
4920 scoped_ptr
<HttpNetworkTransaction
> trans(
4921 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
4923 TestCompletionCallback callback
;
4924 int rv
= trans
->Start(
4925 &helper
.request(), callback
.callback(), BoundNetLog());
4926 EXPECT_EQ(ERR_IO_PENDING
, rv
);
4927 // On the second transaction, we trigger the RST.
4929 if (variant
== VARIANT_RST_DURING_READ_COMPLETION
) {
4930 // Writes to the socket complete asynchronously on SPDY by running
4931 // through the message loop. Complete the write here.
4932 base::RunLoop().RunUntilIdle();
4935 // Now schedule the ERR_CONNECTION_RESET.
4936 EXPECT_EQ(3u, data1
.read_index());
4937 data1
.CompleteRead();
4938 EXPECT_EQ(4u, data1
.read_index());
4940 rv
= callback
.WaitForResult();
4943 const HttpResponseInfo
* response
= trans
->GetResponseInfo();
4944 ASSERT_TRUE(response
!= NULL
);
4945 EXPECT_TRUE(response
->headers
.get() != NULL
);
4946 EXPECT_TRUE(response
->was_fetched_via_spdy
);
4947 std::string response_data
;
4948 rv
= ReadTransaction(trans
.get(), &response_data
);
4950 EXPECT_EQ("HTTP/1.1 200 OK", response
->headers
->GetStatusLine());
4951 EXPECT_EQ("hello!", response_data
);
4954 helper
.VerifyDataConsumed();
4958 // Test that turning SPDY on and off works properly.
4959 TEST_P(SpdyNetworkTransactionTest
, SpdyOnOffToggle
) {
4960 HttpStreamFactory::set_spdy_enabled(true);
4961 scoped_ptr
<SpdyFrame
> req(
4962 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
4963 MockWrite spdy_writes
[] = { CreateMockWrite(*req
) };
4965 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
4966 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
4967 MockRead spdy_reads
[] = {
4968 CreateMockRead(*resp
),
4969 CreateMockRead(*body
),
4970 MockRead(ASYNC
, 0, 0) // EOF
4973 DelayedSocketData
data(1, spdy_reads
, arraysize(spdy_reads
),
4974 spdy_writes
, arraysize(spdy_writes
));
4975 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
4976 BoundNetLog(), GetParam(), NULL
);
4977 helper
.RunToCompletion(&data
);
4978 TransactionHelperResult out
= helper
.output();
4979 EXPECT_EQ(OK
, out
.rv
);
4980 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
4981 EXPECT_EQ("hello!", out
.response_data
);
4983 HttpStreamFactory::set_spdy_enabled(false);
4984 MockRead http_reads
[] = {
4985 MockRead("HTTP/1.1 200 OK\r\n\r\n"),
4986 MockRead("hello from http"),
4987 MockRead(SYNCHRONOUS
, OK
),
4989 DelayedSocketData
data2(1, http_reads
, arraysize(http_reads
), NULL
, 0);
4990 NormalSpdyTransactionHelper
helper2(CreateGetRequest(), DEFAULT_PRIORITY
,
4991 BoundNetLog(), GetParam(), NULL
);
4992 helper2
.SetSpdyDisabled();
4993 helper2
.RunToCompletion(&data2
);
4994 TransactionHelperResult out2
= helper2
.output();
4995 EXPECT_EQ(OK
, out2
.rv
);
4996 EXPECT_EQ("HTTP/1.1 200 OK", out2
.status_line
);
4997 EXPECT_EQ("hello from http", out2
.response_data
);
4999 HttpStreamFactory::set_spdy_enabled(true);
5002 // Tests that Basic authentication works over SPDY
5003 TEST_P(SpdyNetworkTransactionTest
, SpdyBasicAuth
) {
5004 HttpStreamFactory::set_spdy_enabled(true);
5006 // The first request will be a bare GET, the second request will be a
5007 // GET with an Authorization header.
5008 scoped_ptr
<SpdyFrame
> req_get(
5009 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
5010 const char* const kExtraAuthorizationHeaders
[] = {
5011 "authorization", "Basic Zm9vOmJhcg=="
5013 scoped_ptr
<SpdyFrame
> req_get_authorization(
5014 spdy_util_
.ConstructSpdyGet(kExtraAuthorizationHeaders
,
5015 arraysize(kExtraAuthorizationHeaders
) / 2,
5016 false, 3, LOWEST
, true));
5017 MockWrite spdy_writes
[] = {
5018 CreateMockWrite(*req_get
, 1),
5019 CreateMockWrite(*req_get_authorization
, 4),
5022 // The first response is a 401 authentication challenge, and the second
5023 // response will be a 200 response since the second request includes a valid
5024 // Authorization header.
5025 const char* const kExtraAuthenticationHeaders
[] = {
5027 "Basic realm=\"MyRealm\""
5029 scoped_ptr
<SpdyFrame
> resp_authentication(
5030 spdy_util_
.ConstructSpdySynReplyError(
5031 "401 Authentication Required",
5032 kExtraAuthenticationHeaders
,
5033 arraysize(kExtraAuthenticationHeaders
) / 2,
5035 scoped_ptr
<SpdyFrame
> body_authentication(
5036 spdy_util_
.ConstructSpdyBodyFrame(1, true));
5037 scoped_ptr
<SpdyFrame
> resp_data(
5038 spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 3));
5039 scoped_ptr
<SpdyFrame
> body_data(spdy_util_
.ConstructSpdyBodyFrame(3, true));
5040 MockRead spdy_reads
[] = {
5041 CreateMockRead(*resp_authentication
, 2),
5042 CreateMockRead(*body_authentication
, 3),
5043 CreateMockRead(*resp_data
, 5),
5044 CreateMockRead(*body_data
, 6),
5045 MockRead(ASYNC
, 0, 7),
5048 OrderedSocketData
data(spdy_reads
, arraysize(spdy_reads
),
5049 spdy_writes
, arraysize(spdy_writes
));
5050 HttpRequestInfo
request(CreateGetRequest());
5051 BoundNetLog net_log
;
5052 NormalSpdyTransactionHelper
helper(request
, DEFAULT_PRIORITY
,
5053 net_log
, GetParam(), NULL
);
5055 helper
.RunPreTestSetup();
5056 helper
.AddData(&data
);
5057 HttpNetworkTransaction
* trans
= helper
.trans();
5058 TestCompletionCallback callback
;
5059 const int rv_start
= trans
->Start(&request
, callback
.callback(), net_log
);
5060 EXPECT_EQ(ERR_IO_PENDING
, rv_start
);
5061 const int rv_start_complete
= callback
.WaitForResult();
5062 EXPECT_EQ(OK
, rv_start_complete
);
5064 // Make sure the response has an auth challenge.
5065 const HttpResponseInfo
* const response_start
= trans
->GetResponseInfo();
5066 ASSERT_TRUE(response_start
!= NULL
);
5067 ASSERT_TRUE(response_start
->headers
.get() != NULL
);
5068 EXPECT_EQ(401, response_start
->headers
->response_code());
5069 EXPECT_TRUE(response_start
->was_fetched_via_spdy
);
5070 AuthChallengeInfo
* auth_challenge
= response_start
->auth_challenge
.get();
5071 ASSERT_TRUE(auth_challenge
!= NULL
);
5072 EXPECT_FALSE(auth_challenge
->is_proxy
);
5073 EXPECT_EQ("basic", auth_challenge
->scheme
);
5074 EXPECT_EQ("MyRealm", auth_challenge
->realm
);
5076 // Restart with a username/password.
5077 AuthCredentials
credentials(base::ASCIIToUTF16("foo"),
5078 base::ASCIIToUTF16("bar"));
5079 TestCompletionCallback callback_restart
;
5080 const int rv_restart
= trans
->RestartWithAuth(
5081 credentials
, callback_restart
.callback());
5082 EXPECT_EQ(ERR_IO_PENDING
, rv_restart
);
5083 const int rv_restart_complete
= callback_restart
.WaitForResult();
5084 EXPECT_EQ(OK
, rv_restart_complete
);
5085 // TODO(cbentzel): This is actually the same response object as before, but
5086 // data has changed.
5087 const HttpResponseInfo
* const response_restart
= trans
->GetResponseInfo();
5088 ASSERT_TRUE(response_restart
!= NULL
);
5089 ASSERT_TRUE(response_restart
->headers
.get() != NULL
);
5090 EXPECT_EQ(200, response_restart
->headers
->response_code());
5091 EXPECT_TRUE(response_restart
->auth_challenge
.get() == NULL
);
5094 TEST_P(SpdyNetworkTransactionTest
, ServerPushWithHeaders
) {
5095 scoped_ptr
<SpdyFrame
> stream1_syn(
5096 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
5097 scoped_ptr
<SpdyFrame
> stream1_body(
5098 spdy_util_
.ConstructSpdyBodyFrame(1, true));
5099 MockWrite writes
[] = {
5100 CreateMockWrite(*stream1_syn
, 1),
5103 scoped_ptr
<SpdyHeaderBlock
> initial_headers(new SpdyHeaderBlock());
5104 spdy_util_
.AddUrlToHeaderBlock(GetDefaultUrlWithPath("/foo.dat"),
5105 initial_headers
.get());
5106 scoped_ptr
<SpdyFrame
> stream2_syn(
5107 spdy_util_
.ConstructInitialSpdyPushFrame(initial_headers
.Pass(), 2, 1));
5109 scoped_ptr
<SpdyHeaderBlock
> late_headers(new SpdyHeaderBlock());
5110 (*late_headers
)["hello"] = "bye";
5111 (*late_headers
)[spdy_util_
.GetStatusKey()] = "200";
5112 (*late_headers
)[spdy_util_
.GetVersionKey()] = "HTTP/1.1";
5113 scoped_ptr
<SpdyFrame
> stream2_headers(
5114 spdy_util_
.ConstructSpdyControlFrame(late_headers
.Pass(),
5122 scoped_ptr
<SpdyFrame
>
5123 stream1_reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
5124 const char kPushedData
[] = "pushed";
5125 scoped_ptr
<SpdyFrame
> stream2_body(
5126 spdy_util_
.ConstructSpdyBodyFrame(
5127 2, kPushedData
, strlen(kPushedData
), true));
5128 MockRead reads
[] = {
5129 CreateMockRead(*stream1_reply
, 2),
5130 CreateMockRead(*stream2_syn
, 3),
5131 CreateMockRead(*stream2_headers
, 4),
5132 CreateMockRead(*stream1_body
, 5, SYNCHRONOUS
),
5133 CreateMockRead(*stream2_body
, 5),
5134 MockRead(ASYNC
, ERR_IO_PENDING
, 7), // Force a pause
5137 HttpResponseInfo response
;
5138 HttpResponseInfo response2
;
5139 std::string
expected_push_result("pushed");
5140 OrderedSocketData
data(reads
, arraysize(reads
),
5141 writes
, arraysize(writes
));
5142 RunServerPushTest(&data
,
5145 expected_push_result
);
5147 // Verify the SYN_REPLY.
5148 EXPECT_TRUE(response
.headers
.get() != NULL
);
5149 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
5151 // Verify the pushed stream.
5152 EXPECT_TRUE(response2
.headers
.get() != NULL
);
5153 EXPECT_EQ("HTTP/1.1 200 OK", response2
.headers
->GetStatusLine());
5156 TEST_P(SpdyNetworkTransactionTest
, ServerPushClaimBeforeHeaders
) {
5157 // We push a stream and attempt to claim it before the headers come down.
5158 scoped_ptr
<SpdyFrame
> stream1_syn(
5159 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
5160 scoped_ptr
<SpdyFrame
> stream1_body(
5161 spdy_util_
.ConstructSpdyBodyFrame(1, true));
5162 MockWrite writes
[] = {
5163 CreateMockWrite(*stream1_syn
, 0, SYNCHRONOUS
),
5166 scoped_ptr
<SpdyHeaderBlock
> initial_headers(new SpdyHeaderBlock());
5167 spdy_util_
.AddUrlToHeaderBlock(GetDefaultUrlWithPath("/foo.dat"),
5168 initial_headers
.get());
5169 scoped_ptr
<SpdyFrame
> stream2_syn(
5170 spdy_util_
.ConstructInitialSpdyPushFrame(initial_headers
.Pass(), 2, 1));
5172 scoped_ptr
<SpdyHeaderBlock
> late_headers(new SpdyHeaderBlock());
5173 (*late_headers
)["hello"] = "bye";
5174 (*late_headers
)[spdy_util_
.GetStatusKey()] = "200";
5175 (*late_headers
)[spdy_util_
.GetVersionKey()] = "HTTP/1.1";
5176 scoped_ptr
<SpdyFrame
> stream2_headers(
5177 spdy_util_
.ConstructSpdyControlFrame(late_headers
.Pass(),
5185 scoped_ptr
<SpdyFrame
>
5186 stream1_reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
5187 const char kPushedData
[] = "pushed";
5188 scoped_ptr
<SpdyFrame
> stream2_body(
5189 spdy_util_
.ConstructSpdyBodyFrame(
5190 2, kPushedData
, strlen(kPushedData
), true));
5191 MockRead reads
[] = {
5192 CreateMockRead(*stream1_reply
, 1),
5193 CreateMockRead(*stream2_syn
, 2),
5194 CreateMockRead(*stream1_body
, 3),
5195 CreateMockRead(*stream2_headers
, 4),
5196 CreateMockRead(*stream2_body
, 5),
5197 MockRead(ASYNC
, 0, 6), // EOF
5200 HttpResponseInfo response
;
5201 HttpResponseInfo response2
;
5202 std::string
expected_push_result("pushed");
5203 DeterministicSocketData
data(reads
, arraysize(reads
),
5204 writes
, arraysize(writes
));
5206 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
5207 BoundNetLog(), GetParam(), NULL
);
5208 helper
.SetDeterministic();
5209 helper
.AddDeterministicData(&data
);
5210 helper
.RunPreTestSetup();
5212 HttpNetworkTransaction
* trans
= helper
.trans();
5214 // Run until we've received the primary SYN_STREAM, the pushed SYN_STREAM,
5215 // and the body of the primary stream, but before we've received the HEADERS
5216 // for the pushed stream.
5219 // Start the transaction.
5220 TestCompletionCallback callback
;
5221 int rv
= trans
->Start(
5222 &CreateGetRequest(), callback
.callback(), BoundNetLog());
5223 EXPECT_EQ(ERR_IO_PENDING
, rv
);
5225 rv
= callback
.WaitForResult();
5228 // Request the pushed path. At this point, we've received the push, but the
5229 // headers are not yet complete.
5230 scoped_ptr
<HttpNetworkTransaction
> trans2(
5231 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
5233 &CreateGetPushRequest(), callback
.callback(), BoundNetLog());
5234 EXPECT_EQ(ERR_IO_PENDING
, rv
);
5236 base::RunLoop().RunUntilIdle();
5238 // Read the server push body.
5239 std::string result2
;
5240 ReadResult(trans2
.get(), &data
, &result2
);
5241 // Read the response body.
5243 ReadResult(trans
, &data
, &result
);
5245 // Verify that the received push data is same as the expected push data.
5246 EXPECT_EQ(result2
.compare(expected_push_result
), 0)
5247 << "Received data: "
5249 << "||||| Expected data: "
5250 << expected_push_result
;
5252 // Verify the SYN_REPLY.
5253 // Copy the response info, because trans goes away.
5254 response
= *trans
->GetResponseInfo();
5255 response2
= *trans2
->GetResponseInfo();
5257 VerifyStreamsClosed(helper
);
5259 // Verify the SYN_REPLY.
5260 EXPECT_TRUE(response
.headers
.get() != NULL
);
5261 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
5263 // Verify the pushed stream.
5264 EXPECT_TRUE(response2
.headers
.get() != NULL
);
5265 EXPECT_EQ("HTTP/1.1 200 OK", response2
.headers
->GetStatusLine());
5267 // Read the final EOF (which will close the session)
5270 // Verify that we consumed all test data.
5271 EXPECT_TRUE(data
.at_read_eof());
5272 EXPECT_TRUE(data
.at_write_eof());
5275 // TODO(baranovich): HTTP 2 does not allow multiple HEADERS frames
5276 TEST_P(SpdyNetworkTransactionTest
, ServerPushWithTwoHeaderFrames
) {
5277 // We push a stream and attempt to claim it before the headers come down.
5278 scoped_ptr
<SpdyFrame
> stream1_syn(
5279 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
5280 scoped_ptr
<SpdyFrame
> stream1_body(
5281 spdy_util_
.ConstructSpdyBodyFrame(1, true));
5282 MockWrite writes
[] = {
5283 CreateMockWrite(*stream1_syn
, 0, SYNCHRONOUS
),
5286 scoped_ptr
<SpdyHeaderBlock
> initial_headers(new SpdyHeaderBlock());
5287 if (spdy_util_
.spdy_version() < SPDY4
) {
5288 // In SPDY4 PUSH_PROMISE headers won't show up in the response headers.
5289 (*initial_headers
)["alpha"] = "beta";
5291 spdy_util_
.AddUrlToHeaderBlock(GetDefaultUrlWithPath("/foo.dat"),
5292 initial_headers
.get());
5293 scoped_ptr
<SpdyFrame
> stream2_syn(
5294 spdy_util_
.ConstructInitialSpdyPushFrame(initial_headers
.Pass(), 2, 1));
5296 scoped_ptr
<SpdyHeaderBlock
> middle_headers(new SpdyHeaderBlock());
5297 (*middle_headers
)["hello"] = "bye";
5298 scoped_ptr
<SpdyFrame
> stream2_headers1(
5299 spdy_util_
.ConstructSpdyControlFrame(middle_headers
.Pass(),
5307 scoped_ptr
<SpdyHeaderBlock
> late_headers(new SpdyHeaderBlock());
5308 (*late_headers
)[spdy_util_
.GetStatusKey()] = "200";
5309 if (spdy_util_
.spdy_version() < SPDY4
) {
5310 // SPDY4/HTTP2 eliminates use of the :version header.
5311 (*late_headers
)[spdy_util_
.GetVersionKey()] = "HTTP/1.1";
5313 scoped_ptr
<SpdyFrame
> stream2_headers2(
5314 spdy_util_
.ConstructSpdyControlFrame(late_headers
.Pass(),
5322 scoped_ptr
<SpdyFrame
>
5323 stream1_reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
5324 const char kPushedData
[] = "pushed";
5325 scoped_ptr
<SpdyFrame
> stream2_body(
5326 spdy_util_
.ConstructSpdyBodyFrame(
5327 2, kPushedData
, strlen(kPushedData
), true));
5328 MockRead reads
[] = {
5329 CreateMockRead(*stream1_reply
, 1),
5330 CreateMockRead(*stream2_syn
, 2),
5331 CreateMockRead(*stream1_body
, 3),
5332 CreateMockRead(*stream2_headers1
, 4),
5333 CreateMockRead(*stream2_headers2
, 5),
5334 CreateMockRead(*stream2_body
, 6),
5335 MockRead(ASYNC
, 0, 7), // EOF
5338 HttpResponseInfo response
;
5339 HttpResponseInfo response2
;
5340 std::string
expected_push_result("pushed");
5341 DeterministicSocketData
data(reads
, arraysize(reads
),
5342 writes
, arraysize(writes
));
5344 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
5345 BoundNetLog(), GetParam(), NULL
);
5346 helper
.SetDeterministic();
5347 helper
.AddDeterministicData(&data
);
5348 helper
.RunPreTestSetup();
5350 HttpNetworkTransaction
* trans
= helper
.trans();
5352 // Run until we've received the primary SYN_STREAM, the pushed SYN_STREAM,
5353 // the first HEADERS frame, and the body of the primary stream, but before
5354 // we've received the final HEADERS for the pushed stream.
5357 // Start the transaction.
5358 TestCompletionCallback callback
;
5359 int rv
= trans
->Start(
5360 &CreateGetRequest(), callback
.callback(), BoundNetLog());
5361 EXPECT_EQ(ERR_IO_PENDING
, rv
);
5363 rv
= callback
.WaitForResult();
5366 // Request the pushed path. At this point, we've received the push, but the
5367 // headers are not yet complete.
5368 scoped_ptr
<HttpNetworkTransaction
> trans2(
5369 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
5371 &CreateGetPushRequest(), callback
.callback(), BoundNetLog());
5372 EXPECT_EQ(ERR_IO_PENDING
, rv
);
5374 base::RunLoop().RunUntilIdle();
5376 // Read the server push body.
5377 std::string result2
;
5378 ReadResult(trans2
.get(), &data
, &result2
);
5379 // Read the response body.
5381 ReadResult(trans
, &data
, &result
);
5383 // Verify that the received push data is same as the expected push data.
5384 EXPECT_EQ(expected_push_result
, result2
);
5386 // Verify the SYN_REPLY.
5387 // Copy the response info, because trans goes away.
5388 response
= *trans
->GetResponseInfo();
5389 response2
= *trans2
->GetResponseInfo();
5391 VerifyStreamsClosed(helper
);
5393 // Verify the SYN_REPLY.
5394 EXPECT_TRUE(response
.headers
.get() != NULL
);
5395 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
5397 // Verify the pushed stream.
5398 EXPECT_TRUE(response2
.headers
.get() != NULL
);
5399 EXPECT_EQ("HTTP/1.1 200 OK", response2
.headers
->GetStatusLine());
5401 // Verify we got all the headers from all header blocks.
5402 if (spdy_util_
.spdy_version() < SPDY4
)
5403 EXPECT_TRUE(response2
.headers
->HasHeaderValue("alpha", "beta"));
5404 EXPECT_TRUE(response2
.headers
->HasHeaderValue("hello", "bye"));
5405 EXPECT_TRUE(response2
.headers
->HasHeaderValue("status", "200"));
5407 // Read the final EOF (which will close the session)
5410 // Verify that we consumed all test data.
5411 EXPECT_TRUE(data
.at_read_eof());
5412 EXPECT_TRUE(data
.at_write_eof());
5415 TEST_P(SpdyNetworkTransactionTest
, ServerPushWithNoStatusHeaderFrames
) {
5416 // We push a stream and attempt to claim it before the headers come down.
5417 scoped_ptr
<SpdyFrame
> stream1_syn(
5418 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
5419 scoped_ptr
<SpdyFrame
> stream1_body(
5420 spdy_util_
.ConstructSpdyBodyFrame(1, true));
5421 MockWrite writes
[] = {
5422 CreateMockWrite(*stream1_syn
, 0, SYNCHRONOUS
),
5425 scoped_ptr
<SpdyHeaderBlock
> initial_headers(new SpdyHeaderBlock());
5426 spdy_util_
.AddUrlToHeaderBlock(GetDefaultUrlWithPath("/foo.dat"),
5427 initial_headers
.get());
5428 scoped_ptr
<SpdyFrame
> stream2_syn(
5429 spdy_util_
.ConstructInitialSpdyPushFrame(initial_headers
.Pass(), 2, 1));
5431 scoped_ptr
<SpdyHeaderBlock
> middle_headers(new SpdyHeaderBlock());
5432 (*middle_headers
)["hello"] = "bye";
5433 scoped_ptr
<SpdyFrame
> stream2_headers1(
5434 spdy_util_
.ConstructSpdyControlFrame(middle_headers
.Pass(),
5442 scoped_ptr
<SpdyFrame
>
5443 stream1_reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
5444 const char kPushedData
[] = "pushed";
5445 scoped_ptr
<SpdyFrame
> stream2_body(
5446 spdy_util_
.ConstructSpdyBodyFrame(
5447 2, kPushedData
, strlen(kPushedData
), true));
5448 MockRead reads
[] = {
5449 CreateMockRead(*stream1_reply
, 1),
5450 CreateMockRead(*stream2_syn
, 2),
5451 CreateMockRead(*stream1_body
, 3),
5452 CreateMockRead(*stream2_headers1
, 4),
5453 CreateMockRead(*stream2_body
, 5),
5454 MockRead(ASYNC
, 0, 6), // EOF
5457 DeterministicSocketData
data(reads
, arraysize(reads
),
5458 writes
, arraysize(writes
));
5460 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
5461 BoundNetLog(), GetParam(), NULL
);
5462 helper
.SetDeterministic();
5463 helper
.AddDeterministicData(&data
);
5464 helper
.RunPreTestSetup();
5466 HttpNetworkTransaction
* trans
= helper
.trans();
5468 // Run until we've received the primary SYN_STREAM, the pushed SYN_STREAM,
5469 // the first HEADERS frame, and the body of the primary stream, but before
5470 // we've received the final HEADERS for the pushed stream.
5473 // Start the transaction.
5474 TestCompletionCallback callback
;
5475 int rv
= trans
->Start(
5476 &CreateGetRequest(), callback
.callback(), BoundNetLog());
5477 EXPECT_EQ(ERR_IO_PENDING
, rv
);
5479 rv
= callback
.WaitForResult();
5482 // Request the pushed path. At this point, we've received the push, but the
5483 // headers are not yet complete.
5484 scoped_ptr
<HttpNetworkTransaction
> trans2(
5485 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
5487 &CreateGetPushRequest(), callback
.callback(), BoundNetLog());
5488 EXPECT_EQ(ERR_IO_PENDING
, rv
);
5490 base::RunLoop().RunUntilIdle();
5492 // Read the server push body.
5493 std::string result2
;
5494 ReadResult(trans2
.get(), &data
, &result2
);
5495 // Read the response body.
5497 ReadResult(trans
, &data
, &result
);
5498 EXPECT_EQ("hello!", result
);
5500 // Verify that we haven't received any push data.
5501 EXPECT_EQ("", result2
);
5503 // Verify the SYN_REPLY.
5504 // Copy the response info, because trans goes away.
5505 HttpResponseInfo response
= *trans
->GetResponseInfo();
5506 ASSERT_TRUE(trans2
->GetResponseInfo() == NULL
);
5508 VerifyStreamsClosed(helper
);
5510 // Verify the SYN_REPLY.
5511 EXPECT_TRUE(response
.headers
.get() != NULL
);
5512 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
5514 // Read the final EOF (which will close the session).
5517 // Verify that we consumed all test data.
5518 EXPECT_TRUE(data
.at_read_eof());
5519 EXPECT_TRUE(data
.at_write_eof());
5522 TEST_P(SpdyNetworkTransactionTest
, SynReplyWithHeaders
) {
5523 scoped_ptr
<SpdyFrame
> req(
5524 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
5525 scoped_ptr
<SpdyFrame
> rst(
5526 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR
));
5527 MockWrite writes
[] = {
5528 CreateMockWrite(*req
), CreateMockWrite(*rst
),
5531 scoped_ptr
<SpdyFrame
> stream1_reply(
5532 spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
5534 scoped_ptr
<SpdyHeaderBlock
> late_headers(new SpdyHeaderBlock());
5535 (*late_headers
)["hello"] = "bye";
5536 scoped_ptr
<SpdyFrame
> stream1_headers(
5537 spdy_util_
.ConstructSpdyControlFrame(late_headers
.Pass(),
5544 scoped_ptr
<SpdyFrame
> stream1_body(
5545 spdy_util_
.ConstructSpdyBodyFrame(1, true));
5546 MockRead reads
[] = {
5547 CreateMockRead(*stream1_reply
),
5548 CreateMockRead(*stream1_headers
),
5549 CreateMockRead(*stream1_body
),
5550 MockRead(ASYNC
, 0, 0) // EOF
5553 DelayedSocketData
data(1, reads
, arraysize(reads
),
5554 writes
, arraysize(writes
));
5555 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
5556 BoundNetLog(), GetParam(), NULL
);
5557 helper
.RunToCompletion(&data
);
5558 TransactionHelperResult out
= helper
.output();
5559 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR
, out
.rv
);
5562 TEST_P(SpdyNetworkTransactionTest
, SynReplyWithLateHeaders
) {
5563 scoped_ptr
<SpdyFrame
> req(
5564 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
5565 scoped_ptr
<SpdyFrame
> rst(
5566 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR
));
5567 MockWrite writes
[] = {
5568 CreateMockWrite(*req
),
5569 CreateMockWrite(*rst
),
5572 scoped_ptr
<SpdyFrame
> stream1_reply(
5573 spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
5575 scoped_ptr
<SpdyHeaderBlock
> late_headers(new SpdyHeaderBlock());
5576 (*late_headers
)["hello"] = "bye";
5577 scoped_ptr
<SpdyFrame
> stream1_headers(
5578 spdy_util_
.ConstructSpdyControlFrame(late_headers
.Pass(),
5585 scoped_ptr
<SpdyFrame
> stream1_body(
5586 spdy_util_
.ConstructSpdyBodyFrame(1, false));
5587 scoped_ptr
<SpdyFrame
> stream1_body2(
5588 spdy_util_
.ConstructSpdyBodyFrame(1, true));
5589 MockRead reads
[] = {
5590 CreateMockRead(*stream1_reply
),
5591 CreateMockRead(*stream1_body
),
5592 CreateMockRead(*stream1_headers
),
5593 CreateMockRead(*stream1_body2
),
5594 MockRead(ASYNC
, 0, 0) // EOF
5597 DelayedSocketData
data(1, reads
, arraysize(reads
),
5598 writes
, arraysize(writes
));
5599 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
5600 BoundNetLog(), GetParam(), NULL
);
5601 helper
.RunToCompletion(&data
);
5602 TransactionHelperResult out
= helper
.output();
5603 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR
, out
.rv
);
5606 TEST_P(SpdyNetworkTransactionTest
, ServerPushCrossOriginCorrectness
) {
5607 // Running these tests via Alt-Svc is too complicated to be worthwhile.
5608 if (GetParam().ssl_type
!= HTTPS_SPDY_VIA_NPN
)
5611 // In this test we want to verify that we can't accidentally push content
5612 // which can't be pushed by this content server.
5613 // This test assumes that:
5614 // - if we're requesting http://www.foo.com/barbaz
5615 // - the browser has made a connection to "www.foo.com".
5617 // A list of the URL to fetch, followed by the URL being pushed.
5618 static const char* const kTestCases
[] = {
5619 "https://www.google.com/foo.html",
5620 "https://www.google.com:81/foo.js", // Bad port
5622 "https://www.google.com/foo.html",
5623 "http://www.google.com/foo.js", // Bad protocol
5625 "https://www.google.com/foo.html",
5626 "ftp://www.google.com/foo.js", // Invalid Protocol
5628 "https://www.google.com/foo.html",
5629 "https://blat.www.google.com/foo.js", // Cross subdomain
5631 "https://www.google.com/foo.html",
5632 "https://www.foo.com/foo.js", // Cross domain
5635 for (size_t index
= 0; index
< arraysize(kTestCases
); index
+= 2) {
5636 const char* url_to_fetch
= kTestCases
[index
];
5637 const char* url_to_push
= kTestCases
[index
+ 1];
5639 scoped_ptr
<SpdyFrame
> stream1_syn(
5640 spdy_util_
.ConstructSpdyGet(url_to_fetch
, false, 1, LOWEST
));
5641 scoped_ptr
<SpdyFrame
> stream1_body(
5642 spdy_util_
.ConstructSpdyBodyFrame(1, true));
5643 scoped_ptr
<SpdyFrame
> push_rst(
5644 spdy_util_
.ConstructSpdyRstStream(2, RST_STREAM_REFUSED_STREAM
));
5645 MockWrite writes
[] = {
5646 CreateMockWrite(*stream1_syn
, 1),
5647 CreateMockWrite(*push_rst
, 4),
5650 scoped_ptr
<SpdyFrame
>
5651 stream1_reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
5652 scoped_ptr
<SpdyFrame
>
5653 stream2_syn(spdy_util_
.ConstructSpdyPush(NULL
,
5658 const char kPushedData
[] = "pushed";
5659 scoped_ptr
<SpdyFrame
> stream2_body(
5660 spdy_util_
.ConstructSpdyBodyFrame(
5661 2, kPushedData
, strlen(kPushedData
), true));
5662 scoped_ptr
<SpdyFrame
> rst(
5663 spdy_util_
.ConstructSpdyRstStream(2, RST_STREAM_CANCEL
));
5665 MockRead reads
[] = {
5666 CreateMockRead(*stream1_reply
, 2),
5667 CreateMockRead(*stream2_syn
, 3),
5668 CreateMockRead(*stream1_body
, 5, SYNCHRONOUS
),
5669 CreateMockRead(*stream2_body
, 6),
5670 MockRead(ASYNC
, ERR_IO_PENDING
, 7), // Force a pause
5673 HttpResponseInfo response
;
5674 OrderedSocketData
data(reads
, arraysize(reads
),
5675 writes
, arraysize(writes
));
5677 HttpRequestInfo request
;
5678 request
.method
= "GET";
5679 request
.url
= GURL(url_to_fetch
);
5680 request
.load_flags
= 0;
5682 // Enable cross-origin push. Since we are not using a proxy, this should
5683 // not actually enable cross-origin SPDY push.
5684 scoped_ptr
<SpdySessionDependencies
> session_deps(
5685 CreateSpdySessionDependencies(GetParam()));
5686 session_deps
->trusted_spdy_proxy
= "123.45.67.89:8080";
5687 NormalSpdyTransactionHelper
helper(request
, DEFAULT_PRIORITY
,
5688 BoundNetLog(), GetParam(),
5689 session_deps
.release());
5690 helper
.RunPreTestSetup();
5691 helper
.AddData(&data
);
5693 HttpNetworkTransaction
* trans
= helper
.trans();
5695 // Start the transaction with basic parameters.
5696 TestCompletionCallback callback
;
5698 int rv
= trans
->Start(&request
, callback
.callback(), BoundNetLog());
5699 EXPECT_EQ(ERR_IO_PENDING
, rv
);
5700 rv
= callback
.WaitForResult();
5702 // Read the response body.
5704 ReadResult(trans
, &data
, &result
);
5706 // Verify that we consumed all test data.
5707 EXPECT_TRUE(data
.at_read_eof());
5708 EXPECT_TRUE(data
.at_write_eof());
5710 // Verify the SYN_REPLY.
5711 // Copy the response info, because trans goes away.
5712 response
= *trans
->GetResponseInfo();
5714 VerifyStreamsClosed(helper
);
5716 // Verify the SYN_REPLY.
5717 EXPECT_TRUE(response
.headers
.get() != NULL
);
5718 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
5722 TEST_P(SpdyNetworkTransactionTest
, RetryAfterRefused
) {
5723 // Construct the request.
5724 scoped_ptr
<SpdyFrame
> req(
5725 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
5726 scoped_ptr
<SpdyFrame
> req2(
5727 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 3, LOWEST
, true));
5728 MockWrite writes
[] = {
5729 CreateMockWrite(*req
, 1),
5730 CreateMockWrite(*req2
, 3),
5733 scoped_ptr
<SpdyFrame
> refused(
5734 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_REFUSED_STREAM
));
5735 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 3));
5736 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(3, true));
5737 MockRead reads
[] = {
5738 CreateMockRead(*refused
, 2),
5739 CreateMockRead(*resp
, 4),
5740 CreateMockRead(*body
, 5),
5741 MockRead(ASYNC
, 0, 6) // EOF
5744 OrderedSocketData
data(reads
, arraysize(reads
),
5745 writes
, arraysize(writes
));
5746 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
5747 BoundNetLog(), GetParam(), NULL
);
5749 helper
.RunPreTestSetup();
5750 helper
.AddData(&data
);
5752 HttpNetworkTransaction
* trans
= helper
.trans();
5754 // Start the transaction with basic parameters.
5755 TestCompletionCallback callback
;
5756 int rv
= trans
->Start(
5757 &CreateGetRequest(), callback
.callback(), BoundNetLog());
5758 EXPECT_EQ(ERR_IO_PENDING
, rv
);
5759 rv
= callback
.WaitForResult();
5762 // Verify that we consumed all test data.
5763 EXPECT_TRUE(data
.at_read_eof()) << "Read count: "
5764 << data
.read_count()
5766 << data
.read_index();
5767 EXPECT_TRUE(data
.at_write_eof()) << "Write count: "
5768 << data
.write_count()
5770 << data
.write_index();
5772 // Verify the SYN_REPLY.
5773 HttpResponseInfo response
= *trans
->GetResponseInfo();
5774 EXPECT_TRUE(response
.headers
.get() != NULL
);
5775 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
5778 TEST_P(SpdyNetworkTransactionTest
, OutOfOrderSynStream
) {
5779 // This first request will start to establish the SpdySession.
5780 // Then we will start the second (MEDIUM priority) and then third
5781 // (HIGHEST priority) request in such a way that the third will actually
5782 // start before the second, causing the second to be numbered differently
5783 // than the order they were created.
5784 scoped_ptr
<SpdyFrame
> req1(
5785 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
5786 scoped_ptr
<SpdyFrame
> req2(
5787 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 3, HIGHEST
, true));
5788 scoped_ptr
<SpdyFrame
> req3(
5789 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 5, MEDIUM
, true));
5790 MockWrite writes
[] = {
5791 CreateMockWrite(*req1
, 0),
5792 CreateMockWrite(*req2
, 3),
5793 CreateMockWrite(*req3
, 4),
5796 scoped_ptr
<SpdyFrame
> resp1(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
5797 scoped_ptr
<SpdyFrame
> body1(spdy_util_
.ConstructSpdyBodyFrame(1, true));
5798 scoped_ptr
<SpdyFrame
> resp2(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 3));
5799 scoped_ptr
<SpdyFrame
> body2(spdy_util_
.ConstructSpdyBodyFrame(3, true));
5800 scoped_ptr
<SpdyFrame
> resp3(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 5));
5801 scoped_ptr
<SpdyFrame
> body3(spdy_util_
.ConstructSpdyBodyFrame(5, true));
5802 MockRead reads
[] = {
5803 CreateMockRead(*resp1
, 1),
5804 CreateMockRead(*body1
, 2),
5805 CreateMockRead(*resp2
, 5),
5806 CreateMockRead(*body2
, 6),
5807 CreateMockRead(*resp3
, 7),
5808 CreateMockRead(*body3
, 8),
5809 MockRead(ASYNC
, 0, 9) // EOF
5812 DeterministicSocketData
data(reads
, arraysize(reads
),
5813 writes
, arraysize(writes
));
5814 NormalSpdyTransactionHelper
helper(CreateGetRequest(), LOWEST
,
5815 BoundNetLog(), GetParam(), NULL
);
5816 helper
.SetDeterministic();
5817 helper
.RunPreTestSetup();
5818 helper
.AddDeterministicData(&data
);
5820 // Start the first transaction to set up the SpdySession
5821 HttpNetworkTransaction
* trans
= helper
.trans();
5822 TestCompletionCallback callback
;
5823 HttpRequestInfo info1
= CreateGetRequest();
5824 int rv
= trans
->Start(&info1
, callback
.callback(), BoundNetLog());
5825 EXPECT_EQ(ERR_IO_PENDING
, rv
);
5827 // Run the message loop, but do not allow the write to complete.
5828 // This leaves the SpdySession with a write pending, which prevents
5829 // SpdySession from attempting subsequent writes until this write completes.
5830 base::RunLoop().RunUntilIdle();
5832 // Now, start both new transactions
5833 HttpRequestInfo info2
= CreateGetRequest();
5834 TestCompletionCallback callback2
;
5835 scoped_ptr
<HttpNetworkTransaction
> trans2(
5836 new HttpNetworkTransaction(MEDIUM
, helper
.session().get()));
5837 rv
= trans2
->Start(&info2
, callback2
.callback(), BoundNetLog());
5838 EXPECT_EQ(ERR_IO_PENDING
, rv
);
5839 base::RunLoop().RunUntilIdle();
5841 HttpRequestInfo info3
= CreateGetRequest();
5842 TestCompletionCallback callback3
;
5843 scoped_ptr
<HttpNetworkTransaction
> trans3(
5844 new HttpNetworkTransaction(HIGHEST
, helper
.session().get()));
5845 rv
= trans3
->Start(&info3
, callback3
.callback(), BoundNetLog());
5846 EXPECT_EQ(ERR_IO_PENDING
, rv
);
5847 base::RunLoop().RunUntilIdle();
5849 // We now have two SYN_STREAM frames queued up which will be
5850 // dequeued only once the first write completes, which we
5851 // now allow to happen.
5853 EXPECT_EQ(OK
, callback
.WaitForResult());
5855 // And now we can allow everything else to run to completion.
5858 EXPECT_EQ(OK
, callback2
.WaitForResult());
5859 EXPECT_EQ(OK
, callback3
.WaitForResult());
5861 helper
.VerifyDataConsumed();
5864 // The tests below are only for SPDY/3 and above.
5866 // Test that sent data frames and received WINDOW_UPDATE frames change
5867 // the send_window_size_ correctly.
5869 // WINDOW_UPDATE is different than most other frames in that it can arrive
5870 // while the client is still sending the request body. In order to enforce
5871 // this scenario, we feed a couple of dummy frames and give a delay of 0 to
5872 // socket data provider, so that initial read that is done as soon as the
5873 // stream is created, succeeds and schedules another read. This way reads
5874 // and writes are interleaved; after doing a full frame write, SpdyStream
5875 // will break out of DoLoop and will read and process a WINDOW_UPDATE.
5876 // Once our WINDOW_UPDATE is read, we cannot send SYN_REPLY right away
5877 // since request has not been completely written, therefore we feed
5878 // enough number of WINDOW_UPDATEs to finish the first read and cause a
5879 // write, leading to a complete write of request body; after that we send
5880 // a reply with a body, to cause a graceful shutdown.
5882 // TODO(agayev): develop a socket data provider where both, reads and
5883 // writes are ordered so that writing tests like these are easy and rewrite
5884 // all these tests using it. Right now we are working around the
5885 // limitations as described above and it's not deterministic, tests may
5886 // fail under specific circumstances.
5887 TEST_P(SpdyNetworkTransactionTest
, WindowUpdateReceived
) {
5888 static int kFrameCount
= 2;
5889 scoped_ptr
<std::string
> content(
5890 new std::string(kMaxSpdyFrameChunkSize
, 'a'));
5891 scoped_ptr
<SpdyFrame
> req(spdy_util_
.ConstructSpdyPost(
5892 GetDefaultUrl(), 1, kMaxSpdyFrameChunkSize
* kFrameCount
, LOWEST
, NULL
,
5894 scoped_ptr
<SpdyFrame
> body(
5895 spdy_util_
.ConstructSpdyBodyFrame(
5896 1, content
->c_str(), content
->size(), false));
5897 scoped_ptr
<SpdyFrame
> body_end(
5898 spdy_util_
.ConstructSpdyBodyFrame(
5899 1, content
->c_str(), content
->size(), true));
5901 MockWrite writes
[] = {
5902 CreateMockWrite(*req
, 0),
5903 CreateMockWrite(*body
, 1),
5904 CreateMockWrite(*body_end
, 2),
5907 static const int32 kDeltaWindowSize
= 0xff;
5908 static const int kDeltaCount
= 4;
5909 scoped_ptr
<SpdyFrame
> window_update(
5910 spdy_util_
.ConstructSpdyWindowUpdate(1, kDeltaWindowSize
));
5911 scoped_ptr
<SpdyFrame
> window_update_dummy(
5912 spdy_util_
.ConstructSpdyWindowUpdate(2, kDeltaWindowSize
));
5913 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyPostSynReply(NULL
, 0));
5914 MockRead reads
[] = {
5915 CreateMockRead(*window_update_dummy
, 3),
5916 CreateMockRead(*window_update_dummy
, 4),
5917 CreateMockRead(*window_update_dummy
, 5),
5918 CreateMockRead(*window_update
, 6), // Four updates, therefore window
5919 CreateMockRead(*window_update
, 7), // size should increase by
5920 CreateMockRead(*window_update
, 8), // kDeltaWindowSize * 4
5921 CreateMockRead(*window_update
, 9),
5922 CreateMockRead(*resp
, 10),
5923 CreateMockRead(*body_end
, 11),
5924 MockRead(ASYNC
, 0, 0, 12) // EOF
5927 DeterministicSocketData
data(reads
, arraysize(reads
),
5928 writes
, arraysize(writes
));
5930 ScopedVector
<UploadElementReader
> element_readers
;
5931 for (int i
= 0; i
< kFrameCount
; ++i
) {
5932 element_readers
.push_back(
5933 new UploadBytesElementReader(content
->c_str(), content
->size()));
5935 ElementsUploadDataStream
upload_data_stream(element_readers
.Pass(), 0);
5937 // Setup the request
5938 HttpRequestInfo request
;
5939 request
.method
= "POST";
5940 request
.url
= GURL(GetDefaultUrl());
5941 request
.upload_data_stream
= &upload_data_stream
;
5943 NormalSpdyTransactionHelper
helper(request
, DEFAULT_PRIORITY
,
5944 BoundNetLog(), GetParam(), NULL
);
5945 helper
.SetDeterministic();
5946 helper
.AddDeterministicData(&data
);
5947 helper
.RunPreTestSetup();
5949 HttpNetworkTransaction
* trans
= helper
.trans();
5951 TestCompletionCallback callback
;
5952 int rv
= trans
->Start(&helper
.request(), callback
.callback(), BoundNetLog());
5954 EXPECT_EQ(ERR_IO_PENDING
, rv
);
5958 SpdyHttpStream
* stream
= static_cast<SpdyHttpStream
*>(trans
->stream_
.get());
5959 ASSERT_TRUE(stream
!= NULL
);
5960 ASSERT_TRUE(stream
->stream() != NULL
);
5961 EXPECT_EQ(static_cast<int>(
5962 SpdySession::GetDefaultInitialWindowSize(GetParam().protocol
)) +
5963 kDeltaWindowSize
* kDeltaCount
-
5964 kMaxSpdyFrameChunkSize
* kFrameCount
,
5965 stream
->stream()->send_window_size());
5969 rv
= callback
.WaitForResult();
5972 helper
.VerifyDataConsumed();
5975 // Test that received data frames and sent WINDOW_UPDATE frames change
5976 // the recv_window_size_ correctly.
5977 TEST_P(SpdyNetworkTransactionTest
, WindowUpdateSent
) {
5978 const int32 default_initial_window_size
=
5979 SpdySession::GetDefaultInitialWindowSize(GetParam().protocol
);
5980 // Session level maximum window size that is more than twice the default
5981 // initial window size so that an initial window update is sent.
5982 const int32 session_max_recv_window_size
= 5 * 64 * 1024;
5983 ASSERT_LT(2 * default_initial_window_size
, session_max_recv_window_size
);
5984 // Stream level maximum window size that is less than the session level
5985 // maximum window size so that we test for confusion between the two.
5986 const int32 stream_max_recv_window_size
= 4 * 64 * 1024;
5987 ASSERT_GT(session_max_recv_window_size
, stream_max_recv_window_size
);
5988 // Size of body to be sent. Has to be less than or equal to both window sizes
5989 // so that we do not run out of receiving window. Also has to be greater than
5990 // half of them so that it triggers both a session level and a stream level
5991 // window update frame.
5992 const int32 kTargetSize
= 3 * 64 * 1024;
5993 ASSERT_GE(session_max_recv_window_size
, kTargetSize
);
5994 ASSERT_GE(stream_max_recv_window_size
, kTargetSize
);
5995 ASSERT_LT(session_max_recv_window_size
/ 2, kTargetSize
);
5996 ASSERT_LT(stream_max_recv_window_size
/ 2, kTargetSize
);
5997 // Size of each DATA frame.
5998 const int32 kChunkSize
= 4096;
5999 // Size of window updates.
6000 ASSERT_EQ(0, session_max_recv_window_size
/ 2 % kChunkSize
);
6001 const int32 session_window_update_delta
=
6002 session_max_recv_window_size
/ 2 + kChunkSize
;
6003 ASSERT_EQ(0, stream_max_recv_window_size
/ 2 % kChunkSize
);
6004 const int32 stream_window_update_delta
=
6005 stream_max_recv_window_size
/ 2 + kChunkSize
;
6007 SettingsMap initial_settings
;
6008 initial_settings
[SETTINGS_MAX_CONCURRENT_STREAMS
] =
6009 SettingsFlagsAndValue(SETTINGS_FLAG_NONE
, kMaxConcurrentPushedStreams
);
6010 initial_settings
[SETTINGS_INITIAL_WINDOW_SIZE
] =
6011 SettingsFlagsAndValue(SETTINGS_FLAG_NONE
, stream_max_recv_window_size
);
6012 scoped_ptr
<SpdyFrame
> initial_settings_frame(
6013 spdy_util_
.ConstructSpdySettings(initial_settings
));
6014 scoped_ptr
<SpdyFrame
> initial_window_update(
6015 spdy_util_
.ConstructSpdyWindowUpdate(
6016 kSessionFlowControlStreamId
,
6017 session_max_recv_window_size
- default_initial_window_size
));
6018 scoped_ptr
<SpdyFrame
> req(
6019 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
6020 scoped_ptr
<SpdyFrame
> session_window_update(
6021 spdy_util_
.ConstructSpdyWindowUpdate(0, session_window_update_delta
));
6022 scoped_ptr
<SpdyFrame
> stream_window_update(
6023 spdy_util_
.ConstructSpdyWindowUpdate(1, stream_window_update_delta
));
6025 std::vector
<MockWrite
> writes
;
6026 if ((GetParam().protocol
>= kProtoSPDY4MinimumVersion
) &&
6027 (GetParam().protocol
<= kProtoSPDY4MaximumVersion
)) {
6028 writes
.push_back(MockWrite(ASYNC
, kHttp2ConnectionHeaderPrefix
,
6029 kHttp2ConnectionHeaderPrefixSize
, 0));
6031 writes
.push_back(CreateMockWrite(*initial_settings_frame
));
6032 writes
.push_back(CreateMockWrite(*initial_window_update
));
6033 writes
.push_back(CreateMockWrite(*req
));
6034 writes
.push_back(CreateMockWrite(*session_window_update
));
6035 writes
.push_back(CreateMockWrite(*stream_window_update
));
6037 std::vector
<MockRead
> reads
;
6038 scoped_ptr
<SpdyFrame
> resp(
6039 spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
6040 reads
.push_back(CreateMockRead(*resp
));
6042 ScopedVector
<SpdyFrame
> body_frames
;
6043 const std::string
body_data(kChunkSize
, 'x');
6044 for (size_t remaining
= kTargetSize
; remaining
!= 0;) {
6045 size_t frame_size
= std::min(remaining
, body_data
.size());
6046 body_frames
.push_back(spdy_util_
.ConstructSpdyBodyFrame(
6047 1, body_data
.data(), frame_size
, false));
6048 reads
.push_back(CreateMockRead(*body_frames
.back()));
6049 remaining
-= frame_size
;
6051 reads
.push_back(MockRead(ASYNC
, ERR_IO_PENDING
, 0)); // Yield.
6053 DelayedSocketData
data(2, vector_as_array(&reads
), reads
.size(),
6054 vector_as_array(&writes
), writes
.size());
6056 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
6057 BoundNetLog(), GetParam(), NULL
);
6058 helper
.AddData(&data
);
6059 helper
.RunPreTestSetup();
6061 SpdySessionPool
* spdy_session_pool
= helper
.session()->spdy_session_pool();
6062 SpdySessionPoolPeer
pool_peer(spdy_session_pool
);
6063 pool_peer
.SetEnableSendingInitialData(true);
6064 pool_peer
.SetSessionMaxRecvWindowSize(session_max_recv_window_size
);
6065 pool_peer
.SetStreamInitialRecvWindowSize(stream_max_recv_window_size
);
6067 HttpNetworkTransaction
* trans
= helper
.trans();
6068 TestCompletionCallback callback
;
6069 int rv
= trans
->Start(&helper
.request(), callback
.callback(), BoundNetLog());
6071 EXPECT_EQ(ERR_IO_PENDING
, rv
);
6072 rv
= callback
.WaitForResult();
6075 SpdyHttpStream
* stream
=
6076 static_cast<SpdyHttpStream
*>(trans
->stream_
.get());
6077 ASSERT_TRUE(stream
!= NULL
);
6078 ASSERT_TRUE(stream
->stream() != NULL
);
6080 // All data has been read, but not consumed. The window reflects this.
6081 EXPECT_EQ(static_cast<int>(stream_max_recv_window_size
- kTargetSize
),
6082 stream
->stream()->recv_window_size());
6084 const HttpResponseInfo
* response
= trans
->GetResponseInfo();
6085 ASSERT_TRUE(response
!= NULL
);
6086 ASSERT_TRUE(response
->headers
.get() != NULL
);
6087 EXPECT_EQ("HTTP/1.1 200 OK", response
->headers
->GetStatusLine());
6088 EXPECT_TRUE(response
->was_fetched_via_spdy
);
6090 // Issue a read which will cause a WINDOW_UPDATE to be sent and window
6091 // size increased to default.
6092 scoped_refptr
<IOBuffer
> buf(new IOBuffer(kTargetSize
));
6093 EXPECT_EQ(static_cast<int>(kTargetSize
),
6094 trans
->Read(buf
.get(), kTargetSize
, CompletionCallback()));
6095 EXPECT_EQ(static_cast<int>(stream_max_recv_window_size
),
6096 stream
->stream()->recv_window_size());
6097 EXPECT_THAT(base::StringPiece(buf
->data(), kTargetSize
), Each(Eq('x')));
6099 // Allow scheduled WINDOW_UPDATE frames to write.
6100 base::RunLoop().RunUntilIdle();
6101 helper
.VerifyDataConsumed();
6104 // Test that WINDOW_UPDATE frame causing overflow is handled correctly.
6105 TEST_P(SpdyNetworkTransactionTest
, WindowUpdateOverflow
) {
6106 // Number of full frames we hope to write (but will not, used to
6107 // set content-length header correctly)
6108 static int kFrameCount
= 3;
6110 scoped_ptr
<std::string
> content(
6111 new std::string(kMaxSpdyFrameChunkSize
, 'a'));
6112 scoped_ptr
<SpdyFrame
> req(spdy_util_
.ConstructSpdyPost(
6113 GetDefaultUrl(), 1, kMaxSpdyFrameChunkSize
* kFrameCount
, LOWEST
, NULL
,
6115 scoped_ptr
<SpdyFrame
> body(
6116 spdy_util_
.ConstructSpdyBodyFrame(
6117 1, content
->c_str(), content
->size(), false));
6118 scoped_ptr
<SpdyFrame
> rst(
6119 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_FLOW_CONTROL_ERROR
));
6121 // We're not going to write a data frame with FIN, we'll receive a bad
6122 // WINDOW_UPDATE while sending a request and will send a RST_STREAM frame.
6123 MockWrite writes
[] = {
6124 CreateMockWrite(*req
, 0),
6125 CreateMockWrite(*body
, 2),
6126 CreateMockWrite(*rst
, 3),
6129 static const int32 kDeltaWindowSize
= 0x7fffffff; // cause an overflow
6130 scoped_ptr
<SpdyFrame
> window_update(
6131 spdy_util_
.ConstructSpdyWindowUpdate(1, kDeltaWindowSize
));
6132 MockRead reads
[] = {
6133 CreateMockRead(*window_update
, 1),
6134 MockRead(ASYNC
, 0, 4) // EOF
6137 DeterministicSocketData
data(reads
, arraysize(reads
),
6138 writes
, arraysize(writes
));
6140 ScopedVector
<UploadElementReader
> element_readers
;
6141 for (int i
= 0; i
< kFrameCount
; ++i
) {
6142 element_readers
.push_back(
6143 new UploadBytesElementReader(content
->c_str(), content
->size()));
6145 ElementsUploadDataStream
upload_data_stream(element_readers
.Pass(), 0);
6147 // Setup the request
6148 HttpRequestInfo request
;
6149 request
.method
= "POST";
6150 request
.url
= GURL(GetDefaultUrl());
6151 request
.upload_data_stream
= &upload_data_stream
;
6153 NormalSpdyTransactionHelper
helper(request
, DEFAULT_PRIORITY
,
6154 BoundNetLog(), GetParam(), NULL
);
6155 helper
.SetDeterministic();
6156 helper
.RunPreTestSetup();
6157 helper
.AddDeterministicData(&data
);
6158 HttpNetworkTransaction
* trans
= helper
.trans();
6160 TestCompletionCallback callback
;
6161 int rv
= trans
->Start(&helper
.request(), callback
.callback(), BoundNetLog());
6162 ASSERT_EQ(ERR_IO_PENDING
, rv
);
6165 ASSERT_TRUE(callback
.have_result());
6166 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR
, callback
.WaitForResult());
6167 helper
.VerifyDataConsumed();
6170 // Test that after hitting a send window size of 0, the write process
6171 // stalls and upon receiving WINDOW_UPDATE frame write resumes.
6173 // This test constructs a POST request followed by enough data frames
6174 // containing 'a' that would make the window size 0, followed by another
6175 // data frame containing default content (which is "hello!") and this frame
6176 // also contains a FIN flag. DelayedSocketData is used to enforce all
6177 // writes go through before a read could happen. However, the last frame
6178 // ("hello!") is not supposed to go through since by the time its turn
6179 // arrives, window size is 0. At this point MessageLoop::Run() called via
6180 // callback would block. Therefore we call MessageLoop::RunUntilIdle()
6181 // which returns after performing all possible writes. We use DCHECKS to
6182 // ensure that last data frame is still there and stream has stalled.
6183 // After that, next read is artifically enforced, which causes a
6184 // WINDOW_UPDATE to be read and I/O process resumes.
6185 TEST_P(SpdyNetworkTransactionTest
, FlowControlStallResume
) {
6186 const int32 initial_window_size
=
6187 SpdySession::GetDefaultInitialWindowSize(GetParam().protocol
);
6188 // Number of frames we need to send to zero out the window size: data
6189 // frames plus SYN_STREAM plus the last data frame; also we need another
6190 // data frame that we will send once the WINDOW_UPDATE is received,
6192 size_t num_writes
= initial_window_size
/ kMaxSpdyFrameChunkSize
+ 3;
6194 // Calculate last frame's size; 0 size data frame is legal.
6195 size_t last_frame_size
= initial_window_size
% kMaxSpdyFrameChunkSize
;
6197 // Construct content for a data frame of maximum size.
6198 std::string
content(kMaxSpdyFrameChunkSize
, 'a');
6200 scoped_ptr
<SpdyFrame
> req(spdy_util_
.ConstructSpdyPost(
6201 GetDefaultUrl(), 1, initial_window_size
+ kUploadDataSize
, LOWEST
, NULL
,
6205 scoped_ptr
<SpdyFrame
> body1(
6206 spdy_util_
.ConstructSpdyBodyFrame(
6207 1, content
.c_str(), content
.size(), false));
6209 // Last frame to zero out the window size.
6210 scoped_ptr
<SpdyFrame
> body2(
6211 spdy_util_
.ConstructSpdyBodyFrame(
6212 1, content
.c_str(), last_frame_size
, false));
6214 // Data frame to be sent once WINDOW_UPDATE frame is received.
6215 scoped_ptr
<SpdyFrame
> body3(spdy_util_
.ConstructSpdyBodyFrame(1, true));
6217 // Fill in mock writes.
6218 scoped_ptr
<MockWrite
[]> writes(new MockWrite
[num_writes
]);
6220 writes
[i
] = CreateMockWrite(*req
);
6221 for (i
= 1; i
< num_writes
- 2; i
++)
6222 writes
[i
] = CreateMockWrite(*body1
);
6223 writes
[i
++] = CreateMockWrite(*body2
);
6224 writes
[i
] = CreateMockWrite(*body3
);
6226 // Construct read frame, give enough space to upload the rest of the
6228 scoped_ptr
<SpdyFrame
> session_window_update(
6229 spdy_util_
.ConstructSpdyWindowUpdate(0, kUploadDataSize
));
6230 scoped_ptr
<SpdyFrame
> window_update(
6231 spdy_util_
.ConstructSpdyWindowUpdate(1, kUploadDataSize
));
6232 scoped_ptr
<SpdyFrame
> reply(spdy_util_
.ConstructSpdyPostSynReply(NULL
, 0));
6233 MockRead reads
[] = {
6234 CreateMockRead(*session_window_update
),
6235 CreateMockRead(*session_window_update
),
6236 CreateMockRead(*window_update
),
6237 CreateMockRead(*window_update
),
6238 CreateMockRead(*reply
),
6239 CreateMockRead(*body2
),
6240 CreateMockRead(*body3
),
6241 MockRead(ASYNC
, 0, 0) // EOF
6244 // Skip the session window updates unless we're using SPDY/3.1 and
6246 size_t read_offset
= (GetParam().protocol
>= kProtoSPDY31
) ? 0 : 2;
6247 size_t num_reads
= arraysize(reads
) - read_offset
;
6249 // Force all writes to happen before any read, last write will not
6250 // actually queue a frame, due to window size being 0.
6251 DelayedSocketData
data(num_writes
, reads
+ read_offset
, num_reads
,
6252 writes
.get(), num_writes
);
6254 ScopedVector
<UploadElementReader
> element_readers
;
6255 std::string
upload_data_string(initial_window_size
, 'a');
6256 upload_data_string
.append(kUploadData
, kUploadDataSize
);
6257 element_readers
.push_back(new UploadBytesElementReader(
6258 upload_data_string
.c_str(), upload_data_string
.size()));
6259 ElementsUploadDataStream
upload_data_stream(element_readers
.Pass(), 0);
6261 HttpRequestInfo request
;
6262 request
.method
= "POST";
6263 request
.url
= GURL(GetDefaultUrl());
6264 request
.upload_data_stream
= &upload_data_stream
;
6265 NormalSpdyTransactionHelper
helper(request
, DEFAULT_PRIORITY
,
6266 BoundNetLog(), GetParam(), NULL
);
6267 helper
.AddData(&data
);
6268 helper
.RunPreTestSetup();
6270 HttpNetworkTransaction
* trans
= helper
.trans();
6272 TestCompletionCallback callback
;
6273 int rv
= trans
->Start(&helper
.request(), callback
.callback(), BoundNetLog());
6274 EXPECT_EQ(ERR_IO_PENDING
, rv
);
6276 base::RunLoop().RunUntilIdle(); // Write as much as we can.
6278 SpdyHttpStream
* stream
= static_cast<SpdyHttpStream
*>(trans
->stream_
.get());
6279 ASSERT_TRUE(stream
!= NULL
);
6280 ASSERT_TRUE(stream
->stream() != NULL
);
6281 EXPECT_EQ(0, stream
->stream()->send_window_size());
6282 // All the body data should have been read.
6283 // TODO(satorux): This is because of the weirdness in reading the request
6284 // body in OnSendBodyComplete(). See crbug.com/113107.
6285 EXPECT_TRUE(upload_data_stream
.IsEOF());
6286 // But the body is not yet fully sent (kUploadData is not yet sent)
6287 // since we're send-stalled.
6288 EXPECT_TRUE(stream
->stream()->send_stalled_by_flow_control());
6290 data
.ForceNextRead(); // Read in WINDOW_UPDATE frame.
6291 rv
= callback
.WaitForResult();
6292 helper
.VerifyDataConsumed();
6295 // Test we correctly handle the case where the SETTINGS frame results in
6296 // unstalling the send window.
6297 TEST_P(SpdyNetworkTransactionTest
, FlowControlStallResumeAfterSettings
) {
6298 const int32 initial_window_size
=
6299 SpdySession::GetDefaultInitialWindowSize(GetParam().protocol
);
6301 // Number of frames we need to send to zero out the window size: data
6302 // frames plus SYN_STREAM plus the last data frame; also we need another
6303 // data frame that we will send once the SETTING is received, therefore +3.
6304 size_t num_writes
= initial_window_size
/ kMaxSpdyFrameChunkSize
+ 3;
6306 // Calculate last frame's size; 0 size data frame is legal.
6307 size_t last_frame_size
= initial_window_size
% kMaxSpdyFrameChunkSize
;
6309 // Construct content for a data frame of maximum size.
6310 std::string
content(kMaxSpdyFrameChunkSize
, 'a');
6312 scoped_ptr
<SpdyFrame
> req(spdy_util_
.ConstructSpdyPost(
6313 GetDefaultUrl(), 1, initial_window_size
+ kUploadDataSize
, LOWEST
, NULL
,
6317 scoped_ptr
<SpdyFrame
> body1(
6318 spdy_util_
.ConstructSpdyBodyFrame(
6319 1, content
.c_str(), content
.size(), false));
6321 // Last frame to zero out the window size.
6322 scoped_ptr
<SpdyFrame
> body2(
6323 spdy_util_
.ConstructSpdyBodyFrame(
6324 1, content
.c_str(), last_frame_size
, false));
6326 // Data frame to be sent once SETTINGS frame is received.
6327 scoped_ptr
<SpdyFrame
> body3(spdy_util_
.ConstructSpdyBodyFrame(1, true));
6329 // Fill in mock reads/writes.
6330 std::vector
<MockRead
> reads
;
6331 std::vector
<MockWrite
> writes
;
6333 writes
.push_back(CreateMockWrite(*req
, i
++));
6334 while (i
< num_writes
- 2)
6335 writes
.push_back(CreateMockWrite(*body1
, i
++));
6336 writes
.push_back(CreateMockWrite(*body2
, i
++));
6338 // Construct read frame for SETTINGS that gives enough space to upload the
6339 // rest of the data.
6340 SettingsMap settings
;
6341 settings
[SETTINGS_INITIAL_WINDOW_SIZE
] =
6342 SettingsFlagsAndValue(SETTINGS_FLAG_NONE
, initial_window_size
* 2);
6343 scoped_ptr
<SpdyFrame
> settings_frame_large(
6344 spdy_util_
.ConstructSpdySettings(settings
));
6346 reads
.push_back(CreateMockRead(*settings_frame_large
, i
++));
6348 scoped_ptr
<SpdyFrame
> session_window_update(
6349 spdy_util_
.ConstructSpdyWindowUpdate(0, kUploadDataSize
));
6350 if (GetParam().protocol
>= kProtoSPDY31
)
6351 reads
.push_back(CreateMockRead(*session_window_update
, i
++));
6353 scoped_ptr
<SpdyFrame
> settings_ack(spdy_util_
.ConstructSpdySettingsAck());
6354 writes
.push_back(CreateMockWrite(*settings_ack
, i
++));
6356 writes
.push_back(CreateMockWrite(*body3
, i
++));
6358 scoped_ptr
<SpdyFrame
> reply(spdy_util_
.ConstructSpdyPostSynReply(NULL
, 0));
6359 reads
.push_back(CreateMockRead(*reply
, i
++));
6360 reads
.push_back(CreateMockRead(*body2
, i
++));
6361 reads
.push_back(CreateMockRead(*body3
, i
++));
6362 reads
.push_back(MockRead(ASYNC
, 0, i
++)); // EOF
6364 // Force all writes to happen before any read, last write will not
6365 // actually queue a frame, due to window size being 0.
6366 DeterministicSocketData
data(vector_as_array(&reads
), reads
.size(),
6367 vector_as_array(&writes
), writes
.size());
6369 ScopedVector
<UploadElementReader
> element_readers
;
6370 std::string
upload_data_string(initial_window_size
, 'a');
6371 upload_data_string
.append(kUploadData
, kUploadDataSize
);
6372 element_readers
.push_back(new UploadBytesElementReader(
6373 upload_data_string
.c_str(), upload_data_string
.size()));
6374 ElementsUploadDataStream
upload_data_stream(element_readers
.Pass(), 0);
6376 HttpRequestInfo request
;
6377 request
.method
= "POST";
6378 request
.url
= GURL(GetDefaultUrl());
6379 request
.upload_data_stream
= &upload_data_stream
;
6380 NormalSpdyTransactionHelper
helper(request
, DEFAULT_PRIORITY
,
6381 BoundNetLog(), GetParam(), NULL
);
6382 helper
.SetDeterministic();
6383 helper
.RunPreTestSetup();
6384 helper
.AddDeterministicData(&data
);
6386 HttpNetworkTransaction
* trans
= helper
.trans();
6388 TestCompletionCallback callback
;
6389 int rv
= trans
->Start(&helper
.request(), callback
.callback(), BoundNetLog());
6390 EXPECT_EQ(ERR_IO_PENDING
, rv
);
6392 data
.RunFor(num_writes
- 1); // Write as much as we can.
6394 SpdyHttpStream
* stream
= static_cast<SpdyHttpStream
*>(trans
->stream_
.get());
6395 ASSERT_TRUE(stream
!= NULL
);
6396 ASSERT_TRUE(stream
->stream() != NULL
);
6397 EXPECT_EQ(0, stream
->stream()->send_window_size());
6399 // All the body data should have been read.
6400 // TODO(satorux): This is because of the weirdness in reading the request
6401 // body in OnSendBodyComplete(). See crbug.com/113107.
6402 EXPECT_TRUE(upload_data_stream
.IsEOF());
6403 // But the body is not yet fully sent (kUploadData is not yet sent)
6404 // since we're send-stalled.
6405 EXPECT_TRUE(stream
->stream()->send_stalled_by_flow_control());
6407 data
.RunFor(7); // Read in SETTINGS frame to unstall.
6408 rv
= callback
.WaitForResult();
6409 helper
.VerifyDataConsumed();
6410 // If stream is NULL, that means it was unstalled and closed.
6411 EXPECT_TRUE(stream
->stream() == NULL
);
6414 // Test we correctly handle the case where the SETTINGS frame results in a
6415 // negative send window size.
6416 TEST_P(SpdyNetworkTransactionTest
, FlowControlNegativeSendWindowSize
) {
6417 const int32 initial_window_size
=
6418 SpdySession::GetDefaultInitialWindowSize(GetParam().protocol
);
6419 // Number of frames we need to send to zero out the window size: data
6420 // frames plus SYN_STREAM plus the last data frame; also we need another
6421 // data frame that we will send once the SETTING is received, therefore +3.
6422 size_t num_writes
= initial_window_size
/ kMaxSpdyFrameChunkSize
+ 3;
6424 // Calculate last frame's size; 0 size data frame is legal.
6425 size_t last_frame_size
= initial_window_size
% kMaxSpdyFrameChunkSize
;
6427 // Construct content for a data frame of maximum size.
6428 std::string
content(kMaxSpdyFrameChunkSize
, 'a');
6430 scoped_ptr
<SpdyFrame
> req(spdy_util_
.ConstructSpdyPost(
6431 GetDefaultUrl(), 1, initial_window_size
+ kUploadDataSize
, LOWEST
, NULL
,
6435 scoped_ptr
<SpdyFrame
> body1(
6436 spdy_util_
.ConstructSpdyBodyFrame(
6437 1, content
.c_str(), content
.size(), false));
6439 // Last frame to zero out the window size.
6440 scoped_ptr
<SpdyFrame
> body2(
6441 spdy_util_
.ConstructSpdyBodyFrame(
6442 1, content
.c_str(), last_frame_size
, false));
6444 // Data frame to be sent once SETTINGS frame is received.
6445 scoped_ptr
<SpdyFrame
> body3(spdy_util_
.ConstructSpdyBodyFrame(1, true));
6447 // Fill in mock reads/writes.
6448 std::vector
<MockRead
> reads
;
6449 std::vector
<MockWrite
> writes
;
6451 writes
.push_back(CreateMockWrite(*req
, i
++));
6452 while (i
< num_writes
- 2)
6453 writes
.push_back(CreateMockWrite(*body1
, i
++));
6454 writes
.push_back(CreateMockWrite(*body2
, i
++));
6456 // Construct read frame for SETTINGS that makes the send_window_size
6458 SettingsMap new_settings
;
6459 new_settings
[SETTINGS_INITIAL_WINDOW_SIZE
] =
6460 SettingsFlagsAndValue(SETTINGS_FLAG_NONE
, initial_window_size
/ 2);
6461 scoped_ptr
<SpdyFrame
> settings_frame_small(
6462 spdy_util_
.ConstructSpdySettings(new_settings
));
6463 // Construct read frames for WINDOW_UPDATE that makes the send_window_size
6465 scoped_ptr
<SpdyFrame
> session_window_update_init_size(
6466 spdy_util_
.ConstructSpdyWindowUpdate(0, initial_window_size
));
6467 scoped_ptr
<SpdyFrame
> window_update_init_size(
6468 spdy_util_
.ConstructSpdyWindowUpdate(1, initial_window_size
));
6470 reads
.push_back(CreateMockRead(*settings_frame_small
, i
++));
6471 reads
.push_back(CreateMockRead(*session_window_update_init_size
, i
++));
6472 reads
.push_back(CreateMockRead(*window_update_init_size
, i
++));
6474 scoped_ptr
<SpdyFrame
> settings_ack(spdy_util_
.ConstructSpdySettingsAck());
6475 writes
.push_back(CreateMockWrite(*settings_ack
, i
++));
6477 writes
.push_back(CreateMockWrite(*body3
, i
++));
6479 scoped_ptr
<SpdyFrame
> reply(spdy_util_
.ConstructSpdyPostSynReply(NULL
, 0));
6480 reads
.push_back(CreateMockRead(*reply
, i
++));
6481 reads
.push_back(CreateMockRead(*body2
, i
++));
6482 reads
.push_back(CreateMockRead(*body3
, i
++));
6483 reads
.push_back(MockRead(ASYNC
, 0, i
++)); // EOF
6485 // Force all writes to happen before any read, last write will not
6486 // actually queue a frame, due to window size being 0.
6487 DeterministicSocketData
data(vector_as_array(&reads
), reads
.size(),
6488 vector_as_array(&writes
), writes
.size());
6490 ScopedVector
<UploadElementReader
> element_readers
;
6491 std::string
upload_data_string(initial_window_size
, 'a');
6492 upload_data_string
.append(kUploadData
, kUploadDataSize
);
6493 element_readers
.push_back(new UploadBytesElementReader(
6494 upload_data_string
.c_str(), upload_data_string
.size()));
6495 ElementsUploadDataStream
upload_data_stream(element_readers
.Pass(), 0);
6497 HttpRequestInfo request
;
6498 request
.method
= "POST";
6499 request
.url
= GURL(GetDefaultUrl());
6500 request
.upload_data_stream
= &upload_data_stream
;
6501 NormalSpdyTransactionHelper
helper(request
, DEFAULT_PRIORITY
,
6502 BoundNetLog(), GetParam(), NULL
);
6503 helper
.SetDeterministic();
6504 helper
.RunPreTestSetup();
6505 helper
.AddDeterministicData(&data
);
6507 HttpNetworkTransaction
* trans
= helper
.trans();
6509 TestCompletionCallback callback
;
6510 int rv
= trans
->Start(&helper
.request(), callback
.callback(), BoundNetLog());
6511 EXPECT_EQ(ERR_IO_PENDING
, rv
);
6513 data
.RunFor(num_writes
- 1); // Write as much as we can.
6515 SpdyHttpStream
* stream
= static_cast<SpdyHttpStream
*>(trans
->stream_
.get());
6516 ASSERT_TRUE(stream
!= NULL
);
6517 ASSERT_TRUE(stream
->stream() != NULL
);
6518 EXPECT_EQ(0, stream
->stream()->send_window_size());
6520 // All the body data should have been read.
6521 // TODO(satorux): This is because of the weirdness in reading the request
6522 // body in OnSendBodyComplete(). See crbug.com/113107.
6523 EXPECT_TRUE(upload_data_stream
.IsEOF());
6524 // But the body is not yet fully sent (kUploadData is not yet sent)
6525 // since we're send-stalled.
6526 EXPECT_TRUE(stream
->stream()->send_stalled_by_flow_control());
6528 // Read in WINDOW_UPDATE or SETTINGS frame.
6529 data
.RunFor((GetParam().protocol
>= kProtoSPDY31
) ? 9 : 8);
6530 rv
= callback
.WaitForResult();
6531 helper
.VerifyDataConsumed();
6534 TEST_P(SpdyNetworkTransactionTest
, GoAwayOnOddPushStreamId
) {
6535 if (spdy_util_
.spdy_version() < SPDY3
)
6538 scoped_ptr
<SpdyHeaderBlock
> push_headers(new SpdyHeaderBlock
);
6539 spdy_util_
.AddUrlToHeaderBlock("http://www.google.com/a.dat",
6540 push_headers
.get());
6541 scoped_ptr
<SpdyFrame
> push(
6542 spdy_util_
.ConstructInitialSpdyPushFrame(push_headers
.Pass(), 3, 1));
6543 MockRead reads
[] = {CreateMockRead(*push
, 1)};
6545 scoped_ptr
<SpdyFrame
> req(
6546 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
6547 scoped_ptr
<SpdyFrame
> goaway(spdy_util_
.ConstructSpdyGoAway(
6548 0, GOAWAY_PROTOCOL_ERROR
, "Odd push stream id."));
6549 MockWrite writes
[] = {
6550 CreateMockWrite(*req
, 0), CreateMockWrite(*goaway
, 2),
6553 DelayedSocketData
data(1, reads
, arraysize(reads
), writes
, arraysize(writes
));
6554 NormalSpdyTransactionHelper
helper(
6555 CreateGetRequest(), DEFAULT_PRIORITY
, BoundNetLog(), GetParam(), NULL
);
6556 helper
.RunToCompletion(&data
);
6557 TransactionHelperResult out
= helper
.output();
6558 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR
, out
.rv
);
6561 TEST_P(SpdyNetworkTransactionTest
,
6562 GoAwayOnPushStreamIdLesserOrEqualThanLastAccepted
) {
6563 if (spdy_util_
.spdy_version() < SPDY3
)
6566 scoped_ptr
<SpdyFrame
> push_a(spdy_util_
.ConstructSpdyPush(
6567 NULL
, 0, 4, 1, GetDefaultUrlWithPath("/a.dat").c_str()));
6568 scoped_ptr
<SpdyHeaderBlock
> push_b_headers(new SpdyHeaderBlock
);
6569 spdy_util_
.AddUrlToHeaderBlock(GetDefaultUrlWithPath("/b.dat"),
6570 push_b_headers
.get());
6571 scoped_ptr
<SpdyFrame
> push_b(
6572 spdy_util_
.ConstructInitialSpdyPushFrame(push_b_headers
.Pass(), 2, 1));
6573 MockRead reads
[] = {
6574 CreateMockRead(*push_a
, 1), CreateMockRead(*push_b
, 2),
6577 scoped_ptr
<SpdyFrame
> req(
6578 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
6579 scoped_ptr
<SpdyFrame
> goaway(spdy_util_
.ConstructSpdyGoAway(
6581 GOAWAY_PROTOCOL_ERROR
,
6582 "New push stream id must be greater than the last accepted."));
6583 MockWrite writes
[] = {
6584 CreateMockWrite(*req
, 0), CreateMockWrite(*goaway
, 3),
6587 DelayedSocketData
data(1, reads
, arraysize(reads
), writes
, arraysize(writes
));
6588 NormalSpdyTransactionHelper
helper(
6589 CreateGetRequest(), DEFAULT_PRIORITY
, BoundNetLog(), GetParam(), NULL
);
6590 helper
.RunToCompletion(&data
);
6591 TransactionHelperResult out
= helper
.output();
6592 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR
, out
.rv
);
6595 class SpdyNetworkTransactionNoTLSUsageCheckTest
6596 : public SpdyNetworkTransactionTest
{
6598 void RunNoTLSUsageCheckTest(scoped_ptr
<SSLSocketDataProvider
> ssl_provider
) {
6599 // Construct the request.
6600 scoped_ptr
<SpdyFrame
> req(
6601 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
6602 MockWrite writes
[] = {CreateMockWrite(*req
)};
6604 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
6605 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
6606 MockRead reads
[] = {
6607 CreateMockRead(*resp
), CreateMockRead(*body
),
6608 MockRead(ASYNC
, 0, 0) // EOF
6611 DelayedSocketData
data(
6612 1, reads
, arraysize(reads
), writes
, arraysize(writes
));
6613 HttpRequestInfo request
;
6614 request
.method
= "GET";
6615 request
.url
= GURL("https://www.google.com/");
6616 NormalSpdyTransactionHelper
helper(
6617 request
, DEFAULT_PRIORITY
, BoundNetLog(), GetParam(), NULL
);
6618 helper
.RunToCompletionWithSSLData(&data
, ssl_provider
.Pass());
6619 TransactionHelperResult out
= helper
.output();
6620 EXPECT_EQ(OK
, out
.rv
);
6621 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
6622 EXPECT_EQ("hello!", out
.response_data
);
6626 //-----------------------------------------------------------------------------
6627 // All tests are run with three different connection types: SPDY after NPN
6628 // negotiation, SPDY without SSL, and SPDY with SSL.
6630 // TODO(akalin): Use ::testing::Combine() when we are able to use
6632 INSTANTIATE_TEST_CASE_P(
6634 SpdyNetworkTransactionNoTLSUsageCheckTest
,
6635 ::testing::Values(SpdyNetworkTransactionTestParams(kProtoSPDY31
,
6636 HTTPS_SPDY_VIA_NPN
)));
6638 TEST_P(SpdyNetworkTransactionNoTLSUsageCheckTest
, TLSVersionTooOld
) {
6639 scoped_ptr
<SSLSocketDataProvider
> ssl_provider(
6640 new SSLSocketDataProvider(ASYNC
, OK
));
6641 SSLConnectionStatusSetVersion(SSL_CONNECTION_VERSION_SSL3
,
6642 &ssl_provider
->connection_status
);
6644 RunNoTLSUsageCheckTest(ssl_provider
.Pass());
6647 TEST_P(SpdyNetworkTransactionNoTLSUsageCheckTest
, TLSCipherSuiteSucky
) {
6648 scoped_ptr
<SSLSocketDataProvider
> ssl_provider(
6649 new SSLSocketDataProvider(ASYNC
, OK
));
6650 // Set to TLS_RSA_WITH_NULL_MD5
6651 SSLConnectionStatusSetCipherSuite(0x1, &ssl_provider
->connection_status
);
6653 RunNoTLSUsageCheckTest(ssl_provider
.Pass());
6656 class SpdyNetworkTransactionTLSUsageCheckTest
6657 : public SpdyNetworkTransactionTest
{
6659 void RunTLSUsageCheckTest(scoped_ptr
<SSLSocketDataProvider
> ssl_provider
) {
6660 scoped_ptr
<SpdyFrame
> goaway(
6661 spdy_util_
.ConstructSpdyGoAway(0, GOAWAY_INADEQUATE_SECURITY
, ""));
6662 MockWrite writes
[] = {CreateMockWrite(*goaway
)};
6664 DelayedSocketData
data(1, NULL
, 0, writes
, arraysize(writes
));
6665 HttpRequestInfo request
;
6666 request
.method
= "GET";
6667 request
.url
= GURL("https://www.google.com/");
6668 NormalSpdyTransactionHelper
helper(
6669 request
, DEFAULT_PRIORITY
, BoundNetLog(), GetParam(), NULL
);
6670 helper
.RunToCompletionWithSSLData(&data
, ssl_provider
.Pass());
6671 TransactionHelperResult out
= helper
.output();
6672 EXPECT_EQ(ERR_SPDY_INADEQUATE_TRANSPORT_SECURITY
, out
.rv
);
6676 INSTANTIATE_TEST_CASE_P(
6678 SpdyNetworkTransactionTLSUsageCheckTest
,
6680 SpdyNetworkTransactionTestParams(kProtoSPDY4_14
, HTTPS_SPDY_VIA_NPN
),
6681 SpdyNetworkTransactionTestParams(kProtoSPDY4
, HTTPS_SPDY_VIA_NPN
)));
6683 TEST_P(SpdyNetworkTransactionTLSUsageCheckTest
, TLSVersionTooOld
) {
6684 scoped_ptr
<SSLSocketDataProvider
> ssl_provider(
6685 new SSLSocketDataProvider(ASYNC
, OK
));
6686 SSLConnectionStatusSetVersion(SSL_CONNECTION_VERSION_SSL3
,
6687 &ssl_provider
->connection_status
);
6689 RunTLSUsageCheckTest(ssl_provider
.Pass());
6692 TEST_P(SpdyNetworkTransactionTLSUsageCheckTest
, TLSCipherSuiteSucky
) {
6693 scoped_ptr
<SSLSocketDataProvider
> ssl_provider(
6694 new SSLSocketDataProvider(ASYNC
, OK
));
6695 // Set to TLS_RSA_WITH_NULL_MD5
6696 SSLConnectionStatusSetCipherSuite(0x1, &ssl_provider
->connection_status
);
6698 RunTLSUsageCheckTest(ssl_provider
.Pass());