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