HELLO·Android
系统源代码
IT资讯
技术文章
我的收藏
注册
登录
-
我收藏的文章
创建代码块
我的代码块
我的账号
Lollipop MR1
|
5.1.0_r3
下载
查看原文件
收藏
根目录
external
chromium_org
net
spdy
spdy_network_transaction_unittest.cc
// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include
#include
#include "base/bind.h" #include "base/bind_helpers.h" #include "base/files/file_util.h" #include "base/files/scoped_temp_dir.h" #include "base/memory/scoped_vector.h" #include "base/run_loop.h" #include "base/stl_util.h" #include "base/strings/string_piece.h" #include "base/test/test_file_util.h" #include "net/base/auth.h" #include "net/base/net_log_unittest.h" #include "net/base/request_priority.h" #include "net/base/upload_bytes_element_reader.h" #include "net/base/upload_data_stream.h" #include "net/base/upload_file_element_reader.h" #include "net/http/http_network_session_peer.h" #include "net/http/http_network_transaction.h" #include "net/http/http_server_properties.h" #include "net/http/http_transaction_test_util.h" #include "net/socket/client_socket_pool_base.h" #include "net/socket/next_proto.h" #include "net/spdy/buffered_spdy_framer.h" #include "net/spdy/spdy_http_stream.h" #include "net/spdy/spdy_http_utils.h" #include "net/spdy/spdy_session.h" #include "net/spdy/spdy_session_pool.h" #include "net/spdy/spdy_test_util_common.h" #include "net/spdy/spdy_test_utils.h" #include "net/ssl/ssl_connection_status_flags.h" #include "net/url_request/url_request_test_util.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/platform_test.h" //----------------------------------------------------------------------------- namespace net { namespace { using testing::Each; using testing::Eq; const char kRequestUrl[] = "http://www.google.com/"; enum SpdyNetworkTransactionTestSSLType { SPDYNPN, SPDYNOSSL, SPDYSSL, }; struct SpdyNetworkTransactionTestParams { SpdyNetworkTransactionTestParams() : protocol(kProtoSPDY3), ssl_type(SPDYNPN) {} SpdyNetworkTransactionTestParams( NextProto protocol, SpdyNetworkTransactionTestSSLType ssl_type) : protocol(protocol), ssl_type(ssl_type) {} NextProto protocol; SpdyNetworkTransactionTestSSLType ssl_type; }; void UpdateSpdySessionDependencies( SpdyNetworkTransactionTestParams test_params, SpdySessionDependencies* session_deps) { switch (test_params.ssl_type) { case SPDYNPN: session_deps->http_server_properties.SetAlternateProtocol( HostPortPair("www.google.com", 80), 443, AlternateProtocolFromNextProto(test_params.protocol), 1); session_deps->use_alternate_protocols = true; session_deps->next_protos = SpdyNextProtos(); break; case SPDYNOSSL: session_deps->force_spdy_over_ssl = false; session_deps->force_spdy_always = true; break; case SPDYSSL: session_deps->force_spdy_over_ssl = true; session_deps->force_spdy_always = true; break; default: NOTREACHED(); } } SpdySessionDependencies* CreateSpdySessionDependencies( SpdyNetworkTransactionTestParams test_params) { SpdySessionDependencies* session_deps = new SpdySessionDependencies(test_params.protocol); UpdateSpdySessionDependencies(test_params, session_deps); return session_deps; } SpdySessionDependencies* CreateSpdySessionDependencies( SpdyNetworkTransactionTestParams test_params, ProxyService* proxy_service) { SpdySessionDependencies* session_deps = new SpdySessionDependencies(test_params.protocol, proxy_service); UpdateSpdySessionDependencies(test_params, session_deps); return session_deps; } } // namespace class SpdyNetworkTransactionTest : public ::testing::TestWithParam
{ protected: SpdyNetworkTransactionTest() : spdy_util_(GetParam().protocol) { } virtual ~SpdyNetworkTransactionTest() { // UploadDataStream posts deletion tasks back to the message loop on // destruction. upload_data_stream_.reset(); base::RunLoop().RunUntilIdle(); } virtual void SetUp() { google_get_request_initialized_ = false; google_post_request_initialized_ = false; google_chunked_post_request_initialized_ = false; ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); } struct TransactionHelperResult { int rv; std::string status_line; std::string response_data; HttpResponseInfo response_info; }; // A helper class that handles all the initial npn/ssl setup. class NormalSpdyTransactionHelper { public: NormalSpdyTransactionHelper(const HttpRequestInfo& request, RequestPriority priority, const BoundNetLog& log, SpdyNetworkTransactionTestParams test_params, SpdySessionDependencies* session_deps) : request_(request), priority_(priority), session_deps_(session_deps == NULL ? CreateSpdySessionDependencies(test_params) : session_deps), session_(SpdySessionDependencies::SpdyCreateSession( session_deps_.get())), log_(log), test_params_(test_params), deterministic_(false), spdy_enabled_(true) { switch (test_params_.ssl_type) { case SPDYNOSSL: case SPDYSSL: port_ = 80; break; case SPDYNPN: port_ = 443; break; default: NOTREACHED(); } } ~NormalSpdyTransactionHelper() { // Any test which doesn't close the socket by sending it an EOF will // have a valid session left open, which leaks the entire session pool. // This is just fine - in fact, some of our tests intentionally do this // so that we can check consistency of the SpdySessionPool as the test // finishes. If we had put an EOF on the socket, the SpdySession would // have closed and we wouldn't be able to check the consistency. // Forcefully close existing sessions here. session()->spdy_session_pool()->CloseAllSessions(); } void SetDeterministic() { session_ = SpdySessionDependencies::SpdyCreateSessionDeterministic( session_deps_.get()); deterministic_ = true; } void SetSpdyDisabled() { spdy_enabled_ = false; port_ = 80; } void RunPreTestSetup() { if (!session_deps_.get()) session_deps_.reset(CreateSpdySessionDependencies(test_params_)); if (!session_.get()) { session_ = SpdySessionDependencies::SpdyCreateSession( session_deps_.get()); } // We're now ready to use SSL-npn SPDY. trans_.reset(new HttpNetworkTransaction(priority_, session_.get())); } // Start the transaction, read some data, finish. void RunDefaultTest() { if (!StartDefaultTest()) return; FinishDefaultTest(); } bool StartDefaultTest() { output_.rv = trans_->Start(&request_, callback_.callback(), log_); // We expect an IO Pending or some sort of error. EXPECT_LT(output_.rv, 0); return output_.rv == ERR_IO_PENDING; } void FinishDefaultTest() { output_.rv = callback_.WaitForResult(); if (output_.rv != OK) { session_->spdy_session_pool()->CloseCurrentSessions(net::ERR_ABORTED); return; } // Verify responses. const HttpResponseInfo* response = trans_->GetResponseInfo(); ASSERT_TRUE(response != NULL); ASSERT_TRUE(response->headers.get() != NULL); EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); EXPECT_EQ(spdy_enabled_, response->was_fetched_via_spdy); if (HttpStreamFactory::spdy_enabled()) { EXPECT_EQ( HttpResponseInfo::ConnectionInfoFromNextProto( test_params_.protocol), response->connection_info); } else { EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP1, response->connection_info); } if (test_params_.ssl_type == SPDYNPN && spdy_enabled_) { EXPECT_TRUE(response->was_npn_negotiated); } else { EXPECT_TRUE(!response->was_npn_negotiated); } // If SPDY is not enabled, a HTTP request should not be diverted // over a SSL session. if (!spdy_enabled_) { EXPECT_EQ(request_.url.SchemeIs("https"), response->was_npn_negotiated); } EXPECT_EQ("127.0.0.1", response->socket_address.host()); EXPECT_EQ(port_, response->socket_address.port()); output_.status_line = response->headers->GetStatusLine(); output_.response_info = *response; // Make a copy so we can verify. output_.rv = ReadTransaction(trans_.get(), &output_.response_data); } // Most tests will want to call this function. In particular, the MockReads // should end with an empty read, and that read needs to be processed to // ensure proper deletion of the spdy_session_pool. void VerifyDataConsumed() { for (DataVector::iterator it = data_vector_.begin(); it != data_vector_.end(); ++it) { EXPECT_TRUE((*it)->at_read_eof()) << "Read count: " << (*it)->read_count() << " Read index: " << (*it)->read_index(); EXPECT_TRUE((*it)->at_write_eof()) << "Write count: " << (*it)->write_count() << " Write index: " << (*it)->write_index(); } } // Occasionally a test will expect to error out before certain reads are // processed. In that case we want to explicitly ensure that the reads were // not processed. void VerifyDataNotConsumed() { for (DataVector::iterator it = data_vector_.begin(); it != data_vector_.end(); ++it) { EXPECT_TRUE(!(*it)->at_read_eof()) << "Read count: " << (*it)->read_count() << " Read index: " << (*it)->read_index(); EXPECT_TRUE(!(*it)->at_write_eof()) << "Write count: " << (*it)->write_count() << " Write index: " << (*it)->write_index(); } } void RunToCompletion(StaticSocketDataProvider* data) { RunPreTestSetup(); AddData(data); RunDefaultTest(); VerifyDataConsumed(); } void RunToCompletionWithSSLData( StaticSocketDataProvider* data, scoped_ptr
ssl_provider) { RunPreTestSetup(); AddDataWithSSLSocketDataProvider(data, ssl_provider.Pass()); RunDefaultTest(); VerifyDataConsumed(); } void AddData(StaticSocketDataProvider* data) { scoped_ptr
ssl_provider( new SSLSocketDataProvider(ASYNC, OK)); AddDataWithSSLSocketDataProvider(data, ssl_provider.Pass()); } void AddDataWithSSLSocketDataProvider( StaticSocketDataProvider* data, scoped_ptr
ssl_provider) { DCHECK(!deterministic_); data_vector_.push_back(data); if (test_params_.ssl_type == SPDYNPN) ssl_provider->SetNextProto(test_params_.protocol); if (test_params_.ssl_type == SPDYNPN || test_params_.ssl_type == SPDYSSL) { session_deps_->socket_factory->AddSSLSocketDataProvider( ssl_provider.get()); } ssl_vector_.push_back(ssl_provider.release()); session_deps_->socket_factory->AddSocketDataProvider(data); if (test_params_.ssl_type == SPDYNPN) { MockConnect never_finishing_connect(SYNCHRONOUS, ERR_IO_PENDING); StaticSocketDataProvider* hanging_non_alternate_protocol_socket = new StaticSocketDataProvider(NULL, 0, NULL, 0); hanging_non_alternate_protocol_socket->set_connect_data( never_finishing_connect); session_deps_->socket_factory->AddSocketDataProvider( hanging_non_alternate_protocol_socket); alternate_vector_.push_back(hanging_non_alternate_protocol_socket); } } void AddDeterministicData(DeterministicSocketData* data) { DCHECK(deterministic_); data_vector_.push_back(data); SSLSocketDataProvider* ssl_provider = new SSLSocketDataProvider(ASYNC, OK); if (test_params_.ssl_type == SPDYNPN) ssl_provider->SetNextProto(test_params_.protocol); ssl_vector_.push_back(ssl_provider); if (test_params_.ssl_type == SPDYNPN || test_params_.ssl_type == SPDYSSL) { session_deps_->deterministic_socket_factory-> AddSSLSocketDataProvider(ssl_provider); } session_deps_->deterministic_socket_factory->AddSocketDataProvider(data); if (test_params_.ssl_type == SPDYNPN) { MockConnect never_finishing_connect(SYNCHRONOUS, ERR_IO_PENDING); DeterministicSocketData* hanging_non_alternate_protocol_socket = new DeterministicSocketData(NULL, 0, NULL, 0); hanging_non_alternate_protocol_socket->set_connect_data( never_finishing_connect); session_deps_->deterministic_socket_factory->AddSocketDataProvider( hanging_non_alternate_protocol_socket); alternate_deterministic_vector_.push_back( hanging_non_alternate_protocol_socket); } } void SetSession(const scoped_refptr
& session) { session_ = session; } HttpNetworkTransaction* trans() { return trans_.get(); } void ResetTrans() { trans_.reset(); } TransactionHelperResult& output() { return output_; } const HttpRequestInfo& request() const { return request_; } const scoped_refptr
& session() const { return session_; } scoped_ptr
& session_deps() { return session_deps_; } int port() const { return port_; } SpdyNetworkTransactionTestParams test_params() const { return test_params_; } private: typedef std::vector
DataVector; typedef ScopedVector
SSLVector; typedef ScopedVector
AlternateVector; typedef ScopedVector
AlternateDeterministicVector; HttpRequestInfo request_; RequestPriority priority_; scoped_ptr
session_deps_; scoped_refptr
session_; TransactionHelperResult output_; scoped_ptr
first_transaction_; SSLVector ssl_vector_; TestCompletionCallback callback_; scoped_ptr
trans_; scoped_ptr
trans_http_; DataVector data_vector_; AlternateVector alternate_vector_; AlternateDeterministicVector alternate_deterministic_vector_; const BoundNetLog& log_; SpdyNetworkTransactionTestParams test_params_; int port_; bool deterministic_; bool spdy_enabled_; }; void ConnectStatusHelperWithExpectedStatus(const MockRead& status, int expected_status); void ConnectStatusHelper(const MockRead& status); const HttpRequestInfo& CreateGetPushRequest() { google_get_push_request_.method = "GET"; google_get_push_request_.url = GURL("http://www.google.com/foo.dat"); google_get_push_request_.load_flags = 0; return google_get_push_request_; } const HttpRequestInfo& CreateGetRequest() { if (!google_get_request_initialized_) { google_get_request_.method = "GET"; google_get_request_.url = GURL(kDefaultURL); google_get_request_.load_flags = 0; google_get_request_initialized_ = true; } return google_get_request_; } const HttpRequestInfo& CreateGetRequestWithUserAgent() { if (!google_get_request_initialized_) { google_get_request_.method = "GET"; google_get_request_.url = GURL(kDefaultURL); google_get_request_.load_flags = 0; google_get_request_.extra_headers.SetHeader("User-Agent", "Chrome"); google_get_request_initialized_ = true; } return google_get_request_; } const HttpRequestInfo& CreatePostRequest() { if (!google_post_request_initialized_) { ScopedVector
element_readers; element_readers.push_back( new UploadBytesElementReader(kUploadData, kUploadDataSize)); upload_data_stream_.reset( new UploadDataStream(element_readers.Pass(), 0)); google_post_request_.method = "POST"; google_post_request_.url = GURL(kDefaultURL); google_post_request_.upload_data_stream = upload_data_stream_.get(); google_post_request_initialized_ = true; } return google_post_request_; } const HttpRequestInfo& CreateFilePostRequest() { if (!google_post_request_initialized_) { base::FilePath file_path; CHECK(base::CreateTemporaryFileInDir(temp_dir_.path(), &file_path)); CHECK_EQ(static_cast
(kUploadDataSize), base::WriteFile(file_path, kUploadData, kUploadDataSize)); ScopedVector
element_readers; element_readers.push_back( new UploadFileElementReader(base::MessageLoopProxy::current().get(), file_path, 0, kUploadDataSize, base::Time())); upload_data_stream_.reset( new UploadDataStream(element_readers.Pass(), 0)); google_post_request_.method = "POST"; google_post_request_.url = GURL(kDefaultURL); google_post_request_.upload_data_stream = upload_data_stream_.get(); google_post_request_initialized_ = true; } return google_post_request_; } const HttpRequestInfo& CreateUnreadableFilePostRequest() { if (google_post_request_initialized_) return google_post_request_; base::FilePath file_path; CHECK(base::CreateTemporaryFileInDir(temp_dir_.path(), &file_path)); CHECK_EQ(static_cast
(kUploadDataSize), base::WriteFile(file_path, kUploadData, kUploadDataSize)); CHECK(base::MakeFileUnreadable(file_path)); ScopedVector
element_readers; element_readers.push_back( new UploadFileElementReader(base::MessageLoopProxy::current().get(), file_path, 0, kUploadDataSize, base::Time())); upload_data_stream_.reset( new UploadDataStream(element_readers.Pass(), 0)); google_post_request_.method = "POST"; google_post_request_.url = GURL(kDefaultURL); google_post_request_.upload_data_stream = upload_data_stream_.get(); google_post_request_initialized_ = true; return google_post_request_; } const HttpRequestInfo& CreateComplexPostRequest() { if (!google_post_request_initialized_) { const int kFileRangeOffset = 1; const int kFileRangeLength = 3; CHECK_LT(kFileRangeOffset + kFileRangeLength, kUploadDataSize); base::FilePath file_path; CHECK(base::CreateTemporaryFileInDir(temp_dir_.path(), &file_path)); CHECK_EQ(static_cast
(kUploadDataSize), base::WriteFile(file_path, kUploadData, kUploadDataSize)); ScopedVector
element_readers; element_readers.push_back( new UploadBytesElementReader(kUploadData, kFileRangeOffset)); element_readers.push_back( new UploadFileElementReader(base::MessageLoopProxy::current().get(), file_path, kFileRangeOffset, kFileRangeLength, base::Time())); element_readers.push_back(new UploadBytesElementReader( kUploadData + kFileRangeOffset + kFileRangeLength, kUploadDataSize - (kFileRangeOffset + kFileRangeLength))); upload_data_stream_.reset( new UploadDataStream(element_readers.Pass(), 0)); google_post_request_.method = "POST"; google_post_request_.url = GURL(kDefaultURL); google_post_request_.upload_data_stream = upload_data_stream_.get(); google_post_request_initialized_ = true; } return google_post_request_; } const HttpRequestInfo& CreateChunkedPostRequest() { if (!google_chunked_post_request_initialized_) { upload_data_stream_.reset( new UploadDataStream(UploadDataStream::CHUNKED, 0)); google_chunked_post_request_.method = "POST"; google_chunked_post_request_.url = GURL(kDefaultURL); google_chunked_post_request_.upload_data_stream = upload_data_stream_.get(); google_chunked_post_request_initialized_ = true; } return google_chunked_post_request_; } // Read the result of a particular transaction, knowing that we've got // multiple transactions in the read pipeline; so as we read, we may have // to skip over data destined for other transactions while we consume // the data for |trans|. int ReadResult(HttpNetworkTransaction* trans, StaticSocketDataProvider* data, std::string* result) { const int kSize = 3000; int bytes_read = 0; scoped_refptr
buf(new net::IOBufferWithSize(kSize)); TestCompletionCallback callback; while (true) { int rv = trans->Read(buf.get(), kSize, callback.callback()); if (rv == ERR_IO_PENDING) { // Multiple transactions may be in the data set. Keep pulling off // reads until we complete our callback. while (!callback.have_result()) { data->CompleteRead(); base::RunLoop().RunUntilIdle(); } rv = callback.WaitForResult(); } else if (rv <= 0) { break; } result->append(buf->data(), rv); bytes_read += rv; } return bytes_read; } void VerifyStreamsClosed(const NormalSpdyTransactionHelper& helper) { // This lengthy block is reaching into the pool to dig out the active // session. Once we have the session, we verify that the streams are // all closed and not leaked at this point. const GURL& url = helper.request().url; int port = helper.test_params().ssl_type == SPDYNPN ? 443 : 80; HostPortPair host_port_pair(url.host(), port); SpdySessionKey key(host_port_pair, ProxyServer::Direct(), PRIVACY_MODE_DISABLED); BoundNetLog log; const scoped_refptr
& session = helper.session(); base::WeakPtr
spdy_session = session->spdy_session_pool()->FindAvailableSession(key, log); ASSERT_TRUE(spdy_session != NULL); EXPECT_EQ(0u, spdy_session->num_active_streams()); EXPECT_EQ(0u, spdy_session->num_unclaimed_pushed_streams()); } void RunServerPushTest(OrderedSocketData* data, HttpResponseInfo* response, HttpResponseInfo* push_response, const std::string& expected) { NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL); helper.RunPreTestSetup(); helper.AddData(data); HttpNetworkTransaction* trans = helper.trans(); // Start the transaction with basic parameters. TestCompletionCallback callback; int rv = trans->Start( &CreateGetRequest(), callback.callback(), BoundNetLog()); EXPECT_EQ(ERR_IO_PENDING, rv); rv = callback.WaitForResult(); // Request the pushed path. scoped_ptr
trans2( new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get())); rv = trans2->Start( &CreateGetPushRequest(), callback.callback(), BoundNetLog()); EXPECT_EQ(ERR_IO_PENDING, rv); base::RunLoop().RunUntilIdle(); // The data for the pushed path may be coming in more than 1 frame. Compile // the results into a single string. // Read the server push body. std::string result2; ReadResult(trans2.get(), data, &result2); // Read the response body. std::string result; ReadResult(trans, data, &result); // Verify that we consumed all test data. EXPECT_TRUE(data->at_read_eof()); EXPECT_TRUE(data->at_write_eof()); // Verify that the received push data is same as the expected push data. EXPECT_EQ(result2.compare(expected), 0) << "Received data: " << result2 << "||||| Expected data: " << expected; // Verify the SYN_REPLY. // Copy the response info, because trans goes away. *response = *trans->GetResponseInfo(); *push_response = *trans2->GetResponseInfo(); VerifyStreamsClosed(helper); } static void DeleteSessionCallback(NormalSpdyTransactionHelper* helper, int result) { helper->ResetTrans(); } static void StartTransactionCallback( const scoped_refptr
& session, int result) { scoped_ptr
trans( new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); TestCompletionCallback callback; HttpRequestInfo request; request.method = "GET"; request.url = GURL("http://www.google.com/"); request.load_flags = 0; int rv = trans->Start(&request, callback.callback(), BoundNetLog()); EXPECT_EQ(ERR_IO_PENDING, rv); callback.WaitForResult(); } SpdyTestUtil spdy_util_; private: scoped_ptr
upload_data_stream_; bool google_get_request_initialized_; bool google_post_request_initialized_; bool google_chunked_post_request_initialized_; HttpRequestInfo google_get_request_; HttpRequestInfo google_post_request_; HttpRequestInfo google_chunked_post_request_; HttpRequestInfo google_get_push_request_; base::ScopedTempDir temp_dir_; }; //----------------------------------------------------------------------------- // All tests are run with three different connection types: SPDY after NPN // negotiation, SPDY without SSL, and SPDY with SSL. // // TODO(akalin): Use ::testing::Combine() when we are able to use //
. INSTANTIATE_TEST_CASE_P( Spdy, SpdyNetworkTransactionTest, ::testing::Values( SpdyNetworkTransactionTestParams(kProtoDeprecatedSPDY2, SPDYNOSSL), SpdyNetworkTransactionTestParams(kProtoDeprecatedSPDY2, SPDYSSL), SpdyNetworkTransactionTestParams(kProtoDeprecatedSPDY2, SPDYNPN), SpdyNetworkTransactionTestParams(kProtoSPDY3, SPDYNOSSL), SpdyNetworkTransactionTestParams(kProtoSPDY3, SPDYSSL), SpdyNetworkTransactionTestParams(kProtoSPDY3, SPDYNPN), SpdyNetworkTransactionTestParams(kProtoSPDY31, SPDYNOSSL), SpdyNetworkTransactionTestParams(kProtoSPDY31, SPDYSSL), SpdyNetworkTransactionTestParams(kProtoSPDY31, SPDYNPN), SpdyNetworkTransactionTestParams(kProtoSPDY4, SPDYNOSSL), SpdyNetworkTransactionTestParams(kProtoSPDY4, SPDYSSL), SpdyNetworkTransactionTestParams(kProtoSPDY4, SPDYNPN))); // Verify HttpNetworkTransaction constructor. TEST_P(SpdyNetworkTransactionTest, Constructor) { scoped_ptr
session_deps( CreateSpdySessionDependencies(GetParam())); scoped_refptr
session( SpdySessionDependencies::SpdyCreateSession(session_deps.get())); scoped_ptr
trans( new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); } TEST_P(SpdyNetworkTransactionTest, Get) { // Construct the request. scoped_ptr
req( spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); MockWrite writes[] = { CreateMockWrite(*req) }; scoped_ptr
resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); scoped_ptr
body(spdy_util_.ConstructSpdyBodyFrame(1, true)); MockRead reads[] = { CreateMockRead(*resp), CreateMockRead(*body), MockRead(ASYNC, 0, 0) // EOF }; DelayedSocketData data(1, reads, arraysize(reads), writes, arraysize(writes)); NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL); helper.RunToCompletion(&data); TransactionHelperResult out = helper.output(); EXPECT_EQ(OK, out.rv); EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); EXPECT_EQ("hello!", out.response_data); } TEST_P(SpdyNetworkTransactionTest, GetAtEachPriority) { for (RequestPriority p = MINIMUM_PRIORITY; p <= MAXIMUM_PRIORITY; p = RequestPriority(p + 1)) { // Construct the request. scoped_ptr
req( spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, p, true)); MockWrite writes[] = { CreateMockWrite(*req) }; SpdyPriority spdy_prio = 0; EXPECT_TRUE(GetSpdyPriority(spdy_util_.spdy_version(), *req, &spdy_prio)); // this repeats the RequestPriority-->SpdyPriority mapping from // SpdyFramer::ConvertRequestPriorityToSpdyPriority to make // sure it's being done right. if (spdy_util_.spdy_version() < SPDY3) { switch(p) { case HIGHEST: EXPECT_EQ(0, spdy_prio); break; case MEDIUM: EXPECT_EQ(1, spdy_prio); break; case LOW: case LOWEST: EXPECT_EQ(2, spdy_prio); break; case IDLE: EXPECT_EQ(3, spdy_prio); break; default: FAIL(); } } else { switch(p) { case HIGHEST: EXPECT_EQ(0, spdy_prio); break; case MEDIUM: EXPECT_EQ(1, spdy_prio); break; case LOW: EXPECT_EQ(2, spdy_prio); break; case LOWEST: EXPECT_EQ(3, spdy_prio); break; case IDLE: EXPECT_EQ(4, spdy_prio); break; default: FAIL(); } } scoped_ptr
resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); scoped_ptr
body(spdy_util_.ConstructSpdyBodyFrame(1, true)); MockRead reads[] = { CreateMockRead(*resp), CreateMockRead(*body), MockRead(ASYNC, 0, 0) // EOF }; DelayedSocketData data(1, reads, arraysize(reads), writes, arraysize(writes)); HttpRequestInfo http_req = CreateGetRequest(); NormalSpdyTransactionHelper helper(http_req, p, BoundNetLog(), GetParam(), NULL); helper.RunToCompletion(&data); TransactionHelperResult out = helper.output(); EXPECT_EQ(OK, out.rv); EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); EXPECT_EQ("hello!", out.response_data); } } // Start three gets simultaniously; making sure that multiplexed // streams work properly. // This can't use the TransactionHelper method, since it only // handles a single transaction, and finishes them as soon // as it launches them. // TODO(gavinp): create a working generalized TransactionHelper that // can allow multiple streams in flight. TEST_P(SpdyNetworkTransactionTest, ThreeGets) { scoped_ptr
req( spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); scoped_ptr
resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); scoped_ptr
body(spdy_util_.ConstructSpdyBodyFrame(1, false)); scoped_ptr
fbody(spdy_util_.ConstructSpdyBodyFrame(1, true)); scoped_ptr
req2( spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, LOWEST, true)); scoped_ptr
resp2(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3)); scoped_ptr
body2(spdy_util_.ConstructSpdyBodyFrame(3, false)); scoped_ptr
fbody2(spdy_util_.ConstructSpdyBodyFrame(3, true)); scoped_ptr
req3( spdy_util_.ConstructSpdyGet(NULL, 0, false, 5, LOWEST, true)); scoped_ptr
resp3(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 5)); scoped_ptr
body3(spdy_util_.ConstructSpdyBodyFrame(5, false)); scoped_ptr
fbody3(spdy_util_.ConstructSpdyBodyFrame(5, true)); MockWrite writes[] = { CreateMockWrite(*req), CreateMockWrite(*req2), CreateMockWrite(*req3), }; MockRead reads[] = { CreateMockRead(*resp, 1), CreateMockRead(*body), CreateMockRead(*resp2, 4), CreateMockRead(*body2), CreateMockRead(*resp3, 7), CreateMockRead(*body3), CreateMockRead(*fbody), CreateMockRead(*fbody2), CreateMockRead(*fbody3), MockRead(ASYNC, 0, 0), // EOF }; OrderedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); OrderedSocketData data_placeholder(NULL, 0, NULL, 0); BoundNetLog log; TransactionHelperResult out; NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL); helper.RunPreTestSetup(); helper.AddData(&data); // We require placeholder data because three get requests are sent out, so // there needs to be three sets of SSL connection data. helper.AddData(&data_placeholder); helper.AddData(&data_placeholder); scoped_ptr
trans1( new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get())); scoped_ptr
trans2( new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get())); scoped_ptr
trans3( new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get())); TestCompletionCallback callback1; TestCompletionCallback callback2; TestCompletionCallback callback3; HttpRequestInfo httpreq1 = CreateGetRequest(); HttpRequestInfo httpreq2 = CreateGetRequest(); HttpRequestInfo httpreq3 = CreateGetRequest(); out.rv = trans1->Start(&httpreq1, callback1.callback(), log); ASSERT_EQ(ERR_IO_PENDING, out.rv); out.rv = trans2->Start(&httpreq2, callback2.callback(), log); ASSERT_EQ(ERR_IO_PENDING, out.rv); out.rv = trans3->Start(&httpreq3, callback3.callback(), log); ASSERT_EQ(ERR_IO_PENDING, out.rv); out.rv = callback1.WaitForResult(); ASSERT_EQ(OK, out.rv); out.rv = callback3.WaitForResult(); ASSERT_EQ(OK, out.rv); const HttpResponseInfo* response1 = trans1->GetResponseInfo(); EXPECT_TRUE(response1->headers.get() != NULL); EXPECT_TRUE(response1->was_fetched_via_spdy); out.status_line = response1->headers->GetStatusLine(); out.response_info = *response1; trans2->GetResponseInfo(); out.rv = ReadTransaction(trans1.get(), &out.response_data); helper.VerifyDataConsumed(); EXPECT_EQ(OK, out.rv); EXPECT_EQ(OK, out.rv); EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); EXPECT_EQ("hello!hello!", out.response_data); } TEST_P(SpdyNetworkTransactionTest, TwoGetsLateBinding) { scoped_ptr
req( spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); scoped_ptr
resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); scoped_ptr
body(spdy_util_.ConstructSpdyBodyFrame(1, false)); scoped_ptr
fbody(spdy_util_.ConstructSpdyBodyFrame(1, true)); scoped_ptr
req2( spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, LOWEST, true)); scoped_ptr
resp2(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3)); scoped_ptr
body2(spdy_util_.ConstructSpdyBodyFrame(3, false)); scoped_ptr
fbody2(spdy_util_.ConstructSpdyBodyFrame(3, true)); MockWrite writes[] = { CreateMockWrite(*req), CreateMockWrite(*req2), }; MockRead reads[] = { CreateMockRead(*resp, 1), CreateMockRead(*body), CreateMockRead(*resp2, 4), CreateMockRead(*body2), CreateMockRead(*fbody), CreateMockRead(*fbody2), MockRead(ASYNC, 0, 0), // EOF }; OrderedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); MockConnect never_finishing_connect(SYNCHRONOUS, ERR_IO_PENDING); OrderedSocketData data_placeholder(NULL, 0, NULL, 0); data_placeholder.set_connect_data(never_finishing_connect); BoundNetLog log; TransactionHelperResult out; NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL); helper.RunPreTestSetup(); helper.AddData(&data); // We require placeholder data because two get requests are sent out, so // there needs to be two sets of SSL connection data. helper.AddData(&data_placeholder); scoped_ptr
trans1( new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get())); scoped_ptr
trans2( new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get())); TestCompletionCallback callback1; TestCompletionCallback callback2; HttpRequestInfo httpreq1 = CreateGetRequest(); HttpRequestInfo httpreq2 = CreateGetRequest(); out.rv = trans1->Start(&httpreq1, callback1.callback(), log); ASSERT_EQ(ERR_IO_PENDING, out.rv); out.rv = trans2->Start(&httpreq2, callback2.callback(), log); ASSERT_EQ(ERR_IO_PENDING, out.rv); out.rv = callback1.WaitForResult(); ASSERT_EQ(OK, out.rv); out.rv = callback2.WaitForResult(); ASSERT_EQ(OK, out.rv); const HttpResponseInfo* response1 = trans1->GetResponseInfo(); EXPECT_TRUE(response1->headers.get() != NULL); EXPECT_TRUE(response1->was_fetched_via_spdy); out.status_line = response1->headers->GetStatusLine(); out.response_info = *response1; out.rv = ReadTransaction(trans1.get(), &out.response_data); EXPECT_EQ(OK, out.rv); EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); EXPECT_EQ("hello!hello!", out.response_data); const HttpResponseInfo* response2 = trans2->GetResponseInfo(); EXPECT_TRUE(response2->headers.get() != NULL); EXPECT_TRUE(response2->was_fetched_via_spdy); out.status_line = response2->headers->GetStatusLine(); out.response_info = *response2; out.rv = ReadTransaction(trans2.get(), &out.response_data); EXPECT_EQ(OK, out.rv); EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); EXPECT_EQ("hello!hello!", out.response_data); helper.VerifyDataConsumed(); } TEST_P(SpdyNetworkTransactionTest, TwoGetsLateBindingFromPreconnect) { scoped_ptr
req( spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); scoped_ptr
resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); scoped_ptr
body(spdy_util_.ConstructSpdyBodyFrame(1, false)); scoped_ptr
fbody(spdy_util_.ConstructSpdyBodyFrame(1, true)); scoped_ptr
req2( spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, LOWEST, true)); scoped_ptr
resp2(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3)); scoped_ptr
body2(spdy_util_.ConstructSpdyBodyFrame(3, false)); scoped_ptr
fbody2(spdy_util_.ConstructSpdyBodyFrame(3, true)); MockWrite writes[] = { CreateMockWrite(*req), CreateMockWrite(*req2), }; MockRead reads[] = { CreateMockRead(*resp, 1), CreateMockRead(*body), CreateMockRead(*resp2, 4), CreateMockRead(*body2), CreateMockRead(*fbody), CreateMockRead(*fbody2), MockRead(ASYNC, 0, 0), // EOF }; OrderedSocketData preconnect_data(reads, arraysize(reads), writes, arraysize(writes)); MockConnect never_finishing_connect(ASYNC, ERR_IO_PENDING); OrderedSocketData data_placeholder(NULL, 0, NULL, 0); data_placeholder.set_connect_data(never_finishing_connect); BoundNetLog log; TransactionHelperResult out; NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL); helper.RunPreTestSetup(); helper.AddData(&preconnect_data); // We require placeholder data because 3 connections are attempted (first is // the preconnect, 2nd and 3rd are the never finished connections. helper.AddData(&data_placeholder); helper.AddData(&data_placeholder); scoped_ptr
trans1( new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get())); scoped_ptr
trans2( new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get())); TestCompletionCallback callback1; TestCompletionCallback callback2; HttpRequestInfo httpreq = CreateGetRequest(); // Preconnect the first. SSLConfig preconnect_ssl_config; helper.session()->ssl_config_service()->GetSSLConfig(&preconnect_ssl_config); HttpStreamFactory* http_stream_factory = helper.session()->http_stream_factory(); helper.session()->GetNextProtos(&preconnect_ssl_config.next_protos); http_stream_factory->PreconnectStreams( 1, httpreq, DEFAULT_PRIORITY, preconnect_ssl_config, preconnect_ssl_config); out.rv = trans1->Start(&httpreq, callback1.callback(), log); ASSERT_EQ(ERR_IO_PENDING, out.rv); out.rv = trans2->Start(&httpreq, callback2.callback(), log); ASSERT_EQ(ERR_IO_PENDING, out.rv); out.rv = callback1.WaitForResult(); ASSERT_EQ(OK, out.rv); out.rv = callback2.WaitForResult(); ASSERT_EQ(OK, out.rv); const HttpResponseInfo* response1 = trans1->GetResponseInfo(); EXPECT_TRUE(response1->headers.get() != NULL); EXPECT_TRUE(response1->was_fetched_via_spdy); out.status_line = response1->headers->GetStatusLine(); out.response_info = *response1; out.rv = ReadTransaction(trans1.get(), &out.response_data); EXPECT_EQ(OK, out.rv); EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); EXPECT_EQ("hello!hello!", out.response_data); const HttpResponseInfo* response2 = trans2->GetResponseInfo(); EXPECT_TRUE(response2->headers.get() != NULL); EXPECT_TRUE(response2->was_fetched_via_spdy); out.status_line = response2->headers->GetStatusLine(); out.response_info = *response2; out.rv = ReadTransaction(trans2.get(), &out.response_data); EXPECT_EQ(OK, out.rv); EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); EXPECT_EQ("hello!hello!", out.response_data); helper.VerifyDataConsumed(); } // Similar to ThreeGets above, however this test adds a SETTINGS // frame. The SETTINGS frame is read during the IO loop waiting on // the first transaction completion, and sets a maximum concurrent // stream limit of 1. This means that our IO loop exists after the // second transaction completes, so we can assert on read_index(). TEST_P(SpdyNetworkTransactionTest, ThreeGetsWithMaxConcurrent) { // Construct the request. scoped_ptr
req( spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); scoped_ptr
resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); scoped_ptr
body(spdy_util_.ConstructSpdyBodyFrame(1, false)); scoped_ptr
fbody(spdy_util_.ConstructSpdyBodyFrame(1, true)); scoped_ptr
req2( spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, LOWEST, true)); scoped_ptr
resp2(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3)); scoped_ptr
body2(spdy_util_.ConstructSpdyBodyFrame(3, false)); scoped_ptr
fbody2(spdy_util_.ConstructSpdyBodyFrame(3, true)); scoped_ptr
req3( spdy_util_.ConstructSpdyGet(NULL, 0, false, 5, LOWEST, true)); scoped_ptr
resp3(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 5)); scoped_ptr
body3(spdy_util_.ConstructSpdyBodyFrame(5, false)); scoped_ptr
fbody3(spdy_util_.ConstructSpdyBodyFrame(5, true)); SettingsMap settings; const uint32 max_concurrent_streams = 1; settings[SETTINGS_MAX_CONCURRENT_STREAMS] = SettingsFlagsAndValue(SETTINGS_FLAG_NONE, max_concurrent_streams); scoped_ptr
settings_frame( spdy_util_.ConstructSpdySettings(settings)); scoped_ptr
settings_ack(spdy_util_.ConstructSpdySettingsAck()); MockWrite writes[] = { CreateMockWrite(*req), CreateMockWrite(*settings_ack, 2), CreateMockWrite(*req2), CreateMockWrite(*req3), }; MockRead reads[] = { CreateMockRead(*settings_frame, 1), CreateMockRead(*resp), CreateMockRead(*body), CreateMockRead(*fbody), CreateMockRead(*resp2, 8), CreateMockRead(*body2), CreateMockRead(*fbody2), CreateMockRead(*resp3, 13), CreateMockRead(*body3), CreateMockRead(*fbody3), MockRead(ASYNC, 0, 0), // EOF }; OrderedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); OrderedSocketData data_placeholder(NULL, 0, NULL, 0); BoundNetLog log; TransactionHelperResult out; { NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL); helper.RunPreTestSetup(); helper.AddData(&data); // We require placeholder data because three get requests are sent out, so // there needs to be three sets of SSL connection data. helper.AddData(&data_placeholder); helper.AddData(&data_placeholder); scoped_ptr
trans1( new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get())); scoped_ptr
trans2( new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get())); scoped_ptr
trans3( new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get())); TestCompletionCallback callback1; TestCompletionCallback callback2; TestCompletionCallback callback3; HttpRequestInfo httpreq1 = CreateGetRequest(); HttpRequestInfo httpreq2 = CreateGetRequest(); HttpRequestInfo httpreq3 = CreateGetRequest(); out.rv = trans1->Start(&httpreq1, callback1.callback(), log); ASSERT_EQ(out.rv, ERR_IO_PENDING); // Run transaction 1 through quickly to force a read of our SETTINGS // frame. out.rv = callback1.WaitForResult(); ASSERT_EQ(OK, out.rv); out.rv = trans2->Start(&httpreq2, callback2.callback(), log); ASSERT_EQ(out.rv, ERR_IO_PENDING); out.rv = trans3->Start(&httpreq3, callback3.callback(), log); ASSERT_EQ(out.rv, ERR_IO_PENDING); out.rv = callback2.WaitForResult(); ASSERT_EQ(OK, out.rv); EXPECT_EQ(7U, data.read_index()); // i.e. the third trans was queued out.rv = callback3.WaitForResult(); ASSERT_EQ(OK, out.rv); const HttpResponseInfo* response1 = trans1->GetResponseInfo(); ASSERT_TRUE(response1 != NULL); EXPECT_TRUE(response1->headers.get() != NULL); EXPECT_TRUE(response1->was_fetched_via_spdy); out.status_line = response1->headers->GetStatusLine(); out.response_info = *response1; out.rv = ReadTransaction(trans1.get(), &out.response_data); EXPECT_EQ(OK, out.rv); EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); EXPECT_EQ("hello!hello!", out.response_data); const HttpResponseInfo* response2 = trans2->GetResponseInfo(); out.status_line = response2->headers->GetStatusLine(); out.response_info = *response2; out.rv = ReadTransaction(trans2.get(), &out.response_data); EXPECT_EQ(OK, out.rv); EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); EXPECT_EQ("hello!hello!", out.response_data); const HttpResponseInfo* response3 = trans3->GetResponseInfo(); out.status_line = response3->headers->GetStatusLine(); out.response_info = *response3; out.rv = ReadTransaction(trans3.get(), &out.response_data); EXPECT_EQ(OK, out.rv); EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); EXPECT_EQ("hello!hello!", out.response_data); helper.VerifyDataConsumed(); } EXPECT_EQ(OK, out.rv); } // Similar to ThreeGetsWithMaxConcurrent above, however this test adds // a fourth transaction. The third and fourth transactions have // different data ("hello!" vs "hello!hello!") and because of the // user specified priority, we expect to see them inverted in // the response from the server. TEST_P(SpdyNetworkTransactionTest, FourGetsWithMaxConcurrentPriority) { // Construct the request. scoped_ptr
req( spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); scoped_ptr
resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); scoped_ptr
body(spdy_util_.ConstructSpdyBodyFrame(1, false)); scoped_ptr
fbody(spdy_util_.ConstructSpdyBodyFrame(1, true)); scoped_ptr
req2( spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, LOWEST, true)); scoped_ptr
resp2(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3)); scoped_ptr
body2(spdy_util_.ConstructSpdyBodyFrame(3, false)); scoped_ptr
fbody2(spdy_util_.ConstructSpdyBodyFrame(3, true)); scoped_ptr
req4( spdy_util_.ConstructSpdyGet(NULL, 0, false, 5, HIGHEST, true)); scoped_ptr
resp4(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 5)); scoped_ptr
fbody4(spdy_util_.ConstructSpdyBodyFrame(5, true)); scoped_ptr
req3( spdy_util_.ConstructSpdyGet(NULL, 0, false, 7, LOWEST, true)); scoped_ptr
resp3(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 7)); scoped_ptr
body3(spdy_util_.ConstructSpdyBodyFrame(7, false)); scoped_ptr
fbody3(spdy_util_.ConstructSpdyBodyFrame(7, true)); SettingsMap settings; const uint32 max_concurrent_streams = 1; settings[SETTINGS_MAX_CONCURRENT_STREAMS] = SettingsFlagsAndValue(SETTINGS_FLAG_NONE, max_concurrent_streams); scoped_ptr
settings_frame( spdy_util_.ConstructSpdySettings(settings)); scoped_ptr
settings_ack(spdy_util_.ConstructSpdySettingsAck()); MockWrite writes[] = { CreateMockWrite(*req), CreateMockWrite(*settings_ack, 2), CreateMockWrite(*req2), CreateMockWrite(*req4), CreateMockWrite(*req3), }; MockRead reads[] = { CreateMockRead(*settings_frame, 1), CreateMockRead(*resp), CreateMockRead(*body), CreateMockRead(*fbody), CreateMockRead(*resp2, 8), CreateMockRead(*body2), CreateMockRead(*fbody2), CreateMockRead(*resp4, 14), CreateMockRead(*fbody4), CreateMockRead(*resp3, 17), CreateMockRead(*body3), CreateMockRead(*fbody3), MockRead(ASYNC, 0, 0), // EOF }; OrderedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); OrderedSocketData data_placeholder(NULL, 0, NULL, 0); BoundNetLog log; TransactionHelperResult out; NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL); helper.RunPreTestSetup(); helper.AddData(&data); // We require placeholder data because four get requests are sent out, so // there needs to be four sets of SSL connection data. helper.AddData(&data_placeholder); helper.AddData(&data_placeholder); helper.AddData(&data_placeholder); scoped_ptr
trans1( new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get())); scoped_ptr
trans2( new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get())); scoped_ptr
trans3( new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get())); scoped_ptr
trans4( new HttpNetworkTransaction(HIGHEST, helper.session().get())); TestCompletionCallback callback1; TestCompletionCallback callback2; TestCompletionCallback callback3; TestCompletionCallback callback4; HttpRequestInfo httpreq1 = CreateGetRequest(); HttpRequestInfo httpreq2 = CreateGetRequest(); HttpRequestInfo httpreq3 = CreateGetRequest(); HttpRequestInfo httpreq4 = CreateGetRequest(); out.rv = trans1->Start(&httpreq1, callback1.callback(), log); ASSERT_EQ(ERR_IO_PENDING, out.rv); // Run transaction 1 through quickly to force a read of our SETTINGS frame. out.rv = callback1.WaitForResult(); ASSERT_EQ(OK, out.rv); out.rv = trans2->Start(&httpreq2, callback2.callback(), log); ASSERT_EQ(ERR_IO_PENDING, out.rv); out.rv = trans3->Start(&httpreq3, callback3.callback(), log); ASSERT_EQ(ERR_IO_PENDING, out.rv); out.rv = trans4->Start(&httpreq4, callback4.callback(), log); ASSERT_EQ(ERR_IO_PENDING, out.rv); out.rv = callback2.WaitForResult(); ASSERT_EQ(OK, out.rv); EXPECT_EQ(data.read_index(), 7U); // i.e. the third & fourth trans queued out.rv = callback3.WaitForResult(); ASSERT_EQ(OK, out.rv); const HttpResponseInfo* response1 = trans1->GetResponseInfo(); EXPECT_TRUE(response1->headers.get() != NULL); EXPECT_TRUE(response1->was_fetched_via_spdy); out.status_line = response1->headers->GetStatusLine(); out.response_info = *response1; out.rv = ReadTransaction(trans1.get(), &out.response_data); EXPECT_EQ(OK, out.rv); EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); EXPECT_EQ("hello!hello!", out.response_data); const HttpResponseInfo* response2 = trans2->GetResponseInfo(); out.status_line = response2->headers->GetStatusLine(); out.response_info = *response2; out.rv = ReadTransaction(trans2.get(), &out.response_data); EXPECT_EQ(OK, out.rv); EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); EXPECT_EQ("hello!hello!", out.response_data); // notice: response3 gets two hellos, response4 gets one // hello, so we know dequeuing priority was respected. const HttpResponseInfo* response3 = trans3->GetResponseInfo(); out.status_line = response3->headers->GetStatusLine(); out.response_info = *response3; out.rv = ReadTransaction(trans3.get(), &out.response_data); EXPECT_EQ(OK, out.rv); EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); EXPECT_EQ("hello!hello!", out.response_data); out.rv = callback4.WaitForResult(); EXPECT_EQ(OK, out.rv); const HttpResponseInfo* response4 = trans4->GetResponseInfo(); out.status_line = response4->headers->GetStatusLine(); out.response_info = *response4; out.rv = ReadTransaction(trans4.get(), &out.response_data); EXPECT_EQ(OK, out.rv); EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); EXPECT_EQ("hello!", out.response_data); helper.VerifyDataConsumed(); EXPECT_EQ(OK, out.rv); } // Similar to ThreeGetsMaxConcurrrent above, however, this test // deletes a session in the middle of the transaction to insure // that we properly remove pendingcreatestream objects from // the spdy_session TEST_P(SpdyNetworkTransactionTest, ThreeGetsWithMaxConcurrentDelete) { // Construct the request. scoped_ptr
req( spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); scoped_ptr
resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); scoped_ptr
body(spdy_util_.ConstructSpdyBodyFrame(1, false)); scoped_ptr
fbody(spdy_util_.ConstructSpdyBodyFrame(1, true)); scoped_ptr
req2( spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, LOWEST, true)); scoped_ptr
resp2(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3)); scoped_ptr
body2(spdy_util_.ConstructSpdyBodyFrame(3, false)); scoped_ptr
fbody2(spdy_util_.ConstructSpdyBodyFrame(3, true)); SettingsMap settings; const uint32 max_concurrent_streams = 1; settings[SETTINGS_MAX_CONCURRENT_STREAMS] = SettingsFlagsAndValue(SETTINGS_FLAG_NONE, max_concurrent_streams); scoped_ptr
settings_frame( spdy_util_.ConstructSpdySettings(settings)); scoped_ptr
settings_ack(spdy_util_.ConstructSpdySettingsAck()); MockWrite writes[] = { CreateMockWrite(*req), CreateMockWrite(*settings_ack, 2), CreateMockWrite(*req2), }; MockRead reads[] = { CreateMockRead(*settings_frame, 1), CreateMockRead(*resp), CreateMockRead(*body), CreateMockRead(*fbody), CreateMockRead(*resp2, 8), CreateMockRead(*body2), CreateMockRead(*fbody2), MockRead(ASYNC, 0, 0), // EOF }; OrderedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); OrderedSocketData data_placeholder(NULL, 0, NULL, 0); BoundNetLog log; TransactionHelperResult out; NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL); helper.RunPreTestSetup(); helper.AddData(&data); // We require placeholder data because three get requests are sent out, so // there needs to be three sets of SSL connection data. helper.AddData(&data_placeholder); helper.AddData(&data_placeholder); scoped_ptr
trans1( new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get())); scoped_ptr
trans2( new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get())); scoped_ptr
trans3( new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get())); TestCompletionCallback callback1; TestCompletionCallback callback2; TestCompletionCallback callback3; HttpRequestInfo httpreq1 = CreateGetRequest(); HttpRequestInfo httpreq2 = CreateGetRequest(); HttpRequestInfo httpreq3 = CreateGetRequest(); out.rv = trans1->Start(&httpreq1, callback1.callback(), log); ASSERT_EQ(out.rv, ERR_IO_PENDING); // Run transaction 1 through quickly to force a read of our SETTINGS frame. out.rv = callback1.WaitForResult(); ASSERT_EQ(OK, out.rv); out.rv = trans2->Start(&httpreq2, callback2.callback(), log); ASSERT_EQ(out.rv, ERR_IO_PENDING); out.rv = trans3->Start(&httpreq3, callback3.callback(), log); delete trans3.release(); ASSERT_EQ(out.rv, ERR_IO_PENDING); out.rv = callback2.WaitForResult(); ASSERT_EQ(OK, out.rv); EXPECT_EQ(8U, data.read_index()); const HttpResponseInfo* response1 = trans1->GetResponseInfo(); ASSERT_TRUE(response1 != NULL); EXPECT_TRUE(response1->headers.get() != NULL); EXPECT_TRUE(response1->was_fetched_via_spdy); out.status_line = response1->headers->GetStatusLine(); out.response_info = *response1; out.rv = ReadTransaction(trans1.get(), &out.response_data); EXPECT_EQ(OK, out.rv); EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); EXPECT_EQ("hello!hello!", out.response_data); const HttpResponseInfo* response2 = trans2->GetResponseInfo(); ASSERT_TRUE(response2 != NULL); out.status_line = response2->headers->GetStatusLine(); out.response_info = *response2; out.rv = ReadTransaction(trans2.get(), &out.response_data); EXPECT_EQ(OK, out.rv); EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); EXPECT_EQ("hello!hello!", out.response_data); helper.VerifyDataConsumed(); EXPECT_EQ(OK, out.rv); } namespace { // The KillerCallback will delete the transaction on error as part of the // callback. class KillerCallback : public TestCompletionCallbackBase { public: explicit KillerCallback(HttpNetworkTransaction* transaction) : transaction_(transaction), callback_(base::Bind(&KillerCallback::OnComplete, base::Unretained(this))) { } virtual ~KillerCallback() {} const CompletionCallback& callback() const { return callback_; } private: void OnComplete(int result) { if (result < 0) delete transaction_; SetResult(result); } HttpNetworkTransaction* transaction_; CompletionCallback callback_; }; } // namespace // Similar to ThreeGetsMaxConcurrrentDelete above, however, this test // closes the socket while we have a pending transaction waiting for // a pending stream creation. http://crbug.com/52901 TEST_P(SpdyNetworkTransactionTest, ThreeGetsWithMaxConcurrentSocketClose) { // Construct the request. scoped_ptr
req( spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); scoped_ptr
resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); scoped_ptr
body(spdy_util_.ConstructSpdyBodyFrame(1, false)); scoped_ptr
fin_body(spdy_util_.ConstructSpdyBodyFrame(1, true)); scoped_ptr
req2( spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, LOWEST, true)); scoped_ptr
resp2(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3)); SettingsMap settings; const uint32 max_concurrent_streams = 1; settings[SETTINGS_MAX_CONCURRENT_STREAMS] = SettingsFlagsAndValue(SETTINGS_FLAG_NONE, max_concurrent_streams); scoped_ptr
settings_frame( spdy_util_.ConstructSpdySettings(settings)); scoped_ptr
settings_ack(spdy_util_.ConstructSpdySettingsAck()); MockWrite writes[] = { CreateMockWrite(*req), CreateMockWrite(*settings_ack, 2), CreateMockWrite(*req2), }; MockRead reads[] = { CreateMockRead(*settings_frame, 1), CreateMockRead(*resp), CreateMockRead(*body), CreateMockRead(*fin_body), CreateMockRead(*resp2, 8), MockRead(ASYNC, ERR_CONNECTION_RESET, 0), // Abort! }; OrderedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); OrderedSocketData data_placeholder(NULL, 0, NULL, 0); BoundNetLog log; TransactionHelperResult out; NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL); helper.RunPreTestSetup(); helper.AddData(&data); // We require placeholder data because three get requests are sent out, so // there needs to be three sets of SSL connection data. helper.AddData(&data_placeholder); helper.AddData(&data_placeholder); HttpNetworkTransaction trans1(DEFAULT_PRIORITY, helper.session().get()); HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session().get()); HttpNetworkTransaction* trans3( new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get())); TestCompletionCallback callback1; TestCompletionCallback callback2; KillerCallback callback3(trans3); HttpRequestInfo httpreq1 = CreateGetRequest(); HttpRequestInfo httpreq2 = CreateGetRequest(); HttpRequestInfo httpreq3 = CreateGetRequest(); out.rv = trans1.Start(&httpreq1, callback1.callback(), log); ASSERT_EQ(out.rv, ERR_IO_PENDING); // Run transaction 1 through quickly to force a read of our SETTINGS frame. out.rv = callback1.WaitForResult(); ASSERT_EQ(OK, out.rv); out.rv = trans2.Start(&httpreq2, callback2.callback(), log); ASSERT_EQ(out.rv, ERR_IO_PENDING); out.rv = trans3->Start(&httpreq3, callback3.callback(), log); ASSERT_EQ(out.rv, ERR_IO_PENDING); out.rv = callback3.WaitForResult(); ASSERT_EQ(ERR_ABORTED, out.rv); EXPECT_EQ(6U, data.read_index()); const HttpResponseInfo* response1 = trans1.GetResponseInfo(); ASSERT_TRUE(response1 != NULL); EXPECT_TRUE(response1->headers.get() != NULL); EXPECT_TRUE(response1->was_fetched_via_spdy); out.status_line = response1->headers->GetStatusLine(); out.response_info = *response1; out.rv = ReadTransaction(&trans1, &out.response_data); EXPECT_EQ(OK, out.rv); const HttpResponseInfo* response2 = trans2.GetResponseInfo(); ASSERT_TRUE(response2 != NULL); out.status_line = response2->headers->GetStatusLine(); out.response_info = *response2; out.rv = ReadTransaction(&trans2, &out.response_data); EXPECT_EQ(ERR_CONNECTION_RESET, out.rv); helper.VerifyDataConsumed(); } // Test that a simple PUT request works. TEST_P(SpdyNetworkTransactionTest, Put) { // Setup the request HttpRequestInfo request; request.method = "PUT"; request.url = GURL("http://www.google.com/"); scoped_ptr
put_headers( spdy_util_.ConstructPutHeaderBlock("http://www.google.com", 0)); scoped_ptr
req( spdy_util_.ConstructSpdySyn(1, *put_headers, LOWEST, false, true)); MockWrite writes[] = { CreateMockWrite(*req), }; scoped_ptr
resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); scoped_ptr
body(spdy_util_.ConstructSpdyBodyFrame(1, true)); MockRead reads[] = { CreateMockRead(*resp), CreateMockRead(*body), MockRead(ASYNC, 0, 0) // EOF }; DelayedSocketData data(1, reads, arraysize(reads), writes, arraysize(writes)); NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL); helper.RunToCompletion(&data); TransactionHelperResult out = helper.output(); EXPECT_EQ(OK, out.rv); EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); } // Test that a simple HEAD request works. TEST_P(SpdyNetworkTransactionTest, Head) { // Setup the request HttpRequestInfo request; request.method = "HEAD"; request.url = GURL("http://www.google.com/"); scoped_ptr
head_headers( spdy_util_.ConstructHeadHeaderBlock("http://www.google.com", 0)); scoped_ptr
req( spdy_util_.ConstructSpdySyn(1, *head_headers, LOWEST, false, true)); MockWrite writes[] = { CreateMockWrite(*req), }; scoped_ptr
resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); scoped_ptr
body(spdy_util_.ConstructSpdyBodyFrame(1, true)); MockRead reads[] = { CreateMockRead(*resp), CreateMockRead(*body), MockRead(ASYNC, 0, 0) // EOF }; DelayedSocketData data(1, reads, arraysize(reads), writes, arraysize(writes)); NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL); helper.RunToCompletion(&data); TransactionHelperResult out = helper.output(); EXPECT_EQ(OK, out.rv); EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); } // Test that a simple POST works. TEST_P(SpdyNetworkTransactionTest, Post) { scoped_ptr
req( spdy_util_.ConstructSpdyPost( kRequestUrl, 1, kUploadDataSize, LOWEST, NULL, 0)); scoped_ptr
body(spdy_util_.ConstructSpdyBodyFrame(1, true)); MockWrite writes[] = { CreateMockWrite(*req), CreateMockWrite(*body), // POST upload frame }; scoped_ptr
resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0)); MockRead reads[] = { CreateMockRead(*resp), CreateMockRead(*body), MockRead(ASYNC, 0, 0) // EOF }; DelayedSocketData data(2, reads, arraysize(reads), writes, arraysize(writes)); NormalSpdyTransactionHelper helper(CreatePostRequest(), DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL); helper.RunToCompletion(&data); TransactionHelperResult out = helper.output(); EXPECT_EQ(OK, out.rv); EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); EXPECT_EQ("hello!", out.response_data); } // Test that a POST with a file works. TEST_P(SpdyNetworkTransactionTest, FilePost) { scoped_ptr
req( spdy_util_.ConstructSpdyPost( kRequestUrl, 1, kUploadDataSize, LOWEST, NULL, 0)); scoped_ptr
body(spdy_util_.ConstructSpdyBodyFrame(1, true)); MockWrite writes[] = { CreateMockWrite(*req), CreateMockWrite(*body), // POST upload frame }; scoped_ptr
resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0)); MockRead reads[] = { CreateMockRead(*resp), CreateMockRead(*body), MockRead(ASYNC, 0, 0) // EOF }; DelayedSocketData data(2, reads, arraysize(reads), writes, arraysize(writes)); NormalSpdyTransactionHelper helper(CreateFilePostRequest(), DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL); helper.RunToCompletion(&data); TransactionHelperResult out = helper.output(); EXPECT_EQ(OK, out.rv); EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); EXPECT_EQ("hello!", out.response_data); } // Test that a POST with a unreadable file fails. TEST_P(SpdyNetworkTransactionTest, UnreadableFilePost) { MockWrite writes[] = { MockWrite(ASYNC, 0, 0) // EOF }; MockRead reads[] = { MockRead(ASYNC, 0, 0) // EOF }; DelayedSocketData data(1, reads, arraysize(reads), writes, arraysize(writes)); NormalSpdyTransactionHelper helper(CreateUnreadableFilePostRequest(), DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL); helper.RunPreTestSetup(); helper.AddData(&data); helper.RunDefaultTest(); base::RunLoop().RunUntilIdle(); helper.VerifyDataNotConsumed(); EXPECT_EQ(ERR_ACCESS_DENIED, helper.output().rv); } // Test that a complex POST works. TEST_P(SpdyNetworkTransactionTest, ComplexPost) { scoped_ptr
req( spdy_util_.ConstructSpdyPost( kRequestUrl, 1, kUploadDataSize, LOWEST, NULL, 0)); scoped_ptr
body(spdy_util_.ConstructSpdyBodyFrame(1, true)); MockWrite writes[] = { CreateMockWrite(*req), CreateMockWrite(*body), // POST upload frame }; scoped_ptr
resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0)); MockRead reads[] = { CreateMockRead(*resp), CreateMockRead(*body), MockRead(ASYNC, 0, 0) // EOF }; DelayedSocketData data(2, reads, arraysize(reads), writes, arraysize(writes)); NormalSpdyTransactionHelper helper(CreateComplexPostRequest(), DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL); helper.RunToCompletion(&data); TransactionHelperResult out = helper.output(); EXPECT_EQ(OK, out.rv); EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); EXPECT_EQ("hello!", out.response_data); } // Test that a chunked POST works. TEST_P(SpdyNetworkTransactionTest, ChunkedPost) { scoped_ptr
req(spdy_util_.ConstructChunkedSpdyPost(NULL, 0)); scoped_ptr
body(spdy_util_.ConstructSpdyBodyFrame(1, true)); MockWrite writes[] = { CreateMockWrite(*req), CreateMockWrite(*body), }; scoped_ptr
resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0)); MockRead reads[] = { CreateMockRead(*resp), CreateMockRead(*body), MockRead(ASYNC, 0, 0) // EOF }; DelayedSocketData data(2, reads, arraysize(reads), writes, arraysize(writes)); NormalSpdyTransactionHelper helper(CreateChunkedPostRequest(), DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL); // These chunks get merged into a single frame when being sent. const int kFirstChunkSize = kUploadDataSize/2; helper.request().upload_data_stream->AppendChunk( kUploadData, kFirstChunkSize, false); helper.request().upload_data_stream->AppendChunk( kUploadData + kFirstChunkSize, kUploadDataSize - kFirstChunkSize, true); helper.RunToCompletion(&data); TransactionHelperResult out = helper.output(); EXPECT_EQ(OK, out.rv); EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); EXPECT_EQ(kUploadData, out.response_data); } // Test that a chunked POST works with chunks appended after transaction starts. TEST_P(SpdyNetworkTransactionTest, DelayedChunkedPost) { scoped_ptr
req(spdy_util_.ConstructChunkedSpdyPost(NULL, 0)); scoped_ptr
chunk1(spdy_util_.ConstructSpdyBodyFrame(1, false)); scoped_ptr
chunk2(spdy_util_.ConstructSpdyBodyFrame(1, false)); scoped_ptr
chunk3(spdy_util_.ConstructSpdyBodyFrame(1, true)); MockWrite writes[] = { CreateMockWrite(*req), CreateMockWrite(*chunk1), CreateMockWrite(*chunk2), CreateMockWrite(*chunk3), }; scoped_ptr
resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0)); MockRead reads[] = { CreateMockRead(*resp), CreateMockRead(*chunk1), CreateMockRead(*chunk2), CreateMockRead(*chunk3), MockRead(ASYNC, 0, 0) // EOF }; DelayedSocketData data(4, reads, arraysize(reads), writes, arraysize(writes)); NormalSpdyTransactionHelper helper(CreateChunkedPostRequest(), DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL); helper.request().upload_data_stream->AppendChunk( kUploadData, kUploadDataSize, false); helper.RunPreTestSetup(); helper.AddData(&data); ASSERT_TRUE(helper.StartDefaultTest()); base::RunLoop().RunUntilIdle(); helper.request().upload_data_stream->AppendChunk( kUploadData, kUploadDataSize, false); base::RunLoop().RunUntilIdle(); helper.request().upload_data_stream->AppendChunk( kUploadData, kUploadDataSize, true); helper.FinishDefaultTest(); helper.VerifyDataConsumed(); std::string expected_response; expected_response += kUploadData; expected_response += kUploadData; expected_response += kUploadData; TransactionHelperResult out = helper.output(); EXPECT_EQ(OK, out.rv); EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); EXPECT_EQ(expected_response, out.response_data); } // Test that a POST without any post data works. TEST_P(SpdyNetworkTransactionTest, NullPost) { BufferedSpdyFramer framer(spdy_util_.spdy_version(), false); // Setup the request HttpRequestInfo request; request.method = "POST"; request.url = GURL(kRequestUrl); // Create an empty UploadData. request.upload_data_stream = NULL; // When request.upload_data_stream is NULL for post, content-length is // expected to be 0. scoped_ptr
req_block( spdy_util_.ConstructPostHeaderBlock(kRequestUrl, 0)); scoped_ptr
req( spdy_util_.ConstructSpdySyn(1, *req_block, LOWEST, false, true)); MockWrite writes[] = { CreateMockWrite(*req), }; scoped_ptr
resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0)); scoped_ptr
body(spdy_util_.ConstructSpdyBodyFrame(1, true)); MockRead reads[] = { CreateMockRead(*resp), CreateMockRead(*body), MockRead(ASYNC, 0, 0) // EOF }; DelayedSocketData data(1, reads, arraysize(reads), writes, arraysize(writes)); NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL); helper.RunToCompletion(&data); TransactionHelperResult out = helper.output(); EXPECT_EQ(OK, out.rv); EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); EXPECT_EQ("hello!", out.response_data); } // Test that a simple POST works. TEST_P(SpdyNetworkTransactionTest, EmptyPost) { BufferedSpdyFramer framer(spdy_util_.spdy_version(), false); // Create an empty UploadDataStream. ScopedVector
element_readers; UploadDataStream stream(element_readers.Pass(), 0); // Setup the request HttpRequestInfo request; request.method = "POST"; request.url = GURL(kRequestUrl); request.upload_data_stream = &stream; const uint64 kContentLength = 0; scoped_ptr
req_block( spdy_util_.ConstructPostHeaderBlock(kRequestUrl, kContentLength)); scoped_ptr
req( spdy_util_.ConstructSpdySyn(1, *req_block, LOWEST, false, true)); MockWrite writes[] = { CreateMockWrite(*req), }; scoped_ptr
resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0)); scoped_ptr
body(spdy_util_.ConstructSpdyBodyFrame(1, true)); MockRead reads[] = { CreateMockRead(*resp), CreateMockRead(*body), MockRead(ASYNC, 0, 0) // EOF }; DelayedSocketData data(1, reads, arraysize(reads), writes, arraysize(writes)); NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL); helper.RunToCompletion(&data); TransactionHelperResult out = helper.output(); EXPECT_EQ(OK, out.rv); EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); EXPECT_EQ("hello!", out.response_data); } // While we're doing a post, the server sends the reply before upload completes. TEST_P(SpdyNetworkTransactionTest, ResponseBeforePostCompletes) { scoped_ptr
req(spdy_util_.ConstructChunkedSpdyPost(NULL, 0)); scoped_ptr
body(spdy_util_.ConstructSpdyBodyFrame(1, true)); MockWrite writes[] = { CreateMockWrite(*req, 0), CreateMockWrite(*body, 3), }; scoped_ptr
resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0)); MockRead reads[] = { CreateMockRead(*resp, 1), CreateMockRead(*body, 2), MockRead(ASYNC, 0, 4) // EOF }; // Write the request headers, and read the complete response // while still waiting for chunked request data. DeterministicSocketData data(reads, arraysize(reads), writes, arraysize(writes)); NormalSpdyTransactionHelper helper(CreateChunkedPostRequest(), DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL); helper.SetDeterministic(); helper.RunPreTestSetup(); helper.AddDeterministicData(&data); ASSERT_TRUE(helper.StartDefaultTest()); // Process the request headers, SYN_REPLY, and response body. // The request body is still in flight. data.RunFor(3); const HttpResponseInfo* response = helper.trans()->GetResponseInfo(); EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); // Finish sending the request body. helper.request().upload_data_stream->AppendChunk( kUploadData, kUploadDataSize, true); data.RunFor(2); std::string response_body; EXPECT_EQ(OK, ReadTransaction(helper.trans(), &response_body)); EXPECT_EQ(kUploadData, response_body); helper.VerifyDataConsumed(); } // The client upon cancellation tries to send a RST_STREAM frame. The mock // socket causes the TCP write to return zero. This test checks that the client // tries to queue up the RST_STREAM frame again. TEST_P(SpdyNetworkTransactionTest, SocketWriteReturnsZero) { scoped_ptr
req( spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); scoped_ptr
rst( spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL)); MockWrite writes[] = { CreateMockWrite(*req.get(), 0, SYNCHRONOUS), MockWrite(SYNCHRONOUS, 0, 0, 2), CreateMockWrite(*rst.get(), 3, SYNCHRONOUS), }; scoped_ptr
resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); MockRead reads[] = { CreateMockRead(*resp.get(), 1, ASYNC), MockRead(ASYNC, 0, 0, 4) // EOF }; DeterministicSocketData data(reads, arraysize(reads), writes, arraysize(writes)); NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL); helper.SetDeterministic(); helper.RunPreTestSetup(); helper.AddDeterministicData(&data); HttpNetworkTransaction* trans = helper.trans(); TestCompletionCallback callback; int rv = trans->Start( &CreateGetRequest(), callback.callback(), BoundNetLog()); EXPECT_EQ(ERR_IO_PENDING, rv); data.SetStop(2); data.Run(); helper.ResetTrans(); data.SetStop(20); data.Run(); helper.VerifyDataConsumed(); } // Test that the transaction doesn't crash when we don't have a reply. TEST_P(SpdyNetworkTransactionTest, ResponseWithoutSynReply) { scoped_ptr
body(spdy_util_.ConstructSpdyBodyFrame(1, true)); MockRead reads[] = { CreateMockRead(*body), MockRead(ASYNC, 0, 0) // EOF }; DelayedSocketData data(1, reads, arraysize(reads), NULL, 0); NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL); helper.RunToCompletion(&data); TransactionHelperResult out = helper.output(); EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, out.rv); } // Test that the transaction doesn't crash when we get two replies on the same // stream ID. See http://crbug.com/45639. TEST_P(SpdyNetworkTransactionTest, ResponseWithTwoSynReplies) { scoped_ptr
req( spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); scoped_ptr
rst( spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR)); MockWrite writes[] = { CreateMockWrite(*req), CreateMockWrite(*rst), }; scoped_ptr
resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); scoped_ptr
body(spdy_util_.ConstructSpdyBodyFrame(1, true)); MockRead reads[] = { CreateMockRead(*resp), CreateMockRead(*resp), CreateMockRead(*body), MockRead(ASYNC, 0, 0) // EOF }; DelayedSocketData data(1, reads, arraysize(reads), writes, arraysize(writes)); NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL); helper.RunPreTestSetup(); helper.AddData(&data); HttpNetworkTransaction* trans = helper.trans(); TestCompletionCallback callback; int rv = trans->Start(&helper.request(), callback.callback(), BoundNetLog()); EXPECT_EQ(ERR_IO_PENDING, rv); rv = callback.WaitForResult(); EXPECT_EQ(OK, rv); const HttpResponseInfo* response = trans->GetResponseInfo(); ASSERT_TRUE(response != NULL); EXPECT_TRUE(response->headers.get() != NULL); EXPECT_TRUE(response->was_fetched_via_spdy); std::string response_data; rv = ReadTransaction(trans, &response_data); EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, rv); helper.VerifyDataConsumed(); } TEST_P(SpdyNetworkTransactionTest, ResetReplyWithTransferEncoding) { // Construct the request. scoped_ptr
req( spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); scoped_ptr
rst( spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR)); MockWrite writes[] = { CreateMockWrite(*req), CreateMockWrite(*rst), }; const char* const headers[] = { "transfer-encoding", "chunked" }; scoped_ptr
resp( spdy_util_.ConstructSpdyGetSynReply(headers, 1, 1)); scoped_ptr
body( spdy_util_.ConstructSpdyBodyFrame(1, true)); MockRead reads[] = { CreateMockRead(*resp), CreateMockRead(*body), MockRead(ASYNC, 0, 0) // EOF }; DelayedSocketData data(1, reads, arraysize(reads), writes, arraysize(writes)); NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL); helper.RunToCompletion(&data); TransactionHelperResult out = helper.output(); EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, out.rv); helper.session()->spdy_session_pool()->CloseAllSessions(); helper.VerifyDataConsumed(); } TEST_P(SpdyNetworkTransactionTest, ResetPushWithTransferEncoding) { // Construct the request. scoped_ptr
req( spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); scoped_ptr
rst( spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR)); MockWrite writes[] = { CreateMockWrite(*req), CreateMockWrite(*rst), }; scoped_ptr
resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); const char* const headers[] = { "transfer-encoding", "chunked" }; scoped_ptr
push( spdy_util_.ConstructSpdyPush(headers, arraysize(headers) / 2, 2, 1, "http://www.google.com/1")); scoped_ptr
body(spdy_util_.ConstructSpdyBodyFrame(1, true)); MockRead reads[] = { CreateMockRead(*resp), CreateMockRead(*push), CreateMockRead(*body), MockRead(ASYNC, 0, 0) // EOF }; DelayedSocketData data(1, reads, arraysize(reads), writes, arraysize(writes)); NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL); helper.RunToCompletion(&data); TransactionHelperResult out = helper.output(); EXPECT_EQ(OK, out.rv); EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); EXPECT_EQ("hello!", out.response_data); helper.session()->spdy_session_pool()->CloseAllSessions(); helper.VerifyDataConsumed(); } TEST_P(SpdyNetworkTransactionTest, CancelledTransaction) { // Construct the request. scoped_ptr
req( spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); MockWrite writes[] = { CreateMockWrite(*req), }; scoped_ptr
resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); MockRead reads[] = { CreateMockRead(*resp), // This following read isn't used by the test, except during the // RunUntilIdle() call at the end since the SpdySession survives the // HttpNetworkTransaction and still tries to continue Read()'ing. Any // MockRead will do here. MockRead(ASYNC, 0, 0) // EOF }; StaticSocketDataProvider data(reads, arraysize(reads), writes, arraysize(writes)); NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL); helper.RunPreTestSetup(); helper.AddData(&data); HttpNetworkTransaction* trans = helper.trans(); TestCompletionCallback callback; int rv = trans->Start( &CreateGetRequest(), callback.callback(), BoundNetLog()); EXPECT_EQ(ERR_IO_PENDING, rv); helper.ResetTrans(); // Cancel the transaction. // Flush the MessageLoop while the SpdySessionDependencies (in particular, the // MockClientSocketFactory) are still alive. base::RunLoop().RunUntilIdle(); helper.VerifyDataNotConsumed(); } // Verify that the client sends a Rst Frame upon cancelling the stream. TEST_P(SpdyNetworkTransactionTest, CancelledTransactionSendRst) { scoped_ptr
req( spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); scoped_ptr
rst( spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL)); MockWrite writes[] = { CreateMockWrite(*req, 0, SYNCHRONOUS), CreateMockWrite(*rst, 2, SYNCHRONOUS), }; scoped_ptr
resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); MockRead reads[] = { CreateMockRead(*resp, 1, ASYNC), MockRead(ASYNC, 0, 0, 3) // EOF }; DeterministicSocketData data(reads, arraysize(reads), writes, arraysize(writes)); NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL); helper.SetDeterministic(); helper.RunPreTestSetup(); helper.AddDeterministicData(&data); HttpNetworkTransaction* trans = helper.trans(); TestCompletionCallback callback; int rv = trans->Start( &CreateGetRequest(), callback.callback(), BoundNetLog()); EXPECT_EQ(ERR_IO_PENDING, rv); data.SetStop(2); data.Run(); helper.ResetTrans(); data.SetStop(20); data.Run(); helper.VerifyDataConsumed(); } // Verify that the client can correctly deal with the user callback attempting // to start another transaction on a session that is closing down. See // http://crbug.com/47455 TEST_P(SpdyNetworkTransactionTest, StartTransactionOnReadCallback) { scoped_ptr
req( spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); MockWrite writes[] = { CreateMockWrite(*req) }; MockWrite writes2[] = { CreateMockWrite(*req) }; // The indicated length of this frame is longer than its actual length. When // the session receives an empty frame after this one, it shuts down the // session, and calls the read callback with the incomplete data. const uint8 kGetBodyFrame2[] = { 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x07, 'h', 'e', 'l', 'l', 'o', '!', }; scoped_ptr
resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); MockRead reads[] = { CreateMockRead(*resp, 2), MockRead(ASYNC, ERR_IO_PENDING, 3), // Force a pause MockRead(ASYNC, reinterpret_cast
(kGetBodyFrame2), arraysize(kGetBodyFrame2), 4), MockRead(ASYNC, ERR_IO_PENDING, 5), // Force a pause MockRead(ASYNC, 0, 0, 6), // EOF }; MockRead reads2[] = { CreateMockRead(*resp, 2), MockRead(ASYNC, 0, 0, 3), // EOF }; OrderedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); DelayedSocketData data2(1, reads2, arraysize(reads2), writes2, arraysize(writes2)); NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL); helper.RunPreTestSetup(); helper.AddData(&data); helper.AddData(&data2); HttpNetworkTransaction* trans = helper.trans(); // Start the transaction with basic parameters. TestCompletionCallback callback; int rv = trans->Start(&helper.request(), callback.callback(), BoundNetLog()); EXPECT_EQ(ERR_IO_PENDING, rv); rv = callback.WaitForResult(); const int kSize = 3000; scoped_refptr
buf(new net::IOBuffer(kSize)); rv = trans->Read( buf.get(), kSize, base::Bind(&SpdyNetworkTransactionTest::StartTransactionCallback, helper.session())); // This forces an err_IO_pending, which sets the callback. data.CompleteRead(); // This finishes the read. data.CompleteRead(); helper.VerifyDataConsumed(); } // Verify that the client can correctly deal with the user callback deleting the // transaction. Failures will usually be valgrind errors. See // http://crbug.com/46925 TEST_P(SpdyNetworkTransactionTest, DeleteSessionOnReadCallback) { scoped_ptr
req( spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); MockWrite writes[] = { CreateMockWrite(*req) }; scoped_ptr
resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); scoped_ptr
body(spdy_util_.ConstructSpdyBodyFrame(1, true)); MockRead reads[] = { CreateMockRead(*resp.get(), 2), MockRead(ASYNC, ERR_IO_PENDING, 3), // Force a pause CreateMockRead(*body.get(), 4), MockRead(ASYNC, 0, 0, 5), // EOF }; OrderedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL); helper.RunPreTestSetup(); helper.AddData(&data); HttpNetworkTransaction* trans = helper.trans(); // Start the transaction with basic parameters. TestCompletionCallback callback; int rv = trans->Start(&helper.request(), callback.callback(), BoundNetLog()); EXPECT_EQ(ERR_IO_PENDING, rv); rv = callback.WaitForResult(); // Setup a user callback which will delete the session, and clear out the // memory holding the stream object. Note that the callback deletes trans. const int kSize = 3000; scoped_refptr
buf(new net::IOBuffer(kSize)); rv = trans->Read( buf.get(), kSize, base::Bind(&SpdyNetworkTransactionTest::DeleteSessionCallback, base::Unretained(&helper))); ASSERT_EQ(ERR_IO_PENDING, rv); data.CompleteRead(); // Finish running rest of tasks. base::RunLoop().RunUntilIdle(); helper.VerifyDataConsumed(); } // Send a spdy request to www.google.com that gets redirected to www.foo.com. TEST_P(SpdyNetworkTransactionTest, RedirectGetRequest) { scoped_ptr
headers( spdy_util_.ConstructGetHeaderBlock("http://www.google.com/")); (*headers)["user-agent"] = ""; (*headers)["accept-encoding"] = "gzip, deflate"; scoped_ptr
headers2( spdy_util_.ConstructGetHeaderBlock("http://www.foo.com/index.php")); (*headers2)["user-agent"] = ""; (*headers2)["accept-encoding"] = "gzip, deflate"; // Setup writes/reads to www.google.com scoped_ptr
req( spdy_util_.ConstructSpdySyn(1, *headers, LOWEST, false, true)); scoped_ptr
req2( spdy_util_.ConstructSpdySyn(1, *headers2, LOWEST, false, true)); scoped_ptr
resp(spdy_util_.ConstructSpdyGetSynReplyRedirect(1)); MockWrite writes[] = { CreateMockWrite(*req, 1), }; MockRead reads[] = { CreateMockRead(*resp, 2), MockRead(ASYNC, 0, 0, 3) // EOF }; // Setup writes/reads to www.foo.com scoped_ptr
resp2(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); scoped_ptr
body2(spdy_util_.ConstructSpdyBodyFrame(1, true)); MockWrite writes2[] = { CreateMockWrite(*req2, 1), }; MockRead reads2[] = { CreateMockRead(*resp2, 2), CreateMockRead(*body2, 3), MockRead(ASYNC, 0, 0, 4) // EOF }; OrderedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); OrderedSocketData data2(reads2, arraysize(reads2), writes2, arraysize(writes2)); // TODO(erikchen): Make test support SPDYSSL, SPDYNPN TestDelegate d; { SpdyURLRequestContext spdy_url_request_context( GetParam().protocol, false /* force_spdy_over_ssl*/, true /* force_spdy_always */); scoped_ptr
r( spdy_url_request_context.CreateRequest(GURL("http://www.google.com/"), DEFAULT_PRIORITY, &d, NULL)); spdy_url_request_context.socket_factory(). AddSocketDataProvider(&data); spdy_url_request_context.socket_factory(). AddSocketDataProvider(&data2); d.set_quit_on_redirect(true); r->Start(); base::RunLoop().Run(); EXPECT_EQ(1, d.received_redirect_count()); r->FollowDeferredRedirect(); base::RunLoop().Run(); EXPECT_EQ(1, d.response_started_count()); EXPECT_FALSE(d.received_data_before_response()); EXPECT_EQ(net::URLRequestStatus::SUCCESS, r->status().status()); std::string contents("hello!"); EXPECT_EQ(contents, d.data_received()); } EXPECT_TRUE(data.at_read_eof()); EXPECT_TRUE(data.at_write_eof()); EXPECT_TRUE(data2.at_read_eof()); EXPECT_TRUE(data2.at_write_eof()); } // Send a spdy request to www.google.com. Get a pushed stream that redirects to // www.foo.com. TEST_P(SpdyNetworkTransactionTest, RedirectServerPush) { scoped_ptr
headers( spdy_util_.ConstructGetHeaderBlock("http://www.google.com/")); (*headers)["user-agent"] = ""; (*headers)["accept-encoding"] = "gzip, deflate"; // Setup writes/reads to www.google.com scoped_ptr
req( spdy_util_.ConstructSpdySyn(1, *headers, LOWEST, false, true)); scoped_ptr
resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); scoped_ptr
rep( spdy_util_.ConstructSpdyPush(NULL, 0, 2, 1, "http://www.google.com/foo.dat", "301 Moved Permanently", "http://www.foo.com/index.php")); scoped_ptr
body(spdy_util_.ConstructSpdyBodyFrame(1, true)); scoped_ptr
rst( spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_CANCEL)); MockWrite writes[] = { CreateMockWrite(*req, 1), CreateMockWrite(*rst, 6), }; MockRead reads[] = { CreateMockRead(*resp, 2), CreateMockRead(*rep, 3), CreateMockRead(*body, 4), MockRead(ASYNC, ERR_IO_PENDING, 5), // Force a pause MockRead(ASYNC, 0, 0, 7) // EOF }; // Setup writes/reads to www.foo.com scoped_ptr
headers2( spdy_util_.ConstructGetHeaderBlock("http://www.foo.com/index.php")); (*headers2)["user-agent"] = ""; (*headers2)["accept-encoding"] = "gzip, deflate"; scoped_ptr
req2( spdy_util_.ConstructSpdySyn(1, *headers2, LOWEST, false, true)); scoped_ptr
resp2(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); scoped_ptr
body2(spdy_util_.ConstructSpdyBodyFrame(1, true)); MockWrite writes2[] = { CreateMockWrite(*req2, 1), }; MockRead reads2[] = { CreateMockRead(*resp2, 2), CreateMockRead(*body2, 3), MockRead(ASYNC, 0, 0, 5) // EOF }; OrderedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); OrderedSocketData data2(reads2, arraysize(reads2), writes2, arraysize(writes2)); // TODO(erikchen): Make test support SPDYSSL, SPDYNPN TestDelegate d; TestDelegate d2; SpdyURLRequestContext spdy_url_request_context( GetParam().protocol, false /* force_spdy_over_ssl*/, true /* force_spdy_always */); { scoped_ptr
r( spdy_url_request_context.CreateRequest(GURL("http://www.google.com/"), DEFAULT_PRIORITY, &d, NULL)); spdy_url_request_context.socket_factory(). AddSocketDataProvider(&data); r->Start(); base::RunLoop().Run(); EXPECT_EQ(0, d.received_redirect_count()); std::string contents("hello!"); EXPECT_EQ(contents, d.data_received()); scoped_ptr
r2( spdy_url_request_context.CreateRequest( GURL("http://www.google.com/foo.dat"), DEFAULT_PRIORITY, &d2, NULL)); spdy_url_request_context.socket_factory(). AddSocketDataProvider(&data2); d2.set_quit_on_redirect(true); r2->Start(); base::RunLoop().Run(); EXPECT_EQ(1, d2.received_redirect_count()); r2->FollowDeferredRedirect(); base::RunLoop().Run(); EXPECT_EQ(1, d2.response_started_count()); EXPECT_FALSE(d2.received_data_before_response()); EXPECT_EQ(net::URLRequestStatus::SUCCESS, r2->status().status()); std::string contents2("hello!"); EXPECT_EQ(contents2, d2.data_received()); } data.CompleteRead(); data2.CompleteRead(); EXPECT_TRUE(data.at_read_eof()); EXPECT_TRUE(data.at_write_eof()); EXPECT_TRUE(data2.at_read_eof()); EXPECT_TRUE(data2.at_write_eof()); } TEST_P(SpdyNetworkTransactionTest, ServerPushSingleDataFrame) { scoped_ptr
stream1_syn( spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); scoped_ptr
stream1_body( spdy_util_.ConstructSpdyBodyFrame(1, true)); MockWrite writes[] = { CreateMockWrite(*stream1_syn, 1), }; scoped_ptr
stream1_reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); scoped_ptr
stream2_syn(spdy_util_.ConstructSpdyPush(NULL, 0, 2, 1, "http://www.google.com/foo.dat")); const char kPushedData[] = "pushed"; scoped_ptr
stream2_body( spdy_util_.ConstructSpdyBodyFrame( 2, kPushedData, strlen(kPushedData), true)); MockRead reads[] = { CreateMockRead(*stream1_reply, 2), CreateMockRead(*stream2_syn, 3), CreateMockRead(*stream1_body, 4, SYNCHRONOUS), CreateMockRead(*stream2_body, 5), MockRead(ASYNC, ERR_IO_PENDING, 6), // Force a pause }; HttpResponseInfo response; HttpResponseInfo response2; std::string expected_push_result("pushed"); OrderedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); RunServerPushTest(&data, &response, &response2, expected_push_result); // Verify the SYN_REPLY. EXPECT_TRUE(response.headers.get() != NULL); EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine()); // Verify the pushed stream. EXPECT_TRUE(response2.headers.get() != NULL); EXPECT_EQ("HTTP/1.1 200 OK", response2.headers->GetStatusLine()); } TEST_P(SpdyNetworkTransactionTest, ServerPushBeforeSynReply) { scoped_ptr
stream1_syn( spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); scoped_ptr
stream1_body( spdy_util_.ConstructSpdyBodyFrame(1, true)); MockWrite writes[] = { CreateMockWrite(*stream1_syn, 1), }; scoped_ptr
stream1_reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); scoped_ptr
stream2_syn(spdy_util_.ConstructSpdyPush(NULL, 0, 2, 1, "http://www.google.com/foo.dat")); const char kPushedData[] = "pushed"; scoped_ptr
stream2_body( spdy_util_.ConstructSpdyBodyFrame( 2, kPushedData, strlen(kPushedData), true)); MockRead reads[] = { CreateMockRead(*stream2_syn, 2), CreateMockRead(*stream1_reply, 3), CreateMockRead(*stream1_body, 4, SYNCHRONOUS), CreateMockRead(*stream2_body, 5), MockRead(ASYNC, ERR_IO_PENDING, 6), // Force a pause }; HttpResponseInfo response; HttpResponseInfo response2; std::string expected_push_result("pushed"); OrderedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); RunServerPushTest(&data, &response, &response2, expected_push_result); // Verify the SYN_REPLY. EXPECT_TRUE(response.headers.get() != NULL); EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine()); // Verify the pushed stream. EXPECT_TRUE(response2.headers.get() != NULL); EXPECT_EQ("HTTP/1.1 200 OK", response2.headers->GetStatusLine()); } TEST_P(SpdyNetworkTransactionTest, ServerPushSingleDataFrame2) { scoped_ptr
stream1_syn( spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); MockWrite writes[] = { CreateMockWrite(*stream1_syn, 1), }; scoped_ptr
stream1_reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); scoped_ptr
stream2_syn(spdy_util_.ConstructSpdyPush(NULL, 0, 2, 1, "http://www.google.com/foo.dat")); const char kPushedData[] = "pushed"; scoped_ptr
stream2_body( spdy_util_.ConstructSpdyBodyFrame( 2, kPushedData, strlen(kPushedData), true)); scoped_ptr
stream1_body(spdy_util_.ConstructSpdyBodyFrame(1, true)); MockRead reads[] = { CreateMockRead(*stream1_reply, 2), CreateMockRead(*stream2_syn, 3), CreateMockRead(*stream2_body, 4), CreateMockRead(*stream1_body, 5, SYNCHRONOUS), MockRead(ASYNC, ERR_IO_PENDING, 6), // Force a pause }; HttpResponseInfo response; HttpResponseInfo response2; std::string expected_push_result("pushed"); OrderedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); RunServerPushTest(&data, &response, &response2, expected_push_result); // Verify the SYN_REPLY. EXPECT_TRUE(response.headers.get() != NULL); EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine()); // Verify the pushed stream. EXPECT_TRUE(response2.headers.get() != NULL); EXPECT_EQ("HTTP/1.1 200 OK", response2.headers->GetStatusLine()); } TEST_P(SpdyNetworkTransactionTest, ServerPushServerAborted) { scoped_ptr
stream1_syn( spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); scoped_ptr
stream1_body( spdy_util_.ConstructSpdyBodyFrame(1, true)); MockWrite writes[] = { CreateMockWrite(*stream1_syn, 1), }; scoped_ptr
stream1_reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); scoped_ptr
stream2_syn(spdy_util_.ConstructSpdyPush(NULL, 0, 2, 1, "http://www.google.com/foo.dat")); scoped_ptr
stream2_rst( spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR)); MockRead reads[] = { CreateMockRead(*stream1_reply, 2), CreateMockRead(*stream2_syn, 3), CreateMockRead(*stream2_rst, 4), CreateMockRead(*stream1_body, 5, SYNCHRONOUS), MockRead(ASYNC, ERR_IO_PENDING, 6), // Force a pause }; OrderedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL); helper.RunPreTestSetup(); helper.AddData(&data); HttpNetworkTransaction* trans = helper.trans(); // Start the transaction with basic parameters. TestCompletionCallback callback; int rv = trans->Start( &CreateGetRequest(), callback.callback(), BoundNetLog()); EXPECT_EQ(ERR_IO_PENDING, rv); rv = callback.WaitForResult(); EXPECT_EQ(OK, rv); // Verify that we consumed all test data. EXPECT_TRUE(data.at_read_eof()) << "Read count: " << data.read_count() << " Read index: " << data.read_index(); EXPECT_TRUE(data.at_write_eof()) << "Write count: " << data.write_count() << " Write index: " << data.write_index(); // Verify the SYN_REPLY. HttpResponseInfo response = *trans->GetResponseInfo(); EXPECT_TRUE(response.headers.get() != NULL); EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine()); } // Verify that we don't leak streams and that we properly send a reset // if the server pushes the same stream twice. TEST_P(SpdyNetworkTransactionTest, ServerPushDuplicate) { scoped_ptr
stream1_syn( spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); scoped_ptr
stream1_body( spdy_util_.ConstructSpdyBodyFrame(1, true)); scoped_ptr
stream3_rst( spdy_util_.ConstructSpdyRstStream(4, RST_STREAM_PROTOCOL_ERROR)); MockWrite writes[] = { CreateMockWrite(*stream1_syn, 1), CreateMockWrite(*stream3_rst, 5), }; scoped_ptr
stream1_reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); scoped_ptr
stream2_syn(spdy_util_.ConstructSpdyPush(NULL, 0, 2, 1, "http://www.google.com/foo.dat")); const char kPushedData[] = "pushed"; scoped_ptr
stream2_body( spdy_util_.ConstructSpdyBodyFrame( 2, kPushedData, strlen(kPushedData), true)); scoped_ptr
stream3_syn(spdy_util_.ConstructSpdyPush(NULL, 0, 4, 1, "http://www.google.com/foo.dat")); MockRead reads[] = { CreateMockRead(*stream1_reply, 2), CreateMockRead(*stream2_syn, 3), CreateMockRead(*stream3_syn, 4), CreateMockRead(*stream1_body, 6, SYNCHRONOUS), CreateMockRead(*stream2_body, 7), MockRead(ASYNC, ERR_IO_PENDING, 8), // Force a pause }; HttpResponseInfo response; HttpResponseInfo response2; std::string expected_push_result("pushed"); OrderedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); RunServerPushTest(&data, &response, &response2, expected_push_result); // Verify the SYN_REPLY. EXPECT_TRUE(response.headers.get() != NULL); EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine()); // Verify the pushed stream. EXPECT_TRUE(response2.headers.get() != NULL); EXPECT_EQ("HTTP/1.1 200 OK", response2.headers->GetStatusLine()); } TEST_P(SpdyNetworkTransactionTest, ServerPushMultipleDataFrame) { scoped_ptr
stream1_syn( spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); scoped_ptr
stream1_body( spdy_util_.ConstructSpdyBodyFrame(1, true)); MockWrite writes[] = { CreateMockWrite(*stream1_syn, 1), }; scoped_ptr
stream1_reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); scoped_ptr