Update Polymer and pull in iron-list
[chromium-blink-merge.git] / net / spdy / spdy_network_transaction_unittest.cc
blobfa4f03b21431a16fe57ed472594ed308e81b5630
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.
5 #include <string>
6 #include <vector>
8 #include "base/bind.h"
9 #include "base/bind_helpers.h"
10 #include "base/files/file_util.h"
11 #include "base/files/scoped_temp_dir.h"
12 #include "base/memory/scoped_vector.h"
13 #include "base/run_loop.h"
14 #include "base/stl_util.h"
15 #include "base/strings/string_piece.h"
16 #include "base/test/test_file_util.h"
17 #include "base/thread_task_runner_handle.h"
18 #include "net/base/auth.h"
19 #include "net/base/chunked_upload_data_stream.h"
20 #include "net/base/elements_upload_data_stream.h"
21 #include "net/base/request_priority.h"
22 #include "net/base/test_data_directory.h"
23 #include "net/base/upload_bytes_element_reader.h"
24 #include "net/base/upload_file_element_reader.h"
25 #include "net/http/http_network_session_peer.h"
26 #include "net/http/http_network_transaction.h"
27 #include "net/http/http_server_properties.h"
28 #include "net/http/http_transaction_test_util.h"
29 #include "net/log/test_net_log.h"
30 #include "net/log/test_net_log_entry.h"
31 #include "net/log/test_net_log_util.h"
32 #include "net/socket/client_socket_pool_base.h"
33 #include "net/socket/next_proto.h"
34 #include "net/spdy/buffered_spdy_framer.h"
35 #include "net/spdy/spdy_http_stream.h"
36 #include "net/spdy/spdy_http_utils.h"
37 #include "net/spdy/spdy_session.h"
38 #include "net/spdy/spdy_session_pool.h"
39 #include "net/spdy/spdy_test_util_common.h"
40 #include "net/spdy/spdy_test_utils.h"
41 #include "net/ssl/ssl_connection_status_flags.h"
42 #include "net/test/cert_test_util.h"
43 #include "net/url_request/url_request_test_util.h"
44 #include "testing/gmock/include/gmock/gmock.h"
45 #include "testing/platform_test.h"
47 //-----------------------------------------------------------------------------
49 namespace net {
51 namespace {
53 using testing::Each;
54 using testing::Eq;
56 enum SpdyNetworkTransactionTestSSLType {
57 // Request an https:// URL and use NPN (or ALPN) to negotiate SPDY during
58 // the TLS handshake.
59 HTTPS_SPDY_VIA_NPN,
60 // Request and http:// URL to a server that supports SPDY via Alternative
61 // Service on port 443.
62 // See: https//tools.ietf.org/id/draft-ietf-httpbis-alt-svc-06.html
63 HTTP_SPDY_VIA_ALT_SVC,
66 struct SpdyNetworkTransactionTestParams {
67 SpdyNetworkTransactionTestParams()
68 : protocol(kProtoSPDY31), ssl_type(HTTPS_SPDY_VIA_NPN) {}
70 SpdyNetworkTransactionTestParams(NextProto protocol,
71 SpdyNetworkTransactionTestSSLType ssl_type)
72 : protocol(protocol), ssl_type(ssl_type) {}
74 friend std::ostream& operator<<(std::ostream& os,
75 const SpdyNetworkTransactionTestParams& p) {
76 std::string type_str;
77 switch (p.ssl_type) {
78 case HTTP_SPDY_VIA_ALT_SVC:
79 type_str = "HTTP_SPDY_VIA_ALT_SVC";
80 break;
81 case HTTPS_SPDY_VIA_NPN:
82 type_str = "HTTPS_SPDY_VIA_NPN";
83 break;
85 os << "{ protocol: " << SSLClientSocket::NextProtoToString(p.protocol)
86 << ", ssl_type: " << type_str << " }";
87 return os;
90 NextProto protocol;
91 SpdyNetworkTransactionTestSSLType ssl_type;
94 void UpdateSpdySessionDependencies(SpdyNetworkTransactionTestParams test_params,
95 SpdySessionDependencies* session_deps) {
96 session_deps->use_alternative_services = true;
97 session_deps->next_protos = SpdyNextProtos();
98 if (test_params.ssl_type == HTTP_SPDY_VIA_ALT_SVC) {
99 base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1);
100 session_deps->http_server_properties.SetAlternativeService(
101 HostPortPair("www.example.org", 80),
102 AlternativeService(AlternateProtocolFromNextProto(test_params.protocol),
103 "www.example.org", 443),
104 1.0, expiration);
108 scoped_ptr<SpdySessionDependencies> CreateSpdySessionDependencies(
109 SpdyNetworkTransactionTestParams test_params) {
110 scoped_ptr<SpdySessionDependencies> session_deps(
111 new SpdySessionDependencies(test_params.protocol));
112 UpdateSpdySessionDependencies(test_params, session_deps.get());
113 return session_deps;
116 scoped_ptr<SpdySessionDependencies> CreateSpdySessionDependencies(
117 SpdyNetworkTransactionTestParams test_params,
118 scoped_ptr<ProxyService> proxy_service) {
119 scoped_ptr<SpdySessionDependencies> session_deps(
120 new SpdySessionDependencies(test_params.protocol, proxy_service.Pass()));
121 UpdateSpdySessionDependencies(test_params, session_deps.get());
122 return session_deps;
125 } // namespace
127 class SpdyNetworkTransactionTest
128 : public ::testing::TestWithParam<SpdyNetworkTransactionTestParams> {
129 protected:
130 SpdyNetworkTransactionTest() : spdy_util_(GetParam().protocol) {
131 spdy_util_.set_default_url(GURL(GetDefaultUrl()));
134 virtual ~SpdyNetworkTransactionTest() {
135 // UploadDataStream may post a deletion tasks back to the message loop on
136 // destruction.
137 upload_data_stream_.reset();
138 base::RunLoop().RunUntilIdle();
141 void SetUp() override {
142 get_request_initialized_ = false;
143 post_request_initialized_ = false;
144 chunked_post_request_initialized_ = false;
145 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
148 struct TransactionHelperResult {
149 int rv;
150 std::string status_line;
151 std::string response_data;
152 HttpResponseInfo response_info;
155 // A helper class that handles all the initial npn/ssl setup.
156 class NormalSpdyTransactionHelper {
157 public:
158 NormalSpdyTransactionHelper(
159 const HttpRequestInfo& request,
160 RequestPriority priority,
161 const BoundNetLog& log,
162 SpdyNetworkTransactionTestParams test_params,
163 scoped_ptr<SpdySessionDependencies> session_deps)
164 : request_(request),
165 priority_(priority),
166 session_deps_(session_deps.get() == NULL
167 ? CreateSpdySessionDependencies(test_params)
168 : session_deps.Pass()),
169 session_(
170 SpdySessionDependencies::SpdyCreateSession(session_deps_.get())),
171 log_(log),
172 test_params_(test_params),
173 port_(443),
174 deterministic_(false),
175 spdy_enabled_(true) {}
177 ~NormalSpdyTransactionHelper() {
178 // Any test which doesn't close the socket by sending it an EOF will
179 // have a valid session left open, which leaks the entire session pool.
180 // This is just fine - in fact, some of our tests intentionally do this
181 // so that we can check consistency of the SpdySessionPool as the test
182 // finishes. If we had put an EOF on the socket, the SpdySession would
183 // have closed and we wouldn't be able to check the consistency.
185 // Forcefully close existing sessions here.
186 session()->spdy_session_pool()->CloseAllSessions();
189 void SetDeterministic() {
190 session_ = SpdySessionDependencies::SpdyCreateSessionDeterministic(
191 session_deps_.get());
192 deterministic_ = true;
195 void SetSpdyDisabled() {
196 spdy_enabled_ = false;
197 port_ = test_params_.ssl_type == HTTP_SPDY_VIA_ALT_SVC ? 80 : 443;
200 void RunPreTestSetup() {
201 if (!session_deps_.get())
202 session_deps_ = CreateSpdySessionDependencies(test_params_);
203 if (!session_.get()) {
204 session_ = SpdySessionDependencies::SpdyCreateSession(
205 session_deps_.get());
208 // We're now ready to use SSL-npn SPDY.
209 trans_.reset(new HttpNetworkTransaction(priority_, session_.get()));
212 // Start the transaction, read some data, finish.
213 void RunDefaultTest() {
214 if (!StartDefaultTest())
215 return;
216 FinishDefaultTest();
219 bool StartDefaultTest() {
220 output_.rv = trans_->Start(&request_, callback_.callback(), log_);
222 // We expect an IO Pending or some sort of error.
223 EXPECT_LT(output_.rv, 0);
224 return output_.rv == ERR_IO_PENDING;
227 void FinishDefaultTest() {
228 output_.rv = callback_.WaitForResult();
229 if (output_.rv != OK) {
230 session_->spdy_session_pool()->CloseCurrentSessions(ERR_ABORTED);
231 return;
234 // Verify responses.
235 const HttpResponseInfo* response = trans_->GetResponseInfo();
236 ASSERT_TRUE(response != NULL);
237 ASSERT_TRUE(response->headers.get() != NULL);
238 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
239 EXPECT_EQ(spdy_enabled_, response->was_fetched_via_spdy);
240 if (HttpStreamFactory::spdy_enabled()) {
241 EXPECT_EQ(
242 HttpResponseInfo::ConnectionInfoFromNextProto(
243 test_params_.protocol),
244 response->connection_info);
245 } else {
246 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP1,
247 response->connection_info);
249 if (spdy_enabled_) {
250 EXPECT_TRUE(response->was_npn_negotiated);
251 } else {
252 // If SPDY is disabled, an HTTP request should not be diverted
253 // over an SSL session.
254 EXPECT_EQ(request_.url.SchemeIs("https"),
255 response->was_npn_negotiated);
257 EXPECT_EQ("127.0.0.1", response->socket_address.host());
258 EXPECT_EQ(port_, response->socket_address.port());
259 output_.status_line = response->headers->GetStatusLine();
260 output_.response_info = *response; // Make a copy so we can verify.
261 output_.rv = ReadTransaction(trans_.get(), &output_.response_data);
264 void FinishDefaultTestWithoutVerification() {
265 output_.rv = callback_.WaitForResult();
266 if (output_.rv != OK)
267 session_->spdy_session_pool()->CloseCurrentSessions(ERR_ABORTED);
270 // Most tests will want to call this function. In particular, the MockReads
271 // should end with an empty read, and that read needs to be processed to
272 // ensure proper deletion of the spdy_session_pool.
273 void VerifyDataConsumed() {
274 for (const SocketDataProvider* provider : data_vector_) {
275 EXPECT_TRUE(provider->AllReadDataConsumed());
276 EXPECT_TRUE(provider->AllWriteDataConsumed());
278 for (const DeterministicSocketData* provider :
279 deterministic_data_vector_) {
280 EXPECT_TRUE(provider->AllReadDataConsumed());
281 EXPECT_TRUE(provider->AllWriteDataConsumed());
285 // Occasionally a test will expect to error out before certain reads are
286 // processed. In that case we want to explicitly ensure that the reads were
287 // not processed.
288 void VerifyDataNotConsumed() {
289 for (const SocketDataProvider* provider : data_vector_) {
290 EXPECT_FALSE(provider->AllReadDataConsumed());
291 EXPECT_FALSE(provider->AllWriteDataConsumed());
293 for (const DeterministicSocketData* provider :
294 deterministic_data_vector_) {
295 EXPECT_FALSE(provider->AllReadDataConsumed());
296 EXPECT_FALSE(provider->AllWriteDataConsumed());
300 void RunToCompletion(SocketDataProvider* data) {
301 RunPreTestSetup();
302 AddData(data);
303 RunDefaultTest();
304 VerifyDataConsumed();
307 void RunToCompletionWithSSLData(
308 SocketDataProvider* data,
309 scoped_ptr<SSLSocketDataProvider> ssl_provider) {
310 RunPreTestSetup();
311 AddDataWithSSLSocketDataProvider(data, ssl_provider.Pass());
312 RunDefaultTest();
313 VerifyDataConsumed();
316 void AddData(SocketDataProvider* data) {
317 scoped_ptr<SSLSocketDataProvider> ssl_provider(
318 new SSLSocketDataProvider(ASYNC, OK));
319 ssl_provider->cert =
320 ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem");
321 AddDataWithSSLSocketDataProvider(data, ssl_provider.Pass());
324 void AddDataWithSSLSocketDataProvider(
325 SocketDataProvider* data,
326 scoped_ptr<SSLSocketDataProvider> ssl_provider) {
327 DCHECK(!deterministic_);
328 data_vector_.push_back(data);
329 if (ssl_provider->next_proto_status ==
330 SSLClientSocket::kNextProtoUnsupported) {
331 ssl_provider->SetNextProto(test_params_.protocol);
334 session_deps_->socket_factory->AddSSLSocketDataProvider(
335 ssl_provider.get());
336 ssl_vector_.push_back(ssl_provider.release());
338 session_deps_->socket_factory->AddSocketDataProvider(data);
339 if (test_params_.ssl_type == HTTP_SPDY_VIA_ALT_SVC) {
340 MockConnect hanging_connect(SYNCHRONOUS, ERR_IO_PENDING);
341 StaticSocketDataProvider* hanging_non_alt_svc_socket =
342 new StaticSocketDataProvider(NULL, 0, NULL, 0);
343 hanging_non_alt_svc_socket->set_connect_data(hanging_connect);
344 session_deps_->socket_factory->AddSocketDataProvider(
345 hanging_non_alt_svc_socket);
346 alternate_vector_.push_back(hanging_non_alt_svc_socket);
350 void AddDeterministicData(DeterministicSocketData* data) {
351 DCHECK(deterministic_);
352 deterministic_data_vector_.push_back(data);
353 SSLSocketDataProvider* ssl_provider =
354 new SSLSocketDataProvider(ASYNC, OK);
355 ssl_provider->SetNextProto(test_params_.protocol);
356 ssl_provider->cert =
357 ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem");
358 ssl_vector_.push_back(ssl_provider);
359 session_deps_->deterministic_socket_factory->AddSSLSocketDataProvider(
360 ssl_provider);
362 session_deps_->deterministic_socket_factory->AddSocketDataProvider(data);
363 if (test_params_.ssl_type == HTTP_SPDY_VIA_ALT_SVC) {
364 MockConnect hanging_connect(SYNCHRONOUS, ERR_IO_PENDING);
365 DeterministicSocketData* hanging_non_alt_svc_socket =
366 new DeterministicSocketData(NULL, 0, NULL, 0);
367 hanging_non_alt_svc_socket->set_connect_data(hanging_connect);
368 session_deps_->deterministic_socket_factory->AddSocketDataProvider(
369 hanging_non_alt_svc_socket);
370 alternate_deterministic_vector_.push_back(hanging_non_alt_svc_socket);
374 void SetSession(const scoped_refptr<HttpNetworkSession>& session) {
375 session_ = session;
377 HttpNetworkTransaction* trans() { return trans_.get(); }
378 void ResetTrans() { trans_.reset(); }
379 TransactionHelperResult& output() { return output_; }
380 const HttpRequestInfo& request() const { return request_; }
381 const scoped_refptr<HttpNetworkSession>& session() const {
382 return session_;
384 scoped_ptr<SpdySessionDependencies>& session_deps() {
385 return session_deps_;
387 int port() const { return port_; }
388 SpdyNetworkTransactionTestParams test_params() const {
389 return test_params_;
392 private:
393 typedef std::vector<SocketDataProvider*> DataVector;
394 typedef std::vector<DeterministicSocketData*> DeterministicDataVector;
395 typedef ScopedVector<SSLSocketDataProvider> SSLVector;
396 typedef ScopedVector<SocketDataProvider> AlternateVector;
397 typedef ScopedVector<DeterministicSocketData> AlternateDeterministicVector;
398 HttpRequestInfo request_;
399 RequestPriority priority_;
400 scoped_ptr<SpdySessionDependencies> session_deps_;
401 scoped_refptr<HttpNetworkSession> session_;
402 TransactionHelperResult output_;
403 scoped_ptr<SocketDataProvider> first_transaction_;
404 SSLVector ssl_vector_;
405 TestCompletionCallback callback_;
406 scoped_ptr<HttpNetworkTransaction> trans_;
407 scoped_ptr<HttpNetworkTransaction> trans_http_;
408 DataVector data_vector_;
409 DeterministicDataVector deterministic_data_vector_;
410 AlternateVector alternate_vector_;
411 AlternateDeterministicVector alternate_deterministic_vector_;
412 const BoundNetLog log_;
413 SpdyNetworkTransactionTestParams test_params_;
414 int port_;
415 bool deterministic_;
416 bool spdy_enabled_;
419 void ConnectStatusHelperWithExpectedStatus(const MockRead& status,
420 int expected_status);
422 void ConnectStatusHelper(const MockRead& status);
424 const HttpRequestInfo& CreateGetPushRequest() {
425 get_push_request_.method = "GET";
426 get_push_request_.url = GURL(GetDefaultUrlWithPath("/foo.dat"));
427 get_push_request_.load_flags = 0;
428 return get_push_request_;
431 const HttpRequestInfo& CreateGetRequest() {
432 if (!get_request_initialized_) {
433 get_request_.method = "GET";
434 get_request_.url = GURL(GetDefaultUrl());
435 get_request_.load_flags = 0;
436 get_request_initialized_ = true;
438 return get_request_;
441 const HttpRequestInfo& CreateGetRequestWithUserAgent() {
442 if (!get_request_initialized_) {
443 get_request_.method = "GET";
444 get_request_.url = GURL(GetDefaultUrl());
445 get_request_.load_flags = 0;
446 get_request_.extra_headers.SetHeader("User-Agent", "Chrome");
447 get_request_initialized_ = true;
449 return get_request_;
452 const HttpRequestInfo& CreatePostRequest() {
453 if (!post_request_initialized_) {
454 ScopedVector<UploadElementReader> element_readers;
455 element_readers.push_back(
456 new UploadBytesElementReader(kUploadData, kUploadDataSize));
457 upload_data_stream_.reset(
458 new ElementsUploadDataStream(element_readers.Pass(), 0));
460 post_request_.method = "POST";
461 post_request_.url = GURL(GetDefaultUrl());
462 post_request_.upload_data_stream = upload_data_stream_.get();
463 post_request_initialized_ = true;
465 return post_request_;
468 const HttpRequestInfo& CreateFilePostRequest() {
469 if (!post_request_initialized_) {
470 base::FilePath file_path;
471 CHECK(base::CreateTemporaryFileInDir(temp_dir_.path(), &file_path));
472 CHECK_EQ(static_cast<int>(kUploadDataSize),
473 base::WriteFile(file_path, kUploadData, kUploadDataSize));
475 ScopedVector<UploadElementReader> element_readers;
476 element_readers.push_back(new UploadFileElementReader(
477 base::ThreadTaskRunnerHandle::Get().get(), file_path, 0,
478 kUploadDataSize, base::Time()));
479 upload_data_stream_.reset(
480 new ElementsUploadDataStream(element_readers.Pass(), 0));
482 post_request_.method = "POST";
483 post_request_.url = GURL(GetDefaultUrl());
484 post_request_.upload_data_stream = upload_data_stream_.get();
485 post_request_initialized_ = true;
487 return post_request_;
490 const HttpRequestInfo& CreateUnreadableFilePostRequest() {
491 if (post_request_initialized_)
492 return post_request_;
494 base::FilePath file_path;
495 CHECK(base::CreateTemporaryFileInDir(temp_dir_.path(), &file_path));
496 CHECK_EQ(static_cast<int>(kUploadDataSize),
497 base::WriteFile(file_path, kUploadData, kUploadDataSize));
498 CHECK(base::MakeFileUnreadable(file_path));
500 ScopedVector<UploadElementReader> element_readers;
501 element_readers.push_back(new UploadFileElementReader(
502 base::ThreadTaskRunnerHandle::Get().get(), file_path, 0,
503 kUploadDataSize, base::Time()));
504 upload_data_stream_.reset(
505 new ElementsUploadDataStream(element_readers.Pass(), 0));
507 post_request_.method = "POST";
508 post_request_.url = GURL(GetDefaultUrl());
509 post_request_.upload_data_stream = upload_data_stream_.get();
510 post_request_initialized_ = true;
511 return post_request_;
514 const HttpRequestInfo& CreateComplexPostRequest() {
515 if (!post_request_initialized_) {
516 const int kFileRangeOffset = 1;
517 const int kFileRangeLength = 3;
518 CHECK_LT(kFileRangeOffset + kFileRangeLength, kUploadDataSize);
520 base::FilePath file_path;
521 CHECK(base::CreateTemporaryFileInDir(temp_dir_.path(), &file_path));
522 CHECK_EQ(static_cast<int>(kUploadDataSize),
523 base::WriteFile(file_path, kUploadData, kUploadDataSize));
525 ScopedVector<UploadElementReader> element_readers;
526 element_readers.push_back(
527 new UploadBytesElementReader(kUploadData, kFileRangeOffset));
528 element_readers.push_back(new UploadFileElementReader(
529 base::ThreadTaskRunnerHandle::Get().get(), file_path,
530 kFileRangeOffset, kFileRangeLength, base::Time()));
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 post_request_.method = "POST";
538 post_request_.url = GURL(GetDefaultUrl());
539 post_request_.upload_data_stream = upload_data_stream_.get();
540 post_request_initialized_ = true;
542 return post_request_;
545 const HttpRequestInfo& CreateChunkedPostRequest() {
546 if (!chunked_post_request_initialized_) {
547 upload_chunked_data_stream_.reset(new ChunkedUploadDataStream(0));
548 chunked_post_request_.method = "POST";
549 chunked_post_request_.url = GURL(GetDefaultUrl());
550 chunked_post_request_.upload_data_stream =
551 upload_chunked_data_stream_.get();
552 chunked_post_request_initialized_ = true;
554 return 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 std::string* result) {
563 const int kSize = 3000;
565 int bytes_read = 0;
566 scoped_refptr<IOBufferWithSize> buf(new IOBufferWithSize(kSize));
567 TestCompletionCallback callback;
568 while (true) {
569 int rv = trans->Read(buf.get(), kSize, callback.callback());
570 if (rv == ERR_IO_PENDING) {
571 rv = callback.WaitForResult();
572 } else if (rv <= 0) {
573 break;
575 result->append(buf->data(), rv);
576 bytes_read += rv;
578 return bytes_read;
581 void VerifyStreamsClosed(const NormalSpdyTransactionHelper& helper) {
582 // This lengthy block is reaching into the pool to dig out the active
583 // session. Once we have the session, we verify that the streams are
584 // all closed and not leaked at this point.
585 const GURL& url = helper.request().url;
586 HostPortPair host_port_pair(url.host(), 443);
587 SpdySessionKey key(host_port_pair, ProxyServer::Direct(),
588 PRIVACY_MODE_DISABLED);
589 BoundNetLog log;
590 const scoped_refptr<HttpNetworkSession>& session = helper.session();
591 base::WeakPtr<SpdySession> spdy_session =
592 session->spdy_session_pool()->FindAvailableSession(key, log);
593 ASSERT_TRUE(spdy_session != NULL);
594 EXPECT_EQ(0u, spdy_session->num_active_streams());
595 EXPECT_EQ(0u, spdy_session->num_unclaimed_pushed_streams());
598 void RunServerPushTest(SequencedSocketData* data,
599 HttpResponseInfo* response,
600 HttpResponseInfo* push_response,
601 const std::string& expected) {
602 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
603 BoundNetLog(), GetParam(), NULL);
604 helper.RunPreTestSetup();
605 helper.AddData(data);
607 HttpNetworkTransaction* trans = helper.trans();
609 // Start the transaction with basic parameters.
610 TestCompletionCallback callback;
611 int rv = trans->Start(
612 &CreateGetRequest(), callback.callback(), BoundNetLog());
613 EXPECT_EQ(ERR_IO_PENDING, rv);
614 rv = callback.WaitForResult();
616 // Request the pushed path.
617 scoped_ptr<HttpNetworkTransaction> trans2(
618 new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get()));
619 rv = trans2->Start(
620 &CreateGetPushRequest(), callback.callback(), BoundNetLog());
621 EXPECT_EQ(ERR_IO_PENDING, rv);
622 base::RunLoop().RunUntilIdle();
624 // The data for the pushed path may be coming in more than 1 frame. Compile
625 // the results into a single string.
627 // Read the server push body.
628 std::string result2;
629 ReadResult(trans2.get(), &result2);
630 // Read the response body.
631 std::string result;
632 ReadResult(trans, &result);
634 // Verify that we consumed all test data.
635 EXPECT_TRUE(data->AllReadDataConsumed());
636 EXPECT_TRUE(data->AllWriteDataConsumed());
638 // Verify that the received push data is same as the expected push data.
639 EXPECT_EQ(result2.compare(expected), 0) << "Received data: "
640 << result2
641 << "||||| Expected data: "
642 << expected;
644 // Verify the SYN_REPLY.
645 // Copy the response info, because trans goes away.
646 *response = *trans->GetResponseInfo();
647 *push_response = *trans2->GetResponseInfo();
649 VerifyStreamsClosed(helper);
652 static void DeleteSessionCallback(NormalSpdyTransactionHelper* helper,
653 int result) {
654 helper->ResetTrans();
657 static void StartTransactionCallback(
658 const scoped_refptr<HttpNetworkSession>& session,
659 GURL url,
660 int result) {
661 scoped_ptr<HttpNetworkTransaction> trans(
662 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
663 TestCompletionCallback callback;
664 HttpRequestInfo request;
665 request.method = "GET";
666 request.url = url;
667 request.load_flags = 0;
668 int rv = trans->Start(&request, callback.callback(), BoundNetLog());
669 EXPECT_EQ(ERR_IO_PENDING, rv);
670 callback.WaitForResult();
673 ChunkedUploadDataStream* upload_chunked_data_stream() const {
674 return upload_chunked_data_stream_.get();
677 const char* GetDefaultUrl() {
678 switch (GetParam().ssl_type) {
679 case HTTP_SPDY_VIA_ALT_SVC:
680 return "http://www.example.org";
681 case HTTPS_SPDY_VIA_NPN:
682 return "https://www.example.org";
683 default:
684 NOTREACHED();
685 return "";
689 std::string GetDefaultUrlWithPath(const char* path) {
690 return std::string(GetDefaultUrl()) + path;
693 SpdyTestUtil spdy_util_;
695 private:
696 scoped_ptr<ChunkedUploadDataStream> upload_chunked_data_stream_;
697 scoped_ptr<UploadDataStream> upload_data_stream_;
698 bool get_request_initialized_;
699 bool post_request_initialized_;
700 bool chunked_post_request_initialized_;
701 HttpRequestInfo get_request_;
702 HttpRequestInfo post_request_;
703 HttpRequestInfo chunked_post_request_;
704 HttpRequestInfo get_push_request_;
705 base::ScopedTempDir temp_dir_;
708 //-----------------------------------------------------------------------------
709 // All tests are run with three different connection types: SPDY after NPN
710 // negotiation, SPDY without SSL, and SPDY with SSL.
712 // TODO(akalin): Use ::testing::Combine() when we are able to use
713 // <tr1/tuple>.
714 INSTANTIATE_TEST_CASE_P(
715 Spdy,
716 SpdyNetworkTransactionTest,
717 ::testing::Values(
718 SpdyNetworkTransactionTestParams(kProtoSPDY31, HTTPS_SPDY_VIA_NPN),
719 SpdyNetworkTransactionTestParams(kProtoSPDY31, HTTP_SPDY_VIA_ALT_SVC),
720 SpdyNetworkTransactionTestParams(kProtoHTTP2, HTTPS_SPDY_VIA_NPN),
721 SpdyNetworkTransactionTestParams(kProtoHTTP2, HTTP_SPDY_VIA_ALT_SVC)));
723 // Verify HttpNetworkTransaction constructor.
724 TEST_P(SpdyNetworkTransactionTest, Constructor) {
725 scoped_ptr<SpdySessionDependencies> session_deps(
726 CreateSpdySessionDependencies(GetParam()));
727 scoped_refptr<HttpNetworkSession> session(
728 SpdySessionDependencies::SpdyCreateSession(session_deps.get()));
729 scoped_ptr<HttpTransaction> trans(
730 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
733 TEST_P(SpdyNetworkTransactionTest, Get) {
734 // Construct the request.
735 scoped_ptr<SpdyFrame> req(
736 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
737 MockWrite writes[] = {CreateMockWrite(*req, 0)};
739 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
740 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
741 MockRead reads[] = {
742 CreateMockRead(*resp, 1),
743 CreateMockRead(*body, 2),
744 MockRead(ASYNC, 0, 3) // EOF
747 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
748 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
749 BoundNetLog(), GetParam(), NULL);
750 helper.RunToCompletion(&data);
751 TransactionHelperResult out = helper.output();
752 EXPECT_EQ(OK, out.rv);
753 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
754 EXPECT_EQ("hello!", out.response_data);
757 TEST_P(SpdyNetworkTransactionTest, GetAtEachPriority) {
758 for (RequestPriority p = MINIMUM_PRIORITY; p <= MAXIMUM_PRIORITY;
759 p = RequestPriority(p + 1)) {
760 // Construct the request.
761 scoped_ptr<SpdyFrame> req(
762 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, p, true));
763 MockWrite writes[] = {CreateMockWrite(*req, 0)};
765 SpdyPriority spdy_prio = 0;
766 EXPECT_TRUE(GetSpdyPriority(spdy_util_.spdy_version(), *req, &spdy_prio));
767 // this repeats the RequestPriority-->SpdyPriority mapping from
768 // SpdyFramer::ConvertRequestPriorityToSpdyPriority to make
769 // sure it's being done right.
770 if (spdy_util_.spdy_version() < SPDY3) {
771 switch (p) {
772 case HIGHEST:
773 EXPECT_EQ(0, spdy_prio);
774 break;
775 case MEDIUM:
776 EXPECT_EQ(1, spdy_prio);
777 break;
778 case LOW:
779 case LOWEST:
780 EXPECT_EQ(2, spdy_prio);
781 break;
782 case IDLE:
783 EXPECT_EQ(3, spdy_prio);
784 break;
785 default:
786 FAIL();
788 } else {
789 switch (p) {
790 case HIGHEST:
791 EXPECT_EQ(0, spdy_prio);
792 break;
793 case MEDIUM:
794 EXPECT_EQ(1, spdy_prio);
795 break;
796 case LOW:
797 EXPECT_EQ(2, spdy_prio);
798 break;
799 case LOWEST:
800 EXPECT_EQ(3, spdy_prio);
801 break;
802 case IDLE:
803 EXPECT_EQ(4, spdy_prio);
804 break;
805 default:
806 FAIL();
810 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
811 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
812 MockRead reads[] = {
813 CreateMockRead(*resp, 1),
814 CreateMockRead(*body, 2),
815 MockRead(ASYNC, 0, 3) // EOF
818 SequencedSocketData data(reads, arraysize(reads), writes,
819 arraysize(writes));
820 HttpRequestInfo http_req = CreateGetRequest();
822 NormalSpdyTransactionHelper helper(http_req, p, BoundNetLog(),
823 GetParam(), NULL);
824 helper.RunToCompletion(&data);
825 TransactionHelperResult out = helper.output();
826 EXPECT_EQ(OK, out.rv);
827 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
828 EXPECT_EQ("hello!", out.response_data);
832 // Start three gets simultaniously; making sure that multiplexed
833 // streams work properly.
835 // This can't use the TransactionHelper method, since it only
836 // handles a single transaction, and finishes them as soon
837 // as it launches them.
839 // TODO(gavinp): create a working generalized TransactionHelper that
840 // can allow multiple streams in flight.
842 TEST_P(SpdyNetworkTransactionTest, ThreeGets) {
843 scoped_ptr<SpdyFrame> req(
844 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
845 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
846 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, false));
847 scoped_ptr<SpdyFrame> fbody(spdy_util_.ConstructSpdyBodyFrame(1, true));
849 scoped_ptr<SpdyFrame> req2(
850 spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, LOWEST, true));
851 scoped_ptr<SpdyFrame> resp2(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3));
852 scoped_ptr<SpdyFrame> body2(spdy_util_.ConstructSpdyBodyFrame(3, false));
853 scoped_ptr<SpdyFrame> fbody2(spdy_util_.ConstructSpdyBodyFrame(3, true));
855 scoped_ptr<SpdyFrame> req3(
856 spdy_util_.ConstructSpdyGet(NULL, 0, false, 5, LOWEST, true));
857 scoped_ptr<SpdyFrame> resp3(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 5));
858 scoped_ptr<SpdyFrame> body3(spdy_util_.ConstructSpdyBodyFrame(5, false));
859 scoped_ptr<SpdyFrame> fbody3(spdy_util_.ConstructSpdyBodyFrame(5, true));
861 MockWrite writes[] = {
862 CreateMockWrite(*req, 0),
863 CreateMockWrite(*req2, 3),
864 CreateMockWrite(*req3, 6),
866 MockRead reads[] = {
867 CreateMockRead(*resp, 1),
868 CreateMockRead(*body, 2),
869 CreateMockRead(*resp2, 4),
870 CreateMockRead(*body2, 5),
871 CreateMockRead(*resp3, 7),
872 CreateMockRead(*body3, 8),
874 CreateMockRead(*fbody, 9),
875 CreateMockRead(*fbody2, 10),
876 CreateMockRead(*fbody3, 11),
878 MockRead(ASYNC, 0, 12), // EOF
880 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
881 SequencedSocketData data_placeholder(NULL, 0, NULL, 0);
883 BoundNetLog log;
884 TransactionHelperResult out;
885 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
886 BoundNetLog(), GetParam(), NULL);
887 helper.RunPreTestSetup();
888 helper.AddData(&data);
889 // We require placeholder data because three get requests are sent out at
890 // the same time which results in three sockets being connected. The first
891 // on will negotiate SPDY and will be used for all requests.
892 helper.AddData(&data_placeholder);
893 helper.AddData(&data_placeholder);
894 scoped_ptr<HttpNetworkTransaction> trans1(
895 new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get()));
896 scoped_ptr<HttpNetworkTransaction> trans2(
897 new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get()));
898 scoped_ptr<HttpNetworkTransaction> trans3(
899 new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get()));
901 TestCompletionCallback callback1;
902 TestCompletionCallback callback2;
903 TestCompletionCallback callback3;
905 HttpRequestInfo httpreq1 = CreateGetRequest();
906 HttpRequestInfo httpreq2 = CreateGetRequest();
907 HttpRequestInfo httpreq3 = CreateGetRequest();
909 out.rv = trans1->Start(&httpreq1, callback1.callback(), log);
910 ASSERT_EQ(ERR_IO_PENDING, out.rv);
911 out.rv = trans2->Start(&httpreq2, callback2.callback(), log);
912 ASSERT_EQ(ERR_IO_PENDING, out.rv);
913 out.rv = trans3->Start(&httpreq3, callback3.callback(), log);
914 ASSERT_EQ(ERR_IO_PENDING, out.rv);
916 out.rv = callback1.WaitForResult();
917 ASSERT_EQ(OK, out.rv);
918 out.rv = callback3.WaitForResult();
919 ASSERT_EQ(OK, out.rv);
921 const HttpResponseInfo* response1 = trans1->GetResponseInfo();
922 EXPECT_TRUE(response1->headers.get() != NULL);
923 EXPECT_TRUE(response1->was_fetched_via_spdy);
924 out.status_line = response1->headers->GetStatusLine();
925 out.response_info = *response1;
927 trans2->GetResponseInfo();
929 out.rv = ReadTransaction(trans1.get(), &out.response_data);
930 helper.VerifyDataConsumed();
931 EXPECT_EQ(OK, out.rv);
933 EXPECT_EQ(OK, out.rv);
934 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
935 EXPECT_EQ("hello!hello!", out.response_data);
938 TEST_P(SpdyNetworkTransactionTest, TwoGetsLateBinding) {
939 scoped_ptr<SpdyFrame> req(
940 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
941 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
942 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, false));
943 scoped_ptr<SpdyFrame> fbody(spdy_util_.ConstructSpdyBodyFrame(1, true));
945 scoped_ptr<SpdyFrame> req2(
946 spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, LOWEST, true));
947 scoped_ptr<SpdyFrame> resp2(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3));
948 scoped_ptr<SpdyFrame> body2(spdy_util_.ConstructSpdyBodyFrame(3, false));
949 scoped_ptr<SpdyFrame> fbody2(spdy_util_.ConstructSpdyBodyFrame(3, true));
951 MockWrite writes[] = {
952 CreateMockWrite(*req, 0), CreateMockWrite(*req2, 3),
954 MockRead reads[] = {
955 CreateMockRead(*resp, 1),
956 CreateMockRead(*body, 2),
957 CreateMockRead(*resp2, 4),
958 CreateMockRead(*body2, 5),
959 CreateMockRead(*fbody, 6),
960 CreateMockRead(*fbody2, 7),
961 MockRead(ASYNC, 0, 8), // EOF
963 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
965 MockConnect never_finishing_connect(SYNCHRONOUS, ERR_IO_PENDING);
966 SequencedSocketData data_placeholder(NULL, 0, NULL, 0);
967 data_placeholder.set_connect_data(never_finishing_connect);
969 BoundNetLog log;
970 TransactionHelperResult out;
971 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
972 BoundNetLog(), GetParam(), NULL);
973 helper.RunPreTestSetup();
974 helper.AddData(&data);
975 // We require placeholder data because two requests are sent out at
976 // the same time which results in two sockets being connected. The first
977 // on will negotiate SPDY and will be used for all requests.
978 helper.AddData(&data_placeholder);
979 scoped_ptr<HttpNetworkTransaction> trans1(
980 new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get()));
981 scoped_ptr<HttpNetworkTransaction> trans2(
982 new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get()));
984 TestCompletionCallback callback1;
985 TestCompletionCallback callback2;
987 HttpRequestInfo httpreq1 = CreateGetRequest();
988 HttpRequestInfo httpreq2 = CreateGetRequest();
990 out.rv = trans1->Start(&httpreq1, callback1.callback(), log);
991 ASSERT_EQ(ERR_IO_PENDING, out.rv);
992 out.rv = trans2->Start(&httpreq2, callback2.callback(), log);
993 ASSERT_EQ(ERR_IO_PENDING, out.rv);
995 out.rv = callback1.WaitForResult();
996 ASSERT_EQ(OK, out.rv);
997 out.rv = callback2.WaitForResult();
998 ASSERT_EQ(OK, out.rv);
1000 const HttpResponseInfo* response1 = trans1->GetResponseInfo();
1001 EXPECT_TRUE(response1->headers.get() != NULL);
1002 EXPECT_TRUE(response1->was_fetched_via_spdy);
1003 out.status_line = response1->headers->GetStatusLine();
1004 out.response_info = *response1;
1005 out.rv = ReadTransaction(trans1.get(), &out.response_data);
1006 EXPECT_EQ(OK, out.rv);
1007 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
1008 EXPECT_EQ("hello!hello!", out.response_data);
1010 const HttpResponseInfo* response2 = trans2->GetResponseInfo();
1011 EXPECT_TRUE(response2->headers.get() != NULL);
1012 EXPECT_TRUE(response2->was_fetched_via_spdy);
1013 out.status_line = response2->headers->GetStatusLine();
1014 out.response_info = *response2;
1015 out.rv = ReadTransaction(trans2.get(), &out.response_data);
1016 EXPECT_EQ(OK, out.rv);
1017 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
1018 EXPECT_EQ("hello!hello!", out.response_data);
1020 helper.VerifyDataConsumed();
1023 TEST_P(SpdyNetworkTransactionTest, TwoGetsLateBindingFromPreconnect) {
1024 scoped_ptr<SpdyFrame> req(
1025 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
1026 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
1027 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, false));
1028 scoped_ptr<SpdyFrame> fbody(spdy_util_.ConstructSpdyBodyFrame(1, true));
1030 scoped_ptr<SpdyFrame> req2(
1031 spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, LOWEST, true));
1032 scoped_ptr<SpdyFrame> resp2(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3));
1033 scoped_ptr<SpdyFrame> body2(spdy_util_.ConstructSpdyBodyFrame(3, false));
1034 scoped_ptr<SpdyFrame> fbody2(spdy_util_.ConstructSpdyBodyFrame(3, true));
1036 MockWrite writes[] = {
1037 CreateMockWrite(*req, 0), CreateMockWrite(*req2, 3),
1039 MockRead reads[] = {
1040 CreateMockRead(*resp, 1),
1041 CreateMockRead(*body, 2),
1042 CreateMockRead(*resp2, 4),
1043 CreateMockRead(*body2, 5),
1044 CreateMockRead(*fbody, 6),
1045 CreateMockRead(*fbody2, 7),
1046 MockRead(ASYNC, 0, 8), // EOF
1048 SequencedSocketData preconnect_data(reads, arraysize(reads), writes,
1049 arraysize(writes));
1051 MockConnect never_finishing_connect(ASYNC, ERR_IO_PENDING);
1053 SequencedSocketData data_placeholder(NULL, 0, NULL, 0);
1054 data_placeholder.set_connect_data(never_finishing_connect);
1056 BoundNetLog log;
1057 TransactionHelperResult out;
1058 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
1059 BoundNetLog(), GetParam(), NULL);
1060 helper.RunPreTestSetup();
1061 helper.AddData(&preconnect_data);
1062 // We require placeholder data because 3 connections are attempted (first is
1063 // the preconnect, 2nd and 3rd are the never finished connections.
1064 helper.AddData(&data_placeholder);
1065 helper.AddData(&data_placeholder);
1067 scoped_ptr<HttpNetworkTransaction> trans1(
1068 new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get()));
1069 scoped_ptr<HttpNetworkTransaction> trans2(
1070 new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get()));
1072 TestCompletionCallback callback1;
1073 TestCompletionCallback callback2;
1075 HttpRequestInfo httpreq = CreateGetRequest();
1077 // Preconnect the first.
1078 SSLConfig preconnect_ssl_config;
1079 helper.session()->ssl_config_service()->GetSSLConfig(&preconnect_ssl_config);
1080 HttpStreamFactory* http_stream_factory =
1081 helper.session()->http_stream_factory();
1082 helper.session()->GetNextProtos(&preconnect_ssl_config.next_protos);
1084 http_stream_factory->PreconnectStreams(1, httpreq, preconnect_ssl_config,
1085 preconnect_ssl_config);
1087 out.rv = trans1->Start(&httpreq, callback1.callback(), log);
1088 ASSERT_EQ(ERR_IO_PENDING, out.rv);
1089 out.rv = trans2->Start(&httpreq, callback2.callback(), log);
1090 ASSERT_EQ(ERR_IO_PENDING, out.rv);
1092 out.rv = callback1.WaitForResult();
1093 ASSERT_EQ(OK, out.rv);
1094 out.rv = callback2.WaitForResult();
1095 ASSERT_EQ(OK, out.rv);
1097 const HttpResponseInfo* response1 = trans1->GetResponseInfo();
1098 EXPECT_TRUE(response1->headers.get() != NULL);
1099 EXPECT_TRUE(response1->was_fetched_via_spdy);
1100 out.status_line = response1->headers->GetStatusLine();
1101 out.response_info = *response1;
1102 out.rv = ReadTransaction(trans1.get(), &out.response_data);
1103 EXPECT_EQ(OK, out.rv);
1104 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
1105 EXPECT_EQ("hello!hello!", out.response_data);
1107 const HttpResponseInfo* response2 = trans2->GetResponseInfo();
1108 EXPECT_TRUE(response2->headers.get() != NULL);
1109 EXPECT_TRUE(response2->was_fetched_via_spdy);
1110 out.status_line = response2->headers->GetStatusLine();
1111 out.response_info = *response2;
1112 out.rv = ReadTransaction(trans2.get(), &out.response_data);
1113 EXPECT_EQ(OK, out.rv);
1114 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
1115 EXPECT_EQ("hello!hello!", out.response_data);
1117 helper.VerifyDataConsumed();
1120 // Similar to ThreeGets above, however this test adds a SETTINGS
1121 // frame. The SETTINGS frame is read during the IO loop waiting on
1122 // the first transaction completion, and sets a maximum concurrent
1123 // stream limit of 1. This means that our IO loop exists after the
1124 // second transaction completes, so we can assert on read_index().
1125 TEST_P(SpdyNetworkTransactionTest, ThreeGetsWithMaxConcurrent) {
1126 // Construct the request.
1127 scoped_ptr<SpdyFrame> req(
1128 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
1129 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
1130 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, false));
1131 scoped_ptr<SpdyFrame> fbody(spdy_util_.ConstructSpdyBodyFrame(1, true));
1133 scoped_ptr<SpdyFrame> req2(
1134 spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, LOWEST, true));
1135 scoped_ptr<SpdyFrame> resp2(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3));
1136 scoped_ptr<SpdyFrame> body2(spdy_util_.ConstructSpdyBodyFrame(3, false));
1137 scoped_ptr<SpdyFrame> fbody2(spdy_util_.ConstructSpdyBodyFrame(3, true));
1139 scoped_ptr<SpdyFrame> req3(
1140 spdy_util_.ConstructSpdyGet(NULL, 0, false, 5, LOWEST, true));
1141 scoped_ptr<SpdyFrame> resp3(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 5));
1142 scoped_ptr<SpdyFrame> body3(spdy_util_.ConstructSpdyBodyFrame(5, false));
1143 scoped_ptr<SpdyFrame> fbody3(spdy_util_.ConstructSpdyBodyFrame(5, true));
1145 SettingsMap settings;
1146 const uint32 max_concurrent_streams = 1;
1147 settings[SETTINGS_MAX_CONCURRENT_STREAMS] =
1148 SettingsFlagsAndValue(SETTINGS_FLAG_NONE, max_concurrent_streams);
1149 scoped_ptr<SpdyFrame> settings_frame(
1150 spdy_util_.ConstructSpdySettings(settings));
1151 scoped_ptr<SpdyFrame> settings_ack(spdy_util_.ConstructSpdySettingsAck());
1153 MockWrite writes[] = {
1154 CreateMockWrite(*req, 0),
1155 CreateMockWrite(*settings_ack, 5),
1156 CreateMockWrite(*req2, 6),
1157 CreateMockWrite(*req3, 10),
1160 MockRead reads[] = {
1161 CreateMockRead(*settings_frame, 1),
1162 CreateMockRead(*resp, 2),
1163 CreateMockRead(*body, 3),
1164 CreateMockRead(*fbody, 4),
1165 CreateMockRead(*resp2, 7),
1166 CreateMockRead(*body2, 8),
1167 CreateMockRead(*fbody2, 9),
1168 CreateMockRead(*resp3, 11),
1169 CreateMockRead(*body3, 12),
1170 CreateMockRead(*fbody3, 13),
1172 MockRead(ASYNC, 0, 14), // EOF
1175 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
1177 BoundNetLog log;
1178 TransactionHelperResult out;
1180 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
1181 BoundNetLog(), GetParam(), NULL);
1182 helper.RunPreTestSetup();
1183 helper.AddData(&data);
1184 scoped_ptr<HttpNetworkTransaction> trans1(
1185 new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get()));
1186 scoped_ptr<HttpNetworkTransaction> trans2(
1187 new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get()));
1188 scoped_ptr<HttpNetworkTransaction> trans3(
1189 new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get()));
1191 TestCompletionCallback callback1;
1192 TestCompletionCallback callback2;
1193 TestCompletionCallback callback3;
1195 HttpRequestInfo httpreq1 = CreateGetRequest();
1196 HttpRequestInfo httpreq2 = CreateGetRequest();
1197 HttpRequestInfo httpreq3 = CreateGetRequest();
1199 out.rv = trans1->Start(&httpreq1, callback1.callback(), log);
1200 ASSERT_EQ(out.rv, ERR_IO_PENDING);
1201 // Run transaction 1 through quickly to force a read of our SETTINGS
1202 // frame.
1203 out.rv = callback1.WaitForResult();
1204 ASSERT_EQ(OK, out.rv);
1206 out.rv = trans2->Start(&httpreq2, callback2.callback(), log);
1207 ASSERT_EQ(out.rv, ERR_IO_PENDING);
1208 out.rv = trans3->Start(&httpreq3, callback3.callback(), log);
1209 ASSERT_EQ(out.rv, ERR_IO_PENDING);
1210 out.rv = callback2.WaitForResult();
1211 ASSERT_EQ(OK, out.rv);
1213 out.rv = callback3.WaitForResult();
1214 ASSERT_EQ(OK, out.rv);
1216 const HttpResponseInfo* response1 = trans1->GetResponseInfo();
1217 ASSERT_TRUE(response1 != NULL);
1218 EXPECT_TRUE(response1->headers.get() != NULL);
1219 EXPECT_TRUE(response1->was_fetched_via_spdy);
1220 out.status_line = response1->headers->GetStatusLine();
1221 out.response_info = *response1;
1222 out.rv = ReadTransaction(trans1.get(), &out.response_data);
1223 EXPECT_EQ(OK, out.rv);
1224 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
1225 EXPECT_EQ("hello!hello!", out.response_data);
1227 const HttpResponseInfo* response2 = trans2->GetResponseInfo();
1228 out.status_line = response2->headers->GetStatusLine();
1229 out.response_info = *response2;
1230 out.rv = ReadTransaction(trans2.get(), &out.response_data);
1231 EXPECT_EQ(OK, out.rv);
1232 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
1233 EXPECT_EQ("hello!hello!", out.response_data);
1235 const HttpResponseInfo* response3 = trans3->GetResponseInfo();
1236 out.status_line = response3->headers->GetStatusLine();
1237 out.response_info = *response3;
1238 out.rv = ReadTransaction(trans3.get(), &out.response_data);
1239 EXPECT_EQ(OK, out.rv);
1240 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
1241 EXPECT_EQ("hello!hello!", out.response_data);
1243 helper.VerifyDataConsumed();
1245 EXPECT_EQ(OK, out.rv);
1248 // Similar to ThreeGetsWithMaxConcurrent above, however this test adds
1249 // a fourth transaction. The third and fourth transactions have
1250 // different data ("hello!" vs "hello!hello!") and because of the
1251 // user specified priority, we expect to see them inverted in
1252 // the response from the server.
1253 TEST_P(SpdyNetworkTransactionTest, FourGetsWithMaxConcurrentPriority) {
1254 // Construct the request.
1255 scoped_ptr<SpdyFrame> req(
1256 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
1257 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
1258 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, false));
1259 scoped_ptr<SpdyFrame> fbody(spdy_util_.ConstructSpdyBodyFrame(1, true));
1261 scoped_ptr<SpdyFrame> req2(
1262 spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, LOWEST, true));
1263 scoped_ptr<SpdyFrame> resp2(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3));
1264 scoped_ptr<SpdyFrame> body2(spdy_util_.ConstructSpdyBodyFrame(3, false));
1265 scoped_ptr<SpdyFrame> fbody2(spdy_util_.ConstructSpdyBodyFrame(3, true));
1267 scoped_ptr<SpdyFrame> req4(
1268 spdy_util_.ConstructSpdyGet(NULL, 0, false, 5, HIGHEST, true));
1269 scoped_ptr<SpdyFrame> resp4(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 5));
1270 scoped_ptr<SpdyFrame> fbody4(spdy_util_.ConstructSpdyBodyFrame(5, true));
1272 scoped_ptr<SpdyFrame> req3(
1273 spdy_util_.ConstructSpdyGet(NULL, 0, false, 7, LOWEST, true));
1274 scoped_ptr<SpdyFrame> resp3(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 7));
1275 scoped_ptr<SpdyFrame> body3(spdy_util_.ConstructSpdyBodyFrame(7, false));
1276 scoped_ptr<SpdyFrame> fbody3(spdy_util_.ConstructSpdyBodyFrame(7, true));
1278 SettingsMap settings;
1279 const uint32 max_concurrent_streams = 1;
1280 settings[SETTINGS_MAX_CONCURRENT_STREAMS] =
1281 SettingsFlagsAndValue(SETTINGS_FLAG_NONE, max_concurrent_streams);
1282 scoped_ptr<SpdyFrame> settings_frame(
1283 spdy_util_.ConstructSpdySettings(settings));
1284 scoped_ptr<SpdyFrame> settings_ack(spdy_util_.ConstructSpdySettingsAck());
1285 MockWrite writes[] = {
1286 CreateMockWrite(*req, 0),
1287 CreateMockWrite(*settings_ack, 5),
1288 // By making these synchronous, it guarantees that they are not *started*
1289 // before their sequence number, which in turn verifies that only a single
1290 // request is in-flight at a time.
1291 CreateMockWrite(*req2, 6, SYNCHRONOUS),
1292 CreateMockWrite(*req4, 10, SYNCHRONOUS),
1293 CreateMockWrite(*req3, 13, SYNCHRONOUS),
1295 MockRead reads[] = {
1296 CreateMockRead(*settings_frame, 1),
1297 CreateMockRead(*resp, 2),
1298 CreateMockRead(*body, 3),
1299 CreateMockRead(*fbody, 4),
1300 CreateMockRead(*resp2, 7),
1301 CreateMockRead(*body2, 8),
1302 CreateMockRead(*fbody2, 9),
1303 CreateMockRead(*resp4, 11),
1304 CreateMockRead(*fbody4, 12),
1305 CreateMockRead(*resp3, 14),
1306 CreateMockRead(*body3, 15),
1307 CreateMockRead(*fbody3, 16),
1309 MockRead(ASYNC, 0, 17), // EOF
1311 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
1312 BoundNetLog log;
1313 TransactionHelperResult out;
1314 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
1315 BoundNetLog(), GetParam(), NULL);
1316 helper.RunPreTestSetup();
1317 helper.AddData(&data);
1319 scoped_ptr<HttpNetworkTransaction> trans1(
1320 new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get()));
1321 scoped_ptr<HttpNetworkTransaction> trans2(
1322 new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get()));
1323 scoped_ptr<HttpNetworkTransaction> trans3(
1324 new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get()));
1325 scoped_ptr<HttpNetworkTransaction> trans4(
1326 new HttpNetworkTransaction(HIGHEST, helper.session().get()));
1328 TestCompletionCallback callback1;
1329 TestCompletionCallback callback2;
1330 TestCompletionCallback callback3;
1331 TestCompletionCallback callback4;
1333 HttpRequestInfo httpreq1 = CreateGetRequest();
1334 HttpRequestInfo httpreq2 = CreateGetRequest();
1335 HttpRequestInfo httpreq3 = CreateGetRequest();
1336 HttpRequestInfo httpreq4 = CreateGetRequest();
1338 out.rv = trans1->Start(&httpreq1, callback1.callback(), log);
1339 ASSERT_EQ(ERR_IO_PENDING, out.rv);
1340 // Run transaction 1 through quickly to force a read of our SETTINGS frame.
1341 out.rv = callback1.WaitForResult();
1342 ASSERT_EQ(OK, out.rv);
1344 out.rv = trans2->Start(&httpreq2, callback2.callback(), log);
1345 ASSERT_EQ(ERR_IO_PENDING, out.rv);
1346 out.rv = trans3->Start(&httpreq3, callback3.callback(), log);
1347 ASSERT_EQ(ERR_IO_PENDING, out.rv);
1348 out.rv = trans4->Start(&httpreq4, callback4.callback(), log);
1349 ASSERT_EQ(ERR_IO_PENDING, out.rv);
1351 out.rv = callback2.WaitForResult();
1352 ASSERT_EQ(OK, out.rv);
1354 out.rv = callback3.WaitForResult();
1355 ASSERT_EQ(OK, out.rv);
1357 const HttpResponseInfo* response1 = trans1->GetResponseInfo();
1358 EXPECT_TRUE(response1->headers.get() != NULL);
1359 EXPECT_TRUE(response1->was_fetched_via_spdy);
1360 out.status_line = response1->headers->GetStatusLine();
1361 out.response_info = *response1;
1362 out.rv = ReadTransaction(trans1.get(), &out.response_data);
1363 EXPECT_EQ(OK, out.rv);
1364 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
1365 EXPECT_EQ("hello!hello!", out.response_data);
1367 const HttpResponseInfo* response2 = trans2->GetResponseInfo();
1368 out.status_line = response2->headers->GetStatusLine();
1369 out.response_info = *response2;
1370 out.rv = ReadTransaction(trans2.get(), &out.response_data);
1371 EXPECT_EQ(OK, out.rv);
1372 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
1373 EXPECT_EQ("hello!hello!", out.response_data);
1375 // notice: response3 gets two hellos, response4 gets one
1376 // hello, so we know dequeuing priority was respected.
1377 const HttpResponseInfo* response3 = trans3->GetResponseInfo();
1378 out.status_line = response3->headers->GetStatusLine();
1379 out.response_info = *response3;
1380 out.rv = ReadTransaction(trans3.get(), &out.response_data);
1381 EXPECT_EQ(OK, out.rv);
1382 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
1383 EXPECT_EQ("hello!hello!", out.response_data);
1385 out.rv = callback4.WaitForResult();
1386 EXPECT_EQ(OK, out.rv);
1387 const HttpResponseInfo* response4 = trans4->GetResponseInfo();
1388 out.status_line = response4->headers->GetStatusLine();
1389 out.response_info = *response4;
1390 out.rv = ReadTransaction(trans4.get(), &out.response_data);
1391 EXPECT_EQ(OK, out.rv);
1392 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
1393 EXPECT_EQ("hello!", out.response_data);
1394 helper.VerifyDataConsumed();
1395 EXPECT_EQ(OK, out.rv);
1398 // Similar to ThreeGetsMaxConcurrrent above, however, this test
1399 // deletes a session in the middle of the transaction to ensure
1400 // that we properly remove pendingcreatestream objects from
1401 // the spdy_session
1402 TEST_P(SpdyNetworkTransactionTest, ThreeGetsWithMaxConcurrentDelete) {
1403 // Construct the request.
1404 scoped_ptr<SpdyFrame> req(
1405 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
1406 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
1407 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, false));
1408 scoped_ptr<SpdyFrame> fbody(spdy_util_.ConstructSpdyBodyFrame(1, true));
1410 scoped_ptr<SpdyFrame> req2(
1411 spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, LOWEST, true));
1412 scoped_ptr<SpdyFrame> resp2(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3));
1413 scoped_ptr<SpdyFrame> body2(spdy_util_.ConstructSpdyBodyFrame(3, false));
1414 scoped_ptr<SpdyFrame> fbody2(spdy_util_.ConstructSpdyBodyFrame(3, true));
1416 SettingsMap settings;
1417 const uint32 max_concurrent_streams = 1;
1418 settings[SETTINGS_MAX_CONCURRENT_STREAMS] =
1419 SettingsFlagsAndValue(SETTINGS_FLAG_NONE, max_concurrent_streams);
1420 scoped_ptr<SpdyFrame> settings_frame(
1421 spdy_util_.ConstructSpdySettings(settings));
1422 scoped_ptr<SpdyFrame> settings_ack(spdy_util_.ConstructSpdySettingsAck());
1424 MockWrite writes[] = {
1425 CreateMockWrite(*req, 0),
1426 CreateMockWrite(*settings_ack, 5),
1427 CreateMockWrite(*req2, 6),
1429 MockRead reads[] = {
1430 CreateMockRead(*settings_frame, 1),
1431 CreateMockRead(*resp, 2),
1432 CreateMockRead(*body, 3),
1433 CreateMockRead(*fbody, 4),
1434 CreateMockRead(*resp2, 7),
1435 CreateMockRead(*body2, 8),
1436 CreateMockRead(*fbody2, 9),
1437 MockRead(ASYNC, 0, 10), // EOF
1440 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
1442 BoundNetLog log;
1443 TransactionHelperResult out;
1444 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
1445 BoundNetLog(), GetParam(), NULL);
1446 helper.RunPreTestSetup();
1447 helper.AddData(&data);
1448 scoped_ptr<HttpNetworkTransaction> trans1(
1449 new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get()));
1450 scoped_ptr<HttpNetworkTransaction> trans2(
1451 new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get()));
1452 scoped_ptr<HttpNetworkTransaction> trans3(
1453 new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get()));
1455 TestCompletionCallback callback1;
1456 TestCompletionCallback callback2;
1457 TestCompletionCallback callback3;
1459 HttpRequestInfo httpreq1 = CreateGetRequest();
1460 HttpRequestInfo httpreq2 = CreateGetRequest();
1461 HttpRequestInfo httpreq3 = CreateGetRequest();
1463 out.rv = trans1->Start(&httpreq1, callback1.callback(), log);
1464 ASSERT_EQ(out.rv, ERR_IO_PENDING);
1465 // Run transaction 1 through quickly to force a read of our SETTINGS frame.
1466 out.rv = callback1.WaitForResult();
1467 ASSERT_EQ(OK, out.rv);
1469 out.rv = trans2->Start(&httpreq2, callback2.callback(), log);
1470 ASSERT_EQ(out.rv, ERR_IO_PENDING);
1471 out.rv = trans3->Start(&httpreq3, callback3.callback(), log);
1472 delete trans3.release();
1473 ASSERT_EQ(out.rv, ERR_IO_PENDING);
1474 out.rv = callback2.WaitForResult();
1475 ASSERT_EQ(OK, out.rv);
1477 const HttpResponseInfo* response1 = trans1->GetResponseInfo();
1478 ASSERT_TRUE(response1 != NULL);
1479 EXPECT_TRUE(response1->headers.get() != NULL);
1480 EXPECT_TRUE(response1->was_fetched_via_spdy);
1481 out.status_line = response1->headers->GetStatusLine();
1482 out.response_info = *response1;
1483 out.rv = ReadTransaction(trans1.get(), &out.response_data);
1484 EXPECT_EQ(OK, out.rv);
1485 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
1486 EXPECT_EQ("hello!hello!", out.response_data);
1488 const HttpResponseInfo* response2 = trans2->GetResponseInfo();
1489 ASSERT_TRUE(response2 != NULL);
1490 out.status_line = response2->headers->GetStatusLine();
1491 out.response_info = *response2;
1492 out.rv = ReadTransaction(trans2.get(), &out.response_data);
1493 EXPECT_EQ(OK, out.rv);
1494 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
1495 EXPECT_EQ("hello!hello!", out.response_data);
1496 helper.VerifyDataConsumed();
1497 EXPECT_EQ(OK, out.rv);
1500 namespace {
1502 // The KillerCallback will delete the transaction on error as part of the
1503 // callback.
1504 class KillerCallback : public TestCompletionCallbackBase {
1505 public:
1506 explicit KillerCallback(HttpNetworkTransaction* transaction)
1507 : transaction_(transaction),
1508 callback_(base::Bind(&KillerCallback::OnComplete,
1509 base::Unretained(this))) {
1512 ~KillerCallback() override {}
1514 const CompletionCallback& callback() const { return callback_; }
1516 private:
1517 void OnComplete(int result) {
1518 if (result < 0)
1519 delete transaction_;
1521 SetResult(result);
1524 HttpNetworkTransaction* transaction_;
1525 CompletionCallback callback_;
1528 } // namespace
1530 // Similar to ThreeGetsMaxConcurrrentDelete above, however, this test
1531 // closes the socket while we have a pending transaction waiting for
1532 // a pending stream creation. http://crbug.com/52901
1533 TEST_P(SpdyNetworkTransactionTest, ThreeGetsWithMaxConcurrentSocketClose) {
1534 // Construct the request.
1535 scoped_ptr<SpdyFrame> req(
1536 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
1537 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
1538 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, false));
1539 scoped_ptr<SpdyFrame> fin_body(spdy_util_.ConstructSpdyBodyFrame(1, true));
1541 scoped_ptr<SpdyFrame> req2(
1542 spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, LOWEST, true));
1543 scoped_ptr<SpdyFrame> resp2(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3));
1545 SettingsMap settings;
1546 const uint32 max_concurrent_streams = 1;
1547 settings[SETTINGS_MAX_CONCURRENT_STREAMS] =
1548 SettingsFlagsAndValue(SETTINGS_FLAG_NONE, max_concurrent_streams);
1549 scoped_ptr<SpdyFrame> settings_frame(
1550 spdy_util_.ConstructSpdySettings(settings));
1551 scoped_ptr<SpdyFrame> settings_ack(spdy_util_.ConstructSpdySettingsAck());
1553 MockWrite writes[] = {
1554 CreateMockWrite(*req, 0),
1555 CreateMockWrite(*settings_ack, 5),
1556 CreateMockWrite(*req2, 6),
1558 MockRead reads[] = {
1559 CreateMockRead(*settings_frame, 1),
1560 CreateMockRead(*resp, 2),
1561 CreateMockRead(*body, 3),
1562 CreateMockRead(*fin_body, 4),
1563 CreateMockRead(*resp2, 7),
1564 MockRead(ASYNC, ERR_CONNECTION_RESET, 8), // Abort!
1567 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
1568 SequencedSocketData data_placeholder(NULL, 0, NULL, 0);
1570 BoundNetLog log;
1571 TransactionHelperResult out;
1572 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
1573 BoundNetLog(), GetParam(), NULL);
1574 helper.RunPreTestSetup();
1575 helper.AddData(&data);
1576 // We require placeholder data because three get requests are sent out, so
1577 // there needs to be three sets of SSL connection data.
1578 helper.AddData(&data_placeholder);
1579 helper.AddData(&data_placeholder);
1580 HttpNetworkTransaction trans1(DEFAULT_PRIORITY, helper.session().get());
1581 HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session().get());
1582 HttpNetworkTransaction* trans3(
1583 new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get()));
1585 TestCompletionCallback callback1;
1586 TestCompletionCallback callback2;
1587 KillerCallback callback3(trans3);
1589 HttpRequestInfo httpreq1 = CreateGetRequest();
1590 HttpRequestInfo httpreq2 = CreateGetRequest();
1591 HttpRequestInfo httpreq3 = CreateGetRequest();
1593 out.rv = trans1.Start(&httpreq1, callback1.callback(), log);
1594 ASSERT_EQ(out.rv, ERR_IO_PENDING);
1595 // Run transaction 1 through quickly to force a read of our SETTINGS frame.
1596 out.rv = callback1.WaitForResult();
1597 ASSERT_EQ(OK, out.rv);
1599 out.rv = trans2.Start(&httpreq2, callback2.callback(), log);
1600 ASSERT_EQ(out.rv, ERR_IO_PENDING);
1601 out.rv = trans3->Start(&httpreq3, callback3.callback(), log);
1602 ASSERT_EQ(out.rv, ERR_IO_PENDING);
1603 out.rv = callback3.WaitForResult();
1604 ASSERT_EQ(ERR_ABORTED, out.rv);
1606 const HttpResponseInfo* response1 = trans1.GetResponseInfo();
1607 ASSERT_TRUE(response1 != NULL);
1608 EXPECT_TRUE(response1->headers.get() != NULL);
1609 EXPECT_TRUE(response1->was_fetched_via_spdy);
1610 out.status_line = response1->headers->GetStatusLine();
1611 out.response_info = *response1;
1612 out.rv = ReadTransaction(&trans1, &out.response_data);
1613 EXPECT_EQ(OK, out.rv);
1615 const HttpResponseInfo* response2 = trans2.GetResponseInfo();
1616 ASSERT_TRUE(response2 != NULL);
1617 out.status_line = response2->headers->GetStatusLine();
1618 out.response_info = *response2;
1619 out.rv = ReadTransaction(&trans2, &out.response_data);
1620 EXPECT_EQ(ERR_CONNECTION_RESET, out.rv);
1622 helper.VerifyDataConsumed();
1625 // Test that a simple PUT request works.
1626 TEST_P(SpdyNetworkTransactionTest, Put) {
1627 // Setup the request
1628 HttpRequestInfo request;
1629 request.method = "PUT";
1630 request.url = GURL(GetDefaultUrl());
1632 scoped_ptr<SpdyHeaderBlock> put_headers(
1633 spdy_util_.ConstructPutHeaderBlock(GetDefaultUrl(), 0));
1634 scoped_ptr<SpdyFrame> req(
1635 spdy_util_.ConstructSpdySyn(1, *put_headers, LOWEST, false, true));
1636 MockWrite writes[] = {
1637 CreateMockWrite(*req, 0),
1640 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
1641 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
1642 MockRead reads[] = {
1643 CreateMockRead(*resp, 1),
1644 CreateMockRead(*body, 2),
1645 MockRead(ASYNC, 0, 3) // EOF
1648 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
1649 NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY,
1650 BoundNetLog(), GetParam(), NULL);
1651 helper.RunToCompletion(&data);
1652 TransactionHelperResult out = helper.output();
1654 EXPECT_EQ(OK, out.rv);
1655 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
1658 // Test that a simple HEAD request works.
1659 TEST_P(SpdyNetworkTransactionTest, Head) {
1660 // Setup the request
1661 HttpRequestInfo request;
1662 request.method = "HEAD";
1663 request.url = GURL(GetDefaultUrl());
1665 scoped_ptr<SpdyHeaderBlock> head_headers(
1666 spdy_util_.ConstructHeadHeaderBlock(GetDefaultUrl(), 0));
1667 scoped_ptr<SpdyFrame> req(
1668 spdy_util_.ConstructSpdySyn(1, *head_headers, LOWEST, false, true));
1669 MockWrite writes[] = {
1670 CreateMockWrite(*req, 0),
1673 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
1674 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
1675 MockRead reads[] = {
1676 CreateMockRead(*resp, 1),
1677 CreateMockRead(*body, 2),
1678 MockRead(ASYNC, 0, 3) // EOF
1681 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
1682 NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY,
1683 BoundNetLog(), GetParam(), NULL);
1684 helper.RunToCompletion(&data);
1685 TransactionHelperResult out = helper.output();
1687 EXPECT_EQ(OK, out.rv);
1688 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
1691 // Test that a simple POST works.
1692 TEST_P(SpdyNetworkTransactionTest, Post) {
1693 scoped_ptr<SpdyFrame> req(spdy_util_.ConstructSpdyPost(
1694 GetDefaultUrl(), 1, kUploadDataSize, LOWEST, NULL, 0));
1695 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
1696 MockWrite writes[] = {
1697 CreateMockWrite(*req, 0), CreateMockWrite(*body, 1), // POST upload frame
1700 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
1701 MockRead reads[] = {
1702 CreateMockRead(*resp, 2),
1703 CreateMockRead(*body, 3),
1704 MockRead(ASYNC, 0, 4) // EOF
1707 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
1708 NormalSpdyTransactionHelper helper(CreatePostRequest(), DEFAULT_PRIORITY,
1709 BoundNetLog(), GetParam(), NULL);
1710 helper.RunToCompletion(&data);
1711 TransactionHelperResult out = helper.output();
1712 EXPECT_EQ(OK, out.rv);
1713 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
1714 EXPECT_EQ("hello!", out.response_data);
1717 // Test that a POST with a file works.
1718 TEST_P(SpdyNetworkTransactionTest, FilePost) {
1719 scoped_ptr<SpdyFrame> req(spdy_util_.ConstructSpdyPost(
1720 GetDefaultUrl(), 1, kUploadDataSize, LOWEST, NULL, 0));
1721 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
1722 MockWrite writes[] = {
1723 CreateMockWrite(*req, 0), CreateMockWrite(*body, 1), // POST upload frame
1726 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
1727 MockRead reads[] = {
1728 CreateMockRead(*resp, 2),
1729 CreateMockRead(*body, 3),
1730 MockRead(ASYNC, 0, 4) // EOF
1733 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
1734 NormalSpdyTransactionHelper helper(CreateFilePostRequest(), DEFAULT_PRIORITY,
1735 BoundNetLog(), GetParam(), NULL);
1736 helper.RunToCompletion(&data);
1737 TransactionHelperResult out = helper.output();
1738 EXPECT_EQ(OK, out.rv);
1739 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
1740 EXPECT_EQ("hello!", out.response_data);
1743 // Test that a POST with a unreadable file fails.
1744 TEST_P(SpdyNetworkTransactionTest, UnreadableFilePost) {
1745 MockWrite writes[] = {
1746 MockWrite(ASYNC, 0, 0) // EOF
1748 MockRead reads[] = {
1749 MockRead(ASYNC, 0, 1) // EOF
1752 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
1753 NormalSpdyTransactionHelper helper(CreateUnreadableFilePostRequest(),
1754 DEFAULT_PRIORITY,
1755 BoundNetLog(), GetParam(), NULL);
1756 helper.RunPreTestSetup();
1757 helper.AddData(&data);
1758 helper.RunDefaultTest();
1760 base::RunLoop().RunUntilIdle();
1761 helper.VerifyDataNotConsumed();
1762 EXPECT_EQ(ERR_ACCESS_DENIED, helper.output().rv);
1765 // Test that a complex POST works.
1766 TEST_P(SpdyNetworkTransactionTest, ComplexPost) {
1767 scoped_ptr<SpdyFrame> req(spdy_util_.ConstructSpdyPost(
1768 GetDefaultUrl(), 1, kUploadDataSize, LOWEST, NULL, 0));
1769 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
1770 MockWrite writes[] = {
1771 CreateMockWrite(*req, 0), CreateMockWrite(*body, 1), // POST upload frame
1774 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
1775 MockRead reads[] = {
1776 CreateMockRead(*resp, 2),
1777 CreateMockRead(*body, 3),
1778 MockRead(ASYNC, 0, 4) // EOF
1781 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
1782 NormalSpdyTransactionHelper helper(CreateComplexPostRequest(),
1783 DEFAULT_PRIORITY,
1784 BoundNetLog(), GetParam(), NULL);
1785 helper.RunToCompletion(&data);
1786 TransactionHelperResult out = helper.output();
1787 EXPECT_EQ(OK, out.rv);
1788 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
1789 EXPECT_EQ("hello!", out.response_data);
1792 // Test that a chunked POST works.
1793 TEST_P(SpdyNetworkTransactionTest, ChunkedPost) {
1794 scoped_ptr<SpdyFrame> req(spdy_util_.ConstructChunkedSpdyPost(NULL, 0));
1795 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
1796 MockWrite writes[] = {
1797 CreateMockWrite(*req, 0), CreateMockWrite(*body, 1),
1800 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
1801 MockRead reads[] = {
1802 CreateMockRead(*resp, 2),
1803 CreateMockRead(*body, 3),
1804 MockRead(ASYNC, 0, 4) // EOF
1807 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
1808 NormalSpdyTransactionHelper helper(CreateChunkedPostRequest(),
1809 DEFAULT_PRIORITY,
1810 BoundNetLog(), GetParam(), NULL);
1812 // These chunks get merged into a single frame when being sent.
1813 const int kFirstChunkSize = kUploadDataSize/2;
1814 upload_chunked_data_stream()->AppendData(kUploadData, kFirstChunkSize, false);
1815 upload_chunked_data_stream()->AppendData(
1816 kUploadData + kFirstChunkSize, kUploadDataSize - kFirstChunkSize, true);
1818 helper.RunToCompletion(&data);
1819 TransactionHelperResult out = helper.output();
1820 EXPECT_EQ(OK, out.rv);
1821 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
1822 EXPECT_EQ(kUploadData, out.response_data);
1825 // Test that a chunked POST works with chunks appended after transaction starts.
1826 TEST_P(SpdyNetworkTransactionTest, DelayedChunkedPost) {
1827 scoped_ptr<SpdyFrame> req(spdy_util_.ConstructChunkedSpdyPost(NULL, 0));
1828 scoped_ptr<SpdyFrame> chunk1(spdy_util_.ConstructSpdyBodyFrame(1, false));
1829 scoped_ptr<SpdyFrame> chunk2(spdy_util_.ConstructSpdyBodyFrame(1, false));
1830 scoped_ptr<SpdyFrame> chunk3(spdy_util_.ConstructSpdyBodyFrame(1, true));
1831 MockWrite writes[] = {
1832 CreateMockWrite(*req, 0),
1833 CreateMockWrite(*chunk1, 1),
1834 CreateMockWrite(*chunk2, 2),
1835 CreateMockWrite(*chunk3, 3),
1838 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
1839 MockRead reads[] = {
1840 CreateMockRead(*resp, 4),
1841 CreateMockRead(*chunk1, 5),
1842 CreateMockRead(*chunk2, 6),
1843 CreateMockRead(*chunk3, 7),
1844 MockRead(ASYNC, 0, 8) // EOF
1847 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
1848 NormalSpdyTransactionHelper helper(CreateChunkedPostRequest(),
1849 DEFAULT_PRIORITY,
1850 BoundNetLog(), GetParam(), NULL);
1852 upload_chunked_data_stream()->AppendData(kUploadData, kUploadDataSize, false);
1854 helper.RunPreTestSetup();
1855 helper.AddData(&data);
1856 ASSERT_TRUE(helper.StartDefaultTest());
1858 base::RunLoop().RunUntilIdle();
1859 upload_chunked_data_stream()->AppendData(kUploadData, kUploadDataSize, false);
1860 base::RunLoop().RunUntilIdle();
1861 upload_chunked_data_stream()->AppendData(kUploadData, kUploadDataSize, true);
1863 helper.FinishDefaultTest();
1864 helper.VerifyDataConsumed();
1866 std::string expected_response;
1867 expected_response += kUploadData;
1868 expected_response += kUploadData;
1869 expected_response += kUploadData;
1871 TransactionHelperResult out = helper.output();
1872 EXPECT_EQ(OK, out.rv);
1873 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
1874 EXPECT_EQ(expected_response, out.response_data);
1877 // Test that a POST without any post data works.
1878 TEST_P(SpdyNetworkTransactionTest, NullPost) {
1879 BufferedSpdyFramer framer(spdy_util_.spdy_version(), false);
1880 // Setup the request
1881 HttpRequestInfo request;
1882 request.method = "POST";
1883 request.url = GURL(GetDefaultUrl());
1884 // Create an empty UploadData.
1885 request.upload_data_stream = NULL;
1887 // When request.upload_data_stream is NULL for post, content-length is
1888 // expected to be 0.
1889 scoped_ptr<SpdyHeaderBlock> req_block(
1890 spdy_util_.ConstructPostHeaderBlock(GetDefaultUrl(), 0));
1891 scoped_ptr<SpdyFrame> req(
1892 spdy_util_.ConstructSpdySyn(1, *req_block, LOWEST, false, true));
1894 MockWrite writes[] = {
1895 CreateMockWrite(*req, 0),
1898 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
1899 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
1900 MockRead reads[] = {
1901 CreateMockRead(*resp, 1),
1902 CreateMockRead(*body, 2),
1903 MockRead(ASYNC, 0, 3) // EOF
1906 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
1908 NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY,
1909 BoundNetLog(), GetParam(), NULL);
1910 helper.RunToCompletion(&data);
1911 TransactionHelperResult out = helper.output();
1912 EXPECT_EQ(OK, out.rv);
1913 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
1914 EXPECT_EQ("hello!", out.response_data);
1917 // Test that a simple POST works.
1918 TEST_P(SpdyNetworkTransactionTest, EmptyPost) {
1919 BufferedSpdyFramer framer(spdy_util_.spdy_version(), false);
1920 // Create an empty UploadDataStream.
1921 ScopedVector<UploadElementReader> element_readers;
1922 ElementsUploadDataStream stream(element_readers.Pass(), 0);
1924 // Setup the request
1925 HttpRequestInfo request;
1926 request.method = "POST";
1927 request.url = GURL(GetDefaultUrl());
1928 request.upload_data_stream = &stream;
1930 const uint64 kContentLength = 0;
1932 scoped_ptr<SpdyHeaderBlock> req_block(
1933 spdy_util_.ConstructPostHeaderBlock(GetDefaultUrl(), kContentLength));
1934 scoped_ptr<SpdyFrame> req(
1935 spdy_util_.ConstructSpdySyn(1, *req_block, LOWEST, false, true));
1937 MockWrite writes[] = {
1938 CreateMockWrite(*req, 0),
1941 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
1942 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
1943 MockRead reads[] = {
1944 CreateMockRead(*resp, 1),
1945 CreateMockRead(*body, 2),
1946 MockRead(ASYNC, 0, 3) // EOF
1949 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
1951 NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY,
1952 BoundNetLog(), GetParam(), NULL);
1953 helper.RunToCompletion(&data);
1954 TransactionHelperResult out = helper.output();
1955 EXPECT_EQ(OK, out.rv);
1956 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
1957 EXPECT_EQ("hello!", out.response_data);
1960 // While we're doing a post, the server sends the reply before upload completes.
1961 TEST_P(SpdyNetworkTransactionTest, ResponseBeforePostCompletes) {
1962 scoped_ptr<SpdyFrame> req(spdy_util_.ConstructChunkedSpdyPost(NULL, 0));
1963 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
1964 MockWrite writes[] = {
1965 CreateMockWrite(*req, 0),
1966 CreateMockWrite(*body, 3),
1968 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
1969 MockRead reads[] = {
1970 CreateMockRead(*resp, 1),
1971 CreateMockRead(*body, 2),
1972 MockRead(ASYNC, 0, 4) // EOF
1975 // Write the request headers, and read the complete response
1976 // while still waiting for chunked request data.
1977 DeterministicSocketData data(reads, arraysize(reads),
1978 writes, arraysize(writes));
1979 NormalSpdyTransactionHelper helper(CreateChunkedPostRequest(),
1980 DEFAULT_PRIORITY,
1981 BoundNetLog(), GetParam(), NULL);
1982 helper.SetDeterministic();
1983 helper.RunPreTestSetup();
1984 helper.AddDeterministicData(&data);
1986 ASSERT_TRUE(helper.StartDefaultTest());
1988 // Process the request headers, SYN_REPLY, and response body.
1989 // The request body is still in flight.
1990 data.RunFor(3);
1992 const HttpResponseInfo* response = helper.trans()->GetResponseInfo();
1993 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
1995 // Finish sending the request body.
1996 upload_chunked_data_stream()->AppendData(kUploadData, kUploadDataSize, true);
1997 data.RunFor(2);
1999 std::string response_body;
2000 EXPECT_EQ(OK, ReadTransaction(helper.trans(), &response_body));
2001 EXPECT_EQ(kUploadData, response_body);
2002 helper.VerifyDataConsumed();
2005 // The client upon cancellation tries to send a RST_STREAM frame. The mock
2006 // socket causes the TCP write to return zero. This test checks that the client
2007 // tries to queue up the RST_STREAM frame again.
2008 TEST_P(SpdyNetworkTransactionTest, SocketWriteReturnsZero) {
2009 scoped_ptr<SpdyFrame> req(
2010 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
2011 scoped_ptr<SpdyFrame> rst(
2012 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL));
2013 MockWrite writes[] = {
2014 CreateMockWrite(*req.get(), 0, SYNCHRONOUS),
2015 MockWrite(SYNCHRONOUS, 0, 0, 2),
2016 CreateMockWrite(*rst.get(), 3, SYNCHRONOUS),
2019 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
2020 MockRead reads[] = {
2021 CreateMockRead(*resp.get(), 1, ASYNC),
2022 MockRead(ASYNC, 0, 0, 4) // EOF
2025 DeterministicSocketData data(reads, arraysize(reads),
2026 writes, arraysize(writes));
2027 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
2028 BoundNetLog(), GetParam(), NULL);
2029 helper.SetDeterministic();
2030 helper.RunPreTestSetup();
2031 helper.AddDeterministicData(&data);
2032 HttpNetworkTransaction* trans = helper.trans();
2034 TestCompletionCallback callback;
2035 int rv = trans->Start(
2036 &CreateGetRequest(), callback.callback(), BoundNetLog());
2037 EXPECT_EQ(ERR_IO_PENDING, rv);
2039 data.SetStop(2);
2040 data.Run();
2041 helper.ResetTrans();
2042 data.SetStop(20);
2043 data.Run();
2045 helper.VerifyDataConsumed();
2048 // Test that the transaction doesn't crash when we don't have a reply.
2049 TEST_P(SpdyNetworkTransactionTest, ResponseWithoutSynReply) {
2050 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
2051 MockRead reads[] = {
2052 CreateMockRead(*body, 1), MockRead(ASYNC, 0, 3) // EOF
2055 scoped_ptr<SpdyFrame> req(
2056 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
2057 scoped_ptr<SpdyFrame> rst(
2058 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR));
2059 MockWrite writes[] = {
2060 CreateMockWrite(*req, 0), CreateMockWrite(*rst, 2),
2062 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
2063 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
2064 BoundNetLog(), GetParam(), NULL);
2065 helper.RunToCompletion(&data);
2066 TransactionHelperResult out = helper.output();
2067 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, out.rv);
2070 // Test that the transaction doesn't crash when we get two replies on the same
2071 // stream ID. See http://crbug.com/45639.
2072 TEST_P(SpdyNetworkTransactionTest, ResponseWithTwoSynReplies) {
2073 scoped_ptr<SpdyFrame> req(
2074 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
2075 scoped_ptr<SpdyFrame> rst(
2076 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR));
2077 MockWrite writes[] = {
2078 CreateMockWrite(*req, 0), CreateMockWrite(*rst, 4),
2081 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
2082 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
2083 MockRead reads[] = {
2084 CreateMockRead(*resp, 1),
2085 CreateMockRead(*resp, 2),
2086 CreateMockRead(*body, 3),
2087 MockRead(ASYNC, 0, 5) // EOF
2090 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
2092 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
2093 BoundNetLog(), GetParam(), NULL);
2094 helper.RunPreTestSetup();
2095 helper.AddData(&data);
2097 HttpNetworkTransaction* trans = helper.trans();
2099 TestCompletionCallback callback;
2100 int rv = trans->Start(&helper.request(), callback.callback(), BoundNetLog());
2101 EXPECT_EQ(ERR_IO_PENDING, rv);
2102 rv = callback.WaitForResult();
2103 EXPECT_EQ(OK, rv);
2105 const HttpResponseInfo* response = trans->GetResponseInfo();
2106 ASSERT_TRUE(response != NULL);
2107 EXPECT_TRUE(response->headers.get() != NULL);
2108 EXPECT_TRUE(response->was_fetched_via_spdy);
2109 std::string response_data;
2110 rv = ReadTransaction(trans, &response_data);
2111 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, rv);
2113 helper.VerifyDataConsumed();
2116 TEST_P(SpdyNetworkTransactionTest, ResetReplyWithTransferEncoding) {
2117 // Construct the request.
2118 scoped_ptr<SpdyFrame> req(
2119 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
2120 scoped_ptr<SpdyFrame> rst(
2121 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR));
2122 MockWrite writes[] = {
2123 CreateMockWrite(*req, 0), CreateMockWrite(*rst, 2),
2126 const char* const headers[] = {
2127 "transfer-encoding", "chunked"
2129 scoped_ptr<SpdyFrame> resp(
2130 spdy_util_.ConstructSpdyGetSynReply(headers, 1, 1));
2131 scoped_ptr<SpdyFrame> body(
2132 spdy_util_.ConstructSpdyBodyFrame(1, true));
2133 MockRead reads[] = {
2134 CreateMockRead(*resp, 1),
2135 CreateMockRead(*body, 3),
2136 MockRead(ASYNC, 0, 4) // EOF
2139 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
2140 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
2141 BoundNetLog(), GetParam(), NULL);
2142 helper.RunToCompletion(&data);
2143 TransactionHelperResult out = helper.output();
2144 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, out.rv);
2146 helper.session()->spdy_session_pool()->CloseAllSessions();
2147 helper.VerifyDataConsumed();
2150 TEST_P(SpdyNetworkTransactionTest, ResetPushWithTransferEncoding) {
2151 // Construct the request.
2152 scoped_ptr<SpdyFrame> req(
2153 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
2154 scoped_ptr<SpdyFrame> rst(
2155 spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR));
2156 MockWrite writes[] = {
2157 CreateMockWrite(*req, 0), CreateMockWrite(*rst, 4),
2160 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
2161 const char* const headers[] = {
2162 "transfer-encoding", "chunked"
2164 scoped_ptr<SpdyFrame> push(
2165 spdy_util_.ConstructSpdyPush(headers, arraysize(headers) / 2, 2, 1,
2166 GetDefaultUrlWithPath("/1").c_str()));
2167 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
2168 MockRead reads[] = {
2169 CreateMockRead(*resp, 1),
2170 CreateMockRead(*push, 2),
2171 CreateMockRead(*body, 3),
2172 MockRead(ASYNC, 0, 5) // EOF
2175 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
2176 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
2177 BoundNetLog(), GetParam(), NULL);
2178 helper.RunToCompletion(&data);
2179 TransactionHelperResult out = helper.output();
2180 EXPECT_EQ(OK, out.rv);
2181 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
2182 EXPECT_EQ("hello!", out.response_data);
2184 helper.session()->spdy_session_pool()->CloseAllSessions();
2185 helper.VerifyDataConsumed();
2188 TEST_P(SpdyNetworkTransactionTest, CancelledTransaction) {
2189 // Construct the request.
2190 scoped_ptr<SpdyFrame> req(
2191 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
2192 MockWrite writes[] = {
2193 CreateMockWrite(*req),
2196 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
2197 MockRead reads[] = {
2198 CreateMockRead(*resp),
2199 // This following read isn't used by the test, except during the
2200 // RunUntilIdle() call at the end since the SpdySession survives the
2201 // HttpNetworkTransaction and still tries to continue Read()'ing. Any
2202 // MockRead will do here.
2203 MockRead(ASYNC, 0, 0) // EOF
2206 StaticSocketDataProvider data(reads, arraysize(reads),
2207 writes, arraysize(writes));
2209 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
2210 BoundNetLog(), GetParam(), NULL);
2211 helper.RunPreTestSetup();
2212 helper.AddData(&data);
2213 HttpNetworkTransaction* trans = helper.trans();
2215 TestCompletionCallback callback;
2216 int rv = trans->Start(
2217 &CreateGetRequest(), callback.callback(), BoundNetLog());
2218 EXPECT_EQ(ERR_IO_PENDING, rv);
2219 helper.ResetTrans(); // Cancel the transaction.
2221 // Flush the MessageLoop while the SpdySessionDependencies (in particular, the
2222 // MockClientSocketFactory) are still alive.
2223 base::RunLoop().RunUntilIdle();
2224 helper.VerifyDataNotConsumed();
2227 // Verify that the client sends a Rst Frame upon cancelling the stream.
2228 TEST_P(SpdyNetworkTransactionTest, CancelledTransactionSendRst) {
2229 scoped_ptr<SpdyFrame> req(
2230 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
2231 scoped_ptr<SpdyFrame> rst(
2232 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL));
2233 MockWrite writes[] = {
2234 CreateMockWrite(*req, 0, SYNCHRONOUS),
2235 CreateMockWrite(*rst, 2, SYNCHRONOUS),
2238 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
2239 MockRead reads[] = {
2240 CreateMockRead(*resp, 1, ASYNC),
2241 MockRead(ASYNC, 0, 0, 3) // EOF
2244 DeterministicSocketData data(reads, arraysize(reads),
2245 writes, arraysize(writes));
2247 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
2248 BoundNetLog(),
2249 GetParam(), NULL);
2250 helper.SetDeterministic();
2251 helper.RunPreTestSetup();
2252 helper.AddDeterministicData(&data);
2253 HttpNetworkTransaction* trans = helper.trans();
2255 TestCompletionCallback callback;
2257 int rv = trans->Start(
2258 &CreateGetRequest(), callback.callback(), BoundNetLog());
2259 EXPECT_EQ(ERR_IO_PENDING, rv);
2261 data.SetStop(2);
2262 data.Run();
2263 helper.ResetTrans();
2264 data.SetStop(20);
2265 data.Run();
2267 helper.VerifyDataConsumed();
2270 // Verify that the client can correctly deal with the user callback attempting
2271 // to start another transaction on a session that is closing down. See
2272 // http://crbug.com/47455
2273 TEST_P(SpdyNetworkTransactionTest, StartTransactionOnReadCallback) {
2274 scoped_ptr<SpdyFrame> req(
2275 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
2276 MockWrite writes[] = {CreateMockWrite(*req)};
2277 MockWrite writes2[] = {CreateMockWrite(*req, 0)};
2279 // The indicated length of this frame is longer than its actual length. When
2280 // the session receives an empty frame after this one, it shuts down the
2281 // session, and calls the read callback with the incomplete data.
2282 const uint8 kGetBodyFrame2[] = {
2283 0x00, 0x00, 0x00, 0x01,
2284 0x01, 0x00, 0x00, 0x07,
2285 'h', 'e', 'l', 'l', 'o', '!',
2288 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
2289 MockRead reads[] = {
2290 CreateMockRead(*resp, 1),
2291 MockRead(ASYNC, ERR_IO_PENDING, 2), // Force a pause
2292 MockRead(ASYNC, reinterpret_cast<const char*>(kGetBodyFrame2),
2293 arraysize(kGetBodyFrame2), 3),
2294 MockRead(ASYNC, ERR_IO_PENDING, 4), // Force a pause
2295 MockRead(ASYNC, 0, 0, 5), // EOF
2297 MockRead reads2[] = {
2298 CreateMockRead(*resp, 1), MockRead(ASYNC, 0, 0, 2), // EOF
2301 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
2302 SequencedSocketData data2(reads2, arraysize(reads2), writes2,
2303 arraysize(writes2));
2305 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
2306 BoundNetLog(), GetParam(), NULL);
2307 helper.RunPreTestSetup();
2308 helper.AddData(&data);
2309 helper.AddData(&data2);
2310 HttpNetworkTransaction* trans = helper.trans();
2312 // Start the transaction with basic parameters.
2313 TestCompletionCallback callback;
2314 int rv = trans->Start(&helper.request(), callback.callback(), BoundNetLog());
2315 EXPECT_EQ(ERR_IO_PENDING, rv);
2316 rv = callback.WaitForResult();
2318 const int kSize = 3000;
2319 scoped_refptr<IOBuffer> buf(new IOBuffer(kSize));
2320 rv = trans->Read(
2321 buf.get(), kSize,
2322 base::Bind(&SpdyNetworkTransactionTest::StartTransactionCallback,
2323 helper.session(), GURL(GetDefaultUrl())));
2324 ASSERT_EQ(ERR_IO_PENDING, rv);
2325 // This forces an err_IO_pending, which sets the callback.
2326 data.CompleteRead();
2327 // This finishes the read.
2328 data.CompleteRead();
2329 helper.VerifyDataConsumed();
2332 // Verify that the client can correctly deal with the user callback deleting the
2333 // transaction. Failures will usually be valgrind errors. See
2334 // http://crbug.com/46925
2335 TEST_P(SpdyNetworkTransactionTest, DeleteSessionOnReadCallback) {
2336 scoped_ptr<SpdyFrame> req(
2337 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
2338 MockWrite writes[] = {CreateMockWrite(*req, 0)};
2340 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
2341 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
2342 MockRead reads[] = {
2343 CreateMockRead(*resp.get(), 1),
2344 MockRead(ASYNC, ERR_IO_PENDING, 2), // Force a pause
2345 CreateMockRead(*body.get(), 3),
2346 MockRead(ASYNC, 0, 0, 4), // EOF
2349 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
2351 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
2352 BoundNetLog(), GetParam(), NULL);
2353 helper.RunPreTestSetup();
2354 helper.AddData(&data);
2355 HttpNetworkTransaction* trans = helper.trans();
2357 // Start the transaction with basic parameters.
2358 TestCompletionCallback callback;
2359 int rv = trans->Start(&helper.request(), callback.callback(), BoundNetLog());
2360 EXPECT_EQ(ERR_IO_PENDING, rv);
2361 rv = callback.WaitForResult();
2363 // Setup a user callback which will delete the session, and clear out the
2364 // memory holding the stream object. Note that the callback deletes trans.
2365 const int kSize = 3000;
2366 scoped_refptr<IOBuffer> buf(new IOBuffer(kSize));
2367 rv = trans->Read(
2368 buf.get(),
2369 kSize,
2370 base::Bind(&SpdyNetworkTransactionTest::DeleteSessionCallback,
2371 base::Unretained(&helper)));
2372 ASSERT_EQ(ERR_IO_PENDING, rv);
2373 data.CompleteRead();
2375 // Finish running rest of tasks.
2376 base::RunLoop().RunUntilIdle();
2377 helper.VerifyDataConsumed();
2380 // Send a spdy request to www.example.org that gets redirected to www.foo.com.
2381 TEST_P(SpdyNetworkTransactionTest, DISABLED_RedirectGetRequest) {
2382 scoped_ptr<SpdyHeaderBlock> headers(
2383 spdy_util_.ConstructGetHeaderBlock(GetDefaultUrl()));
2384 (*headers)["user-agent"] = "";
2385 (*headers)["accept-encoding"] = "gzip, deflate";
2386 scoped_ptr<SpdyHeaderBlock> headers2(
2387 spdy_util_.ConstructGetHeaderBlock("http://www.foo.com/index.php"));
2388 (*headers2)["user-agent"] = "";
2389 (*headers2)["accept-encoding"] = "gzip, deflate";
2391 // Setup writes/reads to www.example.org
2392 scoped_ptr<SpdyFrame> req(
2393 spdy_util_.ConstructSpdySyn(1, *headers, LOWEST, false, true));
2394 scoped_ptr<SpdyFrame> req2(
2395 spdy_util_.ConstructSpdySyn(1, *headers2, LOWEST, false, true));
2396 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReplyRedirect(1));
2397 MockWrite writes[] = {
2398 CreateMockWrite(*req, 1),
2400 MockRead reads[] = {
2401 CreateMockRead(*resp, 2),
2402 MockRead(ASYNC, 0, 0, 3) // EOF
2405 // Setup writes/reads to www.foo.com
2406 scoped_ptr<SpdyFrame> resp2(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
2407 scoped_ptr<SpdyFrame> body2(spdy_util_.ConstructSpdyBodyFrame(1, true));
2408 MockWrite writes2[] = {
2409 CreateMockWrite(*req2, 1),
2411 MockRead reads2[] = {
2412 CreateMockRead(*resp2, 2),
2413 CreateMockRead(*body2, 3),
2414 MockRead(ASYNC, 0, 0, 4) // EOF
2416 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
2417 SequencedSocketData data2(reads2, arraysize(reads2), writes2,
2418 arraysize(writes2));
2420 // TODO(erikchen): Make test support SPDYSSL, SPDYNPN
2421 TestDelegate d;
2423 SpdyURLRequestContext spdy_url_request_context(GetParam().protocol);
2424 scoped_ptr<URLRequest> r(spdy_url_request_context.CreateRequest(
2425 GURL(GetDefaultUrl()), DEFAULT_PRIORITY, &d));
2426 spdy_url_request_context.socket_factory().
2427 AddSocketDataProvider(&data);
2428 spdy_url_request_context.socket_factory().
2429 AddSocketDataProvider(&data2);
2431 d.set_quit_on_redirect(true);
2432 r->Start();
2433 base::RunLoop().Run();
2435 EXPECT_EQ(1, d.received_redirect_count());
2437 r->FollowDeferredRedirect();
2438 base::RunLoop().Run();
2439 EXPECT_EQ(1, d.response_started_count());
2440 EXPECT_FALSE(d.received_data_before_response());
2441 EXPECT_EQ(URLRequestStatus::SUCCESS, r->status().status());
2442 std::string contents("hello!");
2443 EXPECT_EQ(contents, d.data_received());
2445 EXPECT_TRUE(data.AllReadDataConsumed());
2446 EXPECT_TRUE(data.AllWriteDataConsumed());
2447 EXPECT_TRUE(data2.AllReadDataConsumed());
2448 EXPECT_TRUE(data2.AllWriteDataConsumed());
2451 // Send a spdy request to www.example.org. Get a pushed stream that redirects to
2452 // www.foo.com.
2453 TEST_P(SpdyNetworkTransactionTest, DISABLED_RedirectServerPush) {
2454 scoped_ptr<SpdyHeaderBlock> headers(
2455 spdy_util_.ConstructGetHeaderBlock(GetDefaultUrl()));
2456 (*headers)["user-agent"] = "";
2457 (*headers)["accept-encoding"] = "gzip, deflate";
2459 // Setup writes/reads to www.example.org
2460 scoped_ptr<SpdyFrame> req(
2461 spdy_util_.ConstructSpdySyn(1, *headers, LOWEST, false, true));
2462 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
2463 scoped_ptr<SpdyFrame> rep(spdy_util_.ConstructSpdyPush(
2464 NULL, 0, 2, 1, GetDefaultUrlWithPath("/foo.dat").c_str(),
2465 "301 Moved Permanently", "http://www.foo.com/index.php"));
2466 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
2467 scoped_ptr<SpdyFrame> rst(
2468 spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_CANCEL));
2469 MockWrite writes[] = {
2470 CreateMockWrite(*req, 1),
2471 CreateMockWrite(*rst, 6),
2473 MockRead reads[] = {
2474 CreateMockRead(*resp, 2),
2475 CreateMockRead(*rep, 3),
2476 CreateMockRead(*body, 4),
2477 MockRead(ASYNC, ERR_IO_PENDING, 5), // Force a pause
2478 MockRead(ASYNC, 0, 0, 7) // EOF
2481 // Setup writes/reads to www.foo.com
2482 scoped_ptr<SpdyHeaderBlock> headers2(
2483 spdy_util_.ConstructGetHeaderBlock("http://www.foo.com/index.php"));
2484 (*headers2)["user-agent"] = "";
2485 (*headers2)["accept-encoding"] = "gzip, deflate";
2486 scoped_ptr<SpdyFrame> req2(
2487 spdy_util_.ConstructSpdySyn(1, *headers2, LOWEST, false, true));
2488 scoped_ptr<SpdyFrame> resp2(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
2489 scoped_ptr<SpdyFrame> body2(spdy_util_.ConstructSpdyBodyFrame(1, true));
2490 MockWrite writes2[] = {
2491 CreateMockWrite(*req2, 1),
2493 MockRead reads2[] = {
2494 CreateMockRead(*resp2, 2),
2495 CreateMockRead(*body2, 3),
2496 MockRead(ASYNC, 0, 0, 5) // EOF
2498 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
2499 SequencedSocketData data2(reads2, arraysize(reads2), writes2,
2500 arraysize(writes2));
2502 // TODO(erikchen): Make test support SPDYSSL, SPDYNPN
2503 TestDelegate d;
2504 TestDelegate d2;
2505 SpdyURLRequestContext spdy_url_request_context(GetParam().protocol);
2507 scoped_ptr<URLRequest> r(spdy_url_request_context.CreateRequest(
2508 GURL(GetDefaultUrl()), DEFAULT_PRIORITY, &d));
2509 spdy_url_request_context.socket_factory().
2510 AddSocketDataProvider(&data);
2512 r->Start();
2513 base::RunLoop().Run();
2515 EXPECT_EQ(0, d.received_redirect_count());
2516 std::string contents("hello!");
2517 EXPECT_EQ(contents, d.data_received());
2519 scoped_ptr<URLRequest> r2(spdy_url_request_context.CreateRequest(
2520 GURL(GetDefaultUrlWithPath("/foo.dat")), DEFAULT_PRIORITY, &d2));
2521 spdy_url_request_context.socket_factory().
2522 AddSocketDataProvider(&data2);
2524 d2.set_quit_on_redirect(true);
2525 r2->Start();
2526 base::RunLoop().Run();
2527 EXPECT_EQ(1, d2.received_redirect_count());
2529 r2->FollowDeferredRedirect();
2530 base::RunLoop().Run();
2531 EXPECT_EQ(1, d2.response_started_count());
2532 EXPECT_FALSE(d2.received_data_before_response());
2533 EXPECT_EQ(URLRequestStatus::SUCCESS, r2->status().status());
2534 std::string contents2("hello!");
2535 EXPECT_EQ(contents2, d2.data_received());
2537 EXPECT_TRUE(data.AllReadDataConsumed());
2538 EXPECT_TRUE(data.AllWriteDataConsumed());
2539 EXPECT_TRUE(data2.AllReadDataConsumed());
2540 EXPECT_TRUE(data2.AllWriteDataConsumed());
2543 TEST_P(SpdyNetworkTransactionTest, ServerPushSingleDataFrame) {
2544 scoped_ptr<SpdyFrame> stream1_syn(
2545 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
2546 scoped_ptr<SpdyFrame> stream1_body(
2547 spdy_util_.ConstructSpdyBodyFrame(1, true));
2548 MockWrite writes[] = {
2549 CreateMockWrite(*stream1_syn, 0),
2552 scoped_ptr<SpdyFrame>
2553 stream1_reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
2554 scoped_ptr<SpdyFrame> stream2_syn(spdy_util_.ConstructSpdyPush(
2555 NULL, 0, 2, 1, GetDefaultUrlWithPath("/foo.dat").c_str()));
2556 const char kPushedData[] = "pushed";
2557 scoped_ptr<SpdyFrame> stream2_body(
2558 spdy_util_.ConstructSpdyBodyFrame(
2559 2, kPushedData, strlen(kPushedData), true));
2560 MockRead reads[] = {
2561 CreateMockRead(*stream1_reply, 1),
2562 CreateMockRead(*stream2_syn, 2),
2563 CreateMockRead(*stream1_body, 3, SYNCHRONOUS),
2564 CreateMockRead(*stream2_body, 4),
2565 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 5), // Force a pause
2568 HttpResponseInfo response;
2569 HttpResponseInfo response2;
2570 std::string expected_push_result("pushed");
2571 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
2572 RunServerPushTest(&data,
2573 &response,
2574 &response2,
2575 expected_push_result);
2577 // Verify the SYN_REPLY.
2578 EXPECT_TRUE(response.headers.get() != NULL);
2579 EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine());
2581 // Verify the pushed stream.
2582 EXPECT_TRUE(response2.headers.get() != NULL);
2583 EXPECT_EQ("HTTP/1.1 200 OK", response2.headers->GetStatusLine());
2586 TEST_P(SpdyNetworkTransactionTest, ServerPushBeforeSynReply) {
2587 scoped_ptr<SpdyFrame> stream1_syn(
2588 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
2589 scoped_ptr<SpdyFrame> stream1_body(
2590 spdy_util_.ConstructSpdyBodyFrame(1, true));
2591 MockWrite writes[] = {
2592 CreateMockWrite(*stream1_syn, 0),
2595 scoped_ptr<SpdyFrame>
2596 stream1_reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
2597 scoped_ptr<SpdyFrame> stream2_syn(spdy_util_.ConstructSpdyPush(
2598 NULL, 0, 2, 1, GetDefaultUrlWithPath("/foo.dat").c_str()));
2599 const char kPushedData[] = "pushed";
2600 scoped_ptr<SpdyFrame> stream2_body(
2601 spdy_util_.ConstructSpdyBodyFrame(
2602 2, kPushedData, strlen(kPushedData), true));
2603 MockRead reads[] = {
2604 CreateMockRead(*stream2_syn, 1),
2605 CreateMockRead(*stream1_reply, 2),
2606 CreateMockRead(*stream1_body, 3, SYNCHRONOUS),
2607 CreateMockRead(*stream2_body, 4),
2608 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 5), // Force a pause
2611 HttpResponseInfo response;
2612 HttpResponseInfo response2;
2613 std::string expected_push_result("pushed");
2614 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
2615 RunServerPushTest(&data,
2616 &response,
2617 &response2,
2618 expected_push_result);
2620 // Verify the SYN_REPLY.
2621 EXPECT_TRUE(response.headers.get() != NULL);
2622 EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine());
2624 // Verify the pushed stream.
2625 EXPECT_TRUE(response2.headers.get() != NULL);
2626 EXPECT_EQ("HTTP/1.1 200 OK", response2.headers->GetStatusLine());
2629 TEST_P(SpdyNetworkTransactionTest, ServerPushSingleDataFrame2) {
2630 scoped_ptr<SpdyFrame> stream1_syn(
2631 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
2632 MockWrite writes[] = {
2633 CreateMockWrite(*stream1_syn, 0),
2636 scoped_ptr<SpdyFrame>
2637 stream1_reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
2638 scoped_ptr<SpdyFrame> stream2_syn(spdy_util_.ConstructSpdyPush(
2639 NULL, 0, 2, 1, GetDefaultUrlWithPath("/foo.dat").c_str()));
2640 const char kPushedData[] = "pushed";
2641 scoped_ptr<SpdyFrame> stream2_body(
2642 spdy_util_.ConstructSpdyBodyFrame(
2643 2, kPushedData, strlen(kPushedData), true));
2644 scoped_ptr<SpdyFrame>
2645 stream1_body(spdy_util_.ConstructSpdyBodyFrame(1, true));
2646 MockRead reads[] = {
2647 CreateMockRead(*stream1_reply, 1),
2648 CreateMockRead(*stream2_syn, 2),
2649 CreateMockRead(*stream2_body, 3),
2650 CreateMockRead(*stream1_body, 4, SYNCHRONOUS),
2651 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 5), // Force a pause
2654 HttpResponseInfo response;
2655 HttpResponseInfo response2;
2656 std::string expected_push_result("pushed");
2657 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
2658 RunServerPushTest(&data,
2659 &response,
2660 &response2,
2661 expected_push_result);
2663 // Verify the SYN_REPLY.
2664 EXPECT_TRUE(response.headers.get() != NULL);
2665 EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine());
2667 // Verify the pushed stream.
2668 EXPECT_TRUE(response2.headers.get() != NULL);
2669 EXPECT_EQ("HTTP/1.1 200 OK", response2.headers->GetStatusLine());
2672 TEST_P(SpdyNetworkTransactionTest, ServerPushServerAborted) {
2673 scoped_ptr<SpdyFrame> stream1_syn(
2674 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
2675 scoped_ptr<SpdyFrame> stream1_body(
2676 spdy_util_.ConstructSpdyBodyFrame(1, true));
2677 MockWrite writes[] = {
2678 CreateMockWrite(*stream1_syn, 0),
2681 scoped_ptr<SpdyFrame>
2682 stream1_reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
2683 scoped_ptr<SpdyFrame> stream2_syn(spdy_util_.ConstructSpdyPush(
2684 NULL, 0, 2, 1, GetDefaultUrlWithPath("/foo.dat").c_str()));
2685 scoped_ptr<SpdyFrame> stream2_rst(
2686 spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR));
2687 MockRead reads[] = {
2688 CreateMockRead(*stream1_reply, 1),
2689 CreateMockRead(*stream2_syn, 2),
2690 CreateMockRead(*stream2_rst, 3),
2691 CreateMockRead(*stream1_body, 4, SYNCHRONOUS),
2692 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 5), // Force a pause
2695 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
2696 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
2697 BoundNetLog(), GetParam(), NULL);
2699 helper.RunPreTestSetup();
2700 helper.AddData(&data);
2702 HttpNetworkTransaction* trans = helper.trans();
2704 // Start the transaction with basic parameters.
2705 TestCompletionCallback callback;
2706 int rv = trans->Start(
2707 &CreateGetRequest(), callback.callback(), BoundNetLog());
2708 EXPECT_EQ(ERR_IO_PENDING, rv);
2709 rv = callback.WaitForResult();
2710 EXPECT_EQ(OK, rv);
2712 // Verify that we consumed all test data.
2713 EXPECT_TRUE(data.AllReadDataConsumed());
2714 EXPECT_TRUE(data.AllWriteDataConsumed());
2716 // Verify the SYN_REPLY.
2717 HttpResponseInfo response = *trans->GetResponseInfo();
2718 EXPECT_TRUE(response.headers.get() != NULL);
2719 EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine());
2722 // Verify that we don't leak streams and that we properly send a reset
2723 // if the server pushes the same stream twice.
2724 TEST_P(SpdyNetworkTransactionTest, ServerPushDuplicate) {
2725 scoped_ptr<SpdyFrame> stream1_syn(
2726 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
2727 scoped_ptr<SpdyFrame> stream1_body(
2728 spdy_util_.ConstructSpdyBodyFrame(1, true));
2729 scoped_ptr<SpdyFrame> stream3_rst(
2730 spdy_util_.ConstructSpdyRstStream(4, RST_STREAM_PROTOCOL_ERROR));
2731 MockWrite writes[] = {
2732 CreateMockWrite(*stream1_syn, 0), CreateMockWrite(*stream3_rst, 4),
2735 scoped_ptr<SpdyFrame>
2736 stream1_reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
2737 scoped_ptr<SpdyFrame> stream2_syn(spdy_util_.ConstructSpdyPush(
2738 NULL, 0, 2, 1, GetDefaultUrlWithPath("/foo.dat").c_str()));
2739 const char kPushedData[] = "pushed";
2740 scoped_ptr<SpdyFrame> stream2_body(
2741 spdy_util_.ConstructSpdyBodyFrame(
2742 2, kPushedData, strlen(kPushedData), true));
2743 scoped_ptr<SpdyFrame> stream3_syn(spdy_util_.ConstructSpdyPush(
2744 NULL, 0, 4, 1, GetDefaultUrlWithPath("/foo.dat").c_str()));
2745 MockRead reads[] = {
2746 CreateMockRead(*stream1_reply, 1),
2747 CreateMockRead(*stream2_syn, 2),
2748 CreateMockRead(*stream3_syn, 3),
2749 CreateMockRead(*stream1_body, 5),
2750 CreateMockRead(*stream2_body, 6),
2751 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 7), // Force a pause
2754 HttpResponseInfo response;
2755 HttpResponseInfo response2;
2756 std::string expected_push_result("pushed");
2757 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
2758 RunServerPushTest(&data,
2759 &response,
2760 &response2,
2761 expected_push_result);
2763 // Verify the SYN_REPLY.
2764 EXPECT_TRUE(response.headers.get() != NULL);
2765 EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine());
2767 // Verify the pushed stream.
2768 EXPECT_TRUE(response2.headers.get() != NULL);
2769 EXPECT_EQ("HTTP/1.1 200 OK", response2.headers->GetStatusLine());
2772 TEST_P(SpdyNetworkTransactionTest, ServerPushMultipleDataFrame) {
2773 scoped_ptr<SpdyFrame> stream1_syn(
2774 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
2775 scoped_ptr<SpdyFrame> stream1_body(
2776 spdy_util_.ConstructSpdyBodyFrame(1, true));
2777 MockWrite writes[] = {
2778 CreateMockWrite(*stream1_syn, 0),
2781 scoped_ptr<SpdyFrame>
2782 stream1_reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
2783 scoped_ptr<SpdyFrame> stream2_syn(spdy_util_.ConstructSpdyPush(
2784 NULL, 0, 2, 1, GetDefaultUrlWithPath("/foo.dat").c_str()));
2785 static const char kPushedData[] = "pushed my darling hello my baby";
2786 scoped_ptr<SpdyFrame> stream2_body_base(
2787 spdy_util_.ConstructSpdyBodyFrame(
2788 2, kPushedData, strlen(kPushedData), true));
2789 const size_t kChunkSize = strlen(kPushedData) / 4;
2790 scoped_ptr<SpdyFrame> stream2_body1(
2791 new SpdyFrame(stream2_body_base->data(), kChunkSize, false));
2792 scoped_ptr<SpdyFrame> stream2_body2(
2793 new SpdyFrame(stream2_body_base->data() + kChunkSize, kChunkSize, false));
2794 scoped_ptr<SpdyFrame> stream2_body3(
2795 new SpdyFrame(stream2_body_base->data() + 2 * kChunkSize,
2796 kChunkSize, false));
2797 scoped_ptr<SpdyFrame> stream2_body4(
2798 new SpdyFrame(stream2_body_base->data() + 3 * kChunkSize,
2799 stream2_body_base->size() - 3 * kChunkSize, false));
2800 MockRead reads[] = {
2801 CreateMockRead(*stream1_reply, 1),
2802 CreateMockRead(*stream2_syn, 2),
2803 CreateMockRead(*stream2_body1, 3),
2804 CreateMockRead(*stream2_body2, 4),
2805 CreateMockRead(*stream2_body3, 5),
2806 CreateMockRead(*stream2_body4, 6),
2807 CreateMockRead(*stream1_body, 7, SYNCHRONOUS),
2808 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 8), // Force a pause
2811 HttpResponseInfo response;
2812 HttpResponseInfo response2;
2813 std::string expected_push_result("pushed my darling hello my baby");
2814 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
2815 RunServerPushTest(&data, &response, &response2, kPushedData);
2817 // Verify the SYN_REPLY.
2818 EXPECT_TRUE(response.headers.get() != NULL);
2819 EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine());
2821 // Verify the pushed stream.
2822 EXPECT_TRUE(response2.headers.get() != NULL);
2823 EXPECT_EQ("HTTP/1.1 200 OK", response2.headers->GetStatusLine());
2826 TEST_P(SpdyNetworkTransactionTest, ServerPushMultipleDataFrameInterrupted) {
2827 scoped_ptr<SpdyFrame> stream1_syn(
2828 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
2829 scoped_ptr<SpdyFrame> stream1_body(
2830 spdy_util_.ConstructSpdyBodyFrame(1, true));
2831 MockWrite writes[] = {
2832 CreateMockWrite(*stream1_syn, 0),
2835 scoped_ptr<SpdyFrame>
2836 stream1_reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
2837 scoped_ptr<SpdyFrame> stream2_syn(spdy_util_.ConstructSpdyPush(
2838 NULL, 0, 2, 1, GetDefaultUrlWithPath("/foo.dat").c_str()));
2839 static const char kPushedData[] = "pushed my darling hello my baby";
2840 scoped_ptr<SpdyFrame> stream2_body_base(
2841 spdy_util_.ConstructSpdyBodyFrame(
2842 2, kPushedData, strlen(kPushedData), true));
2843 const size_t kChunkSize = strlen(kPushedData) / 4;
2844 scoped_ptr<SpdyFrame> stream2_body1(
2845 new SpdyFrame(stream2_body_base->data(), kChunkSize, false));
2846 scoped_ptr<SpdyFrame> stream2_body2(
2847 new SpdyFrame(stream2_body_base->data() + kChunkSize, kChunkSize, false));
2848 scoped_ptr<SpdyFrame> stream2_body3(
2849 new SpdyFrame(stream2_body_base->data() + 2 * kChunkSize,
2850 kChunkSize, false));
2851 scoped_ptr<SpdyFrame> stream2_body4(
2852 new SpdyFrame(stream2_body_base->data() + 3 * kChunkSize,
2853 stream2_body_base->size() - 3 * kChunkSize, false));
2854 MockRead reads[] = {
2855 CreateMockRead(*stream1_reply, 1),
2856 CreateMockRead(*stream2_syn, 2),
2857 CreateMockRead(*stream2_body1, 3),
2858 CreateMockRead(*stream2_body2, 4),
2859 CreateMockRead(*stream2_body3, 5),
2860 CreateMockRead(*stream2_body4, 6),
2861 CreateMockRead(*stream1_body.get(), 7, SYNCHRONOUS),
2862 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 8) // Force a pause.
2865 HttpResponseInfo response;
2866 HttpResponseInfo response2;
2867 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
2868 RunServerPushTest(&data, &response, &response2, kPushedData);
2870 // Verify the SYN_REPLY.
2871 EXPECT_TRUE(response.headers.get() != NULL);
2872 EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine());
2874 // Verify the pushed stream.
2875 EXPECT_TRUE(response2.headers.get() != NULL);
2876 EXPECT_EQ("HTTP/1.1 200 OK", response2.headers->GetStatusLine());
2879 TEST_P(SpdyNetworkTransactionTest, ServerPushInvalidAssociatedStreamID0) {
2880 if (spdy_util_.spdy_version() == HTTP2) {
2881 // PUSH_PROMISE with stream id 0 is connection-level error.
2882 // TODO(baranovich): Test session going away.
2883 return;
2886 scoped_ptr<SpdyFrame> stream1_syn(
2887 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
2888 scoped_ptr<SpdyFrame> stream1_body(
2889 spdy_util_.ConstructSpdyBodyFrame(1, true));
2890 scoped_ptr<SpdyFrame> stream2_rst(
2891 spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_REFUSED_STREAM));
2892 MockWrite writes[] = {
2893 CreateMockWrite(*stream1_syn, 0), CreateMockWrite(*stream2_rst, 3),
2896 scoped_ptr<SpdyFrame>
2897 stream1_reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
2898 scoped_ptr<SpdyFrame> stream2_syn(spdy_util_.ConstructSpdyPush(
2899 NULL, 0, 2, 0, GetDefaultUrlWithPath("/foo.dat").c_str()));
2900 MockRead reads[] = {
2901 CreateMockRead(*stream1_reply, 1),
2902 CreateMockRead(*stream2_syn, 2),
2903 CreateMockRead(*stream1_body, 4),
2904 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 5) // Force a pause
2907 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
2908 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
2909 BoundNetLog(), GetParam(), NULL);
2911 helper.RunPreTestSetup();
2912 helper.AddData(&data);
2914 HttpNetworkTransaction* trans = helper.trans();
2916 // Start the transaction with basic parameters.
2917 TestCompletionCallback callback;
2918 int rv = trans->Start(
2919 &CreateGetRequest(), callback.callback(), BoundNetLog());
2920 EXPECT_EQ(ERR_IO_PENDING, rv);
2921 rv = callback.WaitForResult();
2922 EXPECT_EQ(OK, rv);
2924 // Verify that we consumed all test data.
2925 EXPECT_TRUE(data.AllReadDataConsumed());
2926 EXPECT_TRUE(data.AllWriteDataConsumed());
2928 // Verify the SYN_REPLY.
2929 HttpResponseInfo response = *trans->GetResponseInfo();
2930 EXPECT_TRUE(response.headers.get() != NULL);
2931 EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine());
2934 TEST_P(SpdyNetworkTransactionTest, ServerPushInvalidAssociatedStreamID9) {
2935 scoped_ptr<SpdyFrame> stream1_syn(
2936 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
2937 scoped_ptr<SpdyFrame> stream1_body(
2938 spdy_util_.ConstructSpdyBodyFrame(1, true));
2939 scoped_ptr<SpdyFrame> stream2_rst(
2940 spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_INVALID_STREAM));
2941 MockWrite writes[] = {
2942 CreateMockWrite(*stream1_syn, 0), CreateMockWrite(*stream2_rst, 3),
2945 scoped_ptr<SpdyFrame>
2946 stream1_reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
2947 scoped_ptr<SpdyFrame> stream2_syn(spdy_util_.ConstructSpdyPush(
2948 NULL, 0, 2, 9, GetDefaultUrlWithPath("/foo.dat").c_str()));
2949 MockRead reads[] = {
2950 CreateMockRead(*stream1_reply, 1),
2951 CreateMockRead(*stream2_syn, 2),
2952 CreateMockRead(*stream1_body, 4),
2953 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 5), // Force a pause
2956 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
2957 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
2958 BoundNetLog(), GetParam(), NULL);
2960 helper.RunPreTestSetup();
2961 helper.AddData(&data);
2963 HttpNetworkTransaction* trans = helper.trans();
2965 // Start the transaction with basic parameters.
2966 TestCompletionCallback callback;
2967 int rv = trans->Start(
2968 &CreateGetRequest(), callback.callback(), BoundNetLog());
2969 EXPECT_EQ(ERR_IO_PENDING, rv);
2970 rv = callback.WaitForResult();
2971 EXPECT_EQ(OK, rv);
2973 // Verify that we consumed all test data.
2974 EXPECT_TRUE(data.AllReadDataConsumed());
2975 EXPECT_TRUE(data.AllWriteDataConsumed());
2977 // Verify the SYN_REPLY.
2978 HttpResponseInfo response = *trans->GetResponseInfo();
2979 EXPECT_TRUE(response.headers.get() != NULL);
2980 EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine());
2983 TEST_P(SpdyNetworkTransactionTest, ServerPushNoURL) {
2984 scoped_ptr<SpdyFrame> stream1_syn(
2985 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
2986 scoped_ptr<SpdyFrame> stream1_body(
2987 spdy_util_.ConstructSpdyBodyFrame(1, true));
2988 scoped_ptr<SpdyFrame> stream2_rst(
2989 spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR));
2990 MockWrite writes[] = {
2991 CreateMockWrite(*stream1_syn, 0), CreateMockWrite(*stream2_rst, 3),
2994 scoped_ptr<SpdyFrame>
2995 stream1_reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
2996 scoped_ptr<SpdyHeaderBlock> incomplete_headers(new SpdyHeaderBlock());
2997 (*incomplete_headers)["hello"] = "bye";
2998 (*incomplete_headers)[spdy_util_.GetStatusKey()] = "200 OK";
2999 (*incomplete_headers)[spdy_util_.GetVersionKey()] = "HTTP/1.1";
3000 scoped_ptr<SpdyFrame> stream2_syn(spdy_util_.ConstructInitialSpdyPushFrame(
3001 incomplete_headers.Pass(), 2, 1));
3002 MockRead reads[] = {
3003 CreateMockRead(*stream1_reply, 1),
3004 CreateMockRead(*stream2_syn, 2),
3005 CreateMockRead(*stream1_body, 4),
3006 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 5) // Force a pause
3009 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
3010 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
3011 BoundNetLog(), GetParam(), NULL);
3013 helper.RunPreTestSetup();
3014 helper.AddData(&data);
3016 HttpNetworkTransaction* trans = helper.trans();
3018 // Start the transaction with basic parameters.
3019 TestCompletionCallback callback;
3020 int rv = trans->Start(
3021 &CreateGetRequest(), callback.callback(), BoundNetLog());
3022 EXPECT_EQ(ERR_IO_PENDING, rv);
3023 rv = callback.WaitForResult();
3024 EXPECT_EQ(OK, rv);
3026 // Verify that we consumed all test data.
3027 EXPECT_TRUE(data.AllReadDataConsumed());
3028 EXPECT_TRUE(data.AllWriteDataConsumed());
3030 // Verify the SYN_REPLY.
3031 HttpResponseInfo response = *trans->GetResponseInfo();
3032 EXPECT_TRUE(response.headers.get() != NULL);
3033 EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine());
3036 // Verify that various SynReply headers parse correctly through the
3037 // HTTP layer.
3038 TEST_P(SpdyNetworkTransactionTest, SynReplyHeaders) {
3039 struct SynReplyHeadersTests {
3040 int num_headers;
3041 const char* extra_headers[5];
3042 SpdyHeaderBlock expected_headers;
3043 } test_cases[] = {
3044 // This uses a multi-valued cookie header.
3045 { 2,
3046 { "cookie", "val1",
3047 "cookie", "val2", // will get appended separated by NULL
3048 NULL
3051 // This is the minimalist set of headers.
3052 { 0,
3053 { NULL },
3055 // Headers with a comma separated list.
3056 { 1,
3057 { "cookie", "val1,val2",
3058 NULL
3063 test_cases[0].expected_headers["cookie"] = "val1";
3064 test_cases[0].expected_headers["cookie"] += '\0';
3065 test_cases[0].expected_headers["cookie"] += "val2";
3066 test_cases[0].expected_headers["hello"] = "bye";
3067 test_cases[0].expected_headers["status"] = "200";
3069 test_cases[1].expected_headers["hello"] = "bye";
3070 test_cases[1].expected_headers["status"] = "200";
3072 test_cases[2].expected_headers["cookie"] = "val1,val2";
3073 test_cases[2].expected_headers["hello"] = "bye";
3074 test_cases[2].expected_headers["status"] = "200";
3076 if (spdy_util_.spdy_version() < HTTP2) {
3077 // HTTP/2 eliminates use of the :version header.
3078 test_cases[0].expected_headers["version"] = "HTTP/1.1";
3079 test_cases[1].expected_headers["version"] = "HTTP/1.1";
3080 test_cases[2].expected_headers["version"] = "HTTP/1.1";
3083 for (size_t i = 0; i < arraysize(test_cases); ++i) {
3084 scoped_ptr<SpdyFrame> req(
3085 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
3086 MockWrite writes[] = {CreateMockWrite(*req, 0)};
3088 scoped_ptr<SpdyFrame> resp(
3089 spdy_util_.ConstructSpdyGetSynReply(test_cases[i].extra_headers,
3090 test_cases[i].num_headers,
3091 1));
3092 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
3093 MockRead reads[] = {
3094 CreateMockRead(*resp, 1),
3095 CreateMockRead(*body, 2),
3096 MockRead(ASYNC, 0, 3) // EOF
3099 SequencedSocketData data(reads, arraysize(reads), writes,
3100 arraysize(writes));
3101 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
3102 BoundNetLog(), GetParam(), NULL);
3103 helper.RunToCompletion(&data);
3104 TransactionHelperResult out = helper.output();
3106 EXPECT_EQ(OK, out.rv);
3107 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
3108 EXPECT_EQ("hello!", out.response_data);
3110 scoped_refptr<HttpResponseHeaders> headers = out.response_info.headers;
3111 EXPECT_TRUE(headers.get() != NULL);
3112 void* iter = NULL;
3113 std::string name, value;
3114 SpdyHeaderBlock header_block;
3115 while (headers->EnumerateHeaderLines(&iter, &name, &value)) {
3116 if (header_block[name].empty()) {
3117 header_block[name] = value;
3118 } else {
3119 header_block[name] += '\0';
3120 header_block[name] += value;
3123 EXPECT_EQ(test_cases[i].expected_headers, header_block);
3127 // Verify that various SynReply headers parse vary fields correctly
3128 // through the HTTP layer, and the response matches the request.
3129 TEST_P(SpdyNetworkTransactionTest, SynReplyHeadersVary) {
3130 // Modify the following data to change/add test cases:
3131 struct SynReplyTests {
3132 bool vary_matches;
3133 int num_headers[2];
3134 const char* extra_headers[2][16];
3135 } test_cases[] = {
3136 // Test the case of a multi-valued cookie. When the value is delimited
3137 // with NUL characters, it needs to be unfolded into multiple headers.
3139 true,
3140 { 1, 4 },
3141 { { "cookie", "val1,val2",
3142 NULL
3144 { "vary", "cookie",
3145 spdy_util_.GetStatusKey(), "200",
3146 spdy_util_.GetPathKey(), "/index.php",
3147 spdy_util_.GetVersionKey(), "HTTP/1.1",
3148 NULL
3151 }, { // Multiple vary fields.
3152 true,
3153 { 2, 5 },
3154 { { "friend", "barney",
3155 "enemy", "snaggletooth",
3156 NULL
3158 { "vary", "friend",
3159 "vary", "enemy",
3160 spdy_util_.GetStatusKey(), "200",
3161 spdy_util_.GetPathKey(), "/index.php",
3162 spdy_util_.GetVersionKey(), "HTTP/1.1",
3163 NULL
3166 }, { // Test a '*' vary field.
3167 false,
3168 { 1, 4 },
3169 { { "cookie", "val1,val2",
3170 NULL
3172 { "vary", "*",
3173 spdy_util_.GetStatusKey(), "200",
3174 spdy_util_.GetPathKey(), "/index.php",
3175 spdy_util_.GetVersionKey(), "HTTP/1.1",
3176 NULL
3179 }, { // Multiple comma-separated vary fields.
3180 true,
3181 { 2, 4 },
3182 { { "friend", "barney",
3183 "enemy", "snaggletooth",
3184 NULL
3186 { "vary", "friend,enemy",
3187 spdy_util_.GetStatusKey(), "200",
3188 spdy_util_.GetPathKey(), "/index.php",
3189 spdy_util_.GetVersionKey(), "HTTP/1.1",
3190 NULL
3196 for (size_t i = 0; i < arraysize(test_cases); ++i) {
3197 // Construct the request.
3198 scoped_ptr<SpdyFrame> frame_req(
3199 spdy_util_.ConstructSpdyGet(test_cases[i].extra_headers[0],
3200 test_cases[i].num_headers[0],
3201 false, 1, LOWEST, true));
3203 MockWrite writes[] = {
3204 CreateMockWrite(*frame_req, 0),
3207 // Construct the reply.
3208 SpdyHeaderBlock reply_headers;
3209 AppendToHeaderBlock(test_cases[i].extra_headers[1],
3210 test_cases[i].num_headers[1],
3211 &reply_headers);
3212 scoped_ptr<SpdyFrame> frame_reply(
3213 spdy_util_.ConstructSpdyReply(1, reply_headers));
3215 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
3216 MockRead reads[] = {
3217 CreateMockRead(*frame_reply, 1),
3218 CreateMockRead(*body, 2),
3219 MockRead(ASYNC, 0, 3) // EOF
3222 // Attach the headers to the request.
3223 int header_count = test_cases[i].num_headers[0];
3225 HttpRequestInfo request = CreateGetRequest();
3226 for (int ct = 0; ct < header_count; ct++) {
3227 const char* header_key = test_cases[i].extra_headers[0][ct * 2];
3228 const char* header_value = test_cases[i].extra_headers[0][ct * 2 + 1];
3229 request.extra_headers.SetHeader(header_key, header_value);
3232 SequencedSocketData data(reads, arraysize(reads), writes,
3233 arraysize(writes));
3234 NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY,
3235 BoundNetLog(), GetParam(), NULL);
3236 helper.RunToCompletion(&data);
3237 TransactionHelperResult out = helper.output();
3239 EXPECT_EQ(OK, out.rv) << i;
3240 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line) << i;
3241 EXPECT_EQ("hello!", out.response_data) << i;
3243 // Test the response information.
3244 EXPECT_EQ(out.response_info.vary_data.is_valid(),
3245 test_cases[i].vary_matches) << i;
3247 // Check the headers.
3248 scoped_refptr<HttpResponseHeaders> headers = out.response_info.headers;
3249 ASSERT_TRUE(headers.get() != NULL) << i;
3250 void* iter = NULL;
3251 std::string name, value, lines;
3252 while (headers->EnumerateHeaderLines(&iter, &name, &value)) {
3253 lines.append(name);
3254 lines.append(": ");
3255 lines.append(value);
3256 lines.append("\n");
3259 // Construct the expected header reply string.
3260 std::string expected_reply =
3261 spdy_util_.ConstructSpdyReplyString(reply_headers);
3262 EXPECT_EQ(expected_reply, lines) << i;
3266 // Verify that we don't crash on invalid SynReply responses.
3267 TEST_P(SpdyNetworkTransactionTest, InvalidSynReply) {
3268 struct InvalidSynReplyTests {
3269 int num_headers;
3270 const char* headers[10];
3271 } test_cases[] = {
3272 // SYN_REPLY missing status header
3273 { 4,
3274 { "cookie", "val1",
3275 "cookie", "val2",
3276 spdy_util_.GetPathKey(), "/index.php",
3277 spdy_util_.GetVersionKey(), "HTTP/1.1",
3278 NULL
3281 // SYN_REPLY missing version header
3282 { 2,
3283 { "status", "200",
3284 spdy_util_.GetPathKey(), "/index.php",
3285 NULL
3288 // SYN_REPLY with no headers
3289 { 0, { NULL }, },
3292 for (size_t i = 0; i < arraysize(test_cases); ++i) {
3293 scoped_ptr<SpdyFrame> req(
3294 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
3295 scoped_ptr<SpdyFrame> rst(
3296 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR));
3297 MockWrite writes[] = {
3298 CreateMockWrite(*req, 0), CreateMockWrite(*rst, 2),
3301 // Construct the reply.
3302 SpdyHeaderBlock reply_headers;
3303 AppendToHeaderBlock(
3304 test_cases[i].headers, test_cases[i].num_headers, &reply_headers);
3305 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyReply(1, reply_headers));
3306 MockRead reads[] = {
3307 CreateMockRead(*resp, 1), MockRead(ASYNC, 0, 3) // EOF
3310 SequencedSocketData data(reads, arraysize(reads), writes,
3311 arraysize(writes));
3312 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
3313 BoundNetLog(), GetParam(), NULL);
3314 helper.RunToCompletion(&data);
3315 TransactionHelperResult out = helper.output();
3316 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, out.rv);
3320 // Verify that we don't crash on some corrupt frames.
3321 // TODO(jgraettinger): HTTP/2 treats a header decompression failure as a
3322 // connection error. I'd like to backport this behavior to SPDY3 as well.
3323 TEST_P(SpdyNetworkTransactionTest, CorruptFrameSessionError) {
3324 if (spdy_util_.spdy_version() >= HTTP2) {
3325 return;
3327 // This is the length field that's too short.
3328 scoped_ptr<SpdyFrame> syn_reply_wrong_length(
3329 spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
3330 BufferedSpdyFramer framer(spdy_util_.spdy_version(), false);
3331 size_t right_size =
3332 (spdy_util_.spdy_version() < HTTP2)
3333 ? syn_reply_wrong_length->size() - framer.GetControlFrameHeaderSize()
3334 : syn_reply_wrong_length->size();
3335 size_t wrong_size = right_size - 4;
3336 test::SetFrameLength(syn_reply_wrong_length.get(),
3337 wrong_size,
3338 spdy_util_.spdy_version());
3340 struct SynReplyTests {
3341 const SpdyFrame* syn_reply;
3342 } test_cases[] = {
3343 { syn_reply_wrong_length.get(), },
3346 for (size_t i = 0; i < arraysize(test_cases); ++i) {
3347 scoped_ptr<SpdyFrame> req(
3348 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
3349 scoped_ptr<SpdyFrame> rst(
3350 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR));
3351 MockWrite writes[] = {
3352 CreateMockWrite(*req, 0), CreateMockWrite(*rst, 3),
3355 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
3356 MockRead reads[] = {
3357 MockRead(ASYNC, test_cases[i].syn_reply->data(), wrong_size, 1),
3358 CreateMockRead(*body, 2),
3359 MockRead(ASYNC, 0, 4) // EOF
3362 SequencedSocketData data(reads, arraysize(reads), writes,
3363 arraysize(writes));
3364 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
3365 BoundNetLog(), GetParam(), NULL);
3366 helper.RunToCompletion(&data);
3367 TransactionHelperResult out = helper.output();
3368 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, out.rv);
3372 // HTTP/2 treats a header decompression failure as a connection-level error.
3373 TEST_P(SpdyNetworkTransactionTest, CorruptFrameSessionErrorSpdy4) {
3374 if (spdy_util_.spdy_version() < HTTP2) {
3375 return;
3377 // This is the length field that's too short.
3378 scoped_ptr<SpdyFrame> syn_reply_wrong_length(
3379 spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
3380 BufferedSpdyFramer framer(spdy_util_.spdy_version(), false);
3381 size_t right_size =
3382 syn_reply_wrong_length->size() - framer.GetControlFrameHeaderSize();
3383 size_t wrong_size = right_size - 4;
3384 test::SetFrameLength(syn_reply_wrong_length.get(),
3385 wrong_size,
3386 spdy_util_.spdy_version());
3388 scoped_ptr<SpdyFrame> req(
3389 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
3390 scoped_ptr<SpdyFrame> goaway(spdy_util_.ConstructSpdyGoAway(
3391 0, GOAWAY_COMPRESSION_ERROR, "Framer error: 5 (DECOMPRESS_FAILURE)."));
3392 MockWrite writes[] = {CreateMockWrite(*req, 0), CreateMockWrite(*goaway, 2)};
3394 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
3395 MockRead reads[] = {
3396 MockRead(ASYNC, syn_reply_wrong_length->data(),
3397 syn_reply_wrong_length->size() - 4, 1),
3400 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
3401 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
3402 BoundNetLog(), GetParam(), NULL);
3403 helper.RunToCompletion(&data);
3404 TransactionHelperResult out = helper.output();
3405 EXPECT_EQ(ERR_SPDY_COMPRESSION_ERROR, out.rv);
3408 TEST_P(SpdyNetworkTransactionTest, GoAwayOnDecompressionFailure) {
3409 if (GetParam().protocol < kProtoHTTP2) {
3410 // Decompression failures are a stream error in SPDY3 and above.
3411 return;
3413 scoped_ptr<SpdyFrame> req(
3414 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
3415 scoped_ptr<SpdyFrame> goaway(spdy_util_.ConstructSpdyGoAway(
3416 0, GOAWAY_COMPRESSION_ERROR, "Framer error: 5 (DECOMPRESS_FAILURE)."));
3417 MockWrite writes[] = {CreateMockWrite(*req, 0), CreateMockWrite(*goaway, 2)};
3419 // Read HEADERS with corrupted payload.
3420 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
3421 memset(resp->data() + 12, 0xff, resp->size() - 12);
3422 MockRead reads[] = {CreateMockRead(*resp, 1)};
3424 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
3425 NormalSpdyTransactionHelper helper(
3426 CreateGetRequest(), DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL);
3427 helper.RunToCompletion(&data);
3428 TransactionHelperResult out = helper.output();
3429 EXPECT_EQ(ERR_SPDY_COMPRESSION_ERROR, out.rv);
3432 TEST_P(SpdyNetworkTransactionTest, GoAwayOnFrameSizeError) {
3433 scoped_ptr<SpdyFrame> req(
3434 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
3435 scoped_ptr<SpdyFrame> goaway(spdy_util_.ConstructSpdyGoAway(
3436 0, GOAWAY_PROTOCOL_ERROR, "Framer error: 1 (INVALID_CONTROL_FRAME)."));
3437 MockWrite writes[] = {CreateMockWrite(*req, 0), CreateMockWrite(*goaway, 2)};
3439 // Read WINDOW_UPDATE with incorrectly-sized payload.
3440 // TODO(jgraettinger): SpdyFramer signals this as an INVALID_CONTROL_FRAME,
3441 // which is mapped to a protocol error, and not a frame size error.
3442 scoped_ptr<SpdyFrame> bad_window_update(
3443 spdy_util_.ConstructSpdyWindowUpdate(1, 1));
3444 test::SetFrameLength(bad_window_update.get(),
3445 bad_window_update->size() - 1,
3446 spdy_util_.spdy_version());
3447 MockRead reads[] = {CreateMockRead(*bad_window_update, 1)};
3449 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
3450 NormalSpdyTransactionHelper helper(
3451 CreateGetRequest(), DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL);
3452 helper.RunToCompletion(&data);
3453 TransactionHelperResult out = helper.output();
3454 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, out.rv);
3457 // Test that we shutdown correctly on write errors.
3458 TEST_P(SpdyNetworkTransactionTest, WriteError) {
3459 scoped_ptr<SpdyFrame> req(
3460 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
3461 MockWrite writes[] = {
3462 // We'll write 10 bytes successfully
3463 MockWrite(ASYNC, req->data(), 10, 0),
3464 // Followed by ERROR!
3465 MockWrite(ASYNC, ERR_FAILED, 1),
3466 // Session drains and attempts to write a GOAWAY: Another ERROR!
3467 MockWrite(ASYNC, ERR_FAILED, 2),
3470 MockRead reads[] = {
3471 MockRead(ASYNC, 0, 3) // EOF
3474 DeterministicSocketData data(reads, arraysize(reads),
3475 writes, arraysize(writes));
3477 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
3478 BoundNetLog(), GetParam(), NULL);
3479 helper.SetDeterministic();
3480 helper.RunPreTestSetup();
3481 helper.AddDeterministicData(&data);
3482 EXPECT_TRUE(helper.StartDefaultTest());
3483 data.RunFor(2);
3484 helper.FinishDefaultTest();
3485 EXPECT_TRUE(data.AllWriteDataConsumed());
3486 EXPECT_TRUE(!data.AllReadDataConsumed());
3487 TransactionHelperResult out = helper.output();
3488 EXPECT_EQ(ERR_FAILED, out.rv);
3491 // Test that partial writes work.
3492 TEST_P(SpdyNetworkTransactionTest, PartialWrite) {
3493 // Chop the SYN_STREAM frame into 5 chunks.
3494 scoped_ptr<SpdyFrame> req(
3495 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
3496 const int kChunks = 5;
3497 scoped_ptr<MockWrite[]> writes(ChopWriteFrame(*req.get(), kChunks));
3498 for (int i = 0; i < kChunks; ++i) {
3499 writes[i].sequence_number = i;
3502 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
3503 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
3504 MockRead reads[] = {
3505 CreateMockRead(*resp, kChunks),
3506 CreateMockRead(*body, kChunks + 1),
3507 MockRead(ASYNC, 0, kChunks + 2) // EOF
3510 SequencedSocketData data(reads, arraysize(reads), writes.get(), kChunks);
3511 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
3512 BoundNetLog(), GetParam(), NULL);
3513 helper.RunToCompletion(&data);
3514 TransactionHelperResult out = helper.output();
3515 EXPECT_EQ(OK, out.rv);
3516 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
3517 EXPECT_EQ("hello!", out.response_data);
3520 // In this test, we enable compression, but get a uncompressed SynReply from
3521 // the server. Verify that teardown is all clean.
3522 TEST_P(SpdyNetworkTransactionTest, DecompressFailureOnSynReply) {
3523 if (spdy_util_.spdy_version() >= HTTP2) {
3524 // HPACK doesn't use deflate compression.
3525 return;
3527 scoped_ptr<SpdyFrame> compressed(
3528 spdy_util_.ConstructSpdyGet(NULL, 0, true, 1, LOWEST, true));
3529 scoped_ptr<SpdyFrame> goaway(spdy_util_.ConstructSpdyGoAway(
3530 0, GOAWAY_COMPRESSION_ERROR, "Framer error: 5 (DECOMPRESS_FAILURE)."));
3531 MockWrite writes[] = {CreateMockWrite(*compressed, 0),
3532 CreateMockWrite(*goaway, 2)};
3534 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
3535 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
3536 MockRead reads[] = {
3537 CreateMockRead(*resp, 1),
3540 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
3541 scoped_ptr<SpdySessionDependencies> session_deps =
3542 CreateSpdySessionDependencies(GetParam());
3543 session_deps->enable_compression = true;
3544 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
3545 BoundNetLog(), GetParam(),
3546 session_deps.Pass());
3547 helper.RunToCompletion(&data);
3548 TransactionHelperResult out = helper.output();
3549 EXPECT_EQ(ERR_SPDY_COMPRESSION_ERROR, out.rv);
3550 data.Reset();
3553 // Test that the NetLog contains good data for a simple GET request.
3554 TEST_P(SpdyNetworkTransactionTest, NetLog) {
3555 static const char* const kExtraHeaders[] = {
3556 "user-agent", "Chrome",
3558 scoped_ptr<SpdyFrame> req(
3559 spdy_util_.ConstructSpdyGet(kExtraHeaders, 1, false, 1, LOWEST, true));
3560 MockWrite writes[] = {CreateMockWrite(*req, 0)};
3562 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
3563 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
3564 MockRead reads[] = {
3565 CreateMockRead(*resp, 1),
3566 CreateMockRead(*body, 2),
3567 MockRead(ASYNC, 0, 3) // EOF
3570 BoundTestNetLog log;
3572 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
3573 NormalSpdyTransactionHelper helper(CreateGetRequestWithUserAgent(),
3574 DEFAULT_PRIORITY,
3575 log.bound(), GetParam(), NULL);
3576 helper.RunToCompletion(&data);
3577 TransactionHelperResult out = helper.output();
3578 EXPECT_EQ(OK, out.rv);
3579 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
3580 EXPECT_EQ("hello!", out.response_data);
3582 // Check that the NetLog was filled reasonably.
3583 // This test is intentionally non-specific about the exact ordering of the
3584 // log; instead we just check to make sure that certain events exist, and that
3585 // they are in the right order.
3586 TestNetLogEntry::List entries;
3587 log.GetEntries(&entries);
3589 EXPECT_LT(0u, entries.size());
3590 int pos = 0;
3591 pos = ExpectLogContainsSomewhere(entries, 0,
3592 NetLog::TYPE_HTTP_TRANSACTION_SEND_REQUEST,
3593 NetLog::PHASE_BEGIN);
3594 pos = ExpectLogContainsSomewhere(entries, pos + 1,
3595 NetLog::TYPE_HTTP_TRANSACTION_SEND_REQUEST,
3596 NetLog::PHASE_END);
3597 pos = ExpectLogContainsSomewhere(entries, pos + 1,
3598 NetLog::TYPE_HTTP_TRANSACTION_READ_HEADERS,
3599 NetLog::PHASE_BEGIN);
3600 pos = ExpectLogContainsSomewhere(entries, pos + 1,
3601 NetLog::TYPE_HTTP_TRANSACTION_READ_HEADERS,
3602 NetLog::PHASE_END);
3603 pos = ExpectLogContainsSomewhere(entries, pos + 1,
3604 NetLog::TYPE_HTTP_TRANSACTION_READ_BODY,
3605 NetLog::PHASE_BEGIN);
3606 pos = ExpectLogContainsSomewhere(entries, pos + 1,
3607 NetLog::TYPE_HTTP_TRANSACTION_READ_BODY,
3608 NetLog::PHASE_END);
3610 // Check that we logged all the headers correctly
3611 const NetLog::EventType type = (GetParam().protocol <= kProtoSPDY31)
3612 ? NetLog::TYPE_HTTP2_SESSION_SYN_STREAM
3613 : NetLog::TYPE_HTTP2_SESSION_SEND_HEADERS;
3614 pos = ExpectLogContainsSomewhere(entries, 0, type, NetLog::PHASE_NONE);
3616 base::ListValue* header_list;
3617 ASSERT_TRUE(entries[pos].params.get());
3618 ASSERT_TRUE(entries[pos].params->GetList("headers", &header_list));
3620 std::vector<std::string> expected;
3621 expected.push_back(std::string(spdy_util_.GetHostKey()) +
3622 ": www.example.org");
3623 expected.push_back(std::string(spdy_util_.GetPathKey()) + ": /");
3624 expected.push_back(std::string(spdy_util_.GetSchemeKey()) + ": " +
3625 spdy_util_.default_url().scheme());
3626 expected.push_back(std::string(spdy_util_.GetMethodKey()) + ": GET");
3627 expected.push_back("user-agent: Chrome");
3628 if (spdy_util_.spdy_version() < HTTP2) {
3629 // HTTP/2 eliminates use of the :version header.
3630 expected.push_back(std::string(spdy_util_.GetVersionKey()) + ": HTTP/1.1");
3632 EXPECT_EQ(expected.size(), header_list->GetSize());
3633 for (std::vector<std::string>::const_iterator it = expected.begin();
3634 it != expected.end();
3635 ++it) {
3636 base::StringValue header(*it);
3637 EXPECT_NE(header_list->end(), header_list->Find(header)) <<
3638 "Header not found: " << *it;
3642 // Since we buffer the IO from the stream to the renderer, this test verifies
3643 // that when we read out the maximum amount of data (e.g. we received 50 bytes
3644 // on the network, but issued a Read for only 5 of those bytes) that the data
3645 // flow still works correctly.
3646 TEST_P(SpdyNetworkTransactionTest, BufferFull) {
3647 BufferedSpdyFramer framer(spdy_util_.spdy_version(), false);
3649 scoped_ptr<SpdyFrame> req(
3650 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
3651 MockWrite writes[] = {CreateMockWrite(*req, 0)};
3653 // 2 data frames in a single read.
3654 scoped_ptr<SpdyFrame> data_frame_1(
3655 framer.CreateDataFrame(1, "goodby", 6, DATA_FLAG_NONE));
3656 scoped_ptr<SpdyFrame> data_frame_2(
3657 framer.CreateDataFrame(1, "e worl", 6, DATA_FLAG_NONE));
3658 const SpdyFrame* data_frames[2] = {
3659 data_frame_1.get(),
3660 data_frame_2.get(),
3662 char combined_data_frames[100];
3663 int combined_data_frames_len =
3664 CombineFrames(data_frames, arraysize(data_frames),
3665 combined_data_frames, arraysize(combined_data_frames));
3666 scoped_ptr<SpdyFrame> last_frame(
3667 framer.CreateDataFrame(1, "d", 1, DATA_FLAG_FIN));
3669 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
3670 MockRead reads[] = {
3671 CreateMockRead(*resp, 1),
3672 MockRead(ASYNC, ERR_IO_PENDING, 2), // Force a pause
3673 MockRead(ASYNC, combined_data_frames, combined_data_frames_len, 3),
3674 MockRead(ASYNC, ERR_IO_PENDING, 4), // Force a pause
3675 CreateMockRead(*last_frame, 5),
3676 MockRead(ASYNC, 0, 6) // EOF
3679 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
3681 TestCompletionCallback callback;
3683 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
3684 BoundNetLog(), GetParam(), NULL);
3685 helper.RunPreTestSetup();
3686 helper.AddData(&data);
3687 HttpNetworkTransaction* trans = helper.trans();
3688 int rv = trans->Start(
3689 &CreateGetRequest(), callback.callback(), BoundNetLog());
3690 EXPECT_EQ(ERR_IO_PENDING, rv);
3692 TransactionHelperResult out = helper.output();
3693 out.rv = callback.WaitForResult();
3694 EXPECT_EQ(out.rv, OK);
3696 const HttpResponseInfo* response = trans->GetResponseInfo();
3697 EXPECT_TRUE(response->headers.get() != NULL);
3698 EXPECT_TRUE(response->was_fetched_via_spdy);
3699 out.status_line = response->headers->GetStatusLine();
3700 out.response_info = *response; // Make a copy so we can verify.
3702 // Read Data
3703 TestCompletionCallback read_callback;
3705 std::string content;
3706 do {
3707 // Read small chunks at a time.
3708 const int kSmallReadSize = 3;
3709 scoped_refptr<IOBuffer> buf(new IOBuffer(kSmallReadSize));
3710 rv = trans->Read(buf.get(), kSmallReadSize, read_callback.callback());
3711 if (rv == ERR_IO_PENDING) {
3712 data.CompleteRead();
3713 rv = read_callback.WaitForResult();
3715 if (rv > 0) {
3716 content.append(buf->data(), rv);
3717 } else if (rv < 0) {
3718 NOTREACHED();
3720 } while (rv > 0);
3722 out.response_data.swap(content);
3724 // Flush the MessageLoop while the SpdySessionDependencies (in particular, the
3725 // MockClientSocketFactory) are still alive.
3726 base::RunLoop().RunUntilIdle();
3728 // Verify that we consumed all test data.
3729 helper.VerifyDataConsumed();
3731 EXPECT_EQ(OK, out.rv);
3732 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
3733 EXPECT_EQ("goodbye world", out.response_data);
3736 // Verify that basic buffering works; when multiple data frames arrive
3737 // at the same time, ensure that we don't notify a read completion for
3738 // each data frame individually.
3739 TEST_P(SpdyNetworkTransactionTest, Buffering) {
3740 BufferedSpdyFramer framer(spdy_util_.spdy_version(), false);
3742 scoped_ptr<SpdyFrame> req(
3743 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
3744 MockWrite writes[] = {CreateMockWrite(*req, 0)};
3746 // 4 data frames in a single read.
3747 scoped_ptr<SpdyFrame> data_frame(
3748 framer.CreateDataFrame(1, "message", 7, DATA_FLAG_NONE));
3749 scoped_ptr<SpdyFrame> data_frame_fin(
3750 framer.CreateDataFrame(1, "message", 7, DATA_FLAG_FIN));
3751 const SpdyFrame* data_frames[4] = {
3752 data_frame.get(),
3753 data_frame.get(),
3754 data_frame.get(),
3755 data_frame_fin.get()
3757 char combined_data_frames[100];
3758 int combined_data_frames_len =
3759 CombineFrames(data_frames, arraysize(data_frames),
3760 combined_data_frames, arraysize(combined_data_frames));
3762 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
3763 MockRead reads[] = {
3764 CreateMockRead(*resp, 1),
3765 MockRead(ASYNC, ERR_IO_PENDING, 2), // Force a pause
3766 MockRead(ASYNC, combined_data_frames, combined_data_frames_len, 3),
3767 MockRead(ASYNC, 0, 4) // EOF
3770 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
3772 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
3773 BoundNetLog(), GetParam(), NULL);
3774 helper.RunPreTestSetup();
3775 helper.AddData(&data);
3776 HttpNetworkTransaction* trans = helper.trans();
3778 TestCompletionCallback callback;
3779 int rv = trans->Start(
3780 &CreateGetRequest(), callback.callback(), BoundNetLog());
3781 EXPECT_EQ(ERR_IO_PENDING, rv);
3783 TransactionHelperResult out = helper.output();
3784 out.rv = callback.WaitForResult();
3785 EXPECT_EQ(out.rv, OK);
3787 const HttpResponseInfo* response = trans->GetResponseInfo();
3788 EXPECT_TRUE(response->headers.get() != NULL);
3789 EXPECT_TRUE(response->was_fetched_via_spdy);
3790 out.status_line = response->headers->GetStatusLine();
3791 out.response_info = *response; // Make a copy so we can verify.
3793 // Read Data
3794 TestCompletionCallback read_callback;
3796 std::string content;
3797 int reads_completed = 0;
3798 do {
3799 // Read small chunks at a time.
3800 const int kSmallReadSize = 14;
3801 scoped_refptr<IOBuffer> buf(new IOBuffer(kSmallReadSize));
3802 rv = trans->Read(buf.get(), kSmallReadSize, read_callback.callback());
3803 if (rv == ERR_IO_PENDING) {
3804 data.CompleteRead();
3805 rv = read_callback.WaitForResult();
3807 if (rv > 0) {
3808 EXPECT_EQ(kSmallReadSize, rv);
3809 content.append(buf->data(), rv);
3810 } else if (rv < 0) {
3811 FAIL() << "Unexpected read error: " << rv;
3813 reads_completed++;
3814 } while (rv > 0);
3816 EXPECT_EQ(3, reads_completed); // Reads are: 14 bytes, 14 bytes, 0 bytes.
3818 out.response_data.swap(content);
3820 // Flush the MessageLoop while the SpdySessionDependencies (in particular, the
3821 // MockClientSocketFactory) are still alive.
3822 base::RunLoop().RunUntilIdle();
3824 // Verify that we consumed all test data.
3825 helper.VerifyDataConsumed();
3827 EXPECT_EQ(OK, out.rv);
3828 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
3829 EXPECT_EQ("messagemessagemessagemessage", out.response_data);
3832 // Verify the case where we buffer data but read it after it has been buffered.
3833 TEST_P(SpdyNetworkTransactionTest, BufferedAll) {
3834 BufferedSpdyFramer framer(spdy_util_.spdy_version(), false);
3836 scoped_ptr<SpdyFrame> req(
3837 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
3838 MockWrite writes[] = {CreateMockWrite(*req, 0)};
3840 // 5 data frames in a single read.
3841 scoped_ptr<SpdyFrame> reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
3842 scoped_ptr<SpdyFrame> data_frame(
3843 framer.CreateDataFrame(1, "message", 7, DATA_FLAG_NONE));
3844 scoped_ptr<SpdyFrame> data_frame_fin(
3845 framer.CreateDataFrame(1, "message", 7, DATA_FLAG_FIN));
3846 const SpdyFrame* frames[5] = {reply.get(), data_frame.get(), data_frame.get(),
3847 data_frame.get(), data_frame_fin.get()};
3848 char combined_frames[200];
3849 int combined_frames_len =
3850 CombineFrames(frames, arraysize(frames),
3851 combined_frames, arraysize(combined_frames));
3853 MockRead reads[] = {
3854 MockRead(ASYNC, combined_frames, combined_frames_len, 1),
3855 MockRead(ASYNC, 0, 2) // EOF
3858 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
3860 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
3861 BoundNetLog(), GetParam(), NULL);
3862 helper.RunPreTestSetup();
3863 helper.AddData(&data);
3864 HttpNetworkTransaction* trans = helper.trans();
3866 TestCompletionCallback callback;
3867 int rv = trans->Start(
3868 &CreateGetRequest(), callback.callback(), BoundNetLog());
3869 EXPECT_EQ(ERR_IO_PENDING, rv);
3871 TransactionHelperResult out = helper.output();
3872 out.rv = callback.WaitForResult();
3873 EXPECT_EQ(out.rv, OK);
3875 const HttpResponseInfo* response = trans->GetResponseInfo();
3876 EXPECT_TRUE(response->headers.get() != NULL);
3877 EXPECT_TRUE(response->was_fetched_via_spdy);
3878 out.status_line = response->headers->GetStatusLine();
3879 out.response_info = *response; // Make a copy so we can verify.
3881 // Read Data
3882 TestCompletionCallback read_callback;
3884 std::string content;
3885 int reads_completed = 0;
3886 do {
3887 // Read small chunks at a time.
3888 const int kSmallReadSize = 14;
3889 scoped_refptr<IOBuffer> buf(new IOBuffer(kSmallReadSize));
3890 rv = trans->Read(buf.get(), kSmallReadSize, read_callback.callback());
3891 if (rv > 0) {
3892 EXPECT_EQ(kSmallReadSize, rv);
3893 content.append(buf->data(), rv);
3894 } else if (rv < 0) {
3895 FAIL() << "Unexpected read error: " << rv;
3897 reads_completed++;
3898 } while (rv > 0);
3900 EXPECT_EQ(3, reads_completed);
3902 out.response_data.swap(content);
3904 // Flush the MessageLoop while the SpdySessionDependencies (in particular, the
3905 // MockClientSocketFactory) are still alive.
3906 base::RunLoop().RunUntilIdle();
3908 // Verify that we consumed all test data.
3909 helper.VerifyDataConsumed();
3911 EXPECT_EQ(OK, out.rv);
3912 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
3913 EXPECT_EQ("messagemessagemessagemessage", out.response_data);
3916 // Verify the case where we buffer data and close the connection.
3917 TEST_P(SpdyNetworkTransactionTest, BufferedClosed) {
3918 BufferedSpdyFramer framer(spdy_util_.spdy_version(), false);
3920 scoped_ptr<SpdyFrame> req(
3921 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
3922 MockWrite writes[] = {CreateMockWrite(*req, 0)};
3924 // All data frames in a single read.
3925 // NOTE: We don't FIN the stream.
3926 scoped_ptr<SpdyFrame> data_frame(
3927 framer.CreateDataFrame(1, "message", 7, DATA_FLAG_NONE));
3928 const SpdyFrame* data_frames[4] = {
3929 data_frame.get(),
3930 data_frame.get(),
3931 data_frame.get(),
3932 data_frame.get()
3934 char combined_data_frames[100];
3935 int combined_data_frames_len =
3936 CombineFrames(data_frames, arraysize(data_frames),
3937 combined_data_frames, arraysize(combined_data_frames));
3938 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
3939 MockRead reads[] = {
3940 CreateMockRead(*resp, 1),
3941 MockRead(ASYNC, ERR_IO_PENDING, 2), // Force a wait
3942 MockRead(ASYNC, combined_data_frames, combined_data_frames_len, 3),
3943 MockRead(ASYNC, 0, 4) // EOF
3946 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
3948 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
3949 BoundNetLog(), GetParam(), NULL);
3950 helper.RunPreTestSetup();
3951 helper.AddData(&data);
3952 HttpNetworkTransaction* trans = helper.trans();
3954 TestCompletionCallback callback;
3956 int rv = trans->Start(
3957 &CreateGetRequest(), callback.callback(), BoundNetLog());
3958 EXPECT_EQ(ERR_IO_PENDING, rv);
3960 TransactionHelperResult out = helper.output();
3961 out.rv = callback.WaitForResult();
3962 EXPECT_EQ(out.rv, OK);
3964 const HttpResponseInfo* response = trans->GetResponseInfo();
3965 EXPECT_TRUE(response->headers.get() != NULL);
3966 EXPECT_TRUE(response->was_fetched_via_spdy);
3967 out.status_line = response->headers->GetStatusLine();
3968 out.response_info = *response; // Make a copy so we can verify.
3970 // Read Data
3971 TestCompletionCallback read_callback;
3973 std::string content;
3974 int reads_completed = 0;
3975 do {
3976 // Read small chunks at a time.
3977 const int kSmallReadSize = 14;
3978 scoped_refptr<IOBuffer> buf(new IOBuffer(kSmallReadSize));
3979 rv = trans->Read(buf.get(), kSmallReadSize, read_callback.callback());
3980 if (rv == ERR_IO_PENDING) {
3981 data.CompleteRead();
3982 rv = read_callback.WaitForResult();
3984 if (rv > 0) {
3985 content.append(buf->data(), rv);
3986 } else if (rv < 0) {
3987 // This test intentionally closes the connection, and will get an error.
3988 EXPECT_EQ(ERR_CONNECTION_CLOSED, rv);
3989 break;
3991 reads_completed++;
3992 } while (rv > 0);
3994 EXPECT_EQ(0, reads_completed);
3996 out.response_data.swap(content);
3998 // Flush the MessageLoop while the SpdySessionDependencies (in particular, the
3999 // MockClientSocketFactory) are still alive.
4000 base::RunLoop().RunUntilIdle();
4002 // Verify that we consumed all test data.
4003 helper.VerifyDataConsumed();
4006 // Verify the case where we buffer data and cancel the transaction.
4007 TEST_P(SpdyNetworkTransactionTest, BufferedCancelled) {
4008 BufferedSpdyFramer framer(spdy_util_.spdy_version(), false);
4010 scoped_ptr<SpdyFrame> req(
4011 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
4012 scoped_ptr<SpdyFrame> rst(
4013 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL));
4014 MockWrite writes[] = {CreateMockWrite(*req, 0), CreateMockWrite(*rst, 4)};
4016 // NOTE: We don't FIN the stream.
4017 scoped_ptr<SpdyFrame> data_frame(
4018 framer.CreateDataFrame(1, "message", 7, DATA_FLAG_NONE));
4020 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
4021 MockRead reads[] = {
4022 CreateMockRead(*resp, 1),
4023 MockRead(ASYNC, ERR_IO_PENDING, 2), // Force a wait
4024 CreateMockRead(*data_frame, 3),
4025 MockRead(ASYNC, 0, 5) // EOF
4028 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
4030 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
4031 BoundNetLog(), GetParam(), NULL);
4032 helper.RunPreTestSetup();
4033 helper.AddData(&data);
4034 HttpNetworkTransaction* trans = helper.trans();
4035 TestCompletionCallback callback;
4037 int rv = trans->Start(
4038 &CreateGetRequest(), callback.callback(), BoundNetLog());
4039 EXPECT_EQ(ERR_IO_PENDING, rv);
4041 TransactionHelperResult out = helper.output();
4042 out.rv = callback.WaitForResult();
4043 EXPECT_EQ(out.rv, OK);
4045 const HttpResponseInfo* response = trans->GetResponseInfo();
4046 EXPECT_TRUE(response->headers.get() != NULL);
4047 EXPECT_TRUE(response->was_fetched_via_spdy);
4048 out.status_line = response->headers->GetStatusLine();
4049 out.response_info = *response; // Make a copy so we can verify.
4051 // Read Data
4052 TestCompletionCallback read_callback;
4054 const int kReadSize = 256;
4055 scoped_refptr<IOBuffer> buf(new IOBuffer(kReadSize));
4056 rv = trans->Read(buf.get(), kReadSize, read_callback.callback());
4057 ASSERT_EQ(ERR_IO_PENDING, rv) << "Unexpected read: " << rv;
4059 // Complete the read now, which causes buffering to start.
4060 data.CompleteRead();
4061 // Destroy the transaction, causing the stream to get cancelled
4062 // and orphaning the buffered IO task.
4063 helper.ResetTrans();
4065 // Flush the MessageLoop; this will cause the buffered IO task
4066 // to run for the final time.
4067 base::RunLoop().RunUntilIdle();
4069 // Verify that we consumed all test data.
4070 helper.VerifyDataConsumed();
4073 // Test that if the server requests persistence of settings, that we save
4074 // the settings in the HttpServerProperties.
4075 TEST_P(SpdyNetworkTransactionTest, SettingsSaved) {
4076 if (spdy_util_.spdy_version() >= HTTP2) {
4077 // HTTP/2 doesn't support settings persistence.
4078 return;
4080 static const SpdyHeaderInfo kSynReplyInfo = {
4081 SYN_REPLY, // Syn Reply
4082 1, // Stream ID
4083 0, // Associated Stream ID
4084 ConvertRequestPriorityToSpdyPriority(
4085 LOWEST, spdy_util_.spdy_version()),
4086 kSpdyCredentialSlotUnused,
4087 CONTROL_FLAG_NONE, // Control Flags
4088 false, // Compressed
4089 RST_STREAM_INVALID, // Status
4090 NULL, // Data
4091 0, // Data Length
4092 DATA_FLAG_NONE // Data Flags
4095 BoundNetLog net_log;
4096 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
4097 net_log, GetParam(), NULL);
4098 helper.RunPreTestSetup();
4100 // Verify that no settings exist initially.
4101 HostPortPair host_port_pair("www.example.org", helper.port());
4102 SpdySessionPool* spdy_session_pool = helper.session()->spdy_session_pool();
4103 EXPECT_TRUE(spdy_session_pool->http_server_properties()->GetSpdySettings(
4104 host_port_pair).empty());
4106 // Construct the request.
4107 scoped_ptr<SpdyFrame> req(
4108 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
4109 MockWrite writes[] = {CreateMockWrite(*req, 0)};
4111 // Construct the reply.
4112 scoped_ptr<SpdyHeaderBlock> reply_headers(new SpdyHeaderBlock());
4113 (*reply_headers)[spdy_util_.GetStatusKey()] = "200";
4114 (*reply_headers)[spdy_util_.GetVersionKey()] = "HTTP/1.1";
4115 scoped_ptr<SpdyFrame> reply(
4116 spdy_util_.ConstructSpdyFrame(kSynReplyInfo, reply_headers.Pass()));
4118 const SpdySettingsIds kSampleId1 = SETTINGS_UPLOAD_BANDWIDTH;
4119 unsigned int kSampleValue1 = 0x0a0a0a0a;
4120 const SpdySettingsIds kSampleId2 = SETTINGS_DOWNLOAD_BANDWIDTH;
4121 unsigned int kSampleValue2 = 0x0b0b0b0b;
4122 const SpdySettingsIds kSampleId3 = SETTINGS_ROUND_TRIP_TIME;
4123 unsigned int kSampleValue3 = 0x0c0c0c0c;
4124 scoped_ptr<SpdyFrame> settings_frame;
4126 // Construct the SETTINGS frame.
4127 SettingsMap settings;
4128 // First add a persisted setting.
4129 settings[kSampleId1] =
4130 SettingsFlagsAndValue(SETTINGS_FLAG_PLEASE_PERSIST, kSampleValue1);
4131 // Next add a non-persisted setting.
4132 settings[kSampleId2] =
4133 SettingsFlagsAndValue(SETTINGS_FLAG_NONE, kSampleValue2);
4134 // Next add another persisted setting.
4135 settings[kSampleId3] =
4136 SettingsFlagsAndValue(SETTINGS_FLAG_PLEASE_PERSIST, kSampleValue3);
4137 settings_frame.reset(spdy_util_.ConstructSpdySettings(settings));
4140 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
4141 MockRead reads[] = {
4142 CreateMockRead(*reply, 1),
4143 CreateMockRead(*body, 2),
4144 CreateMockRead(*settings_frame, 3),
4145 MockRead(ASYNC, 0, 4) // EOF
4148 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
4149 helper.AddData(&data);
4150 helper.RunDefaultTest();
4151 helper.VerifyDataConsumed();
4152 TransactionHelperResult out = helper.output();
4153 EXPECT_EQ(OK, out.rv);
4154 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
4155 EXPECT_EQ("hello!", out.response_data);
4158 // Verify we had two persisted settings.
4159 const SettingsMap& settings_map =
4160 spdy_session_pool->http_server_properties()->GetSpdySettings(
4161 host_port_pair);
4162 ASSERT_EQ(2u, settings_map.size());
4164 // Verify the first persisted setting.
4165 SettingsMap::const_iterator it1 = settings_map.find(kSampleId1);
4166 EXPECT_TRUE(it1 != settings_map.end());
4167 SettingsFlagsAndValue flags_and_value1 = it1->second;
4168 EXPECT_EQ(SETTINGS_FLAG_PERSISTED, flags_and_value1.first);
4169 EXPECT_EQ(kSampleValue1, flags_and_value1.second);
4171 // Verify the second persisted setting.
4172 SettingsMap::const_iterator it3 = settings_map.find(kSampleId3);
4173 EXPECT_TRUE(it3 != settings_map.end());
4174 SettingsFlagsAndValue flags_and_value3 = it3->second;
4175 EXPECT_EQ(SETTINGS_FLAG_PERSISTED, flags_and_value3.first);
4176 EXPECT_EQ(kSampleValue3, flags_and_value3.second);
4180 // Test that when there are settings saved that they are sent back to the
4181 // server upon session establishment.
4182 TEST_P(SpdyNetworkTransactionTest, SettingsPlayback) {
4183 if (spdy_util_.spdy_version() >= HTTP2) {
4184 // HTTP/2 doesn't support settings persistence.
4185 return;
4187 static const SpdyHeaderInfo kSynReplyInfo = {
4188 SYN_REPLY, // Syn Reply
4189 1, // Stream ID
4190 0, // Associated Stream ID
4191 ConvertRequestPriorityToSpdyPriority(
4192 LOWEST, spdy_util_.spdy_version()),
4193 kSpdyCredentialSlotUnused,
4194 CONTROL_FLAG_NONE, // Control Flags
4195 false, // Compressed
4196 RST_STREAM_INVALID, // Status
4197 NULL, // Data
4198 0, // Data Length
4199 DATA_FLAG_NONE // Data Flags
4202 BoundNetLog net_log;
4203 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
4204 net_log, GetParam(), NULL);
4205 helper.RunPreTestSetup();
4207 SpdySessionPool* spdy_session_pool = helper.session()->spdy_session_pool();
4209 SpdySessionPoolPeer pool_peer(spdy_session_pool);
4210 pool_peer.SetEnableSendingInitialData(true);
4212 // Verify that no settings exist initially.
4213 HostPortPair host_port_pair("www.example.org", helper.port());
4214 EXPECT_TRUE(spdy_session_pool->http_server_properties()->GetSpdySettings(
4215 host_port_pair).empty());
4217 const SpdySettingsIds kSampleId1 = SETTINGS_MAX_CONCURRENT_STREAMS;
4218 unsigned int kSampleValue1 = 0x0a0a0a0a;
4219 const SpdySettingsIds kSampleId2 = SETTINGS_INITIAL_WINDOW_SIZE;
4220 unsigned int kSampleValue2 = 0x0c0c0c0c;
4222 // First add a persisted setting.
4223 spdy_session_pool->http_server_properties()->SetSpdySetting(
4224 host_port_pair,
4225 kSampleId1,
4226 SETTINGS_FLAG_PLEASE_PERSIST,
4227 kSampleValue1);
4229 // Next add another persisted setting.
4230 spdy_session_pool->http_server_properties()->SetSpdySetting(
4231 host_port_pair,
4232 kSampleId2,
4233 SETTINGS_FLAG_PLEASE_PERSIST,
4234 kSampleValue2);
4236 EXPECT_EQ(2u, spdy_session_pool->http_server_properties()->GetSpdySettings(
4237 host_port_pair).size());
4239 // Construct the initial SETTINGS frame.
4240 SettingsMap initial_settings;
4241 initial_settings[SETTINGS_MAX_CONCURRENT_STREAMS] =
4242 SettingsFlagsAndValue(SETTINGS_FLAG_NONE, kMaxConcurrentPushedStreams);
4243 scoped_ptr<SpdyFrame> initial_settings_frame(
4244 spdy_util_.ConstructSpdySettings(initial_settings));
4246 // Construct the persisted SETTINGS frame.
4247 const SettingsMap& settings =
4248 spdy_session_pool->http_server_properties()->GetSpdySettings(
4249 host_port_pair);
4250 scoped_ptr<SpdyFrame> settings_frame(
4251 spdy_util_.ConstructSpdySettings(settings));
4253 // Construct the request.
4254 scoped_ptr<SpdyFrame> req(
4255 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
4257 MockWrite writes[] = {
4258 CreateMockWrite(*initial_settings_frame, 0),
4259 CreateMockWrite(*settings_frame, 1),
4260 CreateMockWrite(*req, 2),
4263 // Construct the reply.
4264 scoped_ptr<SpdyHeaderBlock> reply_headers(new SpdyHeaderBlock());
4265 (*reply_headers)[spdy_util_.GetStatusKey()] = "200";
4266 (*reply_headers)[spdy_util_.GetVersionKey()] = "HTTP/1.1";
4267 scoped_ptr<SpdyFrame> reply(
4268 spdy_util_.ConstructSpdyFrame(kSynReplyInfo, reply_headers.Pass()));
4270 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
4271 MockRead reads[] = {
4272 CreateMockRead(*reply, 3),
4273 CreateMockRead(*body, 4),
4274 MockRead(ASYNC, 0, 5) // EOF
4277 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
4278 helper.AddData(&data);
4279 helper.RunDefaultTest();
4280 helper.VerifyDataConsumed();
4281 TransactionHelperResult out = helper.output();
4282 EXPECT_EQ(OK, out.rv);
4283 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
4284 EXPECT_EQ("hello!", out.response_data);
4287 // Verify we had two persisted settings.
4288 const SettingsMap& settings_map =
4289 spdy_session_pool->http_server_properties()->GetSpdySettings(
4290 host_port_pair);
4291 ASSERT_EQ(2u, settings_map.size());
4293 // Verify the first persisted setting.
4294 SettingsMap::const_iterator it1 = settings_map.find(kSampleId1);
4295 EXPECT_TRUE(it1 != settings_map.end());
4296 SettingsFlagsAndValue flags_and_value1 = it1->second;
4297 EXPECT_EQ(SETTINGS_FLAG_PERSISTED, flags_and_value1.first);
4298 EXPECT_EQ(kSampleValue1, flags_and_value1.second);
4300 // Verify the second persisted setting.
4301 SettingsMap::const_iterator it2 = settings_map.find(kSampleId2);
4302 EXPECT_TRUE(it2 != settings_map.end());
4303 SettingsFlagsAndValue flags_and_value2 = it2->second;
4304 EXPECT_EQ(SETTINGS_FLAG_PERSISTED, flags_and_value2.first);
4305 EXPECT_EQ(kSampleValue2, flags_and_value2.second);
4309 TEST_P(SpdyNetworkTransactionTest, GoAwayWithActiveStream) {
4310 scoped_ptr<SpdyFrame> req(
4311 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
4312 MockWrite writes[] = {CreateMockWrite(*req, 0)};
4314 scoped_ptr<SpdyFrame> go_away(spdy_util_.ConstructSpdyGoAway());
4315 MockRead reads[] = {
4316 CreateMockRead(*go_away, 1),
4319 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
4320 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
4321 BoundNetLog(), GetParam(), NULL);
4322 helper.AddData(&data);
4323 helper.RunToCompletion(&data);
4324 TransactionHelperResult out = helper.output();
4325 EXPECT_EQ(ERR_ABORTED, out.rv);
4328 TEST_P(SpdyNetworkTransactionTest, CloseWithActiveStream) {
4329 scoped_ptr<SpdyFrame> req(
4330 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
4331 MockWrite writes[] = {CreateMockWrite(*req, 0)};
4333 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
4334 MockRead reads[] = {
4335 CreateMockRead(*resp, 1), MockRead(SYNCHRONOUS, 0, 2) // EOF
4338 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
4339 BoundNetLog log;
4340 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
4341 log, GetParam(), NULL);
4342 helper.RunPreTestSetup();
4343 helper.AddData(&data);
4344 HttpNetworkTransaction* trans = helper.trans();
4346 TestCompletionCallback callback;
4347 TransactionHelperResult out;
4348 out.rv = trans->Start(&CreateGetRequest(), callback.callback(), log);
4350 EXPECT_EQ(out.rv, ERR_IO_PENDING);
4351 out.rv = callback.WaitForResult();
4352 EXPECT_EQ(out.rv, OK);
4354 const HttpResponseInfo* response = trans->GetResponseInfo();
4355 EXPECT_TRUE(response->headers.get() != NULL);
4356 EXPECT_TRUE(response->was_fetched_via_spdy);
4357 out.rv = ReadTransaction(trans, &out.response_data);
4358 EXPECT_EQ(ERR_CONNECTION_CLOSED, out.rv);
4360 // Verify that we consumed all test data.
4361 helper.VerifyDataConsumed();
4364 // HTTP_1_1_REQUIRED results in ERR_HTTP_1_1_REQUIRED.
4365 TEST_P(SpdyNetworkTransactionTest, HTTP11RequiredError) {
4366 // HTTP_1_1_REQUIRED is only supported by HTTP/2.
4367 if (spdy_util_.spdy_version() < HTTP2)
4368 return;
4370 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
4371 BoundNetLog(), GetParam(), nullptr);
4373 scoped_ptr<SpdyFrame> go_away(spdy_util_.ConstructSpdyGoAway(
4374 0, GOAWAY_HTTP_1_1_REQUIRED, "Try again using HTTP/1.1 please."));
4375 MockRead reads[] = {
4376 CreateMockRead(*go_away, 0),
4378 SequencedSocketData data(reads, arraysize(reads), nullptr, 0);
4380 helper.RunToCompletion(&data);
4381 TransactionHelperResult out = helper.output();
4382 EXPECT_EQ(ERR_HTTP_1_1_REQUIRED, out.rv);
4385 // Retry with HTTP/1.1 when receiving HTTP_1_1_REQUIRED. Note that no actual
4386 // protocol negotiation happens, instead this test forces protocols for both
4387 // sockets.
4388 TEST_P(SpdyNetworkTransactionTest, HTTP11RequiredRetry) {
4389 // HTTP_1_1_REQUIRED is only supported by HTTP/2.
4390 if (spdy_util_.spdy_version() < HTTP2)
4391 return;
4392 // HTTP_1_1_REQUIRED implementation relies on the assumption that HTTP/2 is
4393 // only spoken over SSL.
4394 if (GetParam().ssl_type != HTTPS_SPDY_VIA_NPN)
4395 return;
4397 HttpRequestInfo request;
4398 request.method = "GET";
4399 request.url = GURL("https://www.example.org/");
4400 scoped_ptr<SpdySessionDependencies> session_deps(
4401 CreateSpdySessionDependencies(GetParam()));
4402 // Do not force SPDY so that second socket can negotiate HTTP/1.1.
4403 session_deps->next_protos = SpdyNextProtos();
4404 NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY, BoundNetLog(),
4405 GetParam(), session_deps.Pass());
4407 // First socket: HTTP/2 request rejected with HTTP_1_1_REQUIRED.
4408 const char* url = request.url.spec().c_str();
4409 scoped_ptr<SpdyHeaderBlock> headers(spdy_util_.ConstructGetHeaderBlock(url));
4410 scoped_ptr<SpdyFrame> req(
4411 spdy_util_.ConstructSpdySyn(1, *headers, LOWEST, false, true));
4412 MockWrite writes0[] = {CreateMockWrite(*req, 0)};
4413 scoped_ptr<SpdyFrame> go_away(spdy_util_.ConstructSpdyGoAway(
4414 0, GOAWAY_HTTP_1_1_REQUIRED, "Try again using HTTP/1.1 please."));
4415 MockRead reads0[] = {CreateMockRead(*go_away, 1)};
4416 SequencedSocketData data0(reads0, arraysize(reads0), writes0,
4417 arraysize(writes0));
4419 scoped_ptr<SSLSocketDataProvider> ssl_provider0(
4420 new SSLSocketDataProvider(ASYNC, OK));
4421 // Expect HTTP/2 protocols too in SSLConfig.
4422 ssl_provider0->next_protos_expected_in_ssl_config.push_back(kProtoHTTP11);
4423 ssl_provider0->next_protos_expected_in_ssl_config.push_back(kProtoSPDY31);
4424 ssl_provider0->next_protos_expected_in_ssl_config.push_back(kProtoHTTP2);
4425 // Force SPDY.
4426 ssl_provider0->SetNextProto(GetParam().protocol);
4427 helper.AddDataWithSSLSocketDataProvider(&data0, ssl_provider0.Pass());
4429 // Second socket: falling back to HTTP/1.1.
4430 MockWrite writes1[] = {MockWrite(ASYNC, 0,
4431 "GET / HTTP/1.1\r\n"
4432 "Host: www.example.org\r\n"
4433 "Connection: keep-alive\r\n\r\n")};
4434 MockRead reads1[] = {MockRead(ASYNC, 1,
4435 "HTTP/1.1 200 OK\r\n"
4436 "Content-Length: 5\r\n\r\n"
4437 "hello")};
4438 SequencedSocketData data1(reads1, arraysize(reads1), writes1,
4439 arraysize(writes1));
4441 scoped_ptr<SSLSocketDataProvider> ssl_provider1(
4442 new SSLSocketDataProvider(ASYNC, OK));
4443 // Expect only HTTP/1.1 protocol in SSLConfig.
4444 ssl_provider1->next_protos_expected_in_ssl_config.push_back(kProtoHTTP11);
4445 // Force HTTP/1.1.
4446 ssl_provider1->SetNextProto(kProtoHTTP11);
4447 helper.AddDataWithSSLSocketDataProvider(&data1, ssl_provider1.Pass());
4449 base::WeakPtr<HttpServerProperties> http_server_properties =
4450 helper.session()->spdy_session_pool()->http_server_properties();
4451 const HostPortPair host_port_pair = HostPortPair::FromURL(GURL(url));
4452 EXPECT_FALSE(http_server_properties->RequiresHTTP11(host_port_pair));
4454 helper.RunPreTestSetup();
4455 helper.StartDefaultTest();
4456 helper.FinishDefaultTestWithoutVerification();
4457 helper.VerifyDataConsumed();
4458 EXPECT_TRUE(http_server_properties->RequiresHTTP11(host_port_pair));
4460 const HttpResponseInfo* response = helper.trans()->GetResponseInfo();
4461 ASSERT_TRUE(response != nullptr);
4462 ASSERT_TRUE(response->headers.get() != nullptr);
4463 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
4464 EXPECT_FALSE(response->was_fetched_via_spdy);
4465 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP1, response->connection_info);
4466 EXPECT_TRUE(response->was_npn_negotiated);
4467 EXPECT_TRUE(request.url.SchemeIs("https"));
4468 EXPECT_EQ("127.0.0.1", response->socket_address.host());
4469 EXPECT_EQ(443, response->socket_address.port());
4470 std::string response_data;
4471 ASSERT_EQ(OK, ReadTransaction(helper.trans(), &response_data));
4472 EXPECT_EQ("hello", response_data);
4475 // Retry with HTTP/1.1 to the proxy when receiving HTTP_1_1_REQUIRED from the
4476 // proxy. Note that no actual protocol negotiation happens, instead this test
4477 // forces protocols for both sockets.
4478 TEST_P(SpdyNetworkTransactionTest, HTTP11RequiredProxyRetry) {
4479 // HTTP_1_1_REQUIRED is only supported by HTTP/2.
4480 if (spdy_util_.spdy_version() < HTTP2)
4481 return;
4482 // HTTP_1_1_REQUIRED implementation relies on the assumption that HTTP/2 is
4483 // only spoken over SSL.
4484 if (GetParam().ssl_type != HTTPS_SPDY_VIA_NPN)
4485 return;
4487 HttpRequestInfo request;
4488 request.method = "GET";
4489 request.url = GURL("https://www.example.org/");
4490 scoped_ptr<SpdySessionDependencies> session_deps(
4491 CreateSpdySessionDependencies(
4492 GetParam(),
4493 ProxyService::CreateFixedFromPacResult("HTTPS myproxy:70")));
4494 // Do not force SPDY so that second socket can negotiate HTTP/1.1.
4495 session_deps->next_protos = SpdyNextProtos();
4496 NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY, BoundNetLog(),
4497 GetParam(), session_deps.Pass());
4499 // First socket: HTTP/2 CONNECT rejected with HTTP_1_1_REQUIRED.
4500 scoped_ptr<SpdyFrame> req(spdy_util_.ConstructSpdyConnect(
4501 nullptr, 0, 1, LOWEST, HostPortPair("www.example.org", 443)));
4502 MockWrite writes0[] = {CreateMockWrite(*req, 0)};
4503 scoped_ptr<SpdyFrame> go_away(spdy_util_.ConstructSpdyGoAway(
4504 0, GOAWAY_HTTP_1_1_REQUIRED, "Try again using HTTP/1.1 please."));
4505 MockRead reads0[] = {CreateMockRead(*go_away, 1)};
4506 SequencedSocketData data0(reads0, arraysize(reads0), writes0,
4507 arraysize(writes0));
4509 scoped_ptr<SSLSocketDataProvider> ssl_provider0(
4510 new SSLSocketDataProvider(ASYNC, OK));
4511 // Expect HTTP/2 protocols too in SSLConfig.
4512 ssl_provider0->next_protos_expected_in_ssl_config.push_back(kProtoHTTP11);
4513 ssl_provider0->next_protos_expected_in_ssl_config.push_back(kProtoSPDY31);
4514 ssl_provider0->next_protos_expected_in_ssl_config.push_back(kProtoHTTP2);
4515 // Force SPDY.
4516 ssl_provider0->SetNextProto(GetParam().protocol);
4517 helper.AddDataWithSSLSocketDataProvider(&data0, ssl_provider0.Pass());
4519 // Second socket: retry using HTTP/1.1.
4520 MockWrite writes1[] = {
4521 MockWrite(ASYNC, 0,
4522 "CONNECT www.example.org:443 HTTP/1.1\r\n"
4523 "Host: www.example.org\r\n"
4524 "Proxy-Connection: keep-alive\r\n\r\n"),
4525 MockWrite(ASYNC, 2,
4526 "GET / HTTP/1.1\r\n"
4527 "Host: www.example.org\r\n"
4528 "Connection: keep-alive\r\n\r\n"),
4531 MockRead reads1[] = {
4532 MockRead(ASYNC, 1, "HTTP/1.1 200 OK\r\n\r\n"),
4533 MockRead(ASYNC, 3,
4534 "HTTP/1.1 200 OK\r\n"
4535 "Content-Length: 5\r\n\r\n"
4536 "hello"),
4538 SequencedSocketData data1(reads1, arraysize(reads1), writes1,
4539 arraysize(writes1));
4541 scoped_ptr<SSLSocketDataProvider> ssl_provider1(
4542 new SSLSocketDataProvider(ASYNC, OK));
4543 // Expect only HTTP/1.1 protocol in SSLConfig.
4544 ssl_provider1->next_protos_expected_in_ssl_config.push_back(kProtoHTTP11);
4545 // Force HTTP/1.1.
4546 ssl_provider1->SetNextProto(kProtoHTTP11);
4547 helper.AddDataWithSSLSocketDataProvider(&data1, ssl_provider1.Pass());
4549 // A third socket is needed for the tunnelled connection.
4550 scoped_ptr<SSLSocketDataProvider> ssl_provider2(
4551 new SSLSocketDataProvider(ASYNC, OK));
4552 helper.session_deps()->socket_factory->AddSSLSocketDataProvider(
4553 ssl_provider2.get());
4555 base::WeakPtr<HttpServerProperties> http_server_properties =
4556 helper.session()->spdy_session_pool()->http_server_properties();
4557 const HostPortPair proxy_host_port_pair = HostPortPair("myproxy", 70);
4558 EXPECT_FALSE(http_server_properties->RequiresHTTP11(proxy_host_port_pair));
4560 helper.RunPreTestSetup();
4561 helper.StartDefaultTest();
4562 helper.FinishDefaultTestWithoutVerification();
4563 helper.VerifyDataConsumed();
4564 EXPECT_TRUE(http_server_properties->RequiresHTTP11(proxy_host_port_pair));
4566 const HttpResponseInfo* response = helper.trans()->GetResponseInfo();
4567 ASSERT_TRUE(response != nullptr);
4568 ASSERT_TRUE(response->headers.get() != nullptr);
4569 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
4570 EXPECT_FALSE(response->was_fetched_via_spdy);
4571 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP1, response->connection_info);
4572 EXPECT_FALSE(response->was_npn_negotiated);
4573 EXPECT_TRUE(request.url.SchemeIs("https"));
4574 EXPECT_EQ("127.0.0.1", response->socket_address.host());
4575 EXPECT_EQ(70, response->socket_address.port());
4576 std::string response_data;
4577 ASSERT_EQ(OK, ReadTransaction(helper.trans(), &response_data));
4578 EXPECT_EQ("hello", response_data);
4581 // Test to make sure we can correctly connect through a proxy.
4582 TEST_P(SpdyNetworkTransactionTest, ProxyConnect) {
4583 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
4584 BoundNetLog(), GetParam(), NULL);
4585 helper.session_deps() = CreateSpdySessionDependencies(
4586 GetParam(), ProxyService::CreateFixedFromPacResult("PROXY myproxy:70"));
4587 helper.SetSession(make_scoped_refptr(
4588 SpdySessionDependencies::SpdyCreateSession(helper.session_deps().get())));
4589 helper.RunPreTestSetup();
4590 HttpNetworkTransaction* trans = helper.trans();
4592 const char kConnect443[] = {
4593 "CONNECT www.example.org:443 HTTP/1.1\r\n"
4594 "Host: www.example.org\r\n"
4595 "Proxy-Connection: keep-alive\r\n\r\n"};
4596 const char kHTTP200[] = {"HTTP/1.1 200 OK\r\n\r\n"};
4597 scoped_ptr<SpdyFrame> req(
4598 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
4599 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
4600 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
4602 MockWrite writes[] = {
4603 MockWrite(SYNCHRONOUS, kConnect443, arraysize(kConnect443) - 1, 0),
4604 CreateMockWrite(*req, 2),
4606 MockRead reads[] = {
4607 MockRead(SYNCHRONOUS, kHTTP200, arraysize(kHTTP200) - 1, 1),
4608 CreateMockRead(*resp, 3),
4609 CreateMockRead(*body.get(), 4),
4610 MockRead(ASYNC, 0, 0, 5),
4612 scoped_ptr<SequencedSocketData> data(new SequencedSocketData(
4613 reads, arraysize(reads), writes, arraysize(writes)));
4615 helper.AddData(data.get());
4616 TestCompletionCallback callback;
4618 int rv = trans->Start(
4619 &CreateGetRequest(), callback.callback(), BoundNetLog());
4620 EXPECT_EQ(ERR_IO_PENDING, rv);
4622 rv = callback.WaitForResult();
4623 EXPECT_EQ(0, rv);
4625 // Verify the SYN_REPLY.
4626 HttpResponseInfo response = *trans->GetResponseInfo();
4627 EXPECT_TRUE(response.headers.get() != NULL);
4628 EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine());
4630 std::string response_data;
4631 ASSERT_EQ(OK, ReadTransaction(trans, &response_data));
4632 EXPECT_EQ("hello!", response_data);
4633 helper.VerifyDataConsumed();
4636 // Test to make sure we can correctly connect through a proxy to
4637 // www.example.org, if there already exists a direct spdy connection to
4638 // www.example.org. See https://crbug.com/49874.
4639 TEST_P(SpdyNetworkTransactionTest, DirectConnectProxyReconnect) {
4640 // When setting up the first transaction, we store the SpdySessionPool so that
4641 // we can use the same pool in the second transaction.
4642 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
4643 BoundNetLog(), GetParam(), NULL);
4645 // Use a proxy service which returns a proxy fallback list from DIRECT to
4646 // myproxy:70. For this test there will be no fallback, so it is equivalent
4647 // to simply DIRECT. The reason for appending the second proxy is to verify
4648 // that the session pool key used does is just "DIRECT".
4649 helper.session_deps() = CreateSpdySessionDependencies(
4650 GetParam(),
4651 ProxyService::CreateFixedFromPacResult("DIRECT; PROXY myproxy:70"));
4652 helper.SetSession(make_scoped_refptr(
4653 SpdySessionDependencies::SpdyCreateSession(helper.session_deps().get())));
4655 SpdySessionPool* spdy_session_pool = helper.session()->spdy_session_pool();
4656 helper.RunPreTestSetup();
4658 // Construct and send a simple GET request.
4659 scoped_ptr<SpdyFrame> req(
4660 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
4661 MockWrite writes[] = {
4662 CreateMockWrite(*req, 0),
4665 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
4666 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
4667 MockRead reads[] = {
4668 CreateMockRead(*resp, 1),
4669 CreateMockRead(*body, 2),
4670 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 3), // Force a pause
4672 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
4673 helper.AddData(&data);
4674 HttpNetworkTransaction* trans = helper.trans();
4676 TestCompletionCallback callback;
4677 TransactionHelperResult out;
4678 out.rv = trans->Start(
4679 &CreateGetRequest(), callback.callback(), BoundNetLog());
4681 EXPECT_EQ(out.rv, ERR_IO_PENDING);
4682 out.rv = callback.WaitForResult();
4683 EXPECT_EQ(out.rv, OK);
4685 const HttpResponseInfo* response = trans->GetResponseInfo();
4686 EXPECT_TRUE(response->headers.get() != NULL);
4687 EXPECT_TRUE(response->was_fetched_via_spdy);
4688 out.rv = ReadTransaction(trans, &out.response_data);
4689 EXPECT_EQ(OK, out.rv);
4690 out.status_line = response->headers->GetStatusLine();
4691 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
4692 EXPECT_EQ("hello!", out.response_data);
4694 // Check that the SpdySession is still in the SpdySessionPool.
4695 HostPortPair host_port_pair("www.example.org", helper.port());
4696 SpdySessionKey session_pool_key_direct(
4697 host_port_pair, ProxyServer::Direct(), PRIVACY_MODE_DISABLED);
4698 EXPECT_TRUE(HasSpdySession(spdy_session_pool, session_pool_key_direct));
4699 SpdySessionKey session_pool_key_proxy(
4700 host_port_pair,
4701 ProxyServer::FromURI("www.foo.com", ProxyServer::SCHEME_HTTP),
4702 PRIVACY_MODE_DISABLED);
4703 EXPECT_FALSE(HasSpdySession(spdy_session_pool, session_pool_key_proxy));
4705 // Set up data for the proxy connection.
4706 const char kConnect443[] = {
4707 "CONNECT www.example.org:443 HTTP/1.1\r\n"
4708 "Host: www.example.org\r\n"
4709 "Proxy-Connection: keep-alive\r\n\r\n"};
4710 const char kHTTP200[] = {"HTTP/1.1 200 OK\r\n\r\n"};
4711 scoped_ptr<SpdyFrame> req2(spdy_util_.ConstructSpdyGet(
4712 GetDefaultUrlWithPath("/foo.dat").c_str(), false, 1, LOWEST));
4713 scoped_ptr<SpdyFrame> resp2(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
4714 scoped_ptr<SpdyFrame> body2(spdy_util_.ConstructSpdyBodyFrame(1, true));
4716 MockWrite writes2[] = {
4717 MockWrite(SYNCHRONOUS, kConnect443, arraysize(kConnect443) - 1, 0),
4718 CreateMockWrite(*req2, 2),
4720 MockRead reads2[] = {
4721 MockRead(SYNCHRONOUS, kHTTP200, arraysize(kHTTP200) - 1, 1),
4722 CreateMockRead(*resp2, 3),
4723 CreateMockRead(*body2, 4),
4724 MockRead(ASYNC, 0, 5) // EOF
4727 scoped_ptr<SequencedSocketData> data_proxy(new SequencedSocketData(
4728 reads2, arraysize(reads2), writes2, arraysize(writes2)));
4730 // Create another request to www.example.org, but this time through a proxy.
4731 HttpRequestInfo request_proxy;
4732 request_proxy.method = "GET";
4733 request_proxy.url = GURL(GetDefaultUrlWithPath("/foo.dat"));
4734 request_proxy.load_flags = 0;
4735 scoped_ptr<SpdySessionDependencies> ssd_proxy(
4736 CreateSpdySessionDependencies(GetParam()));
4737 // Ensure that this transaction uses the same SpdySessionPool.
4738 scoped_refptr<HttpNetworkSession> session_proxy(
4739 SpdySessionDependencies::SpdyCreateSession(ssd_proxy.get()));
4740 NormalSpdyTransactionHelper helper_proxy(request_proxy, DEFAULT_PRIORITY,
4741 BoundNetLog(), GetParam(), NULL);
4742 HttpNetworkSessionPeer session_peer(session_proxy);
4743 scoped_ptr<ProxyService> proxy_service(
4744 ProxyService::CreateFixedFromPacResult("PROXY myproxy:70"));
4745 session_peer.SetProxyService(proxy_service.get());
4746 helper_proxy.session_deps().swap(ssd_proxy);
4747 helper_proxy.SetSession(session_proxy);
4748 helper_proxy.RunPreTestSetup();
4749 helper_proxy.AddData(data_proxy.get());
4751 HttpNetworkTransaction* trans_proxy = helper_proxy.trans();
4752 TestCompletionCallback callback_proxy;
4753 int rv = trans_proxy->Start(
4754 &request_proxy, callback_proxy.callback(), BoundNetLog());
4755 EXPECT_EQ(ERR_IO_PENDING, rv);
4756 rv = callback_proxy.WaitForResult();
4757 EXPECT_EQ(0, rv);
4759 HttpResponseInfo response_proxy = *trans_proxy->GetResponseInfo();
4760 EXPECT_TRUE(response_proxy.headers.get() != NULL);
4761 EXPECT_EQ("HTTP/1.1 200 OK", response_proxy.headers->GetStatusLine());
4763 std::string response_data;
4764 ASSERT_EQ(OK, ReadTransaction(trans_proxy, &response_data));
4765 EXPECT_EQ("hello!", response_data);
4767 helper_proxy.VerifyDataConsumed();
4770 // When we get a TCP-level RST, we need to retry a HttpNetworkTransaction
4771 // on a new connection, if the connection was previously known to be good.
4772 // This can happen when a server reboots without saying goodbye, or when
4773 // we're behind a NAT that masked the RST.
4774 TEST_P(SpdyNetworkTransactionTest, VerifyRetryOnConnectionReset) {
4775 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
4776 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
4777 MockRead reads[] = {
4778 CreateMockRead(*resp, 1),
4779 CreateMockRead(*body, 2),
4780 MockRead(ASYNC, ERR_IO_PENDING, 3),
4781 MockRead(ASYNC, ERR_CONNECTION_RESET, 4),
4784 MockRead reads2[] = {
4785 CreateMockRead(*resp, 1),
4786 CreateMockRead(*body, 2),
4787 MockRead(ASYNC, 0, 3) // EOF
4790 scoped_ptr<SpdyFrame> req(
4791 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
4792 scoped_ptr<SpdyFrame> req3(
4793 spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, LOWEST, true));
4794 MockWrite writes1[] = {CreateMockWrite(*req, 0), CreateMockWrite(*req3, 5)};
4795 MockWrite writes2[] = {CreateMockWrite(*req, 0)};
4797 // This test has a couple of variants.
4798 enum {
4799 // Induce the RST while waiting for our transaction to send.
4800 VARIANT_RST_DURING_SEND_COMPLETION = 0,
4801 // Induce the RST while waiting for our transaction to read.
4802 // In this case, the send completed - everything copied into the SNDBUF.
4803 VARIANT_RST_DURING_READ_COMPLETION = 1
4806 for (int variant = VARIANT_RST_DURING_SEND_COMPLETION;
4807 variant <= VARIANT_RST_DURING_READ_COMPLETION;
4808 ++variant) {
4809 SequencedSocketData data1(reads, arraysize(reads), writes1, 1 + variant);
4811 SequencedSocketData data2(reads2, arraysize(reads2), writes2,
4812 arraysize(writes2));
4814 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
4815 BoundNetLog(), GetParam(), NULL);
4816 helper.AddData(&data1);
4817 helper.AddData(&data2);
4818 helper.RunPreTestSetup();
4820 for (int i = 0; i < 2; ++i) {
4821 scoped_ptr<HttpNetworkTransaction> trans(
4822 new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get()));
4824 TestCompletionCallback callback;
4825 int rv = trans->Start(
4826 &helper.request(), callback.callback(), BoundNetLog());
4827 EXPECT_EQ(ERR_IO_PENDING, rv);
4828 // On the second transaction, we trigger the RST.
4829 if (i == 1) {
4830 if (variant == VARIANT_RST_DURING_READ_COMPLETION) {
4831 // Writes to the socket complete asynchronously on SPDY by running
4832 // through the message loop. Complete the write here.
4833 base::RunLoop().RunUntilIdle();
4836 // Now schedule the ERR_CONNECTION_RESET.
4837 data1.CompleteRead();
4839 rv = callback.WaitForResult();
4840 EXPECT_EQ(OK, rv);
4842 const HttpResponseInfo* response = trans->GetResponseInfo();
4843 ASSERT_TRUE(response != NULL);
4844 EXPECT_TRUE(response->headers.get() != NULL);
4845 EXPECT_TRUE(response->was_fetched_via_spdy);
4846 std::string response_data;
4847 rv = ReadTransaction(trans.get(), &response_data);
4848 EXPECT_EQ(OK, rv);
4849 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
4850 EXPECT_EQ("hello!", response_data);
4851 base::RunLoop().RunUntilIdle();
4854 helper.VerifyDataConsumed();
4855 base::RunLoop().RunUntilIdle();
4859 // Test that turning SPDY on and off works properly.
4860 TEST_P(SpdyNetworkTransactionTest, SpdyOnOffToggle) {
4861 HttpStreamFactory::set_spdy_enabled(true);
4862 scoped_ptr<SpdyFrame> req(
4863 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
4864 MockWrite spdy_writes[] = {CreateMockWrite(*req, 0)};
4866 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
4867 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
4868 MockRead spdy_reads[] = {
4869 CreateMockRead(*resp, 1),
4870 CreateMockRead(*body, 2),
4871 MockRead(ASYNC, 0, 3) // EOF
4874 SequencedSocketData data(spdy_reads, arraysize(spdy_reads), spdy_writes,
4875 arraysize(spdy_writes));
4876 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
4877 BoundNetLog(), GetParam(), NULL);
4878 helper.RunToCompletion(&data);
4879 TransactionHelperResult out = helper.output();
4880 EXPECT_EQ(OK, out.rv);
4881 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
4882 EXPECT_EQ("hello!", out.response_data);
4884 HttpStreamFactory::set_spdy_enabled(false);
4885 MockWrite http_writes[] = {
4886 MockWrite(SYNCHRONOUS, 0,
4887 "GET / HTTP/1.1\r\n"
4888 "Host: www.example.org\r\n"
4889 "Connection: keep-alive\r\n\r\n"),
4892 MockRead http_reads[] = {
4893 MockRead(SYNCHRONOUS, 1, "HTTP/1.1 200 OK\r\n\r\n"),
4894 MockRead(SYNCHRONOUS, 2, "hello from http"),
4895 MockRead(SYNCHRONOUS, OK, 3),
4897 SequencedSocketData data2(http_reads, arraysize(http_reads), http_writes,
4898 arraysize(http_writes));
4899 NormalSpdyTransactionHelper helper2(CreateGetRequest(), DEFAULT_PRIORITY,
4900 BoundNetLog(), GetParam(), NULL);
4901 helper2.SetSpdyDisabled();
4902 helper2.RunToCompletion(&data2);
4903 TransactionHelperResult out2 = helper2.output();
4904 EXPECT_EQ(OK, out2.rv);
4905 EXPECT_EQ("HTTP/1.1 200 OK", out2.status_line);
4906 EXPECT_EQ("hello from http", out2.response_data);
4908 HttpStreamFactory::set_spdy_enabled(true);
4911 // Tests that Basic authentication works over SPDY
4912 TEST_P(SpdyNetworkTransactionTest, SpdyBasicAuth) {
4913 HttpStreamFactory::set_spdy_enabled(true);
4915 // The first request will be a bare GET, the second request will be a
4916 // GET with an Authorization header.
4917 scoped_ptr<SpdyFrame> req_get(
4918 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
4919 const char* const kExtraAuthorizationHeaders[] = {
4920 "authorization", "Basic Zm9vOmJhcg=="
4922 scoped_ptr<SpdyFrame> req_get_authorization(
4923 spdy_util_.ConstructSpdyGet(kExtraAuthorizationHeaders,
4924 arraysize(kExtraAuthorizationHeaders) / 2,
4925 false, 3, LOWEST, true));
4926 MockWrite spdy_writes[] = {
4927 CreateMockWrite(*req_get, 0), CreateMockWrite(*req_get_authorization, 3),
4930 // The first response is a 401 authentication challenge, and the second
4931 // response will be a 200 response since the second request includes a valid
4932 // Authorization header.
4933 const char* const kExtraAuthenticationHeaders[] = {
4934 "www-authenticate",
4935 "Basic realm=\"MyRealm\""
4937 scoped_ptr<SpdyFrame> resp_authentication(
4938 spdy_util_.ConstructSpdySynReplyError(
4939 "401 Authentication Required",
4940 kExtraAuthenticationHeaders,
4941 arraysize(kExtraAuthenticationHeaders) / 2,
4942 1));
4943 scoped_ptr<SpdyFrame> body_authentication(
4944 spdy_util_.ConstructSpdyBodyFrame(1, true));
4945 scoped_ptr<SpdyFrame> resp_data(
4946 spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3));
4947 scoped_ptr<SpdyFrame> body_data(spdy_util_.ConstructSpdyBodyFrame(3, true));
4948 MockRead spdy_reads[] = {
4949 CreateMockRead(*resp_authentication, 1),
4950 CreateMockRead(*body_authentication, 2),
4951 CreateMockRead(*resp_data, 4),
4952 CreateMockRead(*body_data, 5),
4953 MockRead(ASYNC, 0, 6),
4956 SequencedSocketData data(spdy_reads, arraysize(spdy_reads), spdy_writes,
4957 arraysize(spdy_writes));
4958 HttpRequestInfo request(CreateGetRequest());
4959 BoundNetLog net_log;
4960 NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY,
4961 net_log, GetParam(), NULL);
4963 helper.RunPreTestSetup();
4964 helper.AddData(&data);
4965 HttpNetworkTransaction* trans = helper.trans();
4966 TestCompletionCallback callback;
4967 const int rv_start = trans->Start(&request, callback.callback(), net_log);
4968 EXPECT_EQ(ERR_IO_PENDING, rv_start);
4969 const int rv_start_complete = callback.WaitForResult();
4970 EXPECT_EQ(OK, rv_start_complete);
4972 // Make sure the response has an auth challenge.
4973 const HttpResponseInfo* const response_start = trans->GetResponseInfo();
4974 ASSERT_TRUE(response_start != NULL);
4975 ASSERT_TRUE(response_start->headers.get() != NULL);
4976 EXPECT_EQ(401, response_start->headers->response_code());
4977 EXPECT_TRUE(response_start->was_fetched_via_spdy);
4978 AuthChallengeInfo* auth_challenge = response_start->auth_challenge.get();
4979 ASSERT_TRUE(auth_challenge != NULL);
4980 EXPECT_FALSE(auth_challenge->is_proxy);
4981 EXPECT_EQ("basic", auth_challenge->scheme);
4982 EXPECT_EQ("MyRealm", auth_challenge->realm);
4984 // Restart with a username/password.
4985 AuthCredentials credentials(base::ASCIIToUTF16("foo"),
4986 base::ASCIIToUTF16("bar"));
4987 TestCompletionCallback callback_restart;
4988 const int rv_restart = trans->RestartWithAuth(
4989 credentials, callback_restart.callback());
4990 EXPECT_EQ(ERR_IO_PENDING, rv_restart);
4991 const int rv_restart_complete = callback_restart.WaitForResult();
4992 EXPECT_EQ(OK, rv_restart_complete);
4993 // TODO(cbentzel): This is actually the same response object as before, but
4994 // data has changed.
4995 const HttpResponseInfo* const response_restart = trans->GetResponseInfo();
4996 ASSERT_TRUE(response_restart != NULL);
4997 ASSERT_TRUE(response_restart->headers.get() != NULL);
4998 EXPECT_EQ(200, response_restart->headers->response_code());
4999 EXPECT_TRUE(response_restart->auth_challenge.get() == NULL);
5002 TEST_P(SpdyNetworkTransactionTest, ServerPushWithHeaders) {
5003 scoped_ptr<SpdyFrame> stream1_syn(
5004 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
5005 scoped_ptr<SpdyFrame> stream1_body(
5006 spdy_util_.ConstructSpdyBodyFrame(1, true));
5007 MockWrite writes[] = {
5008 CreateMockWrite(*stream1_syn, 0),
5011 scoped_ptr<SpdyHeaderBlock> initial_headers(new SpdyHeaderBlock());
5012 spdy_util_.AddUrlToHeaderBlock(GetDefaultUrlWithPath("/foo.dat"),
5013 initial_headers.get());
5014 scoped_ptr<SpdyFrame> stream2_syn(
5015 spdy_util_.ConstructInitialSpdyPushFrame(initial_headers.Pass(), 2, 1));
5017 scoped_ptr<SpdyHeaderBlock> late_headers(new SpdyHeaderBlock());
5018 (*late_headers)["hello"] = "bye";
5019 (*late_headers)[spdy_util_.GetStatusKey()] = "200";
5020 (*late_headers)[spdy_util_.GetVersionKey()] = "HTTP/1.1";
5021 scoped_ptr<SpdyFrame> stream2_headers(
5022 spdy_util_.ConstructSpdyControlFrame(late_headers.Pass(),
5023 false,
5025 LOWEST,
5026 HEADERS,
5027 CONTROL_FLAG_NONE,
5028 0));
5030 scoped_ptr<SpdyFrame>
5031 stream1_reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
5032 const char kPushedData[] = "pushed";
5033 scoped_ptr<SpdyFrame> stream2_body(
5034 spdy_util_.ConstructSpdyBodyFrame(
5035 2, kPushedData, strlen(kPushedData), true));
5036 MockRead reads[] = {
5037 CreateMockRead(*stream1_reply, 1),
5038 CreateMockRead(*stream2_syn, 2),
5039 CreateMockRead(*stream2_headers, 3),
5040 CreateMockRead(*stream1_body, 4, SYNCHRONOUS),
5041 CreateMockRead(*stream2_body, 5),
5042 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 6), // Force a pause
5045 HttpResponseInfo response;
5046 HttpResponseInfo response2;
5047 std::string expected_push_result("pushed");
5048 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
5049 RunServerPushTest(&data,
5050 &response,
5051 &response2,
5052 expected_push_result);
5054 // Verify the SYN_REPLY.
5055 EXPECT_TRUE(response.headers.get() != NULL);
5056 EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine());
5058 // Verify the pushed stream.
5059 EXPECT_TRUE(response2.headers.get() != NULL);
5060 EXPECT_EQ("HTTP/1.1 200 OK", response2.headers->GetStatusLine());
5063 TEST_P(SpdyNetworkTransactionTest, ServerPushClaimBeforeHeaders) {
5064 // We push a stream and attempt to claim it before the headers come down.
5065 scoped_ptr<SpdyFrame> stream1_syn(
5066 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
5067 scoped_ptr<SpdyFrame> stream1_body(
5068 spdy_util_.ConstructSpdyBodyFrame(1, true));
5069 MockWrite writes[] = {
5070 CreateMockWrite(*stream1_syn, 0, SYNCHRONOUS),
5073 scoped_ptr<SpdyHeaderBlock> initial_headers(new SpdyHeaderBlock());
5074 spdy_util_.AddUrlToHeaderBlock(GetDefaultUrlWithPath("/foo.dat"),
5075 initial_headers.get());
5076 scoped_ptr<SpdyFrame> stream2_syn(
5077 spdy_util_.ConstructInitialSpdyPushFrame(initial_headers.Pass(), 2, 1));
5079 scoped_ptr<SpdyHeaderBlock> late_headers(new SpdyHeaderBlock());
5080 (*late_headers)["hello"] = "bye";
5081 (*late_headers)[spdy_util_.GetStatusKey()] = "200";
5082 (*late_headers)[spdy_util_.GetVersionKey()] = "HTTP/1.1";
5083 scoped_ptr<SpdyFrame> stream2_headers(
5084 spdy_util_.ConstructSpdyControlFrame(late_headers.Pass(),
5085 false,
5087 LOWEST,
5088 HEADERS,
5089 CONTROL_FLAG_NONE,
5090 0));
5092 scoped_ptr<SpdyFrame>
5093 stream1_reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
5094 const char kPushedData[] = "pushed";
5095 scoped_ptr<SpdyFrame> stream2_body(
5096 spdy_util_.ConstructSpdyBodyFrame(
5097 2, kPushedData, strlen(kPushedData), true));
5098 MockRead reads[] = {
5099 CreateMockRead(*stream1_reply, 1),
5100 CreateMockRead(*stream2_syn, 2),
5101 CreateMockRead(*stream1_body, 3),
5102 CreateMockRead(*stream2_headers, 4),
5103 CreateMockRead(*stream2_body, 5),
5104 MockRead(ASYNC, 0, 6), // EOF
5107 HttpResponseInfo response;
5108 HttpResponseInfo response2;
5109 std::string expected_push_result("pushed");
5110 DeterministicSocketData data(reads, arraysize(reads),
5111 writes, arraysize(writes));
5113 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
5114 BoundNetLog(), GetParam(), NULL);
5115 helper.SetDeterministic();
5116 helper.AddDeterministicData(&data);
5117 helper.RunPreTestSetup();
5119 HttpNetworkTransaction* trans = helper.trans();
5121 // Run until we've received the primary SYN_STREAM, the pushed SYN_STREAM,
5122 // and the body of the primary stream, but before we've received the HEADERS
5123 // for the pushed stream.
5124 data.SetStop(3);
5126 // Start the transaction.
5127 TestCompletionCallback callback;
5128 int rv = trans->Start(
5129 &CreateGetRequest(), callback.callback(), BoundNetLog());
5130 EXPECT_EQ(ERR_IO_PENDING, rv);
5131 data.Run();
5132 rv = callback.WaitForResult();
5133 EXPECT_EQ(0, rv);
5135 // Request the pushed path. At this point, we've received the push, but the
5136 // headers are not yet complete.
5137 scoped_ptr<HttpNetworkTransaction> trans2(
5138 new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get()));
5139 rv = trans2->Start(
5140 &CreateGetPushRequest(), callback.callback(), BoundNetLog());
5141 EXPECT_EQ(ERR_IO_PENDING, rv);
5142 data.RunFor(3);
5143 base::RunLoop().RunUntilIdle();
5145 // Read the server push body.
5146 std::string result2;
5147 ReadResult(trans2.get(), &result2);
5148 // Read the response body.
5149 std::string result;
5150 ReadResult(trans, &result);
5152 // Verify that the received push data is same as the expected push data.
5153 EXPECT_EQ(result2.compare(expected_push_result), 0)
5154 << "Received data: "
5155 << result2
5156 << "||||| Expected data: "
5157 << expected_push_result;
5159 // Verify the SYN_REPLY.
5160 // Copy the response info, because trans goes away.
5161 response = *trans->GetResponseInfo();
5162 response2 = *trans2->GetResponseInfo();
5164 VerifyStreamsClosed(helper);
5166 // Verify the SYN_REPLY.
5167 EXPECT_TRUE(response.headers.get() != NULL);
5168 EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine());
5170 // Verify the pushed stream.
5171 EXPECT_TRUE(response2.headers.get() != NULL);
5172 EXPECT_EQ("HTTP/1.1 200 OK", response2.headers->GetStatusLine());
5174 // Read the final EOF (which will close the session)
5175 data.RunFor(1);
5177 // Verify that we consumed all test data.
5178 EXPECT_TRUE(data.AllReadDataConsumed());
5179 EXPECT_TRUE(data.AllWriteDataConsumed());
5182 // TODO(baranovich): HTTP 2 does not allow multiple HEADERS frames
5183 TEST_P(SpdyNetworkTransactionTest, ServerPushWithTwoHeaderFrames) {
5184 // We push a stream and attempt to claim it before the headers come down.
5185 scoped_ptr<SpdyFrame> stream1_syn(
5186 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
5187 scoped_ptr<SpdyFrame> stream1_body(
5188 spdy_util_.ConstructSpdyBodyFrame(1, true));
5189 MockWrite writes[] = {
5190 CreateMockWrite(*stream1_syn, 0, SYNCHRONOUS),
5193 scoped_ptr<SpdyHeaderBlock> initial_headers(new SpdyHeaderBlock());
5194 if (spdy_util_.spdy_version() < HTTP2) {
5195 // In HTTP/2 PUSH_PROMISE headers won't show up in the response headers.
5196 (*initial_headers)["alpha"] = "beta";
5198 spdy_util_.AddUrlToHeaderBlock(GetDefaultUrlWithPath("/foo.dat"),
5199 initial_headers.get());
5200 scoped_ptr<SpdyFrame> stream2_syn(
5201 spdy_util_.ConstructInitialSpdyPushFrame(initial_headers.Pass(), 2, 1));
5203 scoped_ptr<SpdyHeaderBlock> middle_headers(new SpdyHeaderBlock());
5204 (*middle_headers)["hello"] = "bye";
5205 scoped_ptr<SpdyFrame> stream2_headers1(
5206 spdy_util_.ConstructSpdyControlFrame(middle_headers.Pass(),
5207 false,
5209 LOWEST,
5210 HEADERS,
5211 CONTROL_FLAG_NONE,
5212 0));
5214 scoped_ptr<SpdyHeaderBlock> late_headers(new SpdyHeaderBlock());
5215 (*late_headers)[spdy_util_.GetStatusKey()] = "200";
5216 if (spdy_util_.spdy_version() < HTTP2) {
5217 // HTTP/2 eliminates use of the :version header.
5218 (*late_headers)[spdy_util_.GetVersionKey()] = "HTTP/1.1";
5220 scoped_ptr<SpdyFrame> stream2_headers2(
5221 spdy_util_.ConstructSpdyControlFrame(late_headers.Pass(),
5222 false,
5224 LOWEST,
5225 HEADERS,
5226 CONTROL_FLAG_NONE,
5227 0));
5229 scoped_ptr<SpdyFrame>
5230 stream1_reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
5231 const char kPushedData[] = "pushed";
5232 scoped_ptr<SpdyFrame> stream2_body(
5233 spdy_util_.ConstructSpdyBodyFrame(
5234 2, kPushedData, strlen(kPushedData), true));
5235 MockRead reads[] = {
5236 CreateMockRead(*stream1_reply, 1),
5237 CreateMockRead(*stream2_syn, 2),
5238 CreateMockRead(*stream1_body, 3),
5239 CreateMockRead(*stream2_headers1, 4),
5240 CreateMockRead(*stream2_headers2, 5),
5241 CreateMockRead(*stream2_body, 6),
5242 MockRead(ASYNC, 0, 7), // EOF
5245 HttpResponseInfo response;
5246 HttpResponseInfo response2;
5247 std::string expected_push_result("pushed");
5248 DeterministicSocketData data(reads, arraysize(reads),
5249 writes, arraysize(writes));
5251 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
5252 BoundNetLog(), GetParam(), NULL);
5253 helper.SetDeterministic();
5254 helper.AddDeterministicData(&data);
5255 helper.RunPreTestSetup();
5257 HttpNetworkTransaction* trans = helper.trans();
5259 // Run until we've received the primary SYN_STREAM, the pushed SYN_STREAM,
5260 // the first HEADERS frame, and the body of the primary stream, but before
5261 // we've received the final HEADERS for the pushed stream.
5262 data.SetStop(4);
5264 // Start the transaction.
5265 TestCompletionCallback callback;
5266 int rv = trans->Start(
5267 &CreateGetRequest(), callback.callback(), BoundNetLog());
5268 EXPECT_EQ(ERR_IO_PENDING, rv);
5269 data.Run();
5270 rv = callback.WaitForResult();
5271 EXPECT_EQ(0, rv);
5273 // Request the pushed path. At this point, we've received the push, but the
5274 // headers are not yet complete.
5275 scoped_ptr<HttpNetworkTransaction> trans2(
5276 new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get()));
5277 rv = trans2->Start(
5278 &CreateGetPushRequest(), callback.callback(), BoundNetLog());
5279 EXPECT_EQ(ERR_IO_PENDING, rv);
5280 data.RunFor(3);
5281 base::RunLoop().RunUntilIdle();
5283 // Read the server push body.
5284 std::string result2;
5285 ReadResult(trans2.get(), &result2);
5286 // Read the response body.
5287 std::string result;
5288 ReadResult(trans, &result);
5290 // Verify that the received push data is same as the expected push data.
5291 EXPECT_EQ(expected_push_result, result2);
5293 // Verify the SYN_REPLY.
5294 // Copy the response info, because trans goes away.
5295 response = *trans->GetResponseInfo();
5296 response2 = *trans2->GetResponseInfo();
5298 VerifyStreamsClosed(helper);
5300 // Verify the SYN_REPLY.
5301 EXPECT_TRUE(response.headers.get() != NULL);
5302 EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine());
5304 // Verify the pushed stream.
5305 EXPECT_TRUE(response2.headers.get() != NULL);
5306 EXPECT_EQ("HTTP/1.1 200 OK", response2.headers->GetStatusLine());
5308 // Verify we got all the headers from all header blocks.
5309 if (spdy_util_.spdy_version() < HTTP2)
5310 EXPECT_TRUE(response2.headers->HasHeaderValue("alpha", "beta"));
5311 EXPECT_TRUE(response2.headers->HasHeaderValue("hello", "bye"));
5312 EXPECT_TRUE(response2.headers->HasHeaderValue("status", "200"));
5314 // Read the final EOF (which will close the session)
5315 data.RunFor(1);
5317 // Verify that we consumed all test data.
5318 EXPECT_TRUE(data.AllReadDataConsumed());
5319 EXPECT_TRUE(data.AllWriteDataConsumed());
5322 TEST_P(SpdyNetworkTransactionTest, ServerPushWithNoStatusHeaderFrames) {
5323 // We push a stream and attempt to claim it before the headers come down.
5324 scoped_ptr<SpdyFrame> stream1_syn(
5325 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
5326 scoped_ptr<SpdyFrame> stream1_body(
5327 spdy_util_.ConstructSpdyBodyFrame(1, true));
5328 MockWrite writes[] = {
5329 CreateMockWrite(*stream1_syn, 0, SYNCHRONOUS),
5332 scoped_ptr<SpdyHeaderBlock> initial_headers(new SpdyHeaderBlock());
5333 spdy_util_.AddUrlToHeaderBlock(GetDefaultUrlWithPath("/foo.dat"),
5334 initial_headers.get());
5335 scoped_ptr<SpdyFrame> stream2_syn(
5336 spdy_util_.ConstructInitialSpdyPushFrame(initial_headers.Pass(), 2, 1));
5338 scoped_ptr<SpdyHeaderBlock> middle_headers(new SpdyHeaderBlock());
5339 (*middle_headers)["hello"] = "bye";
5340 scoped_ptr<SpdyFrame> stream2_headers1(
5341 spdy_util_.ConstructSpdyControlFrame(middle_headers.Pass(),
5342 false,
5344 LOWEST,
5345 HEADERS,
5346 CONTROL_FLAG_NONE,
5347 0));
5349 scoped_ptr<SpdyFrame>
5350 stream1_reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
5351 const char kPushedData[] = "pushed";
5352 scoped_ptr<SpdyFrame> stream2_body(
5353 spdy_util_.ConstructSpdyBodyFrame(
5354 2, kPushedData, strlen(kPushedData), true));
5355 MockRead reads[] = {
5356 CreateMockRead(*stream1_reply, 1),
5357 CreateMockRead(*stream2_syn, 2),
5358 CreateMockRead(*stream1_body, 3),
5359 CreateMockRead(*stream2_headers1, 4),
5360 CreateMockRead(*stream2_body, 5),
5361 MockRead(ASYNC, 0, 6), // EOF
5364 DeterministicSocketData data(reads, arraysize(reads),
5365 writes, arraysize(writes));
5367 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
5368 BoundNetLog(), GetParam(), NULL);
5369 helper.SetDeterministic();
5370 helper.AddDeterministicData(&data);
5371 helper.RunPreTestSetup();
5373 HttpNetworkTransaction* trans = helper.trans();
5375 // Run until we've received the primary SYN_STREAM, the pushed SYN_STREAM,
5376 // the first HEADERS frame, and the body of the primary stream, but before
5377 // we've received the final HEADERS for the pushed stream.
5378 data.SetStop(4);
5380 // Start the transaction.
5381 TestCompletionCallback callback;
5382 int rv = trans->Start(
5383 &CreateGetRequest(), callback.callback(), BoundNetLog());
5384 EXPECT_EQ(ERR_IO_PENDING, rv);
5385 data.Run();
5386 rv = callback.WaitForResult();
5387 EXPECT_EQ(0, rv);
5389 // Request the pushed path. At this point, we've received the push, but the
5390 // headers are not yet complete.
5391 scoped_ptr<HttpNetworkTransaction> trans2(
5392 new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get()));
5393 rv = trans2->Start(
5394 &CreateGetPushRequest(), callback.callback(), BoundNetLog());
5395 EXPECT_EQ(ERR_IO_PENDING, rv);
5396 data.RunFor(2);
5397 base::RunLoop().RunUntilIdle();
5399 // Read the server push body.
5400 std::string result2;
5401 ReadResult(trans2.get(), &result2);
5402 // Read the response body.
5403 std::string result;
5404 ReadResult(trans, &result);
5405 EXPECT_EQ("hello!", result);
5407 // Verify that we haven't received any push data.
5408 EXPECT_EQ("", result2);
5410 // Verify the SYN_REPLY.
5411 // Copy the response info, because trans goes away.
5412 HttpResponseInfo response = *trans->GetResponseInfo();
5414 VerifyStreamsClosed(helper);
5416 // Verify the SYN_REPLY.
5417 EXPECT_TRUE(response.headers.get() != NULL);
5418 EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine());
5420 // Read the final EOF (which will close the session).
5421 data.RunFor(1);
5423 // Verify that we consumed all test data.
5424 EXPECT_TRUE(data.AllReadDataConsumed());
5425 EXPECT_TRUE(data.AllWriteDataConsumed());
5428 TEST_P(SpdyNetworkTransactionTest, SynReplyWithHeaders) {
5429 scoped_ptr<SpdyFrame> req(
5430 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
5431 scoped_ptr<SpdyFrame> rst(
5432 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR));
5433 MockWrite writes[] = {
5434 CreateMockWrite(*req, 0), CreateMockWrite(*rst, 4),
5437 scoped_ptr<SpdyFrame> stream1_reply(
5438 spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
5440 scoped_ptr<SpdyHeaderBlock> late_headers(new SpdyHeaderBlock());
5441 (*late_headers)["hello"] = "bye";
5442 scoped_ptr<SpdyFrame> stream1_headers(
5443 spdy_util_.ConstructSpdyControlFrame(late_headers.Pass(),
5444 false,
5446 LOWEST,
5447 HEADERS,
5448 CONTROL_FLAG_NONE,
5449 0));
5450 scoped_ptr<SpdyFrame> stream1_body(
5451 spdy_util_.ConstructSpdyBodyFrame(1, true));
5452 MockRead reads[] = {
5453 CreateMockRead(*stream1_reply, 1),
5454 CreateMockRead(*stream1_headers, 2),
5455 CreateMockRead(*stream1_body, 3),
5456 MockRead(ASYNC, 0, 5) // EOF
5459 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
5460 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
5461 BoundNetLog(), GetParam(), NULL);
5462 helper.RunToCompletion(&data);
5463 TransactionHelperResult out = helper.output();
5464 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, out.rv);
5467 // Tests that receiving HEADERS, DATA, HEADERS, and DATA in that sequence will
5468 // trigger a ERR_SPDY_PROTOCOL_ERROR because trailing HEADERS must not be
5469 // followed by any DATA frames.
5470 TEST_P(SpdyNetworkTransactionTest, SyncReplyDataAfterTrailers) {
5471 scoped_ptr<SpdyFrame> req(
5472 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
5473 scoped_ptr<SpdyFrame> rst(
5474 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR));
5475 MockWrite writes[] = {
5476 CreateMockWrite(*req, 0), CreateMockWrite(*rst, 5),
5479 scoped_ptr<SpdyFrame> stream1_reply(
5480 spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
5482 scoped_ptr<SpdyHeaderBlock> late_headers(new SpdyHeaderBlock());
5483 (*late_headers)["hello"] = "bye";
5484 scoped_ptr<SpdyFrame> stream1_headers(
5485 spdy_util_.ConstructSpdyControlFrame(late_headers.Pass(),
5486 false,
5488 LOWEST,
5489 HEADERS,
5490 CONTROL_FLAG_NONE,
5491 0));
5492 scoped_ptr<SpdyFrame> stream1_body(
5493 spdy_util_.ConstructSpdyBodyFrame(1, false));
5494 scoped_ptr<SpdyFrame> stream1_body2(
5495 spdy_util_.ConstructSpdyBodyFrame(1, true));
5496 MockRead reads[] = {
5497 CreateMockRead(*stream1_reply, 1), CreateMockRead(*stream1_body, 2),
5498 CreateMockRead(*stream1_headers, 3), CreateMockRead(*stream1_body2, 4),
5499 MockRead(ASYNC, 0, 6) // EOF
5502 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
5503 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
5504 BoundNetLog(), GetParam(), NULL);
5505 helper.RunToCompletion(&data);
5506 TransactionHelperResult out = helper.output();
5507 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, out.rv);
5510 TEST_P(SpdyNetworkTransactionTest, ServerPushCrossOriginCorrectness) {
5511 // Running these tests via Alt-Svc is too complicated to be worthwhile.
5512 if (GetParam().ssl_type != HTTPS_SPDY_VIA_NPN)
5513 return;
5515 // In this test we want to verify that we can't accidentally push content
5516 // which can't be pushed by this content server.
5517 // This test assumes that:
5518 // - if we're requesting http://www.foo.com/barbaz
5519 // - the browser has made a connection to "www.foo.com".
5521 // A list of the URL to fetch, followed by the URL being pushed.
5522 static const char* const kTestCases[] = {
5523 "https://www.example.org/foo.html",
5524 "https://www.example.org:81/foo.js", // Bad port
5526 "https://www.example.org/foo.html",
5527 "http://www.example.org/foo.js", // Bad protocol
5529 "https://www.example.org/foo.html",
5530 "ftp://www.example.org/foo.js", // Invalid Protocol
5532 "https://www.example.org/foo.html",
5533 "https://blat.www.example.org/foo.js", // Cross subdomain
5535 "https://www.example.org/foo.html",
5536 "https://www.foo.com/foo.js", // Cross domain
5539 for (size_t index = 0; index < arraysize(kTestCases); index += 2) {
5540 const char* url_to_fetch = kTestCases[index];
5541 const char* url_to_push = kTestCases[index + 1];
5543 scoped_ptr<SpdyFrame> stream1_syn(
5544 spdy_util_.ConstructSpdyGet(url_to_fetch, false, 1, LOWEST));
5545 scoped_ptr<SpdyFrame> stream1_body(
5546 spdy_util_.ConstructSpdyBodyFrame(1, true));
5547 scoped_ptr<SpdyFrame> push_rst(
5548 spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_REFUSED_STREAM));
5549 MockWrite writes[] = {
5550 CreateMockWrite(*stream1_syn, 0), CreateMockWrite(*push_rst, 3),
5553 scoped_ptr<SpdyFrame>
5554 stream1_reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
5555 scoped_ptr<SpdyFrame>
5556 stream2_syn(spdy_util_.ConstructSpdyPush(NULL,
5560 url_to_push));
5561 const char kPushedData[] = "pushed";
5562 scoped_ptr<SpdyFrame> stream2_body(
5563 spdy_util_.ConstructSpdyBodyFrame(
5564 2, kPushedData, strlen(kPushedData), true));
5565 scoped_ptr<SpdyFrame> rst(
5566 spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_CANCEL));
5568 MockRead reads[] = {
5569 CreateMockRead(*stream1_reply, 1),
5570 CreateMockRead(*stream2_syn, 2),
5571 CreateMockRead(*stream1_body, 4),
5572 CreateMockRead(*stream2_body, 5),
5573 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 6), // Force a pause
5576 HttpResponseInfo response;
5577 SequencedSocketData data(reads, arraysize(reads), writes,
5578 arraysize(writes));
5580 HttpRequestInfo request;
5581 request.method = "GET";
5582 request.url = GURL(url_to_fetch);
5583 request.load_flags = 0;
5585 // Enable cross-origin push. Since we are not using a proxy, this should
5586 // not actually enable cross-origin SPDY push.
5587 scoped_ptr<SpdySessionDependencies> session_deps(
5588 CreateSpdySessionDependencies(GetParam()));
5589 session_deps->trusted_spdy_proxy = "123.45.67.89:8080";
5590 NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY, BoundNetLog(),
5591 GetParam(), session_deps.Pass());
5592 helper.RunPreTestSetup();
5593 helper.AddData(&data);
5595 HttpNetworkTransaction* trans = helper.trans();
5597 // Start the transaction with basic parameters.
5598 TestCompletionCallback callback;
5600 int rv = trans->Start(&request, callback.callback(), BoundNetLog());
5601 EXPECT_EQ(ERR_IO_PENDING, rv);
5602 rv = callback.WaitForResult();
5604 // Read the response body.
5605 std::string result;
5606 ReadResult(trans, &result);
5608 // Verify that we consumed all test data.
5609 EXPECT_TRUE(data.AllReadDataConsumed());
5610 EXPECT_TRUE(data.AllWriteDataConsumed());
5612 // Verify the SYN_REPLY.
5613 // Copy the response info, because trans goes away.
5614 response = *trans->GetResponseInfo();
5616 VerifyStreamsClosed(helper);
5618 // Verify the SYN_REPLY.
5619 EXPECT_TRUE(response.headers.get() != NULL);
5620 EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine());
5624 TEST_P(SpdyNetworkTransactionTest, RetryAfterRefused) {
5625 // Construct the request.
5626 scoped_ptr<SpdyFrame> req(
5627 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
5628 scoped_ptr<SpdyFrame> req2(
5629 spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, LOWEST, true));
5630 MockWrite writes[] = {
5631 CreateMockWrite(*req, 0), CreateMockWrite(*req2, 2),
5634 scoped_ptr<SpdyFrame> refused(
5635 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_REFUSED_STREAM));
5636 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3));
5637 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(3, true));
5638 MockRead reads[] = {
5639 CreateMockRead(*refused, 1),
5640 CreateMockRead(*resp, 3),
5641 CreateMockRead(*body, 4),
5642 MockRead(ASYNC, 0, 5) // EOF
5645 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
5646 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
5647 BoundNetLog(), GetParam(), NULL);
5649 helper.RunPreTestSetup();
5650 helper.AddData(&data);
5652 HttpNetworkTransaction* trans = helper.trans();
5654 // Start the transaction with basic parameters.
5655 TestCompletionCallback callback;
5656 int rv = trans->Start(
5657 &CreateGetRequest(), callback.callback(), BoundNetLog());
5658 EXPECT_EQ(ERR_IO_PENDING, rv);
5659 rv = callback.WaitForResult();
5660 EXPECT_EQ(OK, rv);
5662 // Verify that we consumed all test data.
5663 EXPECT_TRUE(data.AllReadDataConsumed());
5664 EXPECT_TRUE(data.AllWriteDataConsumed());
5666 // Verify the SYN_REPLY.
5667 HttpResponseInfo response = *trans->GetResponseInfo();
5668 EXPECT_TRUE(response.headers.get() != NULL);
5669 EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine());
5672 TEST_P(SpdyNetworkTransactionTest, OutOfOrderSynStream) {
5673 // This first request will start to establish the SpdySession.
5674 // Then we will start the second (MEDIUM priority) and then third
5675 // (HIGHEST priority) request in such a way that the third will actually
5676 // start before the second, causing the second to be numbered differently
5677 // than the order they were created.
5678 scoped_ptr<SpdyFrame> req1(
5679 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
5680 scoped_ptr<SpdyFrame> req2(
5681 spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, HIGHEST, true));
5682 scoped_ptr<SpdyFrame> req3(
5683 spdy_util_.ConstructSpdyGet(NULL, 0, false, 5, MEDIUM, true));
5684 MockWrite writes[] = {
5685 CreateMockWrite(*req1, 0),
5686 CreateMockWrite(*req2, 3),
5687 CreateMockWrite(*req3, 4),
5690 scoped_ptr<SpdyFrame> resp1(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
5691 scoped_ptr<SpdyFrame> body1(spdy_util_.ConstructSpdyBodyFrame(1, true));
5692 scoped_ptr<SpdyFrame> resp2(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3));
5693 scoped_ptr<SpdyFrame> body2(spdy_util_.ConstructSpdyBodyFrame(3, true));
5694 scoped_ptr<SpdyFrame> resp3(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 5));
5695 scoped_ptr<SpdyFrame> body3(spdy_util_.ConstructSpdyBodyFrame(5, true));
5696 MockRead reads[] = {
5697 CreateMockRead(*resp1, 1),
5698 CreateMockRead(*body1, 2),
5699 CreateMockRead(*resp2, 5),
5700 CreateMockRead(*body2, 6),
5701 CreateMockRead(*resp3, 7),
5702 CreateMockRead(*body3, 8),
5703 MockRead(ASYNC, 0, 9) // EOF
5706 DeterministicSocketData data(reads, arraysize(reads),
5707 writes, arraysize(writes));
5708 NormalSpdyTransactionHelper helper(CreateGetRequest(), LOWEST,
5709 BoundNetLog(), GetParam(), NULL);
5710 helper.SetDeterministic();
5711 helper.RunPreTestSetup();
5712 helper.AddDeterministicData(&data);
5714 // Start the first transaction to set up the SpdySession
5715 HttpNetworkTransaction* trans = helper.trans();
5716 TestCompletionCallback callback;
5717 HttpRequestInfo info1 = CreateGetRequest();
5718 int rv = trans->Start(&info1, callback.callback(), BoundNetLog());
5719 EXPECT_EQ(ERR_IO_PENDING, rv);
5721 // Run the message loop, but do not allow the write to complete.
5722 // This leaves the SpdySession with a write pending, which prevents
5723 // SpdySession from attempting subsequent writes until this write completes.
5724 base::RunLoop().RunUntilIdle();
5726 // Now, start both new transactions
5727 HttpRequestInfo info2 = CreateGetRequest();
5728 TestCompletionCallback callback2;
5729 scoped_ptr<HttpNetworkTransaction> trans2(
5730 new HttpNetworkTransaction(MEDIUM, helper.session().get()));
5731 rv = trans2->Start(&info2, callback2.callback(), BoundNetLog());
5732 EXPECT_EQ(ERR_IO_PENDING, rv);
5733 base::RunLoop().RunUntilIdle();
5735 HttpRequestInfo info3 = CreateGetRequest();
5736 TestCompletionCallback callback3;
5737 scoped_ptr<HttpNetworkTransaction> trans3(
5738 new HttpNetworkTransaction(HIGHEST, helper.session().get()));
5739 rv = trans3->Start(&info3, callback3.callback(), BoundNetLog());
5740 EXPECT_EQ(ERR_IO_PENDING, rv);
5741 base::RunLoop().RunUntilIdle();
5743 // We now have two SYN_STREAM frames queued up which will be
5744 // dequeued only once the first write completes, which we
5745 // now allow to happen.
5746 data.RunFor(2);
5747 EXPECT_EQ(OK, callback.WaitForResult());
5749 // And now we can allow everything else to run to completion.
5750 data.SetStop(10);
5751 data.Run();
5752 EXPECT_EQ(OK, callback2.WaitForResult());
5753 EXPECT_EQ(OK, callback3.WaitForResult());
5755 helper.VerifyDataConsumed();
5758 // The tests below are only for SPDY/3 and above.
5760 // Test that sent data frames and received WINDOW_UPDATE frames change
5761 // the send_window_size_ correctly.
5763 // WINDOW_UPDATE is different than most other frames in that it can arrive
5764 // while the client is still sending the request body. In order to enforce
5765 // this scenario, we feed a couple of dummy frames and give a delay of 0 to
5766 // socket data provider, so that initial read that is done as soon as the
5767 // stream is created, succeeds and schedules another read. This way reads
5768 // and writes are interleaved; after doing a full frame write, SpdyStream
5769 // will break out of DoLoop and will read and process a WINDOW_UPDATE.
5770 // Once our WINDOW_UPDATE is read, we cannot send SYN_REPLY right away
5771 // since request has not been completely written, therefore we feed
5772 // enough number of WINDOW_UPDATEs to finish the first read and cause a
5773 // write, leading to a complete write of request body; after that we send
5774 // a reply with a body, to cause a graceful shutdown.
5776 // TODO(agayev): develop a socket data provider where both, reads and
5777 // writes are ordered so that writing tests like these are easy and rewrite
5778 // all these tests using it. Right now we are working around the
5779 // limitations as described above and it's not deterministic, tests may
5780 // fail under specific circumstances.
5781 TEST_P(SpdyNetworkTransactionTest, WindowUpdateReceived) {
5782 static int kFrameCount = 2;
5783 scoped_ptr<std::string> content(
5784 new std::string(kMaxSpdyFrameChunkSize, 'a'));
5785 scoped_ptr<SpdyFrame> req(spdy_util_.ConstructSpdyPost(
5786 GetDefaultUrl(), 1, kMaxSpdyFrameChunkSize * kFrameCount, LOWEST, NULL,
5787 0));
5788 scoped_ptr<SpdyFrame> body(
5789 spdy_util_.ConstructSpdyBodyFrame(
5790 1, content->c_str(), content->size(), false));
5791 scoped_ptr<SpdyFrame> body_end(
5792 spdy_util_.ConstructSpdyBodyFrame(
5793 1, content->c_str(), content->size(), true));
5795 MockWrite writes[] = {
5796 CreateMockWrite(*req, 0),
5797 CreateMockWrite(*body, 1),
5798 CreateMockWrite(*body_end, 2),
5801 static const int32 kDeltaWindowSize = 0xff;
5802 static const int kDeltaCount = 4;
5803 scoped_ptr<SpdyFrame> window_update(
5804 spdy_util_.ConstructSpdyWindowUpdate(1, kDeltaWindowSize));
5805 scoped_ptr<SpdyFrame> window_update_dummy(
5806 spdy_util_.ConstructSpdyWindowUpdate(2, kDeltaWindowSize));
5807 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
5808 MockRead reads[] = {
5809 CreateMockRead(*window_update_dummy, 3),
5810 CreateMockRead(*window_update_dummy, 4),
5811 CreateMockRead(*window_update_dummy, 5),
5812 CreateMockRead(*window_update, 6), // Four updates, therefore window
5813 CreateMockRead(*window_update, 7), // size should increase by
5814 CreateMockRead(*window_update, 8), // kDeltaWindowSize * 4
5815 CreateMockRead(*window_update, 9),
5816 CreateMockRead(*resp, 10),
5817 CreateMockRead(*body_end, 11),
5818 MockRead(ASYNC, 0, 0, 12) // EOF
5821 DeterministicSocketData data(reads, arraysize(reads),
5822 writes, arraysize(writes));
5824 ScopedVector<UploadElementReader> element_readers;
5825 for (int i = 0; i < kFrameCount; ++i) {
5826 element_readers.push_back(
5827 new UploadBytesElementReader(content->c_str(), content->size()));
5829 ElementsUploadDataStream upload_data_stream(element_readers.Pass(), 0);
5831 // Setup the request
5832 HttpRequestInfo request;
5833 request.method = "POST";
5834 request.url = GURL(GetDefaultUrl());
5835 request.upload_data_stream = &upload_data_stream;
5837 NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY,
5838 BoundNetLog(), GetParam(), NULL);
5839 helper.SetDeterministic();
5840 helper.AddDeterministicData(&data);
5841 helper.RunPreTestSetup();
5843 HttpNetworkTransaction* trans = helper.trans();
5845 TestCompletionCallback callback;
5846 int rv = trans->Start(&helper.request(), callback.callback(), BoundNetLog());
5848 EXPECT_EQ(ERR_IO_PENDING, rv);
5850 data.RunFor(11);
5852 SpdyHttpStream* stream = static_cast<SpdyHttpStream*>(trans->stream_.get());
5853 ASSERT_TRUE(stream != NULL);
5854 ASSERT_TRUE(stream->stream() != NULL);
5855 EXPECT_EQ(static_cast<int>(
5856 SpdySession::GetDefaultInitialWindowSize(GetParam().protocol)) +
5857 kDeltaWindowSize * kDeltaCount -
5858 kMaxSpdyFrameChunkSize * kFrameCount,
5859 stream->stream()->send_window_size());
5861 data.RunFor(1);
5863 rv = callback.WaitForResult();
5864 EXPECT_EQ(OK, rv);
5866 helper.VerifyDataConsumed();
5869 // Test that received data frames and sent WINDOW_UPDATE frames change
5870 // the recv_window_size_ correctly.
5871 TEST_P(SpdyNetworkTransactionTest, WindowUpdateSent) {
5872 const int32 default_initial_window_size =
5873 SpdySession::GetDefaultInitialWindowSize(GetParam().protocol);
5874 // Session level maximum window size that is more than twice the default
5875 // initial window size so that an initial window update is sent.
5876 const int32 session_max_recv_window_size = 5 * 64 * 1024;
5877 ASSERT_LT(2 * default_initial_window_size, session_max_recv_window_size);
5878 // Stream level maximum window size that is less than the session level
5879 // maximum window size so that we test for confusion between the two.
5880 const int32 stream_max_recv_window_size = 4 * 64 * 1024;
5881 ASSERT_GT(session_max_recv_window_size, stream_max_recv_window_size);
5882 // Size of body to be sent. Has to be less than or equal to both window sizes
5883 // so that we do not run out of receiving window. Also has to be greater than
5884 // half of them so that it triggers both a session level and a stream level
5885 // window update frame.
5886 const int32 kTargetSize = 3 * 64 * 1024;
5887 ASSERT_GE(session_max_recv_window_size, kTargetSize);
5888 ASSERT_GE(stream_max_recv_window_size, kTargetSize);
5889 ASSERT_LT(session_max_recv_window_size / 2, kTargetSize);
5890 ASSERT_LT(stream_max_recv_window_size / 2, kTargetSize);
5891 // Size of each DATA frame.
5892 const int32 kChunkSize = 4096;
5893 // Size of window updates.
5894 ASSERT_EQ(0, session_max_recv_window_size / 2 % kChunkSize);
5895 const int32 session_window_update_delta =
5896 session_max_recv_window_size / 2 + kChunkSize;
5897 ASSERT_EQ(0, stream_max_recv_window_size / 2 % kChunkSize);
5898 const int32 stream_window_update_delta =
5899 stream_max_recv_window_size / 2 + kChunkSize;
5901 SettingsMap initial_settings;
5902 initial_settings[SETTINGS_MAX_CONCURRENT_STREAMS] =
5903 SettingsFlagsAndValue(SETTINGS_FLAG_NONE, kMaxConcurrentPushedStreams);
5904 initial_settings[SETTINGS_INITIAL_WINDOW_SIZE] =
5905 SettingsFlagsAndValue(SETTINGS_FLAG_NONE, stream_max_recv_window_size);
5906 scoped_ptr<SpdyFrame> initial_settings_frame(
5907 spdy_util_.ConstructSpdySettings(initial_settings));
5908 scoped_ptr<SpdyFrame> initial_window_update(
5909 spdy_util_.ConstructSpdyWindowUpdate(
5910 kSessionFlowControlStreamId,
5911 session_max_recv_window_size - default_initial_window_size));
5912 scoped_ptr<SpdyFrame> req(
5913 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
5914 scoped_ptr<SpdyFrame> session_window_update(
5915 spdy_util_.ConstructSpdyWindowUpdate(0, session_window_update_delta));
5916 scoped_ptr<SpdyFrame> stream_window_update(
5917 spdy_util_.ConstructSpdyWindowUpdate(1, stream_window_update_delta));
5919 std::vector<MockWrite> writes;
5920 if (GetParam().protocol == kProtoHTTP2) {
5921 writes.push_back(MockWrite(ASYNC, kHttp2ConnectionHeaderPrefix,
5922 kHttp2ConnectionHeaderPrefixSize, 0));
5924 writes.push_back(CreateMockWrite(*initial_settings_frame, writes.size()));
5925 writes.push_back(CreateMockWrite(*initial_window_update, writes.size()));
5926 writes.push_back(CreateMockWrite(*req, writes.size()));
5928 std::vector<MockRead> reads;
5929 scoped_ptr<SpdyFrame> resp(
5930 spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
5931 reads.push_back(CreateMockRead(*resp, writes.size() + reads.size()));
5933 ScopedVector<SpdyFrame> body_frames;
5934 const std::string body_data(kChunkSize, 'x');
5935 for (size_t remaining = kTargetSize; remaining != 0;) {
5936 size_t frame_size = std::min(remaining, body_data.size());
5937 body_frames.push_back(spdy_util_.ConstructSpdyBodyFrame(
5938 1, body_data.data(), frame_size, false));
5939 reads.push_back(
5940 CreateMockRead(*body_frames.back(), writes.size() + reads.size()));
5941 remaining -= frame_size;
5943 reads.push_back(
5944 MockRead(ASYNC, ERR_IO_PENDING, writes.size() + reads.size())); // Yield.
5946 writes.push_back(
5947 CreateMockWrite(*session_window_update, writes.size() + reads.size()));
5948 writes.push_back(
5949 CreateMockWrite(*stream_window_update, writes.size() + reads.size()));
5951 SequencedSocketData data(vector_as_array(&reads), reads.size(),
5952 vector_as_array(&writes), writes.size());
5954 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
5955 BoundNetLog(), GetParam(), NULL);
5956 helper.AddData(&data);
5957 helper.RunPreTestSetup();
5959 SpdySessionPool* spdy_session_pool = helper.session()->spdy_session_pool();
5960 SpdySessionPoolPeer pool_peer(spdy_session_pool);
5961 pool_peer.SetEnableSendingInitialData(true);
5962 pool_peer.SetSessionMaxRecvWindowSize(session_max_recv_window_size);
5963 pool_peer.SetStreamInitialRecvWindowSize(stream_max_recv_window_size);
5965 HttpNetworkTransaction* trans = helper.trans();
5966 TestCompletionCallback callback;
5967 int rv = trans->Start(&helper.request(), callback.callback(), BoundNetLog());
5969 EXPECT_EQ(ERR_IO_PENDING, rv);
5970 rv = callback.WaitForResult();
5971 EXPECT_EQ(OK, rv);
5973 SpdyHttpStream* stream =
5974 static_cast<SpdyHttpStream*>(trans->stream_.get());
5975 ASSERT_TRUE(stream != NULL);
5976 ASSERT_TRUE(stream->stream() != NULL);
5978 // All data has been read, but not consumed. The window reflects this.
5979 EXPECT_EQ(static_cast<int>(stream_max_recv_window_size - kTargetSize),
5980 stream->stream()->recv_window_size());
5982 const HttpResponseInfo* response = trans->GetResponseInfo();
5983 ASSERT_TRUE(response != NULL);
5984 ASSERT_TRUE(response->headers.get() != NULL);
5985 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
5986 EXPECT_TRUE(response->was_fetched_via_spdy);
5988 // Issue a read which will cause a WINDOW_UPDATE to be sent and window
5989 // size increased to default.
5990 scoped_refptr<IOBuffer> buf(new IOBuffer(kTargetSize));
5991 EXPECT_EQ(static_cast<int>(kTargetSize),
5992 trans->Read(buf.get(), kTargetSize, CompletionCallback()));
5993 EXPECT_EQ(static_cast<int>(stream_max_recv_window_size),
5994 stream->stream()->recv_window_size());
5995 EXPECT_THAT(base::StringPiece(buf->data(), kTargetSize), Each(Eq('x')));
5997 // Allow scheduled WINDOW_UPDATE frames to write.
5998 base::RunLoop().RunUntilIdle();
5999 helper.VerifyDataConsumed();
6002 // Test that WINDOW_UPDATE frame causing overflow is handled correctly.
6003 TEST_P(SpdyNetworkTransactionTest, WindowUpdateOverflow) {
6004 // Number of full frames we hope to write (but will not, used to
6005 // set content-length header correctly)
6006 static int kFrameCount = 3;
6008 scoped_ptr<std::string> content(
6009 new std::string(kMaxSpdyFrameChunkSize, 'a'));
6010 scoped_ptr<SpdyFrame> req(spdy_util_.ConstructSpdyPost(
6011 GetDefaultUrl(), 1, kMaxSpdyFrameChunkSize * kFrameCount, LOWEST, NULL,
6012 0));
6013 scoped_ptr<SpdyFrame> body(
6014 spdy_util_.ConstructSpdyBodyFrame(
6015 1, content->c_str(), content->size(), false));
6016 scoped_ptr<SpdyFrame> rst(
6017 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_FLOW_CONTROL_ERROR));
6019 // We're not going to write a data frame with FIN, we'll receive a bad
6020 // WINDOW_UPDATE while sending a request and will send a RST_STREAM frame.
6021 MockWrite writes[] = {
6022 CreateMockWrite(*req, 0),
6023 CreateMockWrite(*body, 2),
6024 CreateMockWrite(*rst, 3),
6027 static const int32 kDeltaWindowSize = 0x7fffffff; // cause an overflow
6028 scoped_ptr<SpdyFrame> window_update(
6029 spdy_util_.ConstructSpdyWindowUpdate(1, kDeltaWindowSize));
6030 MockRead reads[] = {
6031 CreateMockRead(*window_update, 1),
6032 MockRead(ASYNC, 0, 4) // EOF
6035 DeterministicSocketData data(reads, arraysize(reads),
6036 writes, arraysize(writes));
6038 ScopedVector<UploadElementReader> element_readers;
6039 for (int i = 0; i < kFrameCount; ++i) {
6040 element_readers.push_back(
6041 new UploadBytesElementReader(content->c_str(), content->size()));
6043 ElementsUploadDataStream upload_data_stream(element_readers.Pass(), 0);
6045 // Setup the request
6046 HttpRequestInfo request;
6047 request.method = "POST";
6048 request.url = GURL(GetDefaultUrl());
6049 request.upload_data_stream = &upload_data_stream;
6051 NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY,
6052 BoundNetLog(), GetParam(), NULL);
6053 helper.SetDeterministic();
6054 helper.RunPreTestSetup();
6055 helper.AddDeterministicData(&data);
6056 HttpNetworkTransaction* trans = helper.trans();
6058 TestCompletionCallback callback;
6059 int rv = trans->Start(&helper.request(), callback.callback(), BoundNetLog());
6060 ASSERT_EQ(ERR_IO_PENDING, rv);
6062 data.RunFor(5);
6063 ASSERT_TRUE(callback.have_result());
6064 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, callback.WaitForResult());
6065 helper.VerifyDataConsumed();
6068 // Test that after hitting a send window size of 0, the write process
6069 // stalls and upon receiving WINDOW_UPDATE frame write resumes.
6071 // This test constructs a POST request followed by enough data frames
6072 // containing 'a' that would make the window size 0, followed by another
6073 // data frame containing default content (which is "hello!") and this frame
6074 // also contains a FIN flag. SequencedSocketData is used to enforce all
6075 // writes, save the last, go through before a read could happen. The last frame
6076 // ("hello!") is not permitted to go through since by the time its turn
6077 // arrives, window size is 0. At this point MessageLoop::Run() called via
6078 // callback would block. Therefore we call MessageLoop::RunUntilIdle()
6079 // which returns after performing all possible writes. We use DCHECKS to
6080 // ensure that last data frame is still there and stream has stalled.
6081 // After that, next read is artifically enforced, which causes a
6082 // WINDOW_UPDATE to be read and I/O process resumes.
6083 TEST_P(SpdyNetworkTransactionTest, FlowControlStallResume) {
6084 const int32 initial_window_size =
6085 SpdySession::GetDefaultInitialWindowSize(GetParam().protocol);
6086 // Number of frames we need to send to zero out the window size: data
6087 // frames plus SYN_STREAM plus the last data frame; also we need another
6088 // data frame that we will send once the WINDOW_UPDATE is received,
6089 // therefore +3.
6090 size_t num_writes = initial_window_size / kMaxSpdyFrameChunkSize + 3;
6092 // Calculate last frame's size; 0 size data frame is legal.
6093 size_t last_frame_size = initial_window_size % kMaxSpdyFrameChunkSize;
6095 // Construct content for a data frame of maximum size.
6096 std::string content(kMaxSpdyFrameChunkSize, 'a');
6098 scoped_ptr<SpdyFrame> req(spdy_util_.ConstructSpdyPost(
6099 GetDefaultUrl(), 1, initial_window_size + kUploadDataSize, LOWEST, NULL,
6100 0));
6102 // Full frames.
6103 scoped_ptr<SpdyFrame> body1(
6104 spdy_util_.ConstructSpdyBodyFrame(
6105 1, content.c_str(), content.size(), false));
6107 // Last frame to zero out the window size.
6108 scoped_ptr<SpdyFrame> body2(
6109 spdy_util_.ConstructSpdyBodyFrame(
6110 1, content.c_str(), last_frame_size, false));
6112 // Data frame to be sent once WINDOW_UPDATE frame is received.
6113 scoped_ptr<SpdyFrame> body3(spdy_util_.ConstructSpdyBodyFrame(1, true));
6115 // Fill in mock writes.
6116 scoped_ptr<MockWrite[]> writes(new MockWrite[num_writes]);
6117 size_t i = 0;
6118 writes[i] = CreateMockWrite(*req, i);
6119 for (i = 1; i < num_writes - 2; i++)
6120 writes[i] = CreateMockWrite(*body1, i);
6121 writes[i] = CreateMockWrite(*body2, i);
6122 // The last write must not be attempted until after the WINDOW_UPDATES
6123 // have been received.
6124 writes[i + 1] = CreateMockWrite(*body3, i + 4, SYNCHRONOUS);
6126 // Construct read frame, give enough space to upload the rest of the
6127 // data.
6128 scoped_ptr<SpdyFrame> session_window_update(
6129 spdy_util_.ConstructSpdyWindowUpdate(0, kUploadDataSize));
6130 scoped_ptr<SpdyFrame> window_update(
6131 spdy_util_.ConstructSpdyWindowUpdate(1, kUploadDataSize));
6132 scoped_ptr<SpdyFrame> reply(spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
6133 MockRead reads[] = {
6134 MockRead(ASYNC, ERR_IO_PENDING, i + 1), // Force a pause
6135 CreateMockRead(*session_window_update, i + 2),
6136 CreateMockRead(*window_update, i + 3),
6137 // Now the last write will occur.
6138 CreateMockRead(*reply, i + 5),
6139 CreateMockRead(*body2, i + 6),
6140 CreateMockRead(*body3, i + 7),
6141 MockRead(ASYNC, 0, i + 8) // EOF
6144 SequencedSocketData data(reads, arraysize(reads), writes.get(), num_writes);
6146 ScopedVector<UploadElementReader> element_readers;
6147 std::string upload_data_string(initial_window_size, 'a');
6148 upload_data_string.append(kUploadData, kUploadDataSize);
6149 element_readers.push_back(new UploadBytesElementReader(
6150 upload_data_string.c_str(), upload_data_string.size()));
6151 ElementsUploadDataStream upload_data_stream(element_readers.Pass(), 0);
6153 HttpRequestInfo request;
6154 request.method = "POST";
6155 request.url = GURL(GetDefaultUrl());
6156 request.upload_data_stream = &upload_data_stream;
6157 NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY,
6158 BoundNetLog(), GetParam(), NULL);
6159 helper.AddData(&data);
6160 helper.RunPreTestSetup();
6162 HttpNetworkTransaction* trans = helper.trans();
6164 TestCompletionCallback callback;
6165 int rv = trans->Start(&helper.request(), callback.callback(), BoundNetLog());
6166 EXPECT_EQ(ERR_IO_PENDING, rv);
6168 base::RunLoop().RunUntilIdle(); // Write as much as we can.
6170 SpdyHttpStream* stream = static_cast<SpdyHttpStream*>(trans->stream_.get());
6171 ASSERT_TRUE(stream != NULL);
6172 ASSERT_TRUE(stream->stream() != NULL);
6173 EXPECT_EQ(0, stream->stream()->send_window_size());
6174 // All the body data should have been read.
6175 // TODO(satorux): This is because of the weirdness in reading the request
6176 // body in OnSendBodyComplete(). See crbug.com/113107.
6177 EXPECT_TRUE(upload_data_stream.IsEOF());
6178 // But the body is not yet fully sent (kUploadData is not yet sent)
6179 // since we're send-stalled.
6180 EXPECT_TRUE(stream->stream()->send_stalled_by_flow_control());
6182 data.CompleteRead(); // Read in WINDOW_UPDATE frame.
6183 rv = callback.WaitForResult();
6184 helper.VerifyDataConsumed();
6187 // Test we correctly handle the case where the SETTINGS frame results in
6188 // unstalling the send window.
6189 TEST_P(SpdyNetworkTransactionTest, FlowControlStallResumeAfterSettings) {
6190 const int32 initial_window_size =
6191 SpdySession::GetDefaultInitialWindowSize(GetParam().protocol);
6193 // Number of frames we need to send to zero out the window size: data
6194 // frames plus SYN_STREAM plus the last data frame; also we need another
6195 // data frame that we will send once the SETTING is received, therefore +3.
6196 size_t num_writes = initial_window_size / kMaxSpdyFrameChunkSize + 3;
6198 // Calculate last frame's size; 0 size data frame is legal.
6199 size_t last_frame_size = initial_window_size % kMaxSpdyFrameChunkSize;
6201 // Construct content for a data frame of maximum size.
6202 std::string content(kMaxSpdyFrameChunkSize, 'a');
6204 scoped_ptr<SpdyFrame> req(spdy_util_.ConstructSpdyPost(
6205 GetDefaultUrl(), 1, initial_window_size + kUploadDataSize, LOWEST, NULL,
6206 0));
6208 // Full frames.
6209 scoped_ptr<SpdyFrame> body1(
6210 spdy_util_.ConstructSpdyBodyFrame(
6211 1, content.c_str(), content.size(), false));
6213 // Last frame to zero out the window size.
6214 scoped_ptr<SpdyFrame> body2(
6215 spdy_util_.ConstructSpdyBodyFrame(
6216 1, content.c_str(), last_frame_size, false));
6218 // Data frame to be sent once SETTINGS frame is received.
6219 scoped_ptr<SpdyFrame> body3(spdy_util_.ConstructSpdyBodyFrame(1, true));
6221 // Fill in mock reads/writes.
6222 std::vector<MockRead> reads;
6223 std::vector<MockWrite> writes;
6224 size_t i = 0;
6225 writes.push_back(CreateMockWrite(*req, i++));
6226 while (i < num_writes - 2)
6227 writes.push_back(CreateMockWrite(*body1, i++));
6228 writes.push_back(CreateMockWrite(*body2, i++));
6230 // Construct read frame for SETTINGS that gives enough space to upload the
6231 // rest of the data.
6232 SettingsMap settings;
6233 settings[SETTINGS_INITIAL_WINDOW_SIZE] =
6234 SettingsFlagsAndValue(SETTINGS_FLAG_NONE, initial_window_size * 2);
6235 scoped_ptr<SpdyFrame> settings_frame_large(
6236 spdy_util_.ConstructSpdySettings(settings));
6238 reads.push_back(CreateMockRead(*settings_frame_large, i++));
6240 scoped_ptr<SpdyFrame> session_window_update(
6241 spdy_util_.ConstructSpdyWindowUpdate(0, kUploadDataSize));
6242 if (GetParam().protocol >= kProtoSPDY31)
6243 reads.push_back(CreateMockRead(*session_window_update, i++));
6245 scoped_ptr<SpdyFrame> settings_ack(spdy_util_.ConstructSpdySettingsAck());
6246 writes.push_back(CreateMockWrite(*settings_ack, i++));
6248 writes.push_back(CreateMockWrite(*body3, i++));
6250 scoped_ptr<SpdyFrame> reply(spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
6251 reads.push_back(CreateMockRead(*reply, i++));
6252 reads.push_back(CreateMockRead(*body2, i++));
6253 reads.push_back(CreateMockRead(*body3, i++));
6254 reads.push_back(MockRead(ASYNC, 0, i++)); // EOF
6256 // Force all writes to happen before any read, last write will not
6257 // actually queue a frame, due to window size being 0.
6258 DeterministicSocketData data(vector_as_array(&reads), reads.size(),
6259 vector_as_array(&writes), writes.size());
6261 ScopedVector<UploadElementReader> element_readers;
6262 std::string upload_data_string(initial_window_size, 'a');
6263 upload_data_string.append(kUploadData, kUploadDataSize);
6264 element_readers.push_back(new UploadBytesElementReader(
6265 upload_data_string.c_str(), upload_data_string.size()));
6266 ElementsUploadDataStream upload_data_stream(element_readers.Pass(), 0);
6268 HttpRequestInfo request;
6269 request.method = "POST";
6270 request.url = GURL(GetDefaultUrl());
6271 request.upload_data_stream = &upload_data_stream;
6272 NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY,
6273 BoundNetLog(), GetParam(), NULL);
6274 helper.SetDeterministic();
6275 helper.RunPreTestSetup();
6276 helper.AddDeterministicData(&data);
6278 HttpNetworkTransaction* trans = helper.trans();
6280 TestCompletionCallback callback;
6281 int rv = trans->Start(&helper.request(), callback.callback(), BoundNetLog());
6282 EXPECT_EQ(ERR_IO_PENDING, rv);
6284 data.RunFor(num_writes - 1); // Write as much as we can.
6286 SpdyHttpStream* stream = static_cast<SpdyHttpStream*>(trans->stream_.get());
6287 ASSERT_TRUE(stream != NULL);
6288 ASSERT_TRUE(stream->stream() != NULL);
6289 EXPECT_EQ(0, stream->stream()->send_window_size());
6291 // All the body data should have been read.
6292 // TODO(satorux): This is because of the weirdness in reading the request
6293 // body in OnSendBodyComplete(). See crbug.com/113107.
6294 EXPECT_TRUE(upload_data_stream.IsEOF());
6295 // But the body is not yet fully sent (kUploadData is not yet sent)
6296 // since we're send-stalled.
6297 EXPECT_TRUE(stream->stream()->send_stalled_by_flow_control());
6299 data.RunFor(7); // Read in SETTINGS frame to unstall.
6300 rv = callback.WaitForResult();
6301 helper.VerifyDataConsumed();
6302 // If stream is NULL, that means it was unstalled and closed.
6303 EXPECT_TRUE(stream->stream() == NULL);
6306 // Test we correctly handle the case where the SETTINGS frame results in a
6307 // negative send window size.
6308 TEST_P(SpdyNetworkTransactionTest, FlowControlNegativeSendWindowSize) {
6309 const int32 initial_window_size =
6310 SpdySession::GetDefaultInitialWindowSize(GetParam().protocol);
6311 // Number of frames we need to send to zero out the window size: data
6312 // frames plus SYN_STREAM plus the last data frame; also we need another
6313 // data frame that we will send once the SETTING is received, therefore +3.
6314 size_t num_writes = initial_window_size / kMaxSpdyFrameChunkSize + 3;
6316 // Calculate last frame's size; 0 size data frame is legal.
6317 size_t last_frame_size = initial_window_size % kMaxSpdyFrameChunkSize;
6319 // Construct content for a data frame of maximum size.
6320 std::string content(kMaxSpdyFrameChunkSize, 'a');
6322 scoped_ptr<SpdyFrame> req(spdy_util_.ConstructSpdyPost(
6323 GetDefaultUrl(), 1, initial_window_size + kUploadDataSize, LOWEST, NULL,
6324 0));
6326 // Full frames.
6327 scoped_ptr<SpdyFrame> body1(
6328 spdy_util_.ConstructSpdyBodyFrame(
6329 1, content.c_str(), content.size(), false));
6331 // Last frame to zero out the window size.
6332 scoped_ptr<SpdyFrame> body2(
6333 spdy_util_.ConstructSpdyBodyFrame(
6334 1, content.c_str(), last_frame_size, false));
6336 // Data frame to be sent once SETTINGS frame is received.
6337 scoped_ptr<SpdyFrame> body3(spdy_util_.ConstructSpdyBodyFrame(1, true));
6339 // Fill in mock reads/writes.
6340 std::vector<MockRead> reads;
6341 std::vector<MockWrite> writes;
6342 size_t i = 0;
6343 writes.push_back(CreateMockWrite(*req, i++));
6344 while (i < num_writes - 2)
6345 writes.push_back(CreateMockWrite(*body1, i++));
6346 writes.push_back(CreateMockWrite(*body2, i++));
6348 // Construct read frame for SETTINGS that makes the send_window_size
6349 // negative.
6350 SettingsMap new_settings;
6351 new_settings[SETTINGS_INITIAL_WINDOW_SIZE] =
6352 SettingsFlagsAndValue(SETTINGS_FLAG_NONE, initial_window_size / 2);
6353 scoped_ptr<SpdyFrame> settings_frame_small(
6354 spdy_util_.ConstructSpdySettings(new_settings));
6355 // Construct read frames for WINDOW_UPDATE that makes the send_window_size
6356 // positive.
6357 scoped_ptr<SpdyFrame> session_window_update_init_size(
6358 spdy_util_.ConstructSpdyWindowUpdate(0, initial_window_size));
6359 scoped_ptr<SpdyFrame> window_update_init_size(
6360 spdy_util_.ConstructSpdyWindowUpdate(1, initial_window_size));
6362 reads.push_back(CreateMockRead(*settings_frame_small, i++));
6363 reads.push_back(CreateMockRead(*session_window_update_init_size, i++));
6364 reads.push_back(CreateMockRead(*window_update_init_size, i++));
6366 scoped_ptr<SpdyFrame> settings_ack(spdy_util_.ConstructSpdySettingsAck());
6367 writes.push_back(CreateMockWrite(*settings_ack, i++));
6369 writes.push_back(CreateMockWrite(*body3, i++));
6371 scoped_ptr<SpdyFrame> reply(spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
6372 reads.push_back(CreateMockRead(*reply, i++));
6373 reads.push_back(CreateMockRead(*body2, i++));
6374 reads.push_back(CreateMockRead(*body3, i++));
6375 reads.push_back(MockRead(ASYNC, 0, i++)); // EOF
6377 // Force all writes to happen before any read, last write will not
6378 // actually queue a frame, due to window size being 0.
6379 DeterministicSocketData data(vector_as_array(&reads), reads.size(),
6380 vector_as_array(&writes), writes.size());
6382 ScopedVector<UploadElementReader> element_readers;
6383 std::string upload_data_string(initial_window_size, 'a');
6384 upload_data_string.append(kUploadData, kUploadDataSize);
6385 element_readers.push_back(new UploadBytesElementReader(
6386 upload_data_string.c_str(), upload_data_string.size()));
6387 ElementsUploadDataStream upload_data_stream(element_readers.Pass(), 0);
6389 HttpRequestInfo request;
6390 request.method = "POST";
6391 request.url = GURL(GetDefaultUrl());
6392 request.upload_data_stream = &upload_data_stream;
6393 NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY,
6394 BoundNetLog(), GetParam(), NULL);
6395 helper.SetDeterministic();
6396 helper.RunPreTestSetup();
6397 helper.AddDeterministicData(&data);
6399 HttpNetworkTransaction* trans = helper.trans();
6401 TestCompletionCallback callback;
6402 int rv = trans->Start(&helper.request(), callback.callback(), BoundNetLog());
6403 EXPECT_EQ(ERR_IO_PENDING, rv);
6405 data.RunFor(num_writes - 1); // Write as much as we can.
6407 SpdyHttpStream* stream = static_cast<SpdyHttpStream*>(trans->stream_.get());
6408 ASSERT_TRUE(stream != NULL);
6409 ASSERT_TRUE(stream->stream() != NULL);
6410 EXPECT_EQ(0, stream->stream()->send_window_size());
6412 // All the body data should have been read.
6413 // TODO(satorux): This is because of the weirdness in reading the request
6414 // body in OnSendBodyComplete(). See crbug.com/113107.
6415 EXPECT_TRUE(upload_data_stream.IsEOF());
6416 // But the body is not yet fully sent (kUploadData is not yet sent)
6417 // since we're send-stalled.
6418 EXPECT_TRUE(stream->stream()->send_stalled_by_flow_control());
6420 // Read in WINDOW_UPDATE or SETTINGS frame.
6421 data.RunFor((GetParam().protocol >= kProtoSPDY31) ? 9 : 8);
6422 rv = callback.WaitForResult();
6423 helper.VerifyDataConsumed();
6426 TEST_P(SpdyNetworkTransactionTest, GoAwayOnOddPushStreamId) {
6427 if (spdy_util_.spdy_version() < SPDY3)
6428 return;
6430 scoped_ptr<SpdyHeaderBlock> push_headers(new SpdyHeaderBlock);
6431 spdy_util_.AddUrlToHeaderBlock("http://www.example.org/a.dat",
6432 push_headers.get());
6433 scoped_ptr<SpdyFrame> push(
6434 spdy_util_.ConstructInitialSpdyPushFrame(push_headers.Pass(), 3, 1));
6435 MockRead reads[] = {CreateMockRead(*push, 1)};
6437 scoped_ptr<SpdyFrame> req(
6438 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
6439 scoped_ptr<SpdyFrame> goaway(spdy_util_.ConstructSpdyGoAway(
6440 0, GOAWAY_PROTOCOL_ERROR, "Odd push stream id."));
6441 MockWrite writes[] = {
6442 CreateMockWrite(*req, 0), CreateMockWrite(*goaway, 2),
6445 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
6446 NormalSpdyTransactionHelper helper(
6447 CreateGetRequest(), DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL);
6448 helper.RunToCompletion(&data);
6449 TransactionHelperResult out = helper.output();
6450 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, out.rv);
6453 TEST_P(SpdyNetworkTransactionTest,
6454 GoAwayOnPushStreamIdLesserOrEqualThanLastAccepted) {
6455 if (spdy_util_.spdy_version() < SPDY3)
6456 return;
6458 scoped_ptr<SpdyFrame> push_a(spdy_util_.ConstructSpdyPush(
6459 NULL, 0, 4, 1, GetDefaultUrlWithPath("/a.dat").c_str()));
6460 scoped_ptr<SpdyHeaderBlock> push_b_headers(new SpdyHeaderBlock);
6461 spdy_util_.AddUrlToHeaderBlock(GetDefaultUrlWithPath("/b.dat"),
6462 push_b_headers.get());
6463 scoped_ptr<SpdyFrame> push_b(
6464 spdy_util_.ConstructInitialSpdyPushFrame(push_b_headers.Pass(), 2, 1));
6465 MockRead reads[] = {
6466 CreateMockRead(*push_a, 1), CreateMockRead(*push_b, 2),
6469 scoped_ptr<SpdyFrame> req(
6470 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
6471 scoped_ptr<SpdyFrame> goaway(spdy_util_.ConstructSpdyGoAway(
6473 GOAWAY_PROTOCOL_ERROR,
6474 "New push stream id must be greater than the last accepted."));
6475 MockWrite writes[] = {
6476 CreateMockWrite(*req, 0), CreateMockWrite(*goaway, 3),
6479 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
6480 NormalSpdyTransactionHelper helper(
6481 CreateGetRequest(), DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL);
6482 helper.RunToCompletion(&data);
6483 TransactionHelperResult out = helper.output();
6484 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, out.rv);
6487 // Regression test for https://crbug.com/493348: request header exceeds 16 kB
6488 // and thus sent in multiple frames when using HTTP/2.
6489 TEST_P(SpdyNetworkTransactionTest, LargeRequest) {
6490 const std::string kKey("foo");
6491 const std::string kValue(1 << 15, 'z');
6493 HttpRequestInfo request;
6494 request.method = "GET";
6495 request.url = GURL(GetDefaultUrl());
6496 request.extra_headers.SetHeader(kKey, kValue);
6498 scoped_ptr<SpdyHeaderBlock> headers(
6499 spdy_util_.ConstructGetHeaderBlock(GetDefaultUrl()));
6500 (*headers)[kKey] = kValue;
6501 scoped_ptr<SpdyFrame> req(
6502 spdy_util_.ConstructSpdySyn(1, *headers, LOWEST, false, true));
6503 MockWrite writes[] = {
6504 CreateMockWrite(*req, 0),
6507 scoped_ptr<SpdyFrame> resp(
6508 spdy_util_.ConstructSpdyGetSynReply(nullptr, 0, 1));
6509 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
6510 MockRead reads[] = {
6511 CreateMockRead(*resp, 1),
6512 CreateMockRead(*body, 2),
6513 MockRead(ASYNC, 0, 3) // EOF
6516 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
6517 NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY, BoundNetLog(),
6518 GetParam(), nullptr);
6519 helper.RunToCompletion(&data);
6520 TransactionHelperResult out = helper.output();
6522 EXPECT_EQ(OK, out.rv);
6523 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
6524 EXPECT_EQ("hello!", out.response_data);
6527 class SpdyNetworkTransactionNoTLSUsageCheckTest
6528 : public SpdyNetworkTransactionTest {
6529 protected:
6530 void RunNoTLSUsageCheckTest(scoped_ptr<SSLSocketDataProvider> ssl_provider) {
6531 // Construct the request.
6532 scoped_ptr<SpdyFrame> req(
6533 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
6534 MockWrite writes[] = {CreateMockWrite(*req, 0)};
6536 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
6537 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
6538 MockRead reads[] = {
6539 CreateMockRead(*resp, 1),
6540 CreateMockRead(*body, 2),
6541 MockRead(ASYNC, 0, 3) // EOF
6544 SequencedSocketData data(reads, arraysize(reads), writes,
6545 arraysize(writes));
6546 HttpRequestInfo request;
6547 request.method = "GET";
6548 request.url = GURL("https://www.example.org/");
6549 NormalSpdyTransactionHelper helper(
6550 request, DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL);
6551 helper.RunToCompletionWithSSLData(&data, ssl_provider.Pass());
6552 TransactionHelperResult out = helper.output();
6553 EXPECT_EQ(OK, out.rv);
6554 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
6555 EXPECT_EQ("hello!", out.response_data);
6559 //-----------------------------------------------------------------------------
6560 // All tests are run with three different connection types: SPDY after NPN
6561 // negotiation, SPDY without SSL, and SPDY with SSL.
6563 // TODO(akalin): Use ::testing::Combine() when we are able to use
6564 // <tr1/tuple>.
6565 INSTANTIATE_TEST_CASE_P(
6566 Spdy,
6567 SpdyNetworkTransactionNoTLSUsageCheckTest,
6568 ::testing::Values(SpdyNetworkTransactionTestParams(kProtoSPDY31,
6569 HTTPS_SPDY_VIA_NPN)));
6571 TEST_P(SpdyNetworkTransactionNoTLSUsageCheckTest, TLSVersionTooOld) {
6572 scoped_ptr<SSLSocketDataProvider> ssl_provider(
6573 new SSLSocketDataProvider(ASYNC, OK));
6574 SSLConnectionStatusSetVersion(SSL_CONNECTION_VERSION_SSL3,
6575 &ssl_provider->connection_status);
6577 RunNoTLSUsageCheckTest(ssl_provider.Pass());
6580 TEST_P(SpdyNetworkTransactionNoTLSUsageCheckTest, TLSCipherSuiteSucky) {
6581 scoped_ptr<SSLSocketDataProvider> ssl_provider(
6582 new SSLSocketDataProvider(ASYNC, OK));
6583 // Set to TLS_RSA_WITH_NULL_MD5
6584 SSLConnectionStatusSetCipherSuite(0x1, &ssl_provider->connection_status);
6586 RunNoTLSUsageCheckTest(ssl_provider.Pass());
6589 class SpdyNetworkTransactionTLSUsageCheckTest
6590 : public SpdyNetworkTransactionTest {
6591 protected:
6592 void RunTLSUsageCheckTest(scoped_ptr<SSLSocketDataProvider> ssl_provider) {
6593 scoped_ptr<SpdyFrame> goaway(
6594 spdy_util_.ConstructSpdyGoAway(0, GOAWAY_INADEQUATE_SECURITY, ""));
6595 MockWrite writes[] = {CreateMockWrite(*goaway)};
6597 StaticSocketDataProvider data(NULL, 0, writes, arraysize(writes));
6598 HttpRequestInfo request;
6599 request.method = "GET";
6600 request.url = GURL("https://www.example.org/");
6601 NormalSpdyTransactionHelper helper(
6602 request, DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL);
6603 helper.RunToCompletionWithSSLData(&data, ssl_provider.Pass());
6604 TransactionHelperResult out = helper.output();
6605 EXPECT_EQ(ERR_SPDY_INADEQUATE_TRANSPORT_SECURITY, out.rv);
6609 INSTANTIATE_TEST_CASE_P(
6610 Spdy,
6611 SpdyNetworkTransactionTLSUsageCheckTest,
6612 ::testing::Values(
6613 SpdyNetworkTransactionTestParams(kProtoHTTP2, HTTPS_SPDY_VIA_NPN)));
6615 TEST_P(SpdyNetworkTransactionTLSUsageCheckTest, TLSVersionTooOld) {
6616 scoped_ptr<SSLSocketDataProvider> ssl_provider(
6617 new SSLSocketDataProvider(ASYNC, OK));
6618 SSLConnectionStatusSetVersion(SSL_CONNECTION_VERSION_SSL3,
6619 &ssl_provider->connection_status);
6621 RunTLSUsageCheckTest(ssl_provider.Pass());
6624 TEST_P(SpdyNetworkTransactionTLSUsageCheckTest, TLSCipherSuiteSucky) {
6625 scoped_ptr<SSLSocketDataProvider> ssl_provider(
6626 new SSLSocketDataProvider(ASYNC, OK));
6627 // Set to TLS_RSA_WITH_NULL_MD5
6628 SSLConnectionStatusSetCipherSuite(0x1, &ssl_provider->connection_status);
6630 RunTLSUsageCheckTest(ssl_provider.Pass());
6633 } // namespace net