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, so
901 // there needs to be three sets of SSL connection data.
902 helper
.AddData(&data_placeholder
);
903 helper
.AddData(&data_placeholder
);
904 scoped_ptr
<HttpNetworkTransaction
> trans1(
905 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
906 scoped_ptr
<HttpNetworkTransaction
> trans2(
907 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
908 scoped_ptr
<HttpNetworkTransaction
> trans3(
909 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
911 TestCompletionCallback callback1
;
912 TestCompletionCallback callback2
;
913 TestCompletionCallback callback3
;
915 HttpRequestInfo httpreq1
= CreateGetRequest();
916 HttpRequestInfo httpreq2
= CreateGetRequest();
917 HttpRequestInfo httpreq3
= CreateGetRequest();
919 out
.rv
= trans1
->Start(&httpreq1
, callback1
.callback(), log
);
920 ASSERT_EQ(ERR_IO_PENDING
, out
.rv
);
921 out
.rv
= trans2
->Start(&httpreq2
, callback2
.callback(), log
);
922 ASSERT_EQ(ERR_IO_PENDING
, out
.rv
);
923 out
.rv
= trans3
->Start(&httpreq3
, callback3
.callback(), log
);
924 ASSERT_EQ(ERR_IO_PENDING
, out
.rv
);
926 out
.rv
= callback1
.WaitForResult();
927 ASSERT_EQ(OK
, out
.rv
);
928 out
.rv
= callback3
.WaitForResult();
929 ASSERT_EQ(OK
, out
.rv
);
931 const HttpResponseInfo
* response1
= trans1
->GetResponseInfo();
932 EXPECT_TRUE(response1
->headers
.get() != NULL
);
933 EXPECT_TRUE(response1
->was_fetched_via_spdy
);
934 out
.status_line
= response1
->headers
->GetStatusLine();
935 out
.response_info
= *response1
;
937 trans2
->GetResponseInfo();
939 out
.rv
= ReadTransaction(trans1
.get(), &out
.response_data
);
940 helper
.VerifyDataConsumed();
941 EXPECT_EQ(OK
, out
.rv
);
943 EXPECT_EQ(OK
, out
.rv
);
944 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
945 EXPECT_EQ("hello!hello!", out
.response_data
);
948 TEST_P(SpdyNetworkTransactionTest
, TwoGetsLateBinding
) {
949 scoped_ptr
<SpdyFrame
> req(
950 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
951 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
952 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, false));
953 scoped_ptr
<SpdyFrame
> fbody(spdy_util_
.ConstructSpdyBodyFrame(1, true));
955 scoped_ptr
<SpdyFrame
> req2(
956 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 3, LOWEST
, true));
957 scoped_ptr
<SpdyFrame
> resp2(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 3));
958 scoped_ptr
<SpdyFrame
> body2(spdy_util_
.ConstructSpdyBodyFrame(3, false));
959 scoped_ptr
<SpdyFrame
> fbody2(spdy_util_
.ConstructSpdyBodyFrame(3, true));
961 MockWrite writes
[] = {
962 CreateMockWrite(*req
),
963 CreateMockWrite(*req2
),
966 CreateMockRead(*resp
, 1),
967 CreateMockRead(*body
),
968 CreateMockRead(*resp2
, 4),
969 CreateMockRead(*body2
),
970 CreateMockRead(*fbody
),
971 CreateMockRead(*fbody2
),
972 MockRead(ASYNC
, 0, 0), // EOF
974 OrderedSocketData
data(reads
, arraysize(reads
),
975 writes
, arraysize(writes
));
977 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 get requests are sent out, so
989 // there needs to be two sets of SSL connection data.
990 helper
.AddData(&data_placeholder
);
991 scoped_ptr
<HttpNetworkTransaction
> trans1(
992 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
993 scoped_ptr
<HttpNetworkTransaction
> trans2(
994 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
996 TestCompletionCallback callback1
;
997 TestCompletionCallback callback2
;
999 HttpRequestInfo httpreq1
= CreateGetRequest();
1000 HttpRequestInfo httpreq2
= CreateGetRequest();
1002 out
.rv
= trans1
->Start(&httpreq1
, callback1
.callback(), log
);
1003 ASSERT_EQ(ERR_IO_PENDING
, out
.rv
);
1004 out
.rv
= trans2
->Start(&httpreq2
, callback2
.callback(), log
);
1005 ASSERT_EQ(ERR_IO_PENDING
, out
.rv
);
1007 out
.rv
= callback1
.WaitForResult();
1008 ASSERT_EQ(OK
, out
.rv
);
1009 out
.rv
= callback2
.WaitForResult();
1010 ASSERT_EQ(OK
, out
.rv
);
1012 const HttpResponseInfo
* response1
= trans1
->GetResponseInfo();
1013 EXPECT_TRUE(response1
->headers
.get() != NULL
);
1014 EXPECT_TRUE(response1
->was_fetched_via_spdy
);
1015 out
.status_line
= response1
->headers
->GetStatusLine();
1016 out
.response_info
= *response1
;
1017 out
.rv
= ReadTransaction(trans1
.get(), &out
.response_data
);
1018 EXPECT_EQ(OK
, out
.rv
);
1019 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1020 EXPECT_EQ("hello!hello!", out
.response_data
);
1022 const HttpResponseInfo
* response2
= trans2
->GetResponseInfo();
1023 EXPECT_TRUE(response2
->headers
.get() != NULL
);
1024 EXPECT_TRUE(response2
->was_fetched_via_spdy
);
1025 out
.status_line
= response2
->headers
->GetStatusLine();
1026 out
.response_info
= *response2
;
1027 out
.rv
= ReadTransaction(trans2
.get(), &out
.response_data
);
1028 EXPECT_EQ(OK
, out
.rv
);
1029 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1030 EXPECT_EQ("hello!hello!", out
.response_data
);
1032 helper
.VerifyDataConsumed();
1035 TEST_P(SpdyNetworkTransactionTest
, TwoGetsLateBindingFromPreconnect
) {
1036 scoped_ptr
<SpdyFrame
> req(
1037 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
1038 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
1039 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, false));
1040 scoped_ptr
<SpdyFrame
> fbody(spdy_util_
.ConstructSpdyBodyFrame(1, true));
1042 scoped_ptr
<SpdyFrame
> req2(
1043 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 3, LOWEST
, true));
1044 scoped_ptr
<SpdyFrame
> resp2(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 3));
1045 scoped_ptr
<SpdyFrame
> body2(spdy_util_
.ConstructSpdyBodyFrame(3, false));
1046 scoped_ptr
<SpdyFrame
> fbody2(spdy_util_
.ConstructSpdyBodyFrame(3, true));
1048 MockWrite writes
[] = {
1049 CreateMockWrite(*req
),
1050 CreateMockWrite(*req2
),
1052 MockRead reads
[] = {
1053 CreateMockRead(*resp
, 1),
1054 CreateMockRead(*body
),
1055 CreateMockRead(*resp2
, 4),
1056 CreateMockRead(*body2
),
1057 CreateMockRead(*fbody
),
1058 CreateMockRead(*fbody2
),
1059 MockRead(ASYNC
, 0, 0), // EOF
1061 OrderedSocketData
preconnect_data(reads
, arraysize(reads
),
1062 writes
, arraysize(writes
));
1064 MockConnect
never_finishing_connect(ASYNC
, ERR_IO_PENDING
);
1066 OrderedSocketData
data_placeholder(NULL
, 0, NULL
, 0);
1067 data_placeholder
.set_connect_data(never_finishing_connect
);
1070 TransactionHelperResult out
;
1071 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
1072 BoundNetLog(), GetParam(), NULL
);
1073 helper
.RunPreTestSetup();
1074 helper
.AddData(&preconnect_data
);
1075 // We require placeholder data because 3 connections are attempted (first is
1076 // the preconnect, 2nd and 3rd are the never finished connections.
1077 helper
.AddData(&data_placeholder
);
1078 helper
.AddData(&data_placeholder
);
1080 scoped_ptr
<HttpNetworkTransaction
> trans1(
1081 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
1082 scoped_ptr
<HttpNetworkTransaction
> trans2(
1083 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
1085 TestCompletionCallback callback1
;
1086 TestCompletionCallback callback2
;
1088 HttpRequestInfo httpreq
= CreateGetRequest();
1090 // Preconnect the first.
1091 SSLConfig preconnect_ssl_config
;
1092 helper
.session()->ssl_config_service()->GetSSLConfig(&preconnect_ssl_config
);
1093 HttpStreamFactory
* http_stream_factory
=
1094 helper
.session()->http_stream_factory();
1095 helper
.session()->GetNextProtos(&preconnect_ssl_config
.next_protos
);
1097 http_stream_factory
->PreconnectStreams(
1098 1, httpreq
, DEFAULT_PRIORITY
,
1099 preconnect_ssl_config
, preconnect_ssl_config
);
1101 out
.rv
= trans1
->Start(&httpreq
, callback1
.callback(), log
);
1102 ASSERT_EQ(ERR_IO_PENDING
, out
.rv
);
1103 out
.rv
= trans2
->Start(&httpreq
, callback2
.callback(), log
);
1104 ASSERT_EQ(ERR_IO_PENDING
, out
.rv
);
1106 out
.rv
= callback1
.WaitForResult();
1107 ASSERT_EQ(OK
, out
.rv
);
1108 out
.rv
= callback2
.WaitForResult();
1109 ASSERT_EQ(OK
, out
.rv
);
1111 const HttpResponseInfo
* response1
= trans1
->GetResponseInfo();
1112 EXPECT_TRUE(response1
->headers
.get() != NULL
);
1113 EXPECT_TRUE(response1
->was_fetched_via_spdy
);
1114 out
.status_line
= response1
->headers
->GetStatusLine();
1115 out
.response_info
= *response1
;
1116 out
.rv
= ReadTransaction(trans1
.get(), &out
.response_data
);
1117 EXPECT_EQ(OK
, out
.rv
);
1118 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1119 EXPECT_EQ("hello!hello!", out
.response_data
);
1121 const HttpResponseInfo
* response2
= trans2
->GetResponseInfo();
1122 EXPECT_TRUE(response2
->headers
.get() != NULL
);
1123 EXPECT_TRUE(response2
->was_fetched_via_spdy
);
1124 out
.status_line
= response2
->headers
->GetStatusLine();
1125 out
.response_info
= *response2
;
1126 out
.rv
= ReadTransaction(trans2
.get(), &out
.response_data
);
1127 EXPECT_EQ(OK
, out
.rv
);
1128 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1129 EXPECT_EQ("hello!hello!", out
.response_data
);
1131 helper
.VerifyDataConsumed();
1134 // Similar to ThreeGets above, however this test adds a SETTINGS
1135 // frame. The SETTINGS frame is read during the IO loop waiting on
1136 // the first transaction completion, and sets a maximum concurrent
1137 // stream limit of 1. This means that our IO loop exists after the
1138 // second transaction completes, so we can assert on read_index().
1139 TEST_P(SpdyNetworkTransactionTest
, ThreeGetsWithMaxConcurrent
) {
1140 // Construct the request.
1141 scoped_ptr
<SpdyFrame
> req(
1142 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
1143 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
1144 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, false));
1145 scoped_ptr
<SpdyFrame
> fbody(spdy_util_
.ConstructSpdyBodyFrame(1, true));
1147 scoped_ptr
<SpdyFrame
> req2(
1148 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 3, LOWEST
, true));
1149 scoped_ptr
<SpdyFrame
> resp2(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 3));
1150 scoped_ptr
<SpdyFrame
> body2(spdy_util_
.ConstructSpdyBodyFrame(3, false));
1151 scoped_ptr
<SpdyFrame
> fbody2(spdy_util_
.ConstructSpdyBodyFrame(3, true));
1153 scoped_ptr
<SpdyFrame
> req3(
1154 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 5, LOWEST
, true));
1155 scoped_ptr
<SpdyFrame
> resp3(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 5));
1156 scoped_ptr
<SpdyFrame
> body3(spdy_util_
.ConstructSpdyBodyFrame(5, false));
1157 scoped_ptr
<SpdyFrame
> fbody3(spdy_util_
.ConstructSpdyBodyFrame(5, true));
1159 SettingsMap settings
;
1160 const uint32 max_concurrent_streams
= 1;
1161 settings
[SETTINGS_MAX_CONCURRENT_STREAMS
] =
1162 SettingsFlagsAndValue(SETTINGS_FLAG_NONE
, max_concurrent_streams
);
1163 scoped_ptr
<SpdyFrame
> settings_frame(
1164 spdy_util_
.ConstructSpdySettings(settings
));
1165 scoped_ptr
<SpdyFrame
> settings_ack(spdy_util_
.ConstructSpdySettingsAck());
1167 MockWrite writes
[] = {
1168 CreateMockWrite(*req
),
1169 CreateMockWrite(*settings_ack
, 2),
1170 CreateMockWrite(*req2
),
1171 CreateMockWrite(*req3
),
1174 MockRead reads
[] = {
1175 CreateMockRead(*settings_frame
, 1),
1176 CreateMockRead(*resp
),
1177 CreateMockRead(*body
),
1178 CreateMockRead(*fbody
),
1179 CreateMockRead(*resp2
, 8),
1180 CreateMockRead(*body2
),
1181 CreateMockRead(*fbody2
),
1182 CreateMockRead(*resp3
, 13),
1183 CreateMockRead(*body3
),
1184 CreateMockRead(*fbody3
),
1186 MockRead(ASYNC
, 0, 0), // EOF
1189 OrderedSocketData
data(reads
, arraysize(reads
),
1190 writes
, arraysize(writes
));
1191 OrderedSocketData
data_placeholder(NULL
, 0, NULL
, 0);
1194 TransactionHelperResult out
;
1196 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
1197 BoundNetLog(), GetParam(), NULL
);
1198 helper
.RunPreTestSetup();
1199 helper
.AddData(&data
);
1200 // We require placeholder data because three get requests are sent out, so
1201 // there needs to be three sets of SSL connection data.
1202 helper
.AddData(&data_placeholder
);
1203 helper
.AddData(&data_placeholder
);
1204 scoped_ptr
<HttpNetworkTransaction
> trans1(
1205 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
1206 scoped_ptr
<HttpNetworkTransaction
> trans2(
1207 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
1208 scoped_ptr
<HttpNetworkTransaction
> trans3(
1209 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
1211 TestCompletionCallback callback1
;
1212 TestCompletionCallback callback2
;
1213 TestCompletionCallback callback3
;
1215 HttpRequestInfo httpreq1
= CreateGetRequest();
1216 HttpRequestInfo httpreq2
= CreateGetRequest();
1217 HttpRequestInfo httpreq3
= CreateGetRequest();
1219 out
.rv
= trans1
->Start(&httpreq1
, callback1
.callback(), log
);
1220 ASSERT_EQ(out
.rv
, ERR_IO_PENDING
);
1221 // Run transaction 1 through quickly to force a read of our SETTINGS
1223 out
.rv
= callback1
.WaitForResult();
1224 ASSERT_EQ(OK
, out
.rv
);
1226 out
.rv
= trans2
->Start(&httpreq2
, callback2
.callback(), log
);
1227 ASSERT_EQ(out
.rv
, ERR_IO_PENDING
);
1228 out
.rv
= trans3
->Start(&httpreq3
, callback3
.callback(), log
);
1229 ASSERT_EQ(out
.rv
, ERR_IO_PENDING
);
1230 out
.rv
= callback2
.WaitForResult();
1231 ASSERT_EQ(OK
, out
.rv
);
1232 EXPECT_EQ(7U, data
.read_index()); // i.e. the third trans was queued
1234 out
.rv
= callback3
.WaitForResult();
1235 ASSERT_EQ(OK
, out
.rv
);
1237 const HttpResponseInfo
* response1
= trans1
->GetResponseInfo();
1238 ASSERT_TRUE(response1
!= NULL
);
1239 EXPECT_TRUE(response1
->headers
.get() != NULL
);
1240 EXPECT_TRUE(response1
->was_fetched_via_spdy
);
1241 out
.status_line
= response1
->headers
->GetStatusLine();
1242 out
.response_info
= *response1
;
1243 out
.rv
= ReadTransaction(trans1
.get(), &out
.response_data
);
1244 EXPECT_EQ(OK
, out
.rv
);
1245 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1246 EXPECT_EQ("hello!hello!", out
.response_data
);
1248 const HttpResponseInfo
* response2
= trans2
->GetResponseInfo();
1249 out
.status_line
= response2
->headers
->GetStatusLine();
1250 out
.response_info
= *response2
;
1251 out
.rv
= ReadTransaction(trans2
.get(), &out
.response_data
);
1252 EXPECT_EQ(OK
, out
.rv
);
1253 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1254 EXPECT_EQ("hello!hello!", out
.response_data
);
1256 const HttpResponseInfo
* response3
= trans3
->GetResponseInfo();
1257 out
.status_line
= response3
->headers
->GetStatusLine();
1258 out
.response_info
= *response3
;
1259 out
.rv
= ReadTransaction(trans3
.get(), &out
.response_data
);
1260 EXPECT_EQ(OK
, out
.rv
);
1261 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1262 EXPECT_EQ("hello!hello!", out
.response_data
);
1264 helper
.VerifyDataConsumed();
1266 EXPECT_EQ(OK
, out
.rv
);
1269 // Similar to ThreeGetsWithMaxConcurrent above, however this test adds
1270 // a fourth transaction. The third and fourth transactions have
1271 // different data ("hello!" vs "hello!hello!") and because of the
1272 // user specified priority, we expect to see them inverted in
1273 // the response from the server.
1274 TEST_P(SpdyNetworkTransactionTest
, FourGetsWithMaxConcurrentPriority
) {
1275 // Construct the request.
1276 scoped_ptr
<SpdyFrame
> req(
1277 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
1278 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
1279 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, false));
1280 scoped_ptr
<SpdyFrame
> fbody(spdy_util_
.ConstructSpdyBodyFrame(1, true));
1282 scoped_ptr
<SpdyFrame
> req2(
1283 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 3, LOWEST
, true));
1284 scoped_ptr
<SpdyFrame
> resp2(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 3));
1285 scoped_ptr
<SpdyFrame
> body2(spdy_util_
.ConstructSpdyBodyFrame(3, false));
1286 scoped_ptr
<SpdyFrame
> fbody2(spdy_util_
.ConstructSpdyBodyFrame(3, true));
1288 scoped_ptr
<SpdyFrame
> req4(
1289 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 5, HIGHEST
, true));
1290 scoped_ptr
<SpdyFrame
> resp4(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 5));
1291 scoped_ptr
<SpdyFrame
> fbody4(spdy_util_
.ConstructSpdyBodyFrame(5, true));
1293 scoped_ptr
<SpdyFrame
> req3(
1294 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 7, LOWEST
, true));
1295 scoped_ptr
<SpdyFrame
> resp3(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 7));
1296 scoped_ptr
<SpdyFrame
> body3(spdy_util_
.ConstructSpdyBodyFrame(7, false));
1297 scoped_ptr
<SpdyFrame
> fbody3(spdy_util_
.ConstructSpdyBodyFrame(7, true));
1299 SettingsMap settings
;
1300 const uint32 max_concurrent_streams
= 1;
1301 settings
[SETTINGS_MAX_CONCURRENT_STREAMS
] =
1302 SettingsFlagsAndValue(SETTINGS_FLAG_NONE
, max_concurrent_streams
);
1303 scoped_ptr
<SpdyFrame
> settings_frame(
1304 spdy_util_
.ConstructSpdySettings(settings
));
1305 scoped_ptr
<SpdyFrame
> settings_ack(spdy_util_
.ConstructSpdySettingsAck());
1307 MockWrite writes
[] = { CreateMockWrite(*req
),
1308 CreateMockWrite(*settings_ack
, 2),
1309 CreateMockWrite(*req2
),
1310 CreateMockWrite(*req4
),
1311 CreateMockWrite(*req3
),
1313 MockRead reads
[] = {
1314 CreateMockRead(*settings_frame
, 1),
1315 CreateMockRead(*resp
),
1316 CreateMockRead(*body
),
1317 CreateMockRead(*fbody
),
1318 CreateMockRead(*resp2
, 8),
1319 CreateMockRead(*body2
),
1320 CreateMockRead(*fbody2
),
1321 CreateMockRead(*resp4
, 14),
1322 CreateMockRead(*fbody4
),
1323 CreateMockRead(*resp3
, 17),
1324 CreateMockRead(*body3
),
1325 CreateMockRead(*fbody3
),
1327 MockRead(ASYNC
, 0, 0), // EOF
1330 OrderedSocketData
data(reads
, arraysize(reads
),
1331 writes
, arraysize(writes
));
1332 OrderedSocketData
data_placeholder(NULL
, 0, NULL
, 0);
1335 TransactionHelperResult out
;
1336 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
1337 BoundNetLog(), GetParam(), NULL
);
1338 helper
.RunPreTestSetup();
1339 helper
.AddData(&data
);
1340 // We require placeholder data because four get requests are sent out, so
1341 // there needs to be four sets of SSL connection data.
1342 helper
.AddData(&data_placeholder
);
1343 helper
.AddData(&data_placeholder
);
1344 helper
.AddData(&data_placeholder
);
1345 scoped_ptr
<HttpNetworkTransaction
> trans1(
1346 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
1347 scoped_ptr
<HttpNetworkTransaction
> trans2(
1348 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
1349 scoped_ptr
<HttpNetworkTransaction
> trans3(
1350 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
1351 scoped_ptr
<HttpNetworkTransaction
> trans4(
1352 new HttpNetworkTransaction(HIGHEST
, helper
.session().get()));
1354 TestCompletionCallback callback1
;
1355 TestCompletionCallback callback2
;
1356 TestCompletionCallback callback3
;
1357 TestCompletionCallback callback4
;
1359 HttpRequestInfo httpreq1
= CreateGetRequest();
1360 HttpRequestInfo httpreq2
= CreateGetRequest();
1361 HttpRequestInfo httpreq3
= CreateGetRequest();
1362 HttpRequestInfo httpreq4
= CreateGetRequest();
1364 out
.rv
= trans1
->Start(&httpreq1
, callback1
.callback(), log
);
1365 ASSERT_EQ(ERR_IO_PENDING
, out
.rv
);
1366 // Run transaction 1 through quickly to force a read of our SETTINGS frame.
1367 out
.rv
= callback1
.WaitForResult();
1368 ASSERT_EQ(OK
, out
.rv
);
1370 out
.rv
= trans2
->Start(&httpreq2
, callback2
.callback(), log
);
1371 ASSERT_EQ(ERR_IO_PENDING
, out
.rv
);
1372 out
.rv
= trans3
->Start(&httpreq3
, callback3
.callback(), log
);
1373 ASSERT_EQ(ERR_IO_PENDING
, out
.rv
);
1374 out
.rv
= trans4
->Start(&httpreq4
, callback4
.callback(), log
);
1375 ASSERT_EQ(ERR_IO_PENDING
, out
.rv
);
1377 out
.rv
= callback2
.WaitForResult();
1378 ASSERT_EQ(OK
, out
.rv
);
1379 EXPECT_EQ(data
.read_index(), 7U); // i.e. the third & fourth trans queued
1381 out
.rv
= callback3
.WaitForResult();
1382 ASSERT_EQ(OK
, out
.rv
);
1384 const HttpResponseInfo
* response1
= trans1
->GetResponseInfo();
1385 EXPECT_TRUE(response1
->headers
.get() != NULL
);
1386 EXPECT_TRUE(response1
->was_fetched_via_spdy
);
1387 out
.status_line
= response1
->headers
->GetStatusLine();
1388 out
.response_info
= *response1
;
1389 out
.rv
= ReadTransaction(trans1
.get(), &out
.response_data
);
1390 EXPECT_EQ(OK
, out
.rv
);
1391 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1392 EXPECT_EQ("hello!hello!", out
.response_data
);
1394 const HttpResponseInfo
* response2
= trans2
->GetResponseInfo();
1395 out
.status_line
= response2
->headers
->GetStatusLine();
1396 out
.response_info
= *response2
;
1397 out
.rv
= ReadTransaction(trans2
.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 // notice: response3 gets two hellos, response4 gets one
1403 // hello, so we know dequeuing priority was respected.
1404 const HttpResponseInfo
* response3
= trans3
->GetResponseInfo();
1405 out
.status_line
= response3
->headers
->GetStatusLine();
1406 out
.response_info
= *response3
;
1407 out
.rv
= ReadTransaction(trans3
.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!hello!", out
.response_data
);
1412 out
.rv
= callback4
.WaitForResult();
1413 EXPECT_EQ(OK
, out
.rv
);
1414 const HttpResponseInfo
* response4
= trans4
->GetResponseInfo();
1415 out
.status_line
= response4
->headers
->GetStatusLine();
1416 out
.response_info
= *response4
;
1417 out
.rv
= ReadTransaction(trans4
.get(), &out
.response_data
);
1418 EXPECT_EQ(OK
, out
.rv
);
1419 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1420 EXPECT_EQ("hello!", out
.response_data
);
1421 helper
.VerifyDataConsumed();
1422 EXPECT_EQ(OK
, out
.rv
);
1425 // Similar to ThreeGetsMaxConcurrrent above, however, this test
1426 // deletes a session in the middle of the transaction to insure
1427 // that we properly remove pendingcreatestream objects from
1429 TEST_P(SpdyNetworkTransactionTest
, ThreeGetsWithMaxConcurrentDelete
) {
1430 // Construct the request.
1431 scoped_ptr
<SpdyFrame
> req(
1432 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
1433 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
1434 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, false));
1435 scoped_ptr
<SpdyFrame
> fbody(spdy_util_
.ConstructSpdyBodyFrame(1, true));
1437 scoped_ptr
<SpdyFrame
> req2(
1438 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 3, LOWEST
, true));
1439 scoped_ptr
<SpdyFrame
> resp2(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 3));
1440 scoped_ptr
<SpdyFrame
> body2(spdy_util_
.ConstructSpdyBodyFrame(3, false));
1441 scoped_ptr
<SpdyFrame
> fbody2(spdy_util_
.ConstructSpdyBodyFrame(3, true));
1443 SettingsMap settings
;
1444 const uint32 max_concurrent_streams
= 1;
1445 settings
[SETTINGS_MAX_CONCURRENT_STREAMS
] =
1446 SettingsFlagsAndValue(SETTINGS_FLAG_NONE
, max_concurrent_streams
);
1447 scoped_ptr
<SpdyFrame
> settings_frame(
1448 spdy_util_
.ConstructSpdySettings(settings
));
1449 scoped_ptr
<SpdyFrame
> settings_ack(spdy_util_
.ConstructSpdySettingsAck());
1451 MockWrite writes
[] = {
1452 CreateMockWrite(*req
),
1453 CreateMockWrite(*settings_ack
, 2),
1454 CreateMockWrite(*req2
),
1456 MockRead reads
[] = {
1457 CreateMockRead(*settings_frame
, 1),
1458 CreateMockRead(*resp
),
1459 CreateMockRead(*body
),
1460 CreateMockRead(*fbody
),
1461 CreateMockRead(*resp2
, 8),
1462 CreateMockRead(*body2
),
1463 CreateMockRead(*fbody2
),
1464 MockRead(ASYNC
, 0, 0), // EOF
1467 OrderedSocketData
data(reads
, arraysize(reads
),
1468 writes
, arraysize(writes
));
1469 OrderedSocketData
data_placeholder(NULL
, 0, NULL
, 0);
1472 TransactionHelperResult out
;
1473 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
1474 BoundNetLog(), GetParam(), NULL
);
1475 helper
.RunPreTestSetup();
1476 helper
.AddData(&data
);
1477 // We require placeholder data because three get requests are sent out, so
1478 // there needs to be three sets of SSL connection data.
1479 helper
.AddData(&data_placeholder
);
1480 helper
.AddData(&data_placeholder
);
1481 scoped_ptr
<HttpNetworkTransaction
> trans1(
1482 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
1483 scoped_ptr
<HttpNetworkTransaction
> trans2(
1484 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
1485 scoped_ptr
<HttpNetworkTransaction
> trans3(
1486 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
1488 TestCompletionCallback callback1
;
1489 TestCompletionCallback callback2
;
1490 TestCompletionCallback callback3
;
1492 HttpRequestInfo httpreq1
= CreateGetRequest();
1493 HttpRequestInfo httpreq2
= CreateGetRequest();
1494 HttpRequestInfo httpreq3
= CreateGetRequest();
1496 out
.rv
= trans1
->Start(&httpreq1
, callback1
.callback(), log
);
1497 ASSERT_EQ(out
.rv
, ERR_IO_PENDING
);
1498 // Run transaction 1 through quickly to force a read of our SETTINGS frame.
1499 out
.rv
= callback1
.WaitForResult();
1500 ASSERT_EQ(OK
, out
.rv
);
1502 out
.rv
= trans2
->Start(&httpreq2
, callback2
.callback(), log
);
1503 ASSERT_EQ(out
.rv
, ERR_IO_PENDING
);
1504 out
.rv
= trans3
->Start(&httpreq3
, callback3
.callback(), log
);
1505 delete trans3
.release();
1506 ASSERT_EQ(out
.rv
, ERR_IO_PENDING
);
1507 out
.rv
= callback2
.WaitForResult();
1508 ASSERT_EQ(OK
, out
.rv
);
1510 EXPECT_EQ(8U, data
.read_index());
1512 const HttpResponseInfo
* response1
= trans1
->GetResponseInfo();
1513 ASSERT_TRUE(response1
!= NULL
);
1514 EXPECT_TRUE(response1
->headers
.get() != NULL
);
1515 EXPECT_TRUE(response1
->was_fetched_via_spdy
);
1516 out
.status_line
= response1
->headers
->GetStatusLine();
1517 out
.response_info
= *response1
;
1518 out
.rv
= ReadTransaction(trans1
.get(), &out
.response_data
);
1519 EXPECT_EQ(OK
, out
.rv
);
1520 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1521 EXPECT_EQ("hello!hello!", out
.response_data
);
1523 const HttpResponseInfo
* response2
= trans2
->GetResponseInfo();
1524 ASSERT_TRUE(response2
!= NULL
);
1525 out
.status_line
= response2
->headers
->GetStatusLine();
1526 out
.response_info
= *response2
;
1527 out
.rv
= ReadTransaction(trans2
.get(), &out
.response_data
);
1528 EXPECT_EQ(OK
, out
.rv
);
1529 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1530 EXPECT_EQ("hello!hello!", out
.response_data
);
1531 helper
.VerifyDataConsumed();
1532 EXPECT_EQ(OK
, out
.rv
);
1537 // The KillerCallback will delete the transaction on error as part of the
1539 class KillerCallback
: public TestCompletionCallbackBase
{
1541 explicit KillerCallback(HttpNetworkTransaction
* transaction
)
1542 : transaction_(transaction
),
1543 callback_(base::Bind(&KillerCallback::OnComplete
,
1544 base::Unretained(this))) {
1547 ~KillerCallback() override
{}
1549 const CompletionCallback
& callback() const { return callback_
; }
1552 void OnComplete(int result
) {
1554 delete transaction_
;
1559 HttpNetworkTransaction
* transaction_
;
1560 CompletionCallback callback_
;
1565 // Similar to ThreeGetsMaxConcurrrentDelete above, however, this test
1566 // closes the socket while we have a pending transaction waiting for
1567 // a pending stream creation. http://crbug.com/52901
1568 TEST_P(SpdyNetworkTransactionTest
, ThreeGetsWithMaxConcurrentSocketClose
) {
1569 // Construct the request.
1570 scoped_ptr
<SpdyFrame
> req(
1571 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
1572 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
1573 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, false));
1574 scoped_ptr
<SpdyFrame
> fin_body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
1576 scoped_ptr
<SpdyFrame
> req2(
1577 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 3, LOWEST
, true));
1578 scoped_ptr
<SpdyFrame
> resp2(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 3));
1580 SettingsMap settings
;
1581 const uint32 max_concurrent_streams
= 1;
1582 settings
[SETTINGS_MAX_CONCURRENT_STREAMS
] =
1583 SettingsFlagsAndValue(SETTINGS_FLAG_NONE
, max_concurrent_streams
);
1584 scoped_ptr
<SpdyFrame
> settings_frame(
1585 spdy_util_
.ConstructSpdySettings(settings
));
1586 scoped_ptr
<SpdyFrame
> settings_ack(spdy_util_
.ConstructSpdySettingsAck());
1588 MockWrite writes
[] = {
1589 CreateMockWrite(*req
),
1590 CreateMockWrite(*settings_ack
, 2),
1591 CreateMockWrite(*req2
),
1593 MockRead reads
[] = {
1594 CreateMockRead(*settings_frame
, 1),
1595 CreateMockRead(*resp
),
1596 CreateMockRead(*body
),
1597 CreateMockRead(*fin_body
),
1598 CreateMockRead(*resp2
, 8),
1599 MockRead(ASYNC
, ERR_CONNECTION_RESET
, 0), // Abort!
1602 OrderedSocketData
data(reads
, arraysize(reads
),
1603 writes
, arraysize(writes
));
1604 OrderedSocketData
data_placeholder(NULL
, 0, NULL
, 0);
1607 TransactionHelperResult out
;
1608 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
1609 BoundNetLog(), GetParam(), NULL
);
1610 helper
.RunPreTestSetup();
1611 helper
.AddData(&data
);
1612 // We require placeholder data because three get requests are sent out, so
1613 // there needs to be three sets of SSL connection data.
1614 helper
.AddData(&data_placeholder
);
1615 helper
.AddData(&data_placeholder
);
1616 HttpNetworkTransaction
trans1(DEFAULT_PRIORITY
, helper
.session().get());
1617 HttpNetworkTransaction
trans2(DEFAULT_PRIORITY
, helper
.session().get());
1618 HttpNetworkTransaction
* trans3(
1619 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
1621 TestCompletionCallback callback1
;
1622 TestCompletionCallback callback2
;
1623 KillerCallback
callback3(trans3
);
1625 HttpRequestInfo httpreq1
= CreateGetRequest();
1626 HttpRequestInfo httpreq2
= CreateGetRequest();
1627 HttpRequestInfo httpreq3
= CreateGetRequest();
1629 out
.rv
= trans1
.Start(&httpreq1
, callback1
.callback(), log
);
1630 ASSERT_EQ(out
.rv
, ERR_IO_PENDING
);
1631 // Run transaction 1 through quickly to force a read of our SETTINGS frame.
1632 out
.rv
= callback1
.WaitForResult();
1633 ASSERT_EQ(OK
, out
.rv
);
1635 out
.rv
= trans2
.Start(&httpreq2
, callback2
.callback(), log
);
1636 ASSERT_EQ(out
.rv
, ERR_IO_PENDING
);
1637 out
.rv
= trans3
->Start(&httpreq3
, callback3
.callback(), log
);
1638 ASSERT_EQ(out
.rv
, ERR_IO_PENDING
);
1639 out
.rv
= callback3
.WaitForResult();
1640 ASSERT_EQ(ERR_ABORTED
, out
.rv
);
1642 EXPECT_EQ(6U, data
.read_index());
1644 const HttpResponseInfo
* response1
= trans1
.GetResponseInfo();
1645 ASSERT_TRUE(response1
!= NULL
);
1646 EXPECT_TRUE(response1
->headers
.get() != NULL
);
1647 EXPECT_TRUE(response1
->was_fetched_via_spdy
);
1648 out
.status_line
= response1
->headers
->GetStatusLine();
1649 out
.response_info
= *response1
;
1650 out
.rv
= ReadTransaction(&trans1
, &out
.response_data
);
1651 EXPECT_EQ(OK
, out
.rv
);
1653 const HttpResponseInfo
* response2
= trans2
.GetResponseInfo();
1654 ASSERT_TRUE(response2
!= NULL
);
1655 out
.status_line
= response2
->headers
->GetStatusLine();
1656 out
.response_info
= *response2
;
1657 out
.rv
= ReadTransaction(&trans2
, &out
.response_data
);
1658 EXPECT_EQ(ERR_CONNECTION_RESET
, out
.rv
);
1660 helper
.VerifyDataConsumed();
1663 // Test that a simple PUT request works.
1664 TEST_P(SpdyNetworkTransactionTest
, Put
) {
1665 // Setup the request
1666 HttpRequestInfo request
;
1667 request
.method
= "PUT";
1668 request
.url
= GURL(GetDefaultUrl());
1670 scoped_ptr
<SpdyHeaderBlock
> put_headers(
1671 spdy_util_
.ConstructPutHeaderBlock(GetDefaultUrl(), 0));
1672 scoped_ptr
<SpdyFrame
> req(
1673 spdy_util_
.ConstructSpdySyn(1, *put_headers
, LOWEST
, false, true));
1674 MockWrite writes
[] = {
1675 CreateMockWrite(*req
),
1678 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
1679 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
1680 MockRead reads
[] = {
1681 CreateMockRead(*resp
),
1682 CreateMockRead(*body
),
1683 MockRead(ASYNC
, 0, 0) // EOF
1686 DelayedSocketData
data(1, reads
, arraysize(reads
),
1687 writes
, arraysize(writes
));
1688 NormalSpdyTransactionHelper
helper(request
, DEFAULT_PRIORITY
,
1689 BoundNetLog(), GetParam(), NULL
);
1690 helper
.RunToCompletion(&data
);
1691 TransactionHelperResult out
= helper
.output();
1693 EXPECT_EQ(OK
, out
.rv
);
1694 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1697 // Test that a simple HEAD request works.
1698 TEST_P(SpdyNetworkTransactionTest
, Head
) {
1699 // Setup the request
1700 HttpRequestInfo request
;
1701 request
.method
= "HEAD";
1702 request
.url
= GURL(GetDefaultUrl());
1704 scoped_ptr
<SpdyHeaderBlock
> head_headers(
1705 spdy_util_
.ConstructHeadHeaderBlock(GetDefaultUrl(), 0));
1706 scoped_ptr
<SpdyFrame
> req(
1707 spdy_util_
.ConstructSpdySyn(1, *head_headers
, LOWEST
, false, true));
1708 MockWrite writes
[] = {
1709 CreateMockWrite(*req
),
1712 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
1713 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
1714 MockRead reads
[] = {
1715 CreateMockRead(*resp
),
1716 CreateMockRead(*body
),
1717 MockRead(ASYNC
, 0, 0) // EOF
1720 DelayedSocketData
data(1, reads
, arraysize(reads
),
1721 writes
, arraysize(writes
));
1722 NormalSpdyTransactionHelper
helper(request
, DEFAULT_PRIORITY
,
1723 BoundNetLog(), GetParam(), NULL
);
1724 helper
.RunToCompletion(&data
);
1725 TransactionHelperResult out
= helper
.output();
1727 EXPECT_EQ(OK
, out
.rv
);
1728 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1731 // Test that a simple POST works.
1732 TEST_P(SpdyNetworkTransactionTest
, Post
) {
1733 scoped_ptr
<SpdyFrame
> req(spdy_util_
.ConstructSpdyPost(
1734 GetDefaultUrl(), 1, kUploadDataSize
, LOWEST
, NULL
, 0));
1735 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
1736 MockWrite writes
[] = {
1737 CreateMockWrite(*req
),
1738 CreateMockWrite(*body
), // POST upload frame
1741 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyPostSynReply(NULL
, 0));
1742 MockRead reads
[] = {
1743 CreateMockRead(*resp
),
1744 CreateMockRead(*body
),
1745 MockRead(ASYNC
, 0, 0) // EOF
1748 DelayedSocketData
data(2, reads
, arraysize(reads
),
1749 writes
, arraysize(writes
));
1750 NormalSpdyTransactionHelper
helper(CreatePostRequest(), DEFAULT_PRIORITY
,
1751 BoundNetLog(), GetParam(), NULL
);
1752 helper
.RunToCompletion(&data
);
1753 TransactionHelperResult out
= helper
.output();
1754 EXPECT_EQ(OK
, out
.rv
);
1755 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1756 EXPECT_EQ("hello!", out
.response_data
);
1759 // Test that a POST with a file works.
1760 TEST_P(SpdyNetworkTransactionTest
, FilePost
) {
1761 scoped_ptr
<SpdyFrame
> req(spdy_util_
.ConstructSpdyPost(
1762 GetDefaultUrl(), 1, kUploadDataSize
, LOWEST
, NULL
, 0));
1763 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
1764 MockWrite writes
[] = {
1765 CreateMockWrite(*req
),
1766 CreateMockWrite(*body
), // POST upload frame
1769 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyPostSynReply(NULL
, 0));
1770 MockRead reads
[] = {
1771 CreateMockRead(*resp
),
1772 CreateMockRead(*body
),
1773 MockRead(ASYNC
, 0, 0) // EOF
1776 DelayedSocketData
data(2, reads
, arraysize(reads
),
1777 writes
, arraysize(writes
));
1778 NormalSpdyTransactionHelper
helper(CreateFilePostRequest(), DEFAULT_PRIORITY
,
1779 BoundNetLog(), GetParam(), NULL
);
1780 helper
.RunToCompletion(&data
);
1781 TransactionHelperResult out
= helper
.output();
1782 EXPECT_EQ(OK
, out
.rv
);
1783 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1784 EXPECT_EQ("hello!", out
.response_data
);
1787 // Test that a POST with a unreadable file fails.
1788 TEST_P(SpdyNetworkTransactionTest
, UnreadableFilePost
) {
1789 MockWrite writes
[] = {
1790 MockWrite(ASYNC
, 0, 0) // EOF
1792 MockRead reads
[] = {
1793 MockRead(ASYNC
, 0, 0) // EOF
1796 DelayedSocketData
data(1, reads
, arraysize(reads
), writes
, arraysize(writes
));
1797 NormalSpdyTransactionHelper
helper(CreateUnreadableFilePostRequest(),
1799 BoundNetLog(), GetParam(), NULL
);
1800 helper
.RunPreTestSetup();
1801 helper
.AddData(&data
);
1802 helper
.RunDefaultTest();
1804 base::RunLoop().RunUntilIdle();
1805 helper
.VerifyDataNotConsumed();
1806 EXPECT_EQ(ERR_ACCESS_DENIED
, helper
.output().rv
);
1809 // Test that a complex POST works.
1810 TEST_P(SpdyNetworkTransactionTest
, ComplexPost
) {
1811 scoped_ptr
<SpdyFrame
> req(spdy_util_
.ConstructSpdyPost(
1812 GetDefaultUrl(), 1, kUploadDataSize
, LOWEST
, NULL
, 0));
1813 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
1814 MockWrite writes
[] = {
1815 CreateMockWrite(*req
),
1816 CreateMockWrite(*body
), // POST upload frame
1819 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyPostSynReply(NULL
, 0));
1820 MockRead reads
[] = {
1821 CreateMockRead(*resp
),
1822 CreateMockRead(*body
),
1823 MockRead(ASYNC
, 0, 0) // EOF
1826 DelayedSocketData
data(2, reads
, arraysize(reads
),
1827 writes
, arraysize(writes
));
1828 NormalSpdyTransactionHelper
helper(CreateComplexPostRequest(),
1830 BoundNetLog(), GetParam(), NULL
);
1831 helper
.RunToCompletion(&data
);
1832 TransactionHelperResult out
= helper
.output();
1833 EXPECT_EQ(OK
, out
.rv
);
1834 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1835 EXPECT_EQ("hello!", out
.response_data
);
1838 // Test that a chunked POST works.
1839 TEST_P(SpdyNetworkTransactionTest
, ChunkedPost
) {
1840 scoped_ptr
<SpdyFrame
> req(spdy_util_
.ConstructChunkedSpdyPost(NULL
, 0));
1841 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
1842 MockWrite writes
[] = {
1843 CreateMockWrite(*req
),
1844 CreateMockWrite(*body
),
1847 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyPostSynReply(NULL
, 0));
1848 MockRead reads
[] = {
1849 CreateMockRead(*resp
),
1850 CreateMockRead(*body
),
1851 MockRead(ASYNC
, 0, 0) // EOF
1854 DelayedSocketData
data(2, reads
, arraysize(reads
),
1855 writes
, arraysize(writes
));
1856 NormalSpdyTransactionHelper
helper(CreateChunkedPostRequest(),
1858 BoundNetLog(), GetParam(), NULL
);
1860 // These chunks get merged into a single frame when being sent.
1861 const int kFirstChunkSize
= kUploadDataSize
/2;
1862 upload_chunked_data_stream()->AppendData(kUploadData
, kFirstChunkSize
, false);
1863 upload_chunked_data_stream()->AppendData(
1864 kUploadData
+ kFirstChunkSize
, kUploadDataSize
- kFirstChunkSize
, true);
1866 helper
.RunToCompletion(&data
);
1867 TransactionHelperResult out
= helper
.output();
1868 EXPECT_EQ(OK
, out
.rv
);
1869 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1870 EXPECT_EQ(kUploadData
, out
.response_data
);
1873 // Test that a chunked POST works with chunks appended after transaction starts.
1874 TEST_P(SpdyNetworkTransactionTest
, DelayedChunkedPost
) {
1875 scoped_ptr
<SpdyFrame
> req(spdy_util_
.ConstructChunkedSpdyPost(NULL
, 0));
1876 scoped_ptr
<SpdyFrame
> chunk1(spdy_util_
.ConstructSpdyBodyFrame(1, false));
1877 scoped_ptr
<SpdyFrame
> chunk2(spdy_util_
.ConstructSpdyBodyFrame(1, false));
1878 scoped_ptr
<SpdyFrame
> chunk3(spdy_util_
.ConstructSpdyBodyFrame(1, true));
1879 MockWrite writes
[] = {
1880 CreateMockWrite(*req
),
1881 CreateMockWrite(*chunk1
),
1882 CreateMockWrite(*chunk2
),
1883 CreateMockWrite(*chunk3
),
1886 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyPostSynReply(NULL
, 0));
1887 MockRead reads
[] = {
1888 CreateMockRead(*resp
),
1889 CreateMockRead(*chunk1
),
1890 CreateMockRead(*chunk2
),
1891 CreateMockRead(*chunk3
),
1892 MockRead(ASYNC
, 0, 0) // EOF
1895 DelayedSocketData
data(4, reads
, arraysize(reads
),
1896 writes
, arraysize(writes
));
1897 NormalSpdyTransactionHelper
helper(CreateChunkedPostRequest(),
1899 BoundNetLog(), GetParam(), NULL
);
1901 upload_chunked_data_stream()->AppendData(kUploadData
, kUploadDataSize
, false);
1903 helper
.RunPreTestSetup();
1904 helper
.AddData(&data
);
1905 ASSERT_TRUE(helper
.StartDefaultTest());
1907 base::RunLoop().RunUntilIdle();
1908 upload_chunked_data_stream()->AppendData(kUploadData
, kUploadDataSize
, false);
1909 base::RunLoop().RunUntilIdle();
1910 upload_chunked_data_stream()->AppendData(kUploadData
, kUploadDataSize
, true);
1912 helper
.FinishDefaultTest();
1913 helper
.VerifyDataConsumed();
1915 std::string expected_response
;
1916 expected_response
+= kUploadData
;
1917 expected_response
+= kUploadData
;
1918 expected_response
+= kUploadData
;
1920 TransactionHelperResult out
= helper
.output();
1921 EXPECT_EQ(OK
, out
.rv
);
1922 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1923 EXPECT_EQ(expected_response
, out
.response_data
);
1926 // Test that a POST without any post data works.
1927 TEST_P(SpdyNetworkTransactionTest
, NullPost
) {
1928 BufferedSpdyFramer
framer(spdy_util_
.spdy_version(), false);
1929 // Setup the request
1930 HttpRequestInfo request
;
1931 request
.method
= "POST";
1932 request
.url
= GURL(GetDefaultUrl());
1933 // Create an empty UploadData.
1934 request
.upload_data_stream
= NULL
;
1936 // When request.upload_data_stream is NULL for post, content-length is
1937 // expected to be 0.
1938 scoped_ptr
<SpdyHeaderBlock
> req_block(
1939 spdy_util_
.ConstructPostHeaderBlock(GetDefaultUrl(), 0));
1940 scoped_ptr
<SpdyFrame
> req(
1941 spdy_util_
.ConstructSpdySyn(1, *req_block
, LOWEST
, false, true));
1943 MockWrite writes
[] = {
1944 CreateMockWrite(*req
),
1947 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyPostSynReply(NULL
, 0));
1948 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
1949 MockRead reads
[] = {
1950 CreateMockRead(*resp
),
1951 CreateMockRead(*body
),
1952 MockRead(ASYNC
, 0, 0) // EOF
1955 DelayedSocketData
data(1, reads
, arraysize(reads
),
1956 writes
, arraysize(writes
));
1958 NormalSpdyTransactionHelper
helper(request
, DEFAULT_PRIORITY
,
1959 BoundNetLog(), GetParam(), NULL
);
1960 helper
.RunToCompletion(&data
);
1961 TransactionHelperResult out
= helper
.output();
1962 EXPECT_EQ(OK
, out
.rv
);
1963 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
1964 EXPECT_EQ("hello!", out
.response_data
);
1967 // Test that a simple POST works.
1968 TEST_P(SpdyNetworkTransactionTest
, EmptyPost
) {
1969 BufferedSpdyFramer
framer(spdy_util_
.spdy_version(), false);
1970 // Create an empty UploadDataStream.
1971 ScopedVector
<UploadElementReader
> element_readers
;
1972 ElementsUploadDataStream
stream(element_readers
.Pass(), 0);
1974 // Setup the request
1975 HttpRequestInfo request
;
1976 request
.method
= "POST";
1977 request
.url
= GURL(GetDefaultUrl());
1978 request
.upload_data_stream
= &stream
;
1980 const uint64 kContentLength
= 0;
1982 scoped_ptr
<SpdyHeaderBlock
> req_block(
1983 spdy_util_
.ConstructPostHeaderBlock(GetDefaultUrl(), kContentLength
));
1984 scoped_ptr
<SpdyFrame
> req(
1985 spdy_util_
.ConstructSpdySyn(1, *req_block
, LOWEST
, false, true));
1987 MockWrite writes
[] = {
1988 CreateMockWrite(*req
),
1991 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyPostSynReply(NULL
, 0));
1992 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
1993 MockRead reads
[] = {
1994 CreateMockRead(*resp
),
1995 CreateMockRead(*body
),
1996 MockRead(ASYNC
, 0, 0) // EOF
1999 DelayedSocketData
data(1, reads
, arraysize(reads
), writes
, arraysize(writes
));
2001 NormalSpdyTransactionHelper
helper(request
, DEFAULT_PRIORITY
,
2002 BoundNetLog(), GetParam(), NULL
);
2003 helper
.RunToCompletion(&data
);
2004 TransactionHelperResult out
= helper
.output();
2005 EXPECT_EQ(OK
, out
.rv
);
2006 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
2007 EXPECT_EQ("hello!", out
.response_data
);
2010 // While we're doing a post, the server sends the reply before upload completes.
2011 TEST_P(SpdyNetworkTransactionTest
, ResponseBeforePostCompletes
) {
2012 scoped_ptr
<SpdyFrame
> req(spdy_util_
.ConstructChunkedSpdyPost(NULL
, 0));
2013 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
2014 MockWrite writes
[] = {
2015 CreateMockWrite(*req
, 0),
2016 CreateMockWrite(*body
, 3),
2018 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyPostSynReply(NULL
, 0));
2019 MockRead reads
[] = {
2020 CreateMockRead(*resp
, 1),
2021 CreateMockRead(*body
, 2),
2022 MockRead(ASYNC
, 0, 4) // EOF
2025 // Write the request headers, and read the complete response
2026 // while still waiting for chunked request data.
2027 DeterministicSocketData
data(reads
, arraysize(reads
),
2028 writes
, arraysize(writes
));
2029 NormalSpdyTransactionHelper
helper(CreateChunkedPostRequest(),
2031 BoundNetLog(), GetParam(), NULL
);
2032 helper
.SetDeterministic();
2033 helper
.RunPreTestSetup();
2034 helper
.AddDeterministicData(&data
);
2036 ASSERT_TRUE(helper
.StartDefaultTest());
2038 // Process the request headers, SYN_REPLY, and response body.
2039 // The request body is still in flight.
2042 const HttpResponseInfo
* response
= helper
.trans()->GetResponseInfo();
2043 EXPECT_EQ("HTTP/1.1 200 OK", response
->headers
->GetStatusLine());
2045 // Finish sending the request body.
2046 upload_chunked_data_stream()->AppendData(kUploadData
, kUploadDataSize
, true);
2049 std::string response_body
;
2050 EXPECT_EQ(OK
, ReadTransaction(helper
.trans(), &response_body
));
2051 EXPECT_EQ(kUploadData
, response_body
);
2052 helper
.VerifyDataConsumed();
2055 // The client upon cancellation tries to send a RST_STREAM frame. The mock
2056 // socket causes the TCP write to return zero. This test checks that the client
2057 // tries to queue up the RST_STREAM frame again.
2058 TEST_P(SpdyNetworkTransactionTest
, SocketWriteReturnsZero
) {
2059 scoped_ptr
<SpdyFrame
> req(
2060 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2061 scoped_ptr
<SpdyFrame
> rst(
2062 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_CANCEL
));
2063 MockWrite writes
[] = {
2064 CreateMockWrite(*req
.get(), 0, SYNCHRONOUS
),
2065 MockWrite(SYNCHRONOUS
, 0, 0, 2),
2066 CreateMockWrite(*rst
.get(), 3, SYNCHRONOUS
),
2069 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2070 MockRead reads
[] = {
2071 CreateMockRead(*resp
.get(), 1, ASYNC
),
2072 MockRead(ASYNC
, 0, 0, 4) // EOF
2075 DeterministicSocketData
data(reads
, arraysize(reads
),
2076 writes
, arraysize(writes
));
2077 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
2078 BoundNetLog(), GetParam(), NULL
);
2079 helper
.SetDeterministic();
2080 helper
.RunPreTestSetup();
2081 helper
.AddDeterministicData(&data
);
2082 HttpNetworkTransaction
* trans
= helper
.trans();
2084 TestCompletionCallback callback
;
2085 int rv
= trans
->Start(
2086 &CreateGetRequest(), callback
.callback(), BoundNetLog());
2087 EXPECT_EQ(ERR_IO_PENDING
, rv
);
2091 helper
.ResetTrans();
2095 helper
.VerifyDataConsumed();
2098 // Test that the transaction doesn't crash when we don't have a reply.
2099 TEST_P(SpdyNetworkTransactionTest
, ResponseWithoutSynReply
) {
2100 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
2101 MockRead reads
[] = {
2102 CreateMockRead(*body
),
2103 MockRead(ASYNC
, 0, 0) // EOF
2106 DelayedSocketData
data(1, reads
, arraysize(reads
), NULL
, 0);
2107 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
2108 BoundNetLog(), GetParam(), NULL
);
2109 helper
.RunToCompletion(&data
);
2110 TransactionHelperResult out
= helper
.output();
2111 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR
, out
.rv
);
2114 // Test that the transaction doesn't crash when we get two replies on the same
2115 // stream ID. See http://crbug.com/45639.
2116 TEST_P(SpdyNetworkTransactionTest
, ResponseWithTwoSynReplies
) {
2117 scoped_ptr
<SpdyFrame
> req(
2118 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2119 scoped_ptr
<SpdyFrame
> rst(
2120 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR
));
2121 MockWrite writes
[] = {
2122 CreateMockWrite(*req
),
2123 CreateMockWrite(*rst
),
2126 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2127 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
2128 MockRead reads
[] = {
2129 CreateMockRead(*resp
),
2130 CreateMockRead(*resp
),
2131 CreateMockRead(*body
),
2132 MockRead(ASYNC
, 0, 0) // EOF
2135 DelayedSocketData
data(1, reads
, arraysize(reads
),
2136 writes
, arraysize(writes
));
2138 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
2139 BoundNetLog(), GetParam(), NULL
);
2140 helper
.RunPreTestSetup();
2141 helper
.AddData(&data
);
2143 HttpNetworkTransaction
* trans
= helper
.trans();
2145 TestCompletionCallback callback
;
2146 int rv
= trans
->Start(&helper
.request(), callback
.callback(), BoundNetLog());
2147 EXPECT_EQ(ERR_IO_PENDING
, rv
);
2148 rv
= callback
.WaitForResult();
2151 const HttpResponseInfo
* response
= trans
->GetResponseInfo();
2152 ASSERT_TRUE(response
!= NULL
);
2153 EXPECT_TRUE(response
->headers
.get() != NULL
);
2154 EXPECT_TRUE(response
->was_fetched_via_spdy
);
2155 std::string response_data
;
2156 rv
= ReadTransaction(trans
, &response_data
);
2157 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR
, rv
);
2159 helper
.VerifyDataConsumed();
2162 TEST_P(SpdyNetworkTransactionTest
, ResetReplyWithTransferEncoding
) {
2163 // Construct the request.
2164 scoped_ptr
<SpdyFrame
> req(
2165 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2166 scoped_ptr
<SpdyFrame
> rst(
2167 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR
));
2168 MockWrite writes
[] = {
2169 CreateMockWrite(*req
),
2170 CreateMockWrite(*rst
),
2173 const char* const headers
[] = {
2174 "transfer-encoding", "chunked"
2176 scoped_ptr
<SpdyFrame
> resp(
2177 spdy_util_
.ConstructSpdyGetSynReply(headers
, 1, 1));
2178 scoped_ptr
<SpdyFrame
> body(
2179 spdy_util_
.ConstructSpdyBodyFrame(1, true));
2180 MockRead reads
[] = {
2181 CreateMockRead(*resp
),
2182 CreateMockRead(*body
),
2183 MockRead(ASYNC
, 0, 0) // EOF
2186 DelayedSocketData
data(1, reads
, arraysize(reads
),
2187 writes
, arraysize(writes
));
2188 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
2189 BoundNetLog(), GetParam(), NULL
);
2190 helper
.RunToCompletion(&data
);
2191 TransactionHelperResult out
= helper
.output();
2192 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR
, out
.rv
);
2194 helper
.session()->spdy_session_pool()->CloseAllSessions();
2195 helper
.VerifyDataConsumed();
2198 TEST_P(SpdyNetworkTransactionTest
, ResetPushWithTransferEncoding
) {
2199 // Construct the request.
2200 scoped_ptr
<SpdyFrame
> req(
2201 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2202 scoped_ptr
<SpdyFrame
> rst(
2203 spdy_util_
.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR
));
2204 MockWrite writes
[] = {
2205 CreateMockWrite(*req
),
2206 CreateMockWrite(*rst
),
2209 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2210 const char* const headers
[] = {
2211 "transfer-encoding", "chunked"
2213 scoped_ptr
<SpdyFrame
> push(
2214 spdy_util_
.ConstructSpdyPush(headers
, arraysize(headers
) / 2, 2, 1,
2215 GetDefaultUrlWithPath("/1").c_str()));
2216 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
2217 MockRead reads
[] = {
2218 CreateMockRead(*resp
),
2219 CreateMockRead(*push
),
2220 CreateMockRead(*body
),
2221 MockRead(ASYNC
, 0, 0) // EOF
2224 DelayedSocketData
data(1, reads
, arraysize(reads
),
2225 writes
, arraysize(writes
));
2226 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
2227 BoundNetLog(), GetParam(), NULL
);
2228 helper
.RunToCompletion(&data
);
2229 TransactionHelperResult out
= helper
.output();
2230 EXPECT_EQ(OK
, out
.rv
);
2231 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
2232 EXPECT_EQ("hello!", out
.response_data
);
2234 helper
.session()->spdy_session_pool()->CloseAllSessions();
2235 helper
.VerifyDataConsumed();
2238 TEST_P(SpdyNetworkTransactionTest
, CancelledTransaction
) {
2239 // Construct the request.
2240 scoped_ptr
<SpdyFrame
> req(
2241 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2242 MockWrite writes
[] = {
2243 CreateMockWrite(*req
),
2246 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2247 MockRead reads
[] = {
2248 CreateMockRead(*resp
),
2249 // This following read isn't used by the test, except during the
2250 // RunUntilIdle() call at the end since the SpdySession survives the
2251 // HttpNetworkTransaction and still tries to continue Read()'ing. Any
2252 // MockRead will do here.
2253 MockRead(ASYNC
, 0, 0) // EOF
2256 StaticSocketDataProvider
data(reads
, arraysize(reads
),
2257 writes
, arraysize(writes
));
2259 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
2260 BoundNetLog(), GetParam(), NULL
);
2261 helper
.RunPreTestSetup();
2262 helper
.AddData(&data
);
2263 HttpNetworkTransaction
* trans
= helper
.trans();
2265 TestCompletionCallback callback
;
2266 int rv
= trans
->Start(
2267 &CreateGetRequest(), callback
.callback(), BoundNetLog());
2268 EXPECT_EQ(ERR_IO_PENDING
, rv
);
2269 helper
.ResetTrans(); // Cancel the transaction.
2271 // Flush the MessageLoop while the SpdySessionDependencies (in particular, the
2272 // MockClientSocketFactory) are still alive.
2273 base::RunLoop().RunUntilIdle();
2274 helper
.VerifyDataNotConsumed();
2277 // Verify that the client sends a Rst Frame upon cancelling the stream.
2278 TEST_P(SpdyNetworkTransactionTest
, CancelledTransactionSendRst
) {
2279 scoped_ptr
<SpdyFrame
> req(
2280 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2281 scoped_ptr
<SpdyFrame
> rst(
2282 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_CANCEL
));
2283 MockWrite writes
[] = {
2284 CreateMockWrite(*req
, 0, SYNCHRONOUS
),
2285 CreateMockWrite(*rst
, 2, SYNCHRONOUS
),
2288 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2289 MockRead reads
[] = {
2290 CreateMockRead(*resp
, 1, ASYNC
),
2291 MockRead(ASYNC
, 0, 0, 3) // EOF
2294 DeterministicSocketData
data(reads
, arraysize(reads
),
2295 writes
, arraysize(writes
));
2297 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
2300 helper
.SetDeterministic();
2301 helper
.RunPreTestSetup();
2302 helper
.AddDeterministicData(&data
);
2303 HttpNetworkTransaction
* trans
= helper
.trans();
2305 TestCompletionCallback callback
;
2307 int rv
= trans
->Start(
2308 &CreateGetRequest(), callback
.callback(), BoundNetLog());
2309 EXPECT_EQ(ERR_IO_PENDING
, rv
);
2313 helper
.ResetTrans();
2317 helper
.VerifyDataConsumed();
2320 // Verify that the client can correctly deal with the user callback attempting
2321 // to start another transaction on a session that is closing down. See
2322 // http://crbug.com/47455
2323 TEST_P(SpdyNetworkTransactionTest
, StartTransactionOnReadCallback
) {
2324 scoped_ptr
<SpdyFrame
> req(
2325 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2326 MockWrite writes
[] = { CreateMockWrite(*req
) };
2327 MockWrite writes2
[] = { CreateMockWrite(*req
) };
2329 // The indicated length of this frame is longer than its actual length. When
2330 // the session receives an empty frame after this one, it shuts down the
2331 // session, and calls the read callback with the incomplete data.
2332 const uint8 kGetBodyFrame2
[] = {
2333 0x00, 0x00, 0x00, 0x01,
2334 0x01, 0x00, 0x00, 0x07,
2335 'h', 'e', 'l', 'l', 'o', '!',
2338 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2339 MockRead reads
[] = {
2340 CreateMockRead(*resp
, 2),
2341 MockRead(ASYNC
, ERR_IO_PENDING
, 3), // Force a pause
2342 MockRead(ASYNC
, reinterpret_cast<const char*>(kGetBodyFrame2
),
2343 arraysize(kGetBodyFrame2
), 4),
2344 MockRead(ASYNC
, ERR_IO_PENDING
, 5), // Force a pause
2345 MockRead(ASYNC
, 0, 0, 6), // EOF
2347 MockRead reads2
[] = {
2348 CreateMockRead(*resp
, 2),
2349 MockRead(ASYNC
, 0, 0, 3), // EOF
2352 OrderedSocketData
data(reads
, arraysize(reads
),
2353 writes
, arraysize(writes
));
2354 DelayedSocketData
data2(1, reads2
, arraysize(reads2
),
2355 writes2
, arraysize(writes2
));
2357 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
2358 BoundNetLog(), GetParam(), NULL
);
2359 helper
.RunPreTestSetup();
2360 helper
.AddData(&data
);
2361 helper
.AddData(&data2
);
2362 HttpNetworkTransaction
* trans
= helper
.trans();
2364 // Start the transaction with basic parameters.
2365 TestCompletionCallback callback
;
2366 int rv
= trans
->Start(&helper
.request(), callback
.callback(), BoundNetLog());
2367 EXPECT_EQ(ERR_IO_PENDING
, rv
);
2368 rv
= callback
.WaitForResult();
2370 const int kSize
= 3000;
2371 scoped_refptr
<IOBuffer
> buf(new IOBuffer(kSize
));
2374 base::Bind(&SpdyNetworkTransactionTest::StartTransactionCallback
,
2375 helper
.session(), GURL(GetDefaultUrl())));
2376 // This forces an err_IO_pending, which sets the callback.
2377 data
.CompleteRead();
2378 // This finishes the read.
2379 data
.CompleteRead();
2380 helper
.VerifyDataConsumed();
2383 // Verify that the client can correctly deal with the user callback deleting the
2384 // transaction. Failures will usually be valgrind errors. See
2385 // http://crbug.com/46925
2386 TEST_P(SpdyNetworkTransactionTest
, DeleteSessionOnReadCallback
) {
2387 scoped_ptr
<SpdyFrame
> req(
2388 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2389 MockWrite writes
[] = { CreateMockWrite(*req
) };
2391 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2392 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
2393 MockRead reads
[] = {
2394 CreateMockRead(*resp
.get(), 2),
2395 MockRead(ASYNC
, ERR_IO_PENDING
, 3), // Force a pause
2396 CreateMockRead(*body
.get(), 4),
2397 MockRead(ASYNC
, 0, 0, 5), // EOF
2400 OrderedSocketData
data(reads
, arraysize(reads
),
2401 writes
, arraysize(writes
));
2403 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
2404 BoundNetLog(), GetParam(), NULL
);
2405 helper
.RunPreTestSetup();
2406 helper
.AddData(&data
);
2407 HttpNetworkTransaction
* trans
= helper
.trans();
2409 // Start the transaction with basic parameters.
2410 TestCompletionCallback callback
;
2411 int rv
= trans
->Start(&helper
.request(), callback
.callback(), BoundNetLog());
2412 EXPECT_EQ(ERR_IO_PENDING
, rv
);
2413 rv
= callback
.WaitForResult();
2415 // Setup a user callback which will delete the session, and clear out the
2416 // memory holding the stream object. Note that the callback deletes trans.
2417 const int kSize
= 3000;
2418 scoped_refptr
<IOBuffer
> buf(new IOBuffer(kSize
));
2422 base::Bind(&SpdyNetworkTransactionTest::DeleteSessionCallback
,
2423 base::Unretained(&helper
)));
2424 ASSERT_EQ(ERR_IO_PENDING
, rv
);
2425 data
.CompleteRead();
2427 // Finish running rest of tasks.
2428 base::RunLoop().RunUntilIdle();
2429 helper
.VerifyDataConsumed();
2432 // Send a spdy request to www.google.com that gets redirected to www.foo.com.
2433 TEST_P(SpdyNetworkTransactionTest
, DISABLED_RedirectGetRequest
) {
2434 scoped_ptr
<SpdyHeaderBlock
> headers(
2435 spdy_util_
.ConstructGetHeaderBlock(GetDefaultUrl()));
2436 (*headers
)["user-agent"] = "";
2437 (*headers
)["accept-encoding"] = "gzip, deflate";
2438 scoped_ptr
<SpdyHeaderBlock
> headers2(
2439 spdy_util_
.ConstructGetHeaderBlock("http://www.foo.com/index.php"));
2440 (*headers2
)["user-agent"] = "";
2441 (*headers2
)["accept-encoding"] = "gzip, deflate";
2443 // Setup writes/reads to www.google.com
2444 scoped_ptr
<SpdyFrame
> req(
2445 spdy_util_
.ConstructSpdySyn(1, *headers
, LOWEST
, false, true));
2446 scoped_ptr
<SpdyFrame
> req2(
2447 spdy_util_
.ConstructSpdySyn(1, *headers2
, LOWEST
, false, true));
2448 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReplyRedirect(1));
2449 MockWrite writes
[] = {
2450 CreateMockWrite(*req
, 1),
2452 MockRead reads
[] = {
2453 CreateMockRead(*resp
, 2),
2454 MockRead(ASYNC
, 0, 0, 3) // EOF
2457 // Setup writes/reads to www.foo.com
2458 scoped_ptr
<SpdyFrame
> resp2(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2459 scoped_ptr
<SpdyFrame
> body2(spdy_util_
.ConstructSpdyBodyFrame(1, true));
2460 MockWrite writes2
[] = {
2461 CreateMockWrite(*req2
, 1),
2463 MockRead reads2
[] = {
2464 CreateMockRead(*resp2
, 2),
2465 CreateMockRead(*body2
, 3),
2466 MockRead(ASYNC
, 0, 0, 4) // EOF
2468 OrderedSocketData
data(reads
, arraysize(reads
),
2469 writes
, arraysize(writes
));
2470 OrderedSocketData
data2(reads2
, arraysize(reads2
),
2471 writes2
, arraysize(writes2
));
2473 // TODO(erikchen): Make test support SPDYSSL, SPDYNPN
2476 SpdyURLRequestContext
spdy_url_request_context(GetParam().protocol
);
2477 scoped_ptr
<URLRequest
> r(spdy_url_request_context
.CreateRequest(
2478 GURL(GetDefaultUrl()), DEFAULT_PRIORITY
, &d
));
2479 spdy_url_request_context
.socket_factory().
2480 AddSocketDataProvider(&data
);
2481 spdy_url_request_context
.socket_factory().
2482 AddSocketDataProvider(&data2
);
2484 d
.set_quit_on_redirect(true);
2486 base::RunLoop().Run();
2488 EXPECT_EQ(1, d
.received_redirect_count());
2490 r
->FollowDeferredRedirect();
2491 base::RunLoop().Run();
2492 EXPECT_EQ(1, d
.response_started_count());
2493 EXPECT_FALSE(d
.received_data_before_response());
2494 EXPECT_EQ(URLRequestStatus::SUCCESS
, r
->status().status());
2495 std::string
contents("hello!");
2496 EXPECT_EQ(contents
, d
.data_received());
2498 EXPECT_TRUE(data
.at_read_eof());
2499 EXPECT_TRUE(data
.at_write_eof());
2500 EXPECT_TRUE(data2
.at_read_eof());
2501 EXPECT_TRUE(data2
.at_write_eof());
2504 // Send a spdy request to www.google.com. Get a pushed stream that redirects to
2506 TEST_P(SpdyNetworkTransactionTest
, DISABLED_RedirectServerPush
) {
2507 scoped_ptr
<SpdyHeaderBlock
> headers(
2508 spdy_util_
.ConstructGetHeaderBlock(GetDefaultUrl()));
2509 (*headers
)["user-agent"] = "";
2510 (*headers
)["accept-encoding"] = "gzip, deflate";
2512 // Setup writes/reads to www.google.com
2513 scoped_ptr
<SpdyFrame
> req(
2514 spdy_util_
.ConstructSpdySyn(1, *headers
, LOWEST
, false, true));
2515 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2516 scoped_ptr
<SpdyFrame
> rep(spdy_util_
.ConstructSpdyPush(
2517 NULL
, 0, 2, 1, GetDefaultUrlWithPath("/foo.dat").c_str(),
2518 "301 Moved Permanently", "http://www.foo.com/index.php"));
2519 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
2520 scoped_ptr
<SpdyFrame
> rst(
2521 spdy_util_
.ConstructSpdyRstStream(2, RST_STREAM_CANCEL
));
2522 MockWrite writes
[] = {
2523 CreateMockWrite(*req
, 1),
2524 CreateMockWrite(*rst
, 6),
2526 MockRead reads
[] = {
2527 CreateMockRead(*resp
, 2),
2528 CreateMockRead(*rep
, 3),
2529 CreateMockRead(*body
, 4),
2530 MockRead(ASYNC
, ERR_IO_PENDING
, 5), // Force a pause
2531 MockRead(ASYNC
, 0, 0, 7) // EOF
2534 // Setup writes/reads to www.foo.com
2535 scoped_ptr
<SpdyHeaderBlock
> headers2(
2536 spdy_util_
.ConstructGetHeaderBlock("http://www.foo.com/index.php"));
2537 (*headers2
)["user-agent"] = "";
2538 (*headers2
)["accept-encoding"] = "gzip, deflate";
2539 scoped_ptr
<SpdyFrame
> req2(
2540 spdy_util_
.ConstructSpdySyn(1, *headers2
, LOWEST
, false, true));
2541 scoped_ptr
<SpdyFrame
> resp2(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2542 scoped_ptr
<SpdyFrame
> body2(spdy_util_
.ConstructSpdyBodyFrame(1, true));
2543 MockWrite writes2
[] = {
2544 CreateMockWrite(*req2
, 1),
2546 MockRead reads2
[] = {
2547 CreateMockRead(*resp2
, 2),
2548 CreateMockRead(*body2
, 3),
2549 MockRead(ASYNC
, 0, 0, 5) // EOF
2551 OrderedSocketData
data(reads
, arraysize(reads
),
2552 writes
, arraysize(writes
));
2553 OrderedSocketData
data2(reads2
, arraysize(reads2
),
2554 writes2
, arraysize(writes2
));
2556 // TODO(erikchen): Make test support SPDYSSL, SPDYNPN
2559 SpdyURLRequestContext
spdy_url_request_context(GetParam().protocol
);
2561 scoped_ptr
<URLRequest
> r(spdy_url_request_context
.CreateRequest(
2562 GURL(GetDefaultUrl()), DEFAULT_PRIORITY
, &d
));
2563 spdy_url_request_context
.socket_factory().
2564 AddSocketDataProvider(&data
);
2567 base::RunLoop().Run();
2569 EXPECT_EQ(0, d
.received_redirect_count());
2570 std::string
contents("hello!");
2571 EXPECT_EQ(contents
, d
.data_received());
2573 scoped_ptr
<URLRequest
> r2(spdy_url_request_context
.CreateRequest(
2574 GURL(GetDefaultUrlWithPath("/foo.dat")), DEFAULT_PRIORITY
, &d2
));
2575 spdy_url_request_context
.socket_factory().
2576 AddSocketDataProvider(&data2
);
2578 d2
.set_quit_on_redirect(true);
2580 base::RunLoop().Run();
2581 EXPECT_EQ(1, d2
.received_redirect_count());
2583 r2
->FollowDeferredRedirect();
2584 base::RunLoop().Run();
2585 EXPECT_EQ(1, d2
.response_started_count());
2586 EXPECT_FALSE(d2
.received_data_before_response());
2587 EXPECT_EQ(URLRequestStatus::SUCCESS
, r2
->status().status());
2588 std::string
contents2("hello!");
2589 EXPECT_EQ(contents2
, d2
.data_received());
2591 data
.CompleteRead();
2592 data2
.CompleteRead();
2593 EXPECT_TRUE(data
.at_read_eof());
2594 EXPECT_TRUE(data
.at_write_eof());
2595 EXPECT_TRUE(data2
.at_read_eof());
2596 EXPECT_TRUE(data2
.at_write_eof());
2599 TEST_P(SpdyNetworkTransactionTest
, ServerPushSingleDataFrame
) {
2600 scoped_ptr
<SpdyFrame
> stream1_syn(
2601 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2602 scoped_ptr
<SpdyFrame
> stream1_body(
2603 spdy_util_
.ConstructSpdyBodyFrame(1, true));
2604 MockWrite writes
[] = {
2605 CreateMockWrite(*stream1_syn
, 1),
2608 scoped_ptr
<SpdyFrame
>
2609 stream1_reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2610 scoped_ptr
<SpdyFrame
> stream2_syn(spdy_util_
.ConstructSpdyPush(
2611 NULL
, 0, 2, 1, GetDefaultUrlWithPath("/foo.dat").c_str()));
2612 const char kPushedData
[] = "pushed";
2613 scoped_ptr
<SpdyFrame
> stream2_body(
2614 spdy_util_
.ConstructSpdyBodyFrame(
2615 2, kPushedData
, strlen(kPushedData
), true));
2616 MockRead reads
[] = {
2617 CreateMockRead(*stream1_reply
, 2),
2618 CreateMockRead(*stream2_syn
, 3),
2619 CreateMockRead(*stream1_body
, 4, SYNCHRONOUS
),
2620 CreateMockRead(*stream2_body
, 5),
2621 MockRead(ASYNC
, ERR_IO_PENDING
, 6), // Force a pause
2624 HttpResponseInfo response
;
2625 HttpResponseInfo response2
;
2626 std::string
expected_push_result("pushed");
2627 OrderedSocketData
data(reads
, arraysize(reads
),
2628 writes
, arraysize(writes
));
2629 RunServerPushTest(&data
,
2632 expected_push_result
);
2634 // Verify the SYN_REPLY.
2635 EXPECT_TRUE(response
.headers
.get() != NULL
);
2636 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
2638 // Verify the pushed stream.
2639 EXPECT_TRUE(response2
.headers
.get() != NULL
);
2640 EXPECT_EQ("HTTP/1.1 200 OK", response2
.headers
->GetStatusLine());
2643 TEST_P(SpdyNetworkTransactionTest
, ServerPushBeforeSynReply
) {
2644 scoped_ptr
<SpdyFrame
> stream1_syn(
2645 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2646 scoped_ptr
<SpdyFrame
> stream1_body(
2647 spdy_util_
.ConstructSpdyBodyFrame(1, true));
2648 MockWrite writes
[] = {
2649 CreateMockWrite(*stream1_syn
, 1),
2652 scoped_ptr
<SpdyFrame
>
2653 stream1_reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2654 scoped_ptr
<SpdyFrame
> stream2_syn(spdy_util_
.ConstructSpdyPush(
2655 NULL
, 0, 2, 1, GetDefaultUrlWithPath("/foo.dat").c_str()));
2656 const char kPushedData
[] = "pushed";
2657 scoped_ptr
<SpdyFrame
> stream2_body(
2658 spdy_util_
.ConstructSpdyBodyFrame(
2659 2, kPushedData
, strlen(kPushedData
), true));
2660 MockRead reads
[] = {
2661 CreateMockRead(*stream2_syn
, 2),
2662 CreateMockRead(*stream1_reply
, 3),
2663 CreateMockRead(*stream1_body
, 4, SYNCHRONOUS
),
2664 CreateMockRead(*stream2_body
, 5),
2665 MockRead(ASYNC
, ERR_IO_PENDING
, 6), // Force a pause
2668 HttpResponseInfo response
;
2669 HttpResponseInfo response2
;
2670 std::string
expected_push_result("pushed");
2671 OrderedSocketData
data(reads
, arraysize(reads
),
2672 writes
, arraysize(writes
));
2673 RunServerPushTest(&data
,
2676 expected_push_result
);
2678 // Verify the SYN_REPLY.
2679 EXPECT_TRUE(response
.headers
.get() != NULL
);
2680 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
2682 // Verify the pushed stream.
2683 EXPECT_TRUE(response2
.headers
.get() != NULL
);
2684 EXPECT_EQ("HTTP/1.1 200 OK", response2
.headers
->GetStatusLine());
2687 TEST_P(SpdyNetworkTransactionTest
, ServerPushSingleDataFrame2
) {
2688 scoped_ptr
<SpdyFrame
> stream1_syn(
2689 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2690 MockWrite writes
[] = { CreateMockWrite(*stream1_syn
, 1), };
2692 scoped_ptr
<SpdyFrame
>
2693 stream1_reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2694 scoped_ptr
<SpdyFrame
> stream2_syn(spdy_util_
.ConstructSpdyPush(
2695 NULL
, 0, 2, 1, GetDefaultUrlWithPath("/foo.dat").c_str()));
2696 const char kPushedData
[] = "pushed";
2697 scoped_ptr
<SpdyFrame
> stream2_body(
2698 spdy_util_
.ConstructSpdyBodyFrame(
2699 2, kPushedData
, strlen(kPushedData
), true));
2700 scoped_ptr
<SpdyFrame
>
2701 stream1_body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
2702 MockRead reads
[] = {
2703 CreateMockRead(*stream1_reply
, 2),
2704 CreateMockRead(*stream2_syn
, 3),
2705 CreateMockRead(*stream2_body
, 4),
2706 CreateMockRead(*stream1_body
, 5, SYNCHRONOUS
),
2707 MockRead(ASYNC
, ERR_IO_PENDING
, 6), // Force a pause
2710 HttpResponseInfo response
;
2711 HttpResponseInfo response2
;
2712 std::string
expected_push_result("pushed");
2713 OrderedSocketData
data(reads
, arraysize(reads
),
2714 writes
, arraysize(writes
));
2715 RunServerPushTest(&data
,
2718 expected_push_result
);
2720 // Verify the SYN_REPLY.
2721 EXPECT_TRUE(response
.headers
.get() != NULL
);
2722 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
2724 // Verify the pushed stream.
2725 EXPECT_TRUE(response2
.headers
.get() != NULL
);
2726 EXPECT_EQ("HTTP/1.1 200 OK", response2
.headers
->GetStatusLine());
2729 TEST_P(SpdyNetworkTransactionTest
, ServerPushServerAborted
) {
2730 scoped_ptr
<SpdyFrame
> stream1_syn(
2731 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2732 scoped_ptr
<SpdyFrame
> stream1_body(
2733 spdy_util_
.ConstructSpdyBodyFrame(1, true));
2734 MockWrite writes
[] = {
2735 CreateMockWrite(*stream1_syn
, 1),
2738 scoped_ptr
<SpdyFrame
>
2739 stream1_reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2740 scoped_ptr
<SpdyFrame
> stream2_syn(spdy_util_
.ConstructSpdyPush(
2741 NULL
, 0, 2, 1, GetDefaultUrlWithPath("/foo.dat").c_str()));
2742 scoped_ptr
<SpdyFrame
> stream2_rst(
2743 spdy_util_
.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR
));
2744 MockRead reads
[] = {
2745 CreateMockRead(*stream1_reply
, 2),
2746 CreateMockRead(*stream2_syn
, 3),
2747 CreateMockRead(*stream2_rst
, 4),
2748 CreateMockRead(*stream1_body
, 5, SYNCHRONOUS
),
2749 MockRead(ASYNC
, ERR_IO_PENDING
, 6), // Force a pause
2752 OrderedSocketData
data(reads
, arraysize(reads
),
2753 writes
, arraysize(writes
));
2754 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
2755 BoundNetLog(), GetParam(), NULL
);
2757 helper
.RunPreTestSetup();
2758 helper
.AddData(&data
);
2760 HttpNetworkTransaction
* trans
= helper
.trans();
2762 // Start the transaction with basic parameters.
2763 TestCompletionCallback callback
;
2764 int rv
= trans
->Start(
2765 &CreateGetRequest(), callback
.callback(), BoundNetLog());
2766 EXPECT_EQ(ERR_IO_PENDING
, rv
);
2767 rv
= callback
.WaitForResult();
2770 // Verify that we consumed all test data.
2771 EXPECT_TRUE(data
.at_read_eof()) << "Read count: "
2772 << data
.read_count()
2774 << data
.read_index();
2775 EXPECT_TRUE(data
.at_write_eof()) << "Write count: "
2776 << data
.write_count()
2778 << data
.write_index();
2780 // Verify the SYN_REPLY.
2781 HttpResponseInfo response
= *trans
->GetResponseInfo();
2782 EXPECT_TRUE(response
.headers
.get() != NULL
);
2783 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
2786 // Verify that we don't leak streams and that we properly send a reset
2787 // if the server pushes the same stream twice.
2788 TEST_P(SpdyNetworkTransactionTest
, ServerPushDuplicate
) {
2789 scoped_ptr
<SpdyFrame
> stream1_syn(
2790 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2791 scoped_ptr
<SpdyFrame
> stream1_body(
2792 spdy_util_
.ConstructSpdyBodyFrame(1, true));
2793 scoped_ptr
<SpdyFrame
> stream3_rst(
2794 spdy_util_
.ConstructSpdyRstStream(4, RST_STREAM_PROTOCOL_ERROR
));
2795 MockWrite writes
[] = {
2796 CreateMockWrite(*stream1_syn
, 1),
2797 CreateMockWrite(*stream3_rst
, 5),
2800 scoped_ptr
<SpdyFrame
>
2801 stream1_reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2802 scoped_ptr
<SpdyFrame
> stream2_syn(spdy_util_
.ConstructSpdyPush(
2803 NULL
, 0, 2, 1, GetDefaultUrlWithPath("/foo.dat").c_str()));
2804 const char kPushedData
[] = "pushed";
2805 scoped_ptr
<SpdyFrame
> stream2_body(
2806 spdy_util_
.ConstructSpdyBodyFrame(
2807 2, kPushedData
, strlen(kPushedData
), true));
2808 scoped_ptr
<SpdyFrame
> stream3_syn(spdy_util_
.ConstructSpdyPush(
2809 NULL
, 0, 4, 1, GetDefaultUrlWithPath("/foo.dat").c_str()));
2810 MockRead reads
[] = {
2811 CreateMockRead(*stream1_reply
, 2),
2812 CreateMockRead(*stream2_syn
, 3),
2813 CreateMockRead(*stream3_syn
, 4),
2814 CreateMockRead(*stream1_body
, 6, SYNCHRONOUS
),
2815 CreateMockRead(*stream2_body
, 7),
2816 MockRead(ASYNC
, ERR_IO_PENDING
, 8), // Force a pause
2819 HttpResponseInfo response
;
2820 HttpResponseInfo response2
;
2821 std::string
expected_push_result("pushed");
2822 OrderedSocketData
data(reads
, arraysize(reads
),
2823 writes
, arraysize(writes
));
2824 RunServerPushTest(&data
,
2827 expected_push_result
);
2829 // Verify the SYN_REPLY.
2830 EXPECT_TRUE(response
.headers
.get() != NULL
);
2831 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
2833 // Verify the pushed stream.
2834 EXPECT_TRUE(response2
.headers
.get() != NULL
);
2835 EXPECT_EQ("HTTP/1.1 200 OK", response2
.headers
->GetStatusLine());
2838 TEST_P(SpdyNetworkTransactionTest
, ServerPushMultipleDataFrame
) {
2839 scoped_ptr
<SpdyFrame
> stream1_syn(
2840 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2841 scoped_ptr
<SpdyFrame
> stream1_body(
2842 spdy_util_
.ConstructSpdyBodyFrame(1, true));
2843 MockWrite writes
[] = {
2844 CreateMockWrite(*stream1_syn
, 1),
2847 scoped_ptr
<SpdyFrame
>
2848 stream1_reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2849 scoped_ptr
<SpdyFrame
> stream2_syn(spdy_util_
.ConstructSpdyPush(
2850 NULL
, 0, 2, 1, GetDefaultUrlWithPath("/foo.dat").c_str()));
2851 static const char kPushedData
[] = "pushed my darling hello my baby";
2852 scoped_ptr
<SpdyFrame
> stream2_body_base(
2853 spdy_util_
.ConstructSpdyBodyFrame(
2854 2, kPushedData
, strlen(kPushedData
), true));
2855 const size_t kChunkSize
= strlen(kPushedData
) / 4;
2856 scoped_ptr
<SpdyFrame
> stream2_body1(
2857 new SpdyFrame(stream2_body_base
->data(), kChunkSize
, false));
2858 scoped_ptr
<SpdyFrame
> stream2_body2(
2859 new SpdyFrame(stream2_body_base
->data() + kChunkSize
, kChunkSize
, false));
2860 scoped_ptr
<SpdyFrame
> stream2_body3(
2861 new SpdyFrame(stream2_body_base
->data() + 2 * kChunkSize
,
2862 kChunkSize
, false));
2863 scoped_ptr
<SpdyFrame
> stream2_body4(
2864 new SpdyFrame(stream2_body_base
->data() + 3 * kChunkSize
,
2865 stream2_body_base
->size() - 3 * kChunkSize
, false));
2866 MockRead reads
[] = {
2867 CreateMockRead(*stream1_reply
, 2),
2868 CreateMockRead(*stream2_syn
, 3),
2869 CreateMockRead(*stream2_body1
, 4),
2870 CreateMockRead(*stream2_body2
, 5),
2871 CreateMockRead(*stream2_body3
, 6),
2872 CreateMockRead(*stream2_body4
, 7),
2873 CreateMockRead(*stream1_body
, 8, SYNCHRONOUS
),
2874 MockRead(ASYNC
, ERR_IO_PENDING
, 9), // Force a pause
2877 HttpResponseInfo response
;
2878 HttpResponseInfo response2
;
2879 std::string
expected_push_result("pushed my darling hello my baby");
2880 OrderedSocketData
data(reads
, arraysize(reads
),
2881 writes
, arraysize(writes
));
2882 RunServerPushTest(&data
, &response
, &response2
, kPushedData
);
2884 // Verify the SYN_REPLY.
2885 EXPECT_TRUE(response
.headers
.get() != NULL
);
2886 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
2888 // Verify the pushed stream.
2889 EXPECT_TRUE(response2
.headers
.get() != NULL
);
2890 EXPECT_EQ("HTTP/1.1 200 OK", response2
.headers
->GetStatusLine());
2893 TEST_P(SpdyNetworkTransactionTest
, ServerPushMultipleDataFrameInterrupted
) {
2894 scoped_ptr
<SpdyFrame
> stream1_syn(
2895 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2896 scoped_ptr
<SpdyFrame
> stream1_body(
2897 spdy_util_
.ConstructSpdyBodyFrame(1, true));
2898 MockWrite writes
[] = {
2899 CreateMockWrite(*stream1_syn
, 1),
2902 scoped_ptr
<SpdyFrame
>
2903 stream1_reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2904 scoped_ptr
<SpdyFrame
> stream2_syn(spdy_util_
.ConstructSpdyPush(
2905 NULL
, 0, 2, 1, GetDefaultUrlWithPath("/foo.dat").c_str()));
2906 static const char kPushedData
[] = "pushed my darling hello my baby";
2907 scoped_ptr
<SpdyFrame
> stream2_body_base(
2908 spdy_util_
.ConstructSpdyBodyFrame(
2909 2, kPushedData
, strlen(kPushedData
), true));
2910 const size_t kChunkSize
= strlen(kPushedData
) / 4;
2911 scoped_ptr
<SpdyFrame
> stream2_body1(
2912 new SpdyFrame(stream2_body_base
->data(), kChunkSize
, false));
2913 scoped_ptr
<SpdyFrame
> stream2_body2(
2914 new SpdyFrame(stream2_body_base
->data() + kChunkSize
, kChunkSize
, false));
2915 scoped_ptr
<SpdyFrame
> stream2_body3(
2916 new SpdyFrame(stream2_body_base
->data() + 2 * kChunkSize
,
2917 kChunkSize
, false));
2918 scoped_ptr
<SpdyFrame
> stream2_body4(
2919 new SpdyFrame(stream2_body_base
->data() + 3 * kChunkSize
,
2920 stream2_body_base
->size() - 3 * kChunkSize
, false));
2921 MockRead reads
[] = {
2922 CreateMockRead(*stream1_reply
, 2),
2923 CreateMockRead(*stream2_syn
, 3),
2924 CreateMockRead(*stream2_body1
, 4),
2925 CreateMockRead(*stream2_body2
, 5),
2926 MockRead(ASYNC
, ERR_IO_PENDING
, 6), // Force a pause
2927 CreateMockRead(*stream2_body3
, 7),
2928 CreateMockRead(*stream2_body4
, 8),
2929 CreateMockRead(*stream1_body
.get(), 9, SYNCHRONOUS
),
2930 MockRead(ASYNC
, ERR_IO_PENDING
, 10) // Force a pause.
2933 HttpResponseInfo response
;
2934 HttpResponseInfo response2
;
2935 OrderedSocketData
data(reads
, arraysize(reads
),
2936 writes
, arraysize(writes
));
2937 RunServerPushTest(&data
, &response
, &response2
, kPushedData
);
2939 // Verify the SYN_REPLY.
2940 EXPECT_TRUE(response
.headers
.get() != NULL
);
2941 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
2943 // Verify the pushed stream.
2944 EXPECT_TRUE(response2
.headers
.get() != NULL
);
2945 EXPECT_EQ("HTTP/1.1 200 OK", response2
.headers
->GetStatusLine());
2948 TEST_P(SpdyNetworkTransactionTest
, ServerPushInvalidAssociatedStreamID0
) {
2949 if (spdy_util_
.spdy_version() == SPDY4
) {
2950 // PUSH_PROMISE with stream id 0 is connection-level error.
2951 // TODO(baranovich): Test session going away.
2955 scoped_ptr
<SpdyFrame
> stream1_syn(
2956 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2957 scoped_ptr
<SpdyFrame
> stream1_body(
2958 spdy_util_
.ConstructSpdyBodyFrame(1, true));
2959 scoped_ptr
<SpdyFrame
> stream2_rst(
2960 spdy_util_
.ConstructSpdyRstStream(2, RST_STREAM_REFUSED_STREAM
));
2961 MockWrite writes
[] = {
2962 CreateMockWrite(*stream1_syn
, 1),
2963 CreateMockWrite(*stream2_rst
, 4),
2966 scoped_ptr
<SpdyFrame
>
2967 stream1_reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2968 scoped_ptr
<SpdyFrame
> stream2_syn(spdy_util_
.ConstructSpdyPush(
2969 NULL
, 0, 2, 0, GetDefaultUrlWithPath("/foo.dat").c_str()));
2970 MockRead reads
[] = {
2971 CreateMockRead(*stream1_reply
, 2),
2972 CreateMockRead(*stream2_syn
, 3),
2973 CreateMockRead(*stream1_body
, 4),
2974 MockRead(ASYNC
, ERR_IO_PENDING
, 5) // Force a pause
2977 OrderedSocketData
data(reads
, arraysize(reads
),
2978 writes
, arraysize(writes
));
2979 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
2980 BoundNetLog(), GetParam(), NULL
);
2982 helper
.RunPreTestSetup();
2983 helper
.AddData(&data
);
2985 HttpNetworkTransaction
* trans
= helper
.trans();
2987 // Start the transaction with basic parameters.
2988 TestCompletionCallback callback
;
2989 int rv
= trans
->Start(
2990 &CreateGetRequest(), callback
.callback(), BoundNetLog());
2991 EXPECT_EQ(ERR_IO_PENDING
, rv
);
2992 rv
= callback
.WaitForResult();
2995 // Verify that we consumed all test data.
2996 EXPECT_TRUE(data
.at_read_eof()) << "Read count: "
2997 << data
.read_count()
2999 << data
.read_index();
3000 EXPECT_TRUE(data
.at_write_eof()) << "Write count: "
3001 << data
.write_count()
3003 << data
.write_index();
3005 // Verify the SYN_REPLY.
3006 HttpResponseInfo response
= *trans
->GetResponseInfo();
3007 EXPECT_TRUE(response
.headers
.get() != NULL
);
3008 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
3011 TEST_P(SpdyNetworkTransactionTest
, ServerPushInvalidAssociatedStreamID9
) {
3012 scoped_ptr
<SpdyFrame
> stream1_syn(
3013 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
3014 scoped_ptr
<SpdyFrame
> stream1_body(
3015 spdy_util_
.ConstructSpdyBodyFrame(1, true));
3016 scoped_ptr
<SpdyFrame
> stream2_rst(
3017 spdy_util_
.ConstructSpdyRstStream(2, RST_STREAM_INVALID_STREAM
));
3018 MockWrite writes
[] = {
3019 CreateMockWrite(*stream1_syn
, 1),
3020 CreateMockWrite(*stream2_rst
, 4),
3023 scoped_ptr
<SpdyFrame
>
3024 stream1_reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
3025 scoped_ptr
<SpdyFrame
> stream2_syn(spdy_util_
.ConstructSpdyPush(
3026 NULL
, 0, 2, 9, GetDefaultUrlWithPath("/foo.dat").c_str()));
3027 MockRead reads
[] = {
3028 CreateMockRead(*stream1_reply
, 2),
3029 CreateMockRead(*stream2_syn
, 3),
3030 CreateMockRead(*stream1_body
, 4),
3031 MockRead(ASYNC
, ERR_IO_PENDING
, 5), // Force a pause
3034 OrderedSocketData
data(reads
, arraysize(reads
),
3035 writes
, arraysize(writes
));
3036 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
3037 BoundNetLog(), GetParam(), NULL
);
3039 helper
.RunPreTestSetup();
3040 helper
.AddData(&data
);
3042 HttpNetworkTransaction
* trans
= helper
.trans();
3044 // Start the transaction with basic parameters.
3045 TestCompletionCallback callback
;
3046 int rv
= trans
->Start(
3047 &CreateGetRequest(), callback
.callback(), BoundNetLog());
3048 EXPECT_EQ(ERR_IO_PENDING
, rv
);
3049 rv
= callback
.WaitForResult();
3052 // Verify that we consumed all test data.
3053 EXPECT_TRUE(data
.at_read_eof()) << "Read count: "
3054 << data
.read_count()
3056 << data
.read_index();
3057 EXPECT_TRUE(data
.at_write_eof()) << "Write count: "
3058 << data
.write_count()
3060 << data
.write_index();
3062 // Verify the SYN_REPLY.
3063 HttpResponseInfo response
= *trans
->GetResponseInfo();
3064 EXPECT_TRUE(response
.headers
.get() != NULL
);
3065 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
3068 TEST_P(SpdyNetworkTransactionTest
, ServerPushNoURL
) {
3069 scoped_ptr
<SpdyFrame
> stream1_syn(
3070 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
3071 scoped_ptr
<SpdyFrame
> stream1_body(
3072 spdy_util_
.ConstructSpdyBodyFrame(1, true));
3073 scoped_ptr
<SpdyFrame
> stream2_rst(
3074 spdy_util_
.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR
));
3075 MockWrite writes
[] = {
3076 CreateMockWrite(*stream1_syn
, 1),
3077 CreateMockWrite(*stream2_rst
, 4),
3080 scoped_ptr
<SpdyFrame
>
3081 stream1_reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
3082 scoped_ptr
<SpdyHeaderBlock
> incomplete_headers(new SpdyHeaderBlock());
3083 (*incomplete_headers
)["hello"] = "bye";
3084 (*incomplete_headers
)[spdy_util_
.GetStatusKey()] = "200 OK";
3085 (*incomplete_headers
)[spdy_util_
.GetVersionKey()] = "HTTP/1.1";
3086 scoped_ptr
<SpdyFrame
> stream2_syn(spdy_util_
.ConstructInitialSpdyPushFrame(
3087 incomplete_headers
.Pass(), 2, 1));
3088 MockRead reads
[] = {
3089 CreateMockRead(*stream1_reply
, 2),
3090 CreateMockRead(*stream2_syn
, 3),
3091 CreateMockRead(*stream1_body
, 4),
3092 MockRead(ASYNC
, ERR_IO_PENDING
, 5) // Force a pause
3095 OrderedSocketData
data(reads
, arraysize(reads
),
3096 writes
, arraysize(writes
));
3097 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
3098 BoundNetLog(), GetParam(), NULL
);
3100 helper
.RunPreTestSetup();
3101 helper
.AddData(&data
);
3103 HttpNetworkTransaction
* trans
= helper
.trans();
3105 // Start the transaction with basic parameters.
3106 TestCompletionCallback callback
;
3107 int rv
= trans
->Start(
3108 &CreateGetRequest(), callback
.callback(), BoundNetLog());
3109 EXPECT_EQ(ERR_IO_PENDING
, rv
);
3110 rv
= callback
.WaitForResult();
3112 // Verify that we consumed all test data.
3113 EXPECT_TRUE(data
.at_read_eof()) << "Read count: "
3114 << data
.read_count()
3116 << data
.read_index();
3117 EXPECT_TRUE(data
.at_write_eof()) << "Write count: "
3118 << data
.write_count()
3120 << data
.write_index();
3122 // Verify the SYN_REPLY.
3123 HttpResponseInfo response
= *trans
->GetResponseInfo();
3124 EXPECT_TRUE(response
.headers
.get() != NULL
);
3125 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
3128 // Verify that various SynReply headers parse correctly through the
3130 TEST_P(SpdyNetworkTransactionTest
, SynReplyHeaders
) {
3131 struct SynReplyHeadersTests
{
3133 const char* extra_headers
[5];
3134 SpdyHeaderBlock expected_headers
;
3136 // This uses a multi-valued cookie header.
3139 "cookie", "val2", // will get appended separated by NULL
3143 // This is the minimalist set of headers.
3147 // Headers with a comma separated list.
3149 { "cookie", "val1,val2",
3155 test_cases
[0].expected_headers
["cookie"] = "val1";
3156 test_cases
[0].expected_headers
["cookie"] += '\0';
3157 test_cases
[0].expected_headers
["cookie"] += "val2";
3158 test_cases
[0].expected_headers
["hello"] = "bye";
3159 test_cases
[0].expected_headers
["status"] = "200";
3161 test_cases
[1].expected_headers
["hello"] = "bye";
3162 test_cases
[1].expected_headers
["status"] = "200";
3164 test_cases
[2].expected_headers
["cookie"] = "val1,val2";
3165 test_cases
[2].expected_headers
["hello"] = "bye";
3166 test_cases
[2].expected_headers
["status"] = "200";
3168 if (spdy_util_
.spdy_version() < SPDY4
) {
3169 // SPDY4/HTTP2 eliminates use of the :version header.
3170 test_cases
[0].expected_headers
["version"] = "HTTP/1.1";
3171 test_cases
[1].expected_headers
["version"] = "HTTP/1.1";
3172 test_cases
[2].expected_headers
["version"] = "HTTP/1.1";
3175 for (size_t i
= 0; i
< arraysize(test_cases
); ++i
) {
3176 scoped_ptr
<SpdyFrame
> req(
3177 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
3178 MockWrite writes
[] = { CreateMockWrite(*req
) };
3180 scoped_ptr
<SpdyFrame
> resp(
3181 spdy_util_
.ConstructSpdyGetSynReply(test_cases
[i
].extra_headers
,
3182 test_cases
[i
].num_headers
,
3184 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
3185 MockRead reads
[] = {
3186 CreateMockRead(*resp
),
3187 CreateMockRead(*body
),
3188 MockRead(ASYNC
, 0, 0) // EOF
3191 DelayedSocketData
data(1, reads
, arraysize(reads
),
3192 writes
, arraysize(writes
));
3193 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
3194 BoundNetLog(), GetParam(), NULL
);
3195 helper
.RunToCompletion(&data
);
3196 TransactionHelperResult out
= helper
.output();
3198 EXPECT_EQ(OK
, out
.rv
);
3199 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
3200 EXPECT_EQ("hello!", out
.response_data
);
3202 scoped_refptr
<HttpResponseHeaders
> headers
= out
.response_info
.headers
;
3203 EXPECT_TRUE(headers
.get() != NULL
);
3205 std::string name
, value
;
3206 SpdyHeaderBlock header_block
;
3207 while (headers
->EnumerateHeaderLines(&iter
, &name
, &value
)) {
3208 if (header_block
[name
].empty()) {
3209 header_block
[name
] = value
;
3211 header_block
[name
] += '\0';
3212 header_block
[name
] += value
;
3215 EXPECT_EQ(test_cases
[i
].expected_headers
, header_block
);
3219 // Verify that various SynReply headers parse vary fields correctly
3220 // through the HTTP layer, and the response matches the request.
3221 TEST_P(SpdyNetworkTransactionTest
, SynReplyHeadersVary
) {
3222 // Modify the following data to change/add test cases:
3223 struct SynReplyTests
{
3226 const char* extra_headers
[2][16];
3228 // Test the case of a multi-valued cookie. When the value is delimited
3229 // with NUL characters, it needs to be unfolded into multiple headers.
3233 { { "cookie", "val1,val2",
3237 spdy_util_
.GetStatusKey(), "200",
3238 spdy_util_
.GetPathKey(), "/index.php",
3239 spdy_util_
.GetVersionKey(), "HTTP/1.1",
3243 }, { // Multiple vary fields.
3246 { { "friend", "barney",
3247 "enemy", "snaggletooth",
3252 spdy_util_
.GetStatusKey(), "200",
3253 spdy_util_
.GetPathKey(), "/index.php",
3254 spdy_util_
.GetVersionKey(), "HTTP/1.1",
3258 }, { // Test a '*' vary field.
3261 { { "cookie", "val1,val2",
3265 spdy_util_
.GetStatusKey(), "200",
3266 spdy_util_
.GetPathKey(), "/index.php",
3267 spdy_util_
.GetVersionKey(), "HTTP/1.1",
3271 }, { // Multiple comma-separated vary fields.
3274 { { "friend", "barney",
3275 "enemy", "snaggletooth",
3278 { "vary", "friend,enemy",
3279 spdy_util_
.GetStatusKey(), "200",
3280 spdy_util_
.GetPathKey(), "/index.php",
3281 spdy_util_
.GetVersionKey(), "HTTP/1.1",
3288 for (size_t i
= 0; i
< arraysize(test_cases
); ++i
) {
3289 // Construct the request.
3290 scoped_ptr
<SpdyFrame
> frame_req(
3291 spdy_util_
.ConstructSpdyGet(test_cases
[i
].extra_headers
[0],
3292 test_cases
[i
].num_headers
[0],
3293 false, 1, LOWEST
, true));
3295 MockWrite writes
[] = {
3296 CreateMockWrite(*frame_req
),
3299 // Construct the reply.
3300 SpdyHeaderBlock reply_headers
;
3301 AppendToHeaderBlock(test_cases
[i
].extra_headers
[1],
3302 test_cases
[i
].num_headers
[1],
3304 scoped_ptr
<SpdyFrame
> frame_reply(
3305 spdy_util_
.ConstructSpdyReply(1, reply_headers
));
3307 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
3308 MockRead reads
[] = {
3309 CreateMockRead(*frame_reply
),
3310 CreateMockRead(*body
),
3311 MockRead(ASYNC
, 0, 0) // EOF
3314 // Attach the headers to the request.
3315 int header_count
= test_cases
[i
].num_headers
[0];
3317 HttpRequestInfo request
= CreateGetRequest();
3318 for (int ct
= 0; ct
< header_count
; ct
++) {
3319 const char* header_key
= test_cases
[i
].extra_headers
[0][ct
* 2];
3320 const char* header_value
= test_cases
[i
].extra_headers
[0][ct
* 2 + 1];
3321 request
.extra_headers
.SetHeader(header_key
, header_value
);
3324 DelayedSocketData
data(1, reads
, arraysize(reads
),
3325 writes
, arraysize(writes
));
3326 NormalSpdyTransactionHelper
helper(request
, DEFAULT_PRIORITY
,
3327 BoundNetLog(), GetParam(), NULL
);
3328 helper
.RunToCompletion(&data
);
3329 TransactionHelperResult out
= helper
.output();
3331 EXPECT_EQ(OK
, out
.rv
) << i
;
3332 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
) << i
;
3333 EXPECT_EQ("hello!", out
.response_data
) << i
;
3335 // Test the response information.
3336 EXPECT_TRUE(out
.response_info
.response_time
>
3337 out
.response_info
.request_time
) << i
;
3338 base::TimeDelta test_delay
= out
.response_info
.response_time
-
3339 out
.response_info
.request_time
;
3340 base::TimeDelta min_expected_delay
;
3341 min_expected_delay
.FromMilliseconds(10);
3342 EXPECT_GT(test_delay
.InMillisecondsF(),
3343 min_expected_delay
.InMillisecondsF()) << i
;
3344 EXPECT_EQ(out
.response_info
.vary_data
.is_valid(),
3345 test_cases
[i
].vary_matches
) << i
;
3347 // Check the headers.
3348 scoped_refptr
<HttpResponseHeaders
> headers
= out
.response_info
.headers
;
3349 ASSERT_TRUE(headers
.get() != NULL
) << i
;
3351 std::string name
, value
, lines
;
3352 while (headers
->EnumerateHeaderLines(&iter
, &name
, &value
)) {
3355 lines
.append(value
);
3359 // Construct the expected header reply string.
3360 std::string expected_reply
=
3361 spdy_util_
.ConstructSpdyReplyString(reply_headers
);
3362 EXPECT_EQ(expected_reply
, lines
) << i
;
3366 // Verify that we don't crash on invalid SynReply responses.
3367 TEST_P(SpdyNetworkTransactionTest
, InvalidSynReply
) {
3368 struct InvalidSynReplyTests
{
3370 const char* headers
[10];
3372 // SYN_REPLY missing status header
3376 spdy_util_
.GetPathKey(), "/index.php",
3377 spdy_util_
.GetVersionKey(), "HTTP/1.1",
3381 // SYN_REPLY missing version header
3384 spdy_util_
.GetPathKey(), "/index.php",
3388 // SYN_REPLY with no headers
3392 for (size_t i
= 0; i
< arraysize(test_cases
); ++i
) {
3393 scoped_ptr
<SpdyFrame
> req(
3394 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
3395 scoped_ptr
<SpdyFrame
> rst(
3396 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR
));
3397 MockWrite writes
[] = {
3398 CreateMockWrite(*req
),
3399 CreateMockWrite(*rst
),
3402 // Construct the reply.
3403 SpdyHeaderBlock reply_headers
;
3404 AppendToHeaderBlock(
3405 test_cases
[i
].headers
, test_cases
[i
].num_headers
, &reply_headers
);
3406 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyReply(1, reply_headers
));
3407 MockRead reads
[] = {
3408 CreateMockRead(*resp
),
3409 MockRead(ASYNC
, 0, 0) // EOF
3412 DelayedSocketData
data(1, reads
, arraysize(reads
),
3413 writes
, arraysize(writes
));
3414 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
3415 BoundNetLog(), GetParam(), NULL
);
3416 helper
.RunToCompletion(&data
);
3417 TransactionHelperResult out
= helper
.output();
3418 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR
, out
.rv
);
3422 // Verify that we don't crash on some corrupt frames.
3423 // TODO(jgraettinger): SPDY4 and up treats a header decompression failure as a
3424 // connection error. I'd like to backport this behavior to SPDY3 as well.
3425 TEST_P(SpdyNetworkTransactionTest
, CorruptFrameSessionError
) {
3426 if (spdy_util_
.spdy_version() >= SPDY4
) {
3429 // This is the length field that's too short.
3430 scoped_ptr
<SpdyFrame
> syn_reply_wrong_length(
3431 spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
3432 BufferedSpdyFramer
framer(spdy_util_
.spdy_version(), false);
3434 (spdy_util_
.spdy_version() < SPDY4
) ?
3435 syn_reply_wrong_length
->size() - framer
.GetControlFrameHeaderSize() :
3436 syn_reply_wrong_length
->size();
3437 size_t wrong_size
= right_size
- 4;
3438 test::SetFrameLength(syn_reply_wrong_length
.get(),
3440 spdy_util_
.spdy_version());
3442 struct SynReplyTests
{
3443 const SpdyFrame
* syn_reply
;
3445 { syn_reply_wrong_length
.get(), },
3448 for (size_t i
= 0; i
< arraysize(test_cases
); ++i
) {
3449 scoped_ptr
<SpdyFrame
> req(
3450 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
3451 scoped_ptr
<SpdyFrame
> rst(
3452 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR
));
3453 MockWrite writes
[] = {
3454 CreateMockWrite(*req
),
3455 CreateMockWrite(*rst
),
3458 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
3459 MockRead reads
[] = {
3460 MockRead(ASYNC
, test_cases
[i
].syn_reply
->data(), wrong_size
),
3461 CreateMockRead(*body
),
3462 MockRead(ASYNC
, 0, 0) // EOF
3465 DelayedSocketData
data(1, reads
, arraysize(reads
),
3466 writes
, arraysize(writes
));
3467 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
3468 BoundNetLog(), GetParam(), NULL
);
3469 helper
.RunToCompletion(&data
);
3470 TransactionHelperResult out
= helper
.output();
3471 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR
, out
.rv
);
3475 // SPDY4 treats a header decompression failure as a connection-level error.
3476 TEST_P(SpdyNetworkTransactionTest
, CorruptFrameSessionErrorSpdy4
) {
3477 if (spdy_util_
.spdy_version() < SPDY4
) {
3480 // This is the length field that's too short.
3481 scoped_ptr
<SpdyFrame
> syn_reply_wrong_length(
3482 spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
3483 BufferedSpdyFramer
framer(spdy_util_
.spdy_version(), false);
3485 syn_reply_wrong_length
->size() - framer
.GetControlFrameHeaderSize();
3486 size_t wrong_size
= right_size
- 4;
3487 test::SetFrameLength(syn_reply_wrong_length
.get(),
3489 spdy_util_
.spdy_version());
3491 scoped_ptr
<SpdyFrame
> req(
3492 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
3493 scoped_ptr
<SpdyFrame
> goaway(spdy_util_
.ConstructSpdyGoAway(
3494 0, GOAWAY_COMPRESSION_ERROR
, "Framer error: 5 (DECOMPRESS_FAILURE)."));
3495 MockWrite writes
[] = {CreateMockWrite(*req
), CreateMockWrite(*goaway
)};
3497 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
3498 MockRead reads
[] = {
3499 MockRead(ASYNC
, syn_reply_wrong_length
->data(),
3500 syn_reply_wrong_length
->size() - 4),
3503 DelayedSocketData
data(1, reads
, arraysize(reads
),
3504 writes
, arraysize(writes
));
3505 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
3506 BoundNetLog(), GetParam(), NULL
);
3507 helper
.RunToCompletion(&data
);
3508 TransactionHelperResult out
= helper
.output();
3509 EXPECT_EQ(ERR_SPDY_COMPRESSION_ERROR
, out
.rv
);
3512 TEST_P(SpdyNetworkTransactionTest
, GoAwayOnDecompressionFailure
) {
3513 if (GetParam().protocol
< kProtoSPDY4MinimumVersion
) {
3514 // Decompression failures are a stream error in SPDY3 and above.
3517 scoped_ptr
<SpdyFrame
> req(
3518 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
3519 scoped_ptr
<SpdyFrame
> goaway(spdy_util_
.ConstructSpdyGoAway(
3520 0, GOAWAY_COMPRESSION_ERROR
, "Framer error: 5 (DECOMPRESS_FAILURE)."));
3521 MockWrite writes
[] = {CreateMockWrite(*req
), CreateMockWrite(*goaway
)};
3523 // Read HEADERS with corrupted payload.
3524 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
3525 memset(resp
->data() + 12, 0xff, resp
->size() - 12);
3526 MockRead reads
[] = {CreateMockRead(*resp
)};
3528 DelayedSocketData
data(1, reads
, arraysize(reads
), writes
, arraysize(writes
));
3529 NormalSpdyTransactionHelper
helper(
3530 CreateGetRequest(), DEFAULT_PRIORITY
, BoundNetLog(), GetParam(), NULL
);
3531 helper
.RunToCompletion(&data
);
3532 TransactionHelperResult out
= helper
.output();
3533 EXPECT_EQ(ERR_SPDY_COMPRESSION_ERROR
, out
.rv
);
3536 TEST_P(SpdyNetworkTransactionTest
, GoAwayOnFrameSizeError
) {
3537 scoped_ptr
<SpdyFrame
> req(
3538 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
3539 scoped_ptr
<SpdyFrame
> goaway(spdy_util_
.ConstructSpdyGoAway(
3540 0, GOAWAY_PROTOCOL_ERROR
, "Framer error: 1 (INVALID_CONTROL_FRAME)."));
3541 MockWrite writes
[] = {CreateMockWrite(*req
), CreateMockWrite(*goaway
)};
3543 // Read WINDOW_UPDATE with incorrectly-sized payload.
3544 // TODO(jgraettinger): SpdyFramer signals this as an INVALID_CONTROL_FRAME,
3545 // which is mapped to a protocol error, and not a frame size error.
3546 scoped_ptr
<SpdyFrame
> bad_window_update(
3547 spdy_util_
.ConstructSpdyWindowUpdate(1, 1));
3548 test::SetFrameLength(bad_window_update
.get(),
3549 bad_window_update
->size() - 1,
3550 spdy_util_
.spdy_version());
3551 MockRead reads
[] = {CreateMockRead(*bad_window_update
)};
3553 DelayedSocketData
data(1, reads
, arraysize(reads
), writes
, arraysize(writes
));
3554 NormalSpdyTransactionHelper
helper(
3555 CreateGetRequest(), DEFAULT_PRIORITY
, BoundNetLog(), GetParam(), NULL
);
3556 helper
.RunToCompletion(&data
);
3557 TransactionHelperResult out
= helper
.output();
3558 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR
, out
.rv
);
3561 // Test that we shutdown correctly on write errors.
3562 TEST_P(SpdyNetworkTransactionTest
, WriteError
) {
3563 scoped_ptr
<SpdyFrame
> req(
3564 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
3565 MockWrite writes
[] = {
3566 // We'll write 10 bytes successfully
3567 MockWrite(ASYNC
, req
->data(), 10, 0),
3568 // Followed by ERROR!
3569 MockWrite(ASYNC
, ERR_FAILED
, 1),
3570 // Session drains and attempts to write a GOAWAY: Another ERROR!
3571 MockWrite(ASYNC
, ERR_FAILED
, 2),
3574 MockRead reads
[] = {
3575 MockRead(ASYNC
, 0, 3) // EOF
3578 DeterministicSocketData
data(reads
, arraysize(reads
),
3579 writes
, arraysize(writes
));
3581 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
3582 BoundNetLog(), GetParam(), NULL
);
3583 helper
.SetDeterministic();
3584 helper
.RunPreTestSetup();
3585 helper
.AddDeterministicData(&data
);
3586 EXPECT_TRUE(helper
.StartDefaultTest());
3588 helper
.FinishDefaultTest();
3589 EXPECT_TRUE(data
.at_write_eof());
3590 EXPECT_TRUE(!data
.at_read_eof());
3591 TransactionHelperResult out
= helper
.output();
3592 EXPECT_EQ(ERR_FAILED
, out
.rv
);
3595 // Test that partial writes work.
3596 TEST_P(SpdyNetworkTransactionTest
, PartialWrite
) {
3597 // Chop the SYN_STREAM frame into 5 chunks.
3598 scoped_ptr
<SpdyFrame
> req(
3599 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
3600 const int kChunks
= 5;
3601 scoped_ptr
<MockWrite
[]> writes(ChopWriteFrame(*req
.get(), kChunks
));
3603 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
3604 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
3605 MockRead reads
[] = {
3606 CreateMockRead(*resp
),
3607 CreateMockRead(*body
),
3608 MockRead(ASYNC
, 0, 0) // EOF
3611 DelayedSocketData
data(kChunks
, reads
, arraysize(reads
),
3612 writes
.get(), kChunks
);
3613 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
3614 BoundNetLog(), GetParam(), NULL
);
3615 helper
.RunToCompletion(&data
);
3616 TransactionHelperResult out
= helper
.output();
3617 EXPECT_EQ(OK
, out
.rv
);
3618 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
3619 EXPECT_EQ("hello!", out
.response_data
);
3622 // In this test, we enable compression, but get a uncompressed SynReply from
3623 // the server. Verify that teardown is all clean.
3624 TEST_P(SpdyNetworkTransactionTest
, DecompressFailureOnSynReply
) {
3625 if (spdy_util_
.spdy_version() >= SPDY4
) {
3626 // HPACK doesn't use deflate compression.
3629 scoped_ptr
<SpdyFrame
> compressed(
3630 spdy_util_
.ConstructSpdyGet(NULL
, 0, true, 1, LOWEST
, true));
3631 scoped_ptr
<SpdyFrame
> goaway(spdy_util_
.ConstructSpdyGoAway(
3632 0, GOAWAY_COMPRESSION_ERROR
, "Framer error: 5 (DECOMPRESS_FAILURE)."));
3633 MockWrite writes
[] = {CreateMockWrite(*compressed
), CreateMockWrite(*goaway
)};
3635 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
3636 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
3637 MockRead reads
[] = {
3638 CreateMockRead(*resp
),
3641 DelayedSocketData
data(1, reads
, arraysize(reads
),
3642 writes
, arraysize(writes
));
3643 SpdySessionDependencies
* session_deps
=
3644 CreateSpdySessionDependencies(GetParam());
3645 session_deps
->enable_compression
= true;
3646 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
3647 BoundNetLog(), GetParam(), session_deps
);
3648 helper
.RunToCompletion(&data
);
3649 TransactionHelperResult out
= helper
.output();
3650 EXPECT_EQ(ERR_SPDY_COMPRESSION_ERROR
, out
.rv
);
3654 // Test that the NetLog contains good data for a simple GET request.
3655 TEST_P(SpdyNetworkTransactionTest
, NetLog
) {
3656 static const char* const kExtraHeaders
[] = {
3657 "user-agent", "Chrome",
3659 scoped_ptr
<SpdyFrame
> req(
3660 spdy_util_
.ConstructSpdyGet(kExtraHeaders
, 1, false, 1, LOWEST
, true));
3661 MockWrite writes
[] = { CreateMockWrite(*req
) };
3663 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
3664 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
3665 MockRead reads
[] = {
3666 CreateMockRead(*resp
),
3667 CreateMockRead(*body
),
3668 MockRead(ASYNC
, 0, 0) // EOF
3671 CapturingBoundNetLog log
;
3673 DelayedSocketData
data(1, reads
, arraysize(reads
),
3674 writes
, arraysize(writes
));
3675 NormalSpdyTransactionHelper
helper(CreateGetRequestWithUserAgent(),
3677 log
.bound(), GetParam(), NULL
);
3678 helper
.RunToCompletion(&data
);
3679 TransactionHelperResult out
= helper
.output();
3680 EXPECT_EQ(OK
, out
.rv
);
3681 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
3682 EXPECT_EQ("hello!", out
.response_data
);
3684 // Check that the NetLog was filled reasonably.
3685 // This test is intentionally non-specific about the exact ordering of the
3686 // log; instead we just check to make sure that certain events exist, and that
3687 // they are in the right order.
3688 CapturingNetLog::CapturedEntryList entries
;
3689 log
.GetEntries(&entries
);
3691 EXPECT_LT(0u, entries
.size());
3693 pos
= ExpectLogContainsSomewhere(entries
, 0,
3694 NetLog::TYPE_HTTP_TRANSACTION_SEND_REQUEST
,
3695 NetLog::PHASE_BEGIN
);
3696 pos
= ExpectLogContainsSomewhere(entries
, pos
+ 1,
3697 NetLog::TYPE_HTTP_TRANSACTION_SEND_REQUEST
,
3699 pos
= ExpectLogContainsSomewhere(entries
, pos
+ 1,
3700 NetLog::TYPE_HTTP_TRANSACTION_READ_HEADERS
,
3701 NetLog::PHASE_BEGIN
);
3702 pos
= ExpectLogContainsSomewhere(entries
, pos
+ 1,
3703 NetLog::TYPE_HTTP_TRANSACTION_READ_HEADERS
,
3705 pos
= ExpectLogContainsSomewhere(entries
, pos
+ 1,
3706 NetLog::TYPE_HTTP_TRANSACTION_READ_BODY
,
3707 NetLog::PHASE_BEGIN
);
3708 pos
= ExpectLogContainsSomewhere(entries
, pos
+ 1,
3709 NetLog::TYPE_HTTP_TRANSACTION_READ_BODY
,
3712 // Check that we logged all the headers correctly
3713 const NetLog::EventType type
= (GetParam().protocol
<= kProtoSPDY31
)
3714 ? NetLog::TYPE_HTTP2_SESSION_SYN_STREAM
3715 : NetLog::TYPE_HTTP2_SESSION_SEND_HEADERS
;
3716 pos
= ExpectLogContainsSomewhere(entries
, 0, type
, NetLog::PHASE_NONE
);
3718 base::ListValue
* header_list
;
3719 ASSERT_TRUE(entries
[pos
].params
.get());
3720 ASSERT_TRUE(entries
[pos
].params
->GetList("headers", &header_list
));
3722 std::vector
<std::string
> expected
;
3723 expected
.push_back(std::string(spdy_util_
.GetHostKey()) + ": www.google.com");
3724 expected
.push_back(std::string(spdy_util_
.GetPathKey()) + ": /");
3725 expected
.push_back(std::string(spdy_util_
.GetSchemeKey()) + ": " +
3726 spdy_util_
.default_url().scheme());
3727 expected
.push_back(std::string(spdy_util_
.GetMethodKey()) + ": GET");
3728 expected
.push_back("user-agent: Chrome");
3729 if (spdy_util_
.spdy_version() < SPDY4
) {
3730 // SPDY4/HTTP2 eliminates use of the :version header.
3731 expected
.push_back(std::string(spdy_util_
.GetVersionKey()) + ": HTTP/1.1");
3733 EXPECT_EQ(expected
.size(), header_list
->GetSize());
3734 for (std::vector
<std::string
>::const_iterator it
= expected
.begin();
3735 it
!= expected
.end();
3737 base::StringValue
header(*it
);
3738 EXPECT_NE(header_list
->end(), header_list
->Find(header
)) <<
3739 "Header not found: " << *it
;
3743 // Since we buffer the IO from the stream to the renderer, this test verifies
3744 // that when we read out the maximum amount of data (e.g. we received 50 bytes
3745 // on the network, but issued a Read for only 5 of those bytes) that the data
3746 // flow still works correctly.
3747 TEST_P(SpdyNetworkTransactionTest
, BufferFull
) {
3748 BufferedSpdyFramer
framer(spdy_util_
.spdy_version(), false);
3750 scoped_ptr
<SpdyFrame
> req(
3751 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
3752 MockWrite writes
[] = { CreateMockWrite(*req
) };
3754 // 2 data frames in a single read.
3755 scoped_ptr
<SpdyFrame
> data_frame_1(
3756 framer
.CreateDataFrame(1, "goodby", 6, DATA_FLAG_NONE
));
3757 scoped_ptr
<SpdyFrame
> data_frame_2(
3758 framer
.CreateDataFrame(1, "e worl", 6, DATA_FLAG_NONE
));
3759 const SpdyFrame
* data_frames
[2] = {
3763 char combined_data_frames
[100];
3764 int combined_data_frames_len
=
3765 CombineFrames(data_frames
, arraysize(data_frames
),
3766 combined_data_frames
, arraysize(combined_data_frames
));
3767 scoped_ptr
<SpdyFrame
> last_frame(
3768 framer
.CreateDataFrame(1, "d", 1, DATA_FLAG_FIN
));
3770 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
3771 MockRead reads
[] = {
3772 CreateMockRead(*resp
),
3773 MockRead(ASYNC
, ERR_IO_PENDING
), // Force a pause
3774 MockRead(ASYNC
, combined_data_frames
, combined_data_frames_len
),
3775 MockRead(ASYNC
, ERR_IO_PENDING
), // Force a pause
3776 CreateMockRead(*last_frame
),
3777 MockRead(ASYNC
, 0, 0) // EOF
3780 DelayedSocketData
data(1, reads
, arraysize(reads
),
3781 writes
, arraysize(writes
));
3783 TestCompletionCallback callback
;
3785 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
3786 BoundNetLog(), GetParam(), NULL
);
3787 helper
.RunPreTestSetup();
3788 helper
.AddData(&data
);
3789 HttpNetworkTransaction
* trans
= helper
.trans();
3790 int rv
= trans
->Start(
3791 &CreateGetRequest(), callback
.callback(), BoundNetLog());
3792 EXPECT_EQ(ERR_IO_PENDING
, rv
);
3794 TransactionHelperResult out
= helper
.output();
3795 out
.rv
= callback
.WaitForResult();
3796 EXPECT_EQ(out
.rv
, OK
);
3798 const HttpResponseInfo
* response
= trans
->GetResponseInfo();
3799 EXPECT_TRUE(response
->headers
.get() != NULL
);
3800 EXPECT_TRUE(response
->was_fetched_via_spdy
);
3801 out
.status_line
= response
->headers
->GetStatusLine();
3802 out
.response_info
= *response
; // Make a copy so we can verify.
3805 TestCompletionCallback read_callback
;
3807 std::string content
;
3809 // Read small chunks at a time.
3810 const int kSmallReadSize
= 3;
3811 scoped_refptr
<IOBuffer
> buf(new IOBuffer(kSmallReadSize
));
3812 rv
= trans
->Read(buf
.get(), kSmallReadSize
, read_callback
.callback());
3813 if (rv
== ERR_IO_PENDING
) {
3814 data
.CompleteRead();
3815 rv
= read_callback
.WaitForResult();
3818 content
.append(buf
->data(), rv
);
3819 } else if (rv
< 0) {
3824 out
.response_data
.swap(content
);
3826 // Flush the MessageLoop while the SpdySessionDependencies (in particular, the
3827 // MockClientSocketFactory) are still alive.
3828 base::RunLoop().RunUntilIdle();
3830 // Verify that we consumed all test data.
3831 helper
.VerifyDataConsumed();
3833 EXPECT_EQ(OK
, out
.rv
);
3834 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
3835 EXPECT_EQ("goodbye world", out
.response_data
);
3838 // Verify that basic buffering works; when multiple data frames arrive
3839 // at the same time, ensure that we don't notify a read completion for
3840 // each data frame individually.
3841 TEST_P(SpdyNetworkTransactionTest
, Buffering
) {
3842 BufferedSpdyFramer
framer(spdy_util_
.spdy_version(), false);
3844 scoped_ptr
<SpdyFrame
> req(
3845 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
3846 MockWrite writes
[] = { CreateMockWrite(*req
) };
3848 // 4 data frames in a single read.
3849 scoped_ptr
<SpdyFrame
> data_frame(
3850 framer
.CreateDataFrame(1, "message", 7, DATA_FLAG_NONE
));
3851 scoped_ptr
<SpdyFrame
> data_frame_fin(
3852 framer
.CreateDataFrame(1, "message", 7, DATA_FLAG_FIN
));
3853 const SpdyFrame
* data_frames
[4] = {
3857 data_frame_fin
.get()
3859 char combined_data_frames
[100];
3860 int combined_data_frames_len
=
3861 CombineFrames(data_frames
, arraysize(data_frames
),
3862 combined_data_frames
, arraysize(combined_data_frames
));
3864 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
3865 MockRead reads
[] = {
3866 CreateMockRead(*resp
),
3867 MockRead(ASYNC
, ERR_IO_PENDING
), // Force a pause
3868 MockRead(ASYNC
, combined_data_frames
, combined_data_frames_len
),
3869 MockRead(ASYNC
, 0, 0) // EOF
3872 DelayedSocketData
data(1, reads
, arraysize(reads
),
3873 writes
, arraysize(writes
));
3875 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
3876 BoundNetLog(), GetParam(), NULL
);
3877 helper
.RunPreTestSetup();
3878 helper
.AddData(&data
);
3879 HttpNetworkTransaction
* trans
= helper
.trans();
3881 TestCompletionCallback callback
;
3882 int rv
= trans
->Start(
3883 &CreateGetRequest(), callback
.callback(), BoundNetLog());
3884 EXPECT_EQ(ERR_IO_PENDING
, rv
);
3886 TransactionHelperResult out
= helper
.output();
3887 out
.rv
= callback
.WaitForResult();
3888 EXPECT_EQ(out
.rv
, OK
);
3890 const HttpResponseInfo
* response
= trans
->GetResponseInfo();
3891 EXPECT_TRUE(response
->headers
.get() != NULL
);
3892 EXPECT_TRUE(response
->was_fetched_via_spdy
);
3893 out
.status_line
= response
->headers
->GetStatusLine();
3894 out
.response_info
= *response
; // Make a copy so we can verify.
3897 TestCompletionCallback read_callback
;
3899 std::string content
;
3900 int reads_completed
= 0;
3902 // Read small chunks at a time.
3903 const int kSmallReadSize
= 14;
3904 scoped_refptr
<IOBuffer
> buf(new IOBuffer(kSmallReadSize
));
3905 rv
= trans
->Read(buf
.get(), kSmallReadSize
, read_callback
.callback());
3906 if (rv
== ERR_IO_PENDING
) {
3907 data
.CompleteRead();
3908 rv
= read_callback
.WaitForResult();
3911 EXPECT_EQ(kSmallReadSize
, rv
);
3912 content
.append(buf
->data(), rv
);
3913 } else if (rv
< 0) {
3914 FAIL() << "Unexpected read error: " << rv
;
3919 EXPECT_EQ(3, reads_completed
); // Reads are: 14 bytes, 14 bytes, 0 bytes.
3921 out
.response_data
.swap(content
);
3923 // Flush the MessageLoop while the SpdySessionDependencies (in particular, the
3924 // MockClientSocketFactory) are still alive.
3925 base::RunLoop().RunUntilIdle();
3927 // Verify that we consumed all test data.
3928 helper
.VerifyDataConsumed();
3930 EXPECT_EQ(OK
, out
.rv
);
3931 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
3932 EXPECT_EQ("messagemessagemessagemessage", out
.response_data
);
3935 // Verify the case where we buffer data but read it after it has been buffered.
3936 TEST_P(SpdyNetworkTransactionTest
, BufferedAll
) {
3937 BufferedSpdyFramer
framer(spdy_util_
.spdy_version(), false);
3939 scoped_ptr
<SpdyFrame
> req(
3940 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
3941 MockWrite writes
[] = { CreateMockWrite(*req
) };
3943 // 5 data frames in a single read.
3944 scoped_ptr
<SpdyFrame
> reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
3945 scoped_ptr
<SpdyFrame
> data_frame(
3946 framer
.CreateDataFrame(1, "message", 7, DATA_FLAG_NONE
));
3947 scoped_ptr
<SpdyFrame
> data_frame_fin(
3948 framer
.CreateDataFrame(1, "message", 7, DATA_FLAG_FIN
));
3949 const SpdyFrame
* frames
[5] = {reply
.get(), data_frame
.get(), data_frame
.get(),
3950 data_frame
.get(), data_frame_fin
.get()};
3951 char combined_frames
[200];
3952 int combined_frames_len
=
3953 CombineFrames(frames
, arraysize(frames
),
3954 combined_frames
, arraysize(combined_frames
));
3956 MockRead reads
[] = {
3957 MockRead(ASYNC
, combined_frames
, combined_frames_len
),
3958 MockRead(ASYNC
, 0, 0) // EOF
3961 DelayedSocketData
data(1, reads
, arraysize(reads
),
3962 writes
, arraysize(writes
));
3964 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
3965 BoundNetLog(), GetParam(), NULL
);
3966 helper
.RunPreTestSetup();
3967 helper
.AddData(&data
);
3968 HttpNetworkTransaction
* trans
= helper
.trans();
3970 TestCompletionCallback callback
;
3971 int rv
= trans
->Start(
3972 &CreateGetRequest(), callback
.callback(), BoundNetLog());
3973 EXPECT_EQ(ERR_IO_PENDING
, rv
);
3975 TransactionHelperResult out
= helper
.output();
3976 out
.rv
= callback
.WaitForResult();
3977 EXPECT_EQ(out
.rv
, OK
);
3979 const HttpResponseInfo
* response
= trans
->GetResponseInfo();
3980 EXPECT_TRUE(response
->headers
.get() != NULL
);
3981 EXPECT_TRUE(response
->was_fetched_via_spdy
);
3982 out
.status_line
= response
->headers
->GetStatusLine();
3983 out
.response_info
= *response
; // Make a copy so we can verify.
3986 TestCompletionCallback read_callback
;
3988 std::string content
;
3989 int reads_completed
= 0;
3991 // Read small chunks at a time.
3992 const int kSmallReadSize
= 14;
3993 scoped_refptr
<IOBuffer
> buf(new IOBuffer(kSmallReadSize
));
3994 rv
= trans
->Read(buf
.get(), kSmallReadSize
, read_callback
.callback());
3996 EXPECT_EQ(kSmallReadSize
, rv
);
3997 content
.append(buf
->data(), rv
);
3998 } else if (rv
< 0) {
3999 FAIL() << "Unexpected read error: " << rv
;
4004 EXPECT_EQ(3, reads_completed
);
4006 out
.response_data
.swap(content
);
4008 // Flush the MessageLoop while the SpdySessionDependencies (in particular, the
4009 // MockClientSocketFactory) are still alive.
4010 base::RunLoop().RunUntilIdle();
4012 // Verify that we consumed all test data.
4013 helper
.VerifyDataConsumed();
4015 EXPECT_EQ(OK
, out
.rv
);
4016 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
4017 EXPECT_EQ("messagemessagemessagemessage", out
.response_data
);
4020 // Verify the case where we buffer data and close the connection.
4021 TEST_P(SpdyNetworkTransactionTest
, BufferedClosed
) {
4022 BufferedSpdyFramer
framer(spdy_util_
.spdy_version(), false);
4024 scoped_ptr
<SpdyFrame
> req(
4025 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
4026 MockWrite writes
[] = { CreateMockWrite(*req
) };
4028 // All data frames in a single read.
4029 // NOTE: We don't FIN the stream.
4030 scoped_ptr
<SpdyFrame
> data_frame(
4031 framer
.CreateDataFrame(1, "message", 7, DATA_FLAG_NONE
));
4032 const SpdyFrame
* data_frames
[4] = {
4038 char combined_data_frames
[100];
4039 int combined_data_frames_len
=
4040 CombineFrames(data_frames
, arraysize(data_frames
),
4041 combined_data_frames
, arraysize(combined_data_frames
));
4042 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
4043 MockRead reads
[] = {
4044 CreateMockRead(*resp
),
4045 MockRead(ASYNC
, ERR_IO_PENDING
), // Force a wait
4046 MockRead(ASYNC
, combined_data_frames
, combined_data_frames_len
),
4047 MockRead(ASYNC
, 0, 0) // EOF
4050 DelayedSocketData
data(1, reads
, arraysize(reads
),
4051 writes
, arraysize(writes
));
4053 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
4054 BoundNetLog(), GetParam(), NULL
);
4055 helper
.RunPreTestSetup();
4056 helper
.AddData(&data
);
4057 HttpNetworkTransaction
* trans
= helper
.trans();
4059 TestCompletionCallback callback
;
4061 int rv
= trans
->Start(
4062 &CreateGetRequest(), callback
.callback(), BoundNetLog());
4063 EXPECT_EQ(ERR_IO_PENDING
, rv
);
4065 TransactionHelperResult out
= helper
.output();
4066 out
.rv
= callback
.WaitForResult();
4067 EXPECT_EQ(out
.rv
, OK
);
4069 const HttpResponseInfo
* response
= trans
->GetResponseInfo();
4070 EXPECT_TRUE(response
->headers
.get() != NULL
);
4071 EXPECT_TRUE(response
->was_fetched_via_spdy
);
4072 out
.status_line
= response
->headers
->GetStatusLine();
4073 out
.response_info
= *response
; // Make a copy so we can verify.
4076 TestCompletionCallback read_callback
;
4078 std::string content
;
4079 int reads_completed
= 0;
4081 // Read small chunks at a time.
4082 const int kSmallReadSize
= 14;
4083 scoped_refptr
<IOBuffer
> buf(new IOBuffer(kSmallReadSize
));
4084 rv
= trans
->Read(buf
.get(), kSmallReadSize
, read_callback
.callback());
4085 if (rv
== ERR_IO_PENDING
) {
4086 data
.CompleteRead();
4087 rv
= read_callback
.WaitForResult();
4090 content
.append(buf
->data(), rv
);
4091 } else if (rv
< 0) {
4092 // This test intentionally closes the connection, and will get an error.
4093 EXPECT_EQ(ERR_CONNECTION_CLOSED
, rv
);
4099 EXPECT_EQ(0, reads_completed
);
4101 out
.response_data
.swap(content
);
4103 // Flush the MessageLoop while the SpdySessionDependencies (in particular, the
4104 // MockClientSocketFactory) are still alive.
4105 base::RunLoop().RunUntilIdle();
4107 // Verify that we consumed all test data.
4108 helper
.VerifyDataConsumed();
4111 // Verify the case where we buffer data and cancel the transaction.
4112 TEST_P(SpdyNetworkTransactionTest
, BufferedCancelled
) {
4113 BufferedSpdyFramer
framer(spdy_util_
.spdy_version(), false);
4115 scoped_ptr
<SpdyFrame
> req(
4116 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
4117 scoped_ptr
<SpdyFrame
> rst(
4118 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_CANCEL
));
4119 MockWrite writes
[] = {CreateMockWrite(*req
), CreateMockWrite(*rst
)};
4121 // NOTE: We don't FIN the stream.
4122 scoped_ptr
<SpdyFrame
> data_frame(
4123 framer
.CreateDataFrame(1, "message", 7, DATA_FLAG_NONE
));
4125 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
4126 MockRead reads
[] = {
4127 CreateMockRead(*resp
),
4128 MockRead(ASYNC
, ERR_IO_PENDING
), // Force a wait
4129 CreateMockRead(*data_frame
),
4130 MockRead(ASYNC
, 0, 0) // EOF
4133 DelayedSocketData
data(1, reads
, arraysize(reads
),
4134 writes
, arraysize(writes
));
4136 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
4137 BoundNetLog(), GetParam(), NULL
);
4138 helper
.RunPreTestSetup();
4139 helper
.AddData(&data
);
4140 HttpNetworkTransaction
* trans
= helper
.trans();
4141 TestCompletionCallback callback
;
4143 int rv
= trans
->Start(
4144 &CreateGetRequest(), callback
.callback(), BoundNetLog());
4145 EXPECT_EQ(ERR_IO_PENDING
, rv
);
4147 TransactionHelperResult out
= helper
.output();
4148 out
.rv
= callback
.WaitForResult();
4149 EXPECT_EQ(out
.rv
, OK
);
4151 const HttpResponseInfo
* response
= trans
->GetResponseInfo();
4152 EXPECT_TRUE(response
->headers
.get() != NULL
);
4153 EXPECT_TRUE(response
->was_fetched_via_spdy
);
4154 out
.status_line
= response
->headers
->GetStatusLine();
4155 out
.response_info
= *response
; // Make a copy so we can verify.
4158 TestCompletionCallback read_callback
;
4160 const int kReadSize
= 256;
4161 scoped_refptr
<IOBuffer
> buf(new IOBuffer(kReadSize
));
4162 rv
= trans
->Read(buf
.get(), kReadSize
, read_callback
.callback());
4163 ASSERT_EQ(ERR_IO_PENDING
, rv
) << "Unexpected read: " << rv
;
4165 // Complete the read now, which causes buffering to start.
4166 data
.CompleteRead();
4167 // Destroy the transaction, causing the stream to get cancelled
4168 // and orphaning the buffered IO task.
4169 helper
.ResetTrans();
4171 // Flush the MessageLoop; this will cause the buffered IO task
4172 // to run for the final time.
4173 base::RunLoop().RunUntilIdle();
4175 // Verify that we consumed all test data.
4176 helper
.VerifyDataConsumed();
4179 // Test that if the server requests persistence of settings, that we save
4180 // the settings in the HttpServerProperties.
4181 TEST_P(SpdyNetworkTransactionTest
, SettingsSaved
) {
4182 if (spdy_util_
.spdy_version() >= SPDY4
) {
4183 // SPDY4 doesn't support settings persistence.
4186 static const SpdyHeaderInfo kSynReplyInfo
= {
4187 SYN_REPLY
, // Syn Reply
4189 0, // Associated Stream ID
4190 ConvertRequestPriorityToSpdyPriority(
4191 LOWEST
, spdy_util_
.spdy_version()),
4192 kSpdyCredentialSlotUnused
,
4193 CONTROL_FLAG_NONE
, // Control Flags
4194 false, // Compressed
4195 RST_STREAM_INVALID
, // Status
4198 DATA_FLAG_NONE
// Data Flags
4201 BoundNetLog net_log
;
4202 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
4203 net_log
, GetParam(), NULL
);
4204 helper
.RunPreTestSetup();
4206 // Verify that no settings exist initially.
4207 HostPortPair
host_port_pair("www.google.com", helper
.port());
4208 SpdySessionPool
* spdy_session_pool
= helper
.session()->spdy_session_pool();
4209 EXPECT_TRUE(spdy_session_pool
->http_server_properties()->GetSpdySettings(
4210 host_port_pair
).empty());
4212 // Construct the request.
4213 scoped_ptr
<SpdyFrame
> req(
4214 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
4215 MockWrite writes
[] = { CreateMockWrite(*req
) };
4217 // Construct the reply.
4218 scoped_ptr
<SpdyHeaderBlock
> reply_headers(new SpdyHeaderBlock());
4219 (*reply_headers
)[spdy_util_
.GetStatusKey()] = "200";
4220 (*reply_headers
)[spdy_util_
.GetVersionKey()] = "HTTP/1.1";
4221 scoped_ptr
<SpdyFrame
> reply(
4222 spdy_util_
.ConstructSpdyFrame(kSynReplyInfo
, reply_headers
.Pass()));
4224 const SpdySettingsIds kSampleId1
= SETTINGS_UPLOAD_BANDWIDTH
;
4225 unsigned int kSampleValue1
= 0x0a0a0a0a;
4226 const SpdySettingsIds kSampleId2
= SETTINGS_DOWNLOAD_BANDWIDTH
;
4227 unsigned int kSampleValue2
= 0x0b0b0b0b;
4228 const SpdySettingsIds kSampleId3
= SETTINGS_ROUND_TRIP_TIME
;
4229 unsigned int kSampleValue3
= 0x0c0c0c0c;
4230 scoped_ptr
<SpdyFrame
> settings_frame
;
4232 // Construct the SETTINGS frame.
4233 SettingsMap settings
;
4234 // First add a persisted setting.
4235 settings
[kSampleId1
] =
4236 SettingsFlagsAndValue(SETTINGS_FLAG_PLEASE_PERSIST
, kSampleValue1
);
4237 // Next add a non-persisted setting.
4238 settings
[kSampleId2
] =
4239 SettingsFlagsAndValue(SETTINGS_FLAG_NONE
, kSampleValue2
);
4240 // Next add another persisted setting.
4241 settings
[kSampleId3
] =
4242 SettingsFlagsAndValue(SETTINGS_FLAG_PLEASE_PERSIST
, kSampleValue3
);
4243 settings_frame
.reset(spdy_util_
.ConstructSpdySettings(settings
));
4246 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
4247 MockRead reads
[] = {
4248 CreateMockRead(*reply
),
4249 CreateMockRead(*body
),
4250 CreateMockRead(*settings_frame
),
4251 MockRead(ASYNC
, 0, 0) // EOF
4254 DelayedSocketData
data(1, reads
, arraysize(reads
),
4255 writes
, arraysize(writes
));
4256 helper
.AddData(&data
);
4257 helper
.RunDefaultTest();
4258 helper
.VerifyDataConsumed();
4259 TransactionHelperResult out
= helper
.output();
4260 EXPECT_EQ(OK
, out
.rv
);
4261 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
4262 EXPECT_EQ("hello!", out
.response_data
);
4265 // Verify we had two persisted settings.
4266 const SettingsMap
& settings_map
=
4267 spdy_session_pool
->http_server_properties()->GetSpdySettings(
4269 ASSERT_EQ(2u, settings_map
.size());
4271 // Verify the first persisted setting.
4272 SettingsMap::const_iterator it1
= settings_map
.find(kSampleId1
);
4273 EXPECT_TRUE(it1
!= settings_map
.end());
4274 SettingsFlagsAndValue flags_and_value1
= it1
->second
;
4275 EXPECT_EQ(SETTINGS_FLAG_PERSISTED
, flags_and_value1
.first
);
4276 EXPECT_EQ(kSampleValue1
, flags_and_value1
.second
);
4278 // Verify the second persisted setting.
4279 SettingsMap::const_iterator it3
= settings_map
.find(kSampleId3
);
4280 EXPECT_TRUE(it3
!= settings_map
.end());
4281 SettingsFlagsAndValue flags_and_value3
= it3
->second
;
4282 EXPECT_EQ(SETTINGS_FLAG_PERSISTED
, flags_and_value3
.first
);
4283 EXPECT_EQ(kSampleValue3
, flags_and_value3
.second
);
4287 // Test that when there are settings saved that they are sent back to the
4288 // server upon session establishment.
4289 TEST_P(SpdyNetworkTransactionTest
, SettingsPlayback
) {
4290 if (spdy_util_
.spdy_version() >= SPDY4
) {
4291 // SPDY4 doesn't support settings persistence.
4294 static const SpdyHeaderInfo kSynReplyInfo
= {
4295 SYN_REPLY
, // Syn Reply
4297 0, // Associated Stream ID
4298 ConvertRequestPriorityToSpdyPriority(
4299 LOWEST
, spdy_util_
.spdy_version()),
4300 kSpdyCredentialSlotUnused
,
4301 CONTROL_FLAG_NONE
, // Control Flags
4302 false, // Compressed
4303 RST_STREAM_INVALID
, // Status
4306 DATA_FLAG_NONE
// Data Flags
4309 BoundNetLog net_log
;
4310 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
4311 net_log
, GetParam(), NULL
);
4312 helper
.RunPreTestSetup();
4314 SpdySessionPool
* spdy_session_pool
= helper
.session()->spdy_session_pool();
4316 SpdySessionPoolPeer
pool_peer(spdy_session_pool
);
4317 pool_peer
.SetEnableSendingInitialData(true);
4319 // Verify that no settings exist initially.
4320 HostPortPair
host_port_pair("www.google.com", helper
.port());
4321 EXPECT_TRUE(spdy_session_pool
->http_server_properties()->GetSpdySettings(
4322 host_port_pair
).empty());
4324 const SpdySettingsIds kSampleId1
= SETTINGS_MAX_CONCURRENT_STREAMS
;
4325 unsigned int kSampleValue1
= 0x0a0a0a0a;
4326 const SpdySettingsIds kSampleId2
= SETTINGS_INITIAL_WINDOW_SIZE
;
4327 unsigned int kSampleValue2
= 0x0c0c0c0c;
4329 // First add a persisted setting.
4330 spdy_session_pool
->http_server_properties()->SetSpdySetting(
4333 SETTINGS_FLAG_PLEASE_PERSIST
,
4336 // Next add another persisted setting.
4337 spdy_session_pool
->http_server_properties()->SetSpdySetting(
4340 SETTINGS_FLAG_PLEASE_PERSIST
,
4343 EXPECT_EQ(2u, spdy_session_pool
->http_server_properties()->GetSpdySettings(
4344 host_port_pair
).size());
4346 // Construct the initial SETTINGS frame.
4347 SettingsMap initial_settings
;
4348 initial_settings
[SETTINGS_MAX_CONCURRENT_STREAMS
] =
4349 SettingsFlagsAndValue(SETTINGS_FLAG_NONE
, kMaxConcurrentPushedStreams
);
4350 scoped_ptr
<SpdyFrame
> initial_settings_frame(
4351 spdy_util_
.ConstructSpdySettings(initial_settings
));
4353 // Construct the persisted SETTINGS frame.
4354 const SettingsMap
& settings
=
4355 spdy_session_pool
->http_server_properties()->GetSpdySettings(
4357 scoped_ptr
<SpdyFrame
> settings_frame(
4358 spdy_util_
.ConstructSpdySettings(settings
));
4360 // Construct the request.
4361 scoped_ptr
<SpdyFrame
> req(
4362 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
4364 std::vector
<MockWrite
> writes
;
4365 if ((GetParam().protocol
>= kProtoSPDY4MinimumVersion
) &&
4366 (GetParam().protocol
<= kProtoSPDY4MaximumVersion
)) {
4369 kHttp2ConnectionHeaderPrefix
,
4370 kHttp2ConnectionHeaderPrefixSize
));
4372 writes
.push_back(CreateMockWrite(*initial_settings_frame
));
4373 writes
.push_back(CreateMockWrite(*settings_frame
));
4374 writes
.push_back(CreateMockWrite(*req
));
4376 // Construct the reply.
4377 scoped_ptr
<SpdyHeaderBlock
> reply_headers(new SpdyHeaderBlock());
4378 (*reply_headers
)[spdy_util_
.GetStatusKey()] = "200";
4379 (*reply_headers
)[spdy_util_
.GetVersionKey()] = "HTTP/1.1";
4380 scoped_ptr
<SpdyFrame
> reply(
4381 spdy_util_
.ConstructSpdyFrame(kSynReplyInfo
, reply_headers
.Pass()));
4383 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
4384 MockRead reads
[] = {
4385 CreateMockRead(*reply
),
4386 CreateMockRead(*body
),
4387 MockRead(ASYNC
, 0, 0) // EOF
4390 DelayedSocketData
data(2, reads
, arraysize(reads
),
4391 vector_as_array(&writes
), writes
.size());
4392 helper
.AddData(&data
);
4393 helper
.RunDefaultTest();
4394 helper
.VerifyDataConsumed();
4395 TransactionHelperResult out
= helper
.output();
4396 EXPECT_EQ(OK
, out
.rv
);
4397 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
4398 EXPECT_EQ("hello!", out
.response_data
);
4401 // Verify we had two persisted settings.
4402 const SettingsMap
& settings_map
=
4403 spdy_session_pool
->http_server_properties()->GetSpdySettings(
4405 ASSERT_EQ(2u, settings_map
.size());
4407 // Verify the first persisted setting.
4408 SettingsMap::const_iterator it1
= settings_map
.find(kSampleId1
);
4409 EXPECT_TRUE(it1
!= settings_map
.end());
4410 SettingsFlagsAndValue flags_and_value1
= it1
->second
;
4411 EXPECT_EQ(SETTINGS_FLAG_PERSISTED
, flags_and_value1
.first
);
4412 EXPECT_EQ(kSampleValue1
, flags_and_value1
.second
);
4414 // Verify the second persisted setting.
4415 SettingsMap::const_iterator it2
= settings_map
.find(kSampleId2
);
4416 EXPECT_TRUE(it2
!= settings_map
.end());
4417 SettingsFlagsAndValue flags_and_value2
= it2
->second
;
4418 EXPECT_EQ(SETTINGS_FLAG_PERSISTED
, flags_and_value2
.first
);
4419 EXPECT_EQ(kSampleValue2
, flags_and_value2
.second
);
4423 TEST_P(SpdyNetworkTransactionTest
, GoAwayWithActiveStream
) {
4424 scoped_ptr
<SpdyFrame
> req(
4425 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
4426 MockWrite writes
[] = { CreateMockWrite(*req
) };
4428 scoped_ptr
<SpdyFrame
> go_away(spdy_util_
.ConstructSpdyGoAway());
4429 MockRead reads
[] = {
4430 CreateMockRead(*go_away
),
4433 DelayedSocketData
data(1, reads
, arraysize(reads
),
4434 writes
, arraysize(writes
));
4435 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
4436 BoundNetLog(), GetParam(), NULL
);
4437 helper
.AddData(&data
);
4438 helper
.RunToCompletion(&data
);
4439 TransactionHelperResult out
= helper
.output();
4440 EXPECT_EQ(ERR_ABORTED
, out
.rv
);
4443 TEST_P(SpdyNetworkTransactionTest
, CloseWithActiveStream
) {
4444 scoped_ptr
<SpdyFrame
> req(
4445 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
4446 MockWrite writes
[] = { CreateMockWrite(*req
) };
4448 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
4449 MockRead reads
[] = {
4450 CreateMockRead(*resp
),
4451 MockRead(SYNCHRONOUS
, 0, 0) // EOF
4454 DelayedSocketData
data(1, reads
, arraysize(reads
),
4455 writes
, arraysize(writes
));
4457 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
4458 log
, GetParam(), NULL
);
4459 helper
.RunPreTestSetup();
4460 helper
.AddData(&data
);
4461 HttpNetworkTransaction
* trans
= helper
.trans();
4463 TestCompletionCallback callback
;
4464 TransactionHelperResult out
;
4465 out
.rv
= trans
->Start(&CreateGetRequest(), callback
.callback(), log
);
4467 EXPECT_EQ(out
.rv
, ERR_IO_PENDING
);
4468 out
.rv
= callback
.WaitForResult();
4469 EXPECT_EQ(out
.rv
, OK
);
4471 const HttpResponseInfo
* response
= trans
->GetResponseInfo();
4472 EXPECT_TRUE(response
->headers
.get() != NULL
);
4473 EXPECT_TRUE(response
->was_fetched_via_spdy
);
4474 out
.rv
= ReadTransaction(trans
, &out
.response_data
);
4475 EXPECT_EQ(ERR_CONNECTION_CLOSED
, out
.rv
);
4477 // Verify that we consumed all test data.
4478 helper
.VerifyDataConsumed();
4481 // HTTP_1_1_REQUIRED results in ERR_HTTP_1_1_REQUIRED.
4482 TEST_P(SpdyNetworkTransactionTest
, HTTP11RequiredError
) {
4483 // HTTP_1_1_REQUIRED is only supported by SPDY4.
4484 if (spdy_util_
.spdy_version() < SPDY4
)
4487 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
4488 BoundNetLog(), GetParam(), nullptr);
4490 scoped_ptr
<SpdyFrame
> go_away(spdy_util_
.ConstructSpdyGoAway(
4491 0, GOAWAY_HTTP_1_1_REQUIRED
, "Try again using HTTP/1.1 please."));
4492 MockRead reads
[] = {
4493 CreateMockRead(*go_away
),
4495 DelayedSocketData
data(0, reads
, arraysize(reads
), nullptr, 0);
4497 helper
.RunToCompletion(&data
);
4498 TransactionHelperResult out
= helper
.output();
4499 EXPECT_EQ(ERR_HTTP_1_1_REQUIRED
, out
.rv
);
4502 // Retry with HTTP/1.1 when receiving HTTP_1_1_REQUIRED. Note that no actual
4503 // protocol negotiation happens, instead this test forces protocols for both
4505 TEST_P(SpdyNetworkTransactionTest
, HTTP11RequiredRetry
) {
4506 // HTTP_1_1_REQUIRED is only supported by SPDY4.
4507 if (spdy_util_
.spdy_version() < SPDY4
)
4509 // HTTP_1_1_REQUIRED implementation relies on the assumption that HTTP/2 is
4510 // only spoken over SSL.
4511 if (GetParam().ssl_type
!= HTTPS_SPDY_VIA_NPN
)
4514 HttpRequestInfo request
;
4515 request
.method
= "GET";
4516 request
.url
= GURL(GetDefaultUrl());
4517 scoped_ptr
<SpdySessionDependencies
> session_deps(
4518 CreateSpdySessionDependencies(GetParam()));
4519 // Do not force SPDY so that second socket can negotiate HTTP/1.1.
4520 session_deps
->next_protos
= SpdyNextProtos();
4521 NormalSpdyTransactionHelper
helper(request
, DEFAULT_PRIORITY
, BoundNetLog(),
4522 GetParam(), session_deps
.release());
4524 // First socket: HTTP/2 request rejected with HTTP_1_1_REQUIRED.
4525 const char* url
= request
.url
.spec().c_str();
4526 scoped_ptr
<SpdyHeaderBlock
> headers(spdy_util_
.ConstructGetHeaderBlock(url
));
4527 scoped_ptr
<SpdyFrame
> req(
4528 spdy_util_
.ConstructSpdySyn(1, *headers
, LOWEST
, false, true));
4529 MockWrite writes0
[] = {CreateMockWrite(*req
)};
4530 scoped_ptr
<SpdyFrame
> go_away(spdy_util_
.ConstructSpdyGoAway(
4531 0, GOAWAY_HTTP_1_1_REQUIRED
, "Try again using HTTP/1.1 please."));
4532 MockRead reads0
[] = {CreateMockRead(*go_away
)};
4533 DelayedSocketData
data0(1, reads0
, arraysize(reads0
), writes0
,
4534 arraysize(writes0
));
4536 scoped_ptr
<SSLSocketDataProvider
> ssl_provider0(
4537 new SSLSocketDataProvider(ASYNC
, OK
));
4538 // Expect HTTP/2 protocols too in SSLConfig.
4539 ssl_provider0
->next_protos_expected_in_ssl_config
.push_back(kProtoHTTP11
);
4540 ssl_provider0
->next_protos_expected_in_ssl_config
.push_back(kProtoSPDY31
);
4541 ssl_provider0
->next_protos_expected_in_ssl_config
.push_back(kProtoSPDY4_14
);
4542 ssl_provider0
->next_protos_expected_in_ssl_config
.push_back(kProtoSPDY4
);
4544 ssl_provider0
->SetNextProto(GetParam().protocol
);
4545 helper
.AddDataWithSSLSocketDataProvider(&data0
, ssl_provider0
.Pass());
4547 // Second socket: falling back to HTTP/1.1.
4548 MockWrite writes1
[] = {MockWrite(
4549 "GET / HTTP/1.1\r\n"
4550 "Host: www.google.com\r\n"
4551 "Connection: keep-alive\r\n\r\n")};
4552 MockRead reads1
[] = {MockRead(
4553 "HTTP/1.1 200 OK\r\n"
4554 "Content-Length: 5\r\n\r\n"
4556 DelayedSocketData
data1(1, reads1
, arraysize(reads1
), writes1
,
4557 arraysize(writes1
));
4559 scoped_ptr
<SSLSocketDataProvider
> ssl_provider1(
4560 new SSLSocketDataProvider(ASYNC
, OK
));
4561 // Expect only HTTP/1.1 protocol in SSLConfig.
4562 ssl_provider1
->next_protos_expected_in_ssl_config
.push_back(kProtoHTTP11
);
4564 ssl_provider1
->SetNextProto(kProtoHTTP11
);
4565 helper
.AddDataWithSSLSocketDataProvider(&data1
, ssl_provider1
.Pass());
4567 base::WeakPtr
<HttpServerProperties
> http_server_properties
=
4568 helper
.session()->spdy_session_pool()->http_server_properties();
4569 const HostPortPair host_port_pair
= HostPortPair::FromURL(GURL(url
));
4570 EXPECT_FALSE(http_server_properties
->RequiresHTTP11(host_port_pair
));
4572 helper
.RunPreTestSetup();
4573 helper
.StartDefaultTest();
4574 helper
.FinishDefaultTestWithoutVerification();
4575 helper
.VerifyDataConsumed();
4576 EXPECT_TRUE(http_server_properties
->RequiresHTTP11(host_port_pair
));
4578 const HttpResponseInfo
* response
= helper
.trans()->GetResponseInfo();
4579 ASSERT_TRUE(response
!= nullptr);
4580 ASSERT_TRUE(response
->headers
.get() != nullptr);
4581 EXPECT_EQ("HTTP/1.1 200 OK", response
->headers
->GetStatusLine());
4582 EXPECT_FALSE(response
->was_fetched_via_spdy
);
4583 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP1
, response
->connection_info
);
4584 EXPECT_TRUE(response
->was_npn_negotiated
);
4585 EXPECT_TRUE(request
.url
.SchemeIs("https"));
4586 EXPECT_EQ("127.0.0.1", response
->socket_address
.host());
4587 EXPECT_EQ(443, response
->socket_address
.port());
4588 std::string response_data
;
4589 ASSERT_EQ(OK
, ReadTransaction(helper
.trans(), &response_data
));
4590 EXPECT_EQ("hello", response_data
);
4593 // Retry with HTTP/1.1 to the proxy when receiving HTTP_1_1_REQUIRED from the
4594 // proxy. Note that no actual protocol negotiation happens, instead this test
4595 // forces protocols for both sockets.
4596 TEST_P(SpdyNetworkTransactionTest
, HTTP11RequiredProxyRetry
) {
4597 // HTTP_1_1_REQUIRED is only supported by SPDY4.
4598 if (spdy_util_
.spdy_version() < SPDY4
)
4600 // HTTP_1_1_REQUIRED implementation relies on the assumption that HTTP/2 is
4601 // only spoken over SSL.
4602 if (GetParam().ssl_type
!= HTTPS_SPDY_VIA_NPN
)
4605 HttpRequestInfo request
;
4606 request
.method
= "GET";
4607 request
.url
= GURL("https://www.google.com/");
4608 scoped_ptr
<SpdySessionDependencies
> session_deps(
4609 CreateSpdySessionDependencies(
4611 ProxyService::CreateFixedFromPacResult("HTTPS myproxy:70")));
4612 // Do not force SPDY so that second socket can negotiate HTTP/1.1.
4613 session_deps
->next_protos
= SpdyNextProtos();
4614 NormalSpdyTransactionHelper
helper(request
, DEFAULT_PRIORITY
, BoundNetLog(),
4615 GetParam(), session_deps
.release());
4617 // First socket: HTTP/2 CONNECT rejected with HTTP_1_1_REQUIRED.
4618 scoped_ptr
<SpdyFrame
> req(spdy_util_
.ConstructSpdyConnect(
4619 nullptr, 0, 1, LOWEST
, HostPortPair("www.google.com", 443)));
4620 MockWrite writes0
[] = {CreateMockWrite(*req
)};
4621 scoped_ptr
<SpdyFrame
> go_away(spdy_util_
.ConstructSpdyGoAway(
4622 0, GOAWAY_HTTP_1_1_REQUIRED
, "Try again using HTTP/1.1 please."));
4623 MockRead reads0
[] = {CreateMockRead(*go_away
)};
4624 DelayedSocketData
data0(1, reads0
, arraysize(reads0
), writes0
,
4625 arraysize(writes0
));
4627 scoped_ptr
<SSLSocketDataProvider
> ssl_provider0(
4628 new SSLSocketDataProvider(ASYNC
, OK
));
4629 // Expect HTTP/2 protocols too in SSLConfig.
4630 ssl_provider0
->next_protos_expected_in_ssl_config
.push_back(kProtoHTTP11
);
4631 ssl_provider0
->next_protos_expected_in_ssl_config
.push_back(kProtoSPDY31
);
4632 ssl_provider0
->next_protos_expected_in_ssl_config
.push_back(kProtoSPDY4_14
);
4633 ssl_provider0
->next_protos_expected_in_ssl_config
.push_back(kProtoSPDY4
);
4635 ssl_provider0
->SetNextProto(GetParam().protocol
);
4636 helper
.AddDataWithSSLSocketDataProvider(&data0
, ssl_provider0
.Pass());
4638 // Second socket: retry using HTTP/1.1.
4639 MockWrite writes1
[] = {
4641 "CONNECT www.google.com:443 HTTP/1.1\r\n"
4642 "Host: www.google.com\r\n"
4643 "Proxy-Connection: keep-alive\r\n\r\n"),
4645 "GET / HTTP/1.1\r\n"
4646 "Host: www.google.com\r\n"
4647 "Connection: keep-alive\r\n\r\n"),
4650 MockRead reads1
[] = {
4651 MockRead(ASYNC
, 2, "HTTP/1.1 200 OK\r\n\r\n"),
4653 "HTTP/1.1 200 OK\r\n"
4654 "Content-Length: 5\r\n\r\n"
4657 DelayedSocketData
data1(1, reads1
, arraysize(reads1
), writes1
,
4658 arraysize(writes1
));
4660 scoped_ptr
<SSLSocketDataProvider
> ssl_provider1(
4661 new SSLSocketDataProvider(ASYNC
, OK
));
4662 // Expect only HTTP/1.1 protocol in SSLConfig.
4663 ssl_provider1
->next_protos_expected_in_ssl_config
.push_back(kProtoHTTP11
);
4665 ssl_provider1
->SetNextProto(kProtoHTTP11
);
4666 helper
.AddDataWithSSLSocketDataProvider(&data1
, ssl_provider1
.Pass());
4668 // A third socket is needed for the tunnelled connection.
4669 scoped_ptr
<SSLSocketDataProvider
> ssl_provider2(
4670 new SSLSocketDataProvider(ASYNC
, OK
));
4671 helper
.session_deps()->socket_factory
->AddSSLSocketDataProvider(
4672 ssl_provider2
.get());
4674 base::WeakPtr
<HttpServerProperties
> http_server_properties
=
4675 helper
.session()->spdy_session_pool()->http_server_properties();
4676 const HostPortPair proxy_host_port_pair
= HostPortPair("myproxy", 70);
4677 EXPECT_FALSE(http_server_properties
->RequiresHTTP11(proxy_host_port_pair
));
4679 helper
.RunPreTestSetup();
4680 helper
.StartDefaultTest();
4681 helper
.FinishDefaultTestWithoutVerification();
4682 helper
.VerifyDataConsumed();
4683 EXPECT_TRUE(http_server_properties
->RequiresHTTP11(proxy_host_port_pair
));
4685 const HttpResponseInfo
* response
= helper
.trans()->GetResponseInfo();
4686 ASSERT_TRUE(response
!= nullptr);
4687 ASSERT_TRUE(response
->headers
.get() != nullptr);
4688 EXPECT_EQ("HTTP/1.1 200 OK", response
->headers
->GetStatusLine());
4689 EXPECT_FALSE(response
->was_fetched_via_spdy
);
4690 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP1
, response
->connection_info
);
4691 EXPECT_FALSE(response
->was_npn_negotiated
);
4692 EXPECT_TRUE(request
.url
.SchemeIs("https"));
4693 EXPECT_EQ("127.0.0.1", response
->socket_address
.host());
4694 EXPECT_EQ(70, response
->socket_address
.port());
4695 std::string response_data
;
4696 ASSERT_EQ(OK
, ReadTransaction(helper
.trans(), &response_data
));
4697 EXPECT_EQ("hello", response_data
);
4700 // Test to make sure we can correctly connect through a proxy.
4701 TEST_P(SpdyNetworkTransactionTest
, ProxyConnect
) {
4702 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
4703 BoundNetLog(), GetParam(), NULL
);
4704 helper
.session_deps().reset(CreateSpdySessionDependencies(
4706 ProxyService::CreateFixedFromPacResult("PROXY myproxy:70")));
4707 helper
.SetSession(make_scoped_refptr(
4708 SpdySessionDependencies::SpdyCreateSession(helper
.session_deps().get())));
4709 helper
.RunPreTestSetup();
4710 HttpNetworkTransaction
* trans
= helper
.trans();
4712 const char kConnect443
[] = {
4713 "CONNECT www.google.com:443 HTTP/1.1\r\n"
4714 "Host: www.google.com\r\n"
4715 "Proxy-Connection: keep-alive\r\n\r\n"};
4716 const char kHTTP200
[] = {"HTTP/1.1 200 OK\r\n\r\n"};
4717 scoped_ptr
<SpdyFrame
> req(
4718 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
4719 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
4720 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
4722 MockWrite writes
[] = {
4723 MockWrite(SYNCHRONOUS
, kConnect443
, arraysize(kConnect443
) - 1, 0),
4724 CreateMockWrite(*req
, 2),
4726 MockRead reads
[] = {
4727 MockRead(SYNCHRONOUS
, kHTTP200
, arraysize(kHTTP200
) - 1, 1),
4728 CreateMockRead(*resp
, 3),
4729 CreateMockRead(*body
.get(), 4),
4730 MockRead(ASYNC
, 0, 0, 5),
4732 scoped_ptr
<OrderedSocketData
> data(new OrderedSocketData(
4733 reads
, arraysize(reads
), writes
, arraysize(writes
)));
4735 helper
.AddData(data
.get());
4736 TestCompletionCallback callback
;
4738 int rv
= trans
->Start(
4739 &CreateGetRequest(), callback
.callback(), BoundNetLog());
4740 EXPECT_EQ(ERR_IO_PENDING
, rv
);
4742 rv
= callback
.WaitForResult();
4745 // Verify the SYN_REPLY.
4746 HttpResponseInfo response
= *trans
->GetResponseInfo();
4747 EXPECT_TRUE(response
.headers
.get() != NULL
);
4748 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
4750 std::string response_data
;
4751 ASSERT_EQ(OK
, ReadTransaction(trans
, &response_data
));
4752 EXPECT_EQ("hello!", response_data
);
4753 helper
.VerifyDataConsumed();
4756 // Test to make sure we can correctly connect through a proxy to www.google.com,
4757 // if there already exists a direct spdy connection to www.google.com. See
4758 // http://crbug.com/49874
4759 TEST_P(SpdyNetworkTransactionTest
, DirectConnectProxyReconnect
) {
4760 // When setting up the first transaction, we store the SpdySessionPool so that
4761 // we can use the same pool in the second transaction.
4762 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
4763 BoundNetLog(), GetParam(), NULL
);
4765 // Use a proxy service which returns a proxy fallback list from DIRECT to
4766 // myproxy:70. For this test there will be no fallback, so it is equivalent
4767 // to simply DIRECT. The reason for appending the second proxy is to verify
4768 // that the session pool key used does is just "DIRECT".
4769 helper
.session_deps().reset(CreateSpdySessionDependencies(
4771 ProxyService::CreateFixedFromPacResult("DIRECT; PROXY myproxy:70")));
4772 helper
.SetSession(make_scoped_refptr(
4773 SpdySessionDependencies::SpdyCreateSession(helper
.session_deps().get())));
4775 SpdySessionPool
* spdy_session_pool
= helper
.session()->spdy_session_pool();
4776 helper
.RunPreTestSetup();
4778 // Construct and send a simple GET request.
4779 scoped_ptr
<SpdyFrame
> req(
4780 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
4781 MockWrite writes
[] = {
4782 CreateMockWrite(*req
, 1),
4785 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
4786 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
4787 MockRead reads
[] = {
4788 CreateMockRead(*resp
, 2),
4789 CreateMockRead(*body
, 3),
4790 MockRead(ASYNC
, ERR_IO_PENDING
, 4), // Force a pause
4791 MockRead(ASYNC
, 0, 5) // EOF
4793 OrderedSocketData
data(reads
, arraysize(reads
),
4794 writes
, arraysize(writes
));
4795 helper
.AddData(&data
);
4796 HttpNetworkTransaction
* trans
= helper
.trans();
4798 TestCompletionCallback callback
;
4799 TransactionHelperResult out
;
4800 out
.rv
= trans
->Start(
4801 &CreateGetRequest(), callback
.callback(), BoundNetLog());
4803 EXPECT_EQ(out
.rv
, ERR_IO_PENDING
);
4804 out
.rv
= callback
.WaitForResult();
4805 EXPECT_EQ(out
.rv
, OK
);
4807 const HttpResponseInfo
* response
= trans
->GetResponseInfo();
4808 EXPECT_TRUE(response
->headers
.get() != NULL
);
4809 EXPECT_TRUE(response
->was_fetched_via_spdy
);
4810 out
.rv
= ReadTransaction(trans
, &out
.response_data
);
4811 EXPECT_EQ(OK
, out
.rv
);
4812 out
.status_line
= response
->headers
->GetStatusLine();
4813 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
4814 EXPECT_EQ("hello!", out
.response_data
);
4816 // Check that the SpdySession is still in the SpdySessionPool.
4817 HostPortPair
host_port_pair("www.google.com", helper
.port());
4818 SpdySessionKey
session_pool_key_direct(
4819 host_port_pair
, ProxyServer::Direct(), PRIVACY_MODE_DISABLED
);
4820 EXPECT_TRUE(HasSpdySession(spdy_session_pool
, session_pool_key_direct
));
4821 SpdySessionKey
session_pool_key_proxy(
4823 ProxyServer::FromURI("www.foo.com", ProxyServer::SCHEME_HTTP
),
4824 PRIVACY_MODE_DISABLED
);
4825 EXPECT_FALSE(HasSpdySession(spdy_session_pool
, session_pool_key_proxy
));
4827 // Set up data for the proxy connection.
4828 const char kConnect443
[] = {"CONNECT www.google.com:443 HTTP/1.1\r\n"
4829 "Host: www.google.com\r\n"
4830 "Proxy-Connection: keep-alive\r\n\r\n"};
4831 const char kHTTP200
[] = {"HTTP/1.1 200 OK\r\n\r\n"};
4832 scoped_ptr
<SpdyFrame
> req2(spdy_util_
.ConstructSpdyGet(
4833 GetDefaultUrlWithPath("/foo.dat").c_str(), false, 1, LOWEST
));
4834 scoped_ptr
<SpdyFrame
> resp2(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
4835 scoped_ptr
<SpdyFrame
> body2(spdy_util_
.ConstructSpdyBodyFrame(1, true));
4837 MockWrite writes2
[] = {
4838 MockWrite(SYNCHRONOUS
, kConnect443
, arraysize(kConnect443
) - 1, 0),
4839 CreateMockWrite(*req2
, 2),
4841 MockRead reads2
[] = {
4842 MockRead(SYNCHRONOUS
, kHTTP200
, arraysize(kHTTP200
) - 1, 1),
4843 CreateMockRead(*resp2
, 3),
4844 CreateMockRead(*body2
, 4),
4845 MockRead(ASYNC
, 0, 5) // EOF
4848 scoped_ptr
<OrderedSocketData
> data_proxy(new OrderedSocketData(
4849 reads2
, arraysize(reads2
), writes2
, arraysize(writes2
)));
4851 // Create another request to www.google.com, but this time through a proxy.
4852 HttpRequestInfo request_proxy
;
4853 request_proxy
.method
= "GET";
4854 request_proxy
.url
= GURL(GetDefaultUrlWithPath("/foo.dat"));
4855 request_proxy
.load_flags
= 0;
4856 scoped_ptr
<SpdySessionDependencies
> ssd_proxy(
4857 CreateSpdySessionDependencies(GetParam()));
4858 // Ensure that this transaction uses the same SpdySessionPool.
4859 scoped_refptr
<HttpNetworkSession
> session_proxy(
4860 SpdySessionDependencies::SpdyCreateSession(ssd_proxy
.get()));
4861 NormalSpdyTransactionHelper
helper_proxy(request_proxy
, DEFAULT_PRIORITY
,
4862 BoundNetLog(), GetParam(), NULL
);
4863 HttpNetworkSessionPeer
session_peer(session_proxy
);
4864 scoped_ptr
<ProxyService
> proxy_service(
4865 ProxyService::CreateFixedFromPacResult("PROXY myproxy:70"));
4866 session_peer
.SetProxyService(proxy_service
.get());
4867 helper_proxy
.session_deps().swap(ssd_proxy
);
4868 helper_proxy
.SetSession(session_proxy
);
4869 helper_proxy
.RunPreTestSetup();
4870 helper_proxy
.AddData(data_proxy
.get());
4872 HttpNetworkTransaction
* trans_proxy
= helper_proxy
.trans();
4873 TestCompletionCallback callback_proxy
;
4874 int rv
= trans_proxy
->Start(
4875 &request_proxy
, callback_proxy
.callback(), BoundNetLog());
4876 EXPECT_EQ(ERR_IO_PENDING
, rv
);
4877 rv
= callback_proxy
.WaitForResult();
4880 HttpResponseInfo response_proxy
= *trans_proxy
->GetResponseInfo();
4881 EXPECT_TRUE(response_proxy
.headers
.get() != NULL
);
4882 EXPECT_EQ("HTTP/1.1 200 OK", response_proxy
.headers
->GetStatusLine());
4884 std::string response_data
;
4885 ASSERT_EQ(OK
, ReadTransaction(trans_proxy
, &response_data
));
4886 EXPECT_EQ("hello!", response_data
);
4888 data
.CompleteRead();
4889 helper_proxy
.VerifyDataConsumed();
4892 // When we get a TCP-level RST, we need to retry a HttpNetworkTransaction
4893 // on a new connection, if the connection was previously known to be good.
4894 // This can happen when a server reboots without saying goodbye, or when
4895 // we're behind a NAT that masked the RST.
4896 TEST_P(SpdyNetworkTransactionTest
, VerifyRetryOnConnectionReset
) {
4897 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
4898 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
4899 MockRead reads
[] = {
4900 CreateMockRead(*resp
),
4901 CreateMockRead(*body
),
4902 MockRead(ASYNC
, ERR_IO_PENDING
),
4903 MockRead(ASYNC
, ERR_CONNECTION_RESET
),
4906 MockRead reads2
[] = {
4907 CreateMockRead(*resp
),
4908 CreateMockRead(*body
),
4909 MockRead(ASYNC
, 0, 0) // EOF
4912 // This test has a couple of variants.
4914 // Induce the RST while waiting for our transaction to send.
4915 VARIANT_RST_DURING_SEND_COMPLETION
,
4916 // Induce the RST while waiting for our transaction to read.
4917 // In this case, the send completed - everything copied into the SNDBUF.
4918 VARIANT_RST_DURING_READ_COMPLETION
4921 for (int variant
= VARIANT_RST_DURING_SEND_COMPLETION
;
4922 variant
<= VARIANT_RST_DURING_READ_COMPLETION
;
4924 DelayedSocketData
data1(1, reads
, arraysize(reads
), NULL
, 0);
4926 DelayedSocketData
data2(1, reads2
, arraysize(reads2
), NULL
, 0);
4928 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
4929 BoundNetLog(), GetParam(), NULL
);
4930 helper
.AddData(&data1
);
4931 helper
.AddData(&data2
);
4932 helper
.RunPreTestSetup();
4934 for (int i
= 0; i
< 2; ++i
) {
4935 scoped_ptr
<HttpNetworkTransaction
> trans(
4936 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
4938 TestCompletionCallback callback
;
4939 int rv
= trans
->Start(
4940 &helper
.request(), callback
.callback(), BoundNetLog());
4941 EXPECT_EQ(ERR_IO_PENDING
, rv
);
4942 // On the second transaction, we trigger the RST.
4944 if (variant
== VARIANT_RST_DURING_READ_COMPLETION
) {
4945 // Writes to the socket complete asynchronously on SPDY by running
4946 // through the message loop. Complete the write here.
4947 base::RunLoop().RunUntilIdle();
4950 // Now schedule the ERR_CONNECTION_RESET.
4951 EXPECT_EQ(3u, data1
.read_index());
4952 data1
.CompleteRead();
4953 EXPECT_EQ(4u, data1
.read_index());
4955 rv
= callback
.WaitForResult();
4958 const HttpResponseInfo
* response
= trans
->GetResponseInfo();
4959 ASSERT_TRUE(response
!= NULL
);
4960 EXPECT_TRUE(response
->headers
.get() != NULL
);
4961 EXPECT_TRUE(response
->was_fetched_via_spdy
);
4962 std::string response_data
;
4963 rv
= ReadTransaction(trans
.get(), &response_data
);
4965 EXPECT_EQ("HTTP/1.1 200 OK", response
->headers
->GetStatusLine());
4966 EXPECT_EQ("hello!", response_data
);
4969 helper
.VerifyDataConsumed();
4973 // Test that turning SPDY on and off works properly.
4974 TEST_P(SpdyNetworkTransactionTest
, SpdyOnOffToggle
) {
4975 HttpStreamFactory::set_spdy_enabled(true);
4976 scoped_ptr
<SpdyFrame
> req(
4977 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
4978 MockWrite spdy_writes
[] = { CreateMockWrite(*req
) };
4980 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
4981 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
4982 MockRead spdy_reads
[] = {
4983 CreateMockRead(*resp
),
4984 CreateMockRead(*body
),
4985 MockRead(ASYNC
, 0, 0) // EOF
4988 DelayedSocketData
data(1, spdy_reads
, arraysize(spdy_reads
),
4989 spdy_writes
, arraysize(spdy_writes
));
4990 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
4991 BoundNetLog(), GetParam(), NULL
);
4992 helper
.RunToCompletion(&data
);
4993 TransactionHelperResult out
= helper
.output();
4994 EXPECT_EQ(OK
, out
.rv
);
4995 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
4996 EXPECT_EQ("hello!", out
.response_data
);
4998 HttpStreamFactory::set_spdy_enabled(false);
4999 MockRead http_reads
[] = {
5000 MockRead("HTTP/1.1 200 OK\r\n\r\n"),
5001 MockRead("hello from http"),
5002 MockRead(SYNCHRONOUS
, OK
),
5004 DelayedSocketData
data2(1, http_reads
, arraysize(http_reads
), NULL
, 0);
5005 NormalSpdyTransactionHelper
helper2(CreateGetRequest(), DEFAULT_PRIORITY
,
5006 BoundNetLog(), GetParam(), NULL
);
5007 helper2
.SetSpdyDisabled();
5008 helper2
.RunToCompletion(&data2
);
5009 TransactionHelperResult out2
= helper2
.output();
5010 EXPECT_EQ(OK
, out2
.rv
);
5011 EXPECT_EQ("HTTP/1.1 200 OK", out2
.status_line
);
5012 EXPECT_EQ("hello from http", out2
.response_data
);
5014 HttpStreamFactory::set_spdy_enabled(true);
5017 // Tests that Basic authentication works over SPDY
5018 TEST_P(SpdyNetworkTransactionTest
, SpdyBasicAuth
) {
5019 HttpStreamFactory::set_spdy_enabled(true);
5021 // The first request will be a bare GET, the second request will be a
5022 // GET with an Authorization header.
5023 scoped_ptr
<SpdyFrame
> req_get(
5024 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
5025 const char* const kExtraAuthorizationHeaders
[] = {
5026 "authorization", "Basic Zm9vOmJhcg=="
5028 scoped_ptr
<SpdyFrame
> req_get_authorization(
5029 spdy_util_
.ConstructSpdyGet(kExtraAuthorizationHeaders
,
5030 arraysize(kExtraAuthorizationHeaders
) / 2,
5031 false, 3, LOWEST
, true));
5032 MockWrite spdy_writes
[] = {
5033 CreateMockWrite(*req_get
, 1),
5034 CreateMockWrite(*req_get_authorization
, 4),
5037 // The first response is a 401 authentication challenge, and the second
5038 // response will be a 200 response since the second request includes a valid
5039 // Authorization header.
5040 const char* const kExtraAuthenticationHeaders
[] = {
5042 "Basic realm=\"MyRealm\""
5044 scoped_ptr
<SpdyFrame
> resp_authentication(
5045 spdy_util_
.ConstructSpdySynReplyError(
5046 "401 Authentication Required",
5047 kExtraAuthenticationHeaders
,
5048 arraysize(kExtraAuthenticationHeaders
) / 2,
5050 scoped_ptr
<SpdyFrame
> body_authentication(
5051 spdy_util_
.ConstructSpdyBodyFrame(1, true));
5052 scoped_ptr
<SpdyFrame
> resp_data(
5053 spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 3));
5054 scoped_ptr
<SpdyFrame
> body_data(spdy_util_
.ConstructSpdyBodyFrame(3, true));
5055 MockRead spdy_reads
[] = {
5056 CreateMockRead(*resp_authentication
, 2),
5057 CreateMockRead(*body_authentication
, 3),
5058 CreateMockRead(*resp_data
, 5),
5059 CreateMockRead(*body_data
, 6),
5060 MockRead(ASYNC
, 0, 7),
5063 OrderedSocketData
data(spdy_reads
, arraysize(spdy_reads
),
5064 spdy_writes
, arraysize(spdy_writes
));
5065 HttpRequestInfo
request(CreateGetRequest());
5066 BoundNetLog net_log
;
5067 NormalSpdyTransactionHelper
helper(request
, DEFAULT_PRIORITY
,
5068 net_log
, GetParam(), NULL
);
5070 helper
.RunPreTestSetup();
5071 helper
.AddData(&data
);
5072 HttpNetworkTransaction
* trans
= helper
.trans();
5073 TestCompletionCallback callback
;
5074 const int rv_start
= trans
->Start(&request
, callback
.callback(), net_log
);
5075 EXPECT_EQ(ERR_IO_PENDING
, rv_start
);
5076 const int rv_start_complete
= callback
.WaitForResult();
5077 EXPECT_EQ(OK
, rv_start_complete
);
5079 // Make sure the response has an auth challenge.
5080 const HttpResponseInfo
* const response_start
= trans
->GetResponseInfo();
5081 ASSERT_TRUE(response_start
!= NULL
);
5082 ASSERT_TRUE(response_start
->headers
.get() != NULL
);
5083 EXPECT_EQ(401, response_start
->headers
->response_code());
5084 EXPECT_TRUE(response_start
->was_fetched_via_spdy
);
5085 AuthChallengeInfo
* auth_challenge
= response_start
->auth_challenge
.get();
5086 ASSERT_TRUE(auth_challenge
!= NULL
);
5087 EXPECT_FALSE(auth_challenge
->is_proxy
);
5088 EXPECT_EQ("basic", auth_challenge
->scheme
);
5089 EXPECT_EQ("MyRealm", auth_challenge
->realm
);
5091 // Restart with a username/password.
5092 AuthCredentials
credentials(base::ASCIIToUTF16("foo"),
5093 base::ASCIIToUTF16("bar"));
5094 TestCompletionCallback callback_restart
;
5095 const int rv_restart
= trans
->RestartWithAuth(
5096 credentials
, callback_restart
.callback());
5097 EXPECT_EQ(ERR_IO_PENDING
, rv_restart
);
5098 const int rv_restart_complete
= callback_restart
.WaitForResult();
5099 EXPECT_EQ(OK
, rv_restart_complete
);
5100 // TODO(cbentzel): This is actually the same response object as before, but
5101 // data has changed.
5102 const HttpResponseInfo
* const response_restart
= trans
->GetResponseInfo();
5103 ASSERT_TRUE(response_restart
!= NULL
);
5104 ASSERT_TRUE(response_restart
->headers
.get() != NULL
);
5105 EXPECT_EQ(200, response_restart
->headers
->response_code());
5106 EXPECT_TRUE(response_restart
->auth_challenge
.get() == NULL
);
5109 TEST_P(SpdyNetworkTransactionTest
, ServerPushWithHeaders
) {
5110 scoped_ptr
<SpdyFrame
> stream1_syn(
5111 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
5112 scoped_ptr
<SpdyFrame
> stream1_body(
5113 spdy_util_
.ConstructSpdyBodyFrame(1, true));
5114 MockWrite writes
[] = {
5115 CreateMockWrite(*stream1_syn
, 1),
5118 scoped_ptr
<SpdyHeaderBlock
> initial_headers(new SpdyHeaderBlock());
5119 spdy_util_
.AddUrlToHeaderBlock(GetDefaultUrlWithPath("/foo.dat"),
5120 initial_headers
.get());
5121 scoped_ptr
<SpdyFrame
> stream2_syn(
5122 spdy_util_
.ConstructInitialSpdyPushFrame(initial_headers
.Pass(), 2, 1));
5124 scoped_ptr
<SpdyHeaderBlock
> late_headers(new SpdyHeaderBlock());
5125 (*late_headers
)["hello"] = "bye";
5126 (*late_headers
)[spdy_util_
.GetStatusKey()] = "200";
5127 (*late_headers
)[spdy_util_
.GetVersionKey()] = "HTTP/1.1";
5128 scoped_ptr
<SpdyFrame
> stream2_headers(
5129 spdy_util_
.ConstructSpdyControlFrame(late_headers
.Pass(),
5137 scoped_ptr
<SpdyFrame
>
5138 stream1_reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
5139 const char kPushedData
[] = "pushed";
5140 scoped_ptr
<SpdyFrame
> stream2_body(
5141 spdy_util_
.ConstructSpdyBodyFrame(
5142 2, kPushedData
, strlen(kPushedData
), true));
5143 MockRead reads
[] = {
5144 CreateMockRead(*stream1_reply
, 2),
5145 CreateMockRead(*stream2_syn
, 3),
5146 CreateMockRead(*stream2_headers
, 4),
5147 CreateMockRead(*stream1_body
, 5, SYNCHRONOUS
),
5148 CreateMockRead(*stream2_body
, 5),
5149 MockRead(ASYNC
, ERR_IO_PENDING
, 7), // Force a pause
5152 HttpResponseInfo response
;
5153 HttpResponseInfo response2
;
5154 std::string
expected_push_result("pushed");
5155 OrderedSocketData
data(reads
, arraysize(reads
),
5156 writes
, arraysize(writes
));
5157 RunServerPushTest(&data
,
5160 expected_push_result
);
5162 // Verify the SYN_REPLY.
5163 EXPECT_TRUE(response
.headers
.get() != NULL
);
5164 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
5166 // Verify the pushed stream.
5167 EXPECT_TRUE(response2
.headers
.get() != NULL
);
5168 EXPECT_EQ("HTTP/1.1 200 OK", response2
.headers
->GetStatusLine());
5171 TEST_P(SpdyNetworkTransactionTest
, ServerPushClaimBeforeHeaders
) {
5172 // We push a stream and attempt to claim it before the headers come down.
5173 scoped_ptr
<SpdyFrame
> stream1_syn(
5174 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
5175 scoped_ptr
<SpdyFrame
> stream1_body(
5176 spdy_util_
.ConstructSpdyBodyFrame(1, true));
5177 MockWrite writes
[] = {
5178 CreateMockWrite(*stream1_syn
, 0, SYNCHRONOUS
),
5181 scoped_ptr
<SpdyHeaderBlock
> initial_headers(new SpdyHeaderBlock());
5182 spdy_util_
.AddUrlToHeaderBlock(GetDefaultUrlWithPath("/foo.dat"),
5183 initial_headers
.get());
5184 scoped_ptr
<SpdyFrame
> stream2_syn(
5185 spdy_util_
.ConstructInitialSpdyPushFrame(initial_headers
.Pass(), 2, 1));
5187 scoped_ptr
<SpdyHeaderBlock
> late_headers(new SpdyHeaderBlock());
5188 (*late_headers
)["hello"] = "bye";
5189 (*late_headers
)[spdy_util_
.GetStatusKey()] = "200";
5190 (*late_headers
)[spdy_util_
.GetVersionKey()] = "HTTP/1.1";
5191 scoped_ptr
<SpdyFrame
> stream2_headers(
5192 spdy_util_
.ConstructSpdyControlFrame(late_headers
.Pass(),
5200 scoped_ptr
<SpdyFrame
>
5201 stream1_reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
5202 const char kPushedData
[] = "pushed";
5203 scoped_ptr
<SpdyFrame
> stream2_body(
5204 spdy_util_
.ConstructSpdyBodyFrame(
5205 2, kPushedData
, strlen(kPushedData
), true));
5206 MockRead reads
[] = {
5207 CreateMockRead(*stream1_reply
, 1),
5208 CreateMockRead(*stream2_syn
, 2),
5209 CreateMockRead(*stream1_body
, 3),
5210 CreateMockRead(*stream2_headers
, 4),
5211 CreateMockRead(*stream2_body
, 5),
5212 MockRead(ASYNC
, 0, 6), // EOF
5215 HttpResponseInfo response
;
5216 HttpResponseInfo response2
;
5217 std::string
expected_push_result("pushed");
5218 DeterministicSocketData
data(reads
, arraysize(reads
),
5219 writes
, arraysize(writes
));
5221 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
5222 BoundNetLog(), GetParam(), NULL
);
5223 helper
.SetDeterministic();
5224 helper
.AddDeterministicData(&data
);
5225 helper
.RunPreTestSetup();
5227 HttpNetworkTransaction
* trans
= helper
.trans();
5229 // Run until we've received the primary SYN_STREAM, the pushed SYN_STREAM,
5230 // and the body of the primary stream, but before we've received the HEADERS
5231 // for the pushed stream.
5234 // Start the transaction.
5235 TestCompletionCallback callback
;
5236 int rv
= trans
->Start(
5237 &CreateGetRequest(), callback
.callback(), BoundNetLog());
5238 EXPECT_EQ(ERR_IO_PENDING
, rv
);
5240 rv
= callback
.WaitForResult();
5243 // Request the pushed path. At this point, we've received the push, but the
5244 // headers are not yet complete.
5245 scoped_ptr
<HttpNetworkTransaction
> trans2(
5246 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
5248 &CreateGetPushRequest(), callback
.callback(), BoundNetLog());
5249 EXPECT_EQ(ERR_IO_PENDING
, rv
);
5251 base::RunLoop().RunUntilIdle();
5253 // Read the server push body.
5254 std::string result2
;
5255 ReadResult(trans2
.get(), &data
, &result2
);
5256 // Read the response body.
5258 ReadResult(trans
, &data
, &result
);
5260 // Verify that the received push data is same as the expected push data.
5261 EXPECT_EQ(result2
.compare(expected_push_result
), 0)
5262 << "Received data: "
5264 << "||||| Expected data: "
5265 << expected_push_result
;
5267 // Verify the SYN_REPLY.
5268 // Copy the response info, because trans goes away.
5269 response
= *trans
->GetResponseInfo();
5270 response2
= *trans2
->GetResponseInfo();
5272 VerifyStreamsClosed(helper
);
5274 // Verify the SYN_REPLY.
5275 EXPECT_TRUE(response
.headers
.get() != NULL
);
5276 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
5278 // Verify the pushed stream.
5279 EXPECT_TRUE(response2
.headers
.get() != NULL
);
5280 EXPECT_EQ("HTTP/1.1 200 OK", response2
.headers
->GetStatusLine());
5282 // Read the final EOF (which will close the session)
5285 // Verify that we consumed all test data.
5286 EXPECT_TRUE(data
.at_read_eof());
5287 EXPECT_TRUE(data
.at_write_eof());
5290 // TODO(baranovich): HTTP 2 does not allow multiple HEADERS frames
5291 TEST_P(SpdyNetworkTransactionTest
, ServerPushWithTwoHeaderFrames
) {
5292 // We push a stream and attempt to claim it before the headers come down.
5293 scoped_ptr
<SpdyFrame
> stream1_syn(
5294 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
5295 scoped_ptr
<SpdyFrame
> stream1_body(
5296 spdy_util_
.ConstructSpdyBodyFrame(1, true));
5297 MockWrite writes
[] = {
5298 CreateMockWrite(*stream1_syn
, 0, SYNCHRONOUS
),
5301 scoped_ptr
<SpdyHeaderBlock
> initial_headers(new SpdyHeaderBlock());
5302 if (spdy_util_
.spdy_version() < SPDY4
) {
5303 // In SPDY4 PUSH_PROMISE headers won't show up in the response headers.
5304 (*initial_headers
)["alpha"] = "beta";
5306 spdy_util_
.AddUrlToHeaderBlock(GetDefaultUrlWithPath("/foo.dat"),
5307 initial_headers
.get());
5308 scoped_ptr
<SpdyFrame
> stream2_syn(
5309 spdy_util_
.ConstructInitialSpdyPushFrame(initial_headers
.Pass(), 2, 1));
5311 scoped_ptr
<SpdyHeaderBlock
> middle_headers(new SpdyHeaderBlock());
5312 (*middle_headers
)["hello"] = "bye";
5313 scoped_ptr
<SpdyFrame
> stream2_headers1(
5314 spdy_util_
.ConstructSpdyControlFrame(middle_headers
.Pass(),
5322 scoped_ptr
<SpdyHeaderBlock
> late_headers(new SpdyHeaderBlock());
5323 (*late_headers
)[spdy_util_
.GetStatusKey()] = "200";
5324 if (spdy_util_
.spdy_version() < SPDY4
) {
5325 // SPDY4/HTTP2 eliminates use of the :version header.
5326 (*late_headers
)[spdy_util_
.GetVersionKey()] = "HTTP/1.1";
5328 scoped_ptr
<SpdyFrame
> stream2_headers2(
5329 spdy_util_
.ConstructSpdyControlFrame(late_headers
.Pass(),
5337 scoped_ptr
<SpdyFrame
>
5338 stream1_reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
5339 const char kPushedData
[] = "pushed";
5340 scoped_ptr
<SpdyFrame
> stream2_body(
5341 spdy_util_
.ConstructSpdyBodyFrame(
5342 2, kPushedData
, strlen(kPushedData
), true));
5343 MockRead reads
[] = {
5344 CreateMockRead(*stream1_reply
, 1),
5345 CreateMockRead(*stream2_syn
, 2),
5346 CreateMockRead(*stream1_body
, 3),
5347 CreateMockRead(*stream2_headers1
, 4),
5348 CreateMockRead(*stream2_headers2
, 5),
5349 CreateMockRead(*stream2_body
, 6),
5350 MockRead(ASYNC
, 0, 7), // EOF
5353 HttpResponseInfo response
;
5354 HttpResponseInfo response2
;
5355 std::string
expected_push_result("pushed");
5356 DeterministicSocketData
data(reads
, arraysize(reads
),
5357 writes
, arraysize(writes
));
5359 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
5360 BoundNetLog(), GetParam(), NULL
);
5361 helper
.SetDeterministic();
5362 helper
.AddDeterministicData(&data
);
5363 helper
.RunPreTestSetup();
5365 HttpNetworkTransaction
* trans
= helper
.trans();
5367 // Run until we've received the primary SYN_STREAM, the pushed SYN_STREAM,
5368 // the first HEADERS frame, and the body of the primary stream, but before
5369 // we've received the final HEADERS for the pushed stream.
5372 // Start the transaction.
5373 TestCompletionCallback callback
;
5374 int rv
= trans
->Start(
5375 &CreateGetRequest(), callback
.callback(), BoundNetLog());
5376 EXPECT_EQ(ERR_IO_PENDING
, rv
);
5378 rv
= callback
.WaitForResult();
5381 // Request the pushed path. At this point, we've received the push, but the
5382 // headers are not yet complete.
5383 scoped_ptr
<HttpNetworkTransaction
> trans2(
5384 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
5386 &CreateGetPushRequest(), callback
.callback(), BoundNetLog());
5387 EXPECT_EQ(ERR_IO_PENDING
, rv
);
5389 base::RunLoop().RunUntilIdle();
5391 // Read the server push body.
5392 std::string result2
;
5393 ReadResult(trans2
.get(), &data
, &result2
);
5394 // Read the response body.
5396 ReadResult(trans
, &data
, &result
);
5398 // Verify that the received push data is same as the expected push data.
5399 EXPECT_EQ(expected_push_result
, result2
);
5401 // Verify the SYN_REPLY.
5402 // Copy the response info, because trans goes away.
5403 response
= *trans
->GetResponseInfo();
5404 response2
= *trans2
->GetResponseInfo();
5406 VerifyStreamsClosed(helper
);
5408 // Verify the SYN_REPLY.
5409 EXPECT_TRUE(response
.headers
.get() != NULL
);
5410 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
5412 // Verify the pushed stream.
5413 EXPECT_TRUE(response2
.headers
.get() != NULL
);
5414 EXPECT_EQ("HTTP/1.1 200 OK", response2
.headers
->GetStatusLine());
5416 // Verify we got all the headers from all header blocks.
5417 if (spdy_util_
.spdy_version() < SPDY4
)
5418 EXPECT_TRUE(response2
.headers
->HasHeaderValue("alpha", "beta"));
5419 EXPECT_TRUE(response2
.headers
->HasHeaderValue("hello", "bye"));
5420 EXPECT_TRUE(response2
.headers
->HasHeaderValue("status", "200"));
5422 // Read the final EOF (which will close the session)
5425 // Verify that we consumed all test data.
5426 EXPECT_TRUE(data
.at_read_eof());
5427 EXPECT_TRUE(data
.at_write_eof());
5430 TEST_P(SpdyNetworkTransactionTest
, ServerPushWithNoStatusHeaderFrames
) {
5431 // We push a stream and attempt to claim it before the headers come down.
5432 scoped_ptr
<SpdyFrame
> stream1_syn(
5433 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
5434 scoped_ptr
<SpdyFrame
> stream1_body(
5435 spdy_util_
.ConstructSpdyBodyFrame(1, true));
5436 MockWrite writes
[] = {
5437 CreateMockWrite(*stream1_syn
, 0, SYNCHRONOUS
),
5440 scoped_ptr
<SpdyHeaderBlock
> initial_headers(new SpdyHeaderBlock());
5441 spdy_util_
.AddUrlToHeaderBlock(GetDefaultUrlWithPath("/foo.dat"),
5442 initial_headers
.get());
5443 scoped_ptr
<SpdyFrame
> stream2_syn(
5444 spdy_util_
.ConstructInitialSpdyPushFrame(initial_headers
.Pass(), 2, 1));
5446 scoped_ptr
<SpdyHeaderBlock
> middle_headers(new SpdyHeaderBlock());
5447 (*middle_headers
)["hello"] = "bye";
5448 scoped_ptr
<SpdyFrame
> stream2_headers1(
5449 spdy_util_
.ConstructSpdyControlFrame(middle_headers
.Pass(),
5457 scoped_ptr
<SpdyFrame
>
5458 stream1_reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
5459 const char kPushedData
[] = "pushed";
5460 scoped_ptr
<SpdyFrame
> stream2_body(
5461 spdy_util_
.ConstructSpdyBodyFrame(
5462 2, kPushedData
, strlen(kPushedData
), true));
5463 MockRead reads
[] = {
5464 CreateMockRead(*stream1_reply
, 1),
5465 CreateMockRead(*stream2_syn
, 2),
5466 CreateMockRead(*stream1_body
, 3),
5467 CreateMockRead(*stream2_headers1
, 4),
5468 CreateMockRead(*stream2_body
, 5),
5469 MockRead(ASYNC
, 0, 6), // EOF
5472 DeterministicSocketData
data(reads
, arraysize(reads
),
5473 writes
, arraysize(writes
));
5475 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
5476 BoundNetLog(), GetParam(), NULL
);
5477 helper
.SetDeterministic();
5478 helper
.AddDeterministicData(&data
);
5479 helper
.RunPreTestSetup();
5481 HttpNetworkTransaction
* trans
= helper
.trans();
5483 // Run until we've received the primary SYN_STREAM, the pushed SYN_STREAM,
5484 // the first HEADERS frame, and the body of the primary stream, but before
5485 // we've received the final HEADERS for the pushed stream.
5488 // Start the transaction.
5489 TestCompletionCallback callback
;
5490 int rv
= trans
->Start(
5491 &CreateGetRequest(), callback
.callback(), BoundNetLog());
5492 EXPECT_EQ(ERR_IO_PENDING
, rv
);
5494 rv
= callback
.WaitForResult();
5497 // Request the pushed path. At this point, we've received the push, but the
5498 // headers are not yet complete.
5499 scoped_ptr
<HttpNetworkTransaction
> trans2(
5500 new HttpNetworkTransaction(DEFAULT_PRIORITY
, helper
.session().get()));
5502 &CreateGetPushRequest(), callback
.callback(), BoundNetLog());
5503 EXPECT_EQ(ERR_IO_PENDING
, rv
);
5505 base::RunLoop().RunUntilIdle();
5507 // Read the server push body.
5508 std::string result2
;
5509 ReadResult(trans2
.get(), &data
, &result2
);
5510 // Read the response body.
5512 ReadResult(trans
, &data
, &result
);
5513 EXPECT_EQ("hello!", result
);
5515 // Verify that we haven't received any push data.
5516 EXPECT_EQ("", result2
);
5518 // Verify the SYN_REPLY.
5519 // Copy the response info, because trans goes away.
5520 HttpResponseInfo response
= *trans
->GetResponseInfo();
5521 ASSERT_TRUE(trans2
->GetResponseInfo() == NULL
);
5523 VerifyStreamsClosed(helper
);
5525 // Verify the SYN_REPLY.
5526 EXPECT_TRUE(response
.headers
.get() != NULL
);
5527 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
5529 // Read the final EOF (which will close the session).
5532 // Verify that we consumed all test data.
5533 EXPECT_TRUE(data
.at_read_eof());
5534 EXPECT_TRUE(data
.at_write_eof());
5537 TEST_P(SpdyNetworkTransactionTest
, SynReplyWithHeaders
) {
5538 scoped_ptr
<SpdyFrame
> req(
5539 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
5540 scoped_ptr
<SpdyFrame
> rst(
5541 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR
));
5542 MockWrite writes
[] = {
5543 CreateMockWrite(*req
), CreateMockWrite(*rst
),
5546 scoped_ptr
<SpdyFrame
> stream1_reply(
5547 spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
5549 scoped_ptr
<SpdyHeaderBlock
> late_headers(new SpdyHeaderBlock());
5550 (*late_headers
)["hello"] = "bye";
5551 scoped_ptr
<SpdyFrame
> stream1_headers(
5552 spdy_util_
.ConstructSpdyControlFrame(late_headers
.Pass(),
5559 scoped_ptr
<SpdyFrame
> stream1_body(
5560 spdy_util_
.ConstructSpdyBodyFrame(1, true));
5561 MockRead reads
[] = {
5562 CreateMockRead(*stream1_reply
),
5563 CreateMockRead(*stream1_headers
),
5564 CreateMockRead(*stream1_body
),
5565 MockRead(ASYNC
, 0, 0) // EOF
5568 DelayedSocketData
data(1, reads
, arraysize(reads
),
5569 writes
, arraysize(writes
));
5570 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
5571 BoundNetLog(), GetParam(), NULL
);
5572 helper
.RunToCompletion(&data
);
5573 TransactionHelperResult out
= helper
.output();
5574 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR
, out
.rv
);
5577 TEST_P(SpdyNetworkTransactionTest
, SynReplyWithLateHeaders
) {
5578 scoped_ptr
<SpdyFrame
> req(
5579 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
5580 scoped_ptr
<SpdyFrame
> rst(
5581 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR
));
5582 MockWrite writes
[] = {
5583 CreateMockWrite(*req
),
5584 CreateMockWrite(*rst
),
5587 scoped_ptr
<SpdyFrame
> stream1_reply(
5588 spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
5590 scoped_ptr
<SpdyHeaderBlock
> late_headers(new SpdyHeaderBlock());
5591 (*late_headers
)["hello"] = "bye";
5592 scoped_ptr
<SpdyFrame
> stream1_headers(
5593 spdy_util_
.ConstructSpdyControlFrame(late_headers
.Pass(),
5600 scoped_ptr
<SpdyFrame
> stream1_body(
5601 spdy_util_
.ConstructSpdyBodyFrame(1, false));
5602 scoped_ptr
<SpdyFrame
> stream1_body2(
5603 spdy_util_
.ConstructSpdyBodyFrame(1, true));
5604 MockRead reads
[] = {
5605 CreateMockRead(*stream1_reply
),
5606 CreateMockRead(*stream1_body
),
5607 CreateMockRead(*stream1_headers
),
5608 CreateMockRead(*stream1_body2
),
5609 MockRead(ASYNC
, 0, 0) // EOF
5612 DelayedSocketData
data(1, reads
, arraysize(reads
),
5613 writes
, arraysize(writes
));
5614 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
5615 BoundNetLog(), GetParam(), NULL
);
5616 helper
.RunToCompletion(&data
);
5617 TransactionHelperResult out
= helper
.output();
5618 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR
, out
.rv
);
5621 TEST_P(SpdyNetworkTransactionTest
, ServerPushCrossOriginCorrectness
) {
5622 // Running these tests via Alt-Svc is too complicated to be worthwhile.
5623 if (GetParam().ssl_type
!= HTTPS_SPDY_VIA_NPN
)
5626 // In this test we want to verify that we can't accidentally push content
5627 // which can't be pushed by this content server.
5628 // This test assumes that:
5629 // - if we're requesting http://www.foo.com/barbaz
5630 // - the browser has made a connection to "www.foo.com".
5632 // A list of the URL to fetch, followed by the URL being pushed.
5633 static const char* const kTestCases
[] = {
5634 "https://www.google.com/foo.html",
5635 "https://www.google.com:81/foo.js", // Bad port
5637 "https://www.google.com/foo.html",
5638 "http://www.google.com/foo.js", // Bad protocol
5640 "https://www.google.com/foo.html",
5641 "ftp://www.google.com/foo.js", // Invalid Protocol
5643 "https://www.google.com/foo.html",
5644 "https://blat.www.google.com/foo.js", // Cross subdomain
5646 "https://www.google.com/foo.html",
5647 "https://www.foo.com/foo.js", // Cross domain
5650 for (size_t index
= 0; index
< arraysize(kTestCases
); index
+= 2) {
5651 const char* url_to_fetch
= kTestCases
[index
];
5652 const char* url_to_push
= kTestCases
[index
+ 1];
5654 scoped_ptr
<SpdyFrame
> stream1_syn(
5655 spdy_util_
.ConstructSpdyGet(url_to_fetch
, false, 1, LOWEST
));
5656 scoped_ptr
<SpdyFrame
> stream1_body(
5657 spdy_util_
.ConstructSpdyBodyFrame(1, true));
5658 scoped_ptr
<SpdyFrame
> push_rst(
5659 spdy_util_
.ConstructSpdyRstStream(2, RST_STREAM_REFUSED_STREAM
));
5660 MockWrite writes
[] = {
5661 CreateMockWrite(*stream1_syn
, 1),
5662 CreateMockWrite(*push_rst
, 4),
5665 scoped_ptr
<SpdyFrame
>
5666 stream1_reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
5667 scoped_ptr
<SpdyFrame
>
5668 stream2_syn(spdy_util_
.ConstructSpdyPush(NULL
,
5673 const char kPushedData
[] = "pushed";
5674 scoped_ptr
<SpdyFrame
> stream2_body(
5675 spdy_util_
.ConstructSpdyBodyFrame(
5676 2, kPushedData
, strlen(kPushedData
), true));
5677 scoped_ptr
<SpdyFrame
> rst(
5678 spdy_util_
.ConstructSpdyRstStream(2, RST_STREAM_CANCEL
));
5680 MockRead reads
[] = {
5681 CreateMockRead(*stream1_reply
, 2),
5682 CreateMockRead(*stream2_syn
, 3),
5683 CreateMockRead(*stream1_body
, 5, SYNCHRONOUS
),
5684 CreateMockRead(*stream2_body
, 6),
5685 MockRead(ASYNC
, ERR_IO_PENDING
, 7), // Force a pause
5688 HttpResponseInfo response
;
5689 OrderedSocketData
data(reads
, arraysize(reads
),
5690 writes
, arraysize(writes
));
5692 HttpRequestInfo request
;
5693 request
.method
= "GET";
5694 request
.url
= GURL(url_to_fetch
);
5695 request
.load_flags
= 0;
5697 // Enable cross-origin push. Since we are not using a proxy, this should
5698 // not actually enable cross-origin SPDY push.
5699 scoped_ptr
<SpdySessionDependencies
> session_deps(
5700 CreateSpdySessionDependencies(GetParam()));
5701 session_deps
->trusted_spdy_proxy
= "123.45.67.89:8080";
5702 NormalSpdyTransactionHelper
helper(request
, DEFAULT_PRIORITY
,
5703 BoundNetLog(), GetParam(),
5704 session_deps
.release());
5705 helper
.RunPreTestSetup();
5706 helper
.AddData(&data
);
5708 HttpNetworkTransaction
* trans
= helper
.trans();
5710 // Start the transaction with basic parameters.
5711 TestCompletionCallback callback
;
5713 int rv
= trans
->Start(&request
, callback
.callback(), BoundNetLog());
5714 EXPECT_EQ(ERR_IO_PENDING
, rv
);
5715 rv
= callback
.WaitForResult();
5717 // Read the response body.
5719 ReadResult(trans
, &data
, &result
);
5721 // Verify that we consumed all test data.
5722 EXPECT_TRUE(data
.at_read_eof());
5723 EXPECT_TRUE(data
.at_write_eof());
5725 // Verify the SYN_REPLY.
5726 // Copy the response info, because trans goes away.
5727 response
= *trans
->GetResponseInfo();
5729 VerifyStreamsClosed(helper
);
5731 // Verify the SYN_REPLY.
5732 EXPECT_TRUE(response
.headers
.get() != NULL
);
5733 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
5737 TEST_P(SpdyNetworkTransactionTest
, RetryAfterRefused
) {
5738 // Construct the request.
5739 scoped_ptr
<SpdyFrame
> req(
5740 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
5741 scoped_ptr
<SpdyFrame
> req2(
5742 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 3, LOWEST
, true));
5743 MockWrite writes
[] = {
5744 CreateMockWrite(*req
, 1),
5745 CreateMockWrite(*req2
, 3),
5748 scoped_ptr
<SpdyFrame
> refused(
5749 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_REFUSED_STREAM
));
5750 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 3));
5751 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(3, true));
5752 MockRead reads
[] = {
5753 CreateMockRead(*refused
, 2),
5754 CreateMockRead(*resp
, 4),
5755 CreateMockRead(*body
, 5),
5756 MockRead(ASYNC
, 0, 6) // EOF
5759 OrderedSocketData
data(reads
, arraysize(reads
),
5760 writes
, arraysize(writes
));
5761 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
5762 BoundNetLog(), GetParam(), NULL
);
5764 helper
.RunPreTestSetup();
5765 helper
.AddData(&data
);
5767 HttpNetworkTransaction
* trans
= helper
.trans();
5769 // Start the transaction with basic parameters.
5770 TestCompletionCallback callback
;
5771 int rv
= trans
->Start(
5772 &CreateGetRequest(), callback
.callback(), BoundNetLog());
5773 EXPECT_EQ(ERR_IO_PENDING
, rv
);
5774 rv
= callback
.WaitForResult();
5777 // Verify that we consumed all test data.
5778 EXPECT_TRUE(data
.at_read_eof()) << "Read count: "
5779 << data
.read_count()
5781 << data
.read_index();
5782 EXPECT_TRUE(data
.at_write_eof()) << "Write count: "
5783 << data
.write_count()
5785 << data
.write_index();
5787 // Verify the SYN_REPLY.
5788 HttpResponseInfo response
= *trans
->GetResponseInfo();
5789 EXPECT_TRUE(response
.headers
.get() != NULL
);
5790 EXPECT_EQ("HTTP/1.1 200 OK", response
.headers
->GetStatusLine());
5793 TEST_P(SpdyNetworkTransactionTest
, OutOfOrderSynStream
) {
5794 // This first request will start to establish the SpdySession.
5795 // Then we will start the second (MEDIUM priority) and then third
5796 // (HIGHEST priority) request in such a way that the third will actually
5797 // start before the second, causing the second to be numbered differently
5798 // than the order they were created.
5799 scoped_ptr
<SpdyFrame
> req1(
5800 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
5801 scoped_ptr
<SpdyFrame
> req2(
5802 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 3, HIGHEST
, true));
5803 scoped_ptr
<SpdyFrame
> req3(
5804 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 5, MEDIUM
, true));
5805 MockWrite writes
[] = {
5806 CreateMockWrite(*req1
, 0),
5807 CreateMockWrite(*req2
, 3),
5808 CreateMockWrite(*req3
, 4),
5811 scoped_ptr
<SpdyFrame
> resp1(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
5812 scoped_ptr
<SpdyFrame
> body1(spdy_util_
.ConstructSpdyBodyFrame(1, true));
5813 scoped_ptr
<SpdyFrame
> resp2(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 3));
5814 scoped_ptr
<SpdyFrame
> body2(spdy_util_
.ConstructSpdyBodyFrame(3, true));
5815 scoped_ptr
<SpdyFrame
> resp3(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 5));
5816 scoped_ptr
<SpdyFrame
> body3(spdy_util_
.ConstructSpdyBodyFrame(5, true));
5817 MockRead reads
[] = {
5818 CreateMockRead(*resp1
, 1),
5819 CreateMockRead(*body1
, 2),
5820 CreateMockRead(*resp2
, 5),
5821 CreateMockRead(*body2
, 6),
5822 CreateMockRead(*resp3
, 7),
5823 CreateMockRead(*body3
, 8),
5824 MockRead(ASYNC
, 0, 9) // EOF
5827 DeterministicSocketData
data(reads
, arraysize(reads
),
5828 writes
, arraysize(writes
));
5829 NormalSpdyTransactionHelper
helper(CreateGetRequest(), LOWEST
,
5830 BoundNetLog(), GetParam(), NULL
);
5831 helper
.SetDeterministic();
5832 helper
.RunPreTestSetup();
5833 helper
.AddDeterministicData(&data
);
5835 // Start the first transaction to set up the SpdySession
5836 HttpNetworkTransaction
* trans
= helper
.trans();
5837 TestCompletionCallback callback
;
5838 HttpRequestInfo info1
= CreateGetRequest();
5839 int rv
= trans
->Start(&info1
, callback
.callback(), BoundNetLog());
5840 EXPECT_EQ(ERR_IO_PENDING
, rv
);
5842 // Run the message loop, but do not allow the write to complete.
5843 // This leaves the SpdySession with a write pending, which prevents
5844 // SpdySession from attempting subsequent writes until this write completes.
5845 base::RunLoop().RunUntilIdle();
5847 // Now, start both new transactions
5848 HttpRequestInfo info2
= CreateGetRequest();
5849 TestCompletionCallback callback2
;
5850 scoped_ptr
<HttpNetworkTransaction
> trans2(
5851 new HttpNetworkTransaction(MEDIUM
, helper
.session().get()));
5852 rv
= trans2
->Start(&info2
, callback2
.callback(), BoundNetLog());
5853 EXPECT_EQ(ERR_IO_PENDING
, rv
);
5854 base::RunLoop().RunUntilIdle();
5856 HttpRequestInfo info3
= CreateGetRequest();
5857 TestCompletionCallback callback3
;
5858 scoped_ptr
<HttpNetworkTransaction
> trans3(
5859 new HttpNetworkTransaction(HIGHEST
, helper
.session().get()));
5860 rv
= trans3
->Start(&info3
, callback3
.callback(), BoundNetLog());
5861 EXPECT_EQ(ERR_IO_PENDING
, rv
);
5862 base::RunLoop().RunUntilIdle();
5864 // We now have two SYN_STREAM frames queued up which will be
5865 // dequeued only once the first write completes, which we
5866 // now allow to happen.
5868 EXPECT_EQ(OK
, callback
.WaitForResult());
5870 // And now we can allow everything else to run to completion.
5873 EXPECT_EQ(OK
, callback2
.WaitForResult());
5874 EXPECT_EQ(OK
, callback3
.WaitForResult());
5876 helper
.VerifyDataConsumed();
5879 // The tests below are only for SPDY/3 and above.
5881 // Test that sent data frames and received WINDOW_UPDATE frames change
5882 // the send_window_size_ correctly.
5884 // WINDOW_UPDATE is different than most other frames in that it can arrive
5885 // while the client is still sending the request body. In order to enforce
5886 // this scenario, we feed a couple of dummy frames and give a delay of 0 to
5887 // socket data provider, so that initial read that is done as soon as the
5888 // stream is created, succeeds and schedules another read. This way reads
5889 // and writes are interleaved; after doing a full frame write, SpdyStream
5890 // will break out of DoLoop and will read and process a WINDOW_UPDATE.
5891 // Once our WINDOW_UPDATE is read, we cannot send SYN_REPLY right away
5892 // since request has not been completely written, therefore we feed
5893 // enough number of WINDOW_UPDATEs to finish the first read and cause a
5894 // write, leading to a complete write of request body; after that we send
5895 // a reply with a body, to cause a graceful shutdown.
5897 // TODO(agayev): develop a socket data provider where both, reads and
5898 // writes are ordered so that writing tests like these are easy and rewrite
5899 // all these tests using it. Right now we are working around the
5900 // limitations as described above and it's not deterministic, tests may
5901 // fail under specific circumstances.
5902 TEST_P(SpdyNetworkTransactionTest
, WindowUpdateReceived
) {
5903 static int kFrameCount
= 2;
5904 scoped_ptr
<std::string
> content(
5905 new std::string(kMaxSpdyFrameChunkSize
, 'a'));
5906 scoped_ptr
<SpdyFrame
> req(spdy_util_
.ConstructSpdyPost(
5907 GetDefaultUrl(), 1, kMaxSpdyFrameChunkSize
* kFrameCount
, LOWEST
, NULL
,
5909 scoped_ptr
<SpdyFrame
> body(
5910 spdy_util_
.ConstructSpdyBodyFrame(
5911 1, content
->c_str(), content
->size(), false));
5912 scoped_ptr
<SpdyFrame
> body_end(
5913 spdy_util_
.ConstructSpdyBodyFrame(
5914 1, content
->c_str(), content
->size(), true));
5916 MockWrite writes
[] = {
5917 CreateMockWrite(*req
, 0),
5918 CreateMockWrite(*body
, 1),
5919 CreateMockWrite(*body_end
, 2),
5922 static const int32 kDeltaWindowSize
= 0xff;
5923 static const int kDeltaCount
= 4;
5924 scoped_ptr
<SpdyFrame
> window_update(
5925 spdy_util_
.ConstructSpdyWindowUpdate(1, kDeltaWindowSize
));
5926 scoped_ptr
<SpdyFrame
> window_update_dummy(
5927 spdy_util_
.ConstructSpdyWindowUpdate(2, kDeltaWindowSize
));
5928 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyPostSynReply(NULL
, 0));
5929 MockRead reads
[] = {
5930 CreateMockRead(*window_update_dummy
, 3),
5931 CreateMockRead(*window_update_dummy
, 4),
5932 CreateMockRead(*window_update_dummy
, 5),
5933 CreateMockRead(*window_update
, 6), // Four updates, therefore window
5934 CreateMockRead(*window_update
, 7), // size should increase by
5935 CreateMockRead(*window_update
, 8), // kDeltaWindowSize * 4
5936 CreateMockRead(*window_update
, 9),
5937 CreateMockRead(*resp
, 10),
5938 CreateMockRead(*body_end
, 11),
5939 MockRead(ASYNC
, 0, 0, 12) // EOF
5942 DeterministicSocketData
data(reads
, arraysize(reads
),
5943 writes
, arraysize(writes
));
5945 ScopedVector
<UploadElementReader
> element_readers
;
5946 for (int i
= 0; i
< kFrameCount
; ++i
) {
5947 element_readers
.push_back(
5948 new UploadBytesElementReader(content
->c_str(), content
->size()));
5950 ElementsUploadDataStream
upload_data_stream(element_readers
.Pass(), 0);
5952 // Setup the request
5953 HttpRequestInfo request
;
5954 request
.method
= "POST";
5955 request
.url
= GURL(GetDefaultUrl());
5956 request
.upload_data_stream
= &upload_data_stream
;
5958 NormalSpdyTransactionHelper
helper(request
, DEFAULT_PRIORITY
,
5959 BoundNetLog(), GetParam(), NULL
);
5960 helper
.SetDeterministic();
5961 helper
.AddDeterministicData(&data
);
5962 helper
.RunPreTestSetup();
5964 HttpNetworkTransaction
* trans
= helper
.trans();
5966 TestCompletionCallback callback
;
5967 int rv
= trans
->Start(&helper
.request(), callback
.callback(), BoundNetLog());
5969 EXPECT_EQ(ERR_IO_PENDING
, rv
);
5973 SpdyHttpStream
* stream
= static_cast<SpdyHttpStream
*>(trans
->stream_
.get());
5974 ASSERT_TRUE(stream
!= NULL
);
5975 ASSERT_TRUE(stream
->stream() != NULL
);
5976 EXPECT_EQ(static_cast<int>(
5977 SpdySession::GetDefaultInitialWindowSize(GetParam().protocol
)) +
5978 kDeltaWindowSize
* kDeltaCount
-
5979 kMaxSpdyFrameChunkSize
* kFrameCount
,
5980 stream
->stream()->send_window_size());
5984 rv
= callback
.WaitForResult();
5987 helper
.VerifyDataConsumed();
5990 // Test that received data frames and sent WINDOW_UPDATE frames change
5991 // the recv_window_size_ correctly.
5992 TEST_P(SpdyNetworkTransactionTest
, WindowUpdateSent
) {
5993 const int32 default_initial_window_size
=
5994 SpdySession::GetDefaultInitialWindowSize(GetParam().protocol
);
5995 // Session level maximum window size that is more than twice the default
5996 // initial window size so that an initial window update is sent.
5997 const int32 session_max_recv_window_size
= 5 * 64 * 1024;
5998 ASSERT_LT(2 * default_initial_window_size
, session_max_recv_window_size
);
5999 // Stream level maximum window size that is less than the session level
6000 // maximum window size so that we test for confusion between the two.
6001 const int32 stream_max_recv_window_size
= 4 * 64 * 1024;
6002 ASSERT_GT(session_max_recv_window_size
, stream_max_recv_window_size
);
6003 // Size of body to be sent. Has to be less than or equal to both window sizes
6004 // so that we do not run out of receiving window. Also has to be greater than
6005 // half of them so that it triggers both a session level and a stream level
6006 // window update frame.
6007 const int32 kTargetSize
= 3 * 64 * 1024;
6008 ASSERT_GE(session_max_recv_window_size
, kTargetSize
);
6009 ASSERT_GE(stream_max_recv_window_size
, kTargetSize
);
6010 ASSERT_LT(session_max_recv_window_size
/ 2, kTargetSize
);
6011 ASSERT_LT(stream_max_recv_window_size
/ 2, kTargetSize
);
6012 // Size of each DATA frame.
6013 const int32 kChunkSize
= 4096;
6014 // Size of window updates.
6015 ASSERT_EQ(0, session_max_recv_window_size
/ 2 % kChunkSize
);
6016 const int32 session_window_update_delta
=
6017 session_max_recv_window_size
/ 2 + kChunkSize
;
6018 ASSERT_EQ(0, stream_max_recv_window_size
/ 2 % kChunkSize
);
6019 const int32 stream_window_update_delta
=
6020 stream_max_recv_window_size
/ 2 + kChunkSize
;
6022 SettingsMap initial_settings
;
6023 initial_settings
[SETTINGS_MAX_CONCURRENT_STREAMS
] =
6024 SettingsFlagsAndValue(SETTINGS_FLAG_NONE
, kMaxConcurrentPushedStreams
);
6025 initial_settings
[SETTINGS_INITIAL_WINDOW_SIZE
] =
6026 SettingsFlagsAndValue(SETTINGS_FLAG_NONE
, stream_max_recv_window_size
);
6027 scoped_ptr
<SpdyFrame
> initial_settings_frame(
6028 spdy_util_
.ConstructSpdySettings(initial_settings
));
6029 scoped_ptr
<SpdyFrame
> initial_window_update(
6030 spdy_util_
.ConstructSpdyWindowUpdate(
6031 kSessionFlowControlStreamId
,
6032 session_max_recv_window_size
- default_initial_window_size
));
6033 scoped_ptr
<SpdyFrame
> req(
6034 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
6035 scoped_ptr
<SpdyFrame
> session_window_update(
6036 spdy_util_
.ConstructSpdyWindowUpdate(0, session_window_update_delta
));
6037 scoped_ptr
<SpdyFrame
> stream_window_update(
6038 spdy_util_
.ConstructSpdyWindowUpdate(1, stream_window_update_delta
));
6040 std::vector
<MockWrite
> writes
;
6041 if ((GetParam().protocol
>= kProtoSPDY4MinimumVersion
) &&
6042 (GetParam().protocol
<= kProtoSPDY4MaximumVersion
)) {
6043 writes
.push_back(MockWrite(ASYNC
, kHttp2ConnectionHeaderPrefix
,
6044 kHttp2ConnectionHeaderPrefixSize
, 0));
6046 writes
.push_back(CreateMockWrite(*initial_settings_frame
));
6047 writes
.push_back(CreateMockWrite(*initial_window_update
));
6048 writes
.push_back(CreateMockWrite(*req
));
6049 writes
.push_back(CreateMockWrite(*session_window_update
));
6050 writes
.push_back(CreateMockWrite(*stream_window_update
));
6052 std::vector
<MockRead
> reads
;
6053 scoped_ptr
<SpdyFrame
> resp(
6054 spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
6055 reads
.push_back(CreateMockRead(*resp
));
6057 ScopedVector
<SpdyFrame
> body_frames
;
6058 const std::string
body_data(kChunkSize
, 'x');
6059 for (size_t remaining
= kTargetSize
; remaining
!= 0;) {
6060 size_t frame_size
= std::min(remaining
, body_data
.size());
6061 body_frames
.push_back(spdy_util_
.ConstructSpdyBodyFrame(
6062 1, body_data
.data(), frame_size
, false));
6063 reads
.push_back(CreateMockRead(*body_frames
.back()));
6064 remaining
-= frame_size
;
6066 reads
.push_back(MockRead(ASYNC
, ERR_IO_PENDING
, 0)); // Yield.
6068 DelayedSocketData
data(2, vector_as_array(&reads
), reads
.size(),
6069 vector_as_array(&writes
), writes
.size());
6071 NormalSpdyTransactionHelper
helper(CreateGetRequest(), DEFAULT_PRIORITY
,
6072 BoundNetLog(), GetParam(), NULL
);
6073 helper
.AddData(&data
);
6074 helper
.RunPreTestSetup();
6076 SpdySessionPool
* spdy_session_pool
= helper
.session()->spdy_session_pool();
6077 SpdySessionPoolPeer
pool_peer(spdy_session_pool
);
6078 pool_peer
.SetEnableSendingInitialData(true);
6079 pool_peer
.SetSessionMaxRecvWindowSize(session_max_recv_window_size
);
6080 pool_peer
.SetStreamInitialRecvWindowSize(stream_max_recv_window_size
);
6082 HttpNetworkTransaction
* trans
= helper
.trans();
6083 TestCompletionCallback callback
;
6084 int rv
= trans
->Start(&helper
.request(), callback
.callback(), BoundNetLog());
6086 EXPECT_EQ(ERR_IO_PENDING
, rv
);
6087 rv
= callback
.WaitForResult();
6090 SpdyHttpStream
* stream
=
6091 static_cast<SpdyHttpStream
*>(trans
->stream_
.get());
6092 ASSERT_TRUE(stream
!= NULL
);
6093 ASSERT_TRUE(stream
->stream() != NULL
);
6095 // All data has been read, but not consumed. The window reflects this.
6096 EXPECT_EQ(static_cast<int>(stream_max_recv_window_size
- kTargetSize
),
6097 stream
->stream()->recv_window_size());
6099 const HttpResponseInfo
* response
= trans
->GetResponseInfo();
6100 ASSERT_TRUE(response
!= NULL
);
6101 ASSERT_TRUE(response
->headers
.get() != NULL
);
6102 EXPECT_EQ("HTTP/1.1 200 OK", response
->headers
->GetStatusLine());
6103 EXPECT_TRUE(response
->was_fetched_via_spdy
);
6105 // Issue a read which will cause a WINDOW_UPDATE to be sent and window
6106 // size increased to default.
6107 scoped_refptr
<IOBuffer
> buf(new IOBuffer(kTargetSize
));
6108 EXPECT_EQ(static_cast<int>(kTargetSize
),
6109 trans
->Read(buf
.get(), kTargetSize
, CompletionCallback()));
6110 EXPECT_EQ(static_cast<int>(stream_max_recv_window_size
),
6111 stream
->stream()->recv_window_size());
6112 EXPECT_THAT(base::StringPiece(buf
->data(), kTargetSize
), Each(Eq('x')));
6114 // Allow scheduled WINDOW_UPDATE frames to write.
6115 base::RunLoop().RunUntilIdle();
6116 helper
.VerifyDataConsumed();
6119 // Test that WINDOW_UPDATE frame causing overflow is handled correctly.
6120 TEST_P(SpdyNetworkTransactionTest
, WindowUpdateOverflow
) {
6121 // Number of full frames we hope to write (but will not, used to
6122 // set content-length header correctly)
6123 static int kFrameCount
= 3;
6125 scoped_ptr
<std::string
> content(
6126 new std::string(kMaxSpdyFrameChunkSize
, 'a'));
6127 scoped_ptr
<SpdyFrame
> req(spdy_util_
.ConstructSpdyPost(
6128 GetDefaultUrl(), 1, kMaxSpdyFrameChunkSize
* kFrameCount
, LOWEST
, NULL
,
6130 scoped_ptr
<SpdyFrame
> body(
6131 spdy_util_
.ConstructSpdyBodyFrame(
6132 1, content
->c_str(), content
->size(), false));
6133 scoped_ptr
<SpdyFrame
> rst(
6134 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_FLOW_CONTROL_ERROR
));
6136 // We're not going to write a data frame with FIN, we'll receive a bad
6137 // WINDOW_UPDATE while sending a request and will send a RST_STREAM frame.
6138 MockWrite writes
[] = {
6139 CreateMockWrite(*req
, 0),
6140 CreateMockWrite(*body
, 2),
6141 CreateMockWrite(*rst
, 3),
6144 static const int32 kDeltaWindowSize
= 0x7fffffff; // cause an overflow
6145 scoped_ptr
<SpdyFrame
> window_update(
6146 spdy_util_
.ConstructSpdyWindowUpdate(1, kDeltaWindowSize
));
6147 MockRead reads
[] = {
6148 CreateMockRead(*window_update
, 1),
6149 MockRead(ASYNC
, 0, 4) // EOF
6152 DeterministicSocketData
data(reads
, arraysize(reads
),
6153 writes
, arraysize(writes
));
6155 ScopedVector
<UploadElementReader
> element_readers
;
6156 for (int i
= 0; i
< kFrameCount
; ++i
) {
6157 element_readers
.push_back(
6158 new UploadBytesElementReader(content
->c_str(), content
->size()));
6160 ElementsUploadDataStream
upload_data_stream(element_readers
.Pass(), 0);
6162 // Setup the request
6163 HttpRequestInfo request
;
6164 request
.method
= "POST";
6165 request
.url
= GURL(GetDefaultUrl());
6166 request
.upload_data_stream
= &upload_data_stream
;
6168 NormalSpdyTransactionHelper
helper(request
, DEFAULT_PRIORITY
,
6169 BoundNetLog(), GetParam(), NULL
);
6170 helper
.SetDeterministic();
6171 helper
.RunPreTestSetup();
6172 helper
.AddDeterministicData(&data
);
6173 HttpNetworkTransaction
* trans
= helper
.trans();
6175 TestCompletionCallback callback
;
6176 int rv
= trans
->Start(&helper
.request(), callback
.callback(), BoundNetLog());
6177 ASSERT_EQ(ERR_IO_PENDING
, rv
);
6180 ASSERT_TRUE(callback
.have_result());
6181 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR
, callback
.WaitForResult());
6182 helper
.VerifyDataConsumed();
6185 // Test that after hitting a send window size of 0, the write process
6186 // stalls and upon receiving WINDOW_UPDATE frame write resumes.
6188 // This test constructs a POST request followed by enough data frames
6189 // containing 'a' that would make the window size 0, followed by another
6190 // data frame containing default content (which is "hello!") and this frame
6191 // also contains a FIN flag. DelayedSocketData is used to enforce all
6192 // writes go through before a read could happen. However, the last frame
6193 // ("hello!") is not supposed to go through since by the time its turn
6194 // arrives, window size is 0. At this point MessageLoop::Run() called via
6195 // callback would block. Therefore we call MessageLoop::RunUntilIdle()
6196 // which returns after performing all possible writes. We use DCHECKS to
6197 // ensure that last data frame is still there and stream has stalled.
6198 // After that, next read is artifically enforced, which causes a
6199 // WINDOW_UPDATE to be read and I/O process resumes.
6200 TEST_P(SpdyNetworkTransactionTest
, FlowControlStallResume
) {
6201 const int32 initial_window_size
=
6202 SpdySession::GetDefaultInitialWindowSize(GetParam().protocol
);
6203 // Number of frames we need to send to zero out the window size: data
6204 // frames plus SYN_STREAM plus the last data frame; also we need another
6205 // data frame that we will send once the WINDOW_UPDATE is received,
6207 size_t num_writes
= initial_window_size
/ kMaxSpdyFrameChunkSize
+ 3;
6209 // Calculate last frame's size; 0 size data frame is legal.
6210 size_t last_frame_size
= initial_window_size
% kMaxSpdyFrameChunkSize
;
6212 // Construct content for a data frame of maximum size.
6213 std::string
content(kMaxSpdyFrameChunkSize
, 'a');
6215 scoped_ptr
<SpdyFrame
> req(spdy_util_
.ConstructSpdyPost(
6216 GetDefaultUrl(), 1, initial_window_size
+ kUploadDataSize
, LOWEST
, NULL
,
6220 scoped_ptr
<SpdyFrame
> body1(
6221 spdy_util_
.ConstructSpdyBodyFrame(
6222 1, content
.c_str(), content
.size(), false));
6224 // Last frame to zero out the window size.
6225 scoped_ptr
<SpdyFrame
> body2(
6226 spdy_util_
.ConstructSpdyBodyFrame(
6227 1, content
.c_str(), last_frame_size
, false));
6229 // Data frame to be sent once WINDOW_UPDATE frame is received.
6230 scoped_ptr
<SpdyFrame
> body3(spdy_util_
.ConstructSpdyBodyFrame(1, true));
6232 // Fill in mock writes.
6233 scoped_ptr
<MockWrite
[]> writes(new MockWrite
[num_writes
]);
6235 writes
[i
] = CreateMockWrite(*req
);
6236 for (i
= 1; i
< num_writes
- 2; i
++)
6237 writes
[i
] = CreateMockWrite(*body1
);
6238 writes
[i
++] = CreateMockWrite(*body2
);
6239 writes
[i
] = CreateMockWrite(*body3
);
6241 // Construct read frame, give enough space to upload the rest of the
6243 scoped_ptr
<SpdyFrame
> session_window_update(
6244 spdy_util_
.ConstructSpdyWindowUpdate(0, kUploadDataSize
));
6245 scoped_ptr
<SpdyFrame
> window_update(
6246 spdy_util_
.ConstructSpdyWindowUpdate(1, kUploadDataSize
));
6247 scoped_ptr
<SpdyFrame
> reply(spdy_util_
.ConstructSpdyPostSynReply(NULL
, 0));
6248 MockRead reads
[] = {
6249 CreateMockRead(*session_window_update
),
6250 CreateMockRead(*session_window_update
),
6251 CreateMockRead(*window_update
),
6252 CreateMockRead(*window_update
),
6253 CreateMockRead(*reply
),
6254 CreateMockRead(*body2
),
6255 CreateMockRead(*body3
),
6256 MockRead(ASYNC
, 0, 0) // EOF
6259 // Skip the session window updates unless we're using SPDY/3.1 and
6261 size_t read_offset
= (GetParam().protocol
>= kProtoSPDY31
) ? 0 : 2;
6262 size_t num_reads
= arraysize(reads
) - read_offset
;
6264 // Force all writes to happen before any read, last write will not
6265 // actually queue a frame, due to window size being 0.
6266 DelayedSocketData
data(num_writes
, reads
+ read_offset
, num_reads
,
6267 writes
.get(), num_writes
);
6269 ScopedVector
<UploadElementReader
> element_readers
;
6270 std::string
upload_data_string(initial_window_size
, 'a');
6271 upload_data_string
.append(kUploadData
, kUploadDataSize
);
6272 element_readers
.push_back(new UploadBytesElementReader(
6273 upload_data_string
.c_str(), upload_data_string
.size()));
6274 ElementsUploadDataStream
upload_data_stream(element_readers
.Pass(), 0);
6276 HttpRequestInfo request
;
6277 request
.method
= "POST";
6278 request
.url
= GURL(GetDefaultUrl());
6279 request
.upload_data_stream
= &upload_data_stream
;
6280 NormalSpdyTransactionHelper
helper(request
, DEFAULT_PRIORITY
,
6281 BoundNetLog(), GetParam(), NULL
);
6282 helper
.AddData(&data
);
6283 helper
.RunPreTestSetup();
6285 HttpNetworkTransaction
* trans
= helper
.trans();
6287 TestCompletionCallback callback
;
6288 int rv
= trans
->Start(&helper
.request(), callback
.callback(), BoundNetLog());
6289 EXPECT_EQ(ERR_IO_PENDING
, rv
);
6291 base::RunLoop().RunUntilIdle(); // Write as much as we can.
6293 SpdyHttpStream
* stream
= static_cast<SpdyHttpStream
*>(trans
->stream_
.get());
6294 ASSERT_TRUE(stream
!= NULL
);
6295 ASSERT_TRUE(stream
->stream() != NULL
);
6296 EXPECT_EQ(0, stream
->stream()->send_window_size());
6297 // All the body data should have been read.
6298 // TODO(satorux): This is because of the weirdness in reading the request
6299 // body in OnSendBodyComplete(). See crbug.com/113107.
6300 EXPECT_TRUE(upload_data_stream
.IsEOF());
6301 // But the body is not yet fully sent (kUploadData is not yet sent)
6302 // since we're send-stalled.
6303 EXPECT_TRUE(stream
->stream()->send_stalled_by_flow_control());
6305 data
.ForceNextRead(); // Read in WINDOW_UPDATE frame.
6306 rv
= callback
.WaitForResult();
6307 helper
.VerifyDataConsumed();
6310 // Test we correctly handle the case where the SETTINGS frame results in
6311 // unstalling the send window.
6312 TEST_P(SpdyNetworkTransactionTest
, FlowControlStallResumeAfterSettings
) {
6313 const int32 initial_window_size
=
6314 SpdySession::GetDefaultInitialWindowSize(GetParam().protocol
);
6316 // Number of frames we need to send to zero out the window size: data
6317 // frames plus SYN_STREAM plus the last data frame; also we need another
6318 // data frame that we will send once the SETTING is received, therefore +3.
6319 size_t num_writes
= initial_window_size
/ kMaxSpdyFrameChunkSize
+ 3;
6321 // Calculate last frame's size; 0 size data frame is legal.
6322 size_t last_frame_size
= initial_window_size
% kMaxSpdyFrameChunkSize
;
6324 // Construct content for a data frame of maximum size.
6325 std::string
content(kMaxSpdyFrameChunkSize
, 'a');
6327 scoped_ptr
<SpdyFrame
> req(spdy_util_
.ConstructSpdyPost(
6328 GetDefaultUrl(), 1, initial_window_size
+ kUploadDataSize
, LOWEST
, NULL
,
6332 scoped_ptr
<SpdyFrame
> body1(
6333 spdy_util_
.ConstructSpdyBodyFrame(
6334 1, content
.c_str(), content
.size(), false));
6336 // Last frame to zero out the window size.
6337 scoped_ptr
<SpdyFrame
> body2(
6338 spdy_util_
.ConstructSpdyBodyFrame(
6339 1, content
.c_str(), last_frame_size
, false));
6341 // Data frame to be sent once SETTINGS frame is received.
6342 scoped_ptr
<SpdyFrame
> body3(spdy_util_
.ConstructSpdyBodyFrame(1, true));
6344 // Fill in mock reads/writes.
6345 std::vector
<MockRead
> reads
;
6346 std::vector
<MockWrite
> writes
;
6348 writes
.push_back(CreateMockWrite(*req
, i
++));
6349 while (i
< num_writes
- 2)
6350 writes
.push_back(CreateMockWrite(*body1
, i
++));
6351 writes
.push_back(CreateMockWrite(*body2
, i
++));
6353 // Construct read frame for SETTINGS that gives enough space to upload the
6354 // rest of the data.
6355 SettingsMap settings
;
6356 settings
[SETTINGS_INITIAL_WINDOW_SIZE
] =
6357 SettingsFlagsAndValue(SETTINGS_FLAG_NONE
, initial_window_size
* 2);
6358 scoped_ptr
<SpdyFrame
> settings_frame_large(
6359 spdy_util_
.ConstructSpdySettings(settings
));
6361 reads
.push_back(CreateMockRead(*settings_frame_large
, i
++));
6363 scoped_ptr
<SpdyFrame
> session_window_update(
6364 spdy_util_
.ConstructSpdyWindowUpdate(0, kUploadDataSize
));
6365 if (GetParam().protocol
>= kProtoSPDY31
)
6366 reads
.push_back(CreateMockRead(*session_window_update
, i
++));
6368 scoped_ptr
<SpdyFrame
> settings_ack(spdy_util_
.ConstructSpdySettingsAck());
6369 writes
.push_back(CreateMockWrite(*settings_ack
, i
++));
6371 writes
.push_back(CreateMockWrite(*body3
, i
++));
6373 scoped_ptr
<SpdyFrame
> reply(spdy_util_
.ConstructSpdyPostSynReply(NULL
, 0));
6374 reads
.push_back(CreateMockRead(*reply
, i
++));
6375 reads
.push_back(CreateMockRead(*body2
, i
++));
6376 reads
.push_back(CreateMockRead(*body3
, i
++));
6377 reads
.push_back(MockRead(ASYNC
, 0, i
++)); // EOF
6379 // Force all writes to happen before any read, last write will not
6380 // actually queue a frame, due to window size being 0.
6381 DeterministicSocketData
data(vector_as_array(&reads
), reads
.size(),
6382 vector_as_array(&writes
), writes
.size());
6384 ScopedVector
<UploadElementReader
> element_readers
;
6385 std::string
upload_data_string(initial_window_size
, 'a');
6386 upload_data_string
.append(kUploadData
, kUploadDataSize
);
6387 element_readers
.push_back(new UploadBytesElementReader(
6388 upload_data_string
.c_str(), upload_data_string
.size()));
6389 ElementsUploadDataStream
upload_data_stream(element_readers
.Pass(), 0);
6391 HttpRequestInfo request
;
6392 request
.method
= "POST";
6393 request
.url
= GURL(GetDefaultUrl());
6394 request
.upload_data_stream
= &upload_data_stream
;
6395 NormalSpdyTransactionHelper
helper(request
, DEFAULT_PRIORITY
,
6396 BoundNetLog(), GetParam(), NULL
);
6397 helper
.SetDeterministic();
6398 helper
.RunPreTestSetup();
6399 helper
.AddDeterministicData(&data
);
6401 HttpNetworkTransaction
* trans
= helper
.trans();
6403 TestCompletionCallback callback
;
6404 int rv
= trans
->Start(&helper
.request(), callback
.callback(), BoundNetLog());
6405 EXPECT_EQ(ERR_IO_PENDING
, rv
);
6407 data
.RunFor(num_writes
- 1); // Write as much as we can.
6409 SpdyHttpStream
* stream
= static_cast<SpdyHttpStream
*>(trans
->stream_
.get());
6410 ASSERT_TRUE(stream
!= NULL
);
6411 ASSERT_TRUE(stream
->stream() != NULL
);
6412 EXPECT_EQ(0, stream
->stream()->send_window_size());
6414 // All the body data should have been read.
6415 // TODO(satorux): This is because of the weirdness in reading the request
6416 // body in OnSendBodyComplete(). See crbug.com/113107.
6417 EXPECT_TRUE(upload_data_stream
.IsEOF());
6418 // But the body is not yet fully sent (kUploadData is not yet sent)
6419 // since we're send-stalled.
6420 EXPECT_TRUE(stream
->stream()->send_stalled_by_flow_control());
6422 data
.RunFor(7); // Read in SETTINGS frame to unstall.
6423 rv
= callback
.WaitForResult();
6424 helper
.VerifyDataConsumed();
6425 // If stream is NULL, that means it was unstalled and closed.
6426 EXPECT_TRUE(stream
->stream() == NULL
);
6429 // Test we correctly handle the case where the SETTINGS frame results in a
6430 // negative send window size.
6431 TEST_P(SpdyNetworkTransactionTest
, FlowControlNegativeSendWindowSize
) {
6432 const int32 initial_window_size
=
6433 SpdySession::GetDefaultInitialWindowSize(GetParam().protocol
);
6434 // Number of frames we need to send to zero out the window size: data
6435 // frames plus SYN_STREAM plus the last data frame; also we need another
6436 // data frame that we will send once the SETTING is received, therefore +3.
6437 size_t num_writes
= initial_window_size
/ kMaxSpdyFrameChunkSize
+ 3;
6439 // Calculate last frame's size; 0 size data frame is legal.
6440 size_t last_frame_size
= initial_window_size
% kMaxSpdyFrameChunkSize
;
6442 // Construct content for a data frame of maximum size.
6443 std::string
content(kMaxSpdyFrameChunkSize
, 'a');
6445 scoped_ptr
<SpdyFrame
> req(spdy_util_
.ConstructSpdyPost(
6446 GetDefaultUrl(), 1, initial_window_size
+ kUploadDataSize
, LOWEST
, NULL
,
6450 scoped_ptr
<SpdyFrame
> body1(
6451 spdy_util_
.ConstructSpdyBodyFrame(
6452 1, content
.c_str(), content
.size(), false));
6454 // Last frame to zero out the window size.
6455 scoped_ptr
<SpdyFrame
> body2(
6456 spdy_util_
.ConstructSpdyBodyFrame(
6457 1, content
.c_str(), last_frame_size
, false));
6459 // Data frame to be sent once SETTINGS frame is received.
6460 scoped_ptr
<SpdyFrame
> body3(spdy_util_
.ConstructSpdyBodyFrame(1, true));
6462 // Fill in mock reads/writes.
6463 std::vector
<MockRead
> reads
;
6464 std::vector
<MockWrite
> writes
;
6466 writes
.push_back(CreateMockWrite(*req
, i
++));
6467 while (i
< num_writes
- 2)
6468 writes
.push_back(CreateMockWrite(*body1
, i
++));
6469 writes
.push_back(CreateMockWrite(*body2
, i
++));
6471 // Construct read frame for SETTINGS that makes the send_window_size
6473 SettingsMap new_settings
;
6474 new_settings
[SETTINGS_INITIAL_WINDOW_SIZE
] =
6475 SettingsFlagsAndValue(SETTINGS_FLAG_NONE
, initial_window_size
/ 2);
6476 scoped_ptr
<SpdyFrame
> settings_frame_small(
6477 spdy_util_
.ConstructSpdySettings(new_settings
));
6478 // Construct read frames for WINDOW_UPDATE that makes the send_window_size
6480 scoped_ptr
<SpdyFrame
> session_window_update_init_size(
6481 spdy_util_
.ConstructSpdyWindowUpdate(0, initial_window_size
));
6482 scoped_ptr
<SpdyFrame
> window_update_init_size(
6483 spdy_util_
.ConstructSpdyWindowUpdate(1, initial_window_size
));
6485 reads
.push_back(CreateMockRead(*settings_frame_small
, i
++));
6486 reads
.push_back(CreateMockRead(*session_window_update_init_size
, i
++));
6487 reads
.push_back(CreateMockRead(*window_update_init_size
, i
++));
6489 scoped_ptr
<SpdyFrame
> settings_ack(spdy_util_
.ConstructSpdySettingsAck());
6490 writes
.push_back(CreateMockWrite(*settings_ack
, i
++));
6492 writes
.push_back(CreateMockWrite(*body3
, i
++));
6494 scoped_ptr
<SpdyFrame
> reply(spdy_util_
.ConstructSpdyPostSynReply(NULL
, 0));
6495 reads
.push_back(CreateMockRead(*reply
, i
++));
6496 reads
.push_back(CreateMockRead(*body2
, i
++));
6497 reads
.push_back(CreateMockRead(*body3
, i
++));
6498 reads
.push_back(MockRead(ASYNC
, 0, i
++)); // EOF
6500 // Force all writes to happen before any read, last write will not
6501 // actually queue a frame, due to window size being 0.
6502 DeterministicSocketData
data(vector_as_array(&reads
), reads
.size(),
6503 vector_as_array(&writes
), writes
.size());
6505 ScopedVector
<UploadElementReader
> element_readers
;
6506 std::string
upload_data_string(initial_window_size
, 'a');
6507 upload_data_string
.append(kUploadData
, kUploadDataSize
);
6508 element_readers
.push_back(new UploadBytesElementReader(
6509 upload_data_string
.c_str(), upload_data_string
.size()));
6510 ElementsUploadDataStream
upload_data_stream(element_readers
.Pass(), 0);
6512 HttpRequestInfo request
;
6513 request
.method
= "POST";
6514 request
.url
= GURL(GetDefaultUrl());
6515 request
.upload_data_stream
= &upload_data_stream
;
6516 NormalSpdyTransactionHelper
helper(request
, DEFAULT_PRIORITY
,
6517 BoundNetLog(), GetParam(), NULL
);
6518 helper
.SetDeterministic();
6519 helper
.RunPreTestSetup();
6520 helper
.AddDeterministicData(&data
);
6522 HttpNetworkTransaction
* trans
= helper
.trans();
6524 TestCompletionCallback callback
;
6525 int rv
= trans
->Start(&helper
.request(), callback
.callback(), BoundNetLog());
6526 EXPECT_EQ(ERR_IO_PENDING
, rv
);
6528 data
.RunFor(num_writes
- 1); // Write as much as we can.
6530 SpdyHttpStream
* stream
= static_cast<SpdyHttpStream
*>(trans
->stream_
.get());
6531 ASSERT_TRUE(stream
!= NULL
);
6532 ASSERT_TRUE(stream
->stream() != NULL
);
6533 EXPECT_EQ(0, stream
->stream()->send_window_size());
6535 // All the body data should have been read.
6536 // TODO(satorux): This is because of the weirdness in reading the request
6537 // body in OnSendBodyComplete(). See crbug.com/113107.
6538 EXPECT_TRUE(upload_data_stream
.IsEOF());
6539 // But the body is not yet fully sent (kUploadData is not yet sent)
6540 // since we're send-stalled.
6541 EXPECT_TRUE(stream
->stream()->send_stalled_by_flow_control());
6543 // Read in WINDOW_UPDATE or SETTINGS frame.
6544 data
.RunFor((GetParam().protocol
>= kProtoSPDY31
) ? 9 : 8);
6545 rv
= callback
.WaitForResult();
6546 helper
.VerifyDataConsumed();
6549 TEST_P(SpdyNetworkTransactionTest
, GoAwayOnOddPushStreamId
) {
6550 if (spdy_util_
.spdy_version() < SPDY3
)
6553 scoped_ptr
<SpdyHeaderBlock
> push_headers(new SpdyHeaderBlock
);
6554 spdy_util_
.AddUrlToHeaderBlock("http://www.google.com/a.dat",
6555 push_headers
.get());
6556 scoped_ptr
<SpdyFrame
> push(
6557 spdy_util_
.ConstructInitialSpdyPushFrame(push_headers
.Pass(), 3, 1));
6558 MockRead reads
[] = {CreateMockRead(*push
, 1)};
6560 scoped_ptr
<SpdyFrame
> req(
6561 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
6562 scoped_ptr
<SpdyFrame
> goaway(spdy_util_
.ConstructSpdyGoAway(
6563 0, GOAWAY_PROTOCOL_ERROR
, "Odd push stream id."));
6564 MockWrite writes
[] = {
6565 CreateMockWrite(*req
, 0), CreateMockWrite(*goaway
, 2),
6568 DelayedSocketData
data(1, reads
, arraysize(reads
), writes
, arraysize(writes
));
6569 NormalSpdyTransactionHelper
helper(
6570 CreateGetRequest(), DEFAULT_PRIORITY
, BoundNetLog(), GetParam(), NULL
);
6571 helper
.RunToCompletion(&data
);
6572 TransactionHelperResult out
= helper
.output();
6573 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR
, out
.rv
);
6576 TEST_P(SpdyNetworkTransactionTest
,
6577 GoAwayOnPushStreamIdLesserOrEqualThanLastAccepted
) {
6578 if (spdy_util_
.spdy_version() < SPDY3
)
6581 scoped_ptr
<SpdyFrame
> push_a(spdy_util_
.ConstructSpdyPush(
6582 NULL
, 0, 4, 1, GetDefaultUrlWithPath("/a.dat").c_str()));
6583 scoped_ptr
<SpdyHeaderBlock
> push_b_headers(new SpdyHeaderBlock
);
6584 spdy_util_
.AddUrlToHeaderBlock(GetDefaultUrlWithPath("/b.dat"),
6585 push_b_headers
.get());
6586 scoped_ptr
<SpdyFrame
> push_b(
6587 spdy_util_
.ConstructInitialSpdyPushFrame(push_b_headers
.Pass(), 2, 1));
6588 MockRead reads
[] = {
6589 CreateMockRead(*push_a
, 1), CreateMockRead(*push_b
, 2),
6592 scoped_ptr
<SpdyFrame
> req(
6593 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
6594 scoped_ptr
<SpdyFrame
> goaway(spdy_util_
.ConstructSpdyGoAway(
6596 GOAWAY_PROTOCOL_ERROR
,
6597 "New push stream id must be greater than the last accepted."));
6598 MockWrite writes
[] = {
6599 CreateMockWrite(*req
, 0), CreateMockWrite(*goaway
, 3),
6602 DelayedSocketData
data(1, reads
, arraysize(reads
), writes
, arraysize(writes
));
6603 NormalSpdyTransactionHelper
helper(
6604 CreateGetRequest(), DEFAULT_PRIORITY
, BoundNetLog(), GetParam(), NULL
);
6605 helper
.RunToCompletion(&data
);
6606 TransactionHelperResult out
= helper
.output();
6607 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR
, out
.rv
);
6610 class SpdyNetworkTransactionNoTLSUsageCheckTest
6611 : public SpdyNetworkTransactionTest
{
6613 void RunNoTLSUsageCheckTest(scoped_ptr
<SSLSocketDataProvider
> ssl_provider
) {
6614 // Construct the request.
6615 scoped_ptr
<SpdyFrame
> req(
6616 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
6617 MockWrite writes
[] = {CreateMockWrite(*req
)};
6619 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
6620 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
6621 MockRead reads
[] = {
6622 CreateMockRead(*resp
), CreateMockRead(*body
),
6623 MockRead(ASYNC
, 0, 0) // EOF
6626 DelayedSocketData
data(
6627 1, reads
, arraysize(reads
), writes
, arraysize(writes
));
6628 HttpRequestInfo request
;
6629 request
.method
= "GET";
6630 request
.url
= GURL("https://www.google.com/");
6631 NormalSpdyTransactionHelper
helper(
6632 request
, DEFAULT_PRIORITY
, BoundNetLog(), GetParam(), NULL
);
6633 helper
.RunToCompletionWithSSLData(&data
, ssl_provider
.Pass());
6634 TransactionHelperResult out
= helper
.output();
6635 EXPECT_EQ(OK
, out
.rv
);
6636 EXPECT_EQ("HTTP/1.1 200 OK", out
.status_line
);
6637 EXPECT_EQ("hello!", out
.response_data
);
6641 //-----------------------------------------------------------------------------
6642 // All tests are run with three different connection types: SPDY after NPN
6643 // negotiation, SPDY without SSL, and SPDY with SSL.
6645 // TODO(akalin): Use ::testing::Combine() when we are able to use
6647 INSTANTIATE_TEST_CASE_P(
6649 SpdyNetworkTransactionNoTLSUsageCheckTest
,
6650 ::testing::Values(SpdyNetworkTransactionTestParams(kProtoSPDY31
,
6651 HTTPS_SPDY_VIA_NPN
)));
6653 TEST_P(SpdyNetworkTransactionNoTLSUsageCheckTest
, TLSVersionTooOld
) {
6654 scoped_ptr
<SSLSocketDataProvider
> ssl_provider(
6655 new SSLSocketDataProvider(ASYNC
, OK
));
6656 SSLConnectionStatusSetVersion(SSL_CONNECTION_VERSION_SSL3
,
6657 &ssl_provider
->connection_status
);
6659 RunNoTLSUsageCheckTest(ssl_provider
.Pass());
6662 TEST_P(SpdyNetworkTransactionNoTLSUsageCheckTest
, TLSCipherSuiteSucky
) {
6663 scoped_ptr
<SSLSocketDataProvider
> ssl_provider(
6664 new SSLSocketDataProvider(ASYNC
, OK
));
6665 // Set to TLS_RSA_WITH_NULL_MD5
6666 SSLConnectionStatusSetCipherSuite(0x1, &ssl_provider
->connection_status
);
6668 RunNoTLSUsageCheckTest(ssl_provider
.Pass());
6671 class SpdyNetworkTransactionTLSUsageCheckTest
6672 : public SpdyNetworkTransactionTest
{
6674 void RunTLSUsageCheckTest(scoped_ptr
<SSLSocketDataProvider
> ssl_provider
) {
6675 scoped_ptr
<SpdyFrame
> goaway(
6676 spdy_util_
.ConstructSpdyGoAway(0, GOAWAY_INADEQUATE_SECURITY
, ""));
6677 MockWrite writes
[] = {CreateMockWrite(*goaway
)};
6679 DelayedSocketData
data(1, NULL
, 0, writes
, arraysize(writes
));
6680 HttpRequestInfo request
;
6681 request
.method
= "GET";
6682 request
.url
= GURL("https://www.google.com/");
6683 NormalSpdyTransactionHelper
helper(
6684 request
, DEFAULT_PRIORITY
, BoundNetLog(), GetParam(), NULL
);
6685 helper
.RunToCompletionWithSSLData(&data
, ssl_provider
.Pass());
6686 TransactionHelperResult out
= helper
.output();
6687 EXPECT_EQ(ERR_SPDY_INADEQUATE_TRANSPORT_SECURITY
, out
.rv
);
6691 INSTANTIATE_TEST_CASE_P(
6693 SpdyNetworkTransactionTLSUsageCheckTest
,
6695 SpdyNetworkTransactionTestParams(kProtoSPDY4_14
, HTTPS_SPDY_VIA_NPN
),
6696 SpdyNetworkTransactionTestParams(kProtoSPDY4
, HTTPS_SPDY_VIA_NPN
)));
6698 TEST_P(SpdyNetworkTransactionTLSUsageCheckTest
, TLSVersionTooOld
) {
6699 scoped_ptr
<SSLSocketDataProvider
> ssl_provider(
6700 new SSLSocketDataProvider(ASYNC
, OK
));
6701 SSLConnectionStatusSetVersion(SSL_CONNECTION_VERSION_SSL3
,
6702 &ssl_provider
->connection_status
);
6704 RunTLSUsageCheckTest(ssl_provider
.Pass());
6707 TEST_P(SpdyNetworkTransactionTLSUsageCheckTest
, TLSCipherSuiteSucky
) {
6708 scoped_ptr
<SSLSocketDataProvider
> ssl_provider(
6709 new SSLSocketDataProvider(ASYNC
, OK
));
6710 // Set to TLS_RSA_WITH_NULL_MD5
6711 SSLConnectionStatusSetCipherSuite(0x1, &ssl_provider
->connection_status
);
6713 RunTLSUsageCheckTest(ssl_provider
.Pass());