blob: 1da839038e009a24c404800520792a8b174b2097 [file] [log] [blame]
[email protected]a1595312012-01-22 03:25:041// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]5af3c572010-07-20 14:16:272// Use of this source code is governed by a BSD-style license that can be
[email protected]aea80602009-09-18 00:55:083// found in the LICENSE file.
4
xunjieli179a6e72016-04-26 19:47:455#include <cmath>
dchengc7eeda422015-12-26 03:56:486#include <utility>
[email protected]a33cad2b62010-07-30 22:24:397#include <vector>
8
[email protected]49639fa2011-12-20 23:22:419#include "base/bind.h"
10#include "base/bind_helpers.h"
Bence Békydb3cf652017-10-10 15:22:1011#include "base/compiler_specific.h"
thestigd8df0332014-09-04 06:33:2912#include "base/files/file_util.h"
[email protected]ea1a3f62012-11-16 20:34:2313#include "base/files/scoped_temp_dir.h"
[email protected]fc9d88472013-08-14 02:31:1714#include "base/run_loop.h"
Avi Drissman4365a4782018-12-28 19:26:2415#include "base/stl_util.h"
Bence Békyd74f4382018-02-20 18:26:1916#include "base/strings/string_piece.h"
Devlin Cronine4bcb40e2018-06-05 18:02:4717#include "base/test/metrics/histogram_tester.h"
Matt Menkef2ee07c2019-08-29 02:10:3618#include "base/test/scoped_feature_list.h"
[email protected]999dd8c2013-11-12 06:45:5419#include "base/test/test_file_util.h"
gabf767595f2016-05-11 18:50:3520#include "base/threading/thread_task_runner_handle.h"
Matt Menke5062be22019-05-01 17:50:2421#include "build/build_config.h"
[email protected]018aabc2010-10-29 16:16:5922#include "net/base/auth.h"
mmenkecbc2b712014-10-09 20:29:0723#include "net/base/chunked_upload_data_stream.h"
Bence Béky8ddc2492018-06-13 01:02:0424#include "net/base/completion_once_callback.h"
mmenkecbc2b712014-10-09 20:29:0725#include "net/base/elements_upload_data_stream.h"
Matt Menkef2ee07c2019-08-29 02:10:3626#include "net/base/features.h"
Tsuyoshi Horo01faed62019-02-20 22:11:3727#include "net/base/ip_endpoint.h"
Matt Menkef2ee07c2019-08-29 02:10:3628#include "net/base/network_isolation_key.h"
tbansal28e68f82016-02-04 02:56:1529#include "net/base/proxy_delegate.h"
Lily Houghton582d4622018-01-22 22:43:4030#include "net/base/proxy_server.h"
[email protected]262eec82013-03-19 21:01:3631#include "net/base/request_priority.h"
tbansal28e68f82016-02-04 02:56:1532#include "net/base/test_proxy_delegate.h"
[email protected]b2d26cfd2012-12-11 10:36:0633#include "net/base/upload_bytes_element_reader.h"
[email protected]b2d26cfd2012-12-11 10:36:0634#include "net/base/upload_file_element_reader.h"
Bence Béky1a5d8562018-01-05 17:29:2835#include "net/dns/mock_host_resolver.h"
aberentbba302d2015-12-03 10:20:1936#include "net/http/http_auth_scheme.h"
bnc3171a2432016-12-28 18:40:2637#include "net/http/http_network_session.h"
[email protected]87bfa3f2010-09-30 14:54:5638#include "net/http/http_network_session_peer.h"
[email protected]513963e2013-06-15 01:53:0439#include "net/http/http_network_transaction.h"
Matt Menke6e879bd2019-03-18 17:26:0440#include "net/http/http_proxy_connect_job.h"
Bence Béky3a0c48532018-03-02 13:38:5141#include "net/http/http_response_info.h"
[email protected]513963e2013-06-15 01:53:0442#include "net/http/http_server_properties.h"
[email protected]c41737d2014-05-14 07:47:1943#include "net/http/http_transaction_test_util.h"
mikecirone8b85c432016-09-08 19:11:0044#include "net/log/net_log_event_type.h"
mikecironef22f9812016-10-04 03:40:1945#include "net/log/net_log_with_source.h"
mmenke16a7cbdd2015-04-24 23:00:5646#include "net/log/test_net_log.h"
mmenke43758e62015-05-04 21:09:4647#include "net/log/test_net_log_util.h"
Nicolas Arciniega8ec5bfa2020-03-20 05:07:2648#include "net/proxy_resolution/configured_proxy_resolution_service.h"
[email protected]bb88e1d32013-05-03 23:11:0749#include "net/socket/next_proto.h"
Paul Jensena457017a2018-01-19 23:52:0450#include "net/socket/socket_tag.h"
Bence Béky94658bf2018-05-11 19:22:5851#include "net/spdy/buffered_spdy_framer.h"
52#include "net/spdy/spdy_http_stream.h"
53#include "net/spdy/spdy_http_utils.h"
54#include "net/spdy/spdy_session.h"
55#include "net/spdy/spdy_session_pool.h"
56#include "net/spdy/spdy_test_util_common.h"
[email protected]514aeaf2014-05-23 10:31:5157#include "net/ssl/ssl_connection_status_flags.h"
bncce36dca22015-04-21 22:11:2358#include "net/test/cert_test_util.h"
robpercival214763f2016-07-01 23:27:0159#include "net/test/gtest_util.h"
rsleevia69c79a2016-06-22 03:28:4360#include "net/test/test_data_directory.h"
Gabriel Charettec7108742019-08-23 03:31:4061#include "net/test/test_with_task_environment.h"
Victor Vasiliev27cc7712019-01-24 11:50:1462#include "net/third_party/quiche/src/spdy/core/spdy_protocol.h"
63#include "net/third_party/quiche/src/spdy/core/spdy_test_utils.h"
rhalavati9ebaba7e2017-04-27 06:16:2964#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
[email protected]d2db0292011-01-26 20:23:4465#include "net/url_request/url_request_test_util.h"
Bence Béky0ca719f2018-01-31 13:41:1966#include "net/websockets/websocket_test_util.h"
[email protected]251029e2014-03-19 06:04:4067#include "testing/gmock/include/gmock/gmock.h"
[email protected]aea80602009-09-18 00:55:0868#include "testing/platform_test.h"
69
robpercival214763f2016-07-01 23:27:0170using net::test::IsError;
71using net::test::IsOk;
72
[email protected]aea80602009-09-18 00:55:0873//-----------------------------------------------------------------------------
74
[email protected]d1eda932009-11-04 01:03:1075namespace net {
[email protected]dae22c52010-07-30 02:16:3576
[email protected]cbdd73162013-03-18 23:27:3377namespace {
[email protected]251029e2014-03-19 06:04:4078
79using testing::Each;
80using testing::Eq;
81
xunjieli179a6e72016-04-26 19:47:4582const int32_t kBufferSize = SpdyHttpStream::kRequestBodyBufferSize;
83
[email protected]513963e2013-06-15 01:53:0484} // namespace
85
Bence Békyd2df6c1c82018-04-20 22:52:0186const char kPushedUrl[] = "https://www.example.org/foo.dat";
87
Gabriel Charette694c3c332019-08-19 14:53:0588class SpdyNetworkTransactionTest : public TestWithTaskEnvironment {
[email protected]34437af82009-11-06 02:28:4989 protected:
rdsmithebb50aa2015-11-12 03:44:3890 SpdyNetworkTransactionTest()
David Benjaminbae08ba2019-10-18 21:06:1591 : TestWithTaskEnvironment(
92 base::test::TaskEnvironment::TimeSource::MOCK_TIME),
93 default_url_(kDefaultUrl),
bncd16676a2016-07-20 16:23:0194 host_port_pair_(HostPortPair::FromURL(default_url_)) {}
[email protected]2d6728692011-03-12 01:39:5595
bncd16676a2016-07-20 16:23:0196 ~SpdyNetworkTransactionTest() override {
Bence Békydb3cf652017-10-10 15:22:1097 // UploadDataStream may post a deletion task back to the message loop on
[email protected]fc9d88472013-08-14 02:31:1798 // destruction.
99 upload_data_stream_.reset();
100 base::RunLoop().RunUntilIdle();
101 }
102
dcheng67be2b1f2014-10-27 21:47:29103 void SetUp() override {
Bence Békydb3cf652017-10-10 15:22:10104 request_.method = "GET";
105 request_.url = GURL(kDefaultUrl);
Ramin Halavatib5e433e62018-02-07 07:41:10106 request_.traffic_annotation =
107 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
[email protected]69e6b4a2012-10-18 08:03:01108 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
[email protected]aea80602009-09-18 00:55:08109 }
110
[email protected]72552f02009-10-28 15:25:01111 struct TransactionHelperResult {
[email protected]aea80602009-09-18 00:55:08112 int rv;
Bence Béky4e83f492018-05-13 23:14:25113 std::string status_line;
114 std::string response_data;
[email protected]8b070372009-11-16 22:01:25115 HttpResponseInfo response_info;
[email protected]aea80602009-09-18 00:55:08116 };
117
[email protected]3caf5542010-07-16 15:19:47118 // A helper class that handles all the initial npn/ssl setup.
119 class NormalSpdyTransactionHelper {
120 public:
rdsmith82957ad2015-09-16 19:42:03121 NormalSpdyTransactionHelper(
122 const HttpRequestInfo& request,
123 RequestPriority priority,
tfarina428341112016-09-22 13:38:20124 const NetLogWithSource& log,
danakjaee3e1ec2016-04-16 00:23:18125 std::unique_ptr<SpdySessionDependencies> session_deps)
[email protected]30c942b2010-07-21 16:59:59126 : request_(request),
[email protected]262eec82013-03-19 21:01:36127 priority_(priority),
tombergan5d22c182017-01-11 02:05:35128 session_deps_(session_deps.get() == nullptr
Jeremy Roman0579ed62017-08-29 15:56:19129 ? std::make_unique<SpdySessionDependencies>()
bncd16676a2016-07-20 16:23:01130 : std::move(session_deps)),
xunjieli925519532017-01-30 15:33:17131 log_(log) {
132 session_deps_->net_log = log.net_log();
133 session_ =
134 SpdySessionDependencies::SpdyCreateSession(session_deps_.get());
135 }
[email protected]61b4efc2012-04-27 18:12:50136
[email protected]19ec8a72010-08-23 03:38:23137 ~NormalSpdyTransactionHelper() {
138 // Any test which doesn't close the socket by sending it an EOF will
139 // have a valid session left open, which leaks the entire session pool.
140 // This is just fine - in fact, some of our tests intentionally do this
141 // so that we can check consistency of the SpdySessionPool as the test
142 // finishes. If we had put an EOF on the socket, the SpdySession would
143 // have closed and we wouldn't be able to check the consistency.
144
145 // Forcefully close existing sessions here.
146 session()->spdy_session_pool()->CloseAllSessions();
147 }
148
[email protected]3caf5542010-07-16 15:19:47149 void RunPreTestSetup() {
[email protected]3caf5542010-07-16 15:19:47150 // We're now ready to use SSL-npn SPDY.
bnc3f6a8552017-05-17 13:40:34151 trans_ =
Jeremy Roman0579ed62017-08-29 15:56:19152 std::make_unique<HttpNetworkTransaction>(priority_, session_.get());
[email protected]cb54b3b22010-06-03 16:28:55153 }
[email protected]aea80602009-09-18 00:55:08154
[email protected]3caf5542010-07-16 15:19:47155 // Start the transaction, read some data, finish.
156 void RunDefaultTest() {
[email protected]34b345f92013-02-22 03:27:26157 if (!StartDefaultTest())
158 return;
159 FinishDefaultTest();
160 }
161
162 bool StartDefaultTest() {
[email protected]514aeaf2014-05-23 10:31:51163 output_.rv = trans_->Start(&request_, callback_.callback(), log_);
[email protected]aea80602009-09-18 00:55:08164
[email protected]3caf5542010-07-16 15:19:47165 // We expect an IO Pending or some sort of error.
166 EXPECT_LT(output_.rv, 0);
[email protected]34b345f92013-02-22 03:27:26167 return output_.rv == ERR_IO_PENDING;
168 }
[email protected]aea80602009-09-18 00:55:08169
[email protected]34b345f92013-02-22 03:27:26170 void FinishDefaultTest() {
[email protected]514aeaf2014-05-23 10:31:51171 output_.rv = callback_.WaitForResult();
bnceb9aa7112017-01-05 01:03:46172 // Finish async network reads/writes.
173 base::RunLoop().RunUntilIdle();
[email protected]3caf5542010-07-16 15:19:47174 if (output_.rv != OK) {
bnc301745a2015-03-10 03:22:16175 session_->spdy_session_pool()->CloseCurrentSessions(ERR_ABORTED);
[email protected]3caf5542010-07-16 15:19:47176 return;
177 }
[email protected]ff57bb82009-11-12 06:52:14178
[email protected]3caf5542010-07-16 15:19:47179 // Verify responses.
180 const HttpResponseInfo* response = trans_->GetResponseInfo();
wezca1070932016-05-26 20:30:52181 ASSERT_TRUE(response);
182 ASSERT_TRUE(response->headers);
bnc80bb1d42016-10-26 18:11:34183 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP2,
bnc927c4962016-07-21 14:45:59184 response->connection_info);
185 EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
186 EXPECT_TRUE(response->was_fetched_via_spdy);
bnc94c92842016-09-21 15:22:52187 EXPECT_TRUE(response->was_alpn_negotiated);
Tsuyoshi Horo01faed62019-02-20 22:11:37188 EXPECT_EQ("127.0.0.1", response->remote_endpoint.ToStringWithoutPort());
189 EXPECT_EQ(443, response->remote_endpoint.port());
[email protected]3caf5542010-07-16 15:19:47190 output_.status_line = response->headers->GetStatusLine();
191 output_.response_info = *response; // Make a copy so we can verify.
192 output_.rv = ReadTransaction(trans_.get(), &output_.response_data);
[email protected]3caf5542010-07-16 15:19:47193 }
194
bncfacdd852015-01-09 19:22:54195 void FinishDefaultTestWithoutVerification() {
196 output_.rv = callback_.WaitForResult();
bnceb9aa7112017-01-05 01:03:46197 // Finish async network reads/writes.
198 base::RunLoop().RunUntilIdle();
bncfacdd852015-01-09 19:22:54199 if (output_.rv != OK)
bnc301745a2015-03-10 03:22:16200 session_->spdy_session_pool()->CloseCurrentSessions(ERR_ABORTED);
bncfacdd852015-01-09 19:22:54201 }
202
maksim.sisov8d2df66d2016-06-20 07:07:11203 void WaitForCallbackToComplete() { output_.rv = callback_.WaitForResult(); }
mmenke666a6fea2015-12-19 04:16:33204
[email protected]3caf5542010-07-16 15:19:47205 // Most tests will want to call this function. In particular, the MockReads
206 // should end with an empty read, and that read needs to be processed to
207 // ensure proper deletion of the spdy_session_pool.
208 void VerifyDataConsumed() {
rch08e3aa3e2015-05-16 14:27:52209 for (const SocketDataProvider* provider : data_vector_) {
210 EXPECT_TRUE(provider->AllReadDataConsumed());
211 EXPECT_TRUE(provider->AllWriteDataConsumed());
[email protected]3caf5542010-07-16 15:19:47212 }
213 }
214
215 // Occasionally a test will expect to error out before certain reads are
216 // processed. In that case we want to explicitly ensure that the reads were
217 // not processed.
218 void VerifyDataNotConsumed() {
rch08e3aa3e2015-05-16 14:27:52219 for (const SocketDataProvider* provider : data_vector_) {
220 EXPECT_FALSE(provider->AllReadDataConsumed());
221 EXPECT_FALSE(provider->AllWriteDataConsumed());
[email protected]3caf5542010-07-16 15:19:47222 }
223 }
224
rch08e3aa3e2015-05-16 14:27:52225 void RunToCompletion(SocketDataProvider* data) {
[email protected]3caf5542010-07-16 15:19:47226 RunPreTestSetup();
[email protected]e3ebba0f2010-08-05 17:59:58227 AddData(data);
[email protected]3caf5542010-07-16 15:19:47228 RunDefaultTest();
229 VerifyDataConsumed();
230 }
[email protected]e6b06862010-07-20 16:32:58231
[email protected]514aeaf2014-05-23 10:31:51232 void RunToCompletionWithSSLData(
rch08e3aa3e2015-05-16 14:27:52233 SocketDataProvider* data,
danakjaee3e1ec2016-04-16 00:23:18234 std::unique_ptr<SSLSocketDataProvider> ssl_provider) {
[email protected]514aeaf2014-05-23 10:31:51235 RunPreTestSetup();
dchengc7eeda422015-12-26 03:56:48236 AddDataWithSSLSocketDataProvider(data, std::move(ssl_provider));
[email protected]514aeaf2014-05-23 10:31:51237 RunDefaultTest();
238 VerifyDataConsumed();
239 }
240
rch08e3aa3e2015-05-16 14:27:52241 void AddData(SocketDataProvider* data) {
Jeremy Roman0579ed62017-08-29 15:56:19242 auto ssl_provider = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
Ryan Sleevi4f832092017-11-21 23:25:49243 ssl_provider->ssl_info.cert =
bncce36dca22015-04-21 22:11:23244 ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem");
dchengc7eeda422015-12-26 03:56:48245 AddDataWithSSLSocketDataProvider(data, std::move(ssl_provider));
[email protected]514aeaf2014-05-23 10:31:51246 }
247
248 void AddDataWithSSLSocketDataProvider(
rch08e3aa3e2015-05-16 14:27:52249 SocketDataProvider* data,
danakjaee3e1ec2016-04-16 00:23:18250 std::unique_ptr<SSLSocketDataProvider> ssl_provider) {
[email protected]3caf5542010-07-16 15:19:47251 data_vector_.push_back(data);
bnc3cf2a592016-08-11 14:48:36252 if (ssl_provider->next_proto == kProtoUnknown)
253 ssl_provider->next_proto = kProtoHTTP2;
rchebf12982015-04-10 01:15:00254
255 session_deps_->socket_factory->AddSSLSocketDataProvider(
256 ssl_provider.get());
olli.raulaae011c422015-12-10 07:38:51257 ssl_vector_.push_back(std::move(ssl_provider));
[email protected]d4f00222012-07-10 06:24:51258
[email protected]3b7828432010-08-18 18:33:27259 session_deps_->socket_factory->AddSocketDataProvider(data);
260 }
261
[email protected]3caf5542010-07-16 15:19:47262 HttpNetworkTransaction* trans() { return trans_.get(); }
263 void ResetTrans() { trans_.reset(); }
bnc4d782f492016-08-18 13:50:00264 const TransactionHelperResult& output() { return output_; }
mmenkee65e7af2015-10-13 17:16:42265 HttpNetworkSession* session() const { return session_.get(); }
bncd16676a2016-07-20 16:23:01266 SpdySessionDependencies* session_deps() { return session_deps_.get(); }
[email protected]3caf5542010-07-16 15:19:47267
268 private:
rch08e3aa3e2015-05-16 14:27:52269 typedef std::vector<SocketDataProvider*> DataVector;
danakjaee3e1ec2016-04-16 00:23:18270 typedef std::vector<std::unique_ptr<SSLSocketDataProvider>> SSLVector;
271 typedef std::vector<std::unique_ptr<SocketDataProvider>> AlternateVector;
Bence Békydb3cf652017-10-10 15:22:10272 const HttpRequestInfo request_;
273 const RequestPriority priority_;
danakjaee3e1ec2016-04-16 00:23:18274 std::unique_ptr<SpdySessionDependencies> session_deps_;
275 std::unique_ptr<HttpNetworkSession> session_;
[email protected]3caf5542010-07-16 15:19:47276 TransactionHelperResult output_;
[email protected]3caf5542010-07-16 15:19:47277 SSLVector ssl_vector_;
[email protected]514aeaf2014-05-23 10:31:51278 TestCompletionCallback callback_;
danakjaee3e1ec2016-04-16 00:23:18279 std::unique_ptr<HttpNetworkTransaction> trans_;
[email protected]3caf5542010-07-16 15:19:47280 DataVector data_vector_;
tfarina428341112016-09-22 13:38:20281 const NetLogWithSource log_;
[email protected]3caf5542010-07-16 15:19:47282 };
[email protected]aea80602009-09-18 00:55:08283
284 void ConnectStatusHelperWithExpectedStatus(const MockRead& status,
285 int expected_status);
286
287 void ConnectStatusHelper(const MockRead& status);
[email protected]d3cee19d2010-06-22 18:42:18288
Bence Békydb3cf652017-10-10 15:22:10289 HttpRequestInfo CreateGetPushRequest() const WARN_UNUSED_RESULT {
290 HttpRequestInfo request;
291 request.method = "GET";
Bence Békyd2df6c1c82018-04-20 22:52:01292 request.url = GURL(kPushedUrl);
Ramin Halavatib5e433e62018-02-07 07:41:10293 request.traffic_annotation =
294 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
Bence Békydb3cf652017-10-10 15:22:10295 return request;
[email protected]e3ebba0f2010-08-05 17:59:58296 }
297
Bence Békydb3cf652017-10-10 15:22:10298 void UsePostRequest() {
299 ASSERT_FALSE(upload_data_stream_);
300 std::vector<std::unique_ptr<UploadElementReader>> element_readers;
301 element_readers.push_back(std::make_unique<UploadBytesElementReader>(
302 kUploadData, kUploadDataSize));
303 upload_data_stream_ = std::make_unique<ElementsUploadDataStream>(
304 std::move(element_readers), 0);
305
306 request_.method = "POST";
307 request_.upload_data_stream = upload_data_stream_.get();
[email protected]d3cee19d2010-06-22 18:42:18308 }
309
Bence Békydb3cf652017-10-10 15:22:10310 void UseFilePostRequest() {
311 ASSERT_FALSE(upload_data_stream_);
312 base::FilePath file_path;
313 CHECK(base::CreateTemporaryFileInDir(temp_dir_.GetPath(), &file_path));
314 CHECK_EQ(static_cast<int>(kUploadDataSize),
315 base::WriteFile(file_path, kUploadData, kUploadDataSize));
316
317 std::vector<std::unique_ptr<UploadElementReader>> element_readers;
318 element_readers.push_back(std::make_unique<UploadFileElementReader>(
319 base::ThreadTaskRunnerHandle::Get().get(), file_path, 0,
320 kUploadDataSize, base::Time()));
321 upload_data_stream_ = std::make_unique<ElementsUploadDataStream>(
322 std::move(element_readers), 0);
323
324 request_.method = "POST";
325 request_.upload_data_stream = upload_data_stream_.get();
Ramin Halavatib5e433e62018-02-07 07:41:10326 request_.traffic_annotation =
327 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
[email protected]3deb9a52010-11-11 00:24:40328 }
329
Bence Békydb3cf652017-10-10 15:22:10330 void UseUnreadableFilePostRequest() {
331 ASSERT_FALSE(upload_data_stream_);
[email protected]999dd8c2013-11-12 06:45:54332 base::FilePath file_path;
vabrb8582322016-09-09 08:05:37333 CHECK(base::CreateTemporaryFileInDir(temp_dir_.GetPath(), &file_path));
[email protected]999dd8c2013-11-12 06:45:54334 CHECK_EQ(static_cast<int>(kUploadDataSize),
[email protected]e5c2a22e2014-03-06 20:42:30335 base::WriteFile(file_path, kUploadData, kUploadDataSize));
[email protected]92be8eb2014-08-07 22:57:11336 CHECK(base::MakeFileUnreadable(file_path));
[email protected]999dd8c2013-11-12 06:45:54337
danakjaee3e1ec2016-04-16 00:23:18338 std::vector<std::unique_ptr<UploadElementReader>> element_readers;
Jeremy Roman0579ed62017-08-29 15:56:19339 element_readers.push_back(std::make_unique<UploadFileElementReader>(
skyostil4891b25b2015-06-11 11:43:45340 base::ThreadTaskRunnerHandle::Get().get(), file_path, 0,
ricea2deef682016-09-09 08:04:07341 kUploadDataSize, base::Time()));
Jeremy Roman0579ed62017-08-29 15:56:19342 upload_data_stream_ = std::make_unique<ElementsUploadDataStream>(
bnc3f6a8552017-05-17 13:40:34343 std::move(element_readers), 0);
[email protected]999dd8c2013-11-12 06:45:54344
Bence Békydb3cf652017-10-10 15:22:10345 request_.method = "POST";
346 request_.upload_data_stream = upload_data_stream_.get();
[email protected]999dd8c2013-11-12 06:45:54347 }
348
Bence Békydb3cf652017-10-10 15:22:10349 void UseComplexPostRequest() {
350 ASSERT_FALSE(upload_data_stream_);
351 const int kFileRangeOffset = 1;
352 const int kFileRangeLength = 3;
353 CHECK_LT(kFileRangeOffset + kFileRangeLength, kUploadDataSize);
[email protected]69e6b4a2012-10-18 08:03:01354
Bence Békydb3cf652017-10-10 15:22:10355 base::FilePath file_path;
356 CHECK(base::CreateTemporaryFileInDir(temp_dir_.GetPath(), &file_path));
357 CHECK_EQ(static_cast<int>(kUploadDataSize),
358 base::WriteFile(file_path, kUploadData, kUploadDataSize));
[email protected]69e6b4a2012-10-18 08:03:01359
Bence Békydb3cf652017-10-10 15:22:10360 std::vector<std::unique_ptr<UploadElementReader>> element_readers;
361 element_readers.push_back(std::make_unique<UploadBytesElementReader>(
362 kUploadData, kFileRangeOffset));
363 element_readers.push_back(std::make_unique<UploadFileElementReader>(
364 base::ThreadTaskRunnerHandle::Get().get(), file_path, kFileRangeOffset,
365 kFileRangeLength, base::Time()));
366 element_readers.push_back(std::make_unique<UploadBytesElementReader>(
367 kUploadData + kFileRangeOffset + kFileRangeLength,
368 kUploadDataSize - (kFileRangeOffset + kFileRangeLength)));
369 upload_data_stream_ = std::make_unique<ElementsUploadDataStream>(
370 std::move(element_readers), 0);
[email protected]329b68b2012-11-14 17:54:27371
Bence Békydb3cf652017-10-10 15:22:10372 request_.method = "POST";
373 request_.upload_data_stream = upload_data_stream_.get();
[email protected]69e6b4a2012-10-18 08:03:01374 }
375
Bence Békydb3cf652017-10-10 15:22:10376 void UseChunkedPostRequest() {
377 ASSERT_FALSE(upload_chunked_data_stream_);
378 upload_chunked_data_stream_ = std::make_unique<ChunkedUploadDataStream>(0);
379 request_.method = "POST";
380 request_.upload_data_stream = upload_chunked_data_stream_.get();
[email protected]0c9bf872011-03-04 17:53:22381 }
382
[email protected]19ec8a72010-08-23 03:38:23383 // Read the result of a particular transaction, knowing that we've got
384 // multiple transactions in the read pipeline; so as we read, we may have
385 // to skip over data destined for other transactions while we consume
386 // the data for |trans|.
Bence Béky4e83f492018-05-13 23:14:25387 int ReadResult(HttpNetworkTransaction* trans, std::string* result) {
[email protected]19ec8a72010-08-23 03:38:23388 const int kSize = 3000;
[email protected]e3ebba0f2010-08-05 17:59:58389
[email protected]19ec8a72010-08-23 03:38:23390 int bytes_read = 0;
Victor Costan9c7302b2018-08-27 16:39:44391 scoped_refptr<IOBufferWithSize> buf =
392 base::MakeRefCounted<IOBufferWithSize>(kSize);
[email protected]49639fa2011-12-20 23:22:41393 TestCompletionCallback callback;
[email protected]19ec8a72010-08-23 03:38:23394 while (true) {
[email protected]90499482013-06-01 00:39:50395 int rv = trans->Read(buf.get(), kSize, callback.callback());
[email protected]19ec8a72010-08-23 03:38:23396 if (rv == ERR_IO_PENDING) {
[email protected]19ec8a72010-08-23 03:38:23397 rv = callback.WaitForResult();
398 } else if (rv <= 0) {
399 break;
400 }
401 result->append(buf->data(), rv);
402 bytes_read += rv;
[email protected]e3ebba0f2010-08-05 17:59:58403 }
[email protected]19ec8a72010-08-23 03:38:23404 return bytes_read;
405 }
[email protected]e3ebba0f2010-08-05 17:59:58406
[email protected]19ec8a72010-08-23 03:38:23407 void VerifyStreamsClosed(const NormalSpdyTransactionHelper& helper) {
408 // This lengthy block is reaching into the pool to dig out the active
409 // session. Once we have the session, we verify that the streams are
410 // all closed and not leaked at this point.
Bence Békydb3cf652017-10-10 15:22:10411 SpdySessionKey key(HostPortPair::FromURL(request_.url),
Paul Jensena457017a2018-01-19 23:52:04412 ProxyServer::Direct(), PRIVACY_MODE_DISABLED,
dalyk51ab46b2019-10-15 15:14:34413 SpdySessionKey::IsProxySession::kFalse, SocketTag(),
414 NetworkIsolationKey(), false /* disable_secure_dns */);
mmenkee65e7af2015-10-13 17:16:42415 HttpNetworkSession* session = helper.session();
[email protected]795cbf82013-07-22 09:37:27416 base::WeakPtr<SpdySession> spdy_session =
bnc9ead3ae2017-03-16 00:48:15417 session->spdy_session_pool()->FindAvailableSession(
Bence Békyd885b2b2018-02-03 00:58:31418 key, /* enable_ip_based_pooling = */ true,
419 /* is_websocket = */ false, log_);
wezca1070932016-05-26 20:30:52420 ASSERT_TRUE(spdy_session);
Bence Béky285e7d42017-12-04 20:22:11421 EXPECT_EQ(0u, num_active_streams(spdy_session));
422 EXPECT_EQ(0u, num_unclaimed_pushed_streams(spdy_session));
[email protected]19ec8a72010-08-23 03:38:23423 }
[email protected]e3ebba0f2010-08-05 17:59:58424
rch08e3aa3e2015-05-16 14:27:52425 void RunServerPushTest(SequencedSocketData* data,
[email protected]e3ebba0f2010-08-05 17:59:58426 HttpResponseInfo* response,
[email protected]a7a265ef2010-12-08 18:05:57427 HttpResponseInfo* push_response,
Bence Béky4e83f492018-05-13 23:14:25428 const std::string& expected) {
Bence Békydb3cf652017-10-10 15:22:10429 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
430 nullptr);
[email protected]e3ebba0f2010-08-05 17:59:58431 helper.RunPreTestSetup();
[email protected]d08358502010-12-03 22:04:03432 helper.AddData(data);
[email protected]e3ebba0f2010-08-05 17:59:58433
434 HttpNetworkTransaction* trans = helper.trans();
435
436 // Start the transaction with basic parameters.
[email protected]49639fa2011-12-20 23:22:41437 TestCompletionCallback callback;
Bence Békydb3cf652017-10-10 15:22:10438 int rv = trans->Start(&request_, callback.callback(), log_);
robpercival214763f2016-07-01 23:27:01439 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]e3ebba0f2010-08-05 17:59:58440 rv = callback.WaitForResult();
441
bnceb9aa7112017-01-05 01:03:46442 // Finish async network reads/writes.
443 base::RunLoop().RunUntilIdle();
444
[email protected]e3ebba0f2010-08-05 17:59:58445 // Request the pushed path.
bnc691fda62016-08-12 00:43:16446 HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session());
Bence Békydb3cf652017-10-10 15:22:10447 HttpRequestInfo request = CreateGetPushRequest();
448 rv = trans2.Start(&request, callback.callback(), log_);
robpercival214763f2016-07-01 23:27:01449 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]fc9d88472013-08-14 02:31:17450 base::RunLoop().RunUntilIdle();
[email protected]e3ebba0f2010-08-05 17:59:58451
[email protected]513963e2013-06-15 01:53:04452 // The data for the pushed path may be coming in more than 1 frame. Compile
[email protected]e3ebba0f2010-08-05 17:59:58453 // the results into a single string.
[email protected]19ec8a72010-08-23 03:38:23454
455 // Read the server push body.
Bence Béky4e83f492018-05-13 23:14:25456 std::string result2;
bnc691fda62016-08-12 00:43:16457 ReadResult(&trans2, &result2);
[email protected]19ec8a72010-08-23 03:38:23458 // Read the response body.
Bence Béky4e83f492018-05-13 23:14:25459 std::string result;
rch0aecfd82015-05-19 17:22:32460 ReadResult(trans, &result);
[email protected]e3ebba0f2010-08-05 17:59:58461
462 // Verify that we consumed all test data.
rch37de576c2015-05-17 20:28:17463 EXPECT_TRUE(data->AllReadDataConsumed());
464 EXPECT_TRUE(data->AllWriteDataConsumed());
[email protected]e3ebba0f2010-08-05 17:59:58465
caseqe8340bc92016-04-20 00:02:57466 LoadTimingInfo load_timing_info;
467 EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info));
468 EXPECT_TRUE(load_timing_info.push_start.is_null());
469 EXPECT_TRUE(load_timing_info.push_end.is_null());
470
471 LoadTimingInfo load_timing_info2;
bnc691fda62016-08-12 00:43:16472 EXPECT_TRUE(trans2.GetLoadTimingInfo(&load_timing_info2));
caseqe8340bc92016-04-20 00:02:57473 EXPECT_FALSE(load_timing_info2.push_start.is_null());
474 EXPECT_FALSE(load_timing_info2.push_end.is_null());
475
[email protected]e3ebba0f2010-08-05 17:59:58476 // Verify that the received push data is same as the expected push data.
[email protected]19ec8a72010-08-23 03:38:23477 EXPECT_EQ(result2.compare(expected), 0) << "Received data: "
478 << result2
479 << "||||| Expected data: "
480 << expected;
[email protected]e3ebba0f2010-08-05 17:59:58481
bnc42331402016-07-25 13:36:15482 // Verify the response HEADERS.
[email protected]e3ebba0f2010-08-05 17:59:58483 // Copy the response info, because trans goes away.
484 *response = *trans->GetResponseInfo();
bnc691fda62016-08-12 00:43:16485 *push_response = *trans2.GetResponseInfo();
[email protected]19ec8a72010-08-23 03:38:23486
487 VerifyStreamsClosed(helper);
[email protected]e3ebba0f2010-08-05 17:59:58488 }
489
morlovichab1d1c1e2017-02-07 19:59:28490 void RunBrokenPushTest(SequencedSocketData* data, int expected_rv) {
Bence Békydb3cf652017-10-10 15:22:10491 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
492 nullptr);
morlovichab1d1c1e2017-02-07 19:59:28493 helper.RunPreTestSetup();
494 helper.AddData(data);
495
496 HttpNetworkTransaction* trans = helper.trans();
497
498 // Start the transaction with basic parameters.
499 TestCompletionCallback callback;
Bence Békydb3cf652017-10-10 15:22:10500 int rv = trans->Start(&request_, callback.callback(), log_);
morlovichab1d1c1e2017-02-07 19:59:28501 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
502 rv = callback.WaitForResult();
503 EXPECT_EQ(expected_rv, rv);
504
505 // Finish async network reads/writes.
506 base::RunLoop().RunUntilIdle();
507
508 // Verify that we consumed all test data.
509 EXPECT_TRUE(data->AllReadDataConsumed());
510 EXPECT_TRUE(data->AllWriteDataConsumed());
511
512 if (expected_rv == OK) {
513 // Expected main request to succeed, even if push failed.
514 HttpResponseInfo response = *trans->GetResponseInfo();
515 EXPECT_TRUE(response.headers);
516 EXPECT_EQ("HTTP/1.1 200", response.headers->GetStatusLine());
517 }
518 }
519
[email protected]49639fa2011-12-20 23:22:41520 static void DeleteSessionCallback(NormalSpdyTransactionHelper* helper,
521 int result) {
522 helper->ResetTrans();
523 }
524
mmenkee65e7af2015-10-13 17:16:42525 static void StartTransactionCallback(HttpNetworkSession* session,
526 GURL url,
Bence Békyd3dde832017-09-19 19:02:31527 NetLogWithSource log,
mmenkee65e7af2015-10-13 17:16:42528 int result) {
krasin0bfeb6b2017-01-13 21:48:04529 HttpRequestInfo request;
bnc691fda62016-08-12 00:43:16530 HttpNetworkTransaction trans(DEFAULT_PRIORITY, session);
[email protected]49639fa2011-12-20 23:22:41531 TestCompletionCallback callback;
[email protected]49639fa2011-12-20 23:22:41532 request.method = "GET";
rchebf12982015-04-10 01:15:00533 request.url = url;
Ramin Halavatib5e433e62018-02-07 07:41:10534 request.traffic_annotation =
535 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
Bence Békyd3dde832017-09-19 19:02:31536 int rv = trans.Start(&request, callback.callback(), log);
robpercival214763f2016-07-01 23:27:01537 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]49639fa2011-12-20 23:22:41538 callback.WaitForResult();
539 }
540
Bence Békydb3cf652017-10-10 15:22:10541 ChunkedUploadDataStream* upload_chunked_data_stream() {
mmenkecbc2b712014-10-09 20:29:07542 return upload_chunked_data_stream_.get();
543 }
544
Bence Béky285e7d42017-12-04 20:22:11545 size_t num_active_streams(base::WeakPtr<SpdySession> session) {
546 return session->active_streams_.size();
547 }
548
Bence Békyfd2c1fd2017-12-15 02:32:03549 static size_t num_unclaimed_pushed_streams(
550 base::WeakPtr<SpdySession> session) {
551 return session->pool_->push_promise_index()->CountStreamsForSession(
552 session.get());
Bence Béky285e7d42017-12-04 20:22:11553 }
554
Bence Békyfd2c1fd2017-12-15 02:32:03555 static bool has_unclaimed_pushed_stream_for_url(
556 base::WeakPtr<SpdySession> session,
557 const GURL& url) {
558 return session->pool_->push_promise_index()->FindStream(
559 url, session.get()) != kNoPushedStreamFound;
Bence Béky285e7d42017-12-04 20:22:11560 }
561
Ryan Hamilton0239aac2018-05-19 00:03:13562 static spdy::SpdyStreamId spdy_stream_hi_water_mark(
Yoav Weiss9693572f2018-01-04 09:37:34563 base::WeakPtr<SpdySession> session) {
564 return session->stream_hi_water_mark_;
565 }
566
David Benjaminbae08ba2019-10-18 21:06:15567 base::RepeatingClosure FastForwardByCallback(base::TimeDelta delta) {
568 return base::BindRepeating(&SpdyNetworkTransactionTest::FastForwardBy,
569 base::Unretained(this), delta);
570 }
571
bncb26024382016-06-29 02:39:45572 const GURL default_url_;
573 const HostPortPair host_port_pair_;
Bence Békydb3cf652017-10-10 15:22:10574 HttpRequestInfo request_;
[email protected]9ec54f82013-05-10 02:53:05575 SpdyTestUtil spdy_util_;
Bence Békyd3dde832017-09-19 19:02:31576 const NetLogWithSource log_;
[email protected]9ec54f82013-05-10 02:53:05577
[email protected]d3cee19d2010-06-22 18:42:18578 private:
danakjaee3e1ec2016-04-16 00:23:18579 std::unique_ptr<ChunkedUploadDataStream> upload_chunked_data_stream_;
580 std::unique_ptr<UploadDataStream> upload_data_stream_;
[email protected]ea1a3f62012-11-16 20:34:23581 base::ScopedTempDir temp_dir_;
[email protected]aea80602009-09-18 00:55:08582};
583
[email protected]3caf5542010-07-16 15:19:47584// Verify HttpNetworkTransaction constructor.
bncd16676a2016-07-20 16:23:01585TEST_F(SpdyNetworkTransactionTest, Constructor) {
Jeremy Roman0579ed62017-08-29 15:56:19586 auto session_deps = std::make_unique<SpdySessionDependencies>();
danakjaee3e1ec2016-04-16 00:23:18587 std::unique_ptr<HttpNetworkSession> session(
[email protected]bb88e1d32013-05-03 23:11:07588 SpdySessionDependencies::SpdyCreateSession(session_deps.get()));
bncd16676a2016-07-20 16:23:01589 auto trans =
Jeremy Roman0579ed62017-08-29 15:56:19590 std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
[email protected]aea80602009-09-18 00:55:08591}
592
bncd16676a2016-07-20 16:23:01593TEST_F(SpdyNetworkTransactionTest, Get) {
[email protected]75f30cc22010-06-28 21:41:38594 // Construct the request.
Ryan Hamilton0239aac2018-05-19 00:03:13595 spdy::SpdySerializedFrame req(
596 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
bncdf80d44fd2016-07-15 20:27:41597 MockWrite writes[] = {CreateMockWrite(req, 0)};
[email protected]72552f02009-10-28 15:25:01598
Ryan Hamilton0239aac2018-05-19 00:03:13599 spdy::SpdySerializedFrame resp(
600 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
601 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]72552f02009-10-28 15:25:01602 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:41603 CreateMockRead(resp, 1), CreateMockRead(body, 2),
rch08e3aa3e2015-05-16 14:27:52604 MockRead(ASYNC, 0, 3) // EOF
[email protected]72552f02009-10-28 15:25:01605 };
606
Ryan Sleevib8d7ea02018-05-07 20:01:01607 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:10608 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]dd54bd82012-07-19 23:44:57609 helper.RunToCompletion(&data);
[email protected]3caf5542010-07-16 15:19:47610 TransactionHelperResult out = helper.output();
robpercival214763f2016-07-01 23:27:01611 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:02612 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]72552f02009-10-28 15:25:01613 EXPECT_EQ("hello!", out.response_data);
614}
615
Bence Béky2fcf4fa2018-04-06 20:06:01616TEST_F(SpdyNetworkTransactionTest, SetPriority) {
617 for (bool set_priority_before_starting_transaction : {true, false}) {
618 SpdyTestUtil spdy_test_util;
Ryan Hamilton0239aac2018-05-19 00:03:13619 spdy::SpdySerializedFrame req(
Bence Béky2fcf4fa2018-04-06 20:06:01620 spdy_test_util.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
621 MockWrite writes[] = {CreateMockWrite(req, 0)};
622
Ryan Hamilton0239aac2018-05-19 00:03:13623 spdy::SpdySerializedFrame resp(
Bence Béky2fcf4fa2018-04-06 20:06:01624 spdy_test_util.ConstructSpdyGetReply(nullptr, 0, 1));
Ryan Hamilton0239aac2018-05-19 00:03:13625 spdy::SpdySerializedFrame body(
626 spdy_test_util.ConstructSpdyDataFrame(1, true));
Bence Béky2fcf4fa2018-04-06 20:06:01627 MockRead reads[] = {CreateMockRead(resp, 1), CreateMockRead(body, 2),
628 MockRead(ASYNC, 0, 3)};
629
Ryan Sleevib8d7ea02018-05-07 20:01:01630 SequencedSocketData data(reads, writes);
Bence Béky2fcf4fa2018-04-06 20:06:01631 NormalSpdyTransactionHelper helper(request_, HIGHEST, log_, nullptr);
632 helper.RunPreTestSetup();
633 helper.AddData(&data);
634
635 if (set_priority_before_starting_transaction) {
636 helper.trans()->SetPriority(LOWEST);
637 EXPECT_TRUE(helper.StartDefaultTest());
638 } else {
639 EXPECT_TRUE(helper.StartDefaultTest());
640 helper.trans()->SetPriority(LOWEST);
641 }
642
643 helper.FinishDefaultTest();
644 helper.VerifyDataConsumed();
645
646 TransactionHelperResult out = helper.output();
647 EXPECT_THAT(out.rv, IsOk());
648 EXPECT_EQ("HTTP/1.1 200", out.status_line);
649 EXPECT_EQ("hello!", out.response_data);
650 }
651}
652
Bence Béky7a4836c2018-05-08 03:52:48653// Test that changing the request priority of an existing stream triggers
Bence Béky73b85292018-06-14 04:56:43654// sending PRIORITY frames in case there are multiple open streams and their
Bence Béky7a4836c2018-05-08 03:52:48655// relative priorities change.
Bence Béky73b85292018-06-14 04:56:43656TEST_F(SpdyNetworkTransactionTest, SetPriorityOnExistingStream) {
Bence Béky7a4836c2018-05-08 03:52:48657 const char* kUrl2 = "https://www.example.org/bar";
658
Ryan Hamilton0239aac2018-05-19 00:03:13659 spdy::SpdySerializedFrame req1(
660 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, HIGHEST));
661 spdy::SpdySerializedFrame req2(spdy_util_.ConstructSpdyGet(kUrl2, 3, MEDIUM));
662 spdy::SpdySerializedFrame priority1(
Bence Béky7a4836c2018-05-08 03:52:48663 spdy_util_.ConstructSpdyPriority(3, 0, MEDIUM, true));
Ryan Hamilton0239aac2018-05-19 00:03:13664 spdy::SpdySerializedFrame priority2(
Bence Béky7a4836c2018-05-08 03:52:48665 spdy_util_.ConstructSpdyPriority(1, 3, LOWEST, true));
666 MockWrite writes[] = {CreateMockWrite(req1, 0), CreateMockWrite(req2, 2),
667 CreateMockWrite(priority1, 4),
668 CreateMockWrite(priority2, 5)};
669
Ryan Hamilton0239aac2018-05-19 00:03:13670 spdy::SpdySerializedFrame resp1(
671 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
672 spdy::SpdySerializedFrame resp2(
673 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
674 spdy::SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true));
675 spdy::SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(3, true));
Bence Béky7a4836c2018-05-08 03:52:48676 MockRead reads[] = {CreateMockRead(resp1, 1), CreateMockRead(resp2, 3),
677 CreateMockRead(body1, 6), CreateMockRead(body2, 7),
678 MockRead(ASYNC, 0, 8)};
679
680 SequencedSocketData data(reads, writes);
681 NormalSpdyTransactionHelper helper(request_, HIGHEST, log_, nullptr);
682 helper.RunPreTestSetup();
683 helper.AddData(&data);
684 EXPECT_TRUE(helper.StartDefaultTest());
685
686 // Open HTTP/2 connection and create first stream.
687 base::RunLoop().RunUntilIdle();
688
689 HttpNetworkTransaction trans2(MEDIUM, helper.session());
690 HttpRequestInfo request2;
691 request2.url = GURL(kUrl2);
692 request2.method = "GET";
693 request2.traffic_annotation =
694 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
695 TestCompletionCallback callback2;
696 int rv = trans2.Start(&request2, callback2.callback(), log_);
697 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
698
699 // Create second stream.
700 base::RunLoop().RunUntilIdle();
701
702 // First request has HIGHEST priority, second request has MEDIUM priority.
703 // Changing the priority of the first request to LOWEST changes their order,
704 // and therefore triggers sending PRIORITY frames.
705 helper.trans()->SetPriority(LOWEST);
706
707 helper.FinishDefaultTest();
708 helper.VerifyDataConsumed();
709
710 TransactionHelperResult out = helper.output();
711 EXPECT_THAT(out.rv, IsOk());
712 EXPECT_EQ("HTTP/1.1 200", out.status_line);
713 EXPECT_EQ("hello!", out.response_data);
714
715 rv = callback2.WaitForResult();
716 ASSERT_THAT(rv, IsOk());
717 const HttpResponseInfo* response2 = trans2.GetResponseInfo();
718 ASSERT_TRUE(response2);
719 ASSERT_TRUE(response2->headers);
720 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP2,
721 response2->connection_info);
722 EXPECT_EQ("HTTP/1.1 200", response2->headers->GetStatusLine());
723}
724
Bence Béky73b85292018-06-14 04:56:43725// Create two requests: a lower priority one first, then a higher priority one.
726// Test that the second request gets sent out first.
727TEST_F(SpdyNetworkTransactionTest, RequestsOrderedByPriority) {
728 const char* kUrl2 = "https://www.example.org/foo";
729
730 // First send second request on stream 1, then first request on stream 3.
731 spdy::SpdySerializedFrame req2(
732 spdy_util_.ConstructSpdyGet(kUrl2, 1, HIGHEST));
733 spdy::SpdySerializedFrame req1(
734 spdy_util_.ConstructSpdyGet(nullptr, 0, 3, LOW));
735 MockWrite writes[] = {CreateMockWrite(req2, 0), CreateMockWrite(req1, 1)};
736
737 spdy::SpdySerializedFrame resp2(
738 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
739 spdy::SpdySerializedFrame resp1(
740 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
741 spdy::SpdySerializedFrame body2(
742 spdy_util_.ConstructSpdyDataFrame(1, "stream 1", true));
743 spdy::SpdySerializedFrame body1(
744 spdy_util_.ConstructSpdyDataFrame(3, "stream 3", true));
745 MockRead reads[] = {CreateMockRead(resp2, 2), CreateMockRead(body2, 3),
746 CreateMockRead(resp1, 4), CreateMockRead(body1, 5),
747 MockRead(ASYNC, 0, 6)};
748
749 SequencedSocketData data(reads, writes);
750 NormalSpdyTransactionHelper helper(request_, LOW, log_, nullptr);
751 helper.RunPreTestSetup();
752 helper.AddData(&data);
753
754 // Create HTTP/2 connection. This is necessary because starting the first
755 // transaction does not create the connection yet, so the second request
756 // could not use the same connection, whereas running the message loop after
757 // starting the first transaction would call Socket::Write() with the first
758 // HEADERS frame, so the second transaction could not get ahead of it.
759 SpdySessionKey key(HostPortPair("www.example.org", 443),
Matt Menke2436b2f2018-12-11 18:07:11760 ProxyServer::Direct(), PRIVACY_MODE_DISABLED,
dalyk51ab46b2019-10-15 15:14:34761 SpdySessionKey::IsProxySession::kFalse, SocketTag(),
762 NetworkIsolationKey(), false /* disable_secure_dns */);
Bence Béky73b85292018-06-14 04:56:43763 auto spdy_session = CreateSpdySession(helper.session(), key, log_);
764 EXPECT_TRUE(spdy_session);
765
766 // Start first transaction.
767 EXPECT_TRUE(helper.StartDefaultTest());
768
769 // Start second transaction.
770 HttpNetworkTransaction trans2(HIGHEST, helper.session());
771 HttpRequestInfo request2;
772 request2.url = GURL(kUrl2);
773 request2.method = "GET";
774 request2.traffic_annotation =
775 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
776 TestCompletionCallback callback2;
777 int rv = trans2.Start(&request2, callback2.callback(), log_);
778 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
779
780 // Complete first transaction and verify results.
781 helper.FinishDefaultTest();
782 helper.VerifyDataConsumed();
783
784 TransactionHelperResult out = helper.output();
785 EXPECT_THAT(out.rv, IsOk());
786 EXPECT_EQ("HTTP/1.1 200", out.status_line);
787 EXPECT_EQ("stream 3", out.response_data);
788
789 // Complete second transaction and verify results.
790 rv = callback2.WaitForResult();
791 ASSERT_THAT(rv, IsOk());
792 const HttpResponseInfo* response2 = trans2.GetResponseInfo();
793 ASSERT_TRUE(response2);
794 ASSERT_TRUE(response2->headers);
795 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP2,
796 response2->connection_info);
797 EXPECT_EQ("HTTP/1.1 200", response2->headers->GetStatusLine());
798 std::string response_data;
799 ReadTransaction(&trans2, &response_data);
800 EXPECT_EQ("stream 1", response_data);
801}
802
803// Test that already enqueued HEADERS frames are reordered if their relative
804// priority changes.
805TEST_F(SpdyNetworkTransactionTest, QueuedFramesReorderedOnPriorityChange) {
806 const char* kUrl2 = "https://www.example.org/foo";
807 const char* kUrl3 = "https://www.example.org/bar";
808
809 spdy::SpdySerializedFrame req1(
810 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, DEFAULT_PRIORITY));
811 spdy::SpdySerializedFrame req3(spdy_util_.ConstructSpdyGet(kUrl3, 3, MEDIUM));
812 spdy::SpdySerializedFrame req2(spdy_util_.ConstructSpdyGet(kUrl2, 5, LOWEST));
813 MockWrite writes[] = {MockWrite(ASYNC, ERR_IO_PENDING, 0),
814 CreateMockWrite(req1, 1), CreateMockWrite(req3, 2),
815 CreateMockWrite(req2, 3)};
816
817 spdy::SpdySerializedFrame resp1(
818 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
819 spdy::SpdySerializedFrame resp3(
820 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
821 spdy::SpdySerializedFrame resp2(
822 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 5));
823 spdy::SpdySerializedFrame body1(
824 spdy_util_.ConstructSpdyDataFrame(1, "stream 1", true));
825 spdy::SpdySerializedFrame body3(
826 spdy_util_.ConstructSpdyDataFrame(3, "stream 3", true));
827 spdy::SpdySerializedFrame body2(
828 spdy_util_.ConstructSpdyDataFrame(5, "stream 5", true));
829 MockRead reads[] = {CreateMockRead(resp1, 4), CreateMockRead(body1, 5),
830 CreateMockRead(resp3, 6), CreateMockRead(body3, 7),
831 CreateMockRead(resp2, 8), CreateMockRead(body2, 9),
832 MockRead(ASYNC, 0, 10)};
833
834 SequencedSocketData data(reads, writes);
835 // Priority of first request does not matter, because Socket::Write() will be
836 // called with its HEADERS frame before the other requests start.
837 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
838 helper.RunPreTestSetup();
839 helper.AddData(&data);
840 EXPECT_TRUE(helper.StartDefaultTest());
841
842 // Open HTTP/2 connection, create HEADERS frame for first request, and call
843 // Socket::Write() with that frame. After this, no other request can get
844 // ahead of the first one.
845 base::RunLoop().RunUntilIdle();
846
847 HttpNetworkTransaction trans2(HIGHEST, helper.session());
848 HttpRequestInfo request2;
849 request2.url = GURL(kUrl2);
850 request2.method = "GET";
851 request2.traffic_annotation =
852 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
853 TestCompletionCallback callback2;
854 int rv = trans2.Start(&request2, callback2.callback(), log_);
855 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
856
857 HttpNetworkTransaction trans3(MEDIUM, helper.session());
858 HttpRequestInfo request3;
859 request3.url = GURL(kUrl3);
860 request3.method = "GET";
861 request3.traffic_annotation =
862 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
863 TestCompletionCallback callback3;
864 rv = trans3.Start(&request3, callback3.callback(), log_);
865 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
866
867 // Create HEADERS frames for second and third request and enqueue them in
868 // SpdyWriteQueue with their original priorities. Writing of the first
869 // HEADERS frame to the socked still has not completed.
870 base::RunLoop().RunUntilIdle();
871
872 // Second request is of HIGHEST, third of MEDIUM priority. Changing second
873 // request to LOWEST changes their relative order. This should result in
874 // already enqueued frames being reordered within SpdyWriteQueue.
875 trans2.SetPriority(LOWEST);
876
877 // Complete async write of the first HEADERS frame.
878 data.Resume();
879
880 helper.FinishDefaultTest();
881 TransactionHelperResult out = helper.output();
882 EXPECT_THAT(out.rv, IsOk());
883 EXPECT_EQ("HTTP/1.1 200", out.status_line);
884 EXPECT_EQ("stream 1", out.response_data);
885
886 rv = callback2.WaitForResult();
887 ASSERT_THAT(rv, IsOk());
888 const HttpResponseInfo* response2 = trans2.GetResponseInfo();
889 ASSERT_TRUE(response2);
890 ASSERT_TRUE(response2->headers);
891 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP2,
892 response2->connection_info);
893 EXPECT_EQ("HTTP/1.1 200", response2->headers->GetStatusLine());
894 std::string response_data;
895 ReadTransaction(&trans2, &response_data);
896 EXPECT_EQ("stream 5", response_data);
897
898 rv = callback3.WaitForResult();
899 ASSERT_THAT(rv, IsOk());
900 const HttpResponseInfo* response3 = trans3.GetResponseInfo();
901 ASSERT_TRUE(response3);
902 ASSERT_TRUE(response3->headers);
903 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP2,
904 response3->connection_info);
905 EXPECT_EQ("HTTP/1.1 200", response3->headers->GetStatusLine());
906 ReadTransaction(&trans3, &response_data);
907 EXPECT_EQ("stream 3", response_data);
908
909 helper.VerifyDataConsumed();
910}
911
bncd16676a2016-07-20 16:23:01912TEST_F(SpdyNetworkTransactionTest, GetAtEachPriority) {
[email protected]3d08dd382013-10-19 00:13:11913 for (RequestPriority p = MINIMUM_PRIORITY; p <= MAXIMUM_PRIORITY;
[email protected]31ae7ab2012-04-24 21:09:05914 p = RequestPriority(p + 1)) {
bncd16676a2016-07-20 16:23:01915 SpdyTestUtil spdy_test_util;
bnc38dcd392016-02-09 23:19:49916
[email protected]c9c6f5c2010-07-31 01:30:03917 // Construct the request.
Ryan Hamilton0239aac2018-05-19 00:03:13918 spdy::SpdySerializedFrame req(
919 spdy_test_util.ConstructSpdyGet(nullptr, 0, 1, p));
bncdf80d44fd2016-07-15 20:27:41920 MockWrite writes[] = {CreateMockWrite(req, 0)};
[email protected]c9c6f5c2010-07-31 01:30:03921
Ryan Hamilton0239aac2018-05-19 00:03:13922 spdy::SpdyPriority spdy_prio = 0;
bncdf80d44fd2016-07-15 20:27:41923 EXPECT_TRUE(GetSpdyPriority(req, &spdy_prio));
Ryan Hamilton0239aac2018-05-19 00:03:13924 // this repeats the RequestPriority-->spdy::SpdyPriority mapping from
925 // spdy::SpdyFramer::ConvertRequestPriorityToSpdyPriority to make
[email protected]c9c6f5c2010-07-31 01:30:03926 // sure it's being done right.
bnc05808ff42016-01-08 23:48:25927 switch (p) {
928 case HIGHEST:
929 EXPECT_EQ(0, spdy_prio);
930 break;
931 case MEDIUM:
932 EXPECT_EQ(1, spdy_prio);
933 break;
934 case LOW:
935 EXPECT_EQ(2, spdy_prio);
936 break;
937 case LOWEST:
938 EXPECT_EQ(3, spdy_prio);
939 break;
940 case IDLE:
941 EXPECT_EQ(4, spdy_prio);
942 break;
rdsmith5eb6fbc2016-10-21 17:36:08943 case THROTTLED:
944 EXPECT_EQ(5, spdy_prio);
945 break;
bnc05808ff42016-01-08 23:48:25946 default:
947 FAIL();
[email protected]c9c6f5c2010-07-31 01:30:03948 }
949
Ryan Hamilton0239aac2018-05-19 00:03:13950 spdy::SpdySerializedFrame resp(
bnc42331402016-07-25 13:36:15951 spdy_test_util.ConstructSpdyGetReply(nullptr, 0, 1));
Ryan Hamilton0239aac2018-05-19 00:03:13952 spdy::SpdySerializedFrame body(
953 spdy_test_util.ConstructSpdyDataFrame(1, true));
[email protected]c9c6f5c2010-07-31 01:30:03954 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:41955 CreateMockRead(resp, 1), CreateMockRead(body, 2),
rch08e3aa3e2015-05-16 14:27:52956 MockRead(ASYNC, 0, 3) // EOF
[email protected]c9c6f5c2010-07-31 01:30:03957 };
958
Ryan Sleevib8d7ea02018-05-07 20:01:01959 SequencedSocketData data(reads, writes);
[email protected]c9c6f5c2010-07-31 01:30:03960
Bence Békydb3cf652017-10-10 15:22:10961 NormalSpdyTransactionHelper helper(request_, p, log_, nullptr);
[email protected]dd54bd82012-07-19 23:44:57962 helper.RunToCompletion(&data);
[email protected]c9c6f5c2010-07-31 01:30:03963 TransactionHelperResult out = helper.output();
robpercival214763f2016-07-01 23:27:01964 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:02965 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]c9c6f5c2010-07-31 01:30:03966 EXPECT_EQ("hello!", out.response_data);
967 }
968}
969
[email protected]2bd93022010-07-17 00:58:44970// Start three gets simultaniously; making sure that multiplexed
971// streams work properly.
972
973// This can't use the TransactionHelper method, since it only
974// handles a single transaction, and finishes them as soon
975// as it launches them.
976
977// TODO(gavinp): create a working generalized TransactionHelper that
978// can allow multiple streams in flight.
979
bncd16676a2016-07-20 16:23:01980TEST_F(SpdyNetworkTransactionTest, ThreeGets) {
Ryan Hamilton0239aac2018-05-19 00:03:13981 spdy::SpdySerializedFrame req(
982 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
983 spdy::SpdySerializedFrame resp(
984 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
985 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, false));
986 spdy::SpdySerializedFrame fbody(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]2bd93022010-07-17 00:58:44987
Ryan Hamilton0239aac2018-05-19 00:03:13988 spdy::SpdySerializedFrame req2(
989 spdy_util_.ConstructSpdyGet(nullptr, 0, 3, LOWEST));
990 spdy::SpdySerializedFrame resp2(
991 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
992 spdy::SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(3, false));
993 spdy::SpdySerializedFrame fbody2(spdy_util_.ConstructSpdyDataFrame(3, true));
[email protected]2bd93022010-07-17 00:58:44994
Ryan Hamilton0239aac2018-05-19 00:03:13995 spdy::SpdySerializedFrame req3(
996 spdy_util_.ConstructSpdyGet(nullptr, 0, 5, LOWEST));
997 spdy::SpdySerializedFrame resp3(
998 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 5));
999 spdy::SpdySerializedFrame body3(spdy_util_.ConstructSpdyDataFrame(5, false));
1000 spdy::SpdySerializedFrame fbody3(spdy_util_.ConstructSpdyDataFrame(5, true));
[email protected]2bd93022010-07-17 00:58:441001
[email protected]1b323172011-03-01 17:50:171002 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:411003 CreateMockWrite(req, 0), CreateMockWrite(req2, 3),
1004 CreateMockWrite(req3, 6),
[email protected]2bd93022010-07-17 00:58:441005 };
1006 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:411007 CreateMockRead(resp, 1), CreateMockRead(body, 2),
1008 CreateMockRead(resp2, 4), CreateMockRead(body2, 5),
1009 CreateMockRead(resp3, 7), CreateMockRead(body3, 8),
[email protected]2bd93022010-07-17 00:58:441010
bncdf80d44fd2016-07-15 20:27:411011 CreateMockRead(fbody, 9), CreateMockRead(fbody2, 10),
1012 CreateMockRead(fbody3, 11),
[email protected]2bd93022010-07-17 00:58:441013
rch08e3aa3e2015-05-16 14:27:521014 MockRead(ASYNC, 0, 12), // EOF
[email protected]2bd93022010-07-17 00:58:441015 };
Ryan Sleevib8d7ea02018-05-07 20:01:011016 SequencedSocketData data(reads, writes);
1017 SequencedSocketData data_placeholder1;
1018 SequencedSocketData data_placeholder2;
[email protected]2bd93022010-07-17 00:58:441019
[email protected]2bd93022010-07-17 00:58:441020 TransactionHelperResult out;
Bence Békydb3cf652017-10-10 15:22:101021 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]bdebd1b2010-08-09 20:18:081022 helper.RunPreTestSetup();
[email protected]dd54bd82012-07-19 23:44:571023 helper.AddData(&data);
rchaeb3f052015-04-14 16:02:491024 // We require placeholder data because three get requests are sent out at
1025 // the same time which results in three sockets being connected. The first
1026 // on will negotiate SPDY and will be used for all requests.
mmenkecc2298e2015-12-07 18:20:181027 helper.AddData(&data_placeholder1);
1028 helper.AddData(&data_placeholder2);
[email protected]49639fa2011-12-20 23:22:411029 TestCompletionCallback callback1;
1030 TestCompletionCallback callback2;
1031 TestCompletionCallback callback3;
[email protected]2bd93022010-07-17 00:58:441032
krasin0bfeb6b2017-01-13 21:48:041033 HttpNetworkTransaction trans1(DEFAULT_PRIORITY, helper.session());
1034 HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session());
1035 HttpNetworkTransaction trans3(DEFAULT_PRIORITY, helper.session());
1036
Bence Békydb3cf652017-10-10 15:22:101037 out.rv = trans1.Start(&request_, callback1.callback(), log_);
robpercival214763f2016-07-01 23:27:011038 ASSERT_THAT(out.rv, IsError(ERR_IO_PENDING));
Bence Békydb3cf652017-10-10 15:22:101039 out.rv = trans2.Start(&request_, callback2.callback(), log_);
robpercival214763f2016-07-01 23:27:011040 ASSERT_THAT(out.rv, IsError(ERR_IO_PENDING));
Bence Békydb3cf652017-10-10 15:22:101041 out.rv = trans3.Start(&request_, callback3.callback(), log_);
robpercival214763f2016-07-01 23:27:011042 ASSERT_THAT(out.rv, IsError(ERR_IO_PENDING));
[email protected]2bd93022010-07-17 00:58:441043
[email protected]bdebd1b2010-08-09 20:18:081044 out.rv = callback1.WaitForResult();
robpercival214763f2016-07-01 23:27:011045 ASSERT_THAT(out.rv, IsOk());
[email protected]bdebd1b2010-08-09 20:18:081046 out.rv = callback3.WaitForResult();
robpercival214763f2016-07-01 23:27:011047 ASSERT_THAT(out.rv, IsOk());
[email protected]2bd93022010-07-17 00:58:441048
bnc691fda62016-08-12 00:43:161049 const HttpResponseInfo* response1 = trans1.GetResponseInfo();
wezca1070932016-05-26 20:30:521050 EXPECT_TRUE(response1->headers);
[email protected]bdebd1b2010-08-09 20:18:081051 EXPECT_TRUE(response1->was_fetched_via_spdy);
1052 out.status_line = response1->headers->GetStatusLine();
1053 out.response_info = *response1;
[email protected]2bd93022010-07-17 00:58:441054
bnc691fda62016-08-12 00:43:161055 trans2.GetResponseInfo();
[email protected]2bd93022010-07-17 00:58:441056
bnc691fda62016-08-12 00:43:161057 out.rv = ReadTransaction(&trans1, &out.response_data);
[email protected]bdebd1b2010-08-09 20:18:081058 helper.VerifyDataConsumed();
robpercival214763f2016-07-01 23:27:011059 EXPECT_THAT(out.rv, IsOk());
[email protected]2bd93022010-07-17 00:58:441060
robpercival214763f2016-07-01 23:27:011061 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:021062 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]2bd93022010-07-17 00:58:441063 EXPECT_EQ("hello!hello!", out.response_data);
1064}
1065
bncd16676a2016-07-20 16:23:011066TEST_F(SpdyNetworkTransactionTest, TwoGetsLateBinding) {
Ryan Hamilton0239aac2018-05-19 00:03:131067 spdy::SpdySerializedFrame req(
1068 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
1069 spdy::SpdySerializedFrame resp(
1070 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
1071 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, false));
1072 spdy::SpdySerializedFrame fbody(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]1b323172011-03-01 17:50:171073
Ryan Hamilton0239aac2018-05-19 00:03:131074 spdy::SpdySerializedFrame req2(
1075 spdy_util_.ConstructSpdyGet(nullptr, 0, 3, LOWEST));
1076 spdy::SpdySerializedFrame resp2(
1077 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
1078 spdy::SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(3, false));
1079 spdy::SpdySerializedFrame fbody2(spdy_util_.ConstructSpdyDataFrame(3, true));
[email protected]1b323172011-03-01 17:50:171080
1081 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:411082 CreateMockWrite(req, 0), CreateMockWrite(req2, 3),
[email protected]1b323172011-03-01 17:50:171083 };
1084 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:411085 CreateMockRead(resp, 1), CreateMockRead(body, 2),
1086 CreateMockRead(resp2, 4), CreateMockRead(body2, 5),
1087 CreateMockRead(fbody, 6), CreateMockRead(fbody2, 7),
rch08e3aa3e2015-05-16 14:27:521088 MockRead(ASYNC, 0, 8), // EOF
[email protected]1b323172011-03-01 17:50:171089 };
Ryan Sleevib8d7ea02018-05-07 20:01:011090 SequencedSocketData data(reads, writes);
[email protected]1b323172011-03-01 17:50:171091
[email protected]d973e99a2012-02-17 21:02:361092 MockConnect never_finishing_connect(SYNCHRONOUS, ERR_IO_PENDING);
Ryan Sleevib8d7ea02018-05-07 20:01:011093 SequencedSocketData data_placeholder;
[email protected]dd54bd82012-07-19 23:44:571094 data_placeholder.set_connect_data(never_finishing_connect);
[email protected]1b323172011-03-01 17:50:171095
[email protected]1b323172011-03-01 17:50:171096 TransactionHelperResult out;
Bence Békydb3cf652017-10-10 15:22:101097 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]1b323172011-03-01 17:50:171098 helper.RunPreTestSetup();
[email protected]dd54bd82012-07-19 23:44:571099 helper.AddData(&data);
rchaeb3f052015-04-14 16:02:491100 // We require placeholder data because two requests are sent out at
1101 // the same time which results in two sockets being connected. The first
1102 // on will negotiate SPDY and will be used for all requests.
[email protected]dd54bd82012-07-19 23:44:571103 helper.AddData(&data_placeholder);
bnc691fda62016-08-12 00:43:161104 HttpNetworkTransaction trans1(DEFAULT_PRIORITY, helper.session());
1105 HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session());
[email protected]1b323172011-03-01 17:50:171106
[email protected]49639fa2011-12-20 23:22:411107 TestCompletionCallback callback1;
1108 TestCompletionCallback callback2;
[email protected]1b323172011-03-01 17:50:171109
Bence Békydb3cf652017-10-10 15:22:101110 out.rv = trans1.Start(&request_, callback1.callback(), log_);
robpercival214763f2016-07-01 23:27:011111 ASSERT_THAT(out.rv, IsError(ERR_IO_PENDING));
Bence Békydb3cf652017-10-10 15:22:101112 out.rv = trans2.Start(&request_, callback2.callback(), log_);
robpercival214763f2016-07-01 23:27:011113 ASSERT_THAT(out.rv, IsError(ERR_IO_PENDING));
[email protected]1b323172011-03-01 17:50:171114
1115 out.rv = callback1.WaitForResult();
robpercival214763f2016-07-01 23:27:011116 ASSERT_THAT(out.rv, IsOk());
[email protected]1b323172011-03-01 17:50:171117 out.rv = callback2.WaitForResult();
robpercival214763f2016-07-01 23:27:011118 ASSERT_THAT(out.rv, IsOk());
[email protected]1b323172011-03-01 17:50:171119
bnc691fda62016-08-12 00:43:161120 const HttpResponseInfo* response1 = trans1.GetResponseInfo();
wezca1070932016-05-26 20:30:521121 EXPECT_TRUE(response1->headers);
[email protected]1b323172011-03-01 17:50:171122 EXPECT_TRUE(response1->was_fetched_via_spdy);
1123 out.status_line = response1->headers->GetStatusLine();
1124 out.response_info = *response1;
bnc691fda62016-08-12 00:43:161125 out.rv = ReadTransaction(&trans1, &out.response_data);
robpercival214763f2016-07-01 23:27:011126 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:021127 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]1b323172011-03-01 17:50:171128 EXPECT_EQ("hello!hello!", out.response_data);
1129
bnc691fda62016-08-12 00:43:161130 const HttpResponseInfo* response2 = trans2.GetResponseInfo();
wezca1070932016-05-26 20:30:521131 EXPECT_TRUE(response2->headers);
[email protected]1b323172011-03-01 17:50:171132 EXPECT_TRUE(response2->was_fetched_via_spdy);
1133 out.status_line = response2->headers->GetStatusLine();
1134 out.response_info = *response2;
bnc691fda62016-08-12 00:43:161135 out.rv = ReadTransaction(&trans2, &out.response_data);
robpercival214763f2016-07-01 23:27:011136 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:021137 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]1b323172011-03-01 17:50:171138 EXPECT_EQ("hello!hello!", out.response_data);
1139
1140 helper.VerifyDataConsumed();
1141}
1142
bncd16676a2016-07-20 16:23:011143TEST_F(SpdyNetworkTransactionTest, TwoGetsLateBindingFromPreconnect) {
Ryan Hamilton0239aac2018-05-19 00:03:131144 spdy::SpdySerializedFrame req(
1145 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
1146 spdy::SpdySerializedFrame resp(
1147 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
1148 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, false));
1149 spdy::SpdySerializedFrame fbody(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]1b323172011-03-01 17:50:171150
Ryan Hamilton0239aac2018-05-19 00:03:131151 spdy::SpdySerializedFrame req2(
1152 spdy_util_.ConstructSpdyGet(nullptr, 0, 3, LOWEST));
1153 spdy::SpdySerializedFrame resp2(
1154 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
1155 spdy::SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(3, false));
1156 spdy::SpdySerializedFrame fbody2(spdy_util_.ConstructSpdyDataFrame(3, true));
[email protected]1b323172011-03-01 17:50:171157
1158 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:411159 CreateMockWrite(req, 0), CreateMockWrite(req2, 3),
[email protected]1b323172011-03-01 17:50:171160 };
1161 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:411162 CreateMockRead(resp, 1), CreateMockRead(body, 2),
1163 CreateMockRead(resp2, 4), CreateMockRead(body2, 5),
1164 CreateMockRead(fbody, 6), CreateMockRead(fbody2, 7),
rch08e3aa3e2015-05-16 14:27:521165 MockRead(ASYNC, 0, 8), // EOF
[email protected]1b323172011-03-01 17:50:171166 };
Ryan Sleevib8d7ea02018-05-07 20:01:011167 SequencedSocketData preconnect_data(reads, writes);
[email protected]1b323172011-03-01 17:50:171168
[email protected]d973e99a2012-02-17 21:02:361169 MockConnect never_finishing_connect(ASYNC, ERR_IO_PENDING);
[email protected]1b323172011-03-01 17:50:171170
Ryan Sleevib8d7ea02018-05-07 20:01:011171 SequencedSocketData data_placeholder;
[email protected]dd54bd82012-07-19 23:44:571172 data_placeholder.set_connect_data(never_finishing_connect);
[email protected]1b323172011-03-01 17:50:171173
[email protected]1b323172011-03-01 17:50:171174 TransactionHelperResult out;
Bence Békydb3cf652017-10-10 15:22:101175 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]1b323172011-03-01 17:50:171176 helper.RunPreTestSetup();
[email protected]dd54bd82012-07-19 23:44:571177 helper.AddData(&preconnect_data);
[email protected]1b323172011-03-01 17:50:171178 // We require placeholder data because 3 connections are attempted (first is
1179 // the preconnect, 2nd and 3rd are the never finished connections.
[email protected]dd54bd82012-07-19 23:44:571180 helper.AddData(&data_placeholder);
1181 helper.AddData(&data_placeholder);
[email protected]1b323172011-03-01 17:50:171182
bnc691fda62016-08-12 00:43:161183 HttpNetworkTransaction trans1(DEFAULT_PRIORITY, helper.session());
1184 HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session());
[email protected]1b323172011-03-01 17:50:171185
[email protected]49639fa2011-12-20 23:22:411186 TestCompletionCallback callback1;
1187 TestCompletionCallback callback2;
[email protected]1b323172011-03-01 17:50:171188
[email protected]1b323172011-03-01 17:50:171189 // Preconnect the first.
[email protected]1b323172011-03-01 17:50:171190 HttpStreamFactory* http_stream_factory =
1191 helper.session()->http_stream_factory();
[email protected]1b323172011-03-01 17:50:171192
Bence Békydb3cf652017-10-10 15:22:101193 http_stream_factory->PreconnectStreams(1, request_);
[email protected]1b323172011-03-01 17:50:171194
Bence Békydb3cf652017-10-10 15:22:101195 out.rv = trans1.Start(&request_, callback1.callback(), log_);
robpercival214763f2016-07-01 23:27:011196 ASSERT_THAT(out.rv, IsError(ERR_IO_PENDING));
Bence Békydb3cf652017-10-10 15:22:101197 out.rv = trans2.Start(&request_, callback2.callback(), log_);
robpercival214763f2016-07-01 23:27:011198 ASSERT_THAT(out.rv, IsError(ERR_IO_PENDING));
[email protected]1b323172011-03-01 17:50:171199
1200 out.rv = callback1.WaitForResult();
robpercival214763f2016-07-01 23:27:011201 ASSERT_THAT(out.rv, IsOk());
[email protected]1b323172011-03-01 17:50:171202 out.rv = callback2.WaitForResult();
robpercival214763f2016-07-01 23:27:011203 ASSERT_THAT(out.rv, IsOk());
[email protected]1b323172011-03-01 17:50:171204
bnc691fda62016-08-12 00:43:161205 const HttpResponseInfo* response1 = trans1.GetResponseInfo();
wezca1070932016-05-26 20:30:521206 EXPECT_TRUE(response1->headers);
[email protected]1b323172011-03-01 17:50:171207 EXPECT_TRUE(response1->was_fetched_via_spdy);
1208 out.status_line = response1->headers->GetStatusLine();
1209 out.response_info = *response1;
bnc691fda62016-08-12 00:43:161210 out.rv = ReadTransaction(&trans1, &out.response_data);
robpercival214763f2016-07-01 23:27:011211 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:021212 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]1b323172011-03-01 17:50:171213 EXPECT_EQ("hello!hello!", out.response_data);
1214
bnc691fda62016-08-12 00:43:161215 const HttpResponseInfo* response2 = trans2.GetResponseInfo();
wezca1070932016-05-26 20:30:521216 EXPECT_TRUE(response2->headers);
[email protected]1b323172011-03-01 17:50:171217 EXPECT_TRUE(response2->was_fetched_via_spdy);
1218 out.status_line = response2->headers->GetStatusLine();
1219 out.response_info = *response2;
bnc691fda62016-08-12 00:43:161220 out.rv = ReadTransaction(&trans2, &out.response_data);
robpercival214763f2016-07-01 23:27:011221 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:021222 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]1b323172011-03-01 17:50:171223 EXPECT_EQ("hello!hello!", out.response_data);
1224
1225 helper.VerifyDataConsumed();
1226}
1227
[email protected]2bd93022010-07-17 00:58:441228// Similar to ThreeGets above, however this test adds a SETTINGS
1229// frame. The SETTINGS frame is read during the IO loop waiting on
1230// the first transaction completion, and sets a maximum concurrent
1231// stream limit of 1. This means that our IO loop exists after the
1232// second transaction completes, so we can assert on read_index().
bncd16676a2016-07-20 16:23:011233TEST_F(SpdyNetworkTransactionTest, ThreeGetsWithMaxConcurrent) {
[email protected]2bd93022010-07-17 00:58:441234 // Construct the request.
rdsmithebb50aa2015-11-12 03:44:381235 // Each request fully completes before the next starts.
Ryan Hamilton0239aac2018-05-19 00:03:131236 spdy::SpdySerializedFrame req(
1237 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
1238 spdy::SpdySerializedFrame resp(
1239 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
1240 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, false));
1241 spdy::SpdySerializedFrame fbody(spdy_util_.ConstructSpdyDataFrame(1, true));
rdsmithebb50aa2015-11-12 03:44:381242 spdy_util_.UpdateWithStreamDestruction(1);
[email protected]2bd93022010-07-17 00:58:441243
Ryan Hamilton0239aac2018-05-19 00:03:131244 spdy::SpdySerializedFrame req2(
1245 spdy_util_.ConstructSpdyGet(nullptr, 0, 3, LOWEST));
1246 spdy::SpdySerializedFrame resp2(
1247 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
1248 spdy::SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(3, false));
1249 spdy::SpdySerializedFrame fbody2(spdy_util_.ConstructSpdyDataFrame(3, true));
rdsmithebb50aa2015-11-12 03:44:381250 spdy_util_.UpdateWithStreamDestruction(3);
[email protected]2bd93022010-07-17 00:58:441251
Ryan Hamilton0239aac2018-05-19 00:03:131252 spdy::SpdySerializedFrame req3(
1253 spdy_util_.ConstructSpdyGet(nullptr, 0, 5, LOWEST));
1254 spdy::SpdySerializedFrame resp3(
1255 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 5));
1256 spdy::SpdySerializedFrame body3(spdy_util_.ConstructSpdyDataFrame(5, false));
1257 spdy::SpdySerializedFrame fbody3(spdy_util_.ConstructSpdyDataFrame(5, true));
[email protected]2bd93022010-07-17 00:58:441258
Ryan Hamilton0239aac2018-05-19 00:03:131259 spdy::SettingsMap settings;
Avi Drissman13fc8932015-12-20 04:40:461260 const uint32_t max_concurrent_streams = 1;
Ryan Hamilton0239aac2018-05-19 00:03:131261 settings[spdy::SETTINGS_MAX_CONCURRENT_STREAMS] = max_concurrent_streams;
1262 spdy::SpdySerializedFrame settings_frame(
[email protected]c10b20852013-05-15 21:29:201263 spdy_util_.ConstructSpdySettings(settings));
Ryan Hamilton0239aac2018-05-19 00:03:131264 spdy::SpdySerializedFrame settings_ack(spdy_util_.ConstructSpdySettingsAck());
[email protected]2bd93022010-07-17 00:58:441265
[email protected]2d6728692011-03-12 01:39:551266 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:411267 CreateMockWrite(req, 0), CreateMockWrite(settings_ack, 5),
1268 CreateMockWrite(req2, 6), CreateMockWrite(req3, 10),
[email protected]2bd93022010-07-17 00:58:441269 };
[email protected]2d6728692011-03-12 01:39:551270
[email protected]2bd93022010-07-17 00:58:441271 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:411272 CreateMockRead(settings_frame, 1),
1273 CreateMockRead(resp, 2),
1274 CreateMockRead(body, 3),
1275 CreateMockRead(fbody, 4),
1276 CreateMockRead(resp2, 7),
1277 CreateMockRead(body2, 8),
1278 CreateMockRead(fbody2, 9),
1279 CreateMockRead(resp3, 11),
1280 CreateMockRead(body3, 12),
1281 CreateMockRead(fbody3, 13),
[email protected]2bd93022010-07-17 00:58:441282
rch08e3aa3e2015-05-16 14:27:521283 MockRead(ASYNC, 0, 14), // EOF
[email protected]2bd93022010-07-17 00:58:441284 };
1285
Ryan Sleevib8d7ea02018-05-07 20:01:011286 SequencedSocketData data(reads, writes);
[email protected]2bd93022010-07-17 00:58:441287
[email protected]2bd93022010-07-17 00:58:441288 TransactionHelperResult out;
1289 {
Bence Békydb3cf652017-10-10 15:22:101290 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
1291 nullptr);
[email protected]2d6728692011-03-12 01:39:551292 helper.RunPreTestSetup();
[email protected]dd54bd82012-07-19 23:44:571293 helper.AddData(&data);
bnc691fda62016-08-12 00:43:161294 HttpNetworkTransaction trans1(DEFAULT_PRIORITY, helper.session());
1295 HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session());
1296 HttpNetworkTransaction trans3(DEFAULT_PRIORITY, helper.session());
[email protected]2bd93022010-07-17 00:58:441297
[email protected]49639fa2011-12-20 23:22:411298 TestCompletionCallback callback1;
1299 TestCompletionCallback callback2;
1300 TestCompletionCallback callback3;
[email protected]2bd93022010-07-17 00:58:441301
Bence Békydb3cf652017-10-10 15:22:101302 out.rv = trans1.Start(&request_, callback1.callback(), log_);
[email protected]2bd93022010-07-17 00:58:441303 ASSERT_EQ(out.rv, ERR_IO_PENDING);
[email protected]513963e2013-06-15 01:53:041304 // Run transaction 1 through quickly to force a read of our SETTINGS
1305 // frame.
[email protected]2bd93022010-07-17 00:58:441306 out.rv = callback1.WaitForResult();
robpercival214763f2016-07-01 23:27:011307 ASSERT_THAT(out.rv, IsOk());
[email protected]2bd93022010-07-17 00:58:441308
Bence Békydb3cf652017-10-10 15:22:101309 out.rv = trans2.Start(&request_, callback2.callback(), log_);
[email protected]2bd93022010-07-17 00:58:441310 ASSERT_EQ(out.rv, ERR_IO_PENDING);
Bence Békydb3cf652017-10-10 15:22:101311 out.rv = trans3.Start(&request_, callback3.callback(), log_);
[email protected]2bd93022010-07-17 00:58:441312 ASSERT_EQ(out.rv, ERR_IO_PENDING);
1313 out.rv = callback2.WaitForResult();
robpercival214763f2016-07-01 23:27:011314 ASSERT_THAT(out.rv, IsOk());
[email protected]2bd93022010-07-17 00:58:441315
1316 out.rv = callback3.WaitForResult();
robpercival214763f2016-07-01 23:27:011317 ASSERT_THAT(out.rv, IsOk());
[email protected]2bd93022010-07-17 00:58:441318
bnc691fda62016-08-12 00:43:161319 const HttpResponseInfo* response1 = trans1.GetResponseInfo();
wezca1070932016-05-26 20:30:521320 ASSERT_TRUE(response1);
1321 EXPECT_TRUE(response1->headers);
[email protected]2bd93022010-07-17 00:58:441322 EXPECT_TRUE(response1->was_fetched_via_spdy);
1323 out.status_line = response1->headers->GetStatusLine();
1324 out.response_info = *response1;
bnc691fda62016-08-12 00:43:161325 out.rv = ReadTransaction(&trans1, &out.response_data);
robpercival214763f2016-07-01 23:27:011326 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:021327 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]2bd93022010-07-17 00:58:441328 EXPECT_EQ("hello!hello!", out.response_data);
1329
bnc691fda62016-08-12 00:43:161330 const HttpResponseInfo* response2 = trans2.GetResponseInfo();
[email protected]2bd93022010-07-17 00:58:441331 out.status_line = response2->headers->GetStatusLine();
1332 out.response_info = *response2;
bnc691fda62016-08-12 00:43:161333 out.rv = ReadTransaction(&trans2, &out.response_data);
robpercival214763f2016-07-01 23:27:011334 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:021335 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]2bd93022010-07-17 00:58:441336 EXPECT_EQ("hello!hello!", out.response_data);
1337
bnc691fda62016-08-12 00:43:161338 const HttpResponseInfo* response3 = trans3.GetResponseInfo();
[email protected]2bd93022010-07-17 00:58:441339 out.status_line = response3->headers->GetStatusLine();
1340 out.response_info = *response3;
bnc691fda62016-08-12 00:43:161341 out.rv = ReadTransaction(&trans3, &out.response_data);
robpercival214763f2016-07-01 23:27:011342 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:021343 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]2bd93022010-07-17 00:58:441344 EXPECT_EQ("hello!hello!", out.response_data);
[email protected]044dcc52010-09-17 15:44:261345
1346 helper.VerifyDataConsumed();
[email protected]2bd93022010-07-17 00:58:441347 }
robpercival214763f2016-07-01 23:27:011348 EXPECT_THAT(out.rv, IsOk());
[email protected]2bd93022010-07-17 00:58:441349}
1350
1351// Similar to ThreeGetsWithMaxConcurrent above, however this test adds
1352// a fourth transaction. The third and fourth transactions have
1353// different data ("hello!" vs "hello!hello!") and because of the
1354// user specified priority, we expect to see them inverted in
1355// the response from the server.
bncd16676a2016-07-20 16:23:011356TEST_F(SpdyNetworkTransactionTest, FourGetsWithMaxConcurrentPriority) {
[email protected]2bd93022010-07-17 00:58:441357 // Construct the request.
Ryan Hamilton0239aac2018-05-19 00:03:131358 spdy::SpdySerializedFrame req(
1359 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
1360 spdy::SpdySerializedFrame resp(
1361 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
1362 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, false));
1363 spdy::SpdySerializedFrame fbody(spdy_util_.ConstructSpdyDataFrame(1, true));
rdsmithebb50aa2015-11-12 03:44:381364 spdy_util_.UpdateWithStreamDestruction(1);
[email protected]2bd93022010-07-17 00:58:441365
Ryan Hamilton0239aac2018-05-19 00:03:131366 spdy::SpdySerializedFrame req2(
1367 spdy_util_.ConstructSpdyGet(nullptr, 0, 3, LOWEST));
1368 spdy::SpdySerializedFrame resp2(
1369 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
1370 spdy::SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(3, false));
1371 spdy::SpdySerializedFrame fbody2(spdy_util_.ConstructSpdyDataFrame(3, true));
rdsmithebb50aa2015-11-12 03:44:381372 spdy_util_.UpdateWithStreamDestruction(3);
[email protected]2bd93022010-07-17 00:58:441373
Ryan Hamilton0239aac2018-05-19 00:03:131374 spdy::SpdySerializedFrame req4(
1375 spdy_util_.ConstructSpdyGet(nullptr, 0, 5, HIGHEST));
1376 spdy::SpdySerializedFrame resp4(
1377 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 5));
1378 spdy::SpdySerializedFrame fbody4(spdy_util_.ConstructSpdyDataFrame(5, true));
rdsmithebb50aa2015-11-12 03:44:381379 spdy_util_.UpdateWithStreamDestruction(5);
[email protected]2bd93022010-07-17 00:58:441380
Ryan Hamilton0239aac2018-05-19 00:03:131381 spdy::SpdySerializedFrame req3(
1382 spdy_util_.ConstructSpdyGet(nullptr, 0, 7, LOWEST));
1383 spdy::SpdySerializedFrame resp3(
1384 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 7));
1385 spdy::SpdySerializedFrame body3(spdy_util_.ConstructSpdyDataFrame(7, false));
1386 spdy::SpdySerializedFrame fbody3(spdy_util_.ConstructSpdyDataFrame(7, true));
[email protected]2bd93022010-07-17 00:58:441387
Ryan Hamilton0239aac2018-05-19 00:03:131388 spdy::SettingsMap settings;
Avi Drissman13fc8932015-12-20 04:40:461389 const uint32_t max_concurrent_streams = 1;
Ryan Hamilton0239aac2018-05-19 00:03:131390 settings[spdy::SETTINGS_MAX_CONCURRENT_STREAMS] = max_concurrent_streams;
1391 spdy::SpdySerializedFrame settings_frame(
[email protected]c10b20852013-05-15 21:29:201392 spdy_util_.ConstructSpdySettings(settings));
Ryan Hamilton0239aac2018-05-19 00:03:131393 spdy::SpdySerializedFrame settings_ack(spdy_util_.ConstructSpdySettingsAck());
rch08e3aa3e2015-05-16 14:27:521394 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:411395 CreateMockWrite(req, 0), CreateMockWrite(settings_ack, 5),
rch08e3aa3e2015-05-16 14:27:521396 // By making these synchronous, it guarantees that they are not *started*
1397 // before their sequence number, which in turn verifies that only a single
1398 // request is in-flight at a time.
bncdf80d44fd2016-07-15 20:27:411399 CreateMockWrite(req2, 6, SYNCHRONOUS),
1400 CreateMockWrite(req4, 10, SYNCHRONOUS),
1401 CreateMockWrite(req3, 13, SYNCHRONOUS),
[email protected]2bd93022010-07-17 00:58:441402 };
1403 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:411404 CreateMockRead(settings_frame, 1),
1405 CreateMockRead(resp, 2),
1406 CreateMockRead(body, 3),
1407 CreateMockRead(fbody, 4),
1408 CreateMockRead(resp2, 7),
1409 CreateMockRead(body2, 8),
1410 CreateMockRead(fbody2, 9),
1411 CreateMockRead(resp4, 11),
1412 CreateMockRead(fbody4, 12),
1413 CreateMockRead(resp3, 14),
1414 CreateMockRead(body3, 15),
1415 CreateMockRead(fbody3, 16),
[email protected]2bd93022010-07-17 00:58:441416
rch08e3aa3e2015-05-16 14:27:521417 MockRead(ASYNC, 0, 17), // EOF
[email protected]2bd93022010-07-17 00:58:441418 };
Ryan Sleevib8d7ea02018-05-07 20:01:011419 SequencedSocketData data(reads, writes);
[email protected]2bd93022010-07-17 00:58:441420 TransactionHelperResult out;
Bence Békydb3cf652017-10-10 15:22:101421 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]bdebd1b2010-08-09 20:18:081422 helper.RunPreTestSetup();
[email protected]dd54bd82012-07-19 23:44:571423 helper.AddData(&data);
rch08e3aa3e2015-05-16 14:27:521424
bnc691fda62016-08-12 00:43:161425 HttpNetworkTransaction trans1(DEFAULT_PRIORITY, helper.session());
1426 HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session());
1427 HttpNetworkTransaction trans3(DEFAULT_PRIORITY, helper.session());
1428 HttpNetworkTransaction trans4(HIGHEST, helper.session());
[email protected]2bd93022010-07-17 00:58:441429
[email protected]49639fa2011-12-20 23:22:411430 TestCompletionCallback callback1;
1431 TestCompletionCallback callback2;
1432 TestCompletionCallback callback3;
1433 TestCompletionCallback callback4;
[email protected]2bd93022010-07-17 00:58:441434
Bence Békydb3cf652017-10-10 15:22:101435 out.rv = trans1.Start(&request_, callback1.callback(), log_);
robpercival214763f2016-07-01 23:27:011436 ASSERT_THAT(out.rv, IsError(ERR_IO_PENDING));
[email protected]e0935cc2012-03-24 14:12:481437 // Run transaction 1 through quickly to force a read of our SETTINGS frame.
[email protected]bdebd1b2010-08-09 20:18:081438 out.rv = callback1.WaitForResult();
robpercival214763f2016-07-01 23:27:011439 ASSERT_THAT(out.rv, IsOk());
[email protected]2bd93022010-07-17 00:58:441440
bnceb9aa7112017-01-05 01:03:461441 // Finish async network reads and writes associated with |trans1|.
1442 base::RunLoop().RunUntilIdle();
1443
Bence Békydb3cf652017-10-10 15:22:101444 out.rv = trans2.Start(&request_, callback2.callback(), log_);
robpercival214763f2016-07-01 23:27:011445 ASSERT_THAT(out.rv, IsError(ERR_IO_PENDING));
Bence Békydb3cf652017-10-10 15:22:101446 out.rv = trans3.Start(&request_, callback3.callback(), log_);
robpercival214763f2016-07-01 23:27:011447 ASSERT_THAT(out.rv, IsError(ERR_IO_PENDING));
Bence Békydb3cf652017-10-10 15:22:101448 out.rv = trans4.Start(&request_, callback4.callback(), log_);
robpercival214763f2016-07-01 23:27:011449 ASSERT_THAT(out.rv, IsError(ERR_IO_PENDING));
[email protected]2bd93022010-07-17 00:58:441450
[email protected]bdebd1b2010-08-09 20:18:081451 out.rv = callback2.WaitForResult();
robpercival214763f2016-07-01 23:27:011452 ASSERT_THAT(out.rv, IsOk());
[email protected]2bd93022010-07-17 00:58:441453
[email protected]bdebd1b2010-08-09 20:18:081454 out.rv = callback3.WaitForResult();
robpercival214763f2016-07-01 23:27:011455 ASSERT_THAT(out.rv, IsOk());
[email protected]2bd93022010-07-17 00:58:441456
bnc691fda62016-08-12 00:43:161457 const HttpResponseInfo* response1 = trans1.GetResponseInfo();
wezca1070932016-05-26 20:30:521458 EXPECT_TRUE(response1->headers);
[email protected]bdebd1b2010-08-09 20:18:081459 EXPECT_TRUE(response1->was_fetched_via_spdy);
1460 out.status_line = response1->headers->GetStatusLine();
1461 out.response_info = *response1;
bnc691fda62016-08-12 00:43:161462 out.rv = ReadTransaction(&trans1, &out.response_data);
robpercival214763f2016-07-01 23:27:011463 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:021464 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]bdebd1b2010-08-09 20:18:081465 EXPECT_EQ("hello!hello!", out.response_data);
[email protected]2bd93022010-07-17 00:58:441466
bnc691fda62016-08-12 00:43:161467 const HttpResponseInfo* response2 = trans2.GetResponseInfo();
[email protected]bdebd1b2010-08-09 20:18:081468 out.status_line = response2->headers->GetStatusLine();
1469 out.response_info = *response2;
bnc691fda62016-08-12 00:43:161470 out.rv = ReadTransaction(&trans2, &out.response_data);
robpercival214763f2016-07-01 23:27:011471 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:021472 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]bdebd1b2010-08-09 20:18:081473 EXPECT_EQ("hello!hello!", out.response_data);
[email protected]2bd93022010-07-17 00:58:441474
[email protected]bdebd1b2010-08-09 20:18:081475 // notice: response3 gets two hellos, response4 gets one
1476 // hello, so we know dequeuing priority was respected.
bnc691fda62016-08-12 00:43:161477 const HttpResponseInfo* response3 = trans3.GetResponseInfo();
[email protected]bdebd1b2010-08-09 20:18:081478 out.status_line = response3->headers->GetStatusLine();
1479 out.response_info = *response3;
bnc691fda62016-08-12 00:43:161480 out.rv = ReadTransaction(&trans3, &out.response_data);
robpercival214763f2016-07-01 23:27:011481 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:021482 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]bdebd1b2010-08-09 20:18:081483 EXPECT_EQ("hello!hello!", out.response_data);
[email protected]2bd93022010-07-17 00:58:441484
[email protected]bdebd1b2010-08-09 20:18:081485 out.rv = callback4.WaitForResult();
robpercival214763f2016-07-01 23:27:011486 EXPECT_THAT(out.rv, IsOk());
bnc691fda62016-08-12 00:43:161487 const HttpResponseInfo* response4 = trans4.GetResponseInfo();
[email protected]bdebd1b2010-08-09 20:18:081488 out.status_line = response4->headers->GetStatusLine();
1489 out.response_info = *response4;
bnc691fda62016-08-12 00:43:161490 out.rv = ReadTransaction(&trans4, &out.response_data);
robpercival214763f2016-07-01 23:27:011491 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:021492 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]bdebd1b2010-08-09 20:18:081493 EXPECT_EQ("hello!", out.response_data);
1494 helper.VerifyDataConsumed();
robpercival214763f2016-07-01 23:27:011495 EXPECT_THAT(out.rv, IsOk());
[email protected]2bd93022010-07-17 00:58:441496}
1497
1498// Similar to ThreeGetsMaxConcurrrent above, however, this test
rch08e3aa3e2015-05-16 14:27:521499// deletes a session in the middle of the transaction to ensure
[email protected]2bd93022010-07-17 00:58:441500// that we properly remove pendingcreatestream objects from
1501// the spdy_session
bncd16676a2016-07-20 16:23:011502TEST_F(SpdyNetworkTransactionTest, ThreeGetsWithMaxConcurrentDelete) {
[email protected]2bd93022010-07-17 00:58:441503 // Construct the request.
Ryan Hamilton0239aac2018-05-19 00:03:131504 spdy::SpdySerializedFrame req(
1505 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
1506 spdy::SpdySerializedFrame resp(
1507 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
1508 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, false));
1509 spdy::SpdySerializedFrame fbody(spdy_util_.ConstructSpdyDataFrame(1, true));
rdsmithebb50aa2015-11-12 03:44:381510 spdy_util_.UpdateWithStreamDestruction(1);
[email protected]2bd93022010-07-17 00:58:441511
Ryan Hamilton0239aac2018-05-19 00:03:131512 spdy::SpdySerializedFrame req2(
1513 spdy_util_.ConstructSpdyGet(nullptr, 0, 3, LOWEST));
1514 spdy::SpdySerializedFrame resp2(
1515 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
1516 spdy::SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(3, false));
1517 spdy::SpdySerializedFrame fbody2(spdy_util_.ConstructSpdyDataFrame(3, true));
[email protected]2bd93022010-07-17 00:58:441518
Ryan Hamilton0239aac2018-05-19 00:03:131519 spdy::SettingsMap settings;
Avi Drissman13fc8932015-12-20 04:40:461520 const uint32_t max_concurrent_streams = 1;
Ryan Hamilton0239aac2018-05-19 00:03:131521 settings[spdy::SETTINGS_MAX_CONCURRENT_STREAMS] = max_concurrent_streams;
1522 spdy::SpdySerializedFrame settings_frame(
[email protected]c10b20852013-05-15 21:29:201523 spdy_util_.ConstructSpdySettings(settings));
Ryan Hamilton0239aac2018-05-19 00:03:131524 spdy::SpdySerializedFrame settings_ack(spdy_util_.ConstructSpdySettingsAck());
[email protected]2bd93022010-07-17 00:58:441525
[email protected]d4a77c12014-05-15 20:45:211526 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:411527 CreateMockWrite(req, 0), CreateMockWrite(settings_ack, 5),
1528 CreateMockWrite(req2, 6),
[email protected]2bd93022010-07-17 00:58:441529 };
1530 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:411531 CreateMockRead(settings_frame, 1), CreateMockRead(resp, 2),
1532 CreateMockRead(body, 3), CreateMockRead(fbody, 4),
1533 CreateMockRead(resp2, 7), CreateMockRead(body2, 8),
1534 CreateMockRead(fbody2, 9), MockRead(ASYNC, 0, 10), // EOF
[email protected]2bd93022010-07-17 00:58:441535 };
1536
Ryan Sleevib8d7ea02018-05-07 20:01:011537 SequencedSocketData data(reads, writes);
[email protected]2bd93022010-07-17 00:58:441538
[email protected]2bd93022010-07-17 00:58:441539 TransactionHelperResult out;
Bence Békydb3cf652017-10-10 15:22:101540 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]bdebd1b2010-08-09 20:18:081541 helper.RunPreTestSetup();
[email protected]dd54bd82012-07-19 23:44:571542 helper.AddData(&data);
Jeremy Roman0579ed62017-08-29 15:56:191543 auto trans1 = std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY,
bnc3f6a8552017-05-17 13:40:341544 helper.session());
Jeremy Roman0579ed62017-08-29 15:56:191545 auto trans2 = std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY,
bnc3f6a8552017-05-17 13:40:341546 helper.session());
Jeremy Roman0579ed62017-08-29 15:56:191547 auto trans3 = std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY,
bnc3f6a8552017-05-17 13:40:341548 helper.session());
[email protected]2bd93022010-07-17 00:58:441549
[email protected]49639fa2011-12-20 23:22:411550 TestCompletionCallback callback1;
1551 TestCompletionCallback callback2;
1552 TestCompletionCallback callback3;
[email protected]2bd93022010-07-17 00:58:441553
Bence Békydb3cf652017-10-10 15:22:101554 out.rv = trans1->Start(&request_, callback1.callback(), log_);
[email protected]bdebd1b2010-08-09 20:18:081555 ASSERT_EQ(out.rv, ERR_IO_PENDING);
[email protected]e0935cc2012-03-24 14:12:481556 // Run transaction 1 through quickly to force a read of our SETTINGS frame.
[email protected]bdebd1b2010-08-09 20:18:081557 out.rv = callback1.WaitForResult();
robpercival214763f2016-07-01 23:27:011558 ASSERT_THAT(out.rv, IsOk());
[email protected]2bd93022010-07-17 00:58:441559
Bence Békydb3cf652017-10-10 15:22:101560 out.rv = trans2->Start(&request_, callback2.callback(), log_);
[email protected]bdebd1b2010-08-09 20:18:081561 ASSERT_EQ(out.rv, ERR_IO_PENDING);
Bence Békydb3cf652017-10-10 15:22:101562 out.rv = trans3->Start(&request_, callback3.callback(), log_);
olli.raula7ca9cd1d2016-01-04 06:50:371563 trans3.reset();
[email protected]bdebd1b2010-08-09 20:18:081564 ASSERT_EQ(out.rv, ERR_IO_PENDING);
1565 out.rv = callback2.WaitForResult();
robpercival214763f2016-07-01 23:27:011566 ASSERT_THAT(out.rv, IsOk());
[email protected]2bd93022010-07-17 00:58:441567
[email protected]bdebd1b2010-08-09 20:18:081568 const HttpResponseInfo* response1 = trans1->GetResponseInfo();
wezca1070932016-05-26 20:30:521569 ASSERT_TRUE(response1);
1570 EXPECT_TRUE(response1->headers);
[email protected]bdebd1b2010-08-09 20:18:081571 EXPECT_TRUE(response1->was_fetched_via_spdy);
1572 out.status_line = response1->headers->GetStatusLine();
1573 out.response_info = *response1;
1574 out.rv = ReadTransaction(trans1.get(), &out.response_data);
robpercival214763f2016-07-01 23:27:011575 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:021576 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]bdebd1b2010-08-09 20:18:081577 EXPECT_EQ("hello!hello!", out.response_data);
[email protected]2bd93022010-07-17 00:58:441578
[email protected]bdebd1b2010-08-09 20:18:081579 const HttpResponseInfo* response2 = trans2->GetResponseInfo();
wezca1070932016-05-26 20:30:521580 ASSERT_TRUE(response2);
[email protected]bdebd1b2010-08-09 20:18:081581 out.status_line = response2->headers->GetStatusLine();
1582 out.response_info = *response2;
1583 out.rv = ReadTransaction(trans2.get(), &out.response_data);
robpercival214763f2016-07-01 23:27:011584 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:021585 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]bdebd1b2010-08-09 20:18:081586 EXPECT_EQ("hello!hello!", out.response_data);
1587 helper.VerifyDataConsumed();
robpercival214763f2016-07-01 23:27:011588 EXPECT_THAT(out.rv, IsOk());
[email protected]044dcc52010-09-17 15:44:261589}
[email protected]2bd93022010-07-17 00:58:441590
[email protected]448d4ca52012-03-04 04:12:231591namespace {
1592
Bence Béky8ddc2492018-06-13 01:02:041593// A helper class that will delete |transaction| on error when the callback is
1594// invoked.
[email protected]49639fa2011-12-20 23:22:411595class KillerCallback : public TestCompletionCallbackBase {
[email protected]044dcc52010-09-17 15:44:261596 public:
1597 explicit KillerCallback(HttpNetworkTransaction* transaction)
Bence Béky8ddc2492018-06-13 01:02:041598 : transaction_(transaction) {}
[email protected]044dcc52010-09-17 15:44:261599
Chris Watkins61914cb2017-12-01 19:59:001600 ~KillerCallback() override = default;
[email protected]49639fa2011-12-20 23:22:411601
Bence Béky8ddc2492018-06-13 01:02:041602 CompletionOnceCallback callback() {
1603 return base::BindOnce(&KillerCallback::OnComplete, base::Unretained(this));
1604 }
[email protected]49639fa2011-12-20 23:22:411605
[email protected]044dcc52010-09-17 15:44:261606 private:
[email protected]49639fa2011-12-20 23:22:411607 void OnComplete(int result) {
1608 if (result < 0)
1609 delete transaction_;
1610
1611 SetResult(result);
1612 }
1613
[email protected]044dcc52010-09-17 15:44:261614 HttpNetworkTransaction* transaction_;
1615};
1616
[email protected]448d4ca52012-03-04 04:12:231617} // namespace
1618
[email protected]044dcc52010-09-17 15:44:261619// Similar to ThreeGetsMaxConcurrrentDelete above, however, this test
1620// closes the socket while we have a pending transaction waiting for
1621// a pending stream creation. http://crbug.com/52901
bncd16676a2016-07-20 16:23:011622TEST_F(SpdyNetworkTransactionTest, ThreeGetsWithMaxConcurrentSocketClose) {
Matt Menke66e502a72019-04-15 13:34:381623 // Construct the request. Each stream uses a different priority to provide
1624 // more useful failure information if the requests are made in an unexpected
1625 // order.
Ryan Hamilton0239aac2018-05-19 00:03:131626 spdy::SpdySerializedFrame req(
Matt Menke66e502a72019-04-15 13:34:381627 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, HIGHEST));
Ryan Hamilton0239aac2018-05-19 00:03:131628 spdy::SpdySerializedFrame resp(
1629 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
1630 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, false));
1631 spdy::SpdySerializedFrame fin_body(
1632 spdy_util_.ConstructSpdyDataFrame(1, true));
rdsmithebb50aa2015-11-12 03:44:381633 spdy_util_.UpdateWithStreamDestruction(1);
[email protected]044dcc52010-09-17 15:44:261634
Ryan Hamilton0239aac2018-05-19 00:03:131635 spdy::SpdySerializedFrame req2(
Matt Menke66e502a72019-04-15 13:34:381636 spdy_util_.ConstructSpdyGet(nullptr, 0, 3, MEDIUM));
Ryan Hamilton0239aac2018-05-19 00:03:131637 spdy::SpdySerializedFrame resp2(
1638 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
[email protected]044dcc52010-09-17 15:44:261639
Ryan Hamilton0239aac2018-05-19 00:03:131640 spdy::SettingsMap settings;
Avi Drissman13fc8932015-12-20 04:40:461641 const uint32_t max_concurrent_streams = 1;
Ryan Hamilton0239aac2018-05-19 00:03:131642 settings[spdy::SETTINGS_MAX_CONCURRENT_STREAMS] = max_concurrent_streams;
1643 spdy::SpdySerializedFrame settings_frame(
[email protected]c10b20852013-05-15 21:29:201644 spdy_util_.ConstructSpdySettings(settings));
Ryan Hamilton0239aac2018-05-19 00:03:131645 spdy::SpdySerializedFrame settings_ack(spdy_util_.ConstructSpdySettingsAck());
[email protected]044dcc52010-09-17 15:44:261646
Matt Menke66e502a72019-04-15 13:34:381647 MockWrite writes[] = {CreateMockWrite(req, 0),
1648 CreateMockWrite(settings_ack, 6),
1649 CreateMockWrite(req2, 7)};
[email protected]044dcc52010-09-17 15:44:261650 MockRead reads[] = {
Matt Menke66e502a72019-04-15 13:34:381651 CreateMockRead(settings_frame, 1), CreateMockRead(resp, 2),
bncdf80d44fd2016-07-15 20:27:411652 CreateMockRead(body, 3),
Matt Menke66e502a72019-04-15 13:34:381653 // Delay the request here. For this test to pass, the three HTTP streams
1654 // have to be created in order, but SpdySession doesn't actually guarantee
1655 // that (See note in SpdySession::ProcessPendingStreamRequests). As a
1656 // workaround, delay finishing up the first stream until the second and
1657 // third streams are waiting in the SPDY stream request queue.
1658 MockRead(ASYNC, ERR_IO_PENDING, 4), CreateMockRead(fin_body, 5),
1659 CreateMockRead(resp2, 8),
David Benjamin73dc5242019-05-15 21:59:281660 // The exact error does not matter, but some errors, such as
1661 // ERR_CONNECTION_RESET, may trigger a retry, which this test does not
1662 // account for.
1663 MockRead(ASYNC, ERR_SSL_BAD_RECORD_MAC_ALERT, 9), // Abort!
[email protected]044dcc52010-09-17 15:44:261664 };
1665
Ryan Sleevib8d7ea02018-05-07 20:01:011666 SequencedSocketData data(reads, writes);
1667 SequencedSocketData data_placeholder;
[email protected]044dcc52010-09-17 15:44:261668
[email protected]044dcc52010-09-17 15:44:261669 TransactionHelperResult out;
Matt Menke66e502a72019-04-15 13:34:381670 NormalSpdyTransactionHelper helper(request_, HIGHEST, log_, nullptr);
[email protected]044dcc52010-09-17 15:44:261671 helper.RunPreTestSetup();
[email protected]dd54bd82012-07-19 23:44:571672 helper.AddData(&data);
[email protected]044dcc52010-09-17 15:44:261673 // We require placeholder data because three get requests are sent out, so
1674 // there needs to be three sets of SSL connection data.
[email protected]dd54bd82012-07-19 23:44:571675 helper.AddData(&data_placeholder);
1676 helper.AddData(&data_placeholder);
Matt Menke66e502a72019-04-15 13:34:381677 HttpNetworkTransaction trans1(HIGHEST, helper.session());
1678 HttpNetworkTransaction trans2(MEDIUM, helper.session());
[email protected]262eec82013-03-19 21:01:361679 HttpNetworkTransaction* trans3(
mmenkee65e7af2015-10-13 17:16:421680 new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session()));
[email protected]044dcc52010-09-17 15:44:261681
[email protected]49639fa2011-12-20 23:22:411682 TestCompletionCallback callback1;
1683 TestCompletionCallback callback2;
[email protected]044dcc52010-09-17 15:44:261684 KillerCallback callback3(trans3);
1685
Bence Békydb3cf652017-10-10 15:22:101686 out.rv = trans1.Start(&request_, callback1.callback(), log_);
[email protected]044dcc52010-09-17 15:44:261687 ASSERT_EQ(out.rv, ERR_IO_PENDING);
[email protected]e0935cc2012-03-24 14:12:481688 // Run transaction 1 through quickly to force a read of our SETTINGS frame.
[email protected]044dcc52010-09-17 15:44:261689 out.rv = callback1.WaitForResult();
robpercival214763f2016-07-01 23:27:011690 ASSERT_THAT(out.rv, IsOk());
[email protected]044dcc52010-09-17 15:44:261691
Bence Békydb3cf652017-10-10 15:22:101692 out.rv = trans2.Start(&request_, callback2.callback(), log_);
[email protected]044dcc52010-09-17 15:44:261693 ASSERT_EQ(out.rv, ERR_IO_PENDING);
Bence Békydb3cf652017-10-10 15:22:101694 out.rv = trans3->Start(&request_, callback3.callback(), log_);
[email protected]044dcc52010-09-17 15:44:261695 ASSERT_EQ(out.rv, ERR_IO_PENDING);
Matt Menke66e502a72019-04-15 13:34:381696
1697 // Run until both transactions are in the SpdySession's queue, waiting for the
1698 // final request to complete.
1699 base::RunLoop().RunUntilIdle();
1700 data.Resume();
1701
[email protected]044dcc52010-09-17 15:44:261702 out.rv = callback3.WaitForResult();
David Benjamin73dc5242019-05-15 21:59:281703 EXPECT_THAT(out.rv, IsError(ERR_SSL_BAD_RECORD_MAC_ALERT));
[email protected]044dcc52010-09-17 15:44:261704
[email protected]044dcc52010-09-17 15:44:261705 const HttpResponseInfo* response1 = trans1.GetResponseInfo();
wezca1070932016-05-26 20:30:521706 ASSERT_TRUE(response1);
1707 EXPECT_TRUE(response1->headers);
[email protected]044dcc52010-09-17 15:44:261708 EXPECT_TRUE(response1->was_fetched_via_spdy);
1709 out.status_line = response1->headers->GetStatusLine();
1710 out.response_info = *response1;
1711 out.rv = ReadTransaction(&trans1, &out.response_data);
robpercival214763f2016-07-01 23:27:011712 EXPECT_THAT(out.rv, IsOk());
[email protected]044dcc52010-09-17 15:44:261713
1714 const HttpResponseInfo* response2 = trans2.GetResponseInfo();
wezca1070932016-05-26 20:30:521715 ASSERT_TRUE(response2);
[email protected]044dcc52010-09-17 15:44:261716 out.status_line = response2->headers->GetStatusLine();
1717 out.response_info = *response2;
1718 out.rv = ReadTransaction(&trans2, &out.response_data);
David Benjamin73dc5242019-05-15 21:59:281719 EXPECT_THAT(out.rv, IsError(ERR_SSL_BAD_RECORD_MAC_ALERT));
[email protected]044dcc52010-09-17 15:44:261720
1721 helper.VerifyDataConsumed();
[email protected]2bd93022010-07-17 00:58:441722}
1723
[email protected]d8ef27b2010-08-06 17:34:391724// Test that a simple PUT request works.
bncd16676a2016-07-20 16:23:011725TEST_F(SpdyNetworkTransactionTest, Put) {
Bence Békydb3cf652017-10-10 15:22:101726 // Setup the request.
1727 request_.method = "PUT";
[email protected]d8ef27b2010-08-06 17:34:391728
Ryan Hamilton0239aac2018-05-19 00:03:131729 spdy::SpdyHeaderBlock put_headers(
bncb26024382016-06-29 02:39:451730 spdy_util_.ConstructPutHeaderBlock(kDefaultUrl, 0));
Ryan Hamilton0239aac2018-05-19 00:03:131731 spdy::SpdySerializedFrame req(
bnc42331402016-07-25 13:36:151732 spdy_util_.ConstructSpdyHeaders(1, std::move(put_headers), LOWEST, true));
[email protected]d8ef27b2010-08-06 17:34:391733 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:411734 CreateMockWrite(req, 0),
[email protected]d8ef27b2010-08-06 17:34:391735 };
1736
Ryan Hamilton0239aac2018-05-19 00:03:131737 spdy::SpdySerializedFrame resp(
1738 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
1739 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]d8ef27b2010-08-06 17:34:391740 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:411741 CreateMockRead(resp, 1), CreateMockRead(body, 2),
rch08e3aa3e2015-05-16 14:27:521742 MockRead(ASYNC, 0, 3) // EOF
[email protected]d8ef27b2010-08-06 17:34:391743 };
1744
Ryan Sleevib8d7ea02018-05-07 20:01:011745 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:101746 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]dd54bd82012-07-19 23:44:571747 helper.RunToCompletion(&data);
[email protected]d8ef27b2010-08-06 17:34:391748 TransactionHelperResult out = helper.output();
1749
robpercival214763f2016-07-01 23:27:011750 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:021751 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]d8ef27b2010-08-06 17:34:391752}
1753
1754// Test that a simple HEAD request works.
bncd16676a2016-07-20 16:23:011755TEST_F(SpdyNetworkTransactionTest, Head) {
Bence Békydb3cf652017-10-10 15:22:101756 // Setup the request.
1757 request_.method = "HEAD";
[email protected]d8ef27b2010-08-06 17:34:391758
Ryan Hamilton0239aac2018-05-19 00:03:131759 spdy::SpdyHeaderBlock head_headers(
bncb26024382016-06-29 02:39:451760 spdy_util_.ConstructHeadHeaderBlock(kDefaultUrl, 0));
Ryan Hamilton0239aac2018-05-19 00:03:131761 spdy::SpdySerializedFrame req(spdy_util_.ConstructSpdyHeaders(
bnc42331402016-07-25 13:36:151762 1, std::move(head_headers), LOWEST, true));
[email protected]d8ef27b2010-08-06 17:34:391763 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:411764 CreateMockWrite(req, 0),
[email protected]d8ef27b2010-08-06 17:34:391765 };
1766
Ryan Hamilton0239aac2018-05-19 00:03:131767 spdy::SpdySerializedFrame resp(
1768 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
1769 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]d8ef27b2010-08-06 17:34:391770 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:411771 CreateMockRead(resp, 1), CreateMockRead(body, 2),
rch08e3aa3e2015-05-16 14:27:521772 MockRead(ASYNC, 0, 3) // EOF
[email protected]d8ef27b2010-08-06 17:34:391773 };
1774
Ryan Sleevib8d7ea02018-05-07 20:01:011775 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:101776 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]dd54bd82012-07-19 23:44:571777 helper.RunToCompletion(&data);
[email protected]d8ef27b2010-08-06 17:34:391778 TransactionHelperResult out = helper.output();
1779
robpercival214763f2016-07-01 23:27:011780 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:021781 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]d8ef27b2010-08-06 17:34:391782}
1783
[email protected]72552f02009-10-28 15:25:011784// Test that a simple POST works.
bncd16676a2016-07-20 16:23:011785TEST_F(SpdyNetworkTransactionTest, Post) {
Ryan Hamilton0239aac2018-05-19 00:03:131786 spdy::SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
tombergan5d22c182017-01-11 02:05:351787 kDefaultUrl, 1, kUploadDataSize, LOWEST, nullptr, 0));
Ryan Hamilton0239aac2018-05-19 00:03:131788 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]ff57bb82009-11-12 06:52:141789 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:411790 CreateMockWrite(req, 0), CreateMockWrite(body, 1), // POST upload frame
[email protected]ff57bb82009-11-12 06:52:141791 };
[email protected]72552f02009-10-28 15:25:011792
Ryan Hamilton0239aac2018-05-19 00:03:131793 spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
[email protected]ff57bb82009-11-12 06:52:141794 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:411795 CreateMockRead(resp, 2), CreateMockRead(body, 3),
rch08e3aa3e2015-05-16 14:27:521796 MockRead(ASYNC, 0, 4) // EOF
[email protected]aea80602009-09-18 00:55:081797 };
1798
Ryan Sleevib8d7ea02018-05-07 20:01:011799 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:101800 UsePostRequest();
1801 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]dd54bd82012-07-19 23:44:571802 helper.RunToCompletion(&data);
[email protected]3caf5542010-07-16 15:19:471803 TransactionHelperResult out = helper.output();
robpercival214763f2016-07-01 23:27:011804 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:021805 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]aea80602009-09-18 00:55:081806 EXPECT_EQ("hello!", out.response_data);
1807}
1808
[email protected]69e6b4a2012-10-18 08:03:011809// Test that a POST with a file works.
bncd16676a2016-07-20 16:23:011810TEST_F(SpdyNetworkTransactionTest, FilePost) {
Ryan Hamilton0239aac2018-05-19 00:03:131811 spdy::SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
tombergan5d22c182017-01-11 02:05:351812 kDefaultUrl, 1, kUploadDataSize, LOWEST, nullptr, 0));
Ryan Hamilton0239aac2018-05-19 00:03:131813 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]69e6b4a2012-10-18 08:03:011814 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:411815 CreateMockWrite(req, 0), CreateMockWrite(body, 1), // POST upload frame
[email protected]69e6b4a2012-10-18 08:03:011816 };
1817
Ryan Hamilton0239aac2018-05-19 00:03:131818 spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
[email protected]69e6b4a2012-10-18 08:03:011819 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:411820 CreateMockRead(resp, 2), CreateMockRead(body, 3),
rch08e3aa3e2015-05-16 14:27:521821 MockRead(ASYNC, 0, 4) // EOF
[email protected]69e6b4a2012-10-18 08:03:011822 };
1823
Ryan Sleevib8d7ea02018-05-07 20:01:011824 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:101825 UseFilePostRequest();
1826 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]69e6b4a2012-10-18 08:03:011827 helper.RunToCompletion(&data);
1828 TransactionHelperResult out = helper.output();
robpercival214763f2016-07-01 23:27:011829 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:021830 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]69e6b4a2012-10-18 08:03:011831 EXPECT_EQ("hello!", out.response_data);
1832}
1833
[email protected]999dd8c2013-11-12 06:45:541834// Test that a POST with a unreadable file fails.
bncd16676a2016-07-20 16:23:011835TEST_F(SpdyNetworkTransactionTest, UnreadableFilePost) {
[email protected]999dd8c2013-11-12 06:45:541836 MockWrite writes[] = {
rch08e3aa3e2015-05-16 14:27:521837 MockWrite(ASYNC, 0, 0) // EOF
[email protected]999dd8c2013-11-12 06:45:541838 };
1839 MockRead reads[] = {
rch08e3aa3e2015-05-16 14:27:521840 MockRead(ASYNC, 0, 1) // EOF
[email protected]999dd8c2013-11-12 06:45:541841 };
1842
Ryan Sleevib8d7ea02018-05-07 20:01:011843 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:101844 UseUnreadableFilePostRequest();
1845 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]999dd8c2013-11-12 06:45:541846 helper.RunPreTestSetup();
1847 helper.AddData(&data);
1848 helper.RunDefaultTest();
1849
1850 base::RunLoop().RunUntilIdle();
1851 helper.VerifyDataNotConsumed();
robpercival214763f2016-07-01 23:27:011852 EXPECT_THAT(helper.output().rv, IsError(ERR_ACCESS_DENIED));
[email protected]999dd8c2013-11-12 06:45:541853}
1854
[email protected]69e6b4a2012-10-18 08:03:011855// Test that a complex POST works.
bncd16676a2016-07-20 16:23:011856TEST_F(SpdyNetworkTransactionTest, ComplexPost) {
Ryan Hamilton0239aac2018-05-19 00:03:131857 spdy::SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
tombergan5d22c182017-01-11 02:05:351858 kDefaultUrl, 1, kUploadDataSize, LOWEST, nullptr, 0));
Ryan Hamilton0239aac2018-05-19 00:03:131859 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]69e6b4a2012-10-18 08:03:011860 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:411861 CreateMockWrite(req, 0), CreateMockWrite(body, 1), // POST upload frame
[email protected]69e6b4a2012-10-18 08:03:011862 };
1863
Ryan Hamilton0239aac2018-05-19 00:03:131864 spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
[email protected]69e6b4a2012-10-18 08:03:011865 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:411866 CreateMockRead(resp, 2), CreateMockRead(body, 3),
rch08e3aa3e2015-05-16 14:27:521867 MockRead(ASYNC, 0, 4) // EOF
[email protected]69e6b4a2012-10-18 08:03:011868 };
1869
Ryan Sleevib8d7ea02018-05-07 20:01:011870 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:101871 UseComplexPostRequest();
1872 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]69e6b4a2012-10-18 08:03:011873 helper.RunToCompletion(&data);
1874 TransactionHelperResult out = helper.output();
robpercival214763f2016-07-01 23:27:011875 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:021876 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]69e6b4a2012-10-18 08:03:011877 EXPECT_EQ("hello!", out.response_data);
1878}
1879
[email protected]0c9bf872011-03-04 17:53:221880// Test that a chunked POST works.
bncd16676a2016-07-20 16:23:011881TEST_F(SpdyNetworkTransactionTest, ChunkedPost) {
Ryan Hamilton0239aac2018-05-19 00:03:131882 spdy::SpdySerializedFrame req(
1883 spdy_util_.ConstructChunkedSpdyPost(nullptr, 0));
1884 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]0c9bf872011-03-04 17:53:221885 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:411886 CreateMockWrite(req, 0), CreateMockWrite(body, 1),
[email protected]0c9bf872011-03-04 17:53:221887 };
1888
Ryan Hamilton0239aac2018-05-19 00:03:131889 spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
[email protected]0c9bf872011-03-04 17:53:221890 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:411891 CreateMockRead(resp, 2), CreateMockRead(body, 3),
rch08e3aa3e2015-05-16 14:27:521892 MockRead(ASYNC, 0, 4) // EOF
[email protected]0c9bf872011-03-04 17:53:221893 };
1894
Ryan Sleevib8d7ea02018-05-07 20:01:011895 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:101896 UseChunkedPostRequest();
1897 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]34b345f92013-02-22 03:27:261898
1899 // These chunks get merged into a single frame when being sent.
1900 const int kFirstChunkSize = kUploadDataSize/2;
mmenkecbc2b712014-10-09 20:29:071901 upload_chunked_data_stream()->AppendData(kUploadData, kFirstChunkSize, false);
1902 upload_chunked_data_stream()->AppendData(
[email protected]34b345f92013-02-22 03:27:261903 kUploadData + kFirstChunkSize, kUploadDataSize - kFirstChunkSize, true);
1904
[email protected]dd54bd82012-07-19 23:44:571905 helper.RunToCompletion(&data);
[email protected]0c9bf872011-03-04 17:53:221906 TransactionHelperResult out = helper.output();
robpercival214763f2016-07-01 23:27:011907 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:021908 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]34b345f92013-02-22 03:27:261909 EXPECT_EQ(kUploadData, out.response_data);
1910}
1911
1912// Test that a chunked POST works with chunks appended after transaction starts.
bncd16676a2016-07-20 16:23:011913TEST_F(SpdyNetworkTransactionTest, DelayedChunkedPost) {
Ryan Hamilton0239aac2018-05-19 00:03:131914 spdy::SpdySerializedFrame req(
1915 spdy_util_.ConstructChunkedSpdyPost(nullptr, 0));
1916 spdy::SpdySerializedFrame chunk1(spdy_util_.ConstructSpdyDataFrame(1, false));
1917 spdy::SpdySerializedFrame chunk2(spdy_util_.ConstructSpdyDataFrame(1, false));
1918 spdy::SpdySerializedFrame chunk3(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]34b345f92013-02-22 03:27:261919 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:411920 CreateMockWrite(req, 0), CreateMockWrite(chunk1, 1),
1921 CreateMockWrite(chunk2, 2), CreateMockWrite(chunk3, 3),
[email protected]34b345f92013-02-22 03:27:261922 };
1923
Ryan Hamilton0239aac2018-05-19 00:03:131924 spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
[email protected]34b345f92013-02-22 03:27:261925 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:411926 CreateMockRead(resp, 4), CreateMockRead(chunk1, 5),
1927 CreateMockRead(chunk2, 6), CreateMockRead(chunk3, 7),
rch08e3aa3e2015-05-16 14:27:521928 MockRead(ASYNC, 0, 8) // EOF
[email protected]34b345f92013-02-22 03:27:261929 };
1930
Ryan Sleevib8d7ea02018-05-07 20:01:011931 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:101932 UseChunkedPostRequest();
1933 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]34b345f92013-02-22 03:27:261934
mmenkecbc2b712014-10-09 20:29:071935 upload_chunked_data_stream()->AppendData(kUploadData, kUploadDataSize, false);
[email protected]34b345f92013-02-22 03:27:261936
1937 helper.RunPreTestSetup();
1938 helper.AddData(&data);
1939 ASSERT_TRUE(helper.StartDefaultTest());
1940
[email protected]fc9d88472013-08-14 02:31:171941 base::RunLoop().RunUntilIdle();
mmenkecbc2b712014-10-09 20:29:071942 upload_chunked_data_stream()->AppendData(kUploadData, kUploadDataSize, false);
[email protected]fc9d88472013-08-14 02:31:171943 base::RunLoop().RunUntilIdle();
mmenkecbc2b712014-10-09 20:29:071944 upload_chunked_data_stream()->AppendData(kUploadData, kUploadDataSize, true);
[email protected]34b345f92013-02-22 03:27:261945
1946 helper.FinishDefaultTest();
1947 helper.VerifyDataConsumed();
1948
Bence Béky4e83f492018-05-13 23:14:251949 std::string expected_response;
[email protected]34b345f92013-02-22 03:27:261950 expected_response += kUploadData;
1951 expected_response += kUploadData;
1952 expected_response += kUploadData;
1953
1954 TransactionHelperResult out = helper.output();
robpercival214763f2016-07-01 23:27:011955 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:021956 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]34b345f92013-02-22 03:27:261957 EXPECT_EQ(expected_response, out.response_data);
[email protected]0c9bf872011-03-04 17:53:221958}
1959
[email protected]a33cad2b62010-07-30 22:24:391960// Test that a POST without any post data works.
bncd16676a2016-07-20 16:23:011961TEST_F(SpdyNetworkTransactionTest, NullPost) {
Bence Békydb3cf652017-10-10 15:22:101962 // Setup the request.
1963 request_.method = "POST";
[email protected]a33cad2b62010-07-30 22:24:391964 // Create an empty UploadData.
Bence Békydb3cf652017-10-10 15:22:101965 request_.upload_data_stream = nullptr;
[email protected]a33cad2b62010-07-30 22:24:391966
[email protected]329b68b2012-11-14 17:54:271967 // When request.upload_data_stream is NULL for post, content-length is
[email protected]a33cad2b62010-07-30 22:24:391968 // expected to be 0.
Ryan Hamilton0239aac2018-05-19 00:03:131969 spdy::SpdyHeaderBlock req_block(
bncb26024382016-06-29 02:39:451970 spdy_util_.ConstructPostHeaderBlock(kDefaultUrl, 0));
Ryan Hamilton0239aac2018-05-19 00:03:131971 spdy::SpdySerializedFrame req(
bnc42331402016-07-25 13:36:151972 spdy_util_.ConstructSpdyHeaders(1, std::move(req_block), LOWEST, true));
[email protected]d2c1a97b2014-03-03 19:25:091973
[email protected]a33cad2b62010-07-30 22:24:391974 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:411975 CreateMockWrite(req, 0),
[email protected]a33cad2b62010-07-30 22:24:391976 };
1977
Ryan Hamilton0239aac2018-05-19 00:03:131978 spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
1979 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]a33cad2b62010-07-30 22:24:391980 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:411981 CreateMockRead(resp, 1), CreateMockRead(body, 2),
rch08e3aa3e2015-05-16 14:27:521982 MockRead(ASYNC, 0, 3) // EOF
[email protected]a33cad2b62010-07-30 22:24:391983 };
1984
Ryan Sleevib8d7ea02018-05-07 20:01:011985 SequencedSocketData data(reads, writes);
[email protected]a33cad2b62010-07-30 22:24:391986
Bence Békydb3cf652017-10-10 15:22:101987 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]dd54bd82012-07-19 23:44:571988 helper.RunToCompletion(&data);
[email protected]a33cad2b62010-07-30 22:24:391989 TransactionHelperResult out = helper.output();
robpercival214763f2016-07-01 23:27:011990 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:021991 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]a33cad2b62010-07-30 22:24:391992 EXPECT_EQ("hello!", out.response_data);
1993}
1994
[email protected]edd3b0a52009-11-24 18:56:361995// Test that a simple POST works.
bncd16676a2016-07-20 16:23:011996TEST_F(SpdyNetworkTransactionTest, EmptyPost) {
[email protected]329b68b2012-11-14 17:54:271997 // Create an empty UploadDataStream.
danakjaee3e1ec2016-04-16 00:23:181998 std::vector<std::unique_ptr<UploadElementReader>> element_readers;
olli.raula6df48b2a2015-11-26 07:40:221999 ElementsUploadDataStream stream(std::move(element_readers), 0);
[email protected]329b68b2012-11-14 17:54:272000
Bence Békydb3cf652017-10-10 15:22:102001 // Setup the request.
2002 request_.method = "POST";
2003 request_.upload_data_stream = &stream;
[email protected]edd3b0a52009-11-24 18:56:362004
Avi Drissman13fc8932015-12-20 04:40:462005 const uint64_t kContentLength = 0;
[email protected]d2c1a97b2014-03-03 19:25:092006
Ryan Hamilton0239aac2018-05-19 00:03:132007 spdy::SpdyHeaderBlock req_block(
bncb26024382016-06-29 02:39:452008 spdy_util_.ConstructPostHeaderBlock(kDefaultUrl, kContentLength));
Ryan Hamilton0239aac2018-05-19 00:03:132009 spdy::SpdySerializedFrame req(
bnc42331402016-07-25 13:36:152010 spdy_util_.ConstructSpdyHeaders(1, std::move(req_block), LOWEST, true));
[email protected]d2c1a97b2014-03-03 19:25:092011
[email protected]edd3b0a52009-11-24 18:56:362012 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:412013 CreateMockWrite(req, 0),
[email protected]edd3b0a52009-11-24 18:56:362014 };
2015
Ryan Hamilton0239aac2018-05-19 00:03:132016 spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
2017 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]edd3b0a52009-11-24 18:56:362018 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:412019 CreateMockRead(resp, 1), CreateMockRead(body, 2),
rch08e3aa3e2015-05-16 14:27:522020 MockRead(ASYNC, 0, 3) // EOF
[email protected]edd3b0a52009-11-24 18:56:362021 };
2022
Ryan Sleevib8d7ea02018-05-07 20:01:012023 SequencedSocketData data(reads, writes);
[email protected]bf2491a92009-11-29 16:39:482024
Bence Békydb3cf652017-10-10 15:22:102025 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]dd54bd82012-07-19 23:44:572026 helper.RunToCompletion(&data);
[email protected]3caf5542010-07-16 15:19:472027 TransactionHelperResult out = helper.output();
robpercival214763f2016-07-01 23:27:012028 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:022029 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]edd3b0a52009-11-24 18:56:362030 EXPECT_EQ("hello!", out.response_data);
2031}
2032
[email protected]35c3fc732014-02-15 00:16:072033// While we're doing a post, the server sends the reply before upload completes.
bncd16676a2016-07-20 16:23:012034TEST_F(SpdyNetworkTransactionTest, ResponseBeforePostCompletes) {
Ryan Hamilton0239aac2018-05-19 00:03:132035 spdy::SpdySerializedFrame req(
2036 spdy_util_.ConstructChunkedSpdyPost(nullptr, 0));
2037 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]35c3fc732014-02-15 00:16:072038 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:412039 CreateMockWrite(req, 0), CreateMockWrite(body, 3),
[email protected]35c3fc732014-02-15 00:16:072040 };
Ryan Hamilton0239aac2018-05-19 00:03:132041 spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
[email protected]a5566f9702010-05-05 22:25:432042 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:412043 CreateMockRead(resp, 1), CreateMockRead(body, 2),
2044 MockRead(ASYNC, 0, 4) // EOF
[email protected]a5566f9702010-05-05 22:25:432045 };
2046
[email protected]35c3fc732014-02-15 00:16:072047 // Write the request headers, and read the complete response
2048 // while still waiting for chunked request data.
Ryan Sleevib8d7ea02018-05-07 20:01:012049 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:102050 UseChunkedPostRequest();
2051 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]c92f4b4542012-07-26 23:53:212052 helper.RunPreTestSetup();
mmenke666a6fea2015-12-19 04:16:332053 helper.AddData(&data);
[email protected]c92f4b4542012-07-26 23:53:212054
[email protected]35c3fc732014-02-15 00:16:072055 ASSERT_TRUE(helper.StartDefaultTest());
[email protected]c92f4b4542012-07-26 23:53:212056
maksim.sisov8d2df66d2016-06-20 07:07:112057 base::RunLoop().RunUntilIdle();
mmenke666a6fea2015-12-19 04:16:332058
bnc42331402016-07-25 13:36:152059 // Process the request headers, response headers, and response body.
[email protected]35c3fc732014-02-15 00:16:072060 // The request body is still in flight.
[email protected]35c3fc732014-02-15 00:16:072061 const HttpResponseInfo* response = helper.trans()->GetResponseInfo();
bnc84e7fb52015-12-02 11:50:022062 EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
[email protected]35c3fc732014-02-15 00:16:072063
2064 // Finish sending the request body.
mmenkecbc2b712014-10-09 20:29:072065 upload_chunked_data_stream()->AppendData(kUploadData, kUploadDataSize, true);
maksim.sisov8d2df66d2016-06-20 07:07:112066 helper.WaitForCallbackToComplete();
robpercival214763f2016-07-01 23:27:012067 EXPECT_THAT(helper.output().rv, IsOk());
[email protected]35c3fc732014-02-15 00:16:072068
Bence Béky4e83f492018-05-13 23:14:252069 std::string response_body;
robpercival214763f2016-07-01 23:27:012070 EXPECT_THAT(ReadTransaction(helper.trans(), &response_body), IsOk());
[email protected]35c3fc732014-02-15 00:16:072071 EXPECT_EQ(kUploadData, response_body);
bnceb9aa7112017-01-05 01:03:462072
2073 // Finish async network reads/writes.
2074 base::RunLoop().RunUntilIdle();
[email protected]35c3fc732014-02-15 00:16:072075 helper.VerifyDataConsumed();
[email protected]a5566f9702010-05-05 22:25:432076}
2077
[email protected]f9a26d72010-08-03 18:07:132078// The client upon cancellation tries to send a RST_STREAM frame. The mock
2079// socket causes the TCP write to return zero. This test checks that the client
2080// tries to queue up the RST_STREAM frame again.
bncd16676a2016-07-20 16:23:012081TEST_F(SpdyNetworkTransactionTest, SocketWriteReturnsZero) {
Ryan Hamilton0239aac2018-05-19 00:03:132082 spdy::SpdySerializedFrame req(
2083 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
2084 spdy::SpdySerializedFrame rst(
2085 spdy_util_.ConstructSpdyRstStream(1, spdy::ERROR_CODE_CANCEL));
[email protected]f9a26d72010-08-03 18:07:132086 MockWrite writes[] = {
Raul Tambre94493c652019-03-11 17:18:352087 CreateMockWrite(req, 0, SYNCHRONOUS),
2088 MockWrite(SYNCHRONOUS, nullptr, 0, 2),
bncdf80d44fd2016-07-15 20:27:412089 CreateMockWrite(rst, 3, SYNCHRONOUS),
[email protected]f9a26d72010-08-03 18:07:132090 };
2091
Ryan Hamilton0239aac2018-05-19 00:03:132092 spdy::SpdySerializedFrame resp(
2093 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
[email protected]f9a26d72010-08-03 18:07:132094 MockRead reads[] = {
Raul Tambre94493c652019-03-11 17:18:352095 CreateMockRead(resp, 1, ASYNC), MockRead(ASYNC, nullptr, 0, 4) // EOF
[email protected]f9a26d72010-08-03 18:07:132096 };
2097
Ryan Sleevib8d7ea02018-05-07 20:01:012098 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:102099 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]f9a26d72010-08-03 18:07:132100 helper.RunPreTestSetup();
mmenke666a6fea2015-12-19 04:16:332101 helper.AddData(&data);
bnc4d782f492016-08-18 13:50:002102 helper.StartDefaultTest();
2103 EXPECT_THAT(helper.output().rv, IsError(ERR_IO_PENDING));
[email protected]f9a26d72010-08-03 18:07:132104
bnc4d782f492016-08-18 13:50:002105 helper.WaitForCallbackToComplete();
2106 EXPECT_THAT(helper.output().rv, IsOk());
[email protected]3b7828432010-08-18 18:33:272107
[email protected]f9a26d72010-08-03 18:07:132108 helper.ResetTrans();
mmenke666a6fea2015-12-19 04:16:332109 base::RunLoop().RunUntilIdle();
[email protected]3b7828432010-08-18 18:33:272110
[email protected]f9a26d72010-08-03 18:07:132111 helper.VerifyDataConsumed();
2112}
2113
[email protected]93300672009-10-24 13:22:512114// Test that the transaction doesn't crash when we don't have a reply.
bnc42331402016-07-25 13:36:152115TEST_F(SpdyNetworkTransactionTest, ResponseWithoutHeaders) {
Ryan Hamilton0239aac2018-05-19 00:03:132116 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]ff57bb82009-11-12 06:52:142117 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:412118 CreateMockRead(body, 1), MockRead(ASYNC, 0, 3) // EOF
[email protected]93300672009-10-24 13:22:512119 };
2120
Ryan Hamilton0239aac2018-05-19 00:03:132121 spdy::SpdySerializedFrame req(
2122 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
2123 spdy::SpdySerializedFrame rst(
2124 spdy_util_.ConstructSpdyRstStream(1, spdy::ERROR_CODE_PROTOCOL_ERROR));
rch08e3aa3e2015-05-16 14:27:522125 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:412126 CreateMockWrite(req, 0), CreateMockWrite(rst, 2),
rch08e3aa3e2015-05-16 14:27:522127 };
Ryan Sleevib8d7ea02018-05-07 20:01:012128 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:102129 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]dd54bd82012-07-19 23:44:572130 helper.RunToCompletion(&data);
[email protected]3caf5542010-07-16 15:19:472131 TransactionHelperResult out = helper.output();
Bence Békyd0d69502019-06-25 19:47:182132 EXPECT_THAT(out.rv, IsError(ERR_HTTP2_PROTOCOL_ERROR));
[email protected]93300672009-10-24 13:22:512133}
2134
[email protected]d30022352010-06-24 19:17:582135// Test that the transaction doesn't crash when we get two replies on the same
2136// stream ID. See http://crbug.com/45639.
bncd16676a2016-07-20 16:23:012137TEST_F(SpdyNetworkTransactionTest, ResponseWithTwoSynReplies) {
Ryan Hamilton0239aac2018-05-19 00:03:132138 spdy::SpdySerializedFrame req(
2139 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
2140 spdy::SpdySerializedFrame rst(
2141 spdy_util_.ConstructSpdyRstStream(1, spdy::ERROR_CODE_PROTOCOL_ERROR));
[email protected]2aeef782013-06-21 18:30:562142 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:412143 CreateMockWrite(req, 0), CreateMockWrite(rst, 4),
[email protected]2aeef782013-06-21 18:30:562144 };
[email protected]d30022352010-06-24 19:17:582145
Ryan Hamilton0239aac2018-05-19 00:03:132146 spdy::SpdySerializedFrame resp0(
2147 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
2148 spdy::SpdySerializedFrame resp1(
2149 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
2150 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]d30022352010-06-24 19:17:582151 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:412152 CreateMockRead(resp0, 1), CreateMockRead(resp1, 2),
2153 CreateMockRead(body, 3), MockRead(ASYNC, 0, 5) // EOF
[email protected]d30022352010-06-24 19:17:582154 };
2155
Ryan Sleevib8d7ea02018-05-07 20:01:012156 SequencedSocketData data(reads, writes);
[email protected]d30022352010-06-24 19:17:582157
Bence Békydb3cf652017-10-10 15:22:102158 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]3caf5542010-07-16 15:19:472159 helper.RunPreTestSetup();
[email protected]dd54bd82012-07-19 23:44:572160 helper.AddData(&data);
[email protected]3caf5542010-07-16 15:19:472161
2162 HttpNetworkTransaction* trans = helper.trans();
[email protected]d30022352010-06-24 19:17:582163
[email protected]49639fa2011-12-20 23:22:412164 TestCompletionCallback callback;
Bence Békydb3cf652017-10-10 15:22:102165 int rv = trans->Start(&request_, callback.callback(), log_);
robpercival214763f2016-07-01 23:27:012166 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]d30022352010-06-24 19:17:582167 rv = callback.WaitForResult();
robpercival214763f2016-07-01 23:27:012168 EXPECT_THAT(rv, IsOk());
[email protected]d30022352010-06-24 19:17:582169
2170 const HttpResponseInfo* response = trans->GetResponseInfo();
wezca1070932016-05-26 20:30:522171 ASSERT_TRUE(response);
2172 EXPECT_TRUE(response->headers);
[email protected]d30022352010-06-24 19:17:582173 EXPECT_TRUE(response->was_fetched_via_spdy);
Bence Béky4e83f492018-05-13 23:14:252174 std::string response_data;
[email protected]3caf5542010-07-16 15:19:472175 rv = ReadTransaction(trans, &response_data);
Bence Békyd0d69502019-06-25 19:47:182176 EXPECT_THAT(rv, IsError(ERR_HTTP2_PROTOCOL_ERROR));
[email protected]3caf5542010-07-16 15:19:472177
2178 helper.VerifyDataConsumed();
[email protected]d30022352010-06-24 19:17:582179}
2180
bncd16676a2016-07-20 16:23:012181TEST_F(SpdyNetworkTransactionTest, ResetReplyWithTransferEncoding) {
[email protected]b3503002012-03-27 04:57:252182 // Construct the request.
Ryan Hamilton0239aac2018-05-19 00:03:132183 spdy::SpdySerializedFrame req(
2184 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
2185 spdy::SpdySerializedFrame rst(
2186 spdy_util_.ConstructSpdyRstStream(1, spdy::ERROR_CODE_PROTOCOL_ERROR));
[email protected]b3503002012-03-27 04:57:252187 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:412188 CreateMockWrite(req, 0), CreateMockWrite(rst, 2),
[email protected]b3503002012-03-27 04:57:252189 };
2190
2191 const char* const headers[] = {
[email protected]513963e2013-06-15 01:53:042192 "transfer-encoding", "chunked"
[email protected]b3503002012-03-27 04:57:252193 };
Ryan Hamilton0239aac2018-05-19 00:03:132194 spdy::SpdySerializedFrame resp(
2195 spdy_util_.ConstructSpdyGetReply(headers, 1, 1));
2196 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]b3503002012-03-27 04:57:252197 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:412198 CreateMockRead(resp, 1), CreateMockRead(body, 3),
rch08e3aa3e2015-05-16 14:27:522199 MockRead(ASYNC, 0, 4) // EOF
[email protected]b3503002012-03-27 04:57:252200 };
2201
Ryan Sleevib8d7ea02018-05-07 20:01:012202 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:102203 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]dd54bd82012-07-19 23:44:572204 helper.RunToCompletion(&data);
[email protected]b3503002012-03-27 04:57:252205 TransactionHelperResult out = helper.output();
Bence Békyd0d69502019-06-25 19:47:182206 EXPECT_THAT(out.rv, IsError(ERR_HTTP2_PROTOCOL_ERROR));
[email protected]b3503002012-03-27 04:57:252207
2208 helper.session()->spdy_session_pool()->CloseAllSessions();
2209 helper.VerifyDataConsumed();
2210}
2211
bncd16676a2016-07-20 16:23:012212TEST_F(SpdyNetworkTransactionTest, ResetPushWithTransferEncoding) {
[email protected]b3503002012-03-27 04:57:252213 // Construct the request.
Ryan Hamilton0239aac2018-05-19 00:03:132214 spdy::SpdySerializedFrame req(
2215 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
2216 spdy::SpdySerializedFrame priority(
tombergan5d22c182017-01-11 02:05:352217 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true));
Ryan Hamilton0239aac2018-05-19 00:03:132218 spdy::SpdySerializedFrame rst(
2219 spdy_util_.ConstructSpdyRstStream(2, spdy::ERROR_CODE_PROTOCOL_ERROR));
[email protected]b3503002012-03-27 04:57:252220 MockWrite writes[] = {
tombergan5d22c182017-01-11 02:05:352221 CreateMockWrite(req, 0), CreateMockWrite(priority, 3),
2222 CreateMockWrite(rst, 5),
[email protected]b3503002012-03-27 04:57:252223 };
2224
Ryan Hamilton0239aac2018-05-19 00:03:132225 spdy::SpdySerializedFrame resp(
2226 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
[email protected]513963e2013-06-15 01:53:042227 const char* const headers[] = {
2228 "transfer-encoding", "chunked"
2229 };
Ryan Hamilton0239aac2018-05-19 00:03:132230 spdy::SpdySerializedFrame push(spdy_util_.ConstructSpdyPush(
Avi Drissman4365a4782018-12-28 19:26:242231 headers, base::size(headers) / 2, 2, 1, "https://www.example.org/1"));
Ryan Hamilton0239aac2018-05-19 00:03:132232 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]b3503002012-03-27 04:57:252233 MockRead reads[] = {
tombergan5d22c182017-01-11 02:05:352234 CreateMockRead(resp, 1), CreateMockRead(push, 2), CreateMockRead(body, 4),
2235 MockRead(ASYNC, 0, 6) // EOF
[email protected]b3503002012-03-27 04:57:252236 };
2237
Ryan Sleevib8d7ea02018-05-07 20:01:012238 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:102239 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]dd54bd82012-07-19 23:44:572240 helper.RunToCompletion(&data);
[email protected]b3503002012-03-27 04:57:252241 TransactionHelperResult out = helper.output();
robpercival214763f2016-07-01 23:27:012242 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:022243 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]b3503002012-03-27 04:57:252244 EXPECT_EQ("hello!", out.response_data);
2245
2246 helper.session()->spdy_session_pool()->CloseAllSessions();
2247 helper.VerifyDataConsumed();
2248}
2249
bncd16676a2016-07-20 16:23:012250TEST_F(SpdyNetworkTransactionTest, CancelledTransaction) {
[email protected]75f30cc22010-06-28 21:41:382251 // Construct the request.
Ryan Hamilton0239aac2018-05-19 00:03:132252 spdy::SpdySerializedFrame req(
2253 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
[email protected]34437af82009-11-06 02:28:492254 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:412255 CreateMockWrite(req),
[email protected]34437af82009-11-06 02:28:492256 };
2257
Ryan Hamilton0239aac2018-05-19 00:03:132258 spdy::SpdySerializedFrame resp(
2259 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
[email protected]34437af82009-11-06 02:28:492260 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:412261 CreateMockRead(resp),
2262 // This following read isn't used by the test, except during the
2263 // RunUntilIdle() call at the end since the SpdySession survives the
2264 // HttpNetworkTransaction and still tries to continue Read()'ing. Any
2265 // MockRead will do here.
2266 MockRead(ASYNC, 0, 0) // EOF
[email protected]34437af82009-11-06 02:28:492267 };
2268
Ryan Sleevib8d7ea02018-05-07 20:01:012269 StaticSocketDataProvider data(reads, writes);
[email protected]3caf5542010-07-16 15:19:472270
Bence Békydb3cf652017-10-10 15:22:102271 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]3caf5542010-07-16 15:19:472272 helper.RunPreTestSetup();
[email protected]e3ebba0f2010-08-05 17:59:582273 helper.AddData(&data);
[email protected]3caf5542010-07-16 15:19:472274 HttpNetworkTransaction* trans = helper.trans();
[email protected]34437af82009-11-06 02:28:492275
[email protected]49639fa2011-12-20 23:22:412276 TestCompletionCallback callback;
Bence Békydb3cf652017-10-10 15:22:102277 int rv = trans->Start(&request_, callback.callback(), log_);
robpercival214763f2016-07-01 23:27:012278 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]3caf5542010-07-16 15:19:472279 helper.ResetTrans(); // Cancel the transaction.
[email protected]34437af82009-11-06 02:28:492280
[email protected]30c942b2010-07-21 16:59:592281 // Flush the MessageLoop while the SpdySessionDependencies (in particular, the
[email protected]34437af82009-11-06 02:28:492282 // MockClientSocketFactory) are still alive.
[email protected]fc9d88472013-08-14 02:31:172283 base::RunLoop().RunUntilIdle();
[email protected]3caf5542010-07-16 15:19:472284 helper.VerifyDataNotConsumed();
[email protected]34437af82009-11-06 02:28:492285}
[email protected]72552f02009-10-28 15:25:012286
[email protected]6c6ea172010-07-27 20:04:032287// Verify that the client sends a Rst Frame upon cancelling the stream.
bncd16676a2016-07-20 16:23:012288TEST_F(SpdyNetworkTransactionTest, CancelledTransactionSendRst) {
Ryan Hamilton0239aac2018-05-19 00:03:132289 spdy::SpdySerializedFrame req(
2290 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
2291 spdy::SpdySerializedFrame rst(
2292 spdy_util_.ConstructSpdyRstStream(1, spdy::ERROR_CODE_CANCEL));
[email protected]6c6ea172010-07-27 20:04:032293 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:412294 CreateMockWrite(req, 0, SYNCHRONOUS),
2295 CreateMockWrite(rst, 2, SYNCHRONOUS),
[email protected]6c6ea172010-07-27 20:04:032296 };
2297
Ryan Hamilton0239aac2018-05-19 00:03:132298 spdy::SpdySerializedFrame resp(
2299 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
[email protected]6c6ea172010-07-27 20:04:032300 MockRead reads[] = {
Raul Tambre94493c652019-03-11 17:18:352301 CreateMockRead(resp, 1, ASYNC), MockRead(ASYNC, nullptr, 0, 3) // EOF
[email protected]6c6ea172010-07-27 20:04:032302 };
2303
Ryan Sleevib8d7ea02018-05-07 20:01:012304 SequencedSocketData data(reads, writes);
[email protected]6c6ea172010-07-27 20:04:032305
Bence Békydb3cf652017-10-10 15:22:102306 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]6c6ea172010-07-27 20:04:032307 helper.RunPreTestSetup();
mmenke666a6fea2015-12-19 04:16:332308 helper.AddData(&data);
[email protected]6c6ea172010-07-27 20:04:032309 HttpNetworkTransaction* trans = helper.trans();
2310
[email protected]49639fa2011-12-20 23:22:412311 TestCompletionCallback callback;
[email protected]6c6ea172010-07-27 20:04:032312
Bence Békydb3cf652017-10-10 15:22:102313 int rv = trans->Start(&request_, callback.callback(), log_);
robpercival214763f2016-07-01 23:27:012314 EXPECT_THAT(callback.GetResult(rv), IsOk());
[email protected]6c6ea172010-07-27 20:04:032315
[email protected]3b7828432010-08-18 18:33:272316 helper.ResetTrans();
mmenke666a6fea2015-12-19 04:16:332317 base::RunLoop().RunUntilIdle();
[email protected]3b7828432010-08-18 18:33:272318
[email protected]6c6ea172010-07-27 20:04:032319 helper.VerifyDataConsumed();
2320}
2321
[email protected]b278eb72010-07-09 20:17:002322// Verify that the client can correctly deal with the user callback attempting
2323// to start another transaction on a session that is closing down. See
2324// http://crbug.com/47455
bncd16676a2016-07-20 16:23:012325TEST_F(SpdyNetworkTransactionTest, StartTransactionOnReadCallback) {
Ryan Hamilton0239aac2018-05-19 00:03:132326 spdy::SpdySerializedFrame req(
2327 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
bncdf80d44fd2016-07-15 20:27:412328 MockWrite writes[] = {CreateMockWrite(req)};
bnceb9aa7112017-01-05 01:03:462329 MockWrite writes2[] = {CreateMockWrite(req, 0),
2330 MockWrite(SYNCHRONOUS, ERR_IO_PENDING, 3)};
[email protected]b278eb72010-07-09 20:17:002331
[email protected]cbdd73162013-03-18 23:27:332332 // The indicated length of this frame is longer than its actual length. When
2333 // the session receives an empty frame after this one, it shuts down the
[email protected]b278eb72010-07-09 20:17:002334 // session, and calls the read callback with the incomplete data.
Avi Drissman13fc8932015-12-20 04:40:462335 const uint8_t kGetBodyFrame2[] = {
2336 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00,
2337 0x07, 'h', 'e', 'l', 'l', 'o', '!',
[email protected]b278eb72010-07-09 20:17:002338 };
2339
Ryan Hamilton0239aac2018-05-19 00:03:132340 spdy::SpdySerializedFrame resp(
2341 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
[email protected]b278eb72010-07-09 20:17:002342 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:412343 CreateMockRead(resp, 1),
rch32320842015-05-16 15:57:092344 MockRead(ASYNC, ERR_IO_PENDING, 2), // Force a pause
2345 MockRead(ASYNC, reinterpret_cast<const char*>(kGetBodyFrame2),
Avi Drissman4365a4782018-12-28 19:26:242346 base::size(kGetBodyFrame2), 3),
rch32320842015-05-16 15:57:092347 MockRead(ASYNC, ERR_IO_PENDING, 4), // Force a pause
Raul Tambre94493c652019-03-11 17:18:352348 MockRead(ASYNC, nullptr, 0, 5), // EOF
[email protected]b278eb72010-07-09 20:17:002349 };
2350 MockRead reads2[] = {
Raul Tambre94493c652019-03-11 17:18:352351 CreateMockRead(resp, 1), MockRead(ASYNC, nullptr, 0, 2), // EOF
[email protected]b278eb72010-07-09 20:17:002352 };
2353
Ryan Sleevib8d7ea02018-05-07 20:01:012354 SequencedSocketData data(reads, writes);
2355 SequencedSocketData data2(reads2, writes2);
[email protected]3caf5542010-07-16 15:19:472356
Bence Békydb3cf652017-10-10 15:22:102357 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]e3ebba0f2010-08-05 17:59:582358 helper.RunPreTestSetup();
[email protected]dd54bd82012-07-19 23:44:572359 helper.AddData(&data);
2360 helper.AddData(&data2);
[email protected]3caf5542010-07-16 15:19:472361 HttpNetworkTransaction* trans = helper.trans();
[email protected]b278eb72010-07-09 20:17:002362
2363 // Start the transaction with basic parameters.
[email protected]49639fa2011-12-20 23:22:412364 TestCompletionCallback callback;
Bence Békydb3cf652017-10-10 15:22:102365 int rv = trans->Start(&request_, callback.callback(), log_);
robpercival214763f2016-07-01 23:27:012366 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]b278eb72010-07-09 20:17:002367 rv = callback.WaitForResult();
2368
[email protected]b278eb72010-07-09 20:17:002369 const int kSize = 3000;
Victor Costan9c7302b2018-08-27 16:39:442370 scoped_refptr<IOBuffer> buf = base::MakeRefCounted<IOBuffer>(kSize);
[email protected]49639fa2011-12-20 23:22:412371 rv = trans->Read(
rchebf12982015-04-10 01:15:002372 buf.get(), kSize,
Yannic Bonenberger00e09842019-08-31 20:46:192373 base::BindOnce(&SpdyNetworkTransactionTest::StartTransactionCallback,
2374 helper.session(), default_url_, log_));
robpercival214763f2016-07-01 23:27:012375 ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]3caf5542010-07-16 15:19:472376 // This forces an err_IO_pending, which sets the callback.
mmenkee24011922015-12-17 22:12:592377 data.Resume();
2378 data.RunUntilPaused();
2379
[email protected]3caf5542010-07-16 15:19:472380 // This finishes the read.
mmenkee24011922015-12-17 22:12:592381 data.Resume();
2382 base::RunLoop().RunUntilIdle();
[email protected]3caf5542010-07-16 15:19:472383 helper.VerifyDataConsumed();
[email protected]b278eb72010-07-09 20:17:002384}
2385
Mostyn Bramley-Moore699c5312018-05-01 10:48:092386// Verify that the client can correctly deal with the user callback deleting
2387// the transaction. Failures will usually be flagged by thread and/or memory
2388// checking tools. See http://crbug.com/46925
bncd16676a2016-07-20 16:23:012389TEST_F(SpdyNetworkTransactionTest, DeleteSessionOnReadCallback) {
Ryan Hamilton0239aac2018-05-19 00:03:132390 spdy::SpdySerializedFrame req(
2391 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
bncdf80d44fd2016-07-15 20:27:412392 MockWrite writes[] = {CreateMockWrite(req, 0)};
[email protected]9be804c82010-06-24 17:59:462393
Ryan Hamilton0239aac2018-05-19 00:03:132394 spdy::SpdySerializedFrame resp(
2395 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
2396 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]9be804c82010-06-24 17:59:462397 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:412398 CreateMockRead(resp, 1),
Raul Tambre94493c652019-03-11 17:18:352399 MockRead(ASYNC, ERR_IO_PENDING, 2), // Force a pause
2400 CreateMockRead(body, 3), MockRead(ASYNC, nullptr, 0, 4), // EOF
[email protected]9be804c82010-06-24 17:59:462401 };
2402
Ryan Sleevib8d7ea02018-05-07 20:01:012403 SequencedSocketData data(reads, writes);
[email protected]3caf5542010-07-16 15:19:472404
Bence Békydb3cf652017-10-10 15:22:102405 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]3caf5542010-07-16 15:19:472406 helper.RunPreTestSetup();
[email protected]dd54bd82012-07-19 23:44:572407 helper.AddData(&data);
[email protected]3caf5542010-07-16 15:19:472408 HttpNetworkTransaction* trans = helper.trans();
[email protected]9be804c82010-06-24 17:59:462409
2410 // Start the transaction with basic parameters.
[email protected]49639fa2011-12-20 23:22:412411 TestCompletionCallback callback;
Bence Békydb3cf652017-10-10 15:22:102412 int rv = trans->Start(&request_, callback.callback(), log_);
robpercival214763f2016-07-01 23:27:012413 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]9be804c82010-06-24 17:59:462414 rv = callback.WaitForResult();
2415
2416 // Setup a user callback which will delete the session, and clear out the
2417 // memory holding the stream object. Note that the callback deletes trans.
[email protected]9be804c82010-06-24 17:59:462418 const int kSize = 3000;
Victor Costan9c7302b2018-08-27 16:39:442419 scoped_refptr<IOBuffer> buf = base::MakeRefCounted<IOBuffer>(kSize);
[email protected]49639fa2011-12-20 23:22:412420 rv = trans->Read(
Yannic Bonenberger00e09842019-08-31 20:46:192421 buf.get(), kSize,
2422 base::BindOnce(&SpdyNetworkTransactionTest::DeleteSessionCallback,
2423 base::Unretained(&helper)));
robpercival214763f2016-07-01 23:27:012424 ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
mmenkee24011922015-12-17 22:12:592425 data.Resume();
[email protected]9be804c82010-06-24 17:59:462426
2427 // Finish running rest of tasks.
[email protected]fc9d88472013-08-14 02:31:172428 base::RunLoop().RunUntilIdle();
[email protected]3caf5542010-07-16 15:19:472429 helper.VerifyDataConsumed();
[email protected]9be804c82010-06-24 17:59:462430}
2431
allada71b2efb2016-09-09 04:57:482432TEST_F(SpdyNetworkTransactionTest, TestRawHeaderSizeSuccessfullRequest) {
Ryan Hamilton0239aac2018-05-19 00:03:132433 spdy::SpdyHeaderBlock headers(
2434 spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
allada71b2efb2016-09-09 04:57:482435 headers["user-agent"] = "";
2436 headers["accept-encoding"] = "gzip, deflate";
2437
Ryan Hamilton0239aac2018-05-19 00:03:132438 spdy::SpdySerializedFrame req(
allada71b2efb2016-09-09 04:57:482439 spdy_util_.ConstructSpdyHeaders(1, std::move(headers), LOWEST, true));
2440 MockWrite writes[] = {
2441 CreateMockWrite(req, 0),
2442 };
2443
Ryan Hamilton0239aac2018-05-19 00:03:132444 spdy::SpdySerializedFrame resp(
2445 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
allada71b2efb2016-09-09 04:57:482446
Ryan Hamilton0239aac2018-05-19 00:03:132447 spdy::SpdySerializedFrame response_body_frame(
Bence Békyd74f4382018-02-20 18:26:192448 spdy_util_.ConstructSpdyDataFrame(1, "should not include", true));
allada71b2efb2016-09-09 04:57:482449
2450 MockRead response_headers(CreateMockRead(resp, 1));
2451 MockRead reads[] = {
2452 response_headers, CreateMockRead(response_body_frame, 2),
Raul Tambre94493c652019-03-11 17:18:352453 MockRead(ASYNC, nullptr, 0, 3) // EOF
allada71b2efb2016-09-09 04:57:482454 };
Ryan Sleevib8d7ea02018-05-07 20:01:012455 SequencedSocketData data(reads, writes);
allada71b2efb2016-09-09 04:57:482456
2457 TestDelegate delegate;
2458 SpdyURLRequestContext spdy_url_request_context;
2459 TestNetworkDelegate network_delegate;
2460 spdy_url_request_context.set_network_delegate(&network_delegate);
2461 SSLSocketDataProvider ssl_data(ASYNC, OK);
2462 ssl_data.next_proto = kProtoHTTP2;
2463
2464 std::unique_ptr<URLRequest> request(spdy_url_request_context.CreateRequest(
rhalavati9ebaba7e2017-04-27 06:16:292465 GURL(kDefaultUrl), DEFAULT_PRIORITY, &delegate,
2466 TRAFFIC_ANNOTATION_FOR_TESTS));
allada71b2efb2016-09-09 04:57:482467 spdy_url_request_context.socket_factory().AddSSLSocketDataProvider(&ssl_data);
2468 spdy_url_request_context.socket_factory().AddSocketDataProvider(&data);
2469
2470 request->Start();
2471 base::RunLoop().Run();
2472
2473 EXPECT_LT(0, request->GetTotalSentBytes());
2474 EXPECT_LT(0, request->GetTotalReceivedBytes());
allada71b2efb2016-09-09 04:57:482475 EXPECT_EQ(response_headers.data_len, request->raw_header_size());
2476 EXPECT_TRUE(data.AllReadDataConsumed());
2477 EXPECT_TRUE(data.AllWriteDataConsumed());
2478}
2479
2480TEST_F(SpdyNetworkTransactionTest,
2481 TestRawHeaderSizeSuccessfullPushHeadersFirst) {
Ryan Hamilton0239aac2018-05-19 00:03:132482 spdy::SpdyHeaderBlock headers(
2483 spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
allada71b2efb2016-09-09 04:57:482484 headers["user-agent"] = "";
2485 headers["accept-encoding"] = "gzip, deflate";
2486
Ryan Hamilton0239aac2018-05-19 00:03:132487 spdy::SpdySerializedFrame req(
allada71b2efb2016-09-09 04:57:482488 spdy_util_.ConstructSpdyHeaders(1, std::move(headers), LOWEST, true));
Ryan Hamilton0239aac2018-05-19 00:03:132489 spdy::SpdySerializedFrame priority(
tombergan5d22c182017-01-11 02:05:352490 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true));
allada71b2efb2016-09-09 04:57:482491 MockWrite writes[] = {
tombergan5d22c182017-01-11 02:05:352492 CreateMockWrite(req, 0), CreateMockWrite(priority, 2),
allada71b2efb2016-09-09 04:57:482493 };
2494
Ryan Hamilton0239aac2018-05-19 00:03:132495 spdy::SpdySerializedFrame resp(
2496 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
2497 spdy::SpdySerializedFrame response_body_frame(
Bence Békyd74f4382018-02-20 18:26:192498 spdy_util_.ConstructSpdyDataFrame(1, "should not include", true));
allada71b2efb2016-09-09 04:57:482499
Ryan Hamilton0239aac2018-05-19 00:03:132500 spdy::SpdyHeaderBlock push_headers;
bncc055fa32017-06-19 13:44:422501 push_headers[":method"] = "GET";
Bence Béky4e83f492018-05-13 23:14:252502 spdy_util_.AddUrlToHeaderBlock(std::string(kDefaultUrl) + "b.dat",
allada71b2efb2016-09-09 04:57:482503 &push_headers);
2504
Ryan Hamilton0239aac2018-05-19 00:03:132505 spdy::SpdySerializedFrame push_init_frame(
Bence Békyf1d78522018-01-11 01:16:502506 spdy_util_.ConstructSpdyPushPromise(1, 2, std::move(push_headers)));
allada71b2efb2016-09-09 04:57:482507
Ryan Hamilton0239aac2018-05-19 00:03:132508 spdy::SpdySerializedFrame push_headers_frame(
allada71b2efb2016-09-09 04:57:482509 spdy_util_.ConstructSpdyPushHeaders(2, nullptr, 0));
2510
Ryan Hamilton0239aac2018-05-19 00:03:132511 spdy::SpdySerializedFrame push_body_frame(
Bence Békyd74f4382018-02-20 18:26:192512 spdy_util_.ConstructSpdyDataFrame(2, "should not include either", false));
allada71b2efb2016-09-09 04:57:482513
2514 MockRead push_init_read(CreateMockRead(push_init_frame, 1));
tombergan5d22c182017-01-11 02:05:352515 MockRead response_headers(CreateMockRead(resp, 5));
allada71b2efb2016-09-09 04:57:482516 // raw_header_size() will contain the size of the push promise frame
2517 // initialization.
2518 int expected_response_headers_size =
2519 response_headers.data_len + push_init_read.data_len;
2520
2521 MockRead reads[] = {
2522 push_init_read,
tombergan5d22c182017-01-11 02:05:352523 CreateMockRead(push_headers_frame, 3),
2524 CreateMockRead(push_body_frame, 4),
allada71b2efb2016-09-09 04:57:482525 response_headers,
tombergan5d22c182017-01-11 02:05:352526 CreateMockRead(response_body_frame, 6),
2527 MockRead(ASYNC, 0, 7) // EOF
allada71b2efb2016-09-09 04:57:482528 };
2529
Ryan Sleevib8d7ea02018-05-07 20:01:012530 SequencedSocketData data(reads, writes);
allada71b2efb2016-09-09 04:57:482531
2532 TestDelegate delegate;
2533 SpdyURLRequestContext spdy_url_request_context;
2534 TestNetworkDelegate network_delegate;
2535 spdy_url_request_context.set_network_delegate(&network_delegate);
2536 SSLSocketDataProvider ssl_data(ASYNC, OK);
2537 ssl_data.next_proto = kProtoHTTP2;
2538
2539 std::unique_ptr<URLRequest> request(spdy_url_request_context.CreateRequest(
rhalavati9ebaba7e2017-04-27 06:16:292540 GURL(kDefaultUrl), DEFAULT_PRIORITY, &delegate,
2541 TRAFFIC_ANNOTATION_FOR_TESTS));
allada71b2efb2016-09-09 04:57:482542 spdy_url_request_context.socket_factory().AddSSLSocketDataProvider(&ssl_data);
2543 spdy_url_request_context.socket_factory().AddSocketDataProvider(&data);
2544
2545 request->Start();
2546 base::RunLoop().Run();
2547
2548 EXPECT_LT(0, request->GetTotalSentBytes());
2549 EXPECT_LT(0, request->GetTotalReceivedBytes());
allada71b2efb2016-09-09 04:57:482550 EXPECT_EQ(expected_response_headers_size, request->raw_header_size());
2551 EXPECT_TRUE(data.AllReadDataConsumed());
2552 EXPECT_TRUE(data.AllWriteDataConsumed());
2553}
2554
bncf2ba58832017-06-07 00:22:282555TEST_F(SpdyNetworkTransactionTest, RedirectGetRequest) {
2556 SpdyURLRequestContext spdy_url_request_context;
Matt Menke5062be22019-05-01 17:50:242557 // Use a different port to avoid trying to reuse the initial H2 session.
2558 const char kRedirectUrl[] = "https://www.foo.com:8080/index.php";
[email protected]e3ebba0f2010-08-05 17:59:582559
bncf2ba58832017-06-07 00:22:282560 SSLSocketDataProvider ssl_provider0(ASYNC, OK);
2561 ssl_provider0.next_proto = kProtoHTTP2;
2562 spdy_url_request_context.socket_factory().AddSSLSocketDataProvider(
2563 &ssl_provider0);
[email protected]e3ebba0f2010-08-05 17:59:582564
Ryan Hamilton0239aac2018-05-19 00:03:132565 spdy::SpdyHeaderBlock headers0(
2566 spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
bncf2ba58832017-06-07 00:22:282567 headers0["user-agent"] = "";
2568 headers0["accept-encoding"] = "gzip, deflate";
bnc086b39e12016-06-24 13:05:262569
Ryan Hamilton0239aac2018-05-19 00:03:132570 spdy::SpdySerializedFrame req0(
bncf2ba58832017-06-07 00:22:282571 spdy_util_.ConstructSpdyHeaders(1, std::move(headers0), LOWEST, true));
Ryan Hamilton0239aac2018-05-19 00:03:132572 spdy::SpdySerializedFrame rst(
2573 spdy_util_.ConstructSpdyRstStream(1, spdy::ERROR_CODE_CANCEL));
Shivani Sharmac18f9762017-10-23 16:43:232574 MockWrite writes0[] = {CreateMockWrite(req0, 0), CreateMockWrite(rst, 2)};
bnc086b39e12016-06-24 13:05:262575
Matt Menke5062be22019-05-01 17:50:242576 const char* const kExtraHeaders[] = {"location", kRedirectUrl};
Ryan Hamilton0239aac2018-05-19 00:03:132577 spdy::SpdySerializedFrame resp0(spdy_util_.ConstructSpdyReplyError(
Avi Drissman4365a4782018-12-28 19:26:242578 "301", kExtraHeaders, base::size(kExtraHeaders) / 2, 1));
Shivani Sharmac18f9762017-10-23 16:43:232579 MockRead reads0[] = {CreateMockRead(resp0, 1), MockRead(ASYNC, 0, 3)};
[email protected]e3ebba0f2010-08-05 17:59:582580
Ryan Sleevib8d7ea02018-05-07 20:01:012581 SequencedSocketData data0(reads0, writes0);
bncf2ba58832017-06-07 00:22:282582 spdy_url_request_context.socket_factory().AddSocketDataProvider(&data0);
[email protected]e3ebba0f2010-08-05 17:59:582583
bncf2ba58832017-06-07 00:22:282584 SSLSocketDataProvider ssl_provider1(ASYNC, OK);
2585 ssl_provider1.next_proto = kProtoHTTP2;
2586 spdy_url_request_context.socket_factory().AddSSLSocketDataProvider(
2587 &ssl_provider1);
[email protected]513963e2013-06-15 01:53:042588
bncf2ba58832017-06-07 00:22:282589 SpdyTestUtil spdy_util1;
Ryan Hamilton0239aac2018-05-19 00:03:132590 spdy::SpdyHeaderBlock headers1(
Matt Menke5062be22019-05-01 17:50:242591 spdy_util1.ConstructGetHeaderBlock(kRedirectUrl));
bncf2ba58832017-06-07 00:22:282592 headers1["user-agent"] = "";
2593 headers1["accept-encoding"] = "gzip, deflate";
Ryan Hamilton0239aac2018-05-19 00:03:132594 spdy::SpdySerializedFrame req1(
bncf2ba58832017-06-07 00:22:282595 spdy_util1.ConstructSpdyHeaders(1, std::move(headers1), LOWEST, true));
2596 MockWrite writes1[] = {CreateMockWrite(req1, 0)};
[email protected]e3ebba0f2010-08-05 17:59:582597
Ryan Hamilton0239aac2018-05-19 00:03:132598 spdy::SpdySerializedFrame resp1(
2599 spdy_util1.ConstructSpdyGetReply(nullptr, 0, 1));
2600 spdy::SpdySerializedFrame body1(spdy_util1.ConstructSpdyDataFrame(1, true));
bncf2ba58832017-06-07 00:22:282601 MockRead reads1[] = {CreateMockRead(resp1, 1), CreateMockRead(body1, 2),
2602 MockRead(ASYNC, 0, 3)};
2603
Ryan Sleevib8d7ea02018-05-07 20:01:012604 SequencedSocketData data1(reads1, writes1);
bncf2ba58832017-06-07 00:22:282605 spdy_url_request_context.socket_factory().AddSocketDataProvider(&data1);
2606
2607 TestDelegate delegate;
bncf2ba58832017-06-07 00:22:282608
2609 std::unique_ptr<URLRequest> request = spdy_url_request_context.CreateRequest(
2610 default_url_, DEFAULT_PRIORITY, &delegate, TRAFFIC_ANNOTATION_FOR_TESTS);
2611 request->Start();
Wez0e717112018-06-18 23:09:222612 delegate.RunUntilRedirect();
bncf2ba58832017-06-07 00:22:282613
2614 EXPECT_EQ(1, delegate.received_redirect_count());
2615
Arthur Sonzognib8465ff72019-01-04 18:44:352616 request->FollowDeferredRedirect(base::nullopt /* removed_headers */,
2617 base::nullopt /* modified_headers */);
Wez0e717112018-06-18 23:09:222618 delegate.RunUntilComplete();
bncf2ba58832017-06-07 00:22:282619
2620 EXPECT_EQ(1, delegate.response_started_count());
2621 EXPECT_FALSE(delegate.received_data_before_response());
2622 EXPECT_THAT(delegate.request_status(), IsOk());
2623 EXPECT_EQ("hello!", delegate.data_received());
2624
Wez0e717112018-06-18 23:09:222625 // Pump the message loop to allow read data to be consumed.
2626 base::RunLoop().RunUntilIdle();
2627
bncf2ba58832017-06-07 00:22:282628 EXPECT_TRUE(data0.AllReadDataConsumed());
2629 EXPECT_TRUE(data0.AllWriteDataConsumed());
2630 EXPECT_TRUE(data1.AllReadDataConsumed());
2631 EXPECT_TRUE(data1.AllWriteDataConsumed());
[email protected]e3ebba0f2010-08-05 17:59:582632}
2633
bncf2ba58832017-06-07 00:22:282634TEST_F(SpdyNetworkTransactionTest, RedirectServerPush) {
bncf2ba58832017-06-07 00:22:282635 const char redirected_url[] = "https://www.foo.com/index.php";
2636 SpdyURLRequestContext spdy_url_request_context;
[email protected]3a8d6852011-03-11 23:43:442637
bncf2ba58832017-06-07 00:22:282638 SSLSocketDataProvider ssl_provider0(ASYNC, OK);
2639 ssl_provider0.next_proto = kProtoHTTP2;
Ryan Sleevi4f832092017-11-21 23:25:492640 ssl_provider0.ssl_info.cert =
bncf2ba58832017-06-07 00:22:282641 ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem");
Ryan Sleevi4f832092017-11-21 23:25:492642 ASSERT_TRUE(ssl_provider0.ssl_info.cert);
bncf2ba58832017-06-07 00:22:282643 spdy_url_request_context.socket_factory().AddSSLSocketDataProvider(
2644 &ssl_provider0);
2645
Ryan Hamilton0239aac2018-05-19 00:03:132646 spdy::SpdyHeaderBlock headers0(
2647 spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
bncf2ba58832017-06-07 00:22:282648 headers0["user-agent"] = "";
2649 headers0["accept-encoding"] = "gzip, deflate";
Ryan Hamilton0239aac2018-05-19 00:03:132650 spdy::SpdySerializedFrame req0(
bncf2ba58832017-06-07 00:22:282651 spdy_util_.ConstructSpdyHeaders(1, std::move(headers0), LOWEST, true));
Ryan Hamilton0239aac2018-05-19 00:03:132652 spdy::SpdySerializedFrame priority(
bncf2ba58832017-06-07 00:22:282653 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true));
Ryan Hamilton0239aac2018-05-19 00:03:132654 spdy::SpdySerializedFrame rst(
2655 spdy_util_.ConstructSpdyRstStream(2, spdy::ERROR_CODE_CANCEL));
bncf2ba58832017-06-07 00:22:282656 MockWrite writes[] = {CreateMockWrite(req0, 0), CreateMockWrite(priority, 3),
2657 CreateMockWrite(rst, 5)};
[email protected]3a8d6852011-03-11 23:43:442658
Ryan Hamilton0239aac2018-05-19 00:03:132659 spdy::SpdySerializedFrame resp0(
2660 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
2661 spdy::SpdySerializedFrame push(spdy_util_.ConstructSpdyPush(
Bence Békyd2df6c1c82018-04-20 22:52:012662 nullptr, 0, 2, 1, kPushedUrl, "301", redirected_url));
Ryan Hamilton0239aac2018-05-19 00:03:132663 spdy::SpdySerializedFrame body0(spdy_util_.ConstructSpdyDataFrame(1, true));
bncf2ba58832017-06-07 00:22:282664 MockRead reads[] = {CreateMockRead(resp0, 1), CreateMockRead(push, 2),
2665 CreateMockRead(body0, 4), MockRead(ASYNC, 0, 6)};
[email protected]e3ebba0f2010-08-05 17:59:582666
Ryan Sleevib8d7ea02018-05-07 20:01:012667 SequencedSocketData data0(reads, writes);
bncf2ba58832017-06-07 00:22:282668 spdy_url_request_context.socket_factory().AddSocketDataProvider(&data0);
[email protected]e3ebba0f2010-08-05 17:59:582669
bncf2ba58832017-06-07 00:22:282670 SSLSocketDataProvider ssl_provider1(ASYNC, OK);
2671 ssl_provider1.next_proto = kProtoHTTP2;
2672 spdy_url_request_context.socket_factory().AddSSLSocketDataProvider(
2673 &ssl_provider1);
[email protected]e3ebba0f2010-08-05 17:59:582674
bncf2ba58832017-06-07 00:22:282675 SpdyTestUtil spdy_util1;
Ryan Hamilton0239aac2018-05-19 00:03:132676 spdy::SpdyHeaderBlock headers1(
2677 spdy_util1.ConstructGetHeaderBlock(redirected_url));
bncf2ba58832017-06-07 00:22:282678 headers1["user-agent"] = "";
2679 headers1["accept-encoding"] = "gzip, deflate";
Ryan Hamilton0239aac2018-05-19 00:03:132680 spdy::SpdySerializedFrame req1(
bncf2ba58832017-06-07 00:22:282681 spdy_util1.ConstructSpdyHeaders(1, std::move(headers1), LOWEST, true));
2682 MockWrite writes1[] = {CreateMockWrite(req1, 0)};
[email protected]e3ebba0f2010-08-05 17:59:582683
Ryan Hamilton0239aac2018-05-19 00:03:132684 spdy::SpdySerializedFrame resp1(
2685 spdy_util1.ConstructSpdyGetReply(nullptr, 0, 1));
2686 spdy::SpdySerializedFrame body1(spdy_util1.ConstructSpdyDataFrame(1, true));
bncf2ba58832017-06-07 00:22:282687 MockRead reads1[] = {CreateMockRead(resp1, 1), CreateMockRead(body1, 2),
2688 MockRead(ASYNC, 0, 3)};
[email protected]e3ebba0f2010-08-05 17:59:582689
Ryan Sleevib8d7ea02018-05-07 20:01:012690 SequencedSocketData data1(reads1, writes1);
bncf2ba58832017-06-07 00:22:282691 spdy_url_request_context.socket_factory().AddSocketDataProvider(&data1);
[email protected]e3ebba0f2010-08-05 17:59:582692
bncf2ba58832017-06-07 00:22:282693 TestDelegate delegate0;
2694 std::unique_ptr<URLRequest> request = spdy_url_request_context.CreateRequest(
2695 default_url_, DEFAULT_PRIORITY, &delegate0, TRAFFIC_ANNOTATION_FOR_TESTS);
2696
2697 request->Start();
Wez0e717112018-06-18 23:09:222698 delegate0.RunUntilComplete();
bncf2ba58832017-06-07 00:22:282699
2700 EXPECT_EQ(0, delegate0.received_redirect_count());
2701 EXPECT_EQ("hello!", delegate0.data_received());
2702
2703 TestDelegate delegate1;
2704 std::unique_ptr<URLRequest> request1 = spdy_url_request_context.CreateRequest(
Bence Békyd2df6c1c82018-04-20 22:52:012705 GURL(kPushedUrl), DEFAULT_PRIORITY, &delegate1,
2706 TRAFFIC_ANNOTATION_FOR_TESTS);
bncf2ba58832017-06-07 00:22:282707
bncf2ba58832017-06-07 00:22:282708 request1->Start();
Wez0e717112018-06-18 23:09:222709 delegate1.RunUntilRedirect();
bncf2ba58832017-06-07 00:22:282710 EXPECT_EQ(1, delegate1.received_redirect_count());
2711
Arthur Sonzognib8465ff72019-01-04 18:44:352712 request1->FollowDeferredRedirect(base::nullopt /* removed_headers */,
2713 base::nullopt /* modified_headers */);
Wez0e717112018-06-18 23:09:222714 delegate1.RunUntilComplete();
bncf2ba58832017-06-07 00:22:282715 EXPECT_EQ(1, delegate1.response_started_count());
2716 EXPECT_FALSE(delegate1.received_data_before_response());
2717 EXPECT_EQ(OK, delegate1.request_status());
2718 EXPECT_EQ("hello!", delegate1.data_received());
2719
Wez0e717112018-06-18 23:09:222720 // Pump the message loop to allow read data to be consumed.
2721 base::RunLoop().RunUntilIdle();
2722
bncf2ba58832017-06-07 00:22:282723 EXPECT_TRUE(data0.AllReadDataConsumed());
2724 EXPECT_TRUE(data0.AllWriteDataConsumed());
2725 EXPECT_TRUE(data1.AllReadDataConsumed());
2726 EXPECT_TRUE(data1.AllWriteDataConsumed());
[email protected]e3ebba0f2010-08-05 17:59:582727}
2728
bncd16676a2016-07-20 16:23:012729TEST_F(SpdyNetworkTransactionTest, ServerPushSingleDataFrame) {
Ryan Hamilton0239aac2018-05-19 00:03:132730 spdy::SpdySerializedFrame stream1_syn(
Bence Béky27ad0a12018-02-08 00:35:482731 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
Ryan Hamilton0239aac2018-05-19 00:03:132732 spdy::SpdySerializedFrame stream2_priority(
tombergan5d22c182017-01-11 02:05:352733 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true));
[email protected]e3ebba0f2010-08-05 17:59:582734 MockWrite writes[] = {
tombergan5d22c182017-01-11 02:05:352735 CreateMockWrite(stream1_syn, 0), CreateMockWrite(stream2_priority, 3),
[email protected]e3ebba0f2010-08-05 17:59:582736 };
2737
Ryan Hamilton0239aac2018-05-19 00:03:132738 spdy::SpdySerializedFrame stream1_reply(
tombergan5d22c182017-01-11 02:05:352739 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
Ryan Hamilton0239aac2018-05-19 00:03:132740 spdy::SpdySerializedFrame stream2_syn(
Bence Békyd2df6c1c82018-04-20 22:52:012741 spdy_util_.ConstructSpdyPush(nullptr, 0, 2, 1, kPushedUrl));
Ryan Hamilton0239aac2018-05-19 00:03:132742 spdy::SpdySerializedFrame stream1_body(
2743 spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]8a0fc822013-06-27 20:52:432744 const char kPushedData[] = "pushed";
Ryan Hamilton0239aac2018-05-19 00:03:132745 spdy::SpdySerializedFrame stream2_body(
Bence Békyd74f4382018-02-20 18:26:192746 spdy_util_.ConstructSpdyDataFrame(2, kPushedData, true));
[email protected]e3ebba0f2010-08-05 17:59:582747 MockRead reads[] = {
tombergan5d22c182017-01-11 02:05:352748 CreateMockRead(stream1_reply, 1), CreateMockRead(stream2_syn, 2),
2749 CreateMockRead(stream1_body, 4), CreateMockRead(stream2_body, 5),
2750 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 6), // Force a pause
[email protected]e3ebba0f2010-08-05 17:59:582751 };
2752
2753 HttpResponseInfo response;
2754 HttpResponseInfo response2;
Bence Béky4e83f492018-05-13 23:14:252755 std::string expected_push_result("pushed");
Ryan Sleevib8d7ea02018-05-07 20:01:012756 SequencedSocketData data(reads, writes);
[email protected]dd54bd82012-07-19 23:44:572757 RunServerPushTest(&data,
[email protected]d08358502010-12-03 22:04:032758 &response,
2759 &response2,
2760 expected_push_result);
[email protected]e3ebba0f2010-08-05 17:59:582761
bnc42331402016-07-25 13:36:152762 // Verify the response headers.
wezca1070932016-05-26 20:30:522763 EXPECT_TRUE(response.headers);
bnc84e7fb52015-12-02 11:50:022764 EXPECT_EQ("HTTP/1.1 200", response.headers->GetStatusLine());
[email protected]e3ebba0f2010-08-05 17:59:582765
2766 // Verify the pushed stream.
wezca1070932016-05-26 20:30:522767 EXPECT_TRUE(response2.headers);
bnccdc749f2016-01-27 16:39:042768 EXPECT_EQ("HTTP/1.1 200", response2.headers->GetStatusLine());
[email protected]e3ebba0f2010-08-05 17:59:582769}
2770
Bence Béky02b906a2018-07-18 21:03:392771// When server push is disabled by
2772// HttpNetworkSession::initial_settings[SETTINGS_ENABLE_PUSH] = 0, verify that
2773// such a setting is sent out in the initial SETTINGS frame, and if the server
2774// creates a pushed stream despite of this, it is immediately reset.
2775TEST_F(SpdyNetworkTransactionTest, ServerPushDisabled) {
Bence Békyda83e052018-07-20 01:03:322776 base::HistogramTester histogram_tester;
2777
Bence Béky02b906a2018-07-18 21:03:392778 spdy::SpdySerializedFrame preface(
2779 const_cast<char*>(spdy::kHttp2ConnectionHeaderPrefix),
2780 spdy::kHttp2ConnectionHeaderPrefixSize,
2781 /* owns_buffer = */ false);
2782
2783 spdy::SettingsMap initial_settings;
2784 initial_settings[spdy::SETTINGS_HEADER_TABLE_SIZE] = kSpdyMaxHeaderTableSize;
2785 initial_settings[spdy::SETTINGS_ENABLE_PUSH] = 0;
2786 initial_settings[spdy::SETTINGS_MAX_CONCURRENT_STREAMS] =
2787 kSpdyMaxConcurrentPushedStreams;
Bence Béky6cee52f2019-10-24 16:52:332788 initial_settings[spdy::SETTINGS_MAX_HEADER_LIST_SIZE] =
2789 kSpdyMaxHeaderListSize;
Bence Béky02b906a2018-07-18 21:03:392790 spdy::SpdySerializedFrame initial_settings_frame(
2791 spdy_util_.ConstructSpdySettings(initial_settings));
2792
2793 spdy::SpdySerializedFrame req(
2794 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
2795 spdy::SpdySerializedFrame rst(
2796 spdy_util_.ConstructSpdyRstStream(2, spdy::ERROR_CODE_REFUSED_STREAM));
2797
2798 MockWrite writes[] = {CreateMockWrite(preface, 0),
2799 CreateMockWrite(initial_settings_frame, 1),
2800 CreateMockWrite(req, 2), CreateMockWrite(rst, 5)};
2801
2802 spdy::SpdySerializedFrame reply(
2803 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
2804 spdy::SpdySerializedFrame push(
2805 spdy_util_.ConstructSpdyPush(nullptr, 0, 2, 1, kPushedUrl));
2806 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
2807 MockRead reads[] = {CreateMockRead(reply, 3), CreateMockRead(push, 4),
2808 CreateMockRead(body, 6), MockRead(ASYNC, OK, 7)};
2809
2810 SequencedSocketData data(reads, writes);
2811
2812 auto session_deps = std::make_unique<SpdySessionDependencies>();
2813 session_deps->http2_settings[spdy::SETTINGS_ENABLE_PUSH] = 0;
2814 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
2815 std::move(session_deps));
2816
2817 SpdySessionPool* spdy_session_pool = helper.session()->spdy_session_pool();
2818 SpdySessionPoolPeer pool_peer(spdy_session_pool);
2819 pool_peer.SetEnableSendingInitialData(true);
2820
2821 helper.RunToCompletion(&data);
Bence Békyda83e052018-07-20 01:03:322822
2823 histogram_tester.ExpectBucketCount(
2824 "Net.SpdyPushedStreamFate",
2825 static_cast<int>(SpdyPushedStreamFate::kPushDisabled), 1);
2826 histogram_tester.ExpectTotalCount("Net.SpdyPushedStreamFate", 1);
Bence Béky02b906a2018-07-18 21:03:392827}
2828
Bence Béky5b1e4ce72018-01-11 14:55:152829TEST_F(SpdyNetworkTransactionTest, ServerPushHeadMethod) {
Ryan Hamilton0239aac2018-05-19 00:03:132830 spdy::SpdySerializedFrame req(
2831 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
2832 spdy::SpdySerializedFrame priority(
Bence Béky5b1e4ce72018-01-11 14:55:152833 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true));
2834 MockWrite writes[] = {CreateMockWrite(req, 0), CreateMockWrite(priority, 2)};
2835
Ryan Hamilton0239aac2018-05-19 00:03:132836 spdy::SpdyHeaderBlock push_promise_header_block;
2837 push_promise_header_block[spdy::kHttp2MethodHeader] = "HEAD";
Bence Békyd2df6c1c82018-04-20 22:52:012838 spdy_util_.AddUrlToHeaderBlock(kPushedUrl, &push_promise_header_block);
Ryan Hamilton0239aac2018-05-19 00:03:132839 spdy::SpdySerializedFrame push_promise(spdy_util_.ConstructSpdyPushPromise(
Bence Béky5b1e4ce72018-01-11 14:55:152840 1, 2, std::move(push_promise_header_block)));
2841
Ryan Hamilton0239aac2018-05-19 00:03:132842 spdy::SpdyHeaderBlock push_response_headers;
2843 push_response_headers[spdy::kHttp2StatusHeader] = "200";
Bence Béky5b1e4ce72018-01-11 14:55:152844 push_response_headers["foo"] = "bar";
Ryan Hamilton0239aac2018-05-19 00:03:132845 spdy::SpdyHeadersIR headers_ir(2, std::move(push_response_headers));
2846 spdy::SpdySerializedFrame push_headers(spdy_util_.SerializeFrame(headers_ir));
Bence Béky5b1e4ce72018-01-11 14:55:152847
Ryan Hamilton0239aac2018-05-19 00:03:132848 spdy::SpdySerializedFrame resp(
2849 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
2850 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
Bence Béky5b1e4ce72018-01-11 14:55:152851 MockRead reads[] = {
2852 CreateMockRead(push_promise, 1), CreateMockRead(push_headers, 3),
2853 CreateMockRead(resp, 4), CreateMockRead(body, 5),
2854 // Do not close the connection after first request is done.
2855 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 6)};
2856
Ryan Sleevib8d7ea02018-05-07 20:01:012857 SequencedSocketData data(reads, writes);
Bence Béky5b1e4ce72018-01-11 14:55:152858
2859 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
2860 helper.RunPreTestSetup();
2861 helper.AddData(&data);
2862
2863 // Run first request. This reads PUSH_PROMISE.
2864 helper.RunDefaultTest();
2865
2866 // Request the pushed resource.
2867 HttpNetworkTransaction trans(DEFAULT_PRIORITY, helper.session());
2868 HttpRequestInfo request = CreateGetPushRequest();
2869 request.method = "HEAD";
Ramin Halavatib5e433e62018-02-07 07:41:102870 request.traffic_annotation =
2871 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
Bence Béky5b1e4ce72018-01-11 14:55:152872 TestCompletionCallback callback;
2873 int rv = trans.Start(&request, callback.callback(), log_);
2874 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
2875 rv = callback.WaitForResult();
2876 EXPECT_THAT(rv, IsOk());
2877
2878 const HttpResponseInfo* response = trans.GetResponseInfo();
2879 ASSERT_TRUE(response);
2880 EXPECT_TRUE(response->was_fetched_via_spdy);
2881 EXPECT_TRUE(response->was_alpn_negotiated);
2882 ASSERT_TRUE(response->headers);
2883 EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
2884 std::string value;
2885 EXPECT_TRUE(response->headers->GetNormalizedHeader("foo", &value));
2886 EXPECT_EQ("bar", value);
2887
2888 helper.VerifyDataConsumed();
2889}
2890
2891TEST_F(SpdyNetworkTransactionTest, ServerPushHeadDoesNotMatchGetRequest) {
Ryan Hamilton0239aac2018-05-19 00:03:132892 spdy::SpdySerializedFrame req1(
2893 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
2894 spdy::SpdySerializedFrame priority(
Bence Béky5b1e4ce72018-01-11 14:55:152895 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true));
2896 spdy_util_.UpdateWithStreamDestruction(1);
Ryan Hamilton0239aac2018-05-19 00:03:132897 spdy::SpdySerializedFrame req2(
2898 spdy_util_.ConstructSpdyGet(kPushedUrl, 3, LOWEST));
Bence Béky5b1e4ce72018-01-11 14:55:152899 MockWrite writes[] = {CreateMockWrite(req1, 0), CreateMockWrite(priority, 2),
2900 CreateMockWrite(req2, 6)};
2901
Ryan Hamilton0239aac2018-05-19 00:03:132902 spdy::SpdyHeaderBlock push_promise_header_block;
2903 push_promise_header_block[spdy::kHttp2MethodHeader] = "HEAD";
Bence Békyd2df6c1c82018-04-20 22:52:012904 spdy_util_.AddUrlToHeaderBlock(kPushedUrl, &push_promise_header_block);
Ryan Hamilton0239aac2018-05-19 00:03:132905 spdy::SpdySerializedFrame push_promise(spdy_util_.ConstructSpdyPushPromise(
Bence Béky5b1e4ce72018-01-11 14:55:152906 1, 2, std::move(push_promise_header_block)));
2907
Ryan Hamilton0239aac2018-05-19 00:03:132908 spdy::SpdyHeaderBlock push_response_headers;
2909 push_response_headers[spdy::kHttp2StatusHeader] = "200";
Bence Béky5b1e4ce72018-01-11 14:55:152910 push_response_headers["foo"] = "bar";
Ryan Hamilton0239aac2018-05-19 00:03:132911 spdy::SpdyHeadersIR headers_ir(2, std::move(push_response_headers));
2912 spdy::SpdySerializedFrame push_headers(spdy_util_.SerializeFrame(headers_ir));
Bence Béky5b1e4ce72018-01-11 14:55:152913
Ryan Hamilton0239aac2018-05-19 00:03:132914 spdy::SpdySerializedFrame resp1(
2915 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
2916 spdy::SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true));
2917 spdy::SpdySerializedFrame resp2(
2918 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
2919 spdy::SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(3, true));
Bence Béky5b1e4ce72018-01-11 14:55:152920 MockRead reads[] = {CreateMockRead(push_promise, 1),
2921 CreateMockRead(push_headers, 3),
2922 CreateMockRead(resp1, 4),
2923 CreateMockRead(body1, 5),
2924 CreateMockRead(resp2, 7),
2925 CreateMockRead(body2, 8),
2926 MockRead(ASYNC, 0, 9)};
2927
Ryan Sleevib8d7ea02018-05-07 20:01:012928 SequencedSocketData data(reads, writes);
Bence Béky5b1e4ce72018-01-11 14:55:152929
2930 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
2931 helper.RunPreTestSetup();
2932 helper.AddData(&data);
2933
2934 // Run first request. This reads PUSH_PROMISE.
2935 helper.RunDefaultTest();
2936
2937 // Request the pushed resource.
2938 HttpNetworkTransaction trans(DEFAULT_PRIORITY, helper.session());
2939 HttpRequestInfo request = CreateGetPushRequest();
2940 TestCompletionCallback callback;
2941 int rv = trans.Start(&request, callback.callback(), log_);
2942 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
2943 rv = callback.WaitForResult();
2944 EXPECT_THAT(rv, IsOk());
2945
2946 const HttpResponseInfo* response = trans.GetResponseInfo();
2947 ASSERT_TRUE(response);
2948 EXPECT_TRUE(response->was_fetched_via_spdy);
2949 EXPECT_TRUE(response->was_alpn_negotiated);
2950 ASSERT_TRUE(response->headers);
2951 EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
2952 std::string value;
2953 EXPECT_FALSE(response->headers->GetNormalizedHeader("foo", &value));
2954 std::string result;
2955 ReadResult(&trans, &result);
2956 EXPECT_EQ("hello!", result);
2957
2958 // Read EOF.
2959 base::RunLoop().RunUntilIdle();
2960
2961 helper.VerifyDataConsumed();
2962}
2963
bncd16676a2016-07-20 16:23:012964TEST_F(SpdyNetworkTransactionTest, ServerPushSingleDataFrame2) {
Ryan Hamilton0239aac2018-05-19 00:03:132965 spdy::SpdySerializedFrame stream1_syn(
Bence Béky27ad0a12018-02-08 00:35:482966 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
Ryan Hamilton0239aac2018-05-19 00:03:132967 spdy::SpdySerializedFrame stream2_priority(
tombergan5d22c182017-01-11 02:05:352968 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true));
rch08e3aa3e2015-05-16 14:27:522969 MockWrite writes[] = {
tombergan5d22c182017-01-11 02:05:352970 CreateMockWrite(stream1_syn, 0), CreateMockWrite(stream2_priority, 3),
rch08e3aa3e2015-05-16 14:27:522971 };
[email protected]82918cc2010-08-25 17:24:502972
Ryan Hamilton0239aac2018-05-19 00:03:132973 spdy::SpdySerializedFrame stream1_reply(
tombergan5d22c182017-01-11 02:05:352974 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
Ryan Hamilton0239aac2018-05-19 00:03:132975 spdy::SpdySerializedFrame stream2_syn(
Bence Békyd2df6c1c82018-04-20 22:52:012976 spdy_util_.ConstructSpdyPush(nullptr, 0, 2, 1, kPushedUrl));
[email protected]8a0fc822013-06-27 20:52:432977 const char kPushedData[] = "pushed";
Ryan Hamilton0239aac2018-05-19 00:03:132978 spdy::SpdySerializedFrame stream2_body(
Bence Békyd74f4382018-02-20 18:26:192979 spdy_util_.ConstructSpdyDataFrame(2, kPushedData, true));
Ryan Hamilton0239aac2018-05-19 00:03:132980 spdy::SpdySerializedFrame stream1_body(
2981 spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]82918cc2010-08-25 17:24:502982 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:412983 CreateMockRead(stream1_reply, 1),
2984 CreateMockRead(stream2_syn, 2),
tombergan5d22c182017-01-11 02:05:352985 CreateMockRead(stream2_body, 4),
2986 CreateMockRead(stream1_body, 5, SYNCHRONOUS),
2987 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 6), // Force a pause
[email protected]82918cc2010-08-25 17:24:502988 };
2989
2990 HttpResponseInfo response;
2991 HttpResponseInfo response2;
Bence Béky4e83f492018-05-13 23:14:252992 std::string expected_push_result("pushed");
Ryan Sleevib8d7ea02018-05-07 20:01:012993 SequencedSocketData data(reads, writes);
[email protected]dd54bd82012-07-19 23:44:572994 RunServerPushTest(&data,
[email protected]d08358502010-12-03 22:04:032995 &response,
2996 &response2,
2997 expected_push_result);
[email protected]82918cc2010-08-25 17:24:502998
bnc42331402016-07-25 13:36:152999 // Verify the response headers.
wezca1070932016-05-26 20:30:523000 EXPECT_TRUE(response.headers);
bnc84e7fb52015-12-02 11:50:023001 EXPECT_EQ("HTTP/1.1 200", response.headers->GetStatusLine());
[email protected]82918cc2010-08-25 17:24:503002
3003 // Verify the pushed stream.
wezca1070932016-05-26 20:30:523004 EXPECT_TRUE(response2.headers);
bnccdc749f2016-01-27 16:39:043005 EXPECT_EQ("HTTP/1.1 200", response2.headers->GetStatusLine());
[email protected]82918cc2010-08-25 17:24:503006}
3007
tombergan5d22c182017-01-11 02:05:353008TEST_F(SpdyNetworkTransactionTest, ServerPushUpdatesPriority) {
Ryan Hamilton0239aac2018-05-19 00:03:133009 spdy::SpdySerializedFrame stream1_headers(
Bence Béky27ad0a12018-02-08 00:35:483010 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, HIGHEST));
Ryan Hamilton0239aac2018-05-19 00:03:133011 spdy::SpdySerializedFrame stream3_headers(
Bence Béky27ad0a12018-02-08 00:35:483012 spdy_util_.ConstructSpdyGet(nullptr, 0, 3, MEDIUM));
Ryan Hamilton0239aac2018-05-19 00:03:133013 spdy::SpdySerializedFrame stream5_headers(
Bence Béky27ad0a12018-02-08 00:35:483014 spdy_util_.ConstructSpdyGet(nullptr, 0, 5, MEDIUM));
tombergan5d22c182017-01-11 02:05:353015
3016 // Stream 1 pushes two streams that are initially prioritized below stream 5.
3017 // Stream 2 is later prioritized below stream 1 after it matches a request.
Ryan Hamilton0239aac2018-05-19 00:03:133018 spdy::SpdySerializedFrame stream2_priority(
tombergan5d22c182017-01-11 02:05:353019 spdy_util_.ConstructSpdyPriority(2, 5, IDLE, true));
Ryan Hamilton0239aac2018-05-19 00:03:133020 spdy::SpdySerializedFrame stream4_priority(
tombergan5d22c182017-01-11 02:05:353021 spdy_util_.ConstructSpdyPriority(4, 2, IDLE, true));
Ryan Hamilton0239aac2018-05-19 00:03:133022 spdy::SpdySerializedFrame stream4_priority_update(
tombergan5d22c182017-01-11 02:05:353023 spdy_util_.ConstructSpdyPriority(4, 5, IDLE, true));
Ryan Hamilton0239aac2018-05-19 00:03:133024 spdy::SpdySerializedFrame stream2_priority_update(
tombergan5d22c182017-01-11 02:05:353025 spdy_util_.ConstructSpdyPriority(2, 1, HIGHEST, true));
3026
[email protected]e3ebba0f2010-08-05 17:59:583027 MockWrite writes[] = {
tombergan5d22c182017-01-11 02:05:353028 CreateMockWrite(stream1_headers, 0),
3029 CreateMockWrite(stream3_headers, 1),
3030 CreateMockWrite(stream5_headers, 2),
3031 CreateMockWrite(stream2_priority, 7),
3032 CreateMockWrite(stream4_priority, 9),
3033 CreateMockWrite(stream4_priority_update, 11),
3034 CreateMockWrite(stream2_priority_update, 12),
[email protected]e3ebba0f2010-08-05 17:59:583035 };
3036
Ryan Hamilton0239aac2018-05-19 00:03:133037 spdy::SpdySerializedFrame stream1_reply(
tombergan5d22c182017-01-11 02:05:353038 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
Ryan Hamilton0239aac2018-05-19 00:03:133039 spdy::SpdySerializedFrame stream3_reply(
tombergan5d22c182017-01-11 02:05:353040 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
Ryan Hamilton0239aac2018-05-19 00:03:133041 spdy::SpdySerializedFrame stream5_reply(
tombergan5d22c182017-01-11 02:05:353042 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 5));
3043
Ryan Hamilton0239aac2018-05-19 00:03:133044 spdy::SpdySerializedFrame stream2_push(
Bence Békyd2df6c1c82018-04-20 22:52:013045 spdy_util_.ConstructSpdyPush(nullptr, 0, 2, 1, kPushedUrl));
Ryan Hamilton0239aac2018-05-19 00:03:133046 spdy::SpdySerializedFrame stream4_push(spdy_util_.ConstructSpdyPush(
Bence Béky3e01b532018-02-06 23:04:513047 nullptr, 0, 4, 1, "https://www.example.org/bar.dat"));
tombergan5d22c182017-01-11 02:05:353048
Ryan Hamilton0239aac2018-05-19 00:03:133049 spdy::SpdySerializedFrame stream1_body(
3050 spdy_util_.ConstructSpdyDataFrame(1, true));
3051 spdy::SpdySerializedFrame stream2_body(
3052 spdy_util_.ConstructSpdyDataFrame(2, true));
3053 spdy::SpdySerializedFrame stream3_body(
3054 spdy_util_.ConstructSpdyDataFrame(3, true));
3055 spdy::SpdySerializedFrame stream5_body(
3056 spdy_util_.ConstructSpdyDataFrame(5, true));
tombergan5d22c182017-01-11 02:05:353057
3058 MockRead reads[] = {
3059 CreateMockRead(stream1_reply, 3),
3060 CreateMockRead(stream3_reply, 4),
3061 CreateMockRead(stream5_reply, 5),
3062 CreateMockRead(stream2_push, 6),
3063 CreateMockRead(stream4_push, 8),
3064 MockRead(ASYNC, ERR_IO_PENDING, 10),
3065 CreateMockRead(stream1_body, 13),
3066 CreateMockRead(stream2_body, 14),
3067 CreateMockRead(stream3_body, 15),
3068 CreateMockRead(stream5_body, 16),
3069 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 17), // Force a pause
3070 };
3071
Ryan Sleevib8d7ea02018-05-07 20:01:013072 SequencedSocketData data(reads, writes);
3073 SequencedSocketData data_placeholder1;
3074 SequencedSocketData data_placeholder2;
3075 SequencedSocketData data_placeholder3;
tombergan5d22c182017-01-11 02:05:353076
Bence Békydb3cf652017-10-10 15:22:103077 NormalSpdyTransactionHelper helper(request_, LOWEST, log_, nullptr);
tombergan5d22c182017-01-11 02:05:353078 helper.RunPreTestSetup();
3079 helper.AddData(&data);
3080 helper.AddData(&data_placeholder1); // other requests reuse the same socket
3081 helper.AddData(&data_placeholder2);
3082 helper.AddData(&data_placeholder3);
3083 HttpNetworkTransaction trans1(HIGHEST, helper.session());
3084 HttpNetworkTransaction trans3(MEDIUM, helper.session());
3085 HttpNetworkTransaction trans5(MEDIUM, helper.session());
3086
3087 TestCompletionCallback callback1;
3088 TestCompletionCallback callback3;
3089 TestCompletionCallback callback5;
3090
3091 // Start the ordinary requests.
Bence Békydb3cf652017-10-10 15:22:103092 ASSERT_THAT(trans1.Start(&request_, callback1.callback(), log_),
tombergan5d22c182017-01-11 02:05:353093 IsError(ERR_IO_PENDING));
Bence Békydb3cf652017-10-10 15:22:103094 ASSERT_THAT(trans3.Start(&request_, callback3.callback(), log_),
tombergan5d22c182017-01-11 02:05:353095 IsError(ERR_IO_PENDING));
Bence Békydb3cf652017-10-10 15:22:103096 ASSERT_THAT(trans5.Start(&request_, callback5.callback(), log_),
tombergan5d22c182017-01-11 02:05:353097 IsError(ERR_IO_PENDING));
3098 data.RunUntilPaused();
3099
tombergan5d22c182017-01-11 02:05:353100 // Start a request that matches the push.
Bence Békydb3cf652017-10-10 15:22:103101 HttpRequestInfo push_req = CreateGetPushRequest();
krasin0bfeb6b2017-01-13 21:48:043102
3103 HttpNetworkTransaction trans2(HIGHEST, helper.session());
3104 TestCompletionCallback callback2;
Bence Békyd3dde832017-09-19 19:02:313105 ASSERT_THAT(trans2.Start(&push_req, callback2.callback(), log_),
tombergan5d22c182017-01-11 02:05:353106 IsError(ERR_IO_PENDING));
3107 data.Resume();
3108
3109 base::RunLoop().RunUntilIdle();
3110 ASSERT_THAT(callback1.WaitForResult(), IsOk());
3111 ASSERT_THAT(callback2.WaitForResult(), IsOk());
3112 ASSERT_THAT(callback3.WaitForResult(), IsOk());
3113 ASSERT_THAT(callback5.WaitForResult(), IsOk());
3114 helper.VerifyDataConsumed();
3115}
3116
3117TEST_F(SpdyNetworkTransactionTest, ServerPushServerAborted) {
Ryan Hamilton0239aac2018-05-19 00:03:133118 spdy::SpdySerializedFrame stream1_syn(
Bence Béky27ad0a12018-02-08 00:35:483119 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
Ryan Hamilton0239aac2018-05-19 00:03:133120 spdy::SpdySerializedFrame stream2_priority(
tombergan5d22c182017-01-11 02:05:353121 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true));
3122 MockWrite writes[] = {
3123 CreateMockWrite(stream1_syn, 0), CreateMockWrite(stream2_priority, 3),
3124 };
3125
Ryan Hamilton0239aac2018-05-19 00:03:133126 spdy::SpdySerializedFrame stream1_reply(
tombergan5d22c182017-01-11 02:05:353127 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
Ryan Hamilton0239aac2018-05-19 00:03:133128 spdy::SpdySerializedFrame stream2_syn(
Bence Békyd2df6c1c82018-04-20 22:52:013129 spdy_util_.ConstructSpdyPush(nullptr, 0, 2, 1, kPushedUrl));
Ryan Hamilton0239aac2018-05-19 00:03:133130 spdy::SpdySerializedFrame stream2_rst(
3131 spdy_util_.ConstructSpdyRstStream(2, spdy::ERROR_CODE_PROTOCOL_ERROR));
3132 spdy::SpdySerializedFrame stream1_body(
3133 spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]e3ebba0f2010-08-05 17:59:583134 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:413135 CreateMockRead(stream1_reply, 1),
bnceb9aa7112017-01-05 01:03:463136 CreateMockRead(stream2_syn, 2, SYNCHRONOUS),
tombergan5d22c182017-01-11 02:05:353137 CreateMockRead(stream2_rst, 4),
3138 CreateMockRead(stream1_body, 5, SYNCHRONOUS),
3139 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 6), // Force a pause
[email protected]e3ebba0f2010-08-05 17:59:583140 };
3141
Ryan Sleevib8d7ea02018-05-07 20:01:013142 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:103143 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]e3ebba0f2010-08-05 17:59:583144
3145 helper.RunPreTestSetup();
[email protected]dd54bd82012-07-19 23:44:573146 helper.AddData(&data);
[email protected]e3ebba0f2010-08-05 17:59:583147
3148 HttpNetworkTransaction* trans = helper.trans();
3149
3150 // Start the transaction with basic parameters.
[email protected]49639fa2011-12-20 23:22:413151 TestCompletionCallback callback;
Bence Békydb3cf652017-10-10 15:22:103152 int rv = trans->Start(&request_, callback.callback(), log_);
robpercival214763f2016-07-01 23:27:013153 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]e3ebba0f2010-08-05 17:59:583154 rv = callback.WaitForResult();
robpercival214763f2016-07-01 23:27:013155 EXPECT_THAT(rv, IsOk());
[email protected]19ec8a72010-08-23 03:38:233156
3157 // Verify that we consumed all test data.
tombergan5d22c182017-01-11 02:05:353158 base::RunLoop().RunUntilIdle();
rch08e3aa3e2015-05-16 14:27:523159 EXPECT_TRUE(data.AllReadDataConsumed());
3160 EXPECT_TRUE(data.AllWriteDataConsumed());
[email protected]19ec8a72010-08-23 03:38:233161
bnc42331402016-07-25 13:36:153162 // Verify the response headers.
[email protected]19ec8a72010-08-23 03:38:233163 HttpResponseInfo response = *trans->GetResponseInfo();
wezca1070932016-05-26 20:30:523164 EXPECT_TRUE(response.headers);
bnc84e7fb52015-12-02 11:50:023165 EXPECT_EQ("HTTP/1.1 200", response.headers->GetStatusLine());
[email protected]19ec8a72010-08-23 03:38:233166}
3167
[email protected]8a0fc822013-06-27 20:52:433168// Verify that we don't leak streams and that we properly send a reset
3169// if the server pushes the same stream twice.
bncd16676a2016-07-20 16:23:013170TEST_F(SpdyNetworkTransactionTest, ServerPushDuplicate) {
Bence Békyeacd48f2018-05-14 11:34:333171 base::HistogramTester histogram_tester;
3172
Ryan Hamilton0239aac2018-05-19 00:03:133173 spdy::SpdySerializedFrame stream1_syn(
Bence Béky27ad0a12018-02-08 00:35:483174 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
Ryan Hamilton0239aac2018-05-19 00:03:133175 spdy::SpdySerializedFrame stream2_priority(
tombergan5d22c182017-01-11 02:05:353176 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true));
Ryan Hamilton0239aac2018-05-19 00:03:133177 spdy::SpdySerializedFrame stream3_rst(
3178 spdy_util_.ConstructSpdyRstStream(4, spdy::ERROR_CODE_REFUSED_STREAM));
[email protected]fdc165a2010-09-03 03:51:293179 MockWrite writes[] = {
tombergan5d22c182017-01-11 02:05:353180 CreateMockWrite(stream1_syn, 0), CreateMockWrite(stream2_priority, 3),
3181 CreateMockWrite(stream3_rst, 5),
[email protected]fdc165a2010-09-03 03:51:293182 };
3183
Ryan Hamilton0239aac2018-05-19 00:03:133184 spdy::SpdySerializedFrame stream1_reply(
tombergan5d22c182017-01-11 02:05:353185 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
Ryan Hamilton0239aac2018-05-19 00:03:133186 spdy::SpdySerializedFrame stream2_syn(
Bence Békyd2df6c1c82018-04-20 22:52:013187 spdy_util_.ConstructSpdyPush(nullptr, 0, 2, 1, kPushedUrl));
Ryan Hamilton0239aac2018-05-19 00:03:133188 spdy::SpdySerializedFrame stream3_syn(
Bence Békyd2df6c1c82018-04-20 22:52:013189 spdy_util_.ConstructSpdyPush(nullptr, 0, 4, 1, kPushedUrl));
tombergan5d22c182017-01-11 02:05:353190
[email protected]8a0fc822013-06-27 20:52:433191 const char kPushedData[] = "pushed";
Ryan Hamilton0239aac2018-05-19 00:03:133192 spdy::SpdySerializedFrame stream1_body(
3193 spdy_util_.ConstructSpdyDataFrame(1, true));
3194 spdy::SpdySerializedFrame stream2_body(
Bence Békyd74f4382018-02-20 18:26:193195 spdy_util_.ConstructSpdyDataFrame(2, kPushedData, true));
tombergan5d22c182017-01-11 02:05:353196
[email protected]fdc165a2010-09-03 03:51:293197 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:413198 CreateMockRead(stream1_reply, 1),
3199 CreateMockRead(stream2_syn, 2),
tombergan5d22c182017-01-11 02:05:353200 CreateMockRead(stream3_syn, 4),
3201 CreateMockRead(stream1_body, 6),
3202 CreateMockRead(stream2_body, 7),
3203 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 8), // Force a pause
[email protected]fdc165a2010-09-03 03:51:293204 };
3205
3206 HttpResponseInfo response;
3207 HttpResponseInfo response2;
Bence Béky4e83f492018-05-13 23:14:253208 std::string expected_push_result("pushed");
Ryan Sleevib8d7ea02018-05-07 20:01:013209 SequencedSocketData data(reads, writes);
[email protected]dd54bd82012-07-19 23:44:573210 RunServerPushTest(&data,
[email protected]d08358502010-12-03 22:04:033211 &response,
3212 &response2,
3213 expected_push_result);
[email protected]fdc165a2010-09-03 03:51:293214
bnc42331402016-07-25 13:36:153215 // Verify the response headers.
wezca1070932016-05-26 20:30:523216 EXPECT_TRUE(response.headers);
bnc84e7fb52015-12-02 11:50:023217 EXPECT_EQ("HTTP/1.1 200", response.headers->GetStatusLine());
[email protected]fdc165a2010-09-03 03:51:293218
3219 // Verify the pushed stream.
wezca1070932016-05-26 20:30:523220 EXPECT_TRUE(response2.headers);
bnccdc749f2016-01-27 16:39:043221 EXPECT_EQ("HTTP/1.1 200", response2.headers->GetStatusLine());
Bence Békyeacd48f2018-05-14 11:34:333222
3223 histogram_tester.ExpectBucketCount(
3224 "Net.SpdyPushedStreamFate",
3225 static_cast<int>(SpdyPushedStreamFate::kAcceptedNoVary), 1);
3226 histogram_tester.ExpectBucketCount(
3227 "Net.SpdyPushedStreamFate",
3228 static_cast<int>(SpdyPushedStreamFate::kDuplicateUrl), 1);
3229 histogram_tester.ExpectTotalCount("Net.SpdyPushedStreamFate", 2);
[email protected]fdc165a2010-09-03 03:51:293230}
3231
bncd16676a2016-07-20 16:23:013232TEST_F(SpdyNetworkTransactionTest, ServerPushMultipleDataFrame) {
Ryan Hamilton0239aac2018-05-19 00:03:133233 spdy::SpdySerializedFrame stream1_syn(
Bence Béky27ad0a12018-02-08 00:35:483234 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
Ryan Hamilton0239aac2018-05-19 00:03:133235 spdy::SpdySerializedFrame stream2_priority(
tombergan5d22c182017-01-11 02:05:353236 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true));
[email protected]19ec8a72010-08-23 03:38:233237 MockWrite writes[] = {
tombergan5d22c182017-01-11 02:05:353238 CreateMockWrite(stream1_syn, 0), CreateMockWrite(stream2_priority, 3),
[email protected]19ec8a72010-08-23 03:38:233239 };
3240
Ryan Hamilton0239aac2018-05-19 00:03:133241 spdy::SpdySerializedFrame stream1_reply(
tombergan5d22c182017-01-11 02:05:353242 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
Ryan Hamilton0239aac2018-05-19 00:03:133243 spdy::SpdySerializedFrame stream2_syn(
Bence Békyd2df6c1c82018-04-20 22:52:013244 spdy_util_.ConstructSpdyPush(nullptr, 0, 2, 1, kPushedUrl));
Bence Békyd74f4382018-02-20 18:26:193245 static const char kPushedData[] = "pushed payload for chunked test";
Ryan Hamilton0239aac2018-05-19 00:03:133246 spdy::SpdySerializedFrame stream2_body_base(
Bence Békyd74f4382018-02-20 18:26:193247 spdy_util_.ConstructSpdyDataFrame(2, kPushedData, true));
[email protected]8a0fc822013-06-27 20:52:433248 const size_t kChunkSize = strlen(kPushedData) / 4;
Ryan Hamilton0239aac2018-05-19 00:03:133249 spdy::SpdySerializedFrame stream2_body1(stream2_body_base.data(), kChunkSize,
3250 false);
3251 spdy::SpdySerializedFrame stream2_body2(stream2_body_base.data() + kChunkSize,
3252 kChunkSize, false);
3253 spdy::SpdySerializedFrame stream2_body3(
3254 stream2_body_base.data() + 2 * kChunkSize, kChunkSize, false);
3255 spdy::SpdySerializedFrame stream2_body4(
3256 stream2_body_base.data() + 3 * kChunkSize,
3257 stream2_body_base.size() - 3 * kChunkSize, false);
3258 spdy::SpdySerializedFrame stream1_body(
3259 spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]19ec8a72010-08-23 03:38:233260 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:413261 CreateMockRead(stream1_reply, 1),
3262 CreateMockRead(stream2_syn, 2),
tombergan5d22c182017-01-11 02:05:353263 CreateMockRead(stream2_body1, 4),
3264 CreateMockRead(stream2_body2, 5),
3265 CreateMockRead(stream2_body3, 6),
3266 CreateMockRead(stream2_body4, 7),
3267 CreateMockRead(stream1_body, 8, SYNCHRONOUS),
3268 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 9), // Force a pause
[email protected]19ec8a72010-08-23 03:38:233269 };
3270
3271 HttpResponseInfo response;
3272 HttpResponseInfo response2;
Bence Béky4e83f492018-05-13 23:14:253273 std::string expected_push_result(kPushedData);
Ryan Sleevib8d7ea02018-05-07 20:01:013274 SequencedSocketData data(reads, writes);
[email protected]8a0fc822013-06-27 20:52:433275 RunServerPushTest(&data, &response, &response2, kPushedData);
[email protected]19ec8a72010-08-23 03:38:233276
bnc42331402016-07-25 13:36:153277 // Verify the response headers.
wezca1070932016-05-26 20:30:523278 EXPECT_TRUE(response.headers);
bnc84e7fb52015-12-02 11:50:023279 EXPECT_EQ("HTTP/1.1 200", response.headers->GetStatusLine());
[email protected]19ec8a72010-08-23 03:38:233280
3281 // Verify the pushed stream.
wezca1070932016-05-26 20:30:523282 EXPECT_TRUE(response2.headers);
bnccdc749f2016-01-27 16:39:043283 EXPECT_EQ("HTTP/1.1 200", response2.headers->GetStatusLine());
[email protected]19ec8a72010-08-23 03:38:233284}
3285
bncd16676a2016-07-20 16:23:013286TEST_F(SpdyNetworkTransactionTest, ServerPushMultipleDataFrameInterrupted) {
Ryan Hamilton0239aac2018-05-19 00:03:133287 spdy::SpdySerializedFrame stream1_syn(
Bence Béky27ad0a12018-02-08 00:35:483288 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
Ryan Hamilton0239aac2018-05-19 00:03:133289 spdy::SpdySerializedFrame stream2_priority(
tombergan5d22c182017-01-11 02:05:353290 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true));
[email protected]19ec8a72010-08-23 03:38:233291 MockWrite writes[] = {
tombergan5d22c182017-01-11 02:05:353292 CreateMockWrite(stream1_syn, 0), CreateMockWrite(stream2_priority, 3),
[email protected]19ec8a72010-08-23 03:38:233293 };
3294
Ryan Hamilton0239aac2018-05-19 00:03:133295 spdy::SpdySerializedFrame stream1_reply(
tombergan5d22c182017-01-11 02:05:353296 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
Ryan Hamilton0239aac2018-05-19 00:03:133297 spdy::SpdySerializedFrame stream2_syn(
Bence Békyd2df6c1c82018-04-20 22:52:013298 spdy_util_.ConstructSpdyPush(nullptr, 0, 2, 1, kPushedUrl));
Bence Békyd74f4382018-02-20 18:26:193299 static const char kPushedData[] = "pushed payload for chunked test";
Ryan Hamilton0239aac2018-05-19 00:03:133300 spdy::SpdySerializedFrame stream2_body_base(
Bence Békyd74f4382018-02-20 18:26:193301 spdy_util_.ConstructSpdyDataFrame(2, kPushedData, true));
[email protected]8a0fc822013-06-27 20:52:433302 const size_t kChunkSize = strlen(kPushedData) / 4;
Ryan Hamilton0239aac2018-05-19 00:03:133303 spdy::SpdySerializedFrame stream2_body1(stream2_body_base.data(), kChunkSize,
3304 false);
3305 spdy::SpdySerializedFrame stream2_body2(stream2_body_base.data() + kChunkSize,
3306 kChunkSize, false);
3307 spdy::SpdySerializedFrame stream2_body3(
3308 stream2_body_base.data() + 2 * kChunkSize, kChunkSize, false);
3309 spdy::SpdySerializedFrame stream2_body4(
3310 stream2_body_base.data() + 3 * kChunkSize,
3311 stream2_body_base.size() - 3 * kChunkSize, false);
3312 spdy::SpdySerializedFrame stream1_body(
3313 spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]19ec8a72010-08-23 03:38:233314 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:413315 CreateMockRead(stream1_reply, 1),
3316 CreateMockRead(stream2_syn, 2),
tombergan5d22c182017-01-11 02:05:353317 CreateMockRead(stream2_body1, 4),
3318 CreateMockRead(stream2_body2, 5),
3319 CreateMockRead(stream2_body3, 6),
3320 CreateMockRead(stream2_body4, 7),
3321 CreateMockRead(stream1_body, 8, SYNCHRONOUS),
3322 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 9) // Force a pause.
[email protected]19ec8a72010-08-23 03:38:233323 };
3324
3325 HttpResponseInfo response;
3326 HttpResponseInfo response2;
Ryan Sleevib8d7ea02018-05-07 20:01:013327 SequencedSocketData data(reads, writes);
[email protected]8a0fc822013-06-27 20:52:433328 RunServerPushTest(&data, &response, &response2, kPushedData);
[email protected]19ec8a72010-08-23 03:38:233329
bnc42331402016-07-25 13:36:153330 // Verify the response headers.
wezca1070932016-05-26 20:30:523331 EXPECT_TRUE(response.headers);
bnc84e7fb52015-12-02 11:50:023332 EXPECT_EQ("HTTP/1.1 200", response.headers->GetStatusLine());
[email protected]19ec8a72010-08-23 03:38:233333
3334 // Verify the pushed stream.
wezca1070932016-05-26 20:30:523335 EXPECT_TRUE(response2.headers);
bnccdc749f2016-01-27 16:39:043336 EXPECT_EQ("HTTP/1.1 200", response2.headers->GetStatusLine());
[email protected]19ec8a72010-08-23 03:38:233337}
3338
morlovichab1d1c1e2017-02-07 19:59:283339TEST_F(SpdyNetworkTransactionTest, ServerPushInvalidUrl) {
Bence Békyeacd48f2018-05-14 11:34:333340 base::HistogramTester histogram_tester;
3341
morlovichab1d1c1e2017-02-07 19:59:283342 // Coverage on how a non-empty invalid GURL in a PUSH_PROMISE is handled.
Ryan Hamilton0239aac2018-05-19 00:03:133343 spdy::SpdyHeaderBlock headers(
3344 spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
3345 spdy::SpdySerializedFrame req(
morlovichab1d1c1e2017-02-07 19:59:283346 spdy_util_.ConstructSpdyHeaders(1, std::move(headers), LOWEST, true));
3347
3348 // Can't use ConstructSpdyPush here since it wants to parse a URL and
3349 // split it into the appropriate :header pieces. So we have to hand-fill
3350 // those pieces in.
Ryan Hamilton0239aac2018-05-19 00:03:133351 spdy::SpdyHeaderBlock push_promise_header_block;
3352 push_promise_header_block[spdy::kHttp2AuthorityHeader] = "";
3353 push_promise_header_block[spdy::kHttp2SchemeHeader] = "";
3354 push_promise_header_block[spdy::kHttp2PathHeader] = "/index.html";
morlovichab1d1c1e2017-02-07 19:59:283355
Ryan Hamilton0239aac2018-05-19 00:03:133356 spdy::SpdySerializedFrame push_promise(spdy_util_.ConstructSpdyPushPromise(
Bence Békyf1d78522018-01-11 01:16:503357 1, 2, std::move(push_promise_header_block)));
morlovichab1d1c1e2017-02-07 19:59:283358
Ryan Hamilton0239aac2018-05-19 00:03:133359 spdy::SpdySerializedFrame stream2_rst(
3360 spdy_util_.ConstructSpdyRstStream(2, spdy::ERROR_CODE_REFUSED_STREAM));
morlovichab1d1c1e2017-02-07 19:59:283361
3362 MockWrite writes[] = {CreateMockWrite(req, 0),
3363 CreateMockWrite(stream2_rst, 2)};
3364 MockRead reads[] = {
Bence Békyf1d78522018-01-11 01:16:503365 CreateMockRead(push_promise, 1), MockRead(ASYNC, 0, 3) /* EOF */
morlovichab1d1c1e2017-02-07 19:59:283366 };
Ryan Sleevib8d7ea02018-05-07 20:01:013367 SequencedSocketData data(reads, writes);
morlovichab1d1c1e2017-02-07 19:59:283368 RunBrokenPushTest(&data, ERR_CONNECTION_CLOSED);
Bence Békyeacd48f2018-05-14 11:34:333369
3370 histogram_tester.ExpectBucketCount(
3371 "Net.SpdyPushedStreamFate",
3372 static_cast<int>(SpdyPushedStreamFate::kInvalidUrl), 1);
3373 histogram_tester.ExpectTotalCount("Net.SpdyPushedStreamFate", 1);
morlovichab1d1c1e2017-02-07 19:59:283374}
3375
bncd16676a2016-07-20 16:23:013376TEST_F(SpdyNetworkTransactionTest, ServerPushInvalidAssociatedStreamID0) {
Ryan Hamilton0239aac2018-05-19 00:03:133377 spdy::SpdySerializedFrame stream1_syn(
Bence Béky27ad0a12018-02-08 00:35:483378 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
Ryan Hamilton0239aac2018-05-19 00:03:133379 spdy::SpdySerializedFrame goaway(
3380 spdy_util_.ConstructSpdyGoAway(0, spdy::ERROR_CODE_PROTOCOL_ERROR,
3381 "Framer error: 1 (INVALID_STREAM_ID)."));
[email protected]19ec8a72010-08-23 03:38:233382 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:413383 CreateMockWrite(stream1_syn, 0), CreateMockWrite(goaway, 3),
[email protected]19ec8a72010-08-23 03:38:233384 };
3385
Ryan Hamilton0239aac2018-05-19 00:03:133386 spdy::SpdySerializedFrame stream1_reply(
tombergan5d22c182017-01-11 02:05:353387 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
Ryan Hamilton0239aac2018-05-19 00:03:133388 spdy::SpdySerializedFrame stream2_syn(
Bence Békyd2df6c1c82018-04-20 22:52:013389 spdy_util_.ConstructSpdyPush(nullptr, 0, 2, 0, kPushedUrl));
[email protected]19ec8a72010-08-23 03:38:233390 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:413391 CreateMockRead(stream1_reply, 1), CreateMockRead(stream2_syn, 2),
[email protected]19ec8a72010-08-23 03:38:233392 };
Ryan Sleevib8d7ea02018-05-07 20:01:013393 SequencedSocketData data(reads, writes);
morlovichab1d1c1e2017-02-07 19:59:283394 RunBrokenPushTest(&data, OK);
[email protected]e3ebba0f2010-08-05 17:59:583395}
3396
bncd16676a2016-07-20 16:23:013397TEST_F(SpdyNetworkTransactionTest, ServerPushInvalidAssociatedStreamID9) {
Bence Békyeacd48f2018-05-14 11:34:333398 base::HistogramTester histogram_tester;
3399
Ryan Hamilton0239aac2018-05-19 00:03:133400 spdy::SpdySerializedFrame stream1_syn(
Bence Béky27ad0a12018-02-08 00:35:483401 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
Ryan Hamilton0239aac2018-05-19 00:03:133402 spdy::SpdySerializedFrame stream1_body(
3403 spdy_util_.ConstructSpdyDataFrame(1, true));
3404 spdy::SpdySerializedFrame stream2_rst(
3405 spdy_util_.ConstructSpdyRstStream(2, spdy::ERROR_CODE_STREAM_CLOSED));
[email protected]e3ebba0f2010-08-05 17:59:583406 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:413407 CreateMockWrite(stream1_syn, 0), CreateMockWrite(stream2_rst, 3),
[email protected]e3ebba0f2010-08-05 17:59:583408 };
3409
Ryan Hamilton0239aac2018-05-19 00:03:133410 spdy::SpdySerializedFrame stream1_reply(
tombergan5d22c182017-01-11 02:05:353411 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
Ryan Hamilton0239aac2018-05-19 00:03:133412 spdy::SpdySerializedFrame stream2_syn(
Bence Békyd2df6c1c82018-04-20 22:52:013413 spdy_util_.ConstructSpdyPush(nullptr, 0, 2, 9, kPushedUrl));
[email protected]e3ebba0f2010-08-05 17:59:583414 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:413415 CreateMockRead(stream1_reply, 1), CreateMockRead(stream2_syn, 2),
3416 CreateMockRead(stream1_body, 4),
rch08e3aa3e2015-05-16 14:27:523417 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 5), // Force a pause
[email protected]e3ebba0f2010-08-05 17:59:583418 };
3419
Ryan Sleevib8d7ea02018-05-07 20:01:013420 SequencedSocketData data(reads, writes);
morlovichab1d1c1e2017-02-07 19:59:283421 RunBrokenPushTest(&data, OK);
Bence Békyeacd48f2018-05-14 11:34:333422
3423 histogram_tester.ExpectBucketCount(
3424 "Net.SpdyPushedStreamFate",
3425 static_cast<int>(SpdyPushedStreamFate::kInactiveAssociatedStream), 1);
3426 histogram_tester.ExpectTotalCount("Net.SpdyPushedStreamFate", 1);
[email protected]e3ebba0f2010-08-05 17:59:583427}
3428
bncd16676a2016-07-20 16:23:013429TEST_F(SpdyNetworkTransactionTest, ServerPushNoURL) {
Bence Békyeacd48f2018-05-14 11:34:333430 base::HistogramTester histogram_tester;
3431
Ryan Hamilton0239aac2018-05-19 00:03:133432 spdy::SpdySerializedFrame stream1_syn(
Bence Béky27ad0a12018-02-08 00:35:483433 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
Ryan Hamilton0239aac2018-05-19 00:03:133434 spdy::SpdySerializedFrame stream1_body(
3435 spdy_util_.ConstructSpdyDataFrame(1, true));
3436 spdy::SpdySerializedFrame stream2_rst(
3437 spdy_util_.ConstructSpdyRstStream(2, spdy::ERROR_CODE_REFUSED_STREAM));
[email protected]e3ebba0f2010-08-05 17:59:583438 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:413439 CreateMockWrite(stream1_syn, 0), CreateMockWrite(stream2_rst, 3),
[email protected]e3ebba0f2010-08-05 17:59:583440 };
3441
Ryan Hamilton0239aac2018-05-19 00:03:133442 spdy::SpdySerializedFrame stream1_reply(
tombergan5d22c182017-01-11 02:05:353443 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
Ryan Hamilton0239aac2018-05-19 00:03:133444 spdy::SpdyHeaderBlock incomplete_headers;
3445 incomplete_headers[spdy::kHttp2StatusHeader] = "200 OK";
bnc086b39e12016-06-24 13:05:263446 incomplete_headers["hello"] = "bye";
Ryan Hamilton0239aac2018-05-19 00:03:133447 spdy::SpdySerializedFrame stream2_syn(
Bence Békyf1d78522018-01-11 01:16:503448 spdy_util_.ConstructSpdyPushPromise(1, 2, std::move(incomplete_headers)));
[email protected]e3ebba0f2010-08-05 17:59:583449 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:413450 CreateMockRead(stream1_reply, 1), CreateMockRead(stream2_syn, 2),
3451 CreateMockRead(stream1_body, 4),
rch08e3aa3e2015-05-16 14:27:523452 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 5) // Force a pause
[email protected]e3ebba0f2010-08-05 17:59:583453 };
3454
Ryan Sleevib8d7ea02018-05-07 20:01:013455 SequencedSocketData data(reads, writes);
morlovichab1d1c1e2017-02-07 19:59:283456 RunBrokenPushTest(&data, OK);
Bence Békyeacd48f2018-05-14 11:34:333457
3458 histogram_tester.ExpectBucketCount(
3459 "Net.SpdyPushedStreamFate",
3460 static_cast<int>(SpdyPushedStreamFate::kInvalidUrl), 1);
3461 histogram_tester.ExpectTotalCount("Net.SpdyPushedStreamFate", 1);
[email protected]e3ebba0f2010-08-05 17:59:583462}
3463
bnc0cb98b22016-03-04 17:10:523464// PUSH_PROMISE on a server-initiated stream should trigger GOAWAY.
bncd16676a2016-07-20 16:23:013465TEST_F(SpdyNetworkTransactionTest, ServerPushOnPushedStream) {
Bence Békyeacd48f2018-05-14 11:34:333466 base::HistogramTester histogram_tester;
3467
Ryan Hamilton0239aac2018-05-19 00:03:133468 spdy::SpdySerializedFrame stream1_syn(
Bence Béky27ad0a12018-02-08 00:35:483469 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
Ryan Hamilton0239aac2018-05-19 00:03:133470 spdy::SpdySerializedFrame stream2_priority(
tombergan5d22c182017-01-11 02:05:353471 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true));
Ryan Hamilton0239aac2018-05-19 00:03:133472 spdy::SpdySerializedFrame goaway(spdy_util_.ConstructSpdyGoAway(
3473 2, spdy::ERROR_CODE_PROTOCOL_ERROR,
Bence Béky602c40c2017-07-26 05:22:563474 "Received pushed stream id 4 on invalid stream id 2 (must be odd)."));
bnc0cb98b22016-03-04 17:10:523475 MockWrite writes[] = {
tombergan5d22c182017-01-11 02:05:353476 CreateMockWrite(stream1_syn, 0), CreateMockWrite(stream2_priority, 3),
3477 CreateMockWrite(goaway, 5),
bnc0cb98b22016-03-04 17:10:523478 };
3479
Ryan Hamilton0239aac2018-05-19 00:03:133480 spdy::SpdySerializedFrame stream1_reply(
tombergan5d22c182017-01-11 02:05:353481 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
Ryan Hamilton0239aac2018-05-19 00:03:133482 spdy::SpdySerializedFrame stream2_syn(
Bence Békyd2df6c1c82018-04-20 22:52:013483 spdy_util_.ConstructSpdyPush(nullptr, 0, 2, 1, kPushedUrl));
Ryan Hamilton0239aac2018-05-19 00:03:133484 spdy::SpdySerializedFrame stream3_syn(spdy_util_.ConstructSpdyPush(
Bence Béky3e01b532018-02-06 23:04:513485 nullptr, 0, 4, 2, "https://www.example.org/bar.dat"));
bnc0cb98b22016-03-04 17:10:523486 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:413487 CreateMockRead(stream1_reply, 1), CreateMockRead(stream2_syn, 2),
tombergan5d22c182017-01-11 02:05:353488 CreateMockRead(stream3_syn, 4),
bnc0cb98b22016-03-04 17:10:523489 };
3490
Ryan Sleevib8d7ea02018-05-07 20:01:013491 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:103492 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
bnc0cb98b22016-03-04 17:10:523493 helper.RunToCompletion(&data);
Bence Békyeacd48f2018-05-14 11:34:333494
3495 histogram_tester.ExpectBucketCount(
3496 "Net.SpdyPushedStreamFate",
3497 static_cast<int>(SpdyPushedStreamFate::kAssociatedStreamIdParityError),
3498 1);
3499 histogram_tester.ExpectTotalCount("Net.SpdyPushedStreamFate", 1);
bnc0cb98b22016-03-04 17:10:523500}
3501
3502// PUSH_PROMISE on a closed client-initiated stream should trigger RST_STREAM.
bncd16676a2016-07-20 16:23:013503TEST_F(SpdyNetworkTransactionTest, ServerPushOnClosedStream) {
Bence Békyeacd48f2018-05-14 11:34:333504 base::HistogramTester histogram_tester;
3505
Ryan Hamilton0239aac2018-05-19 00:03:133506 spdy::SpdySerializedFrame stream1_syn(
Bence Béky27ad0a12018-02-08 00:35:483507 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
Ryan Hamilton0239aac2018-05-19 00:03:133508 spdy::SpdySerializedFrame rst(
3509 spdy_util_.ConstructSpdyRstStream(2, spdy::ERROR_CODE_STREAM_CLOSED));
bnc0cb98b22016-03-04 17:10:523510 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:413511 CreateMockWrite(stream1_syn, 0), CreateMockWrite(rst, 5),
bnc0cb98b22016-03-04 17:10:523512 };
3513
Ryan Hamilton0239aac2018-05-19 00:03:133514 spdy::SpdySerializedFrame stream1_reply(
bnc42331402016-07-25 13:36:153515 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
Ryan Hamilton0239aac2018-05-19 00:03:133516 spdy::SpdySerializedFrame stream1_body(
3517 spdy_util_.ConstructSpdyDataFrame(1, true));
3518 spdy::SpdySerializedFrame stream2_syn(
Bence Békyd2df6c1c82018-04-20 22:52:013519 spdy_util_.ConstructSpdyPush(nullptr, 0, 2, 1, kPushedUrl));
bnc0cb98b22016-03-04 17:10:523520 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:413521 CreateMockRead(stream1_reply, 1), CreateMockRead(stream1_body, 2),
3522 CreateMockRead(stream2_syn, 3), MockRead(SYNCHRONOUS, ERR_IO_PENDING, 4),
bnc0cb98b22016-03-04 17:10:523523 };
3524
Ryan Sleevib8d7ea02018-05-07 20:01:013525 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:103526 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
bnc0cb98b22016-03-04 17:10:523527 helper.RunPreTestSetup();
3528 helper.AddData(&data);
3529
3530 HttpNetworkTransaction* trans = helper.trans();
3531
3532 TestCompletionCallback callback;
Bence Békydb3cf652017-10-10 15:22:103533 int rv = trans->Start(&request_, callback.callback(), log_);
bnc0cb98b22016-03-04 17:10:523534 rv = callback.GetResult(rv);
robpercival214763f2016-07-01 23:27:013535 EXPECT_THAT(rv, IsOk());
bnceb9aa7112017-01-05 01:03:463536
3537 // Finish async network reads/writes.
3538 base::RunLoop().RunUntilIdle();
3539
bnc0cb98b22016-03-04 17:10:523540 HttpResponseInfo response = *trans->GetResponseInfo();
wezca1070932016-05-26 20:30:523541 EXPECT_TRUE(response.headers);
bnc0cb98b22016-03-04 17:10:523542 EXPECT_EQ("HTTP/1.1 200", response.headers->GetStatusLine());
3543
3544 EXPECT_TRUE(data.AllReadDataConsumed());
3545 EXPECT_TRUE(data.AllWriteDataConsumed());
3546 VerifyStreamsClosed(helper);
Bence Békyeacd48f2018-05-14 11:34:333547
3548 histogram_tester.ExpectBucketCount(
3549 "Net.SpdyPushedStreamFate",
3550 static_cast<int>(SpdyPushedStreamFate::kInactiveAssociatedStream), 1);
3551 histogram_tester.ExpectTotalCount("Net.SpdyPushedStreamFate", 1);
bnc0cb98b22016-03-04 17:10:523552}
3553
3554// PUSH_PROMISE on a server-initiated stream should trigger GOAWAY even if
3555// stream is closed.
bncd16676a2016-07-20 16:23:013556TEST_F(SpdyNetworkTransactionTest, ServerPushOnClosedPushedStream) {
Bence Békyeacd48f2018-05-14 11:34:333557 base::HistogramTester histogram_tester;
3558
Ryan Hamilton0239aac2018-05-19 00:03:133559 spdy::SpdySerializedFrame stream1_syn(
Bence Béky27ad0a12018-02-08 00:35:483560 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
Ryan Hamilton0239aac2018-05-19 00:03:133561 spdy::SpdySerializedFrame stream2_priority(
tombergan5d22c182017-01-11 02:05:353562 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true));
Ryan Hamilton0239aac2018-05-19 00:03:133563 spdy::SpdySerializedFrame goaway(spdy_util_.ConstructSpdyGoAway(
3564 2, spdy::ERROR_CODE_PROTOCOL_ERROR,
Bence Béky602c40c2017-07-26 05:22:563565 "Received pushed stream id 4 on invalid stream id 2 (must be odd)."));
Bence Béky7bf94362018-01-10 13:19:363566 MockWrite writes[] = {CreateMockWrite(stream1_syn, 0),
3567 CreateMockWrite(stream2_priority, 3),
3568 CreateMockWrite(goaway, 8)};
bnc0cb98b22016-03-04 17:10:523569
Ryan Hamilton0239aac2018-05-19 00:03:133570 spdy::SpdySerializedFrame stream2_syn(
Bence Békyd2df6c1c82018-04-20 22:52:013571 spdy_util_.ConstructSpdyPush(nullptr, 0, 2, 1, kPushedUrl));
Ryan Hamilton0239aac2018-05-19 00:03:133572 spdy::SpdySerializedFrame stream1_reply(
Bence Béky7bf94362018-01-10 13:19:363573 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
Ryan Hamilton0239aac2018-05-19 00:03:133574 spdy::SpdySerializedFrame stream1_body(
3575 spdy_util_.ConstructSpdyDataFrame(1, true));
bnc0cb98b22016-03-04 17:10:523576 const char kPushedData[] = "pushed";
Ryan Hamilton0239aac2018-05-19 00:03:133577 spdy::SpdySerializedFrame stream2_body(
Bence Békyd74f4382018-02-20 18:26:193578 spdy_util_.ConstructSpdyDataFrame(2, kPushedData, true));
Ryan Hamilton0239aac2018-05-19 00:03:133579 spdy::SpdySerializedFrame stream3_syn(spdy_util_.ConstructSpdyPush(
Bence Béky3e01b532018-02-06 23:04:513580 nullptr, 0, 4, 2, "https://www.example.org/bar.dat"));
bnc0cb98b22016-03-04 17:10:523581
3582 MockRead reads[] = {
Bence Béky7bf94362018-01-10 13:19:363583 CreateMockRead(stream2_syn, 1), CreateMockRead(stream1_reply, 2),
tombergan5d22c182017-01-11 02:05:353584 CreateMockRead(stream1_body, 4), CreateMockRead(stream2_body, 5),
Bence Béky7bf94362018-01-10 13:19:363585 MockRead(ASYNC, ERR_IO_PENDING, 6), CreateMockRead(stream3_syn, 7)};
bnc0cb98b22016-03-04 17:10:523586
Ryan Sleevib8d7ea02018-05-07 20:01:013587 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:103588 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
bnc0cb98b22016-03-04 17:10:523589 helper.RunPreTestSetup();
3590 helper.AddData(&data);
3591
3592 HttpNetworkTransaction* trans1 = helper.trans();
3593 TestCompletionCallback callback1;
Bence Békydb3cf652017-10-10 15:22:103594 int rv = trans1->Start(&request_, callback1.callback(), log_);
bnc0cb98b22016-03-04 17:10:523595 rv = callback1.GetResult(rv);
robpercival214763f2016-07-01 23:27:013596 EXPECT_THAT(rv, IsOk());
bnc0cb98b22016-03-04 17:10:523597 HttpResponseInfo response = *trans1->GetResponseInfo();
wezca1070932016-05-26 20:30:523598 EXPECT_TRUE(response.headers);
bnc0cb98b22016-03-04 17:10:523599 EXPECT_EQ("HTTP/1.1 200", response.headers->GetStatusLine());
3600
bnc691fda62016-08-12 00:43:163601 HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session());
bnc0cb98b22016-03-04 17:10:523602 TestCompletionCallback callback2;
Bence Békydb3cf652017-10-10 15:22:103603 HttpRequestInfo request = CreateGetPushRequest();
3604 rv = trans2.Start(&request, callback2.callback(), log_);
bnc0cb98b22016-03-04 17:10:523605 rv = callback2.GetResult(rv);
robpercival214763f2016-07-01 23:27:013606 EXPECT_THAT(rv, IsOk());
bnc691fda62016-08-12 00:43:163607 response = *trans2.GetResponseInfo();
wezca1070932016-05-26 20:30:523608 EXPECT_TRUE(response.headers);
bnc0cb98b22016-03-04 17:10:523609 EXPECT_EQ("HTTP/1.1 200", response.headers->GetStatusLine());
Bence Béky4e83f492018-05-13 23:14:253610 std::string result;
bnc691fda62016-08-12 00:43:163611 ReadResult(&trans2, &result);
bnc0cb98b22016-03-04 17:10:523612 EXPECT_EQ(kPushedData, result);
3613
3614 data.Resume();
3615 base::RunLoop().RunUntilIdle();
3616
3617 EXPECT_TRUE(data.AllReadDataConsumed());
3618 EXPECT_TRUE(data.AllWriteDataConsumed());
Bence Békyeacd48f2018-05-14 11:34:333619
3620 histogram_tester.ExpectBucketCount(
3621 "Net.SpdyPushedStreamFate",
3622 static_cast<int>(SpdyPushedStreamFate::kAssociatedStreamIdParityError),
3623 1);
3624 histogram_tester.ExpectBucketCount(
3625 "Net.SpdyPushedStreamFate",
3626 static_cast<int>(SpdyPushedStreamFate::kAcceptedNoVary), 1);
3627 histogram_tester.ExpectTotalCount("Net.SpdyPushedStreamFate", 2);
bnc0cb98b22016-03-04 17:10:523628}
3629
Bence Békye8955cf22018-01-02 17:31:293630TEST_F(SpdyNetworkTransactionTest, ServerCancelsPush) {
Ryan Hamilton0239aac2018-05-19 00:03:133631 spdy::SpdySerializedFrame req1(
3632 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
3633 spdy::SpdySerializedFrame priority(
Bence Békye8955cf22018-01-02 17:31:293634 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true));
Bence Béky1a5d8562018-01-05 17:29:283635 spdy_util_.UpdateWithStreamDestruction(1);
Ryan Hamilton0239aac2018-05-19 00:03:133636 spdy::SpdySerializedFrame req2(
3637 spdy_util_.ConstructSpdyGet(kPushedUrl, 3, LOWEST));
Bence Béky1a5d8562018-01-05 17:29:283638 MockWrite writes1[] = {CreateMockWrite(req1, 0), CreateMockWrite(priority, 3),
3639 CreateMockWrite(req2, 6)};
Bence Békye8955cf22018-01-02 17:31:293640
Ryan Hamilton0239aac2018-05-19 00:03:133641 spdy::SpdySerializedFrame reply1(
3642 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
3643 spdy::SpdySerializedFrame push(
Bence Békyd2df6c1c82018-04-20 22:52:013644 spdy_util_.ConstructSpdyPush(nullptr, 0, 2, 1, kPushedUrl));
Ryan Hamilton0239aac2018-05-19 00:03:133645 spdy::SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true));
3646 spdy::SpdySerializedFrame rst(
3647 spdy_util_.ConstructSpdyRstStream(2, spdy::ERROR_CODE_INTERNAL_ERROR));
3648 spdy::SpdySerializedFrame reply2(
3649 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
3650 spdy::SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(3, true));
Bence Béky1a5d8562018-01-05 17:29:283651 MockRead reads1[] = {CreateMockRead(reply1, 1), CreateMockRead(push, 2),
3652 CreateMockRead(body1, 4), CreateMockRead(rst, 5),
3653 CreateMockRead(reply2, 7), CreateMockRead(body2, 8),
3654 MockRead(ASYNC, 0, 9)};
Bence Békye8955cf22018-01-02 17:31:293655
Ryan Sleevib8d7ea02018-05-07 20:01:013656 SequencedSocketData data(reads1, writes1);
Bence Békye8955cf22018-01-02 17:31:293657
3658 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
3659 helper.RunPreTestSetup();
3660 helper.AddData(&data);
3661
Bence Béky1a5d8562018-01-05 17:29:283662 // First request opens up connection.
Bence Békye8955cf22018-01-02 17:31:293663 HttpNetworkTransaction* trans1 = helper.trans();
3664 TestCompletionCallback callback1;
3665 int rv = trans1->Start(&request_, callback1.callback(), log_);
3666 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
3667
3668 // Read until response body arrives. PUSH_PROMISE comes earlier.
3669 rv = callback1.WaitForResult();
3670 EXPECT_THAT(rv, IsOk());
Bence Béky1a5d8562018-01-05 17:29:283671 const HttpResponseInfo* response = trans1->GetResponseInfo();
3672 EXPECT_TRUE(response->headers);
3673 EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
3674 std::string result1;
3675 ReadResult(trans1, &result1);
3676 EXPECT_EQ("hello!", result1);
3677
3678 SpdySessionPool* spdy_session_pool = helper.session()->spdy_session_pool();
3679 SpdySessionKey key(host_port_pair_, ProxyServer::Direct(),
Matt Menke2436b2f2018-12-11 18:07:113680 PRIVACY_MODE_DISABLED,
dalyk51ab46b2019-10-15 15:14:343681 SpdySessionKey::IsProxySession::kFalse, SocketTag(),
3682 NetworkIsolationKey(), false /* disable_secure_dns */);
Bence Béky1a5d8562018-01-05 17:29:283683 base::WeakPtr<SpdySession> spdy_session =
3684 spdy_session_pool->FindAvailableSession(
Bence Békyd885b2b2018-02-03 00:58:313685 key, /* enable_ip_based_pooling = */ true,
3686 /* is_websocket = */ false, log_);
Bence Béky1a5d8562018-01-05 17:29:283687 EXPECT_EQ(1u, num_unclaimed_pushed_streams(spdy_session));
Bence Békye8955cf22018-01-02 17:31:293688
3689 // Create request matching pushed stream.
Bence Békye8955cf22018-01-02 17:31:293690 HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session());
Bence Béky1a5d8562018-01-05 17:29:283691 HttpRequestInfo request2 = CreateGetPushRequest();
Bence Békye8955cf22018-01-02 17:31:293692 TestCompletionCallback callback2;
Bence Béky1a5d8562018-01-05 17:29:283693 rv = trans2.Start(&request2, callback2.callback(), log_);
Bence Békye8955cf22018-01-02 17:31:293694 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
3695
Bence Béky1a5d8562018-01-05 17:29:283696 // Pushed stream is now claimed by second request.
3697 EXPECT_EQ(0u, num_unclaimed_pushed_streams(spdy_session));
3698
3699 // Second request receives RST_STREAM and is retried on the same connection.
Bence Békye8955cf22018-01-02 17:31:293700 rv = callback2.WaitForResult();
Bence Béky1a5d8562018-01-05 17:29:283701 EXPECT_THAT(rv, IsOk());
3702 response = trans2.GetResponseInfo();
3703 EXPECT_TRUE(response->headers);
3704 EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
3705 std::string result2;
3706 ReadResult(&trans2, &result2);
3707 EXPECT_EQ("hello!", result2);
Bence Békye8955cf22018-01-02 17:31:293708
3709 // Read EOF.
3710 base::RunLoop().RunUntilIdle();
3711
Bence Béky1a5d8562018-01-05 17:29:283712 helper.VerifyDataConsumed();
3713}
3714
3715// Regression test for https://crbug.com/776415.
3716// A client-initiated request can only pool to an existing HTTP/2 connection if
3717// the IP address matches. However, a resource can be pushed by the server on a
3718// connection even if the IP address does not match. This test verifies that if
3719// the request binds to such a pushed stream, and after that the server resets
3720// the stream before SpdySession::GetPushedStream() is called, then the retry
3721// (using a client-initiated stream) does not pool to this connection.
3722TEST_F(SpdyNetworkTransactionTest, ServerCancelsCrossOriginPush) {
3723 const char* kUrl1 = "https://www.example.org";
3724 const char* kUrl2 = "https://mail.example.org";
3725
3726 auto resolver = std::make_unique<MockHostResolver>();
3727 resolver->rules()->ClearRules();
3728 resolver->rules()->AddRule("www.example.org", "127.0.0.1");
3729 resolver->rules()->AddRule("mail.example.org", "127.0.0.2");
3730
3731 auto session_deps = std::make_unique<SpdySessionDependencies>();
3732 session_deps->host_resolver = std::move(resolver);
3733 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
3734 std::move(session_deps));
3735
Ryan Hamilton0239aac2018-05-19 00:03:133736 spdy::SpdySerializedFrame req1(spdy_util_.ConstructSpdyGet(kUrl1, 1, LOWEST));
3737 spdy::SpdySerializedFrame priority(
Bence Béky1a5d8562018-01-05 17:29:283738 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true));
3739 MockWrite writes1[] = {CreateMockWrite(req1, 0),
3740 CreateMockWrite(priority, 3)};
3741
Ryan Hamilton0239aac2018-05-19 00:03:133742 spdy::SpdySerializedFrame reply1(
3743 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
3744 spdy::SpdySerializedFrame push(
Bence Béky1a5d8562018-01-05 17:29:283745 spdy_util_.ConstructSpdyPush(nullptr, 0, 2, 1, kUrl2));
Ryan Hamilton0239aac2018-05-19 00:03:133746 spdy::SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true));
3747 spdy::SpdySerializedFrame rst(
3748 spdy_util_.ConstructSpdyRstStream(2, spdy::ERROR_CODE_INTERNAL_ERROR));
Bence Béky1a5d8562018-01-05 17:29:283749 MockRead reads1[] = {
3750 CreateMockRead(reply1, 1), CreateMockRead(push, 2),
3751 CreateMockRead(body1, 4), CreateMockRead(rst, 5),
3752 MockRead(ASYNC, ERR_IO_PENDING, 6), MockRead(ASYNC, 0, 7)};
3753
Ryan Sleevib8d7ea02018-05-07 20:01:013754 SequencedSocketData data1(reads1, writes1);
Bence Béky1a5d8562018-01-05 17:29:283755
3756 SpdyTestUtil spdy_util2;
Ryan Hamilton0239aac2018-05-19 00:03:133757 spdy::SpdySerializedFrame req2(spdy_util2.ConstructSpdyGet(kUrl2, 1, LOWEST));
Bence Béky1a5d8562018-01-05 17:29:283758 MockWrite writes2[] = {CreateMockWrite(req2, 0)};
3759
Ryan Hamilton0239aac2018-05-19 00:03:133760 spdy::SpdySerializedFrame reply2(
3761 spdy_util2.ConstructSpdyGetReply(nullptr, 0, 1));
3762 spdy::SpdySerializedFrame body2(spdy_util2.ConstructSpdyDataFrame(
Bence Békyd74f4382018-02-20 18:26:193763 1, "Response on the second connection.", true));
Bence Béky1a5d8562018-01-05 17:29:283764 MockRead reads2[] = {CreateMockRead(reply2, 1), CreateMockRead(body2, 2),
3765 MockRead(ASYNC, 0, 3)};
3766
Ryan Sleevib8d7ea02018-05-07 20:01:013767 SequencedSocketData data2(reads2, writes2);
Bence Béky1a5d8562018-01-05 17:29:283768
3769 helper.RunPreTestSetup();
3770 helper.AddData(&data1);
3771 helper.AddData(&data2);
3772
3773 // First request opens up connection to www.example.org.
3774 HttpNetworkTransaction* trans1 = helper.trans();
3775 HttpRequestInfo request1;
3776 request1.method = "GET";
3777 request1.url = GURL(kUrl1);
Ramin Halavatib5e433e62018-02-07 07:41:103778 request1.traffic_annotation =
3779 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
Bence Béky1a5d8562018-01-05 17:29:283780 TestCompletionCallback callback1;
3781 int rv = trans1->Start(&request1, callback1.callback(), log_);
3782 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
3783
3784 // Read until response body arrives. PUSH_PROMISE comes earlier.
3785 rv = callback1.WaitForResult();
3786 EXPECT_THAT(rv, IsOk());
3787 const HttpResponseInfo* response = trans1->GetResponseInfo();
3788 EXPECT_TRUE(response->headers);
3789 EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
3790 std::string result1;
3791 ReadResult(trans1, &result1);
3792 EXPECT_EQ("hello!", result1);
3793
3794 SpdySessionPool* spdy_session_pool = helper.session()->spdy_session_pool();
3795 SpdySessionKey key1(HostPortPair::FromURL(GURL(kUrl1)), ProxyServer::Direct(),
Matt Menke2436b2f2018-12-11 18:07:113796 PRIVACY_MODE_DISABLED,
dalyk51ab46b2019-10-15 15:14:343797 SpdySessionKey::IsProxySession::kFalse, SocketTag(),
3798 NetworkIsolationKey(), false /* disable_secure_dns */);
Bence Béky1a5d8562018-01-05 17:29:283799 base::WeakPtr<SpdySession> spdy_session1 =
3800 spdy_session_pool->FindAvailableSession(
Bence Békyd885b2b2018-02-03 00:58:313801 key1, /* enable_ip_based_pooling = */ true,
3802 /* is_websocket = */ false, log_);
Bence Béky1a5d8562018-01-05 17:29:283803 EXPECT_EQ(1u, num_unclaimed_pushed_streams(spdy_session1));
3804
3805 // While cross-origin push for kUrl2 is allowed on spdy_session1,
3806 // a client-initiated request would not pool to this connection,
3807 // because the IP address does not match.
3808 SpdySessionKey key2(HostPortPair::FromURL(GURL(kUrl2)), ProxyServer::Direct(),
Matt Menke2436b2f2018-12-11 18:07:113809 PRIVACY_MODE_DISABLED,
dalyk51ab46b2019-10-15 15:14:343810 SpdySessionKey::IsProxySession::kFalse, SocketTag(),
3811 NetworkIsolationKey(), false /* disable_secure_dns */);
Bence Béky1a5d8562018-01-05 17:29:283812 EXPECT_FALSE(spdy_session_pool->FindAvailableSession(
Bence Békyd885b2b2018-02-03 00:58:313813 key2, /* enable_ip_based_pooling = */ true,
3814 /* is_websocket = */ false, log_));
Bence Béky1a5d8562018-01-05 17:29:283815
3816 // Create request matching pushed stream.
3817 HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session());
3818 HttpRequestInfo request2;
3819 request2.method = "GET";
3820 request2.url = GURL(kUrl2);
Ramin Halavatib5e433e62018-02-07 07:41:103821 request2.traffic_annotation =
3822 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
Bence Béky1a5d8562018-01-05 17:29:283823 TestCompletionCallback callback2;
3824 rv = trans2.Start(&request2, callback2.callback(), log_);
3825 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
3826
3827 // Pushed stream is now claimed by second request.
3828 EXPECT_EQ(0u, num_unclaimed_pushed_streams(spdy_session1));
3829
3830 // Second request receives RST_STREAM and is retried on a new connection.
3831 rv = callback2.WaitForResult();
3832 EXPECT_THAT(rv, IsOk());
3833 response = trans2.GetResponseInfo();
3834 EXPECT_TRUE(response->headers);
3835 EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
3836 std::string result2;
3837 ReadResult(&trans2, &result2);
3838 EXPECT_EQ("Response on the second connection.", result2);
3839
3840 // Make sure that the first connection is still open. This is important in
3841 // order to test that the retry created its own connection (because the IP
3842 // address does not match), instead of using the connection of the cancelled
3843 // pushed stream.
3844 EXPECT_TRUE(spdy_session1);
3845
3846 // Read EOF.
3847 data1.Resume();
3848 base::RunLoop().RunUntilIdle();
3849
3850 helper.VerifyDataConsumed();
Bence Békye8955cf22018-01-02 17:31:293851}
3852
Matt Menke5062be22019-05-01 17:50:243853TEST_F(SpdyNetworkTransactionTest, NoConnectionPoolingOverTunnel) {
3854 // Use port 443 for two reasons: This makes the endpoint is port 443 check in
3855 // NormalSpdyTransactionHelper pass, and this means that the tunnel uses the
3856 // same port as the servers, to further confuse things.
3857 const char kPacString[] = "PROXY myproxy:443";
3858
3859 auto session_deps = std::make_unique<SpdySessionDependencies>(
Nicolas Arciniegad2013f92020-02-07 23:00:563860 ConfiguredProxyResolutionService::CreateFixedFromPacResult(
Matt Menke5062be22019-05-01 17:50:243861 kPacString, TRAFFIC_ANNOTATION_FOR_TESTS));
3862 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
3863 std::move(session_deps));
3864
3865 // Only one request uses the first connection.
3866 spdy::SpdySerializedFrame req1(
3867 spdy_util_.ConstructSpdyGet("https://www.example.org", 1, LOWEST));
3868 MockWrite writes1[] = {
3869 MockWrite(ASYNC, 0,
3870 "CONNECT www.example.org:443 HTTP/1.1\r\n"
3871 "Host: www.example.org:443\r\n"
3872 "Proxy-Connection: keep-alive\r\n\r\n"),
3873 CreateMockWrite(req1, 2),
3874 };
3875
3876 spdy::SpdySerializedFrame resp1(
3877 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
3878 spdy::SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true));
3879 MockRead reads1[] = {MockRead(ASYNC, 1, "HTTP/1.1 200 OK\r\n\r\n"),
3880 CreateMockRead(resp1, 3), CreateMockRead(body1, 4),
3881 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 5)};
3882
3883 MockConnect connect1(ASYNC, OK);
3884 SequencedSocketData data1(connect1, reads1, writes1);
3885
3886 // Run a transaction to completion to set up a SPDY session.
3887 helper.RunToCompletion(&data1);
3888 TransactionHelperResult out = helper.output();
3889 EXPECT_THAT(out.rv, IsOk());
3890 EXPECT_EQ("HTTP/1.1 200", out.status_line);
3891 EXPECT_EQ("hello!", out.response_data);
3892
3893 // A new SPDY session should have been created.
3894 SpdySessionKey key1(HostPortPair("www.example.org", 443),
3895 ProxyServer::FromPacString(kPacString),
3896 PRIVACY_MODE_DISABLED,
dalyk51ab46b2019-10-15 15:14:343897 SpdySessionKey::IsProxySession::kFalse, SocketTag(),
3898 NetworkIsolationKey(), false /* disable_secure_dns */);
Matt Menke5062be22019-05-01 17:50:243899 base::WeakPtr<SpdySession> session1 =
3900 helper.session()->spdy_session_pool()->FindAvailableSession(
3901 key1, true /* enable_up_base_pooling */, false /* is_websocket */,
3902 NetLogWithSource());
3903 ASSERT_TRUE(session1);
3904
3905 // The second request uses a second connection.
3906 SpdyTestUtil spdy_util2;
3907 spdy::SpdySerializedFrame req2(
3908 spdy_util2.ConstructSpdyGet("https://example.test", 1, LOWEST));
3909 MockWrite writes2[] = {
3910 MockWrite(ASYNC, 0,
3911 "CONNECT example.test:443 HTTP/1.1\r\n"
3912 "Host: example.test:443\r\n"
3913 "Proxy-Connection: keep-alive\r\n\r\n"),
3914 CreateMockWrite(req2, 2),
3915 };
3916
3917 spdy::SpdySerializedFrame resp2(
3918 spdy_util2.ConstructSpdyGetReply(nullptr, 0, 1));
3919 spdy::SpdySerializedFrame body2(spdy_util2.ConstructSpdyDataFrame(1, true));
3920 MockRead reads2[] = {MockRead(ASYNC, 1, "HTTP/1.1 200 OK\r\n\r\n"),
3921 CreateMockRead(resp2, 3), CreateMockRead(body2, 4),
3922 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 5)};
3923
3924 MockConnect connect2(ASYNC, OK);
3925 SequencedSocketData data2(connect2, reads2, writes2);
3926 helper.AddData(&data2);
3927
3928 HttpRequestInfo request2;
3929 request2.method = "GET";
3930 request2.url = GURL("https://example.test/");
3931 request2.load_flags = 0;
3932 request2.traffic_annotation =
3933 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
3934 auto trans2 = std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY,
3935 helper.session());
3936
3937 TestCompletionCallback callback;
3938 EXPECT_THAT(trans2->Start(&request2, callback.callback(), NetLogWithSource()),
3939 IsError(ERR_IO_PENDING));
3940
3941 // Wait for the second request to get headers. It should create a new H2
3942 // session to do so.
3943 EXPECT_THAT(callback.WaitForResult(), IsOk());
3944
3945 const HttpResponseInfo* response = trans2->GetResponseInfo();
3946 ASSERT_TRUE(response);
3947 ASSERT_TRUE(response->headers);
3948 EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
3949 EXPECT_TRUE(response->was_fetched_via_spdy);
3950 EXPECT_TRUE(response->was_alpn_negotiated);
3951 std::string response_data;
3952 ASSERT_THAT(ReadTransaction(trans2.get(), &response_data), IsOk());
3953 EXPECT_EQ("hello!", response_data);
3954
3955 // Inspect the new session.
dalyk51ab46b2019-10-15 15:14:343956 SpdySessionKey key2(
3957 HostPortPair("example.test", 443), ProxyServer::FromPacString(kPacString),
3958 PRIVACY_MODE_DISABLED, SpdySessionKey::IsProxySession::kFalse,
3959 SocketTag(), NetworkIsolationKey(), false /* disable_secure_dns */);
Matt Menke5062be22019-05-01 17:50:243960 base::WeakPtr<SpdySession> session2 =
3961 helper.session()->spdy_session_pool()->FindAvailableSession(
3962 key2, true /* enable_up_base_pooling */, false /* is_websocket */,
3963 NetLogWithSource());
3964 ASSERT_TRUE(session2);
3965 ASSERT_TRUE(session1);
3966 EXPECT_NE(session1.get(), session2.get());
3967}
3968
3969// Check that if a session is found after host resolution, but is closed before
3970// the task to try to use it executes, the request will continue to create a new
3971// socket and use it.
3972TEST_F(SpdyNetworkTransactionTest, ConnectionPoolingSessionClosedBeforeUse) {
3973 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
3974
3975 // Only one request uses the first connection.
3976 spdy::SpdySerializedFrame req1(
3977 spdy_util_.ConstructSpdyGet("https://www.example.org", 1, LOWEST));
3978 MockWrite writes1[] = {
3979 CreateMockWrite(req1, 0),
3980 };
3981
3982 spdy::SpdySerializedFrame resp1(
3983 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
3984 spdy::SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true));
3985 MockRead reads1[] = {CreateMockRead(resp1, 1), CreateMockRead(body1, 2),
3986 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 3)};
3987
3988 MockConnect connect1(ASYNC, OK);
3989 SequencedSocketData data1(connect1, reads1, writes1);
3990
3991 // Run a transaction to completion to set up a SPDY session.
3992 helper.RunToCompletion(&data1);
3993 TransactionHelperResult out = helper.output();
3994 EXPECT_THAT(out.rv, IsOk());
3995 EXPECT_EQ("HTTP/1.1 200", out.status_line);
3996 EXPECT_EQ("hello!", out.response_data);
3997
3998 // A new SPDY session should have been created.
3999 SpdySessionKey key1(HostPortPair("www.example.org", 443),
4000 ProxyServer::Direct(), PRIVACY_MODE_DISABLED,
dalyk51ab46b2019-10-15 15:14:344001 SpdySessionKey::IsProxySession::kFalse, SocketTag(),
4002 NetworkIsolationKey(), false /* disable_secure_dns */);
Matt Menke5062be22019-05-01 17:50:244003 EXPECT_TRUE(helper.session()->spdy_session_pool()->FindAvailableSession(
4004 key1, true /* enable_up_base_pooling */, false /* is_websocket */,
4005 NetLogWithSource()));
4006
4007 // The second request uses a second connection.
4008 SpdyTestUtil spdy_util2;
4009 spdy::SpdySerializedFrame req2(
4010 spdy_util2.ConstructSpdyGet("https://example.test", 1, LOWEST));
4011 MockWrite writes2[] = {
4012 CreateMockWrite(req2, 0),
4013 };
4014
4015 spdy::SpdySerializedFrame resp2(
4016 spdy_util2.ConstructSpdyGetReply(nullptr, 0, 1));
4017 spdy::SpdySerializedFrame body2(spdy_util2.ConstructSpdyDataFrame(1, true));
4018 MockRead reads2[] = {CreateMockRead(resp2, 1), CreateMockRead(body2, 2),
4019 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 3)};
4020
4021 MockConnect connect2(ASYNC, OK);
4022 SequencedSocketData data2(connect2, reads2, writes2);
4023 helper.AddData(&data2);
4024
4025 HttpRequestInfo request2;
4026 request2.method = "GET";
4027 request2.url = GURL("https://example.test/");
4028 request2.load_flags = 0;
4029 request2.traffic_annotation =
4030 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
4031 auto trans2 = std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY,
4032 helper.session());
4033
4034 // Set on-demand mode and run the second request to the DNS lookup.
4035 helper.session_deps()->host_resolver->set_ondemand_mode(true);
4036 TestCompletionCallback callback;
4037 EXPECT_THAT(trans2->Start(&request2, callback.callback(), NetLogWithSource()),
4038 IsError(ERR_IO_PENDING));
4039 base::RunLoop().RunUntilIdle();
4040 ASSERT_TRUE(helper.session_deps()->host_resolver->has_pending_requests());
4041
4042 // Resolve the request now, which should create an alias for the SpdySession
4043 // immediately, but the task to use the session for the second request should
4044 // run asynchronously, so it hasn't run yet.
4045 helper.session_deps()->host_resolver->ResolveOnlyRequestNow();
4046 SpdySessionKey key2(HostPortPair("example.test", 443), ProxyServer::Direct(),
4047 PRIVACY_MODE_DISABLED,
dalyk51ab46b2019-10-15 15:14:344048 SpdySessionKey::IsProxySession::kFalse, SocketTag(),
4049 NetworkIsolationKey(), false /* disable_secure_dns */);
Matt Menke5062be22019-05-01 17:50:244050 base::WeakPtr<SpdySession> session1 =
4051 helper.session()->spdy_session_pool()->FindAvailableSession(
4052 key2, true /* enable_up_base_pooling */, false /* is_websocket */,
4053 NetLogWithSource());
4054 ASSERT_TRUE(session1);
4055 EXPECT_EQ(key1, session1->spdy_session_key());
4056 // Remove the session before the second request can try to use it.
4057 helper.session()->spdy_session_pool()->CloseAllSessions();
4058
4059 // Wait for the second request to get headers. It should create a new H2
4060 // session to do so.
4061 EXPECT_THAT(callback.WaitForResult(), IsOk());
4062
4063 const HttpResponseInfo* response = trans2->GetResponseInfo();
4064 ASSERT_TRUE(response);
4065 ASSERT_TRUE(response->headers);
4066 EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
4067 EXPECT_TRUE(response->was_fetched_via_spdy);
4068 EXPECT_TRUE(response->was_alpn_negotiated);
4069 std::string response_data;
4070 ASSERT_THAT(ReadTransaction(trans2.get(), &response_data), IsOk());
4071 EXPECT_EQ("hello!", response_data);
4072
4073 // Inspect the new session.
4074 base::WeakPtr<SpdySession> session2 =
4075 helper.session()->spdy_session_pool()->FindAvailableSession(
4076 key2, true /* enable_up_base_pooling */, false /* is_websocket */,
4077 NetLogWithSource());
4078 ASSERT_TRUE(session2);
4079 EXPECT_EQ(key2, session2->spdy_session_key());
4080 helper.VerifyDataConsumed();
4081}
4082
4083#if defined(OS_ANDROID)
4084
4085// Test this if two HttpNetworkTransactions try to repurpose the same
4086// SpdySession with two different SocketTags, only one request gets the session,
4087// while the other makes a new SPDY session.
4088TEST_F(SpdyNetworkTransactionTest, ConnectionPoolingMultipleSocketTags) {
4089 const SocketTag kSocketTag1(SocketTag::UNSET_UID, 1);
4090 const SocketTag kSocketTag2(SocketTag::UNSET_UID, 2);
4091 const SocketTag kSocketTag3(SocketTag::UNSET_UID, 3);
4092
4093 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
4094
4095 // The first and third requests use the first connection.
4096 spdy::SpdySerializedFrame req1(
4097 spdy_util_.ConstructSpdyGet("https://www.example.org", 1, LOWEST));
4098 spdy_util_.UpdateWithStreamDestruction(1);
4099 spdy::SpdySerializedFrame req3(
4100 spdy_util_.ConstructSpdyGet("https://example.test/request3", 3, LOWEST));
4101 MockWrite writes1[] = {
4102 CreateMockWrite(req1, 0),
4103 CreateMockWrite(req3, 3),
4104 };
4105
4106 spdy::SpdySerializedFrame resp1(
4107 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
4108 spdy::SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true));
4109 spdy::SpdySerializedFrame resp3(
4110 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
4111 spdy::SpdySerializedFrame body3(spdy_util_.ConstructSpdyDataFrame(3, true));
4112 MockRead reads1[] = {CreateMockRead(resp1, 1), CreateMockRead(body1, 2),
4113 CreateMockRead(resp3, 4), CreateMockRead(body3, 5),
4114 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 6)};
4115
4116 SequencedSocketData data1(MockConnect(ASYNC, OK), reads1, writes1);
4117 helper.AddData(&data1);
4118
4119 // Due to the vagaries of how the socket pools work, in this particular case,
4120 // the second ConnectJob will be cancelled, but only after it tries to start
4121 // connecting. This does not happen in the general case of a bunch of requests
4122 // using the same socket tag.
4123 SequencedSocketData data2(MockConnect(SYNCHRONOUS, ERR_IO_PENDING),
4124 base::span<const MockRead>(),
4125 base::span<const MockWrite>());
4126 helper.AddData(&data2);
4127
4128 // The second request uses a second connection.
4129 SpdyTestUtil spdy_util2;
4130 spdy::SpdySerializedFrame req2(
4131 spdy_util2.ConstructSpdyGet("https://example.test/request2", 1, LOWEST));
4132 MockWrite writes2[] = {
4133 CreateMockWrite(req2, 0),
4134 };
4135
4136 spdy::SpdySerializedFrame resp2(
4137 spdy_util2.ConstructSpdyGetReply(nullptr, 0, 1));
4138 spdy::SpdySerializedFrame body2(spdy_util2.ConstructSpdyDataFrame(1, true));
4139 MockRead reads2[] = {CreateMockRead(resp2, 1), CreateMockRead(body2, 2),
4140 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 3)};
4141
4142 SequencedSocketData data3(MockConnect(ASYNC, OK), reads2, writes2);
4143 helper.AddData(&data3);
4144
4145 // Run a transaction to completion to set up a SPDY session. This can't use
4146 // RunToCompletion(), since it can't call VerifyDataConsumed() yet.
4147 helper.RunPreTestSetup();
4148 helper.RunDefaultTest();
4149 TransactionHelperResult out = helper.output();
4150 EXPECT_THAT(out.rv, IsOk());
4151 EXPECT_EQ("HTTP/1.1 200", out.status_line);
4152 EXPECT_EQ("hello!", out.response_data);
4153
4154 // A new SPDY session should have been created.
4155 SpdySessionKey key1(HostPortPair("www.example.org", 443),
4156 ProxyServer::Direct(), PRIVACY_MODE_DISABLED,
dalyk51ab46b2019-10-15 15:14:344157 SpdySessionKey::IsProxySession::kFalse, SocketTag(),
4158 NetworkIsolationKey(), false /* disable_secure_dns */);
Matt Menke5062be22019-05-01 17:50:244159 EXPECT_TRUE(helper.session()->spdy_session_pool()->FindAvailableSession(
4160 key1, true /* enable_up_base_pooling */, false /* is_websocket */,
4161 NetLogWithSource()));
4162
4163 // Set on-demand mode for the next two requests.
4164 helper.session_deps()->host_resolver->set_ondemand_mode(true);
4165
4166 HttpRequestInfo request2;
4167 request2.socket_tag = kSocketTag2;
4168 request2.method = "GET";
4169 request2.url = GURL("https://example.test/request2");
4170 request2.load_flags = 0;
4171 request2.traffic_annotation =
4172 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
4173 auto trans2 = std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY,
4174 helper.session());
4175 TestCompletionCallback callback2;
4176 EXPECT_THAT(
4177 trans2->Start(&request2, callback2.callback(), NetLogWithSource()),
4178 IsError(ERR_IO_PENDING));
4179
4180 HttpRequestInfo request3;
4181 request3.socket_tag = kSocketTag3;
4182 request3.method = "GET";
4183 request3.url = GURL("https://example.test/request3");
4184 request3.load_flags = 0;
4185 request3.traffic_annotation =
4186 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
4187 auto trans3 = std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY,
4188 helper.session());
4189 TestCompletionCallback callback3;
4190 EXPECT_THAT(
4191 trans3->Start(&request3, callback3.callback(), NetLogWithSource()),
4192 IsError(ERR_IO_PENDING));
4193
4194 // Run the message loop until both requests are waiting on the host resolver.
4195 base::RunLoop().RunUntilIdle();
4196 ASSERT_TRUE(helper.session_deps()->host_resolver->has_pending_requests());
4197
4198 // Complete the second requests's DNS lookup now, which should create an alias
4199 // for the SpdySession immediately, but the task to use the session for the
4200 // second request should run asynchronously, so it hasn't run yet.
4201 helper.session_deps()->host_resolver->ResolveNow(2);
4202 SpdySessionKey key2(HostPortPair("example.test", 443), ProxyServer::Direct(),
4203 PRIVACY_MODE_DISABLED,
dalyk51ab46b2019-10-15 15:14:344204 SpdySessionKey::IsProxySession::kFalse, kSocketTag2,
4205 NetworkIsolationKey(), false /* disable_secure_dns */);
Matt Menke5062be22019-05-01 17:50:244206
4207 // Complete the third requests's DNS lookup now, which should hijack the
4208 // SpdySession from the second request.
4209 helper.session_deps()->host_resolver->ResolveNow(3);
4210 SpdySessionKey key3(HostPortPair("example.test", 443), ProxyServer::Direct(),
4211 PRIVACY_MODE_DISABLED,
dalyk51ab46b2019-10-15 15:14:344212 SpdySessionKey::IsProxySession::kFalse, kSocketTag3,
4213 NetworkIsolationKey(), false /* disable_secure_dns */);
Matt Menke5062be22019-05-01 17:50:244214
4215 // Wait for the second request to get headers. It should create a new H2
4216 // session to do so.
4217 EXPECT_THAT(callback2.WaitForResult(), IsOk());
4218
4219 const HttpResponseInfo* response = trans2->GetResponseInfo();
4220 ASSERT_TRUE(response);
4221 ASSERT_TRUE(response->headers);
4222 EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
4223 EXPECT_TRUE(response->was_fetched_via_spdy);
4224 EXPECT_TRUE(response->was_alpn_negotiated);
4225 std::string response_data;
4226 ASSERT_THAT(ReadTransaction(trans2.get(), &response_data), IsOk());
4227 EXPECT_EQ("hello!", response_data);
4228
4229 // Wait for the third request to get headers. It should have reused the first
4230 // session.
4231 EXPECT_THAT(callback3.WaitForResult(), IsOk());
4232
4233 response = trans3->GetResponseInfo();
4234 ASSERT_TRUE(response);
4235 ASSERT_TRUE(response->headers);
4236 EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
4237 EXPECT_TRUE(response->was_fetched_via_spdy);
4238 EXPECT_TRUE(response->was_alpn_negotiated);
4239 ASSERT_THAT(ReadTransaction(trans3.get(), &response_data), IsOk());
4240 EXPECT_EQ("hello!", response_data);
4241
4242 helper.VerifyDataConsumed();
4243}
4244
4245#endif // defined(OS_ANDROID)
4246
bncc055fa32017-06-19 13:44:424247// Regression test for https://crbug.com/727653.
4248TEST_F(SpdyNetworkTransactionTest, RejectServerPushWithNoMethod) {
Bence Békyeacd48f2018-05-14 11:34:334249 base::HistogramTester histogram_tester;
4250
Ryan Hamilton0239aac2018-05-19 00:03:134251 spdy::SpdySerializedFrame req(
4252 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
4253 spdy::SpdySerializedFrame rst(
4254 spdy_util_.ConstructSpdyRstStream(2, spdy::ERROR_CODE_REFUSED_STREAM));
bncc055fa32017-06-19 13:44:424255 MockWrite writes[] = {CreateMockWrite(req, 0), CreateMockWrite(rst, 3)};
4256
Ryan Hamilton0239aac2018-05-19 00:03:134257 spdy::SpdySerializedFrame reply(
4258 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
bncc055fa32017-06-19 13:44:424259
Ryan Hamilton0239aac2018-05-19 00:03:134260 spdy::SpdyHeaderBlock push_promise_header_block;
Bence Békyd2df6c1c82018-04-20 22:52:014261 spdy_util_.AddUrlToHeaderBlock(kPushedUrl, &push_promise_header_block);
Ryan Hamilton0239aac2018-05-19 00:03:134262 spdy::SpdySerializedFrame push_promise(spdy_util_.ConstructSpdyPushPromise(
Bence Békyf1d78522018-01-11 01:16:504263 1, 2, std::move(push_promise_header_block)));
bncc055fa32017-06-19 13:44:424264
Ryan Hamilton0239aac2018-05-19 00:03:134265 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
Bence Békyf1d78522018-01-11 01:16:504266 MockRead reads[] = {CreateMockRead(reply, 1), CreateMockRead(push_promise, 2),
4267 CreateMockRead(body, 4),
4268 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 5)};
bncc055fa32017-06-19 13:44:424269
Ryan Sleevib8d7ea02018-05-07 20:01:014270 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:104271 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
bncc055fa32017-06-19 13:44:424272 helper.RunToCompletion(&data);
Bence Békyeacd48f2018-05-14 11:34:334273
4274 histogram_tester.ExpectBucketCount(
4275 "Net.SpdyPushedStreamFate",
4276 static_cast<int>(SpdyPushedStreamFate::kInvalidUrl), 1);
4277 histogram_tester.ExpectTotalCount("Net.SpdyPushedStreamFate", 1);
bncc055fa32017-06-19 13:44:424278}
4279
4280// Regression test for https://crbug.com/727653.
4281TEST_F(SpdyNetworkTransactionTest, RejectServerPushWithInvalidMethod) {
Bence Békyeacd48f2018-05-14 11:34:334282 base::HistogramTester histogram_tester;
4283
Ryan Hamilton0239aac2018-05-19 00:03:134284 spdy::SpdySerializedFrame req(
4285 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
4286 spdy::SpdySerializedFrame rst(
4287 spdy_util_.ConstructSpdyRstStream(2, spdy::ERROR_CODE_REFUSED_STREAM));
bncc055fa32017-06-19 13:44:424288 MockWrite writes[] = {CreateMockWrite(req, 0), CreateMockWrite(rst, 3)};
4289
Ryan Hamilton0239aac2018-05-19 00:03:134290 spdy::SpdySerializedFrame reply(
4291 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
bncc055fa32017-06-19 13:44:424292
Ryan Hamilton0239aac2018-05-19 00:03:134293 spdy::SpdyHeaderBlock push_promise_header_block;
bncc055fa32017-06-19 13:44:424294 push_promise_header_block[":method"] = "POST";
Bence Békyd2df6c1c82018-04-20 22:52:014295 spdy_util_.AddUrlToHeaderBlock(kPushedUrl, &push_promise_header_block);
Ryan Hamilton0239aac2018-05-19 00:03:134296 spdy::SpdySerializedFrame push_promise(spdy_util_.ConstructSpdyPushPromise(
Bence Békyf1d78522018-01-11 01:16:504297 1, 2, std::move(push_promise_header_block)));
bncc055fa32017-06-19 13:44:424298
Ryan Hamilton0239aac2018-05-19 00:03:134299 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
Bence Békyf1d78522018-01-11 01:16:504300 MockRead reads[] = {CreateMockRead(reply, 1), CreateMockRead(push_promise, 2),
4301 CreateMockRead(body, 4),
4302 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 5)};
bncc055fa32017-06-19 13:44:424303
Ryan Sleevib8d7ea02018-05-07 20:01:014304 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:104305 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
bncc055fa32017-06-19 13:44:424306 helper.RunToCompletion(&data);
Bence Békyeacd48f2018-05-14 11:34:334307
4308 histogram_tester.ExpectBucketCount(
4309 "Net.SpdyPushedStreamFate",
4310 static_cast<int>(SpdyPushedStreamFate::kInvalidUrl), 1);
4311 histogram_tester.ExpectTotalCount("Net.SpdyPushedStreamFate", 1);
bncc055fa32017-06-19 13:44:424312}
4313
bnc42331402016-07-25 13:36:154314// Verify that various response headers parse correctly through the HTTP layer.
4315TEST_F(SpdyNetworkTransactionTest, ResponseHeaders) {
4316 struct ResponseHeadersTests {
Bence Békye5438512017-11-22 23:07:424317 int extra_header_count;
4318 const char* extra_headers[4];
4319 size_t expected_header_count;
Bence Béky4e83f492018-05-13 23:14:254320 base::StringPiece expected_headers[8];
Bence Békye5438512017-11-22 23:07:424321 } test_cases[] = {
4322 // No extra headers.
4323 {0, {}, 2, {"status", "200", "hello", "bye"}},
4324 // Comma-separated header value.
4325 {1,
4326 {"cookie", "val1, val2"},
4327 3,
4328 {"status", "200", "hello", "bye", "cookie", "val1, val2"}},
4329 // Multiple headers are preserved: they are joined with \0 separator in
Ryan Hamilton0239aac2018-05-19 00:03:134330 // spdy::SpdyHeaderBlock.AppendValueOrAddHeader(), then split up in
Bence Békye5438512017-11-22 23:07:424331 // HpackEncoder, then joined with \0 separator when
Ryan Hamilton0239aac2018-05-19 00:03:134332 // spdy::HpackDecoderAdapter::ListenerAdapter::OnHeader() calls
4333 // spdy::SpdyHeaderBlock.AppendValueOrAddHeader(), then split up again in
Bence Békye5438512017-11-22 23:07:424334 // HttpResponseHeaders.
4335 {2,
4336 {"content-encoding", "val1", "content-encoding", "val2"},
4337 4,
4338 {"status", "200", "hello", "bye", "content-encoding", "val1",
4339 "content-encoding", "val2"}},
4340 // Cookie header is not split up by HttpResponseHeaders.
4341 {2,
4342 {"cookie", "val1", "cookie", "val2"},
4343 3,
4344 {"status", "200", "hello", "bye", "cookie", "val1; val2"}}};
bnc7ecc1122015-09-28 13:22:494345
Avi Drissman4365a4782018-12-28 19:26:244346 for (size_t i = 0; i < base::size(test_cases); ++i) {
bncd16676a2016-07-20 16:23:014347 SpdyTestUtil spdy_test_util;
Ryan Hamilton0239aac2018-05-19 00:03:134348 spdy::SpdySerializedFrame req(
Bence Béky27ad0a12018-02-08 00:35:484349 spdy_test_util.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
bncdf80d44fd2016-07-15 20:27:414350 MockWrite writes[] = {CreateMockWrite(req, 0)};
[email protected]8b070372009-11-16 22:01:254351
Ryan Hamilton0239aac2018-05-19 00:03:134352 spdy::SpdySerializedFrame resp(spdy_test_util.ConstructSpdyGetReply(
Bence Békye5438512017-11-22 23:07:424353 test_cases[i].extra_headers, test_cases[i].extra_header_count, 1));
Ryan Hamilton0239aac2018-05-19 00:03:134354 spdy::SpdySerializedFrame body(
4355 spdy_test_util.ConstructSpdyDataFrame(1, true));
[email protected]8b070372009-11-16 22:01:254356 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:414357 CreateMockRead(resp, 1), CreateMockRead(body, 2),
rch08e3aa3e2015-05-16 14:27:524358 MockRead(ASYNC, 0, 3) // EOF
[email protected]8b070372009-11-16 22:01:254359 };
4360
Ryan Sleevib8d7ea02018-05-07 20:01:014361 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:104362 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
4363 nullptr);
[email protected]dd54bd82012-07-19 23:44:574364 helper.RunToCompletion(&data);
[email protected]3caf5542010-07-16 15:19:474365 TransactionHelperResult out = helper.output();
4366
robpercival214763f2016-07-01 23:27:014367 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:024368 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]8b070372009-11-16 22:01:254369 EXPECT_EQ("hello!", out.response_data);
4370
4371 scoped_refptr<HttpResponseHeaders> headers = out.response_info.headers;
wezca1070932016-05-26 20:30:524372 EXPECT_TRUE(headers);
olli.raula33c282f2016-01-21 12:12:494373 size_t iter = 0;
Bence Béky4e83f492018-05-13 23:14:254374 std::string name, value;
Bence Békye5438512017-11-22 23:07:424375 size_t expected_header_index = 0;
[email protected]8b070372009-11-16 22:01:254376 while (headers->EnumerateHeaderLines(&iter, &name, &value)) {
Bence Békye5438512017-11-22 23:07:424377 ASSERT_LT(expected_header_index, test_cases[i].expected_header_count)
4378 << i;
4379 EXPECT_EQ(name, test_cases[i].expected_headers[2 * expected_header_index])
4380 << i;
4381 EXPECT_EQ(value,
4382 test_cases[i].expected_headers[2 * expected_header_index + 1])
4383 << i;
4384 ++expected_header_index;
[email protected]8b070372009-11-16 22:01:254385 }
Bence Békye5438512017-11-22 23:07:424386 EXPECT_EQ(expected_header_index, test_cases[i].expected_header_count) << i;
[email protected]8b070372009-11-16 22:01:254387 }
4388}
4389
bnc42331402016-07-25 13:36:154390// Verify that various response headers parse vary fields correctly through the
4391// HTTP layer, and the response matches the request.
4392TEST_F(SpdyNetworkTransactionTest, ResponseHeadersVary) {
[email protected]3f662f12010-03-25 19:56:124393 // Modify the following data to change/add test cases:
bnc42331402016-07-25 13:36:154394 struct ResponseTests {
[email protected]3f662f12010-03-25 19:56:124395 bool vary_matches;
4396 int num_headers[2];
4397 const char* extra_headers[2][16];
4398 } test_cases[] = {
bnc7ecc1122015-09-28 13:22:494399 // Test the case of a multi-valued cookie. When the value is delimited
4400 // with NUL characters, it needs to be unfolded into multiple headers.
4401 {true,
bnca9b9e222016-07-11 20:10:404402 {1, 3},
tombergan5d22c182017-01-11 02:05:354403 {{"cookie", "val1,val2", nullptr},
Ryan Hamilton0239aac2018-05-19 00:03:134404 {spdy::kHttp2StatusHeader, "200", spdy::kHttp2PathHeader, "/index.php",
4405 "vary", "cookie", nullptr}}},
bnc7ecc1122015-09-28 13:22:494406 {// Multiple vary fields.
4407 true,
bnc7ecc1122015-09-28 13:22:494408 {2, 4},
tombergan5d22c182017-01-11 02:05:354409 {{"friend", "barney", "enemy", "snaggletooth", nullptr},
Ryan Hamilton0239aac2018-05-19 00:03:134410 {spdy::kHttp2StatusHeader, "200", spdy::kHttp2PathHeader, "/index.php",
4411 "vary", "friend", "vary", "enemy", nullptr}}},
bnca9b9e222016-07-11 20:10:404412 {// Test a '*' vary field.
Maks Orlovich722dc112017-11-10 00:29:304413 true,
bnca9b9e222016-07-11 20:10:404414 {1, 3},
tombergan5d22c182017-01-11 02:05:354415 {{"cookie", "val1,val2", nullptr},
Ryan Hamilton0239aac2018-05-19 00:03:134416 {spdy::kHttp2StatusHeader, "200", spdy::kHttp2PathHeader, "/index.php",
4417 "vary", "*", nullptr}}},
Maks Orlovich722dc112017-11-10 00:29:304418 {// Test w/o a vary field.
4419 false,
4420 {1, 2},
4421 {{"cookie", "val1,val2", nullptr},
Ryan Hamilton0239aac2018-05-19 00:03:134422 {spdy::kHttp2StatusHeader, "200", spdy::kHttp2PathHeader, "/index.php",
4423 nullptr}}},
Maks Orlovich722dc112017-11-10 00:29:304424
bnca9b9e222016-07-11 20:10:404425 {// Multiple comma-separated vary fields.
4426 true,
4427 {2, 3},
tombergan5d22c182017-01-11 02:05:354428 {{"friend", "barney", "enemy", "snaggletooth", nullptr},
Ryan Hamilton0239aac2018-05-19 00:03:134429 {spdy::kHttp2StatusHeader, "200", spdy::kHttp2PathHeader, "/index.php",
4430 "vary", "friend,enemy", nullptr}}}};
[email protected]3f662f12010-03-25 19:56:124431
Avi Drissman4365a4782018-12-28 19:26:244432 for (size_t i = 0; i < base::size(test_cases); ++i) {
bncd16676a2016-07-20 16:23:014433 SpdyTestUtil spdy_test_util;
bnc38dcd392016-02-09 23:19:494434
[email protected]3f662f12010-03-25 19:56:124435 // Construct the request.
Ryan Hamilton0239aac2018-05-19 00:03:134436 spdy::SpdySerializedFrame frame_req(spdy_test_util.ConstructSpdyGet(
Bence Béky27ad0a12018-02-08 00:35:484437 test_cases[i].extra_headers[0], test_cases[i].num_headers[0], 1,
4438 LOWEST));
[email protected]3f662f12010-03-25 19:56:124439
4440 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:414441 CreateMockWrite(frame_req, 0),
[email protected]3f662f12010-03-25 19:56:124442 };
4443
4444 // Construct the reply.
Ryan Hamilton0239aac2018-05-19 00:03:134445 spdy::SpdyHeaderBlock reply_headers;
[email protected]745aa9c2014-06-27 02:21:294446 AppendToHeaderBlock(test_cases[i].extra_headers[1],
4447 test_cases[i].num_headers[1],
4448 &reply_headers);
bnc086b39e12016-06-24 13:05:264449 // Construct the expected header reply string before moving |reply_headers|.
Bence Béky4e83f492018-05-13 23:14:254450 std::string expected_reply =
bnc086b39e12016-06-24 13:05:264451 spdy_test_util.ConstructSpdyReplyString(reply_headers);
4452
Ryan Hamilton0239aac2018-05-19 00:03:134453 spdy::SpdySerializedFrame frame_reply(
bnc086b39e12016-06-24 13:05:264454 spdy_test_util.ConstructSpdyReply(1, std::move(reply_headers)));
[email protected]3f662f12010-03-25 19:56:124455
Ryan Hamilton0239aac2018-05-19 00:03:134456 spdy::SpdySerializedFrame body(
4457 spdy_test_util.ConstructSpdyDataFrame(1, true));
[email protected]3f662f12010-03-25 19:56:124458 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:414459 CreateMockRead(frame_reply, 1), CreateMockRead(body, 2),
rch08e3aa3e2015-05-16 14:27:524460 MockRead(ASYNC, 0, 3) // EOF
[email protected]3f662f12010-03-25 19:56:124461 };
4462
[email protected]3f662f12010-03-25 19:56:124463 // Attach the headers to the request.
[email protected]8c76ae22010-04-20 22:15:434464 int header_count = test_cases[i].num_headers[0];
[email protected]3f662f12010-03-25 19:56:124465
Bence Békydb3cf652017-10-10 15:22:104466 HttpRequestInfo request;
4467 request.method = "GET";
4468 request.url = GURL(kDefaultUrl);
Ramin Halavatib5e433e62018-02-07 07:41:104469 request.traffic_annotation =
4470 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
[email protected]8c76ae22010-04-20 22:15:434471 for (int ct = 0; ct < header_count; ct++) {
4472 const char* header_key = test_cases[i].extra_headers[0][ct * 2];
4473 const char* header_value = test_cases[i].extra_headers[0][ct * 2 + 1];
4474 request.extra_headers.SetHeader(header_key, header_value);
[email protected]3f662f12010-03-25 19:56:124475 }
4476
Ryan Sleevib8d7ea02018-05-07 20:01:014477 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:104478
Bence Békyd3dde832017-09-19 19:02:314479 NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY, log_,
4480 nullptr);
Bence Békydb3cf652017-10-10 15:22:104481
[email protected]dd54bd82012-07-19 23:44:574482 helper.RunToCompletion(&data);
[email protected]3caf5542010-07-16 15:19:474483 TransactionHelperResult out = helper.output();
4484
[email protected]3f662f12010-03-25 19:56:124485 EXPECT_EQ(OK, out.rv) << i;
bnc84e7fb52015-12-02 11:50:024486 EXPECT_EQ("HTTP/1.1 200", out.status_line) << i;
[email protected]3f662f12010-03-25 19:56:124487 EXPECT_EQ("hello!", out.response_data) << i;
4488
4489 // Test the response information.
[email protected]3f662f12010-03-25 19:56:124490 EXPECT_EQ(out.response_info.vary_data.is_valid(),
4491 test_cases[i].vary_matches) << i;
4492
4493 // Check the headers.
4494 scoped_refptr<HttpResponseHeaders> headers = out.response_info.headers;
wezca1070932016-05-26 20:30:524495 ASSERT_TRUE(headers) << i;
olli.raula33c282f2016-01-21 12:12:494496 size_t iter = 0;
Bence Béky4e83f492018-05-13 23:14:254497 std::string name, value, lines;
[email protected]3f662f12010-03-25 19:56:124498 while (headers->EnumerateHeaderLines(&iter, &name, &value)) {
4499 lines.append(name);
4500 lines.append(": ");
4501 lines.append(value);
4502 lines.append("\n");
4503 }
4504
[email protected]9aa323192013-05-31 21:38:404505 EXPECT_EQ(expected_reply, lines) << i;
[email protected]3f662f12010-03-25 19:56:124506 }
4507}
4508
bnc42331402016-07-25 13:36:154509// Verify that we don't crash on invalid response headers.
4510TEST_F(SpdyNetworkTransactionTest, InvalidResponseHeaders) {
4511 struct InvalidResponseHeadersTests {
[email protected]e7f75092010-07-01 22:39:134512 int num_headers;
4513 const char* headers[10];
[email protected]dd11b932009-11-30 19:39:484514 } test_cases[] = {
bnc42331402016-07-25 13:36:154515 // Response headers missing status header
bnc7ecc1122015-09-28 13:22:494516 {
bnca9b9e222016-07-11 20:10:404517 3,
Ryan Hamilton0239aac2018-05-19 00:03:134518 {spdy::kHttp2PathHeader, "/index.php", "cookie", "val1", "cookie",
4519 "val2", nullptr},
[email protected]e7f75092010-07-01 22:39:134520 },
bnc42331402016-07-25 13:36:154521 // Response headers missing version header
bnc7ecc1122015-09-28 13:22:494522 {
Ryan Hamilton0239aac2018-05-19 00:03:134523 1, {spdy::kHttp2PathHeader, "/index.php", "status", "200", nullptr},
[email protected]e7f75092010-07-01 22:39:134524 },
bnc42331402016-07-25 13:36:154525 // Response headers with no headers
bnc7ecc1122015-09-28 13:22:494526 {
tombergan5d22c182017-01-11 02:05:354527 0, {nullptr},
bnc7ecc1122015-09-28 13:22:494528 },
[email protected]dd11b932009-11-30 19:39:484529 };
4530
Avi Drissman4365a4782018-12-28 19:26:244531 for (size_t i = 0; i < base::size(test_cases); ++i) {
bncd16676a2016-07-20 16:23:014532 SpdyTestUtil spdy_test_util;
bnc38dcd392016-02-09 23:19:494533
Ryan Hamilton0239aac2018-05-19 00:03:134534 spdy::SpdySerializedFrame req(
Bence Béky27ad0a12018-02-08 00:35:484535 spdy_test_util.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
Ryan Hamilton0239aac2018-05-19 00:03:134536 spdy::SpdySerializedFrame rst(spdy_test_util.ConstructSpdyRstStream(
4537 1, spdy::ERROR_CODE_PROTOCOL_ERROR));
[email protected]dd11b932009-11-30 19:39:484538 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:414539 CreateMockWrite(req, 0), CreateMockWrite(rst, 2),
[email protected]dd11b932009-11-30 19:39:484540 };
4541
[email protected]745aa9c2014-06-27 02:21:294542 // Construct the reply.
Ryan Hamilton0239aac2018-05-19 00:03:134543 spdy::SpdyHeaderBlock reply_headers;
[email protected]745aa9c2014-06-27 02:21:294544 AppendToHeaderBlock(
4545 test_cases[i].headers, test_cases[i].num_headers, &reply_headers);
Ryan Hamilton0239aac2018-05-19 00:03:134546 spdy::SpdySerializedFrame resp(
bnc086b39e12016-06-24 13:05:264547 spdy_test_util.ConstructSpdyReply(1, std::move(reply_headers)));
[email protected]dd11b932009-11-30 19:39:484548 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:414549 CreateMockRead(resp, 1), MockRead(ASYNC, 0, 3) // EOF
[email protected]dd11b932009-11-30 19:39:484550 };
4551
Ryan Sleevib8d7ea02018-05-07 20:01:014552 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:104553 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
4554 nullptr);
[email protected]dd54bd82012-07-19 23:44:574555 helper.RunToCompletion(&data);
[email protected]3caf5542010-07-16 15:19:474556 TransactionHelperResult out = helper.output();
Bence Békyd0d69502019-06-25 19:47:184557 EXPECT_THAT(out.rv, IsError(ERR_HTTP2_PROTOCOL_ERROR));
[email protected]dd11b932009-11-30 19:39:484558 }
4559}
4560
bncd16676a2016-07-20 16:23:014561TEST_F(SpdyNetworkTransactionTest, CorruptFrameSessionError) {
Ryan Hamilton0239aac2018-05-19 00:03:134562 spdy::SpdySerializedFrame req(
4563 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
Zhongyi Shi495af8072020-02-28 04:43:484564 spdy::SpdySerializedFrame goaway(spdy_util_.ConstructSpdyGoAway(
4565 0, spdy::ERROR_CODE_COMPRESSION_ERROR,
4566 "Framer error: 30 (HPACK_TRUNCATED_BLOCK)."));
bncdf80d44fd2016-07-15 20:27:414567 MockWrite writes[] = {CreateMockWrite(req, 0), CreateMockWrite(goaway, 2)};
[email protected]e3352df2014-03-19 05:55:424568
bnc38dcd392016-02-09 23:19:494569 // This is the length field that's too short.
Ryan Hamilton0239aac2018-05-19 00:03:134570 spdy::SpdySerializedFrame reply_wrong_length(
bnc42331402016-07-25 13:36:154571 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
Ryan Hamilton0239aac2018-05-19 00:03:134572 size_t right_size = reply_wrong_length.size() - spdy::kFrameHeaderSize;
bnc38dcd392016-02-09 23:19:494573 size_t wrong_size = right_size - 4;
Ryan Hamilton0239aac2018-05-19 00:03:134574 spdy::test::SetFrameLength(&reply_wrong_length, wrong_size);
bnc38dcd392016-02-09 23:19:494575
[email protected]e3352df2014-03-19 05:55:424576 MockRead reads[] = {
bnc42331402016-07-25 13:36:154577 MockRead(ASYNC, reply_wrong_length.data(), reply_wrong_length.size() - 4,
4578 1),
[email protected]e3352df2014-03-19 05:55:424579 };
4580
Ryan Sleevib8d7ea02018-05-07 20:01:014581 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:104582 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]e3352df2014-03-19 05:55:424583 helper.RunToCompletion(&data);
4584 TransactionHelperResult out = helper.output();
Bence Békyd0d69502019-06-25 19:47:184585 EXPECT_THAT(out.rv, IsError(ERR_HTTP2_COMPRESSION_ERROR));
[email protected]bdd1b222014-06-10 11:08:394586}
4587
bncd16676a2016-07-20 16:23:014588TEST_F(SpdyNetworkTransactionTest, GoAwayOnDecompressionFailure) {
Ryan Hamilton0239aac2018-05-19 00:03:134589 spdy::SpdySerializedFrame req(
4590 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
Zhongyi Shi495af8072020-02-28 04:43:484591 spdy::SpdySerializedFrame goaway(spdy_util_.ConstructSpdyGoAway(
4592 0, spdy::ERROR_CODE_COMPRESSION_ERROR,
4593 "Framer error: 30 (HPACK_TRUNCATED_BLOCK)."));
bncdf80d44fd2016-07-15 20:27:414594 MockWrite writes[] = {CreateMockWrite(req, 0), CreateMockWrite(goaway, 2)};
[email protected]bdd1b222014-06-10 11:08:394595
4596 // Read HEADERS with corrupted payload.
Ryan Hamilton0239aac2018-05-19 00:03:134597 spdy::SpdySerializedFrame resp(
4598 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
bncdf80d44fd2016-07-15 20:27:414599 memset(resp.data() + 12, 0xcf, resp.size() - 12);
4600 MockRead reads[] = {CreateMockRead(resp, 1)};
[email protected]bdd1b222014-06-10 11:08:394601
Ryan Sleevib8d7ea02018-05-07 20:01:014602 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:104603 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]bdd1b222014-06-10 11:08:394604 helper.RunToCompletion(&data);
4605 TransactionHelperResult out = helper.output();
Bence Békyd0d69502019-06-25 19:47:184606 EXPECT_THAT(out.rv, IsError(ERR_HTTP2_COMPRESSION_ERROR));
[email protected]bdd1b222014-06-10 11:08:394607}
4608
bncd16676a2016-07-20 16:23:014609TEST_F(SpdyNetworkTransactionTest, GoAwayOnFrameSizeError) {
Ryan Hamilton0239aac2018-05-19 00:03:134610 spdy::SpdySerializedFrame req(
4611 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
4612 spdy::SpdySerializedFrame goaway(spdy_util_.ConstructSpdyGoAway(
4613 0, spdy::ERROR_CODE_FRAME_SIZE_ERROR,
dahollingsaf3796492016-05-25 19:21:354614 "Framer error: 15 (INVALID_CONTROL_FRAME_SIZE)."));
bncdf80d44fd2016-07-15 20:27:414615 MockWrite writes[] = {CreateMockWrite(req, 0), CreateMockWrite(goaway, 2)};
[email protected]bdd1b222014-06-10 11:08:394616
4617 // Read WINDOW_UPDATE with incorrectly-sized payload.
Ryan Hamilton0239aac2018-05-19 00:03:134618 spdy::SpdySerializedFrame bad_window_update(
[email protected]bdd1b222014-06-10 11:08:394619 spdy_util_.ConstructSpdyWindowUpdate(1, 1));
Ryan Hamilton0239aac2018-05-19 00:03:134620 spdy::test::SetFrameLength(&bad_window_update, bad_window_update.size() - 1);
bncdf80d44fd2016-07-15 20:27:414621 MockRead reads[] = {CreateMockRead(bad_window_update, 1)};
[email protected]bdd1b222014-06-10 11:08:394622
Ryan Sleevib8d7ea02018-05-07 20:01:014623 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:104624 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]bdd1b222014-06-10 11:08:394625 helper.RunToCompletion(&data);
4626 TransactionHelperResult out = helper.output();
Bence Békyd0d69502019-06-25 19:47:184627 EXPECT_THAT(out.rv, IsError(ERR_HTTP2_FRAME_SIZE_ERROR));
[email protected]e3352df2014-03-19 05:55:424628}
4629
[email protected]bf2491a92009-11-29 16:39:484630// Test that we shutdown correctly on write errors.
bncd16676a2016-07-20 16:23:014631TEST_F(SpdyNetworkTransactionTest, WriteError) {
Ryan Hamilton0239aac2018-05-19 00:03:134632 spdy::SpdySerializedFrame req(
4633 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
[email protected]bf2491a92009-11-29 16:39:484634 MockWrite writes[] = {
[email protected]bdd1b222014-06-10 11:08:394635 // We'll write 10 bytes successfully
bncdf80d44fd2016-07-15 20:27:414636 MockWrite(ASYNC, req.data(), 10, 1),
[email protected]bdd1b222014-06-10 11:08:394637 // Followed by ERROR!
[email protected]bdd1b222014-06-10 11:08:394638 MockWrite(ASYNC, ERR_FAILED, 2),
mmenke666a6fea2015-12-19 04:16:334639 // Session drains and attempts to write a GOAWAY: Another ERROR!
4640 MockWrite(ASYNC, ERR_FAILED, 3),
[email protected]bf2491a92009-11-29 16:39:484641 };
4642
mmenke666a6fea2015-12-19 04:16:334643 MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
[email protected]238002d2013-10-17 02:01:404644
Ryan Sleevib8d7ea02018-05-07 20:01:014645 SequencedSocketData data(reads, writes);
[email protected]238002d2013-10-17 02:01:404646
Bence Békydb3cf652017-10-10 15:22:104647 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]238002d2013-10-17 02:01:404648 helper.RunPreTestSetup();
mmenke666a6fea2015-12-19 04:16:334649 helper.AddData(&data);
[email protected]238002d2013-10-17 02:01:404650 EXPECT_TRUE(helper.StartDefaultTest());
[email protected]238002d2013-10-17 02:01:404651 helper.FinishDefaultTest();
rch37de576c2015-05-17 20:28:174652 EXPECT_TRUE(data.AllWriteDataConsumed());
mmenke666a6fea2015-12-19 04:16:334653 EXPECT_TRUE(data.AllReadDataConsumed());
[email protected]3caf5542010-07-16 15:19:474654 TransactionHelperResult out = helper.output();
robpercival214763f2016-07-01 23:27:014655 EXPECT_THAT(out.rv, IsError(ERR_FAILED));
[email protected]bf2491a92009-11-29 16:39:484656}
4657
4658// Test that partial writes work.
bncd16676a2016-07-20 16:23:014659TEST_F(SpdyNetworkTransactionTest, PartialWrite) {
bnc42331402016-07-25 13:36:154660 // Chop the HEADERS frame into 5 chunks.
Ryan Hamilton0239aac2018-05-19 00:03:134661 spdy::SpdySerializedFrame req(
4662 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
[email protected]bf2491a92009-11-29 16:39:484663 const int kChunks = 5;
bnc3f6a8552017-05-17 13:40:344664 std::unique_ptr<MockWrite[]> writes = ChopWriteFrame(req, kChunks);
rch08e3aa3e2015-05-16 14:27:524665 for (int i = 0; i < kChunks; ++i) {
4666 writes[i].sequence_number = i;
4667 }
[email protected]bf2491a92009-11-29 16:39:484668
Ryan Hamilton0239aac2018-05-19 00:03:134669 spdy::SpdySerializedFrame resp(
4670 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
4671 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]bf2491a92009-11-29 16:39:484672 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:414673 CreateMockRead(resp, kChunks), CreateMockRead(body, kChunks + 1),
rch08e3aa3e2015-05-16 14:27:524674 MockRead(ASYNC, 0, kChunks + 2) // EOF
[email protected]bf2491a92009-11-29 16:39:484675 };
4676
Ryan Sleevib8d7ea02018-05-07 20:01:014677 SequencedSocketData data(reads, base::make_span(writes.get(), kChunks));
Bence Békydb3cf652017-10-10 15:22:104678 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]dd54bd82012-07-19 23:44:574679 helper.RunToCompletion(&data);
[email protected]3caf5542010-07-16 15:19:474680 TransactionHelperResult out = helper.output();
robpercival214763f2016-07-01 23:27:014681 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:024682 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]bf2491a92009-11-29 16:39:484683 EXPECT_EQ("hello!", out.response_data);
4684}
4685
[email protected]9e743cd2010-03-16 07:03:534686// Test that the NetLog contains good data for a simple GET request.
bncd16676a2016-07-20 16:23:014687TEST_F(SpdyNetworkTransactionTest, NetLog) {
[email protected]3deb9a52010-11-11 00:24:404688 static const char* const kExtraHeaders[] = {
4689 "user-agent", "Chrome",
4690 };
Ryan Hamilton0239aac2018-05-19 00:03:134691 spdy::SpdySerializedFrame req(
Bence Béky27ad0a12018-02-08 00:35:484692 spdy_util_.ConstructSpdyGet(kExtraHeaders, 1, 1, LOWEST));
bncdf80d44fd2016-07-15 20:27:414693 MockWrite writes[] = {CreateMockWrite(req, 0)};
[email protected]dac358042009-12-18 02:07:484694
Ryan Hamilton0239aac2018-05-19 00:03:134695 spdy::SpdySerializedFrame resp(
4696 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
4697 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]dac358042009-12-18 02:07:484698 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:414699 CreateMockRead(resp, 1), CreateMockRead(body, 2),
rch08e3aa3e2015-05-16 14:27:524700 MockRead(ASYNC, 0, 3) // EOF
[email protected]dac358042009-12-18 02:07:484701 };
4702
Matt Muellerd9342e3a2019-11-26 01:41:144703 RecordingBoundTestNetLog log;
[email protected]dac358042009-12-18 02:07:484704
Ryan Sleevib8d7ea02018-05-07 20:01:014705 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:104706 request_.extra_headers.SetHeader("User-Agent", "Chrome");
4707 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log.bound(),
4708 nullptr);
[email protected]dd54bd82012-07-19 23:44:574709 helper.RunToCompletion(&data);
[email protected]3caf5542010-07-16 15:19:474710 TransactionHelperResult out = helper.output();
robpercival214763f2016-07-01 23:27:014711 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:024712 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]dac358042009-12-18 02:07:484713 EXPECT_EQ("hello!", out.response_data);
4714
[email protected]9e743cd2010-03-16 07:03:534715 // Check that the NetLog was filled reasonably.
[email protected]3caf5542010-07-16 15:19:474716 // This test is intentionally non-specific about the exact ordering of the
4717 // log; instead we just check to make sure that certain events exist, and that
4718 // they are in the right order.
Eric Roman79cc7552019-07-19 02:17:544719 auto entries = log.GetEntries();
[email protected]b2fcd0e2010-12-01 15:19:404720
4721 EXPECT_LT(0u, entries.size());
[email protected]dac358042009-12-18 02:07:484722 int pos = 0;
mikecirone8b85c432016-09-08 19:11:004723 pos = ExpectLogContainsSomewhere(
4724 entries, 0, NetLogEventType::HTTP_TRANSACTION_SEND_REQUEST,
4725 NetLogEventPhase::BEGIN);
4726 pos = ExpectLogContainsSomewhere(
4727 entries, pos + 1, NetLogEventType::HTTP_TRANSACTION_SEND_REQUEST,
4728 NetLogEventPhase::END);
4729 pos = ExpectLogContainsSomewhere(
4730 entries, pos + 1, NetLogEventType::HTTP_TRANSACTION_READ_HEADERS,
4731 NetLogEventPhase::BEGIN);
4732 pos = ExpectLogContainsSomewhere(
4733 entries, pos + 1, NetLogEventType::HTTP_TRANSACTION_READ_HEADERS,
4734 NetLogEventPhase::END);
bnc301745a2015-03-10 03:22:164735 pos = ExpectLogContainsSomewhere(entries, pos + 1,
mikecirone8b85c432016-09-08 19:11:004736 NetLogEventType::HTTP_TRANSACTION_READ_BODY,
4737 NetLogEventPhase::BEGIN);
bnc301745a2015-03-10 03:22:164738 pos = ExpectLogContainsSomewhere(entries, pos + 1,
mikecirone8b85c432016-09-08 19:11:004739 NetLogEventType::HTTP_TRANSACTION_READ_BODY,
4740 NetLogEventPhase::END);
[email protected]3deb9a52010-11-11 00:24:404741
4742 // Check that we logged all the headers correctly
mikecirone8b85c432016-09-08 19:11:004743 pos = ExpectLogContainsSomewhere(entries, 0,
4744 NetLogEventType::HTTP2_SESSION_SEND_HEADERS,
4745 NetLogEventPhase::NONE);
[email protected]3deb9a52010-11-11 00:24:404746
Eric Roman79cc7552019-07-19 02:17:544747 ASSERT_TRUE(entries[pos].HasParams());
4748 auto* header_list = entries[pos].params.FindKey("headers");
Bence Béky66871e32018-12-06 21:11:244749 ASSERT_TRUE(header_list);
4750 ASSERT_TRUE(header_list->is_list());
4751 ASSERT_EQ(5u, header_list->GetList().size());
[email protected]f3da152d2012-06-02 01:00:574752
Bence Béky66871e32018-12-06 21:11:244753 ASSERT_TRUE(header_list->GetList()[0].is_string());
4754 EXPECT_EQ(":method: GET", header_list->GetList()[0].GetString());
4755
4756 ASSERT_TRUE(header_list->GetList()[1].is_string());
4757 EXPECT_EQ(":authority: www.example.org",
4758 header_list->GetList()[1].GetString());
4759
4760 ASSERT_TRUE(header_list->GetList()[2].is_string());
4761 EXPECT_EQ(":scheme: https", header_list->GetList()[2].GetString());
4762
4763 ASSERT_TRUE(header_list->GetList()[3].is_string());
4764 EXPECT_EQ(":path: /", header_list->GetList()[3].GetString());
4765
4766 ASSERT_TRUE(header_list->GetList()[4].is_string());
4767 EXPECT_EQ("user-agent: Chrome", header_list->GetList()[4].GetString());
[email protected]dac358042009-12-18 02:07:484768}
4769
[email protected]79d84222010-02-26 00:01:444770// Since we buffer the IO from the stream to the renderer, this test verifies
4771// that when we read out the maximum amount of data (e.g. we received 50 bytes
4772// on the network, but issued a Read for only 5 of those bytes) that the data
4773// flow still works correctly.
bncd16676a2016-07-20 16:23:014774TEST_F(SpdyNetworkTransactionTest, BufferFull) {
Ryan Hamilton0239aac2018-05-19 00:03:134775 spdy::SpdySerializedFrame req(
4776 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
bncdf80d44fd2016-07-15 20:27:414777 MockWrite writes[] = {CreateMockWrite(req, 0)};
[email protected]79d84222010-02-26 00:01:444778
[email protected]20d005f2010-07-02 19:55:434779 // 2 data frames in a single read.
Ryan Hamilton0239aac2018-05-19 00:03:134780 spdy::SpdySerializedFrame data_frame_1(
Bence Békyd74f4382018-02-20 18:26:194781 spdy_util_.ConstructSpdyDataFrame(1, "goodby", /*fin=*/false));
Ryan Hamilton0239aac2018-05-19 00:03:134782 spdy::SpdySerializedFrame data_frame_2(
Bence Békyd74f4382018-02-20 18:26:194783 spdy_util_.ConstructSpdyDataFrame(1, "e worl", /*fin=*/false));
Ryan Hamilton0239aac2018-05-19 00:03:134784 spdy::SpdySerializedFrame combined_data_frames =
bncef26b602017-06-12 22:08:194785 CombineFrames({&data_frame_1, &data_frame_2});
4786
Ryan Hamilton0239aac2018-05-19 00:03:134787 spdy::SpdySerializedFrame last_frame(
Bence Békyd74f4382018-02-20 18:26:194788 spdy_util_.ConstructSpdyDataFrame(1, "d", /*fin=*/true));
[email protected]79d84222010-02-26 00:01:444789
Ryan Hamilton0239aac2018-05-19 00:03:134790 spdy::SpdySerializedFrame resp(
4791 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
[email protected]79d84222010-02-26 00:01:444792 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:414793 CreateMockRead(resp, 1),
rch32320842015-05-16 15:57:094794 MockRead(ASYNC, ERR_IO_PENDING, 2), // Force a pause
bncef26b602017-06-12 22:08:194795 CreateMockRead(combined_data_frames, 3),
rch32320842015-05-16 15:57:094796 MockRead(ASYNC, ERR_IO_PENDING, 4), // Force a pause
bncdf80d44fd2016-07-15 20:27:414797 CreateMockRead(last_frame, 5),
rch32320842015-05-16 15:57:094798 MockRead(ASYNC, 0, 6) // EOF
[email protected]79d84222010-02-26 00:01:444799 };
4800
Ryan Sleevib8d7ea02018-05-07 20:01:014801 SequencedSocketData data(reads, writes);
[email protected]79d84222010-02-26 00:01:444802
[email protected]49639fa2011-12-20 23:22:414803 TestCompletionCallback callback;
[email protected]79d84222010-02-26 00:01:444804
Bence Békydb3cf652017-10-10 15:22:104805 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]3caf5542010-07-16 15:19:474806 helper.RunPreTestSetup();
[email protected]dd54bd82012-07-19 23:44:574807 helper.AddData(&data);
[email protected]3caf5542010-07-16 15:19:474808 HttpNetworkTransaction* trans = helper.trans();
Bence Békydb3cf652017-10-10 15:22:104809 int rv = trans->Start(&request_, callback.callback(), log_);
robpercival214763f2016-07-01 23:27:014810 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]79d84222010-02-26 00:01:444811
[email protected]3caf5542010-07-16 15:19:474812 TransactionHelperResult out = helper.output();
[email protected]79d84222010-02-26 00:01:444813 out.rv = callback.WaitForResult();
4814 EXPECT_EQ(out.rv, OK);
4815
4816 const HttpResponseInfo* response = trans->GetResponseInfo();
wezca1070932016-05-26 20:30:524817 EXPECT_TRUE(response->headers);
[email protected]79d84222010-02-26 00:01:444818 EXPECT_TRUE(response->was_fetched_via_spdy);
4819 out.status_line = response->headers->GetStatusLine();
4820 out.response_info = *response; // Make a copy so we can verify.
4821
4822 // Read Data
[email protected]49639fa2011-12-20 23:22:414823 TestCompletionCallback read_callback;
[email protected]79d84222010-02-26 00:01:444824
Bence Béky4e83f492018-05-13 23:14:254825 std::string content;
[email protected]79d84222010-02-26 00:01:444826 do {
4827 // Read small chunks at a time.
4828 const int kSmallReadSize = 3;
Victor Costan9c7302b2018-08-27 16:39:444829 scoped_refptr<IOBuffer> buf =
4830 base::MakeRefCounted<IOBuffer>(kSmallReadSize);
[email protected]90499482013-06-01 00:39:504831 rv = trans->Read(buf.get(), kSmallReadSize, read_callback.callback());
bnc301745a2015-03-10 03:22:164832 if (rv == ERR_IO_PENDING) {
mmenkee24011922015-12-17 22:12:594833 data.Resume();
[email protected]79d84222010-02-26 00:01:444834 rv = read_callback.WaitForResult();
4835 }
4836 if (rv > 0) {
4837 content.append(buf->data(), rv);
4838 } else if (rv < 0) {
4839 NOTREACHED();
4840 }
4841 } while (rv > 0);
4842
4843 out.response_data.swap(content);
4844
[email protected]30c942b2010-07-21 16:59:594845 // Flush the MessageLoop while the SpdySessionDependencies (in particular, the
[email protected]8918d282010-03-02 00:57:554846 // MockClientSocketFactory) are still alive.
[email protected]fc9d88472013-08-14 02:31:174847 base::RunLoop().RunUntilIdle();
[email protected]8918d282010-03-02 00:57:554848
[email protected]79d84222010-02-26 00:01:444849 // Verify that we consumed all test data.
[email protected]3caf5542010-07-16 15:19:474850 helper.VerifyDataConsumed();
[email protected]79d84222010-02-26 00:01:444851
robpercival214763f2016-07-01 23:27:014852 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:024853 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]79d84222010-02-26 00:01:444854 EXPECT_EQ("goodbye world", out.response_data);
4855}
4856
[email protected]8918d282010-03-02 00:57:554857// Verify that basic buffering works; when multiple data frames arrive
4858// at the same time, ensure that we don't notify a read completion for
4859// each data frame individually.
bncd16676a2016-07-20 16:23:014860TEST_F(SpdyNetworkTransactionTest, Buffering) {
Ryan Hamilton0239aac2018-05-19 00:03:134861 spdy::SpdySerializedFrame req(
4862 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
bncdf80d44fd2016-07-15 20:27:414863 MockWrite writes[] = {CreateMockWrite(req, 0)};
[email protected]8918d282010-03-02 00:57:554864
4865 // 4 data frames in a single read.
Ryan Hamilton0239aac2018-05-19 00:03:134866 spdy::SpdySerializedFrame data_frame(
Bence Békyd74f4382018-02-20 18:26:194867 spdy_util_.ConstructSpdyDataFrame(1, "message", /*fin=*/false));
Ryan Hamilton0239aac2018-05-19 00:03:134868 spdy::SpdySerializedFrame data_frame_fin(
Bence Békyd74f4382018-02-20 18:26:194869 spdy_util_.ConstructSpdyDataFrame(1, "message", /*fin=*/true));
Ryan Hamilton0239aac2018-05-19 00:03:134870 spdy::SpdySerializedFrame combined_data_frames =
bncef26b602017-06-12 22:08:194871 CombineFrames({&data_frame, &data_frame, &data_frame, &data_frame_fin});
[email protected]8918d282010-03-02 00:57:554872
Ryan Hamilton0239aac2018-05-19 00:03:134873 spdy::SpdySerializedFrame resp(
4874 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
[email protected]8918d282010-03-02 00:57:554875 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:414876 CreateMockRead(resp, 1),
rch32320842015-05-16 15:57:094877 MockRead(ASYNC, ERR_IO_PENDING, 2), // Force a pause
bncef26b602017-06-12 22:08:194878 CreateMockRead(combined_data_frames, 3), MockRead(ASYNC, 0, 4) // EOF
[email protected]8918d282010-03-02 00:57:554879 };
4880
Ryan Sleevib8d7ea02018-05-07 20:01:014881 SequencedSocketData data(reads, writes);
[email protected]8918d282010-03-02 00:57:554882
Bence Békydb3cf652017-10-10 15:22:104883 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]3caf5542010-07-16 15:19:474884 helper.RunPreTestSetup();
[email protected]dd54bd82012-07-19 23:44:574885 helper.AddData(&data);
[email protected]3caf5542010-07-16 15:19:474886 HttpNetworkTransaction* trans = helper.trans();
[email protected]8918d282010-03-02 00:57:554887
[email protected]49639fa2011-12-20 23:22:414888 TestCompletionCallback callback;
Bence Békydb3cf652017-10-10 15:22:104889 int rv = trans->Start(&request_, callback.callback(), log_);
robpercival214763f2016-07-01 23:27:014890 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]8918d282010-03-02 00:57:554891
[email protected]3caf5542010-07-16 15:19:474892 TransactionHelperResult out = helper.output();
[email protected]8918d282010-03-02 00:57:554893 out.rv = callback.WaitForResult();
4894 EXPECT_EQ(out.rv, OK);
4895
4896 const HttpResponseInfo* response = trans->GetResponseInfo();
wezca1070932016-05-26 20:30:524897 EXPECT_TRUE(response->headers);
[email protected]8918d282010-03-02 00:57:554898 EXPECT_TRUE(response->was_fetched_via_spdy);
4899 out.status_line = response->headers->GetStatusLine();
4900 out.response_info = *response; // Make a copy so we can verify.
4901
4902 // Read Data
[email protected]49639fa2011-12-20 23:22:414903 TestCompletionCallback read_callback;
[email protected]8918d282010-03-02 00:57:554904
Bence Béky4e83f492018-05-13 23:14:254905 std::string content;
[email protected]8918d282010-03-02 00:57:554906 int reads_completed = 0;
4907 do {
4908 // Read small chunks at a time.
4909 const int kSmallReadSize = 14;
Victor Costan9c7302b2018-08-27 16:39:444910 scoped_refptr<IOBuffer> buf =
4911 base::MakeRefCounted<IOBuffer>(kSmallReadSize);
[email protected]90499482013-06-01 00:39:504912 rv = trans->Read(buf.get(), kSmallReadSize, read_callback.callback());
bnc301745a2015-03-10 03:22:164913 if (rv == ERR_IO_PENDING) {
mmenkee24011922015-12-17 22:12:594914 data.Resume();
[email protected]8918d282010-03-02 00:57:554915 rv = read_callback.WaitForResult();
4916 }
4917 if (rv > 0) {
4918 EXPECT_EQ(kSmallReadSize, rv);
4919 content.append(buf->data(), rv);
4920 } else if (rv < 0) {
4921 FAIL() << "Unexpected read error: " << rv;
4922 }
4923 reads_completed++;
4924 } while (rv > 0);
4925
4926 EXPECT_EQ(3, reads_completed); // Reads are: 14 bytes, 14 bytes, 0 bytes.
4927
4928 out.response_data.swap(content);
4929
[email protected]30c942b2010-07-21 16:59:594930 // Flush the MessageLoop while the SpdySessionDependencies (in particular, the
[email protected]8918d282010-03-02 00:57:554931 // MockClientSocketFactory) are still alive.
[email protected]fc9d88472013-08-14 02:31:174932 base::RunLoop().RunUntilIdle();
[email protected]8918d282010-03-02 00:57:554933
4934 // Verify that we consumed all test data.
[email protected]3caf5542010-07-16 15:19:474935 helper.VerifyDataConsumed();
[email protected]8918d282010-03-02 00:57:554936
robpercival214763f2016-07-01 23:27:014937 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:024938 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]8918d282010-03-02 00:57:554939 EXPECT_EQ("messagemessagemessagemessage", out.response_data);
4940}
4941
4942// Verify the case where we buffer data but read it after it has been buffered.
bncd16676a2016-07-20 16:23:014943TEST_F(SpdyNetworkTransactionTest, BufferedAll) {
Ryan Hamilton0239aac2018-05-19 00:03:134944 spdy::SpdySerializedFrame req(
4945 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
bncdf80d44fd2016-07-15 20:27:414946 MockWrite writes[] = {CreateMockWrite(req, 0)};
[email protected]8918d282010-03-02 00:57:554947
[email protected]20d005f2010-07-02 19:55:434948 // 5 data frames in a single read.
Ryan Hamilton0239aac2018-05-19 00:03:134949 spdy::SpdySerializedFrame reply(
4950 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
4951 spdy::SpdySerializedFrame data_frame(
Bence Békyd74f4382018-02-20 18:26:194952 spdy_util_.ConstructSpdyDataFrame(1, "message", /*fin=*/false));
Ryan Hamilton0239aac2018-05-19 00:03:134953 spdy::SpdySerializedFrame data_frame_fin(
Bence Békyd74f4382018-02-20 18:26:194954 spdy_util_.ConstructSpdyDataFrame(1, "message", /*fin=*/true));
Ryan Hamilton0239aac2018-05-19 00:03:134955 spdy::SpdySerializedFrame combined_frames = CombineFrames(
bncef26b602017-06-12 22:08:194956 {&reply, &data_frame, &data_frame, &data_frame, &data_frame_fin});
[email protected]8918d282010-03-02 00:57:554957
4958 MockRead reads[] = {
bncef26b602017-06-12 22:08:194959 CreateMockRead(combined_frames, 1), MockRead(ASYNC, 0, 2) // EOF
[email protected]8918d282010-03-02 00:57:554960 };
4961
Ryan Sleevib8d7ea02018-05-07 20:01:014962 SequencedSocketData data(reads, writes);
[email protected]8918d282010-03-02 00:57:554963
Bence Békydb3cf652017-10-10 15:22:104964 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]3caf5542010-07-16 15:19:474965 helper.RunPreTestSetup();
[email protected]dd54bd82012-07-19 23:44:574966 helper.AddData(&data);
[email protected]3caf5542010-07-16 15:19:474967 HttpNetworkTransaction* trans = helper.trans();
[email protected]8918d282010-03-02 00:57:554968
[email protected]49639fa2011-12-20 23:22:414969 TestCompletionCallback callback;
Bence Békydb3cf652017-10-10 15:22:104970 int rv = trans->Start(&request_, callback.callback(), log_);
robpercival214763f2016-07-01 23:27:014971 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]8918d282010-03-02 00:57:554972
[email protected]3caf5542010-07-16 15:19:474973 TransactionHelperResult out = helper.output();
[email protected]8918d282010-03-02 00:57:554974 out.rv = callback.WaitForResult();
4975 EXPECT_EQ(out.rv, OK);
4976
4977 const HttpResponseInfo* response = trans->GetResponseInfo();
wezca1070932016-05-26 20:30:524978 EXPECT_TRUE(response->headers);
[email protected]8918d282010-03-02 00:57:554979 EXPECT_TRUE(response->was_fetched_via_spdy);
4980 out.status_line = response->headers->GetStatusLine();
4981 out.response_info = *response; // Make a copy so we can verify.
4982
4983 // Read Data
[email protected]49639fa2011-12-20 23:22:414984 TestCompletionCallback read_callback;
[email protected]8918d282010-03-02 00:57:554985
Bence Béky4e83f492018-05-13 23:14:254986 std::string content;
[email protected]8918d282010-03-02 00:57:554987 int reads_completed = 0;
4988 do {
4989 // Read small chunks at a time.
4990 const int kSmallReadSize = 14;
Victor Costan9c7302b2018-08-27 16:39:444991 scoped_refptr<IOBuffer> buf =
4992 base::MakeRefCounted<IOBuffer>(kSmallReadSize);
[email protected]90499482013-06-01 00:39:504993 rv = trans->Read(buf.get(), kSmallReadSize, read_callback.callback());
[email protected]8918d282010-03-02 00:57:554994 if (rv > 0) {
4995 EXPECT_EQ(kSmallReadSize, rv);
4996 content.append(buf->data(), rv);
4997 } else if (rv < 0) {
4998 FAIL() << "Unexpected read error: " << rv;
4999 }
5000 reads_completed++;
5001 } while (rv > 0);
5002
5003 EXPECT_EQ(3, reads_completed);
5004
5005 out.response_data.swap(content);
5006
[email protected]30c942b2010-07-21 16:59:595007 // Flush the MessageLoop while the SpdySessionDependencies (in particular, the
[email protected]8918d282010-03-02 00:57:555008 // MockClientSocketFactory) are still alive.
[email protected]fc9d88472013-08-14 02:31:175009 base::RunLoop().RunUntilIdle();
[email protected]8918d282010-03-02 00:57:555010
5011 // Verify that we consumed all test data.
[email protected]3caf5542010-07-16 15:19:475012 helper.VerifyDataConsumed();
[email protected]8918d282010-03-02 00:57:555013
robpercival214763f2016-07-01 23:27:015014 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:025015 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]8918d282010-03-02 00:57:555016 EXPECT_EQ("messagemessagemessagemessage", out.response_data);
5017}
5018
5019// Verify the case where we buffer data and close the connection.
bncd16676a2016-07-20 16:23:015020TEST_F(SpdyNetworkTransactionTest, BufferedClosed) {
Ryan Hamilton0239aac2018-05-19 00:03:135021 spdy::SpdySerializedFrame req(
5022 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
bncdf80d44fd2016-07-15 20:27:415023 MockWrite writes[] = {CreateMockWrite(req, 0)};
[email protected]8918d282010-03-02 00:57:555024
5025 // All data frames in a single read.
[email protected]20d005f2010-07-02 19:55:435026 // NOTE: We don't FIN the stream.
Ryan Hamilton0239aac2018-05-19 00:03:135027 spdy::SpdySerializedFrame data_frame(
Bence Békyd74f4382018-02-20 18:26:195028 spdy_util_.ConstructSpdyDataFrame(1, "message", /*fin=*/false));
Ryan Hamilton0239aac2018-05-19 00:03:135029 spdy::SpdySerializedFrame combined_data_frames =
bncef26b602017-06-12 22:08:195030 CombineFrames({&data_frame, &data_frame, &data_frame, &data_frame});
Ryan Hamilton0239aac2018-05-19 00:03:135031 spdy::SpdySerializedFrame resp(
5032 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
[email protected]8918d282010-03-02 00:57:555033 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:415034 CreateMockRead(resp, 1),
rch32320842015-05-16 15:57:095035 MockRead(ASYNC, ERR_IO_PENDING, 2), // Force a wait
bncef26b602017-06-12 22:08:195036 CreateMockRead(combined_data_frames, 3), MockRead(ASYNC, 0, 4) // EOF
[email protected]8918d282010-03-02 00:57:555037 };
5038
Ryan Sleevib8d7ea02018-05-07 20:01:015039 SequencedSocketData data(reads, writes);
[email protected]8918d282010-03-02 00:57:555040
Bence Békydb3cf652017-10-10 15:22:105041 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]3caf5542010-07-16 15:19:475042 helper.RunPreTestSetup();
[email protected]dd54bd82012-07-19 23:44:575043 helper.AddData(&data);
[email protected]3caf5542010-07-16 15:19:475044 HttpNetworkTransaction* trans = helper.trans();
[email protected]8918d282010-03-02 00:57:555045
[email protected]49639fa2011-12-20 23:22:415046 TestCompletionCallback callback;
[email protected]8918d282010-03-02 00:57:555047
Bence Békydb3cf652017-10-10 15:22:105048 int rv = trans->Start(&request_, callback.callback(), log_);
robpercival214763f2016-07-01 23:27:015049 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]8918d282010-03-02 00:57:555050
[email protected]3caf5542010-07-16 15:19:475051 TransactionHelperResult out = helper.output();
[email protected]8918d282010-03-02 00:57:555052 out.rv = callback.WaitForResult();
5053 EXPECT_EQ(out.rv, OK);
5054
5055 const HttpResponseInfo* response = trans->GetResponseInfo();
wezca1070932016-05-26 20:30:525056 EXPECT_TRUE(response->headers);
[email protected]8918d282010-03-02 00:57:555057 EXPECT_TRUE(response->was_fetched_via_spdy);
5058 out.status_line = response->headers->GetStatusLine();
5059 out.response_info = *response; // Make a copy so we can verify.
5060
5061 // Read Data
[email protected]49639fa2011-12-20 23:22:415062 TestCompletionCallback read_callback;
[email protected]8918d282010-03-02 00:57:555063
Bence Béky4e83f492018-05-13 23:14:255064 std::string content;
[email protected]8918d282010-03-02 00:57:555065 int reads_completed = 0;
5066 do {
5067 // Read small chunks at a time.
5068 const int kSmallReadSize = 14;
Victor Costan9c7302b2018-08-27 16:39:445069 scoped_refptr<IOBuffer> buf =
5070 base::MakeRefCounted<IOBuffer>(kSmallReadSize);
[email protected]90499482013-06-01 00:39:505071 rv = trans->Read(buf.get(), kSmallReadSize, read_callback.callback());
bnc301745a2015-03-10 03:22:165072 if (rv == ERR_IO_PENDING) {
mmenkee24011922015-12-17 22:12:595073 data.Resume();
[email protected]8918d282010-03-02 00:57:555074 rv = read_callback.WaitForResult();
5075 }
5076 if (rv > 0) {
5077 content.append(buf->data(), rv);
5078 } else if (rv < 0) {
5079 // This test intentionally closes the connection, and will get an error.
robpercival214763f2016-07-01 23:27:015080 EXPECT_THAT(rv, IsError(ERR_CONNECTION_CLOSED));
[email protected]8918d282010-03-02 00:57:555081 break;
5082 }
5083 reads_completed++;
5084 } while (rv > 0);
5085
5086 EXPECT_EQ(0, reads_completed);
5087
5088 out.response_data.swap(content);
5089
[email protected]30c942b2010-07-21 16:59:595090 // Flush the MessageLoop while the SpdySessionDependencies (in particular, the
[email protected]8918d282010-03-02 00:57:555091 // MockClientSocketFactory) are still alive.
[email protected]fc9d88472013-08-14 02:31:175092 base::RunLoop().RunUntilIdle();
[email protected]8918d282010-03-02 00:57:555093
5094 // Verify that we consumed all test data.
[email protected]3caf5542010-07-16 15:19:475095 helper.VerifyDataConsumed();
[email protected]8918d282010-03-02 00:57:555096}
5097
[email protected]1ed7b3dc2010-03-04 05:41:455098// Verify the case where we buffer data and cancel the transaction.
bncd16676a2016-07-20 16:23:015099TEST_F(SpdyNetworkTransactionTest, BufferedCancelled) {
Ryan Hamilton0239aac2018-05-19 00:03:135100 spdy::SpdySerializedFrame req(
5101 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
5102 spdy::SpdySerializedFrame rst(
5103 spdy_util_.ConstructSpdyRstStream(1, spdy::ERROR_CODE_CANCEL));
bncdf80d44fd2016-07-15 20:27:415104 MockWrite writes[] = {CreateMockWrite(req, 0), CreateMockWrite(rst, 4)};
[email protected]1ed7b3dc2010-03-04 05:41:455105
[email protected]20d005f2010-07-02 19:55:435106 // NOTE: We don't FIN the stream.
Ryan Hamilton0239aac2018-05-19 00:03:135107 spdy::SpdySerializedFrame data_frame(
Bence Békyd74f4382018-02-20 18:26:195108 spdy_util_.ConstructSpdyDataFrame(1, "message", /*fin=*/false));
[email protected]1ed7b3dc2010-03-04 05:41:455109
Ryan Hamilton0239aac2018-05-19 00:03:135110 spdy::SpdySerializedFrame resp(
5111 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
[email protected]1ed7b3dc2010-03-04 05:41:455112 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:415113 CreateMockRead(resp, 1),
5114 MockRead(ASYNC, ERR_IO_PENDING, 2), // Force a wait
5115 CreateMockRead(data_frame, 3), MockRead(ASYNC, 0, 5) // EOF
[email protected]1ed7b3dc2010-03-04 05:41:455116 };
5117
Ryan Sleevib8d7ea02018-05-07 20:01:015118 SequencedSocketData data(reads, writes);
[email protected]1ed7b3dc2010-03-04 05:41:455119
Bence Békydb3cf652017-10-10 15:22:105120 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]3caf5542010-07-16 15:19:475121 helper.RunPreTestSetup();
[email protected]dd54bd82012-07-19 23:44:575122 helper.AddData(&data);
[email protected]3caf5542010-07-16 15:19:475123 HttpNetworkTransaction* trans = helper.trans();
[email protected]49639fa2011-12-20 23:22:415124 TestCompletionCallback callback;
[email protected]1ed7b3dc2010-03-04 05:41:455125
Bence Békydb3cf652017-10-10 15:22:105126 int rv = trans->Start(&request_, callback.callback(), log_);
robpercival214763f2016-07-01 23:27:015127 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]1ed7b3dc2010-03-04 05:41:455128
[email protected]3caf5542010-07-16 15:19:475129 TransactionHelperResult out = helper.output();
[email protected]1ed7b3dc2010-03-04 05:41:455130 out.rv = callback.WaitForResult();
5131 EXPECT_EQ(out.rv, OK);
5132
5133 const HttpResponseInfo* response = trans->GetResponseInfo();
wezca1070932016-05-26 20:30:525134 EXPECT_TRUE(response->headers);
[email protected]1ed7b3dc2010-03-04 05:41:455135 EXPECT_TRUE(response->was_fetched_via_spdy);
5136 out.status_line = response->headers->GetStatusLine();
5137 out.response_info = *response; // Make a copy so we can verify.
5138
5139 // Read Data
[email protected]49639fa2011-12-20 23:22:415140 TestCompletionCallback read_callback;
[email protected]1ed7b3dc2010-03-04 05:41:455141
[email protected]88c7b4be2014-03-19 23:04:015142 const int kReadSize = 256;
Victor Costan9c7302b2018-08-27 16:39:445143 scoped_refptr<IOBuffer> buf = base::MakeRefCounted<IOBuffer>(kReadSize);
[email protected]88c7b4be2014-03-19 23:04:015144 rv = trans->Read(buf.get(), kReadSize, read_callback.callback());
bnc301745a2015-03-10 03:22:165145 ASSERT_EQ(ERR_IO_PENDING, rv) << "Unexpected read: " << rv;
[email protected]88c7b4be2014-03-19 23:04:015146
5147 // Complete the read now, which causes buffering to start.
mmenkee24011922015-12-17 22:12:595148 data.Resume();
5149 base::RunLoop().RunUntilIdle();
[email protected]88c7b4be2014-03-19 23:04:015150 // Destroy the transaction, causing the stream to get cancelled
5151 // and orphaning the buffered IO task.
5152 helper.ResetTrans();
[email protected]1ed7b3dc2010-03-04 05:41:455153
5154 // Flush the MessageLoop; this will cause the buffered IO task
5155 // to run for the final time.
[email protected]fc9d88472013-08-14 02:31:175156 base::RunLoop().RunUntilIdle();
[email protected]3caf5542010-07-16 15:19:475157
5158 // Verify that we consumed all test data.
5159 helper.VerifyDataConsumed();
[email protected]1ed7b3dc2010-03-04 05:41:455160}
5161
bncc4769d412017-04-19 19:57:545162// Request should fail upon receiving a GOAWAY frame
5163// with Last-Stream-ID lower than the stream id corresponding to the request
5164// and with error code other than NO_ERROR.
5165TEST_F(SpdyNetworkTransactionTest, FailOnGoAway) {
Ryan Hamilton0239aac2018-05-19 00:03:135166 spdy::SpdySerializedFrame req(
5167 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
bncdf80d44fd2016-07-15 20:27:415168 MockWrite writes[] = {CreateMockWrite(req, 0)};
[email protected]69d717bd2010-04-21 18:43:215169
Ryan Hamilton0239aac2018-05-19 00:03:135170 spdy::SpdySerializedFrame go_away(
5171 spdy_util_.ConstructSpdyGoAway(0, spdy::ERROR_CODE_INTERNAL_ERROR, ""));
[email protected]69d717bd2010-04-21 18:43:215172 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:415173 CreateMockRead(go_away, 1),
[email protected]58cebf8f2010-07-31 19:20:165174 };
5175
Ryan Sleevib8d7ea02018-05-07 20:01:015176 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:105177 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]dd54bd82012-07-19 23:44:575178 helper.RunToCompletion(&data);
[email protected]58cebf8f2010-07-31 19:20:165179 TransactionHelperResult out = helper.output();
robpercival214763f2016-07-01 23:27:015180 EXPECT_THAT(out.rv, IsError(ERR_ABORTED));
[email protected]69d717bd2010-04-21 18:43:215181}
5182
bncc4769d412017-04-19 19:57:545183// Request should be retried on a new connection upon receiving a GOAWAY frame
5184// with Last-Stream-ID lower than the stream id corresponding to the request
5185// and with error code NO_ERROR.
5186TEST_F(SpdyNetworkTransactionTest, RetryOnGoAway) {
Bence Békydb3cf652017-10-10 15:22:105187 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
bncc4769d412017-04-19 19:57:545188
5189 // First connection.
Ryan Hamilton0239aac2018-05-19 00:03:135190 spdy::SpdySerializedFrame req(
5191 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
bncc4769d412017-04-19 19:57:545192 MockWrite writes1[] = {CreateMockWrite(req, 0)};
Ryan Hamilton0239aac2018-05-19 00:03:135193 spdy::SpdySerializedFrame go_away(
5194 spdy_util_.ConstructSpdyGoAway(0, spdy::ERROR_CODE_NO_ERROR, ""));
bncc4769d412017-04-19 19:57:545195 MockRead reads1[] = {CreateMockRead(go_away, 1)};
Ryan Sleevib8d7ea02018-05-07 20:01:015196 SequencedSocketData data1(reads1, writes1);
bncc4769d412017-04-19 19:57:545197 helper.AddData(&data1);
5198
5199 // Second connection.
5200 MockWrite writes2[] = {CreateMockWrite(req, 0)};
Ryan Hamilton0239aac2018-05-19 00:03:135201 spdy::SpdySerializedFrame resp(
5202 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
5203 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
bncc4769d412017-04-19 19:57:545204 MockRead reads2[] = {CreateMockRead(resp, 1), CreateMockRead(body, 2),
5205 MockRead(ASYNC, 0, 3)};
Ryan Sleevib8d7ea02018-05-07 20:01:015206 SequencedSocketData data2(reads2, writes2);
bncc4769d412017-04-19 19:57:545207 helper.AddData(&data2);
5208
5209 helper.RunPreTestSetup();
5210 helper.RunDefaultTest();
5211
5212 TransactionHelperResult out = helper.output();
5213 EXPECT_THAT(out.rv, IsOk());
5214
5215 helper.VerifyDataConsumed();
5216}
5217
bnc1fc7b352017-01-12 17:51:025218// A server can gracefully shut down by sending a GOAWAY frame
5219// with maximum last-stream-id value.
5220// Transactions started before receiving such a GOAWAY frame should succeed,
5221// but SpdySession should be unavailable for new streams.
5222TEST_F(SpdyNetworkTransactionTest, GracefulGoaway) {
Ryan Hamilton0239aac2018-05-19 00:03:135223 spdy::SpdySerializedFrame req1(
5224 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
bnc1fc7b352017-01-12 17:51:025225 spdy_util_.UpdateWithStreamDestruction(1);
Ryan Hamilton0239aac2018-05-19 00:03:135226 spdy::SpdySerializedFrame req2(
bnc1fc7b352017-01-12 17:51:025227 spdy_util_.ConstructSpdyGet("https://www.example.org/foo", 3, LOWEST));
5228 MockWrite writes[] = {CreateMockWrite(req1, 0), CreateMockWrite(req2, 3)};
5229
Ryan Hamilton0239aac2018-05-19 00:03:135230 spdy::SpdySerializedFrame resp1(
5231 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
5232 spdy::SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true));
5233 spdy::SpdySerializedFrame goaway(spdy_util_.ConstructSpdyGoAway(
5234 0x7fffffff, spdy::ERROR_CODE_NO_ERROR, "Graceful shutdown."));
5235 spdy::SpdySerializedFrame resp2(
5236 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
5237 spdy::SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(3, true));
bnc1fc7b352017-01-12 17:51:025238 MockRead reads[] = {CreateMockRead(resp1, 1), CreateMockRead(body1, 2),
5239 CreateMockRead(goaway, 4), CreateMockRead(resp2, 5),
5240 CreateMockRead(body2, 6), MockRead(ASYNC, 0, 7)};
5241
5242 // Run first transaction.
Ryan Sleevib8d7ea02018-05-07 20:01:015243 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:105244 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
bnc1fc7b352017-01-12 17:51:025245 helper.RunPreTestSetup();
5246 helper.AddData(&data);
5247 helper.RunDefaultTest();
5248
5249 // Verify first response.
5250 TransactionHelperResult out = helper.output();
5251 EXPECT_THAT(out.rv, IsOk());
5252 EXPECT_EQ("HTTP/1.1 200", out.status_line);
5253 EXPECT_EQ("hello!", out.response_data);
5254
5255 // GOAWAY frame has not yet been received, SpdySession should be available.
5256 SpdySessionPool* spdy_session_pool = helper.session()->spdy_session_pool();
5257 SpdySessionKey key(host_port_pair_, ProxyServer::Direct(),
Matt Menke2436b2f2018-12-11 18:07:115258 PRIVACY_MODE_DISABLED,
dalyk51ab46b2019-10-15 15:14:345259 SpdySessionKey::IsProxySession::kFalse, SocketTag(),
5260 NetworkIsolationKey(), false /* disable_secure_dns */);
bnc1fc7b352017-01-12 17:51:025261 base::WeakPtr<SpdySession> spdy_session =
bnc9ead3ae2017-03-16 00:48:155262 spdy_session_pool->FindAvailableSession(
Bence Békyd885b2b2018-02-03 00:58:315263 key, /* enable_ip_based_pooling = */ true,
5264 /* is_websocket = */ false, log_);
bnc1fc7b352017-01-12 17:51:025265 EXPECT_TRUE(spdy_session);
5266
5267 // Start second transaction.
5268 HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session());
5269 TestCompletionCallback callback;
5270 HttpRequestInfo request2;
5271 request2.method = "GET";
5272 request2.url = GURL("https://www.example.org/foo");
Ramin Halavatib5e433e62018-02-07 07:41:105273 request2.traffic_annotation =
5274 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
Bence Békyd3dde832017-09-19 19:02:315275 int rv = trans2.Start(&request2, callback.callback(), log_);
bnc1fc7b352017-01-12 17:51:025276 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
5277 rv = callback.WaitForResult();
5278 EXPECT_THAT(rv, IsOk());
5279
5280 // Verify second response.
5281 const HttpResponseInfo* response = trans2.GetResponseInfo();
5282 ASSERT_TRUE(response);
5283 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP2, response->connection_info);
5284 ASSERT_TRUE(response->headers);
5285 EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
5286 EXPECT_TRUE(response->was_fetched_via_spdy);
5287 EXPECT_TRUE(response->was_alpn_negotiated);
Tsuyoshi Horo01faed62019-02-20 22:11:375288 EXPECT_EQ("127.0.0.1", response->remote_endpoint.ToStringWithoutPort());
5289 EXPECT_EQ(443, response->remote_endpoint.port());
Bence Béky4e83f492018-05-13 23:14:255290 std::string response_data;
bnc1fc7b352017-01-12 17:51:025291 rv = ReadTransaction(&trans2, &response_data);
5292 EXPECT_THAT(rv, IsOk());
5293 EXPECT_EQ("hello!", response_data);
5294
5295 // Graceful GOAWAY was received, SpdySession should be unavailable.
bnc9ead3ae2017-03-16 00:48:155296 spdy_session = spdy_session_pool->FindAvailableSession(
Bence Békyd885b2b2018-02-03 00:58:315297 key, /* enable_ip_based_pooling = */ true,
5298 /* is_websocket = */ false, log_);
bnc1fc7b352017-01-12 17:51:025299 EXPECT_FALSE(spdy_session);
5300
5301 helper.VerifyDataConsumed();
5302}
5303
bncd16676a2016-07-20 16:23:015304TEST_F(SpdyNetworkTransactionTest, CloseWithActiveStream) {
Ryan Hamilton0239aac2018-05-19 00:03:135305 spdy::SpdySerializedFrame req(
5306 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
bncdf80d44fd2016-07-15 20:27:415307 MockWrite writes[] = {CreateMockWrite(req, 0)};
[email protected]f5ed21552010-05-04 18:39:545308
Ryan Hamilton0239aac2018-05-19 00:03:135309 spdy::SpdySerializedFrame resp(
5310 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
[email protected]f5ed21552010-05-04 18:39:545311 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:415312 CreateMockRead(resp, 1), MockRead(SYNCHRONOUS, 0, 2) // EOF
[email protected]f5ed21552010-05-04 18:39:545313 };
5314
Ryan Sleevib8d7ea02018-05-07 20:01:015315 SequencedSocketData data(reads, writes);
bnc4d782f492016-08-18 13:50:005316
Bence Békydb3cf652017-10-10 15:22:105317 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]3caf5542010-07-16 15:19:475318 helper.RunPreTestSetup();
[email protected]dd54bd82012-07-19 23:44:575319 helper.AddData(&data);
bnc4d782f492016-08-18 13:50:005320 helper.StartDefaultTest();
5321 EXPECT_THAT(helper.output().rv, IsError(ERR_IO_PENDING));
[email protected]f5ed21552010-05-04 18:39:545322
bnc4d782f492016-08-18 13:50:005323 helper.WaitForCallbackToComplete();
5324 EXPECT_THAT(helper.output().rv, IsError(ERR_CONNECTION_CLOSED));
[email protected]3caf5542010-07-16 15:19:475325
bnc4d782f492016-08-18 13:50:005326 const HttpResponseInfo* response = helper.trans()->GetResponseInfo();
wezca1070932016-05-26 20:30:525327 EXPECT_TRUE(response->headers);
[email protected]f5ed21552010-05-04 18:39:545328 EXPECT_TRUE(response->was_fetched_via_spdy);
[email protected]f5ed21552010-05-04 18:39:545329
5330 // Verify that we consumed all test data.
[email protected]3caf5542010-07-16 15:19:475331 helper.VerifyDataConsumed();
[email protected]f5ed21552010-05-04 18:39:545332}
[email protected]58cebf8f2010-07-31 19:20:165333
Bence Békyc2d37952017-11-20 16:58:165334TEST_F(SpdyNetworkTransactionTest, GoAwayImmediately) {
Ryan Hamilton0239aac2018-05-19 00:03:135335 spdy::SpdySerializedFrame goaway(spdy_util_.ConstructSpdyGoAway(1));
Bence Békyc2d37952017-11-20 16:58:165336 MockRead reads[] = {CreateMockRead(goaway, 0, SYNCHRONOUS)};
Ryan Sleevib8d7ea02018-05-07 20:01:015337 SequencedSocketData data(reads, base::span<MockWrite>());
Bence Békyc2d37952017-11-20 16:58:165338
5339 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
5340 helper.RunPreTestSetup();
5341 helper.AddData(&data);
5342 helper.StartDefaultTest();
5343 EXPECT_THAT(helper.output().rv, IsError(ERR_IO_PENDING));
5344
5345 helper.WaitForCallbackToComplete();
5346 EXPECT_THAT(helper.output().rv, IsError(ERR_CONNECTION_CLOSED));
5347
5348 const HttpResponseInfo* response = helper.trans()->GetResponseInfo();
5349 EXPECT_FALSE(response->headers);
5350 EXPECT_TRUE(response->was_fetched_via_spdy);
5351
5352 // Verify that we consumed all test data.
5353 helper.VerifyDataConsumed();
5354}
5355
bncfacdd852015-01-09 19:22:545356// Retry with HTTP/1.1 when receiving HTTP_1_1_REQUIRED. Note that no actual
5357// protocol negotiation happens, instead this test forces protocols for both
5358// sockets.
bncd16676a2016-07-20 16:23:015359TEST_F(SpdyNetworkTransactionTest, HTTP11RequiredRetry) {
Bence Békydb3cf652017-10-10 15:22:105360 request_.method = "GET";
bncfacdd852015-01-09 19:22:545361 // Do not force SPDY so that second socket can negotiate HTTP/1.1.
Bence Békydb3cf652017-10-10 15:22:105362 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
bncfacdd852015-01-09 19:22:545363
5364 // First socket: HTTP/2 request rejected with HTTP_1_1_REQUIRED.
Ryan Hamilton0239aac2018-05-19 00:03:135365 spdy::SpdyHeaderBlock headers(
5366 spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
5367 spdy::SpdySerializedFrame req(
bnc42331402016-07-25 13:36:155368 spdy_util_.ConstructSpdyHeaders(1, std::move(headers), LOWEST, true));
bncdf80d44fd2016-07-15 20:27:415369 MockWrite writes0[] = {CreateMockWrite(req, 0)};
Ryan Hamilton0239aac2018-05-19 00:03:135370 spdy::SpdySerializedFrame rst(
5371 spdy_util_.ConstructSpdyRstStream(1, spdy::ERROR_CODE_HTTP_1_1_REQUIRED));
Bence Békycb3613122017-09-19 17:06:575372 MockRead reads0[] = {CreateMockRead(rst, 1)};
Ryan Sleevib8d7ea02018-05-07 20:01:015373 SequencedSocketData data0(reads0, writes0);
bncfacdd852015-01-09 19:22:545374
Jeremy Roman0579ed62017-08-29 15:56:195375 auto ssl_provider0 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
bncfacdd852015-01-09 19:22:545376 // Expect HTTP/2 protocols too in SSLConfig.
Bence Béky27a19b82018-01-30 14:58:365377 ssl_provider0->next_protos_expected_in_ssl_config =
5378 NextProtoVector{kProtoHTTP2, kProtoHTTP11};
bncfacdd852015-01-09 19:22:545379 // Force SPDY.
bnc3cf2a592016-08-11 14:48:365380 ssl_provider0->next_proto = kProtoHTTP2;
dchengc7eeda422015-12-26 03:56:485381 helper.AddDataWithSSLSocketDataProvider(&data0, std::move(ssl_provider0));
bncfacdd852015-01-09 19:22:545382
5383 // Second socket: falling back to HTTP/1.1.
rch08e3aa3e2015-05-16 14:27:525384 MockWrite writes1[] = {MockWrite(ASYNC, 0,
5385 "GET / HTTP/1.1\r\n"
5386 "Host: www.example.org\r\n"
5387 "Connection: keep-alive\r\n\r\n")};
5388 MockRead reads1[] = {MockRead(ASYNC, 1,
5389 "HTTP/1.1 200 OK\r\n"
5390 "Content-Length: 5\r\n\r\n"
5391 "hello")};
Ryan Sleevib8d7ea02018-05-07 20:01:015392 SequencedSocketData data1(reads1, writes1);
bncfacdd852015-01-09 19:22:545393
Jeremy Roman0579ed62017-08-29 15:56:195394 auto ssl_provider1 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
bncfacdd852015-01-09 19:22:545395 // Expect only HTTP/1.1 protocol in SSLConfig.
Bence Béky27a19b82018-01-30 14:58:365396 ssl_provider1->next_protos_expected_in_ssl_config =
5397 NextProtoVector{kProtoHTTP11};
bncfacdd852015-01-09 19:22:545398 // Force HTTP/1.1.
bnc3cf2a592016-08-11 14:48:365399 ssl_provider1->next_proto = kProtoHTTP11;
dchengc7eeda422015-12-26 03:56:485400 helper.AddDataWithSSLSocketDataProvider(&data1, std::move(ssl_provider1));
bncfacdd852015-01-09 19:22:545401
bnc525e175a2016-06-20 12:36:405402 HttpServerProperties* http_server_properties =
bncfacdd852015-01-09 19:22:545403 helper.session()->spdy_session_pool()->http_server_properties();
Matt Menkef2ee07c2019-08-29 02:10:365404 EXPECT_FALSE(http_server_properties->RequiresHTTP11(
5405 url::SchemeHostPort(request_.url), NetworkIsolationKey()));
bncfacdd852015-01-09 19:22:545406
5407 helper.RunPreTestSetup();
5408 helper.StartDefaultTest();
5409 helper.FinishDefaultTestWithoutVerification();
5410 helper.VerifyDataConsumed();
Matt Menkef2ee07c2019-08-29 02:10:365411 EXPECT_TRUE(http_server_properties->RequiresHTTP11(
5412 url::SchemeHostPort(request_.url), NetworkIsolationKey()));
bncfacdd852015-01-09 19:22:545413
5414 const HttpResponseInfo* response = helper.trans()->GetResponseInfo();
wezca1070932016-05-26 20:30:525415 ASSERT_TRUE(response);
5416 ASSERT_TRUE(response->headers);
bncfacdd852015-01-09 19:22:545417 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
5418 EXPECT_FALSE(response->was_fetched_via_spdy);
mmenke8210acc2016-07-11 16:34:525419 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP1_1,
5420 response->connection_info);
bnc94c92842016-09-21 15:22:525421 EXPECT_TRUE(response->was_alpn_negotiated);
Bence Békydb3cf652017-10-10 15:22:105422 EXPECT_TRUE(request_.url.SchemeIs("https"));
Tsuyoshi Horo01faed62019-02-20 22:11:375423 EXPECT_EQ("127.0.0.1", response->remote_endpoint.ToStringWithoutPort());
5424 EXPECT_EQ(443, response->remote_endpoint.port());
Bence Béky4e83f492018-05-13 23:14:255425 std::string response_data;
robpercival214763f2016-07-01 23:27:015426 ASSERT_THAT(ReadTransaction(helper.trans(), &response_data), IsOk());
bncfacdd852015-01-09 19:22:545427 EXPECT_EQ("hello", response_data);
5428}
5429
Matt Menkef2ee07c2019-08-29 02:10:365430// Same as above test, but checks that NetworkIsolationKeys are respected.
5431TEST_F(SpdyNetworkTransactionTest, HTTP11RequiredRetryWithNetworkIsolationKey) {
5432 const url::Origin kOrigin1 = url::Origin::Create(GURL("https://foo.test/"));
5433 const url::Origin kOrigin2 = url::Origin::Create(GURL("https://bar.test/"));
5434 const NetworkIsolationKey kNetworkIsolationKey1(kOrigin1, kOrigin1);
5435 const NetworkIsolationKey kNetworkIsolationKey2(kOrigin2, kOrigin2);
5436
5437 const NetworkIsolationKey kNetworkIsolationKeys[] = {
5438 kNetworkIsolationKey1, kNetworkIsolationKey2, NetworkIsolationKey()};
5439
5440 base::test::ScopedFeatureList feature_list;
5441 feature_list.InitWithFeatures(
5442 // enabled_features
5443 {features::kPartitionHttpServerPropertiesByNetworkIsolationKey,
5444 // Need to partition connections by NetworkIsolationKey for
5445 // SpdySessionKeys to include NetworkIsolationKeys.
5446 features::kPartitionConnectionsByNetworkIsolationKey},
5447 // disabled_features
5448 {});
5449
5450 // Do not force SPDY so that sockets can negotiate HTTP/1.1.
5451 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
5452
5453 // For each server, set up and tear down a QUIC session cleanly, and check
5454 // that stats have been added to HttpServerProperties using the correct
5455 // NetworkIsolationKey.
5456 for (size_t i = 0; i < base::size(kNetworkIsolationKeys); ++i) {
5457 SCOPED_TRACE(i);
5458
5459 request_.method = "GET";
5460 request_.network_isolation_key = kNetworkIsolationKeys[i];
5461
5462 // First socket: HTTP/2 request rejected with HTTP_1_1_REQUIRED.
5463 SpdyTestUtil spdy_util;
5464 spdy::SpdyHeaderBlock headers(
5465 spdy_util.ConstructGetHeaderBlock(kDefaultUrl));
5466 spdy::SpdySerializedFrame req(
5467 spdy_util.ConstructSpdyHeaders(1, std::move(headers), LOWEST, true));
5468 MockWrite writes0[] = {CreateMockWrite(req, 0)};
5469 spdy::SpdySerializedFrame rst(spdy_util.ConstructSpdyRstStream(
5470 1, spdy::ERROR_CODE_HTTP_1_1_REQUIRED));
5471 MockRead reads0[] = {CreateMockRead(rst, 1)};
5472 SequencedSocketData data0(reads0, writes0);
5473
5474 auto ssl_provider0 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
5475 // Expect HTTP/2 protocols too in SSLConfig.
5476 ssl_provider0->next_protos_expected_in_ssl_config =
5477 NextProtoVector{kProtoHTTP2, kProtoHTTP11};
5478 // Force SPDY.
5479 ssl_provider0->next_proto = kProtoHTTP2;
5480 helper.AddDataWithSSLSocketDataProvider(&data0, std::move(ssl_provider0));
5481
5482 // Second socket: falling back to HTTP/1.1.
5483 MockWrite writes1[] = {MockWrite(ASYNC, 0,
5484 "GET / HTTP/1.1\r\n"
5485 "Host: www.example.org\r\n"
5486 "Connection: keep-alive\r\n\r\n")};
5487 MockRead reads1[] = {MockRead(ASYNC, 1,
5488 "HTTP/1.1 200 OK\r\n"
5489 "Content-Length: 5\r\n\r\n"
5490 "hello")};
5491 SequencedSocketData data1(reads1, writes1);
5492
5493 auto ssl_provider1 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
5494 // Expect only HTTP/1.1 protocol in SSLConfig.
5495 ssl_provider1->next_protos_expected_in_ssl_config =
5496 NextProtoVector{kProtoHTTP11};
5497 // Force HTTP/1.1.
5498 ssl_provider1->next_proto = kProtoHTTP11;
5499 helper.AddDataWithSSLSocketDataProvider(&data1, std::move(ssl_provider1));
5500
5501 HttpServerProperties* http_server_properties =
5502 helper.session()->spdy_session_pool()->http_server_properties();
5503 EXPECT_FALSE(http_server_properties->RequiresHTTP11(
5504 url::SchemeHostPort(request_.url), kNetworkIsolationKeys[i]));
5505
5506 HttpNetworkTransaction trans(DEFAULT_PRIORITY, helper.session());
5507
5508 TestCompletionCallback callback;
5509 int rv = trans.Start(&request_, callback.callback(), log_);
5510 EXPECT_THAT(callback.GetResult(rv), IsOk());
5511
5512 const HttpResponseInfo* response = trans.GetResponseInfo();
5513 ASSERT_TRUE(response);
5514 ASSERT_TRUE(response->headers);
5515 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
5516 EXPECT_FALSE(response->was_fetched_via_spdy);
5517 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP1_1,
5518 response->connection_info);
5519 EXPECT_TRUE(response->was_alpn_negotiated);
5520 EXPECT_TRUE(request_.url.SchemeIs("https"));
5521 EXPECT_EQ("127.0.0.1", response->remote_endpoint.ToStringWithoutPort());
5522 EXPECT_EQ(443, response->remote_endpoint.port());
5523 std::string response_data;
5524 ASSERT_THAT(ReadTransaction(&trans, &response_data), IsOk());
5525 EXPECT_EQ("hello", response_data);
5526
5527 for (size_t j = 0; j < base::size(kNetworkIsolationKeys); ++j) {
5528 // NetworkIsolationKeys up to kNetworkIsolationKeys[j] are known to
5529 // require HTTP/1.1, others are not.
5530 if (j <= i) {
5531 EXPECT_TRUE(http_server_properties->RequiresHTTP11(
5532 url::SchemeHostPort(request_.url), kNetworkIsolationKeys[j]));
5533 } else {
5534 EXPECT_FALSE(http_server_properties->RequiresHTTP11(
5535 url::SchemeHostPort(request_.url), kNetworkIsolationKeys[j]));
5536 }
5537 }
5538 }
5539}
5540
bncfacdd852015-01-09 19:22:545541// Retry with HTTP/1.1 to the proxy when receiving HTTP_1_1_REQUIRED from the
5542// proxy. Note that no actual protocol negotiation happens, instead this test
5543// forces protocols for both sockets.
bncd16676a2016-07-20 16:23:015544TEST_F(SpdyNetworkTransactionTest, HTTP11RequiredProxyRetry) {
Bence Békydb3cf652017-10-10 15:22:105545 request_.method = "GET";
Jeremy Roman0579ed62017-08-29 15:56:195546 auto session_deps = std::make_unique<SpdySessionDependencies>(
Nicolas Arciniegad2013f92020-02-07 23:00:565547 ConfiguredProxyResolutionService::CreateFixedFromPacResult(
Ramin Halavatica8d5252018-03-12 05:33:495548 "HTTPS myproxy:70", TRAFFIC_ANNOTATION_FOR_TESTS));
bncfacdd852015-01-09 19:22:545549 // Do not force SPDY so that second socket can negotiate HTTP/1.1.
Bence Békydb3cf652017-10-10 15:22:105550 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
Bence Békyd3dde832017-09-19 19:02:315551 std::move(session_deps));
bncfacdd852015-01-09 19:22:545552
5553 // First socket: HTTP/2 CONNECT rejected with HTTP_1_1_REQUIRED.
Ryan Hamilton0239aac2018-05-19 00:03:135554 spdy::SpdySerializedFrame req(spdy_util_.ConstructSpdyConnect(
Matt Menke6e879bd2019-03-18 17:26:045555 nullptr, 0, 1, HttpProxyConnectJob::kH2QuicTunnelPriority,
5556 HostPortPair("www.example.org", 443)));
bncdf80d44fd2016-07-15 20:27:415557 MockWrite writes0[] = {CreateMockWrite(req, 0)};
Ryan Hamilton0239aac2018-05-19 00:03:135558 spdy::SpdySerializedFrame rst(
5559 spdy_util_.ConstructSpdyRstStream(1, spdy::ERROR_CODE_HTTP_1_1_REQUIRED));
Bence Békycb3613122017-09-19 17:06:575560 MockRead reads0[] = {CreateMockRead(rst, 1)};
Ryan Sleevib8d7ea02018-05-07 20:01:015561 SequencedSocketData data0(reads0, writes0);
bncfacdd852015-01-09 19:22:545562
Jeremy Roman0579ed62017-08-29 15:56:195563 auto ssl_provider0 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
bncfacdd852015-01-09 19:22:545564 // Expect HTTP/2 protocols too in SSLConfig.
Bence Béky27a19b82018-01-30 14:58:365565 ssl_provider0->next_protos_expected_in_ssl_config =
5566 NextProtoVector{kProtoHTTP2, kProtoHTTP11};
bncfacdd852015-01-09 19:22:545567 // Force SPDY.
bnc3cf2a592016-08-11 14:48:365568 ssl_provider0->next_proto = kProtoHTTP2;
dchengc7eeda422015-12-26 03:56:485569 helper.AddDataWithSSLSocketDataProvider(&data0, std::move(ssl_provider0));
bncfacdd852015-01-09 19:22:545570
5571 // Second socket: retry using HTTP/1.1.
5572 MockWrite writes1[] = {
rch08e3aa3e2015-05-16 14:27:525573 MockWrite(ASYNC, 0,
bncce36dca22015-04-21 22:11:235574 "CONNECT www.example.org:443 HTTP/1.1\r\n"
rsleevidb16bb02015-11-12 23:47:175575 "Host: www.example.org:443\r\n"
bncfacdd852015-01-09 19:22:545576 "Proxy-Connection: keep-alive\r\n\r\n"),
rch08e3aa3e2015-05-16 14:27:525577 MockWrite(ASYNC, 2,
bncfacdd852015-01-09 19:22:545578 "GET / HTTP/1.1\r\n"
bncce36dca22015-04-21 22:11:235579 "Host: www.example.org\r\n"
bncfacdd852015-01-09 19:22:545580 "Connection: keep-alive\r\n\r\n"),
5581 };
5582
5583 MockRead reads1[] = {
rch08e3aa3e2015-05-16 14:27:525584 MockRead(ASYNC, 1, "HTTP/1.1 200 OK\r\n\r\n"),
5585 MockRead(ASYNC, 3,
bncfacdd852015-01-09 19:22:545586 "HTTP/1.1 200 OK\r\n"
5587 "Content-Length: 5\r\n\r\n"
5588 "hello"),
5589 };
Ryan Sleevib8d7ea02018-05-07 20:01:015590 SequencedSocketData data1(reads1, writes1);
bncfacdd852015-01-09 19:22:545591
Jeremy Roman0579ed62017-08-29 15:56:195592 auto ssl_provider1 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
bncfacdd852015-01-09 19:22:545593 // Expect only HTTP/1.1 protocol in SSLConfig.
Bence Béky27a19b82018-01-30 14:58:365594 ssl_provider1->next_protos_expected_in_ssl_config =
5595 NextProtoVector{kProtoHTTP11};
bncfacdd852015-01-09 19:22:545596 // Force HTTP/1.1.
bnc3cf2a592016-08-11 14:48:365597 ssl_provider1->next_proto = kProtoHTTP11;
dchengc7eeda422015-12-26 03:56:485598 helper.AddDataWithSSLSocketDataProvider(&data1, std::move(ssl_provider1));
bncfacdd852015-01-09 19:22:545599
5600 // A third socket is needed for the tunnelled connection.
Jeremy Roman0579ed62017-08-29 15:56:195601 auto ssl_provider2 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
bncfacdd852015-01-09 19:22:545602 helper.session_deps()->socket_factory->AddSSLSocketDataProvider(
5603 ssl_provider2.get());
5604
bnc525e175a2016-06-20 12:36:405605 HttpServerProperties* http_server_properties =
bncfacdd852015-01-09 19:22:545606 helper.session()->spdy_session_pool()->http_server_properties();
Matt Menkef2ee07c2019-08-29 02:10:365607 url::SchemeHostPort proxy_scheme_host_port(url::kHttpsScheme, "myproxy", 70);
5608 EXPECT_FALSE(http_server_properties->RequiresHTTP11(proxy_scheme_host_port,
5609 NetworkIsolationKey()));
bncfacdd852015-01-09 19:22:545610
5611 helper.RunPreTestSetup();
5612 helper.StartDefaultTest();
5613 helper.FinishDefaultTestWithoutVerification();
5614 helper.VerifyDataConsumed();
Matt Menkef2ee07c2019-08-29 02:10:365615 EXPECT_TRUE(http_server_properties->RequiresHTTP11(proxy_scheme_host_port,
5616 NetworkIsolationKey()));
bncfacdd852015-01-09 19:22:545617
5618 const HttpResponseInfo* response = helper.trans()->GetResponseInfo();
wezca1070932016-05-26 20:30:525619 ASSERT_TRUE(response);
5620 ASSERT_TRUE(response->headers);
bncfacdd852015-01-09 19:22:545621 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
5622 EXPECT_FALSE(response->was_fetched_via_spdy);
mmenke8210acc2016-07-11 16:34:525623 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP1_1,
5624 response->connection_info);
bnc94c92842016-09-21 15:22:525625 EXPECT_FALSE(response->was_alpn_negotiated);
Bence Békydb3cf652017-10-10 15:22:105626 EXPECT_TRUE(request_.url.SchemeIs("https"));
Tsuyoshi Horo01faed62019-02-20 22:11:375627 EXPECT_EQ("127.0.0.1", response->remote_endpoint.ToStringWithoutPort());
5628 EXPECT_EQ(70, response->remote_endpoint.port());
Bence Béky4e83f492018-05-13 23:14:255629 std::string response_data;
robpercival214763f2016-07-01 23:27:015630 ASSERT_THAT(ReadTransaction(helper.trans(), &response_data), IsOk());
bncfacdd852015-01-09 19:22:545631 EXPECT_EQ("hello", response_data);
5632}
5633
Matt Menkef2ee07c2019-08-29 02:10:365634// Same as above, but also test that NetworkIsolationKeys are respected.
5635TEST_F(SpdyNetworkTransactionTest,
5636 HTTP11RequiredProxyRetryWithNetworkIsolationKey) {
5637 const url::Origin kOrigin1 = url::Origin::Create(GURL("https://foo.test/"));
5638 const url::Origin kOrigin2 = url::Origin::Create(GURL("https://bar.test/"));
5639 const NetworkIsolationKey kNetworkIsolationKey1(kOrigin1, kOrigin1);
5640 const NetworkIsolationKey kNetworkIsolationKey2(kOrigin2, kOrigin2);
5641
5642 const NetworkIsolationKey kNetworkIsolationKeys[] = {
5643 kNetworkIsolationKey1, kNetworkIsolationKey2, NetworkIsolationKey()};
5644
5645 base::test::ScopedFeatureList feature_list;
5646 feature_list.InitWithFeatures(
5647 // enabled_features
5648 {features::kPartitionHttpServerPropertiesByNetworkIsolationKey,
5649 // Need to partition connections by NetworkIsolationKey for
5650 // SpdySessionKeys to include NetworkIsolationKeys.
5651 features::kPartitionConnectionsByNetworkIsolationKey},
5652 // disabled_features
5653 {});
5654
5655 request_.method = "GET";
5656 auto session_deps = std::make_unique<SpdySessionDependencies>(
Nicolas Arciniegad2013f92020-02-07 23:00:565657 ConfiguredProxyResolutionService::CreateFixedFromPacResult(
Matt Menkef2ee07c2019-08-29 02:10:365658 "HTTPS myproxy:70", TRAFFIC_ANNOTATION_FOR_TESTS));
5659 // Do not force SPDY so that second socket can negotiate HTTP/1.1.
5660 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
5661 std::move(session_deps));
5662 helper.RunPreTestSetup();
5663
5664 for (size_t i = 0; i < base::size(kNetworkIsolationKeys); ++i) {
5665 // First socket: HTTP/2 CONNECT rejected with HTTP_1_1_REQUIRED.
5666
5667 SpdyTestUtil spdy_util;
5668 spdy::SpdySerializedFrame req(spdy_util.ConstructSpdyConnect(
5669 nullptr, 0, 1, HttpProxyConnectJob::kH2QuicTunnelPriority,
5670 HostPortPair("www.example.org", 443)));
5671 MockWrite writes0[] = {CreateMockWrite(req, 0)};
5672 spdy::SpdySerializedFrame rst(spdy_util.ConstructSpdyRstStream(
5673 1, spdy::ERROR_CODE_HTTP_1_1_REQUIRED));
5674 MockRead reads0[] = {CreateMockRead(rst, 1)};
5675 SequencedSocketData data0(reads0, writes0);
5676
5677 auto ssl_provider0 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
5678 // Expect HTTP/2 protocols too in SSLConfig.
5679 ssl_provider0->next_protos_expected_in_ssl_config =
5680 NextProtoVector{kProtoHTTP2, kProtoHTTP11};
5681 // Force SPDY.
5682 ssl_provider0->next_proto = kProtoHTTP2;
5683 helper.AddDataWithSSLSocketDataProvider(&data0, std::move(ssl_provider0));
5684
5685 // Second socket: retry using HTTP/1.1.
5686 MockWrite writes1[] = {
5687 MockWrite(ASYNC, 0,
5688 "CONNECT www.example.org:443 HTTP/1.1\r\n"
5689 "Host: www.example.org:443\r\n"
5690 "Proxy-Connection: keep-alive\r\n\r\n"),
5691 MockWrite(ASYNC, 2,
5692 "GET / HTTP/1.1\r\n"
5693 "Host: www.example.org\r\n"
5694 "Connection: keep-alive\r\n\r\n"),
5695 };
5696
5697 MockRead reads1[] = {
5698 MockRead(ASYNC, 1, "HTTP/1.1 200 OK\r\n\r\n"),
5699 MockRead(ASYNC, 3,
5700 "HTTP/1.1 200 OK\r\n"
5701 "Content-Length: 5\r\n\r\n"
5702 "hello"),
5703 };
5704 SequencedSocketData data1(reads1, writes1);
5705
5706 auto ssl_provider1 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
5707 // Expect only HTTP/1.1 protocol in SSLConfig.
5708 ssl_provider1->next_protos_expected_in_ssl_config =
5709 NextProtoVector{kProtoHTTP11};
5710 // Force HTTP/1.1.
5711 ssl_provider1->next_proto = kProtoHTTP11;
5712 helper.AddDataWithSSLSocketDataProvider(&data1, std::move(ssl_provider1));
5713
5714 // A third socket is needed for the tunnelled connection.
5715 auto ssl_provider2 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
5716 helper.session_deps()->socket_factory->AddSSLSocketDataProvider(
5717 ssl_provider2.get());
5718
5719 HttpServerProperties* http_server_properties =
5720 helper.session()->spdy_session_pool()->http_server_properties();
5721 url::SchemeHostPort proxy_scheme_host_port(url::kHttpsScheme, "myproxy",
5722 70);
5723 EXPECT_FALSE(http_server_properties->RequiresHTTP11(
5724 proxy_scheme_host_port, kNetworkIsolationKeys[i]));
5725
5726 request_.network_isolation_key = kNetworkIsolationKeys[i];
5727 HttpNetworkTransaction trans(DEFAULT_PRIORITY, helper.session());
5728 TestCompletionCallback callback;
5729 int rv = trans.Start(&request_, callback.callback(), log_);
5730 EXPECT_THAT(callback.GetResult(rv), IsOk());
5731 helper.VerifyDataConsumed();
5732
5733 const HttpResponseInfo* response = trans.GetResponseInfo();
5734 ASSERT_TRUE(response);
5735 ASSERT_TRUE(response->headers);
5736 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
5737 EXPECT_FALSE(response->was_fetched_via_spdy);
5738 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP1_1,
5739 response->connection_info);
5740 EXPECT_FALSE(response->was_alpn_negotiated);
5741 EXPECT_TRUE(request_.url.SchemeIs("https"));
5742 EXPECT_EQ("127.0.0.1", response->remote_endpoint.ToStringWithoutPort());
5743 EXPECT_EQ(70, response->remote_endpoint.port());
5744 std::string response_data;
5745 ASSERT_THAT(ReadTransaction(&trans, &response_data), IsOk());
5746 EXPECT_EQ("hello", response_data);
5747
5748 for (size_t j = 0; j < base::size(kNetworkIsolationKeys); ++j) {
5749 // The proxy SchemeHostPort URL should not be marked as requiring HTTP/1.1
5750 // using the current NetworkIsolationKey, and the state of others should
5751 // be unchanged since the last loop iteration..
5752 if (j <= i) {
5753 EXPECT_TRUE(http_server_properties->RequiresHTTP11(
5754 proxy_scheme_host_port, kNetworkIsolationKeys[j]));
5755 } else {
5756 EXPECT_FALSE(http_server_properties->RequiresHTTP11(
5757 proxy_scheme_host_port, kNetworkIsolationKeys[j]));
5758 }
5759 }
5760
5761 // The destination SchemeHostPort should not be marked as requiring
5762 // HTTP/1.1.
5763 EXPECT_FALSE(http_server_properties->RequiresHTTP11(
5764 url::SchemeHostPort(request_.url), kNetworkIsolationKeys[i]));
5765 }
5766}
5767
[email protected]b261d0e2010-08-02 19:13:245768// Test to make sure we can correctly connect through a proxy.
bncd16676a2016-07-20 16:23:015769TEST_F(SpdyNetworkTransactionTest, ProxyConnect) {
Jeremy Roman0579ed62017-08-29 15:56:195770 auto session_deps = std::make_unique<SpdySessionDependencies>(
Nicolas Arciniegad2013f92020-02-07 23:00:565771 ConfiguredProxyResolutionService::CreateFixedFromPacResult(
Ramin Halavatica8d5252018-03-12 05:33:495772 "PROXY myproxy:70", TRAFFIC_ANNOTATION_FOR_TESTS));
Bence Békydb3cf652017-10-10 15:22:105773 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
tfarina428341112016-09-22 13:38:205774 std::move(session_deps));
[email protected]b261d0e2010-08-02 19:13:245775 helper.RunPreTestSetup();
5776 HttpNetworkTransaction* trans = helper.trans();
5777
rchebf12982015-04-10 01:15:005778 const char kConnect443[] = {
bncce36dca22015-04-21 22:11:235779 "CONNECT www.example.org:443 HTTP/1.1\r\n"
rsleevidb16bb02015-11-12 23:47:175780 "Host: www.example.org:443\r\n"
rchcb934f562015-04-07 16:25:125781 "Proxy-Connection: keep-alive\r\n\r\n"};
[email protected]b261d0e2010-08-02 19:13:245782 const char kHTTP200[] = {"HTTP/1.1 200 OK\r\n\r\n"};
Ryan Hamilton0239aac2018-05-19 00:03:135783 spdy::SpdySerializedFrame req(
5784 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
5785 spdy::SpdySerializedFrame resp(
5786 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
5787 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]b261d0e2010-08-02 19:13:245788
rchebf12982015-04-10 01:15:005789 MockWrite writes[] = {
Avi Drissman4365a4782018-12-28 19:26:245790 MockWrite(SYNCHRONOUS, kConnect443, base::size(kConnect443) - 1, 0),
bncdf80d44fd2016-07-15 20:27:415791 CreateMockWrite(req, 2),
[email protected]b261d0e2010-08-02 19:13:245792 };
rchebf12982015-04-10 01:15:005793 MockRead reads[] = {
Avi Drissman4365a4782018-12-28 19:26:245794 MockRead(SYNCHRONOUS, kHTTP200, base::size(kHTTP200) - 1, 1),
5795 CreateMockRead(resp, 3),
5796 CreateMockRead(body, 4),
Raul Tambre94493c652019-03-11 17:18:355797 MockRead(ASYNC, nullptr, 0, 5),
[email protected]b261d0e2010-08-02 19:13:245798 };
Ryan Sleevib8d7ea02018-05-07 20:01:015799 SequencedSocketData data(reads, writes);
[email protected]b261d0e2010-08-02 19:13:245800
Bence Béky53a5aef2018-03-29 21:54:125801 helper.AddData(&data);
[email protected]49639fa2011-12-20 23:22:415802 TestCompletionCallback callback;
[email protected]b261d0e2010-08-02 19:13:245803
Bence Békydb3cf652017-10-10 15:22:105804 int rv = trans->Start(&request_, callback.callback(), log_);
robpercival214763f2016-07-01 23:27:015805 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]b261d0e2010-08-02 19:13:245806
5807 rv = callback.WaitForResult();
5808 EXPECT_EQ(0, rv);
5809
bnc42331402016-07-25 13:36:155810 // Verify the response headers.
[email protected]b261d0e2010-08-02 19:13:245811 HttpResponseInfo response = *trans->GetResponseInfo();
wezca1070932016-05-26 20:30:525812 ASSERT_TRUE(response.headers);
bnc84e7fb52015-12-02 11:50:025813 EXPECT_EQ("HTTP/1.1 200", response.headers->GetStatusLine());
[email protected]b261d0e2010-08-02 19:13:245814
Bence Béky4e83f492018-05-13 23:14:255815 std::string response_data;
robpercival214763f2016-07-01 23:27:015816 ASSERT_THAT(ReadTransaction(trans, &response_data), IsOk());
[email protected]b261d0e2010-08-02 19:13:245817 EXPECT_EQ("hello!", response_data);
5818 helper.VerifyDataConsumed();
5819}
5820
bncce36dca22015-04-21 22:11:235821// Test to make sure we can correctly connect through a proxy to
5822// www.example.org, if there already exists a direct spdy connection to
5823// www.example.org. See https://crbug.com/49874.
bncd16676a2016-07-20 16:23:015824TEST_F(SpdyNetworkTransactionTest, DirectConnectProxyReconnect) {
[email protected]733b7a6d2010-08-25 01:38:435825 // Use a proxy service which returns a proxy fallback list from DIRECT to
5826 // myproxy:70. For this test there will be no fallback, so it is equivalent
5827 // to simply DIRECT. The reason for appending the second proxy is to verify
5828 // that the session pool key used does is just "DIRECT".
Jeremy Roman0579ed62017-08-29 15:56:195829 auto session_deps = std::make_unique<SpdySessionDependencies>(
Nicolas Arciniegad2013f92020-02-07 23:00:565830 ConfiguredProxyResolutionService::CreateFixedFromPacResult(
Ramin Halavatica8d5252018-03-12 05:33:495831 "DIRECT; PROXY myproxy:70", TRAFFIC_ANNOTATION_FOR_TESTS));
bncd16676a2016-07-20 16:23:015832 // When setting up the first transaction, we store the SpdySessionPool so that
5833 // we can use the same pool in the second transaction.
Bence Békydb3cf652017-10-10 15:22:105834 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
tfarina428341112016-09-22 13:38:205835 std::move(session_deps));
[email protected]733b7a6d2010-08-25 01:38:435836
[email protected]87bfa3f2010-09-30 14:54:565837 SpdySessionPool* spdy_session_pool = helper.session()->spdy_session_pool();
[email protected]b261d0e2010-08-02 19:13:245838 helper.RunPreTestSetup();
5839
5840 // Construct and send a simple GET request.
Ryan Hamilton0239aac2018-05-19 00:03:135841 spdy::SpdySerializedFrame req(
5842 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
[email protected]b261d0e2010-08-02 19:13:245843 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:415844 CreateMockWrite(req, 0),
[email protected]b261d0e2010-08-02 19:13:245845 };
5846
Ryan Hamilton0239aac2018-05-19 00:03:135847 spdy::SpdySerializedFrame resp(
5848 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
5849 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]b261d0e2010-08-02 19:13:245850 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:415851 CreateMockRead(resp, 1), CreateMockRead(body, 2),
rch08e3aa3e2015-05-16 14:27:525852 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 3), // Force a pause
[email protected]b261d0e2010-08-02 19:13:245853 };
Ryan Sleevib8d7ea02018-05-07 20:01:015854 SequencedSocketData data(reads, writes);
[email protected]dd54bd82012-07-19 23:44:575855 helper.AddData(&data);
[email protected]b261d0e2010-08-02 19:13:245856 HttpNetworkTransaction* trans = helper.trans();
5857
[email protected]49639fa2011-12-20 23:22:415858 TestCompletionCallback callback;
[email protected]b261d0e2010-08-02 19:13:245859 TransactionHelperResult out;
Bence Békydb3cf652017-10-10 15:22:105860 out.rv = trans->Start(&request_, callback.callback(), log_);
[email protected]b261d0e2010-08-02 19:13:245861
5862 EXPECT_EQ(out.rv, ERR_IO_PENDING);
5863 out.rv = callback.WaitForResult();
5864 EXPECT_EQ(out.rv, OK);
5865
5866 const HttpResponseInfo* response = trans->GetResponseInfo();
wezca1070932016-05-26 20:30:525867 EXPECT_TRUE(response->headers);
[email protected]b261d0e2010-08-02 19:13:245868 EXPECT_TRUE(response->was_fetched_via_spdy);
5869 out.rv = ReadTransaction(trans, &out.response_data);
robpercival214763f2016-07-01 23:27:015870 EXPECT_THAT(out.rv, IsOk());
[email protected]b261d0e2010-08-02 19:13:245871 out.status_line = response->headers->GetStatusLine();
bnc84e7fb52015-12-02 11:50:025872 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]b261d0e2010-08-02 19:13:245873 EXPECT_EQ("hello!", out.response_data);
5874
5875 // Check that the SpdySession is still in the SpdySessionPool.
Matt Menke2436b2f2018-12-11 18:07:115876 SpdySessionKey session_pool_key_direct(
5877 host_port_pair_, ProxyServer::Direct(), PRIVACY_MODE_DISABLED,
dalyk51ab46b2019-10-15 15:14:345878 SpdySessionKey::IsProxySession::kFalse, SocketTag(),
5879 NetworkIsolationKey(), false /* disable_secure_dns */);
[email protected]41d64e82013-07-03 22:44:265880 EXPECT_TRUE(HasSpdySession(spdy_session_pool, session_pool_key_direct));
[email protected]e6d017652013-05-17 18:01:405881 SpdySessionKey session_pool_key_proxy(
bncb26024382016-06-29 02:39:455882 host_port_pair_,
[email protected]e6d017652013-05-17 18:01:405883 ProxyServer::FromURI("www.foo.com", ProxyServer::SCHEME_HTTP),
Matt Menke2436b2f2018-12-11 18:07:115884 PRIVACY_MODE_DISABLED, SpdySessionKey::IsProxySession::kFalse,
dalyk51ab46b2019-10-15 15:14:345885 SocketTag(), NetworkIsolationKey(), false /* disable_secure_dns */);
[email protected]41d64e82013-07-03 22:44:265886 EXPECT_FALSE(HasSpdySession(spdy_session_pool, session_pool_key_proxy));
[email protected]b261d0e2010-08-02 19:13:245887
rdsmithebb50aa2015-11-12 03:44:385888 // New SpdyTestUtil instance for the session that will be used for the
5889 // proxy connection.
bncd16676a2016-07-20 16:23:015890 SpdyTestUtil spdy_util_2;
rdsmithebb50aa2015-11-12 03:44:385891
[email protected]b261d0e2010-08-02 19:13:245892 // Set up data for the proxy connection.
bncce36dca22015-04-21 22:11:235893 const char kConnect443[] = {
5894 "CONNECT www.example.org:443 HTTP/1.1\r\n"
rsleevidb16bb02015-11-12 23:47:175895 "Host: www.example.org:443\r\n"
bncce36dca22015-04-21 22:11:235896 "Proxy-Connection: keep-alive\r\n\r\n"};
[email protected]b261d0e2010-08-02 19:13:245897 const char kHTTP200[] = {"HTTP/1.1 200 OK\r\n\r\n"};
Ryan Hamilton0239aac2018-05-19 00:03:135898 spdy::SpdySerializedFrame req2(
5899 spdy_util_2.ConstructSpdyGet(kPushedUrl, 1, LOWEST));
5900 spdy::SpdySerializedFrame resp2(
5901 spdy_util_2.ConstructSpdyGetReply(nullptr, 0, 1));
5902 spdy::SpdySerializedFrame body2(spdy_util_2.ConstructSpdyDataFrame(1, true));
[email protected]b261d0e2010-08-02 19:13:245903
rchebf12982015-04-10 01:15:005904 MockWrite writes2[] = {
Avi Drissman4365a4782018-12-28 19:26:245905 MockWrite(SYNCHRONOUS, kConnect443, base::size(kConnect443) - 1, 0),
bncdf80d44fd2016-07-15 20:27:415906 CreateMockWrite(req2, 2),
[email protected]b261d0e2010-08-02 19:13:245907 };
rchebf12982015-04-10 01:15:005908 MockRead reads2[] = {
Avi Drissman4365a4782018-12-28 19:26:245909 MockRead(SYNCHRONOUS, kHTTP200, base::size(kHTTP200) - 1, 1),
bncdf80d44fd2016-07-15 20:27:415910 CreateMockRead(resp2, 3), CreateMockRead(body2, 4),
rchebf12982015-04-10 01:15:005911 MockRead(ASYNC, 0, 5) // EOF
[email protected]b261d0e2010-08-02 19:13:245912 };
5913
Ryan Sleevib8d7ea02018-05-07 20:01:015914 SequencedSocketData data_proxy(reads2, writes2);
[email protected]b261d0e2010-08-02 19:13:245915
bncce36dca22015-04-21 22:11:235916 // Create another request to www.example.org, but this time through a proxy.
Bence Békydb3cf652017-10-10 15:22:105917 request_.method = "GET";
Bence Békyd2df6c1c82018-04-20 22:52:015918 request_.url = GURL(kPushedUrl);
Jeremy Roman0579ed62017-08-29 15:56:195919 auto session_deps_proxy = std::make_unique<SpdySessionDependencies>(
Nicolas Arciniegad2013f92020-02-07 23:00:565920 ConfiguredProxyResolutionService::CreateFixedFromPacResult(
Ramin Halavatica8d5252018-03-12 05:33:495921 "PROXY myproxy:70", TRAFFIC_ANNOTATION_FOR_TESTS));
Bence Békydb3cf652017-10-10 15:22:105922 NormalSpdyTransactionHelper helper_proxy(request_, DEFAULT_PRIORITY, log_,
5923 std::move(session_deps_proxy));
5924
[email protected]b261d0e2010-08-02 19:13:245925 helper_proxy.RunPreTestSetup();
Bence Béky53a5aef2018-03-29 21:54:125926 helper_proxy.AddData(&data_proxy);
[email protected]b261d0e2010-08-02 19:13:245927
5928 HttpNetworkTransaction* trans_proxy = helper_proxy.trans();
[email protected]49639fa2011-12-20 23:22:415929 TestCompletionCallback callback_proxy;
Bence Békydb3cf652017-10-10 15:22:105930 int rv = trans_proxy->Start(&request_, callback_proxy.callback(), log_);
robpercival214763f2016-07-01 23:27:015931 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]b261d0e2010-08-02 19:13:245932 rv = callback_proxy.WaitForResult();
5933 EXPECT_EQ(0, rv);
5934
5935 HttpResponseInfo response_proxy = *trans_proxy->GetResponseInfo();
wezca1070932016-05-26 20:30:525936 ASSERT_TRUE(response_proxy.headers);
bnc84e7fb52015-12-02 11:50:025937 EXPECT_EQ("HTTP/1.1 200", response_proxy.headers->GetStatusLine());
[email protected]b261d0e2010-08-02 19:13:245938
Bence Béky4e83f492018-05-13 23:14:255939 std::string response_data;
robpercival214763f2016-07-01 23:27:015940 ASSERT_THAT(ReadTransaction(trans_proxy, &response_data), IsOk());
[email protected]b261d0e2010-08-02 19:13:245941 EXPECT_EQ("hello!", response_data);
5942
[email protected]b261d0e2010-08-02 19:13:245943 helper_proxy.VerifyDataConsumed();
5944}
5945
[email protected]58cebf8f2010-07-31 19:20:165946// When we get a TCP-level RST, we need to retry a HttpNetworkTransaction
5947// on a new connection, if the connection was previously known to be good.
5948// This can happen when a server reboots without saying goodbye, or when
5949// we're behind a NAT that masked the RST.
bncd16676a2016-07-20 16:23:015950TEST_F(SpdyNetworkTransactionTest, VerifyRetryOnConnectionReset) {
Ryan Hamilton0239aac2018-05-19 00:03:135951 spdy::SpdySerializedFrame resp(
5952 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
5953 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]58cebf8f2010-07-31 19:20:165954 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:415955 CreateMockRead(resp, 1), CreateMockRead(body, 2),
rch32320842015-05-16 15:57:095956 MockRead(ASYNC, ERR_IO_PENDING, 3),
5957 MockRead(ASYNC, ERR_CONNECTION_RESET, 4),
[email protected]58cebf8f2010-07-31 19:20:165958 };
5959
5960 MockRead reads2[] = {
bncdf80d44fd2016-07-15 20:27:415961 CreateMockRead(resp, 1), CreateMockRead(body, 2),
rch32320842015-05-16 15:57:095962 MockRead(ASYNC, 0, 3) // EOF
[email protected]58cebf8f2010-07-31 19:20:165963 };
5964
Ryan Hamilton0239aac2018-05-19 00:03:135965 spdy::SpdySerializedFrame req(
5966 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
rdsmithebb50aa2015-11-12 03:44:385967 // In all cases the connection will be reset before req3 can be
5968 // dispatched, destroying both streams.
5969 spdy_util_.UpdateWithStreamDestruction(1);
Ryan Hamilton0239aac2018-05-19 00:03:135970 spdy::SpdySerializedFrame req3(
5971 spdy_util_.ConstructSpdyGet(nullptr, 0, 3, LOWEST));
bncdf80d44fd2016-07-15 20:27:415972 MockWrite writes1[] = {CreateMockWrite(req, 0), CreateMockWrite(req3, 5)};
5973 MockWrite writes2[] = {CreateMockWrite(req, 0)};
rchacdcbdc2015-05-16 17:16:005974
[email protected]58cebf8f2010-07-31 19:20:165975 // This test has a couple of variants.
5976 enum {
5977 // Induce the RST while waiting for our transaction to send.
rchacdcbdc2015-05-16 17:16:005978 VARIANT_RST_DURING_SEND_COMPLETION = 0,
[email protected]58cebf8f2010-07-31 19:20:165979 // Induce the RST while waiting for our transaction to read.
5980 // In this case, the send completed - everything copied into the SNDBUF.
rchacdcbdc2015-05-16 17:16:005981 VARIANT_RST_DURING_READ_COMPLETION = 1
[email protected]58cebf8f2010-07-31 19:20:165982 };
5983
5984 for (int variant = VARIANT_RST_DURING_SEND_COMPLETION;
5985 variant <= VARIANT_RST_DURING_READ_COMPLETION;
5986 ++variant) {
Ryan Sleevib8d7ea02018-05-07 20:01:015987 SequencedSocketData data1(reads,
5988 base::make_span(writes1).first(1 + variant));
[email protected]58cebf8f2010-07-31 19:20:165989
Ryan Sleevib8d7ea02018-05-07 20:01:015990 SequencedSocketData data2(reads2, writes2);
[email protected]58cebf8f2010-07-31 19:20:165991
Bence Békydb3cf652017-10-10 15:22:105992 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
5993 nullptr);
[email protected]dd54bd82012-07-19 23:44:575994 helper.AddData(&data1);
5995 helper.AddData(&data2);
[email protected]58cebf8f2010-07-31 19:20:165996 helper.RunPreTestSetup();
5997
5998 for (int i = 0; i < 2; ++i) {
bnc691fda62016-08-12 00:43:165999 HttpNetworkTransaction trans(DEFAULT_PRIORITY, helper.session());
[email protected]58cebf8f2010-07-31 19:20:166000
[email protected]49639fa2011-12-20 23:22:416001 TestCompletionCallback callback;
Bence Békydb3cf652017-10-10 15:22:106002 int rv = trans.Start(&request_, callback.callback(), log_);
robpercival214763f2016-07-01 23:27:016003 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]58cebf8f2010-07-31 19:20:166004 // On the second transaction, we trigger the RST.
6005 if (i == 1) {
6006 if (variant == VARIANT_RST_DURING_READ_COMPLETION) {
6007 // Writes to the socket complete asynchronously on SPDY by running
6008 // through the message loop. Complete the write here.
[email protected]fc9d88472013-08-14 02:31:176009 base::RunLoop().RunUntilIdle();
[email protected]58cebf8f2010-07-31 19:20:166010 }
6011
6012 // Now schedule the ERR_CONNECTION_RESET.
mmenkee24011922015-12-17 22:12:596013 data1.Resume();
[email protected]58cebf8f2010-07-31 19:20:166014 }
6015 rv = callback.WaitForResult();
robpercival214763f2016-07-01 23:27:016016 EXPECT_THAT(rv, IsOk());
[email protected]58cebf8f2010-07-31 19:20:166017
bnc691fda62016-08-12 00:43:166018 const HttpResponseInfo* response = trans.GetResponseInfo();
wezca1070932016-05-26 20:30:526019 ASSERT_TRUE(response);
6020 EXPECT_TRUE(response->headers);
[email protected]58cebf8f2010-07-31 19:20:166021 EXPECT_TRUE(response->was_fetched_via_spdy);
Bence Béky4e83f492018-05-13 23:14:256022 std::string response_data;
bnc691fda62016-08-12 00:43:166023 rv = ReadTransaction(&trans, &response_data);
robpercival214763f2016-07-01 23:27:016024 EXPECT_THAT(rv, IsOk());
bnc84e7fb52015-12-02 11:50:026025 EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
[email protected]58cebf8f2010-07-31 19:20:166026 EXPECT_EQ("hello!", response_data);
rchacdcbdc2015-05-16 17:16:006027 base::RunLoop().RunUntilIdle();
[email protected]58cebf8f2010-07-31 19:20:166028 }
6029
6030 helper.VerifyDataConsumed();
rchacdcbdc2015-05-16 17:16:006031 base::RunLoop().RunUntilIdle();
[email protected]58cebf8f2010-07-31 19:20:166032 }
6033}
[email protected]1f418ee2010-10-16 19:46:566034
[email protected]018aabc2010-10-29 16:16:596035// Tests that Basic authentication works over SPDY
bncd16676a2016-07-20 16:23:016036TEST_F(SpdyNetworkTransactionTest, SpdyBasicAuth) {
[email protected]018aabc2010-10-29 16:16:596037 // The first request will be a bare GET, the second request will be a
6038 // GET with an Authorization header.
Ryan Hamilton0239aac2018-05-19 00:03:136039 spdy::SpdySerializedFrame req_get(
Bence Béky27ad0a12018-02-08 00:35:486040 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
rdsmithebb50aa2015-11-12 03:44:386041 // Will be refused for lack of auth.
6042 spdy_util_.UpdateWithStreamDestruction(1);
[email protected]018aabc2010-10-29 16:16:596043 const char* const kExtraAuthorizationHeaders[] = {
[email protected]cdf8f7e72013-05-23 10:56:466044 "authorization", "Basic Zm9vOmJhcg=="
[email protected]018aabc2010-10-29 16:16:596045 };
Ryan Hamilton0239aac2018-05-19 00:03:136046 spdy::SpdySerializedFrame req_get_authorization(spdy_util_.ConstructSpdyGet(
Avi Drissman4365a4782018-12-28 19:26:246047 kExtraAuthorizationHeaders, base::size(kExtraAuthorizationHeaders) / 2, 3,
Bence Béky27ad0a12018-02-08 00:35:486048 LOWEST));
[email protected]018aabc2010-10-29 16:16:596049 MockWrite spdy_writes[] = {
bncdf80d44fd2016-07-15 20:27:416050 CreateMockWrite(req_get, 0), CreateMockWrite(req_get_authorization, 3),
[email protected]018aabc2010-10-29 16:16:596051 };
6052
6053 // The first response is a 401 authentication challenge, and the second
6054 // response will be a 200 response since the second request includes a valid
6055 // Authorization header.
6056 const char* const kExtraAuthenticationHeaders[] = {
[email protected]fb9e4312012-02-17 06:27:266057 "www-authenticate",
[email protected]018aabc2010-10-29 16:16:596058 "Basic realm=\"MyRealm\""
6059 };
Ryan Hamilton0239aac2018-05-19 00:03:136060 spdy::SpdySerializedFrame resp_authentication(
6061 spdy_util_.ConstructSpdyReplyError(
6062 "401", kExtraAuthenticationHeaders,
Avi Drissman4365a4782018-12-28 19:26:246063 base::size(kExtraAuthenticationHeaders) / 2, 1));
Ryan Hamilton0239aac2018-05-19 00:03:136064 spdy::SpdySerializedFrame body_authentication(
bncdf80d44fd2016-07-15 20:27:416065 spdy_util_.ConstructSpdyDataFrame(1, true));
Ryan Hamilton0239aac2018-05-19 00:03:136066 spdy::SpdySerializedFrame resp_data(
tombergan5d22c182017-01-11 02:05:356067 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
Ryan Hamilton0239aac2018-05-19 00:03:136068 spdy::SpdySerializedFrame body_data(
6069 spdy_util_.ConstructSpdyDataFrame(3, true));
tombergan5d22c182017-01-11 02:05:356070
[email protected]018aabc2010-10-29 16:16:596071 MockRead spdy_reads[] = {
bncdf80d44fd2016-07-15 20:27:416072 CreateMockRead(resp_authentication, 1),
bnceb9aa7112017-01-05 01:03:466073 CreateMockRead(body_authentication, 2, SYNCHRONOUS),
bncdf80d44fd2016-07-15 20:27:416074 CreateMockRead(resp_data, 4),
6075 CreateMockRead(body_data, 5),
rch08e3aa3e2015-05-16 14:27:526076 MockRead(ASYNC, 0, 6),
[email protected]018aabc2010-10-29 16:16:596077 };
6078
Ryan Sleevib8d7ea02018-05-07 20:01:016079 SequencedSocketData data(spdy_reads, spdy_writes);
Bence Békydb3cf652017-10-10 15:22:106080 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]018aabc2010-10-29 16:16:596081
6082 helper.RunPreTestSetup();
[email protected]dd54bd82012-07-19 23:44:576083 helper.AddData(&data);
bnc4d782f492016-08-18 13:50:006084 helper.StartDefaultTest();
6085 EXPECT_THAT(helper.output().rv, IsError(ERR_IO_PENDING));
6086
6087 helper.WaitForCallbackToComplete();
6088 EXPECT_THAT(helper.output().rv, IsOk());
[email protected]018aabc2010-10-29 16:16:596089
6090 // Make sure the response has an auth challenge.
bnc4d782f492016-08-18 13:50:006091 HttpNetworkTransaction* trans = helper.trans();
[email protected]018aabc2010-10-29 16:16:596092 const HttpResponseInfo* const response_start = trans->GetResponseInfo();
wezca1070932016-05-26 20:30:526093 ASSERT_TRUE(response_start);
6094 ASSERT_TRUE(response_start->headers);
[email protected]018aabc2010-10-29 16:16:596095 EXPECT_EQ(401, response_start->headers->response_code());
6096 EXPECT_TRUE(response_start->was_fetched_via_spdy);
Emily Starkf2c9bbd2019-04-09 17:08:586097 const base::Optional<AuthChallengeInfo>& auth_challenge =
6098 response_start->auth_challenge;
wezca1070932016-05-26 20:30:526099 ASSERT_TRUE(auth_challenge);
[email protected]79cb5c12011-09-12 13:12:046100 EXPECT_FALSE(auth_challenge->is_proxy);
aberentbba302d2015-12-03 10:20:196101 EXPECT_EQ(kBasicAuthScheme, auth_challenge->scheme);
[email protected]79cb5c12011-09-12 13:12:046102 EXPECT_EQ("MyRealm", auth_challenge->realm);
[email protected]018aabc2010-10-29 16:16:596103
6104 // Restart with a username/password.
[email protected]ad65a3e2013-12-25 18:18:016105 AuthCredentials credentials(base::ASCIIToUTF16("foo"),
6106 base::ASCIIToUTF16("bar"));
[email protected]49639fa2011-12-20 23:22:416107 TestCompletionCallback callback_restart;
6108 const int rv_restart = trans->RestartWithAuth(
6109 credentials, callback_restart.callback());
robpercival214763f2016-07-01 23:27:016110 EXPECT_THAT(rv_restart, IsError(ERR_IO_PENDING));
[email protected]018aabc2010-10-29 16:16:596111 const int rv_restart_complete = callback_restart.WaitForResult();
robpercival214763f2016-07-01 23:27:016112 EXPECT_THAT(rv_restart_complete, IsOk());
[email protected]018aabc2010-10-29 16:16:596113 // TODO(cbentzel): This is actually the same response object as before, but
6114 // data has changed.
6115 const HttpResponseInfo* const response_restart = trans->GetResponseInfo();
wezca1070932016-05-26 20:30:526116 ASSERT_TRUE(response_restart);
6117 ASSERT_TRUE(response_restart->headers);
[email protected]018aabc2010-10-29 16:16:596118 EXPECT_EQ(200, response_restart->headers->response_code());
Emily Starkf2c9bbd2019-04-09 17:08:586119 EXPECT_FALSE(response_restart->auth_challenge);
[email protected]018aabc2010-10-29 16:16:596120}
6121
Bence Békye7023f82018-05-14 01:53:036122struct PushHeaderTestParams {
Bence Béky49db0e22018-05-11 00:54:056123 std::vector<std::pair<base::StringPiece, base::StringPiece>>
6124 extra_request_headers;
6125 std::vector<std::pair<base::StringPiece, base::StringPiece>>
6126 extra_pushed_request_headers;
6127 std::vector<std::pair<base::StringPiece, base::StringPiece>>
6128 extra_pushed_response_headers;
6129 base::StringPiece pushed_status_code;
6130 bool push_accepted;
Bence Békyeacd48f2018-05-14 11:34:336131 SpdyPushedStreamFate expected_fate;
Bence Békye7023f82018-05-14 01:53:036132} push_header_test_cases[] = {
Bence Béky49db0e22018-05-11 00:54:056133 // Base case: no extra headers.
Bence Békyeacd48f2018-05-14 11:34:336134 {{}, {}, {}, "200", true, SpdyPushedStreamFate::kAcceptedNoVary},
Bence Béky49db0e22018-05-11 00:54:056135 // Cookie headers match.
6136 {{{"cookie", "value=foo"}},
6137 {{"cookie", "value=foo"}},
6138 {{"vary", "Cookie"}},
6139 "200",
Bence Békyeacd48f2018-05-14 11:34:336140 true,
6141 SpdyPushedStreamFate::kAcceptedMatchingVary},
Bence Béky49db0e22018-05-11 00:54:056142 // Cookie headers mismatch.
6143 {{{"cookie", "value=foo"}},
6144 {{"cookie", "value=bar"}},
6145 {{"vary", "Cookie"}},
6146 "200",
Bence Békyeacd48f2018-05-14 11:34:336147 false,
6148 SpdyPushedStreamFate::kVaryMismatch},
Bence Béky49db0e22018-05-11 00:54:056149 // Partial Content response, no Range headers.
Bence Békyeacd48f2018-05-14 11:34:336150 {{}, {}, {}, "206", false, SpdyPushedStreamFate::kClientRequestNotRange},
Bence Béky49db0e22018-05-11 00:54:056151 // Partial Content response, no Range headers in pushed request.
Bence Békyeacd48f2018-05-14 11:34:336152 {{{"range", "0-42"}},
6153 {},
6154 {},
6155 "206",
6156 false,
6157 SpdyPushedStreamFate::kPushedRequestNotRange},
Bence Béky49db0e22018-05-11 00:54:056158 // Partial Content response, no Range headers in client request.
Bence Békyeacd48f2018-05-14 11:34:336159 {{},
6160 {{"range", "0-42"}},
6161 {},
6162 "206",
6163 false,
6164 SpdyPushedStreamFate::kClientRequestNotRange},
Bence Béky49db0e22018-05-11 00:54:056165 // Partial Content response, mismatching Range headers.
Bence Békyeacd48f2018-05-14 11:34:336166 {{{"range", "0-42"}},
6167 {{"range", "10-42"}},
6168 {},
6169 "206",
6170 false,
6171 SpdyPushedStreamFate::kRangeMismatch},
Bence Béky49db0e22018-05-11 00:54:056172 // Partial Content response, matching Range headers.
Bence Békyeacd48f2018-05-14 11:34:336173 {{{"range", "0-42"}},
6174 {{"range", "0-42"}},
6175 {},
6176 "206",
6177 true,
6178 SpdyPushedStreamFate::kAcceptedNoVary},
6179};
[email protected]d08358502010-12-03 22:04:036180
Bence Békye7023f82018-05-14 01:53:036181class SpdyNetworkTransactionPushHeaderTest
Bence Béky49db0e22018-05-11 00:54:056182 : public SpdyNetworkTransactionTest,
Bence Békye7023f82018-05-14 01:53:036183 public ::testing::WithParamInterface<PushHeaderTestParams> {
Bence Béky49db0e22018-05-11 00:54:056184 protected:
6185 void RunTest(bool pushed_response_headers_received_before_request) {
Bence Békyeacd48f2018-05-14 11:34:336186 base::HistogramTester histogram_tester;
6187
Bence Békyc4caf072018-04-20 22:27:306188 int seq = 0;
6189 std::vector<MockWrite> writes;
6190 std::vector<MockRead> reads;
bnc38dcd392016-02-09 23:19:496191
Ryan Hamilton0239aac2018-05-19 00:03:136192 spdy::SpdySerializedFrame req1(
Bence Béky49db0e22018-05-11 00:54:056193 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
Bence Békyc4caf072018-04-20 22:27:306194 writes.push_back(CreateMockWrite(req1, seq++));
[email protected]513963e2013-06-15 01:53:046195
Ryan Hamilton0239aac2018-05-19 00:03:136196 spdy::SpdyHeaderBlock pushed_request_headers;
6197 pushed_request_headers[spdy::kHttp2MethodHeader] = "GET";
Bence Béky49db0e22018-05-11 00:54:056198 for (const auto& header : GetParam().extra_pushed_request_headers) {
Bence Békyc4caf072018-04-20 22:27:306199 pushed_request_headers.insert(header);
6200 }
Bence Béky49db0e22018-05-11 00:54:056201 spdy_util_.AddUrlToHeaderBlock(kPushedUrl, &pushed_request_headers);
Ryan Hamilton0239aac2018-05-19 00:03:136202 spdy::SpdySerializedFrame pushed_request(
6203 spdy_util_.ConstructSpdyPushPromise(1, 2,
6204 std::move(pushed_request_headers)));
Bence Békyc4caf072018-04-20 22:27:306205 reads.push_back(CreateMockRead(pushed_request, seq++));
[email protected]d08358502010-12-03 22:04:036206
Ryan Hamilton0239aac2018-05-19 00:03:136207 spdy::SpdySerializedFrame priority(
Bence Béky49db0e22018-05-11 00:54:056208 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true));
Bence Békyc4caf072018-04-20 22:27:306209 writes.push_back(CreateMockWrite(priority, seq++));
bnc38dcd392016-02-09 23:19:496210
Bence Béky49db0e22018-05-11 00:54:056211 reads.push_back(MockRead(ASYNC, ERR_IO_PENDING, seq++));
6212
Ryan Hamilton0239aac2018-05-19 00:03:136213 spdy::SpdyHeaderBlock pushed_response_headers;
6214 pushed_response_headers[spdy::kHttp2StatusHeader] =
6215 GetParam().pushed_status_code;
Bence Béky49db0e22018-05-11 00:54:056216 for (const auto& header : GetParam().extra_pushed_response_headers) {
Bence Békyc4caf072018-04-20 22:27:306217 pushed_response_headers.insert(header);
6218 }
Ryan Hamilton0239aac2018-05-19 00:03:136219 spdy::SpdySerializedFrame pushed_response(
Bence Béky49db0e22018-05-11 00:54:056220 spdy_util_.ConstructSpdyReply(2, std::move(pushed_response_headers)));
Bence Békyc4caf072018-04-20 22:27:306221 reads.push_back(CreateMockRead(pushed_response, seq++));
bnc38dcd392016-02-09 23:19:496222
Ryan Hamilton0239aac2018-05-19 00:03:136223 spdy::SpdySerializedFrame resp1(
6224 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
Bence Békyc4caf072018-04-20 22:27:306225 reads.push_back(CreateMockRead(resp1, seq++));
[email protected]d08358502010-12-03 22:04:036226
Ryan Hamilton0239aac2018-05-19 00:03:136227 spdy::SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true));
Bence Békyc4caf072018-04-20 22:27:306228 reads.push_back(CreateMockRead(body1, seq++));
Bence Béky49db0e22018-05-11 00:54:056229 spdy_util_.UpdateWithStreamDestruction(1);
[email protected]d08358502010-12-03 22:04:036230
Ryan Hamilton0239aac2018-05-19 00:03:136231 spdy::SpdySerializedFrame pushed_body(
Bence Béky49db0e22018-05-11 00:54:056232 spdy_util_.ConstructSpdyDataFrame(2, "This is pushed.", true));
Bence Békyc4caf072018-04-20 22:27:306233 reads.push_back(CreateMockRead(pushed_body, seq++));
[email protected]d08358502010-12-03 22:04:036234
Bence Békyc4caf072018-04-20 22:27:306235 // If push is not accepted, a new request is sent on the wire.
Ryan Hamilton0239aac2018-05-19 00:03:136236 spdy::SpdySerializedFrame rst;
6237 spdy::SpdySerializedFrame req2;
6238 spdy::SpdySerializedFrame resp2;
6239 spdy::SpdySerializedFrame body2;
Bence Béky49db0e22018-05-11 00:54:056240 if (!GetParam().push_accepted) {
Ryan Hamilton0239aac2018-05-19 00:03:136241 rst = spdy_util_.ConstructSpdyRstStream(2, spdy::ERROR_CODE_CANCEL);
Bence Béky49db0e22018-05-11 00:54:056242 writes.push_back(CreateMockWrite(rst, seq++));
6243
Ryan Hamilton0239aac2018-05-19 00:03:136244 spdy::SpdyHeaderBlock request_headers2(
Bence Béky49db0e22018-05-11 00:54:056245 spdy_util_.ConstructGetHeaderBlock(kPushedUrl));
6246 for (const auto& header : GetParam().extra_request_headers) {
Bence Békyc4caf072018-04-20 22:27:306247 request_headers2.insert(header);
6248 }
Bence Béky49db0e22018-05-11 00:54:056249 req2 = spdy_util_.ConstructSpdyHeaders(3, std::move(request_headers2),
6250 LOWEST, true);
Bence Békyc4caf072018-04-20 22:27:306251 writes.push_back(CreateMockWrite(req2, seq++));
[email protected]d08358502010-12-03 22:04:036252
Bence Béky49db0e22018-05-11 00:54:056253 resp2 = spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3);
Bence Békyc4caf072018-04-20 22:27:306254 reads.push_back(CreateMockRead(resp2, seq++));
Bence Béky04268b022018-04-19 01:17:416255
Bence Béky49db0e22018-05-11 00:54:056256 body2 = spdy_util_.ConstructSpdyDataFrame(3, "This is not pushed.", true);
Bence Békyc4caf072018-04-20 22:27:306257 reads.push_back(CreateMockRead(body2, seq++));
6258 }
Bence Béky04268b022018-04-19 01:17:416259
Bence Békyc4caf072018-04-20 22:27:306260 reads.push_back(MockRead(ASYNC, ERR_IO_PENDING, seq++));
Bence Béky04268b022018-04-19 01:17:416261
Bence Békyc4caf072018-04-20 22:27:306262 reads.push_back(MockRead(ASYNC, 0, seq++));
Bence Béky04268b022018-04-19 01:17:416263
Ryan Sleevib8d7ea02018-05-07 20:01:016264 SequencedSocketData data(reads, writes);
Bence Béky04268b022018-04-19 01:17:416265
Bence Békyc4caf072018-04-20 22:27:306266 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
6267 nullptr);
6268 helper.RunPreTestSetup();
6269 helper.AddData(&data);
Bence Béky04268b022018-04-19 01:17:416270
Bence Békyc4caf072018-04-20 22:27:306271 HttpNetworkTransaction* trans = helper.trans();
6272 TestCompletionCallback callback1;
6273 int rv = trans->Start(&request_, callback1.callback(), log_);
6274 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
Bence Béky49db0e22018-05-11 00:54:056275
6276 // Open connection.
6277 base::RunLoop().RunUntilIdle();
6278
6279 if (pushed_response_headers_received_before_request) {
6280 // Read pushed response headers.
6281 data.Resume();
6282 base::RunLoop().RunUntilIdle();
6283 }
6284
6285 HttpRequestInfo request2 = CreateGetPushRequest();
6286 for (const auto& header : GetParam().extra_request_headers) {
6287 request2.extra_headers.SetHeader(header.first, header.second);
6288 }
6289 HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session());
6290 TestCompletionCallback callback2;
6291 rv = trans2.Start(&request2, callback2.callback(), log_);
6292 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
6293 base::RunLoop().RunUntilIdle();
6294
6295 if (!pushed_response_headers_received_before_request) {
6296 // Read pushed response headers.
6297 data.Resume();
6298 base::RunLoop().RunUntilIdle();
6299 }
6300
Bence Békyc4caf072018-04-20 22:27:306301 rv = callback1.WaitForResult();
6302 EXPECT_THAT(rv, IsOk());
Bence Béky04268b022018-04-19 01:17:416303
Bence Békyc4caf072018-04-20 22:27:306304 const HttpResponseInfo* const response1 = trans->GetResponseInfo();
6305 EXPECT_TRUE(response1->headers);
6306 EXPECT_EQ("HTTP/1.1 200", response1->headers->GetStatusLine());
Bence Béky04268b022018-04-19 01:17:416307
Bence Béky4e83f492018-05-13 23:14:256308 std::string result1;
Bence Békyc4caf072018-04-20 22:27:306309 ReadResult(trans, &result1);
6310 EXPECT_EQ(result1, "hello!");
Bence Béky04268b022018-04-19 01:17:416311
Bence Békyc4caf072018-04-20 22:27:306312 rv = callback2.WaitForResult();
6313 EXPECT_THAT(rv, IsOk());
Bence Béky04268b022018-04-19 01:17:416314
Bence Béky4e83f492018-05-13 23:14:256315 std::string result2;
Bence Békyc4caf072018-04-20 22:27:306316 ReadResult(&trans2, &result2);
Bence Béky49db0e22018-05-11 00:54:056317 EXPECT_EQ(result2, GetParam().push_accepted ? "This is pushed."
6318 : "This is not pushed.");
Bence Béky04268b022018-04-19 01:17:416319
Bence Békyc4caf072018-04-20 22:27:306320 data.Resume();
6321 base::RunLoop().RunUntilIdle();
6322 helper.VerifyDataConsumed();
Bence Békyeacd48f2018-05-14 11:34:336323
6324 histogram_tester.ExpectBucketCount(
6325 "Net.SpdyPushedStreamFate", static_cast<int>(GetParam().expected_fate),
6326 1);
6327 histogram_tester.ExpectTotalCount("Net.SpdyPushedStreamFate", 1);
Bence Békyc4caf072018-04-20 22:27:306328 }
Bence Béky49db0e22018-05-11 00:54:056329};
6330
Ilia Samsonov958c9fef2019-11-20 21:37:316331INSTANTIATE_TEST_SUITE_P(All,
Victor Costan2309ea02019-02-13 21:35:476332 SpdyNetworkTransactionPushHeaderTest,
6333 ::testing::ValuesIn(push_header_test_cases));
Bence Béky49db0e22018-05-11 00:54:056334
Bence Békye7023f82018-05-14 01:53:036335TEST_P(SpdyNetworkTransactionPushHeaderTest,
Bence Béky49db0e22018-05-11 00:54:056336 PushedResponseHeadersReceivedBeforeRequest) {
6337 RunTest(/* pushed_response_headers_received_before_request = */ true);
Bence Béky04268b022018-04-19 01:17:416338}
6339
Bence Békye7023f82018-05-14 01:53:036340TEST_P(SpdyNetworkTransactionPushHeaderTest,
Bence Béky49db0e22018-05-11 00:54:056341 PushedResponseHeadersReceivedAfterRequest) {
6342 RunTest(/* pushed_response_headers_received_before_request = */ false);
[email protected]d08358502010-12-03 22:04:036343}
6344
bnc42331402016-07-25 13:36:156345TEST_F(SpdyNetworkTransactionTest, ResponseHeadersTwice) {
Ryan Hamilton0239aac2018-05-19 00:03:136346 spdy::SpdySerializedFrame req(
6347 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
6348 spdy::SpdySerializedFrame rst(
6349 spdy_util_.ConstructSpdyRstStream(1, spdy::ERROR_CODE_PROTOCOL_ERROR));
[email protected]b771bb72013-06-24 09:55:416350 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:416351 CreateMockWrite(req, 0), CreateMockWrite(rst, 4),
[email protected]745aa9c2014-06-27 02:21:296352 };
[email protected]d08358502010-12-03 22:04:036353
Ryan Hamilton0239aac2018-05-19 00:03:136354 spdy::SpdySerializedFrame stream1_reply(
tombergan5d22c182017-01-11 02:05:356355 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
[email protected]513963e2013-06-15 01:53:046356
Ryan Hamilton0239aac2018-05-19 00:03:136357 spdy::SpdyHeaderBlock late_headers;
bnc38dcd392016-02-09 23:19:496358 late_headers["hello"] = "bye";
Ryan Hamilton0239aac2018-05-19 00:03:136359 spdy::SpdySerializedFrame stream1_headers(
6360 spdy_util_.ConstructSpdyResponseHeaders(1, std::move(late_headers),
6361 false));
6362 spdy::SpdySerializedFrame stream1_body(
6363 spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]d08358502010-12-03 22:04:036364 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:416365 CreateMockRead(stream1_reply, 1), CreateMockRead(stream1_headers, 2),
6366 CreateMockRead(stream1_body, 3), MockRead(ASYNC, 0, 5) // EOF
[email protected]d08358502010-12-03 22:04:036367 };
6368
Ryan Sleevib8d7ea02018-05-07 20:01:016369 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:106370 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]dd54bd82012-07-19 23:44:576371 helper.RunToCompletion(&data);
[email protected]d08358502010-12-03 22:04:036372 TransactionHelperResult out = helper.output();
Bence Békyd0d69502019-06-25 19:47:186373 EXPECT_THAT(out.rv, IsError(ERR_HTTP2_PROTOCOL_ERROR));
[email protected]d08358502010-12-03 22:04:036374}
6375
xunjieli294da722015-08-11 19:15:026376// Tests that receiving HEADERS, DATA, HEADERS, and DATA in that sequence will
Bence Békyd0d69502019-06-25 19:47:186377// trigger a ERR_HTTP2_PROTOCOL_ERROR because trailing HEADERS must not be
xunjieli294da722015-08-11 19:15:026378// followed by any DATA frames.
bncd16676a2016-07-20 16:23:016379TEST_F(SpdyNetworkTransactionTest, SyncReplyDataAfterTrailers) {
Ryan Hamilton0239aac2018-05-19 00:03:136380 spdy::SpdySerializedFrame req(
6381 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
6382 spdy::SpdySerializedFrame rst(
6383 spdy_util_.ConstructSpdyRstStream(1, spdy::ERROR_CODE_PROTOCOL_ERROR));
[email protected]b771bb72013-06-24 09:55:416384 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:416385 CreateMockWrite(req, 0), CreateMockWrite(rst, 5),
[email protected]b771bb72013-06-24 09:55:416386 };
[email protected]d08358502010-12-03 22:04:036387
Ryan Hamilton0239aac2018-05-19 00:03:136388 spdy::SpdySerializedFrame stream1_reply(
tombergan5d22c182017-01-11 02:05:356389 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
Ryan Hamilton0239aac2018-05-19 00:03:136390 spdy::SpdySerializedFrame stream1_body(
6391 spdy_util_.ConstructSpdyDataFrame(1, false));
bnc38dcd392016-02-09 23:19:496392
Ryan Hamilton0239aac2018-05-19 00:03:136393 spdy::SpdyHeaderBlock late_headers;
bnc38dcd392016-02-09 23:19:496394 late_headers["hello"] = "bye";
Ryan Hamilton0239aac2018-05-19 00:03:136395 spdy::SpdySerializedFrame stream1_headers(
6396 spdy_util_.ConstructSpdyResponseHeaders(1, std::move(late_headers),
6397 false));
6398 spdy::SpdySerializedFrame stream1_body2(
6399 spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]d08358502010-12-03 22:04:036400 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:416401 CreateMockRead(stream1_reply, 1), CreateMockRead(stream1_body, 2),
6402 CreateMockRead(stream1_headers, 3), CreateMockRead(stream1_body2, 4),
rch08e3aa3e2015-05-16 14:27:526403 MockRead(ASYNC, 0, 6) // EOF
[email protected]d08358502010-12-03 22:04:036404 };
6405
Ryan Sleevib8d7ea02018-05-07 20:01:016406 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:106407 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]dd54bd82012-07-19 23:44:576408 helper.RunToCompletion(&data);
[email protected]d08358502010-12-03 22:04:036409 TransactionHelperResult out = helper.output();
Bence Békyd0d69502019-06-25 19:47:186410 EXPECT_THAT(out.rv, IsError(ERR_HTTP2_PROTOCOL_ERROR));
[email protected]d08358502010-12-03 22:04:036411}
6412
Bence Békye7023f82018-05-14 01:53:036413struct PushUrlTestParams {
6414 const char* url_to_fetch;
6415 const char* url_to_push;
Bence Békyb2f76672018-06-11 21:10:136416 bool client_cert_sent;
Bence Békyeacd48f2018-05-14 11:34:336417 SpdyPushedStreamFate expected_fate;
Bence Békye7023f82018-05-14 01:53:036418} push_url_test_cases[] = {
6419 // http scheme cannot be pushed (except by trusted proxy).
Bence Békyb2f76672018-06-11 21:10:136420 {"https://www.example.org/foo.html", "http://www.example.org/foo.js", false,
Bence Békyeacd48f2018-05-14 11:34:336421 SpdyPushedStreamFate::kNonHttpsPushedScheme},
Bence Békye7023f82018-05-14 01:53:036422 // ftp scheme cannot be pushed.
Bence Békyb2f76672018-06-11 21:10:136423 {"https://www.example.org/foo.html", "ftp://www.example.org/foo.js", false,
Bence Békyeacd48f2018-05-14 11:34:336424 SpdyPushedStreamFate::kInvalidUrl},
Bence Békye7023f82018-05-14 01:53:036425 // Cross subdomain, certificate not valid.
Bence Békyeacd48f2018-05-14 11:34:336426 {"https://www.example.org/foo.html", "https://blat.www.example.org/foo.js",
Bence Békyb2f76672018-06-11 21:10:136427 false, SpdyPushedStreamFate::kCertificateMismatch},
Bence Békye7023f82018-05-14 01:53:036428 // Cross domain, certificate not valid.
Bence Békyb2f76672018-06-11 21:10:136429 {"https://www.example.org/foo.html", "https://www.foo.com/foo.js", false,
6430 SpdyPushedStreamFate::kCertificateMismatch},
6431 // Cross domain, certificate valid, but cross-origin push is rejected on a
6432 // connection with client certificate.
6433 {"https://www.example.org/foo.html", "https://mail.example.org/foo.js",
6434 true, SpdyPushedStreamFate::kCertificateMismatch}};
Bence Békye7023f82018-05-14 01:53:036435
6436class SpdyNetworkTransactionPushUrlTest
6437 : public SpdyNetworkTransactionTest,
6438 public ::testing::WithParamInterface<PushUrlTestParams> {
6439 protected:
[email protected]a7a265ef2010-12-08 18:05:576440 // In this test we want to verify that we can't accidentally push content
6441 // which can't be pushed by this content server.
6442 // This test assumes that:
6443 // - if we're requesting http://www.foo.com/barbaz
6444 // - the browser has made a connection to "www.foo.com".
Bence Békye7023f82018-05-14 01:53:036445 void RunTest() {
Bence Békyeacd48f2018-05-14 11:34:336446 base::HistogramTester histogram_tester;
6447
bncd16676a2016-07-20 16:23:016448 SpdyTestUtil spdy_test_util;
Ryan Hamilton0239aac2018-05-19 00:03:136449 spdy::SpdySerializedFrame stream1_syn(
Bence Békye7023f82018-05-14 01:53:036450 spdy_test_util.ConstructSpdyGet(GetParam().url_to_fetch, 1, LOWEST));
Ryan Hamilton0239aac2018-05-19 00:03:136451 spdy::SpdySerializedFrame stream1_body(
bncdf80d44fd2016-07-15 20:27:416452 spdy_test_util.ConstructSpdyDataFrame(1, true));
Ryan Hamilton0239aac2018-05-19 00:03:136453 spdy::SpdySerializedFrame push_rst(spdy_test_util.ConstructSpdyRstStream(
6454 2, spdy::ERROR_CODE_REFUSED_STREAM));
[email protected]a7a265ef2010-12-08 18:05:576455 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:416456 CreateMockWrite(stream1_syn, 0), CreateMockWrite(push_rst, 3),
[email protected]a7a265ef2010-12-08 18:05:576457 };
6458
Ryan Hamilton0239aac2018-05-19 00:03:136459 spdy::SpdySerializedFrame stream1_reply(
bnc42331402016-07-25 13:36:156460 spdy_test_util.ConstructSpdyGetReply(nullptr, 0, 1));
Ryan Hamilton0239aac2018-05-19 00:03:136461 spdy::SpdySerializedFrame stream2_syn(spdy_test_util.ConstructSpdyPush(
Bence Békye7023f82018-05-14 01:53:036462 nullptr, 0, 2, 1, GetParam().url_to_push));
[email protected]8a0fc822013-06-27 20:52:436463 const char kPushedData[] = "pushed";
Ryan Hamilton0239aac2018-05-19 00:03:136464 spdy::SpdySerializedFrame stream2_body(
Bence Békyd74f4382018-02-20 18:26:196465 spdy_test_util.ConstructSpdyDataFrame(2, kPushedData, true));
Ryan Hamilton0239aac2018-05-19 00:03:136466 spdy::SpdySerializedFrame rst(
6467 spdy_test_util.ConstructSpdyRstStream(2, spdy::ERROR_CODE_CANCEL));
[email protected]a7a265ef2010-12-08 18:05:576468
6469 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:416470 CreateMockRead(stream1_reply, 1),
6471 CreateMockRead(stream2_syn, 2),
6472 CreateMockRead(stream1_body, 4),
6473 CreateMockRead(stream2_body, 5),
rch08e3aa3e2015-05-16 14:27:526474 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 6), // Force a pause
[email protected]a7a265ef2010-12-08 18:05:576475 };
6476
6477 HttpResponseInfo response;
Ryan Sleevib8d7ea02018-05-07 20:01:016478 SequencedSocketData data(reads, writes);
[email protected]a7a265ef2010-12-08 18:05:576479
Bence Békye7023f82018-05-14 01:53:036480 request_.url = GURL(GetParam().url_to_fetch);
[email protected]a7a265ef2010-12-08 18:05:576481
[email protected]7c6f7ba2012-04-03 04:09:296482 // Enable cross-origin push. Since we are not using a proxy, this should
6483 // not actually enable cross-origin SPDY push.
Jeremy Roman0579ed62017-08-29 15:56:196484 auto session_deps = std::make_unique<SpdySessionDependencies>();
6485 auto proxy_delegate = std::make_unique<TestProxyDelegate>();
tbansal28e68f82016-02-04 02:56:156486 proxy_delegate->set_trusted_spdy_proxy(net::ProxyServer::FromURI(
6487 "https://123.45.67.89:443", net::ProxyServer::SCHEME_HTTP));
Eric Roman3d8546a2018-09-10 17:00:526488 session_deps->proxy_resolution_service->SetProxyDelegate(
6489 proxy_delegate.get());
Bence Békydb3cf652017-10-10 15:22:106490 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
Bence Békyd3dde832017-09-19 19:02:316491 std::move(session_deps));
Bence Békydb3cf652017-10-10 15:22:106492
[email protected]61b4efc2012-04-27 18:12:506493 helper.RunPreTestSetup();
Bence Békyb2f76672018-06-11 21:10:136494
6495 auto ssl_provider = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
6496 ssl_provider->ssl_info.client_cert_sent = GetParam().client_cert_sent;
6497 ssl_provider->ssl_info.cert =
6498 ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem");
6499 helper.AddDataWithSSLSocketDataProvider(&data, std::move(ssl_provider));
[email protected]7c6f7ba2012-04-03 04:09:296500
[email protected]a7a265ef2010-12-08 18:05:576501 HttpNetworkTransaction* trans = helper.trans();
6502
6503 // Start the transaction with basic parameters.
[email protected]49639fa2011-12-20 23:22:416504 TestCompletionCallback callback;
[email protected]a7a265ef2010-12-08 18:05:576505
Bence Békydb3cf652017-10-10 15:22:106506 int rv = trans->Start(&request_, callback.callback(), log_);
robpercival214763f2016-07-01 23:27:016507 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]a7a265ef2010-12-08 18:05:576508 rv = callback.WaitForResult();
6509
bnceb9aa7112017-01-05 01:03:466510 // Finish async network reads/writes.
6511 base::RunLoop().RunUntilIdle();
6512
[email protected]a7a265ef2010-12-08 18:05:576513 // Read the response body.
Bence Béky4e83f492018-05-13 23:14:256514 std::string result;
rch0aecfd82015-05-19 17:22:326515 ReadResult(trans, &result);
[email protected]a7a265ef2010-12-08 18:05:576516
6517 // Verify that we consumed all test data.
rch37de576c2015-05-17 20:28:176518 EXPECT_TRUE(data.AllReadDataConsumed());
6519 EXPECT_TRUE(data.AllWriteDataConsumed());
[email protected]a7a265ef2010-12-08 18:05:576520
bnc42331402016-07-25 13:36:156521 // Verify the response headers.
[email protected]a7a265ef2010-12-08 18:05:576522 // Copy the response info, because trans goes away.
6523 response = *trans->GetResponseInfo();
6524
6525 VerifyStreamsClosed(helper);
6526
bnc42331402016-07-25 13:36:156527 // Verify the response headers.
wezca1070932016-05-26 20:30:526528 EXPECT_TRUE(response.headers);
bnc84e7fb52015-12-02 11:50:026529 EXPECT_EQ("HTTP/1.1 200", response.headers->GetStatusLine());
Bence Békyeacd48f2018-05-14 11:34:336530
6531 histogram_tester.ExpectBucketCount(
6532 "Net.SpdyPushedStreamFate", static_cast<int>(GetParam().expected_fate),
6533 1);
6534 histogram_tester.ExpectTotalCount("Net.SpdyPushedStreamFate", 1);
[email protected]a7a265ef2010-12-08 18:05:576535 }
Bence Békye7023f82018-05-14 01:53:036536};
6537
Ilia Samsonov958c9fef2019-11-20 21:37:316538INSTANTIATE_TEST_SUITE_P(All,
Victor Costan2309ea02019-02-13 21:35:476539 SpdyNetworkTransactionPushUrlTest,
6540 ::testing::ValuesIn(push_url_test_cases));
Bence Békye7023f82018-05-14 01:53:036541
6542TEST_P(SpdyNetworkTransactionPushUrlTest, PushUrlTest) {
6543 RunTest();
[email protected]a7a265ef2010-12-08 18:05:576544}
6545
bnc3e79387f2016-03-15 14:49:206546// Verify that push works cross origin as long as the certificate is valid for
6547// the pushed authority.
bncd16676a2016-07-20 16:23:016548TEST_F(SpdyNetworkTransactionTest, ServerPushValidCrossOrigin) {
bnc3e79387f2016-03-15 14:49:206549 // "spdy_pooling.pem" is valid for both www.example.org and mail.example.org.
6550 const char* url_to_fetch = "https://www.example.org";
6551 const char* url_to_push = "https://mail.example.org";
6552
Ryan Hamilton0239aac2018-05-19 00:03:136553 spdy::SpdySerializedFrame headers(
bnc3e79387f2016-03-15 14:49:206554 spdy_util_.ConstructSpdyGet(url_to_fetch, 1, LOWEST));
Ryan Hamilton0239aac2018-05-19 00:03:136555 spdy::SpdySerializedFrame push_priority(
tombergan5d22c182017-01-11 02:05:356556 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true));
bnc3e79387f2016-03-15 14:49:206557 MockWrite writes[] = {
tombergan5d22c182017-01-11 02:05:356558 CreateMockWrite(headers, 0), CreateMockWrite(push_priority, 3),
bnc3e79387f2016-03-15 14:49:206559 };
6560
Ryan Hamilton0239aac2018-05-19 00:03:136561 spdy::SpdySerializedFrame reply(
6562 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
6563 spdy::SpdySerializedFrame push(
bnc3e79387f2016-03-15 14:49:206564 spdy_util_.ConstructSpdyPush(nullptr, 0, 2, 1, url_to_push));
Ryan Hamilton0239aac2018-05-19 00:03:136565 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
bnc3e79387f2016-03-15 14:49:206566 const char kPushedData[] = "pushed";
Ryan Hamilton0239aac2018-05-19 00:03:136567 spdy::SpdySerializedFrame pushed_body(
Bence Békyd74f4382018-02-20 18:26:196568 spdy_util_.ConstructSpdyDataFrame(2, kPushedData, true));
bnc3e79387f2016-03-15 14:49:206569 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:416570 CreateMockRead(reply, 1),
bnceb9aa7112017-01-05 01:03:466571 CreateMockRead(push, 2, SYNCHRONOUS),
tombergan5d22c182017-01-11 02:05:356572 CreateMockRead(body, 4),
6573 CreateMockRead(pushed_body, 5, SYNCHRONOUS),
6574 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 6),
bnc3e79387f2016-03-15 14:49:206575 };
6576
Ryan Sleevib8d7ea02018-05-07 20:01:016577 SequencedSocketData data(reads, writes);
bnc3e79387f2016-03-15 14:49:206578
Bence Békydb3cf652017-10-10 15:22:106579 request_.url = GURL(url_to_fetch);
bnc3e79387f2016-03-15 14:49:206580
Bence Békydb3cf652017-10-10 15:22:106581 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
bnc3e79387f2016-03-15 14:49:206582 helper.RunPreTestSetup();
6583 helper.AddData(&data);
6584
6585 HttpNetworkTransaction* trans0 = helper.trans();
6586 TestCompletionCallback callback0;
Bence Békydb3cf652017-10-10 15:22:106587 int rv = trans0->Start(&request_, callback0.callback(), log_);
bnc3e79387f2016-03-15 14:49:206588 rv = callback0.GetResult(rv);
robpercival214763f2016-07-01 23:27:016589 EXPECT_THAT(rv, IsOk());
bnc3e79387f2016-03-15 14:49:206590
6591 SpdySessionPool* spdy_session_pool = helper.session()->spdy_session_pool();
bncb26024382016-06-29 02:39:456592 SpdySessionKey key(host_port_pair_, ProxyServer::Direct(),
Matt Menke2436b2f2018-12-11 18:07:116593 PRIVACY_MODE_DISABLED,
dalyk51ab46b2019-10-15 15:14:346594 SpdySessionKey::IsProxySession::kFalse, SocketTag(),
6595 NetworkIsolationKey(), false /* disable_secure_dns */);
bnc3e79387f2016-03-15 14:49:206596 base::WeakPtr<SpdySession> spdy_session =
bnc9ead3ae2017-03-16 00:48:156597 spdy_session_pool->FindAvailableSession(
Bence Békyd885b2b2018-02-03 00:58:316598 key, /* enable_ip_based_pooling = */ true,
6599 /* is_websocket = */ false, log_);
bnc3e79387f2016-03-15 14:49:206600
Bence Béky285e7d42017-12-04 20:22:116601 EXPECT_EQ(1u, num_unclaimed_pushed_streams(spdy_session));
Bence Béky3b609012017-12-04 15:19:356602 EXPECT_TRUE(
Bence Béky285e7d42017-12-04 20:22:116603 has_unclaimed_pushed_stream_for_url(spdy_session, GURL(url_to_push)));
bnc3e79387f2016-03-15 14:49:206604
bnc691fda62016-08-12 00:43:166605 HttpNetworkTransaction trans1(DEFAULT_PRIORITY, helper.session());
bnc3e79387f2016-03-15 14:49:206606 HttpRequestInfo push_request;
6607 push_request.method = "GET";
6608 push_request.url = GURL(url_to_push);
Ramin Halavatib5e433e62018-02-07 07:41:106609 push_request.traffic_annotation =
6610 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
bnc3e79387f2016-03-15 14:49:206611 TestCompletionCallback callback1;
Bence Békyd3dde832017-09-19 19:02:316612 rv = trans1.Start(&push_request, callback1.callback(), log_);
bnc3e79387f2016-03-15 14:49:206613 rv = callback1.GetResult(rv);
robpercival214763f2016-07-01 23:27:016614 EXPECT_THAT(rv, IsOk());
bnc3e79387f2016-03-15 14:49:206615
Bence Béky285e7d42017-12-04 20:22:116616 EXPECT_EQ(0u, num_unclaimed_pushed_streams(spdy_session));
bnc3e79387f2016-03-15 14:49:206617
bnc3e79387f2016-03-15 14:49:206618 HttpResponseInfo response = *trans0->GetResponseInfo();
wezca1070932016-05-26 20:30:526619 EXPECT_TRUE(response.headers);
bnc3e79387f2016-03-15 14:49:206620 EXPECT_EQ("HTTP/1.1 200", response.headers->GetStatusLine());
6621
Bence Béky4e83f492018-05-13 23:14:256622 std::string result0;
bnc3e79387f2016-03-15 14:49:206623 ReadResult(trans0, &result0);
6624 EXPECT_EQ("hello!", result0);
6625
bnc691fda62016-08-12 00:43:166626 HttpResponseInfo push_response = *trans1.GetResponseInfo();
wezca1070932016-05-26 20:30:526627 EXPECT_TRUE(push_response.headers);
bnc3e79387f2016-03-15 14:49:206628 EXPECT_EQ("HTTP/1.1 200", push_response.headers->GetStatusLine());
6629
Bence Béky4e83f492018-05-13 23:14:256630 std::string result1;
bnc691fda62016-08-12 00:43:166631 ReadResult(&trans1, &result1);
bnc3e79387f2016-03-15 14:49:206632 EXPECT_EQ(kPushedData, result1);
tombergan5d22c182017-01-11 02:05:356633
6634 base::RunLoop().RunUntilIdle();
6635 helper.VerifyDataConsumed();
6636 VerifyStreamsClosed(helper);
bnc3e79387f2016-03-15 14:49:206637}
6638
Bence Békyb2f76672018-06-11 21:10:136639// Regression test for https://crbug.com/832859: Server push is accepted on a
6640// connection with client certificate, as long as SpdySessionKey matches.
6641TEST_F(SpdyNetworkTransactionTest, ServerPushWithClientCert) {
6642 spdy::SpdySerializedFrame req(
6643 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, DEFAULT_PRIORITY));
6644 spdy::SpdySerializedFrame priority(
6645 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true));
6646 MockWrite writes[] = {CreateMockWrite(req, 0), CreateMockWrite(priority, 3)};
6647
6648 spdy::SpdySerializedFrame resp(
6649 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
6650 spdy::SpdySerializedFrame push(
6651 spdy_util_.ConstructSpdyPush(nullptr, 0, 2, 1, kPushedUrl));
6652 spdy::SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true));
6653 spdy::SpdySerializedFrame body2(
6654 spdy_util_.ConstructSpdyDataFrame(2, "pushed", true));
6655 MockRead reads[] = {CreateMockRead(resp, 1), CreateMockRead(push, 2),
6656 CreateMockRead(body1, 4), CreateMockRead(body2, 5),
6657 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 6)};
6658
6659 SequencedSocketData data(reads, writes);
6660
6661 auto ssl_provider = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
6662 ssl_provider->ssl_info.client_cert_sent = true;
6663 ssl_provider->ssl_info.cert =
6664 ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem");
6665
6666 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
6667 helper.RunPreTestSetup();
6668 helper.AddDataWithSSLSocketDataProvider(&data, std::move(ssl_provider));
6669
6670 EXPECT_TRUE(helper.StartDefaultTest());
6671 helper.FinishDefaultTest();
6672
6673 HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session());
6674 HttpRequestInfo request = CreateGetPushRequest();
6675 TestCompletionCallback callback;
6676 int rv = trans2.Start(&request, callback.callback(), log_);
6677 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
6678
6679 rv = callback.WaitForResult();
6680 EXPECT_THAT(rv, IsOk());
6681
6682 const HttpResponseInfo* const response = trans2.GetResponseInfo();
6683 EXPECT_TRUE(response->headers);
6684 EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
6685
6686 std::string result;
6687 ReadResult(&trans2, &result);
6688 EXPECT_EQ("pushed", result);
6689
6690 EXPECT_TRUE(data.AllReadDataConsumed());
6691 EXPECT_TRUE(data.AllWriteDataConsumed());
6692
6693 VerifyStreamsClosed(helper);
6694}
6695
bnc3e79387f2016-03-15 14:49:206696// Verify that push works cross origin, even if there is already a connection
6697// open to origin of pushed resource.
bncd16676a2016-07-20 16:23:016698TEST_F(SpdyNetworkTransactionTest, ServerPushValidCrossOriginWithOpenSession) {
bnc3e79387f2016-03-15 14:49:206699 const char* url_to_fetch0 = "https://mail.example.org/foo";
6700 const char* url_to_fetch1 = "https://docs.example.org";
6701 const char* url_to_push = "https://mail.example.org/bar";
6702
bncd16676a2016-07-20 16:23:016703 SpdyTestUtil spdy_util_0;
bnc3e79387f2016-03-15 14:49:206704
Ryan Hamilton0239aac2018-05-19 00:03:136705 spdy::SpdySerializedFrame headers0(
bnc3e79387f2016-03-15 14:49:206706 spdy_util_0.ConstructSpdyGet(url_to_fetch0, 1, LOWEST));
6707 MockWrite writes0[] = {
bncdf80d44fd2016-07-15 20:27:416708 CreateMockWrite(headers0, 0),
bnc3e79387f2016-03-15 14:49:206709 };
6710
Ryan Hamilton0239aac2018-05-19 00:03:136711 spdy::SpdySerializedFrame reply0(
6712 spdy_util_0.ConstructSpdyGetReply(nullptr, 0, 1));
bnc3e79387f2016-03-15 14:49:206713 const char kData0[] = "first";
Ryan Hamilton0239aac2018-05-19 00:03:136714 spdy::SpdySerializedFrame body0(
Bence Békyd74f4382018-02-20 18:26:196715 spdy_util_0.ConstructSpdyDataFrame(1, kData0, true));
bncdf80d44fd2016-07-15 20:27:416716 MockRead reads0[] = {CreateMockRead(reply0, 1), CreateMockRead(body0, 2),
6717 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 3)};
bnc3e79387f2016-03-15 14:49:206718
Ryan Sleevib8d7ea02018-05-07 20:01:016719 SequencedSocketData data0(reads0, writes0);
bnc3e79387f2016-03-15 14:49:206720
bncd16676a2016-07-20 16:23:016721 SpdyTestUtil spdy_util_1;
bnc3e79387f2016-03-15 14:49:206722
Ryan Hamilton0239aac2018-05-19 00:03:136723 spdy::SpdySerializedFrame headers1(
bnc3e79387f2016-03-15 14:49:206724 spdy_util_1.ConstructSpdyGet(url_to_fetch1, 1, LOWEST));
Ryan Hamilton0239aac2018-05-19 00:03:136725 spdy::SpdySerializedFrame push_priority(
tombergan5d22c182017-01-11 02:05:356726 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true));
bnc3e79387f2016-03-15 14:49:206727 MockWrite writes1[] = {
bncdf80d44fd2016-07-15 20:27:416728 CreateMockWrite(headers1, 0),
tombergan5d22c182017-01-11 02:05:356729 CreateMockWrite(push_priority, 3, SYNCHRONOUS),
bnc3e79387f2016-03-15 14:49:206730 };
6731
Ryan Hamilton0239aac2018-05-19 00:03:136732 spdy::SpdySerializedFrame reply1(
6733 spdy_util_1.ConstructSpdyGetReply(nullptr, 0, 1));
6734 spdy::SpdySerializedFrame push(
bnc3e79387f2016-03-15 14:49:206735 spdy_util_1.ConstructSpdyPush(nullptr, 0, 2, 1, url_to_push));
6736 const char kData1[] = "second";
Ryan Hamilton0239aac2018-05-19 00:03:136737 spdy::SpdySerializedFrame body1(
Bence Békyd74f4382018-02-20 18:26:196738 spdy_util_1.ConstructSpdyDataFrame(1, kData1, true));
bnc3e79387f2016-03-15 14:49:206739 const char kPushedData[] = "pushed";
Ryan Hamilton0239aac2018-05-19 00:03:136740 spdy::SpdySerializedFrame pushed_body(
Bence Békyd74f4382018-02-20 18:26:196741 spdy_util_1.ConstructSpdyDataFrame(2, kPushedData, true));
bnc3e79387f2016-03-15 14:49:206742
6743 MockRead reads1[] = {
bncdf80d44fd2016-07-15 20:27:416744 CreateMockRead(reply1, 1),
bnceb9aa7112017-01-05 01:03:466745 CreateMockRead(push, 2, SYNCHRONOUS),
tombergan5d22c182017-01-11 02:05:356746 CreateMockRead(body1, 4),
6747 CreateMockRead(pushed_body, 5, SYNCHRONOUS),
6748 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 6),
bnc3e79387f2016-03-15 14:49:206749 };
6750
Ryan Sleevib8d7ea02018-05-07 20:01:016751 SequencedSocketData data1(reads1, writes1);
bnc3e79387f2016-03-15 14:49:206752
6753 // Request |url_to_fetch0| to open connection to mail.example.org.
Bence Békydb3cf652017-10-10 15:22:106754 request_.url = GURL(url_to_fetch0);
bnc3e79387f2016-03-15 14:49:206755
Bence Békydb3cf652017-10-10 15:22:106756 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
bnc3e79387f2016-03-15 14:49:206757 helper.RunPreTestSetup();
6758
6759 // "spdy_pooling.pem" is valid for www.example.org, but not for
6760 // docs.example.org.
Jeremy Roman0579ed62017-08-29 15:56:196761 auto ssl_provider0 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
Ryan Sleevi4f832092017-11-21 23:25:496762 ssl_provider0->ssl_info.cert =
bnc3e79387f2016-03-15 14:49:206763 ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem");
Ryan Sleevi4f832092017-11-21 23:25:496764 ASSERT_TRUE(ssl_provider0->ssl_info.cert);
bnc3e79387f2016-03-15 14:49:206765 helper.AddDataWithSSLSocketDataProvider(&data0, std::move(ssl_provider0));
6766
6767 // "wildcard.pem" is valid for both www.example.org and docs.example.org.
Jeremy Roman0579ed62017-08-29 15:56:196768 auto ssl_provider1 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
Ryan Sleevi4f832092017-11-21 23:25:496769 ssl_provider1->ssl_info.cert =
bnc3e79387f2016-03-15 14:49:206770 ImportCertFromFile(GetTestCertsDirectory(), "wildcard.pem");
Ryan Sleevi4f832092017-11-21 23:25:496771 ASSERT_TRUE(ssl_provider1->ssl_info.cert);
bnc3e79387f2016-03-15 14:49:206772 helper.AddDataWithSSLSocketDataProvider(&data1, std::move(ssl_provider1));
6773
6774 HttpNetworkTransaction* trans0 = helper.trans();
6775 TestCompletionCallback callback0;
Bence Békydb3cf652017-10-10 15:22:106776 int rv = trans0->Start(&request_, callback0.callback(), log_);
bnc3e79387f2016-03-15 14:49:206777 rv = callback0.GetResult(rv);
robpercival214763f2016-07-01 23:27:016778 EXPECT_THAT(rv, IsOk());
bnc3e79387f2016-03-15 14:49:206779
6780 // Request |url_to_fetch1|, during which docs.example.org pushes
6781 // |url_to_push|, which happens to be for www.example.org, to which there is
6782 // already an open connection.
bnc691fda62016-08-12 00:43:166783 HttpNetworkTransaction trans1(DEFAULT_PRIORITY, helper.session());
bnc3e79387f2016-03-15 14:49:206784 HttpRequestInfo request1;
6785 request1.method = "GET";
6786 request1.url = GURL(url_to_fetch1);
Ramin Halavatib5e433e62018-02-07 07:41:106787 request1.traffic_annotation =
6788 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
bnc3e79387f2016-03-15 14:49:206789 TestCompletionCallback callback1;
Bence Békyd3dde832017-09-19 19:02:316790 rv = trans1.Start(&request1, callback1.callback(), log_);
bnc3e79387f2016-03-15 14:49:206791 rv = callback1.GetResult(rv);
robpercival214763f2016-07-01 23:27:016792 EXPECT_THAT(rv, IsOk());
bnc3e79387f2016-03-15 14:49:206793
6794 SpdySessionPool* spdy_session_pool = helper.session()->spdy_session_pool();
6795 HostPortPair host_port_pair0("mail.example.org", 443);
6796 SpdySessionKey key0(host_port_pair0, ProxyServer::Direct(),
Matt Menke2436b2f2018-12-11 18:07:116797 PRIVACY_MODE_DISABLED,
dalyk51ab46b2019-10-15 15:14:346798 SpdySessionKey::IsProxySession::kFalse, SocketTag(),
6799 NetworkIsolationKey(), false /* disable_secure_dns */);
bnc3e79387f2016-03-15 14:49:206800 base::WeakPtr<SpdySession> spdy_session0 =
bnc9ead3ae2017-03-16 00:48:156801 spdy_session_pool->FindAvailableSession(
Bence Békyd885b2b2018-02-03 00:58:316802 key0, /* enable_ip_based_pooling = */ true,
6803 /* is_websocket = */ false, log_);
bnc3e79387f2016-03-15 14:49:206804
Bence Béky285e7d42017-12-04 20:22:116805 EXPECT_EQ(0u, num_unclaimed_pushed_streams(spdy_session0));
bnc3e79387f2016-03-15 14:49:206806
6807 HostPortPair host_port_pair1("docs.example.org", 443);
6808 SpdySessionKey key1(host_port_pair1, ProxyServer::Direct(),
Matt Menke2436b2f2018-12-11 18:07:116809 PRIVACY_MODE_DISABLED,
dalyk51ab46b2019-10-15 15:14:346810 SpdySessionKey::IsProxySession::kFalse, SocketTag(),
6811 NetworkIsolationKey(), false /* disable_secure_dns */);
bnc3e79387f2016-03-15 14:49:206812 base::WeakPtr<SpdySession> spdy_session1 =
bnc9ead3ae2017-03-16 00:48:156813 spdy_session_pool->FindAvailableSession(
Bence Békyd885b2b2018-02-03 00:58:316814 key1, /* enable_ip_based_pooling = */ true,
6815 /* is_websocket = */ false, log_);
bnc3e79387f2016-03-15 14:49:206816
Bence Béky285e7d42017-12-04 20:22:116817 EXPECT_EQ(1u, num_unclaimed_pushed_streams(spdy_session1));
Bence Béky3b609012017-12-04 15:19:356818 EXPECT_TRUE(
Bence Béky285e7d42017-12-04 20:22:116819 has_unclaimed_pushed_stream_for_url(spdy_session1, GURL(url_to_push)));
bnc3e79387f2016-03-15 14:49:206820
6821 // Request |url_to_push|, which should be served from the pushed resource.
bnc691fda62016-08-12 00:43:166822 HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session());
bnc3e79387f2016-03-15 14:49:206823 HttpRequestInfo push_request;
6824 push_request.method = "GET";
6825 push_request.url = GURL(url_to_push);
Ramin Halavatib5e433e62018-02-07 07:41:106826 push_request.traffic_annotation =
6827 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
bnc3e79387f2016-03-15 14:49:206828 TestCompletionCallback callback2;
Bence Békyd3dde832017-09-19 19:02:316829 rv = trans2.Start(&push_request, callback2.callback(), log_);
bnc3e79387f2016-03-15 14:49:206830 rv = callback2.GetResult(rv);
robpercival214763f2016-07-01 23:27:016831 EXPECT_THAT(rv, IsOk());
bnc3e79387f2016-03-15 14:49:206832
Bence Béky285e7d42017-12-04 20:22:116833 EXPECT_EQ(0u, num_unclaimed_pushed_streams(spdy_session0));
6834 EXPECT_EQ(0u, num_unclaimed_pushed_streams(spdy_session1));
bnc3e79387f2016-03-15 14:49:206835
bnc3e79387f2016-03-15 14:49:206836 HttpResponseInfo response0 = *trans0->GetResponseInfo();
wezca1070932016-05-26 20:30:526837 EXPECT_TRUE(response0.headers);
bnc3e79387f2016-03-15 14:49:206838 EXPECT_EQ("HTTP/1.1 200", response0.headers->GetStatusLine());
6839
Bence Béky4e83f492018-05-13 23:14:256840 std::string result0;
bnc3e79387f2016-03-15 14:49:206841 ReadResult(trans0, &result0);
6842 EXPECT_EQ(kData0, result0);
6843
bnc691fda62016-08-12 00:43:166844 HttpResponseInfo response1 = *trans1.GetResponseInfo();
wezca1070932016-05-26 20:30:526845 EXPECT_TRUE(response1.headers);
bnc3e79387f2016-03-15 14:49:206846 EXPECT_EQ("HTTP/1.1 200", response1.headers->GetStatusLine());
6847
Bence Béky4e83f492018-05-13 23:14:256848 std::string result1;
bnc691fda62016-08-12 00:43:166849 ReadResult(&trans1, &result1);
bnc3e79387f2016-03-15 14:49:206850 EXPECT_EQ(kData1, result1);
6851
bnc691fda62016-08-12 00:43:166852 HttpResponseInfo push_response = *trans2.GetResponseInfo();
wezca1070932016-05-26 20:30:526853 EXPECT_TRUE(push_response.headers);
bnc3e79387f2016-03-15 14:49:206854 EXPECT_EQ("HTTP/1.1 200", push_response.headers->GetStatusLine());
6855
Bence Béky4e83f492018-05-13 23:14:256856 std::string result2;
bnc691fda62016-08-12 00:43:166857 ReadResult(&trans2, &result2);
bnc3e79387f2016-03-15 14:49:206858 EXPECT_EQ(kPushedData, result2);
tombergan5d22c182017-01-11 02:05:356859
6860 base::RunLoop().RunUntilIdle();
6861 helper.VerifyDataConsumed();
6862 VerifyStreamsClosed(helper);
bnc3e79387f2016-03-15 14:49:206863}
6864
bncd16676a2016-07-20 16:23:016865TEST_F(SpdyNetworkTransactionTest, RetryAfterRefused) {
[email protected]721c0ce2011-10-13 02:41:006866 // Construct the request.
Ryan Hamilton0239aac2018-05-19 00:03:136867 spdy::SpdySerializedFrame req(
6868 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
rdsmithebb50aa2015-11-12 03:44:386869 // Will be destroyed by the RST before stream 3 starts.
6870 spdy_util_.UpdateWithStreamDestruction(1);
Ryan Hamilton0239aac2018-05-19 00:03:136871 spdy::SpdySerializedFrame req2(
6872 spdy_util_.ConstructSpdyGet(nullptr, 0, 3, LOWEST));
[email protected]721c0ce2011-10-13 02:41:006873 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:416874 CreateMockWrite(req, 0), CreateMockWrite(req2, 2),
[email protected]721c0ce2011-10-13 02:41:006875 };
6876
Ryan Hamilton0239aac2018-05-19 00:03:136877 spdy::SpdySerializedFrame refused(
6878 spdy_util_.ConstructSpdyRstStream(1, spdy::ERROR_CODE_REFUSED_STREAM));
6879 spdy::SpdySerializedFrame resp(
6880 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
6881 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(3, true));
[email protected]721c0ce2011-10-13 02:41:006882 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:416883 CreateMockRead(refused, 1), CreateMockRead(resp, 3),
6884 CreateMockRead(body, 4), MockRead(ASYNC, 0, 5) // EOF
[email protected]721c0ce2011-10-13 02:41:006885 };
6886
Ryan Sleevib8d7ea02018-05-07 20:01:016887 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:106888 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]721c0ce2011-10-13 02:41:006889
6890 helper.RunPreTestSetup();
[email protected]dd54bd82012-07-19 23:44:576891 helper.AddData(&data);
[email protected]721c0ce2011-10-13 02:41:006892
6893 HttpNetworkTransaction* trans = helper.trans();
6894
6895 // Start the transaction with basic parameters.
[email protected]49639fa2011-12-20 23:22:416896 TestCompletionCallback callback;
Bence Békydb3cf652017-10-10 15:22:106897 int rv = trans->Start(&request_, callback.callback(), log_);
robpercival214763f2016-07-01 23:27:016898 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]721c0ce2011-10-13 02:41:006899 rv = callback.WaitForResult();
robpercival214763f2016-07-01 23:27:016900 EXPECT_THAT(rv, IsOk());
[email protected]721c0ce2011-10-13 02:41:006901
bnceb9aa7112017-01-05 01:03:466902 // Finish async network reads.
6903 base::RunLoop().RunUntilIdle();
6904
[email protected]721c0ce2011-10-13 02:41:006905 // Verify that we consumed all test data.
rch08e3aa3e2015-05-16 14:27:526906 EXPECT_TRUE(data.AllReadDataConsumed());
6907 EXPECT_TRUE(data.AllWriteDataConsumed());
[email protected]721c0ce2011-10-13 02:41:006908
bnc42331402016-07-25 13:36:156909 // Verify the response headers.
[email protected]721c0ce2011-10-13 02:41:006910 HttpResponseInfo response = *trans->GetResponseInfo();
wezca1070932016-05-26 20:30:526911 EXPECT_TRUE(response.headers);
bnc84e7fb52015-12-02 11:50:026912 EXPECT_EQ("HTTP/1.1 200", response.headers->GetStatusLine());
[email protected]721c0ce2011-10-13 02:41:006913}
6914
bnc42331402016-07-25 13:36:156915TEST_F(SpdyNetworkTransactionTest, OutOfOrderHeaders) {
[email protected]e1f58efa2012-05-15 18:23:406916 // This first request will start to establish the SpdySession.
6917 // Then we will start the second (MEDIUM priority) and then third
6918 // (HIGHEST priority) request in such a way that the third will actually
[email protected]c92f4b4542012-07-26 23:53:216919 // start before the second, causing the second to be numbered differently
[email protected]513963e2013-06-15 01:53:046920 // than the order they were created.
rdsmithebb50aa2015-11-12 03:44:386921 //
6922 // Note that the requests and responses created below are expectations
6923 // of what the above will produce on the wire, and hence are in the
6924 // initial->HIGHEST->LOWEST priority.
6925 //
6926 // Frames are created by SpdySession just before the write associated
6927 // with the frame is attempted, so stream dependencies will be based
6928 // on the streams alive at the point of the request write attempt. Thus
6929 // req1 is alive when req2 is attempted (during but not after the
6930 // |data.RunFor(2);| statement below) but not when req3 is attempted.
6931 // The call to spdy_util_.UpdateWithStreamDestruction() reflects this.
Ryan Hamilton0239aac2018-05-19 00:03:136932 spdy::SpdySerializedFrame req1(
6933 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
6934 spdy::SpdySerializedFrame req2(
6935 spdy_util_.ConstructSpdyGet(nullptr, 0, 3, HIGHEST));
rdsmithebb50aa2015-11-12 03:44:386936 spdy_util_.UpdateWithStreamDestruction(1);
Ryan Hamilton0239aac2018-05-19 00:03:136937 spdy::SpdySerializedFrame req3(
6938 spdy_util_.ConstructSpdyGet(nullptr, 0, 5, MEDIUM));
[email protected]e1f58efa2012-05-15 18:23:406939 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:416940 MockWrite(ASYNC, ERR_IO_PENDING, 0), CreateMockWrite(req1, 1),
6941 CreateMockWrite(req2, 5), CreateMockWrite(req3, 6),
[email protected]e1f58efa2012-05-15 18:23:406942 };
6943
Ryan Hamilton0239aac2018-05-19 00:03:136944 spdy::SpdySerializedFrame resp1(
6945 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
6946 spdy::SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true));
6947 spdy::SpdySerializedFrame resp2(
6948 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
6949 spdy::SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(3, true));
6950 spdy::SpdySerializedFrame resp3(
6951 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 5));
6952 spdy::SpdySerializedFrame body3(spdy_util_.ConstructSpdyDataFrame(5, true));
[email protected]e1f58efa2012-05-15 18:23:406953 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:416954 CreateMockRead(resp1, 2), MockRead(ASYNC, ERR_IO_PENDING, 3),
6955 CreateMockRead(body1, 4), CreateMockRead(resp2, 7),
6956 CreateMockRead(body2, 8), CreateMockRead(resp3, 9),
6957 CreateMockRead(body3, 10), MockRead(ASYNC, 0, 11) // EOF
[email protected]e1f58efa2012-05-15 18:23:406958 };
6959
Ryan Sleevib8d7ea02018-05-07 20:01:016960 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:106961 NormalSpdyTransactionHelper helper(request_, LOWEST, log_, nullptr);
[email protected]e1f58efa2012-05-15 18:23:406962 helper.RunPreTestSetup();
mmenke666a6fea2015-12-19 04:16:336963 helper.AddData(&data);
[email protected]e1f58efa2012-05-15 18:23:406964
6965 // Start the first transaction to set up the SpdySession
6966 HttpNetworkTransaction* trans = helper.trans();
6967 TestCompletionCallback callback;
Bence Békydb3cf652017-10-10 15:22:106968 int rv = trans->Start(&request_, callback.callback(), log_);
robpercival214763f2016-07-01 23:27:016969 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]e1f58efa2012-05-15 18:23:406970
6971 // Run the message loop, but do not allow the write to complete.
6972 // This leaves the SpdySession with a write pending, which prevents
6973 // SpdySession from attempting subsequent writes until this write completes.
[email protected]fc9d88472013-08-14 02:31:176974 base::RunLoop().RunUntilIdle();
[email protected]e1f58efa2012-05-15 18:23:406975
6976 // Now, start both new transactions
[email protected]e1f58efa2012-05-15 18:23:406977 TestCompletionCallback callback2;
bnc691fda62016-08-12 00:43:166978 HttpNetworkTransaction trans2(MEDIUM, helper.session());
Bence Békydb3cf652017-10-10 15:22:106979 rv = trans2.Start(&request_, callback2.callback(), log_);
robpercival214763f2016-07-01 23:27:016980 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]fc9d88472013-08-14 02:31:176981 base::RunLoop().RunUntilIdle();
[email protected]e1f58efa2012-05-15 18:23:406982
[email protected]e1f58efa2012-05-15 18:23:406983 TestCompletionCallback callback3;
bnc691fda62016-08-12 00:43:166984 HttpNetworkTransaction trans3(HIGHEST, helper.session());
Bence Békydb3cf652017-10-10 15:22:106985 rv = trans3.Start(&request_, callback3.callback(), log_);
robpercival214763f2016-07-01 23:27:016986 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]fc9d88472013-08-14 02:31:176987 base::RunLoop().RunUntilIdle();
[email protected]e1f58efa2012-05-15 18:23:406988
bnc42331402016-07-25 13:36:156989 // We now have two HEADERS frames queued up which will be
[email protected]e1f58efa2012-05-15 18:23:406990 // dequeued only once the first write completes, which we
6991 // now allow to happen.
mmenke666a6fea2015-12-19 04:16:336992 ASSERT_TRUE(data.IsPaused());
6993 data.Resume();
robpercival214763f2016-07-01 23:27:016994 EXPECT_THAT(callback.WaitForResult(), IsOk());
[email protected]e1f58efa2012-05-15 18:23:406995
6996 // And now we can allow everything else to run to completion.
mmenke666a6fea2015-12-19 04:16:336997 data.Resume();
6998 base::RunLoop().RunUntilIdle();
robpercival214763f2016-07-01 23:27:016999 EXPECT_THAT(callback2.WaitForResult(), IsOk());
7000 EXPECT_THAT(callback3.WaitForResult(), IsOk());
[email protected]e1f58efa2012-05-15 18:23:407001
7002 helper.VerifyDataConsumed();
krasin0bfeb6b2017-01-13 21:48:047003
7004 // At this point the test is completed and we need to safely destroy
7005 // all allocated structures. Helper stores a transaction that has a
7006 // reference to a stack allocated request, which has a short lifetime,
7007 // and is accessed during the transaction destruction. We need to delete
7008 // the transaction while the request is still a valid object.
7009 helper.ResetTrans();
[email protected]e1f58efa2012-05-15 18:23:407010}
7011
[email protected]d11b6912013-06-27 23:07:327012// Test that sent data frames and received WINDOW_UPDATE frames change
7013// the send_window_size_ correctly.
7014
7015// WINDOW_UPDATE is different than most other frames in that it can arrive
7016// while the client is still sending the request body. In order to enforce
7017// this scenario, we feed a couple of dummy frames and give a delay of 0 to
7018// socket data provider, so that initial read that is done as soon as the
7019// stream is created, succeeds and schedules another read. This way reads
7020// and writes are interleaved; after doing a full frame write, SpdyStream
7021// will break out of DoLoop and will read and process a WINDOW_UPDATE.
bnc42331402016-07-25 13:36:157022// Once our WINDOW_UPDATE is read, we cannot send HEADERS right away
[email protected]d11b6912013-06-27 23:07:327023// since request has not been completely written, therefore we feed
7024// enough number of WINDOW_UPDATEs to finish the first read and cause a
7025// write, leading to a complete write of request body; after that we send
7026// a reply with a body, to cause a graceful shutdown.
7027
7028// TODO(agayev): develop a socket data provider where both, reads and
7029// writes are ordered so that writing tests like these are easy and rewrite
7030// all these tests using it. Right now we are working around the
7031// limitations as described above and it's not deterministic, tests may
7032// fail under specific circumstances.
bncd16676a2016-07-20 16:23:017033TEST_F(SpdyNetworkTransactionTest, WindowUpdateReceived) {
[email protected]d11b6912013-06-27 23:07:327034 static int kFrameCount = 2;
Bence Békyd74f4382018-02-20 18:26:197035 std::string content(kMaxSpdyFrameChunkSize, 'a');
Ryan Hamilton0239aac2018-05-19 00:03:137036 spdy::SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
tombergan5d22c182017-01-11 02:05:357037 kDefaultUrl, 1, kMaxSpdyFrameChunkSize * kFrameCount, LOWEST, nullptr,
7038 0));
Ryan Hamilton0239aac2018-05-19 00:03:137039 spdy::SpdySerializedFrame body(
Bence Békyd74f4382018-02-20 18:26:197040 spdy_util_.ConstructSpdyDataFrame(1, content, false));
Ryan Hamilton0239aac2018-05-19 00:03:137041 spdy::SpdySerializedFrame body_end(
Bence Békyd74f4382018-02-20 18:26:197042 spdy_util_.ConstructSpdyDataFrame(1, content, true));
[email protected]d11b6912013-06-27 23:07:327043
7044 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:417045 CreateMockWrite(req, 0), CreateMockWrite(body, 1),
7046 CreateMockWrite(body_end, 2),
[email protected]d11b6912013-06-27 23:07:327047 };
7048
Avi Drissman13fc8932015-12-20 04:40:467049 static const int32_t kDeltaWindowSize = 0xff;
[email protected]d11b6912013-06-27 23:07:327050 static const int kDeltaCount = 4;
Ryan Hamilton0239aac2018-05-19 00:03:137051 spdy::SpdySerializedFrame window_update(
[email protected]d11b6912013-06-27 23:07:327052 spdy_util_.ConstructSpdyWindowUpdate(1, kDeltaWindowSize));
Ryan Hamilton0239aac2018-05-19 00:03:137053 spdy::SpdySerializedFrame window_update_dummy(
[email protected]d11b6912013-06-27 23:07:327054 spdy_util_.ConstructSpdyWindowUpdate(2, kDeltaWindowSize));
Ryan Hamilton0239aac2018-05-19 00:03:137055 spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
[email protected]d11b6912013-06-27 23:07:327056 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:417057 CreateMockRead(window_update_dummy, 3),
7058 CreateMockRead(window_update_dummy, 4),
7059 CreateMockRead(window_update_dummy, 5),
7060 CreateMockRead(window_update, 6), // Four updates, therefore window
7061 CreateMockRead(window_update, 7), // size should increase by
7062 CreateMockRead(window_update, 8), // kDeltaWindowSize * 4
7063 CreateMockRead(window_update, 9),
7064 CreateMockRead(resp, 10),
7065 MockRead(ASYNC, ERR_IO_PENDING, 11),
7066 CreateMockRead(body_end, 12),
mmenke666a6fea2015-12-19 04:16:337067 MockRead(ASYNC, 0, 13) // EOF
[email protected]d11b6912013-06-27 23:07:327068 };
7069
Ryan Sleevib8d7ea02018-05-07 20:01:017070 SequencedSocketData data(reads, writes);
[email protected]d11b6912013-06-27 23:07:327071
danakjaee3e1ec2016-04-16 00:23:187072 std::vector<std::unique_ptr<UploadElementReader>> element_readers;
[email protected]d11b6912013-06-27 23:07:327073 for (int i = 0; i < kFrameCount; ++i) {
Jeremy Roman0579ed62017-08-29 15:56:197074 element_readers.push_back(std::make_unique<UploadBytesElementReader>(
Bence Békyd74f4382018-02-20 18:26:197075 content.data(), content.size()));
[email protected]d11b6912013-06-27 23:07:327076 }
olli.raula6df48b2a2015-11-26 07:40:227077 ElementsUploadDataStream upload_data_stream(std::move(element_readers), 0);
[email protected]d11b6912013-06-27 23:07:327078
Bence Békydb3cf652017-10-10 15:22:107079 // Setup the request.
7080 request_.method = "POST";
7081 request_.upload_data_stream = &upload_data_stream;
[email protected]d11b6912013-06-27 23:07:327082
Bence Békydb3cf652017-10-10 15:22:107083 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
mmenke666a6fea2015-12-19 04:16:337084 helper.AddData(&data);
[email protected]d11b6912013-06-27 23:07:327085 helper.RunPreTestSetup();
7086
7087 HttpNetworkTransaction* trans = helper.trans();
7088
7089 TestCompletionCallback callback;
Bence Békydb3cf652017-10-10 15:22:107090 int rv = trans->Start(&request_, callback.callback(), log_);
[email protected]d11b6912013-06-27 23:07:327091
robpercival214763f2016-07-01 23:27:017092 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]d11b6912013-06-27 23:07:327093
mmenke666a6fea2015-12-19 04:16:337094 data.RunUntilPaused();
7095 base::RunLoop().RunUntilIdle();
[email protected]d11b6912013-06-27 23:07:327096
7097 SpdyHttpStream* stream = static_cast<SpdyHttpStream*>(trans->stream_.get());
wezca1070932016-05-26 20:30:527098 ASSERT_TRUE(stream);
7099 ASSERT_TRUE(stream->stream());
bncbca843ba2016-07-14 13:05:487100 EXPECT_EQ(static_cast<int>(kDefaultInitialWindowSize) +
7101 kDeltaWindowSize * kDeltaCount -
7102 kMaxSpdyFrameChunkSize * kFrameCount,
7103 stream->stream()->send_window_size());
[email protected]d11b6912013-06-27 23:07:327104
mmenke666a6fea2015-12-19 04:16:337105 data.Resume();
7106 base::RunLoop().RunUntilIdle();
[email protected]d11b6912013-06-27 23:07:327107
7108 rv = callback.WaitForResult();
robpercival214763f2016-07-01 23:27:017109 EXPECT_THAT(rv, IsOk());
[email protected]d11b6912013-06-27 23:07:327110
7111 helper.VerifyDataConsumed();
7112}
7113
7114// Test that received data frames and sent WINDOW_UPDATE frames change
7115// the recv_window_size_ correctly.
bncd16676a2016-07-20 16:23:017116TEST_F(SpdyNetworkTransactionTest, WindowUpdateSent) {
bnc8f0f3b62015-04-08 04:37:237117 // Session level maximum window size that is more than twice the default
7118 // initial window size so that an initial window update is sent.
Avi Drissman13fc8932015-12-20 04:40:467119 const int32_t session_max_recv_window_size = 5 * 64 * 1024;
bncbca843ba2016-07-14 13:05:487120 ASSERT_LT(2 * kDefaultInitialWindowSize, session_max_recv_window_size);
bnc8f0f3b62015-04-08 04:37:237121 // Stream level maximum window size that is less than the session level
7122 // maximum window size so that we test for confusion between the two.
Avi Drissman13fc8932015-12-20 04:40:467123 const int32_t stream_max_recv_window_size = 4 * 64 * 1024;
bnc8f0f3b62015-04-08 04:37:237124 ASSERT_GT(session_max_recv_window_size, stream_max_recv_window_size);
7125 // Size of body to be sent. Has to be less than or equal to both window sizes
7126 // so that we do not run out of receiving window. Also has to be greater than
7127 // half of them so that it triggers both a session level and a stream level
7128 // window update frame.
Avi Drissman13fc8932015-12-20 04:40:467129 const int32_t kTargetSize = 3 * 64 * 1024;
bnc8f0f3b62015-04-08 04:37:237130 ASSERT_GE(session_max_recv_window_size, kTargetSize);
7131 ASSERT_GE(stream_max_recv_window_size, kTargetSize);
7132 ASSERT_LT(session_max_recv_window_size / 2, kTargetSize);
7133 ASSERT_LT(stream_max_recv_window_size / 2, kTargetSize);
7134 // Size of each DATA frame.
Avi Drissman13fc8932015-12-20 04:40:467135 const int32_t kChunkSize = 4096;
bnc8f0f3b62015-04-08 04:37:237136 // Size of window updates.
7137 ASSERT_EQ(0, session_max_recv_window_size / 2 % kChunkSize);
Avi Drissman13fc8932015-12-20 04:40:467138 const int32_t session_window_update_delta =
bnc8f0f3b62015-04-08 04:37:237139 session_max_recv_window_size / 2 + kChunkSize;
7140 ASSERT_EQ(0, stream_max_recv_window_size / 2 % kChunkSize);
Avi Drissman13fc8932015-12-20 04:40:467141 const int32_t stream_window_update_delta =
bnc8f0f3b62015-04-08 04:37:237142 stream_max_recv_window_size / 2 + kChunkSize;
[email protected]d11b6912013-06-27 23:07:327143
Ryan Hamilton0239aac2018-05-19 00:03:137144 spdy::SpdySerializedFrame preface(
7145 const_cast<char*>(spdy::kHttp2ConnectionHeaderPrefix),
7146 spdy::kHttp2ConnectionHeaderPrefixSize,
7147 /* owns_buffer = */ false);
bnc8abf64af2017-06-07 20:18:547148
Ryan Hamilton0239aac2018-05-19 00:03:137149 spdy::SettingsMap initial_settings;
7150 initial_settings[spdy::SETTINGS_HEADER_TABLE_SIZE] = kSpdyMaxHeaderTableSize;
7151 initial_settings[spdy::SETTINGS_MAX_CONCURRENT_STREAMS] =
bnc3171a2432016-12-28 18:40:267152 kSpdyMaxConcurrentPushedStreams;
Ryan Hamilton0239aac2018-05-19 00:03:137153 initial_settings[spdy::SETTINGS_INITIAL_WINDOW_SIZE] =
7154 stream_max_recv_window_size;
Bence Béky6cee52f2019-10-24 16:52:337155 initial_settings[spdy::SETTINGS_MAX_HEADER_LIST_SIZE] =
7156 kSpdyMaxHeaderListSize;
Ryan Hamilton0239aac2018-05-19 00:03:137157 spdy::SpdySerializedFrame initial_settings_frame(
bnc8f0f3b62015-04-08 04:37:237158 spdy_util_.ConstructSpdySettings(initial_settings));
bnc8abf64af2017-06-07 20:18:547159
Ryan Hamilton0239aac2018-05-19 00:03:137160 spdy::SpdySerializedFrame initial_window_update(
bnc8f0f3b62015-04-08 04:37:237161 spdy_util_.ConstructSpdyWindowUpdate(
Ryan Hamilton0239aac2018-05-19 00:03:137162 spdy::kSessionFlowControlStreamId,
bncbca843ba2016-07-14 13:05:487163 session_max_recv_window_size - kDefaultInitialWindowSize));
bnc8abf64af2017-06-07 20:18:547164
Ryan Hamilton0239aac2018-05-19 00:03:137165 spdy::SpdySerializedFrame combined_frames = CombineFrames(
bncef26b602017-06-12 22:08:197166 {&preface, &initial_settings_frame, &initial_window_update});
[email protected]d11b6912013-06-27 23:07:327167
7168 std::vector<MockWrite> writes;
bncef26b602017-06-12 22:08:197169 writes.push_back(CreateMockWrite(combined_frames));
bnc8abf64af2017-06-07 20:18:547170
Ryan Hamilton0239aac2018-05-19 00:03:137171 spdy::SpdySerializedFrame req(
7172 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
bncdf80d44fd2016-07-15 20:27:417173 writes.push_back(CreateMockWrite(req, writes.size()));
[email protected]d11b6912013-06-27 23:07:327174
[email protected]251029e2014-03-19 06:04:407175 std::vector<MockRead> reads;
Ryan Hamilton0239aac2018-05-19 00:03:137176 spdy::SpdySerializedFrame resp(
7177 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
bncdf80d44fd2016-07-15 20:27:417178 reads.push_back(CreateMockRead(resp, writes.size() + reads.size()));
[email protected]d11b6912013-06-27 23:07:327179
Ryan Hamilton0239aac2018-05-19 00:03:137180 std::vector<spdy::SpdySerializedFrame> body_frames;
Bence Béky4e83f492018-05-13 23:14:257181 const std::string body_data(kChunkSize, 'x');
[email protected]251029e2014-03-19 06:04:407182 for (size_t remaining = kTargetSize; remaining != 0;) {
7183 size_t frame_size = std::min(remaining, body_data.size());
Bence Békyd74f4382018-02-20 18:26:197184 body_frames.push_back(spdy_util_.ConstructSpdyDataFrame(
7185 1, base::StringPiece(body_data.data(), frame_size), false));
rchacdcbdc2015-05-16 17:16:007186 reads.push_back(
bncdf80d44fd2016-07-15 20:27:417187 CreateMockRead(body_frames.back(), writes.size() + reads.size()));
[email protected]251029e2014-03-19 06:04:407188 remaining -= frame_size;
7189 }
mmenkee24011922015-12-17 22:12:597190 // Yield.
rchacdcbdc2015-05-16 17:16:007191 reads.push_back(
mmenkee24011922015-12-17 22:12:597192 MockRead(SYNCHRONOUS, ERR_IO_PENDING, writes.size() + reads.size()));
[email protected]251029e2014-03-19 06:04:407193
Ryan Hamilton0239aac2018-05-19 00:03:137194 spdy::SpdySerializedFrame session_window_update(
bnc8abf64af2017-06-07 20:18:547195 spdy_util_.ConstructSpdyWindowUpdate(0, session_window_update_delta));
rchacdcbdc2015-05-16 17:16:007196 writes.push_back(
bncdf80d44fd2016-07-15 20:27:417197 CreateMockWrite(session_window_update, writes.size() + reads.size()));
Ryan Hamilton0239aac2018-05-19 00:03:137198 spdy::SpdySerializedFrame stream_window_update(
bnc8abf64af2017-06-07 20:18:547199 spdy_util_.ConstructSpdyWindowUpdate(1, stream_window_update_delta));
rchacdcbdc2015-05-16 17:16:007200 writes.push_back(
bncdf80d44fd2016-07-15 20:27:417201 CreateMockWrite(stream_window_update, writes.size() + reads.size()));
rchacdcbdc2015-05-16 17:16:007202
Ryan Sleevib8d7ea02018-05-07 20:01:017203 SequencedSocketData data(reads, writes);
[email protected]d11b6912013-06-27 23:07:327204
Jeremy Roman0579ed62017-08-29 15:56:197205 auto session_deps = std::make_unique<SpdySessionDependencies>();
bnc903e8c12016-12-09 20:50:057206 session_deps->session_max_recv_window_size = session_max_recv_window_size;
Ryan Hamilton0239aac2018-05-19 00:03:137207 session_deps->http2_settings[spdy::SETTINGS_INITIAL_WINDOW_SIZE] =
bnc3171a2432016-12-28 18:40:267208 stream_max_recv_window_size;
bnc903e8c12016-12-09 20:50:057209
Bence Békydb3cf652017-10-10 15:22:107210 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
bnc903e8c12016-12-09 20:50:057211 std::move(session_deps));
[email protected]d11b6912013-06-27 23:07:327212 helper.AddData(&data);
7213 helper.RunPreTestSetup();
[email protected]d11b6912013-06-27 23:07:327214
bnc8f0f3b62015-04-08 04:37:237215 SpdySessionPool* spdy_session_pool = helper.session()->spdy_session_pool();
7216 SpdySessionPoolPeer pool_peer(spdy_session_pool);
7217 pool_peer.SetEnableSendingInitialData(true);
bnc8f0f3b62015-04-08 04:37:237218
7219 HttpNetworkTransaction* trans = helper.trans();
[email protected]d11b6912013-06-27 23:07:327220 TestCompletionCallback callback;
Bence Békydb3cf652017-10-10 15:22:107221 int rv = trans->Start(&request_, callback.callback(), log_);
[email protected]d11b6912013-06-27 23:07:327222
robpercival214763f2016-07-01 23:27:017223 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]d11b6912013-06-27 23:07:327224 rv = callback.WaitForResult();
robpercival214763f2016-07-01 23:27:017225 EXPECT_THAT(rv, IsOk());
[email protected]d11b6912013-06-27 23:07:327226
bnceb9aa7112017-01-05 01:03:467227 // Finish async network reads.
7228 base::RunLoop().RunUntilIdle();
7229
[email protected]d11b6912013-06-27 23:07:327230 SpdyHttpStream* stream =
7231 static_cast<SpdyHttpStream*>(trans->stream_.get());
wezca1070932016-05-26 20:30:527232 ASSERT_TRUE(stream);
7233 ASSERT_TRUE(stream->stream());
[email protected]d11b6912013-06-27 23:07:327234
[email protected]251029e2014-03-19 06:04:407235 // All data has been read, but not consumed. The window reflects this.
bnc8f0f3b62015-04-08 04:37:237236 EXPECT_EQ(static_cast<int>(stream_max_recv_window_size - kTargetSize),
[email protected]251029e2014-03-19 06:04:407237 stream->stream()->recv_window_size());
[email protected]d11b6912013-06-27 23:07:327238
7239 const HttpResponseInfo* response = trans->GetResponseInfo();
wezca1070932016-05-26 20:30:527240 ASSERT_TRUE(response);
7241 ASSERT_TRUE(response->headers);
bnc84e7fb52015-12-02 11:50:027242 EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
[email protected]d11b6912013-06-27 23:07:327243 EXPECT_TRUE(response->was_fetched_via_spdy);
7244
7245 // Issue a read which will cause a WINDOW_UPDATE to be sent and window
7246 // size increased to default.
Victor Costan9c7302b2018-08-27 16:39:447247 scoped_refptr<IOBuffer> buf = base::MakeRefCounted<IOBuffer>(kTargetSize);
[email protected]251029e2014-03-19 06:04:407248 EXPECT_EQ(static_cast<int>(kTargetSize),
Bence Békybdbb0e72018-08-07 21:42:597249 trans->Read(buf.get(), kTargetSize, CompletionOnceCallback()));
bnc8f0f3b62015-04-08 04:37:237250 EXPECT_EQ(static_cast<int>(stream_max_recv_window_size),
[email protected]251029e2014-03-19 06:04:407251 stream->stream()->recv_window_size());
Bence Béky4e83f492018-05-13 23:14:257252 EXPECT_THAT(base::StringPiece(buf->data(), kTargetSize), Each(Eq('x')));
[email protected]d11b6912013-06-27 23:07:327253
[email protected]251029e2014-03-19 06:04:407254 // Allow scheduled WINDOW_UPDATE frames to write.
[email protected]fc9d88472013-08-14 02:31:177255 base::RunLoop().RunUntilIdle();
[email protected]d11b6912013-06-27 23:07:327256 helper.VerifyDataConsumed();
7257}
7258
7259// Test that WINDOW_UPDATE frame causing overflow is handled correctly.
bncd16676a2016-07-20 16:23:017260TEST_F(SpdyNetworkTransactionTest, WindowUpdateOverflow) {
[email protected]d11b6912013-06-27 23:07:327261 // Number of full frames we hope to write (but will not, used to
7262 // set content-length header correctly)
7263 static int kFrameCount = 3;
7264
Bence Békyd74f4382018-02-20 18:26:197265 std::string content(kMaxSpdyFrameChunkSize, 'a');
Ryan Hamilton0239aac2018-05-19 00:03:137266 spdy::SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
tombergan5d22c182017-01-11 02:05:357267 kDefaultUrl, 1, kMaxSpdyFrameChunkSize * kFrameCount, LOWEST, nullptr,
7268 0));
Ryan Hamilton0239aac2018-05-19 00:03:137269 spdy::SpdySerializedFrame body(
Bence Békyd74f4382018-02-20 18:26:197270 spdy_util_.ConstructSpdyDataFrame(1, content, false));
Ryan Hamilton0239aac2018-05-19 00:03:137271 spdy::SpdySerializedFrame rst(spdy_util_.ConstructSpdyRstStream(
7272 1, spdy::ERROR_CODE_FLOW_CONTROL_ERROR));
[email protected]d11b6912013-06-27 23:07:327273
7274 // We're not going to write a data frame with FIN, we'll receive a bad
7275 // WINDOW_UPDATE while sending a request and will send a RST_STREAM frame.
7276 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:417277 CreateMockWrite(req, 0), CreateMockWrite(body, 2),
7278 CreateMockWrite(rst, 3),
[email protected]d11b6912013-06-27 23:07:327279 };
7280
Avi Drissman13fc8932015-12-20 04:40:467281 static const int32_t kDeltaWindowSize = 0x7fffffff; // cause an overflow
Ryan Hamilton0239aac2018-05-19 00:03:137282 spdy::SpdySerializedFrame window_update(
[email protected]d11b6912013-06-27 23:07:327283 spdy_util_.ConstructSpdyWindowUpdate(1, kDeltaWindowSize));
7284 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:417285 CreateMockRead(window_update, 1), MockRead(ASYNC, 0, 4) // EOF
[email protected]d11b6912013-06-27 23:07:327286 };
7287
Ryan Sleevib8d7ea02018-05-07 20:01:017288 SequencedSocketData data(reads, writes);
[email protected]d11b6912013-06-27 23:07:327289
danakjaee3e1ec2016-04-16 00:23:187290 std::vector<std::unique_ptr<UploadElementReader>> element_readers;
[email protected]d11b6912013-06-27 23:07:327291 for (int i = 0; i < kFrameCount; ++i) {
Jeremy Roman0579ed62017-08-29 15:56:197292 element_readers.push_back(std::make_unique<UploadBytesElementReader>(
Bence Békyd74f4382018-02-20 18:26:197293 content.data(), content.size()));
[email protected]d11b6912013-06-27 23:07:327294 }
olli.raula6df48b2a2015-11-26 07:40:227295 ElementsUploadDataStream upload_data_stream(std::move(element_readers), 0);
[email protected]d11b6912013-06-27 23:07:327296
Bence Békydb3cf652017-10-10 15:22:107297 // Setup the request.
7298 request_.method = "POST";
7299 request_.upload_data_stream = &upload_data_stream;
[email protected]d11b6912013-06-27 23:07:327300
Bence Békydb3cf652017-10-10 15:22:107301 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]d11b6912013-06-27 23:07:327302 helper.RunPreTestSetup();
mmenke666a6fea2015-12-19 04:16:337303 helper.AddData(&data);
[email protected]d11b6912013-06-27 23:07:327304 HttpNetworkTransaction* trans = helper.trans();
7305
7306 TestCompletionCallback callback;
Bence Békydb3cf652017-10-10 15:22:107307 int rv = trans->Start(&request_, callback.callback(), log_);
robpercival214763f2016-07-01 23:27:017308 ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]d11b6912013-06-27 23:07:327309
mmenke666a6fea2015-12-19 04:16:337310 base::RunLoop().RunUntilIdle();
[email protected]d11b6912013-06-27 23:07:327311 ASSERT_TRUE(callback.have_result());
Bence Békyd0d69502019-06-25 19:47:187312 EXPECT_THAT(callback.WaitForResult(), IsError(ERR_HTTP2_FLOW_CONTROL_ERROR));
[email protected]d11b6912013-06-27 23:07:327313 helper.VerifyDataConsumed();
7314}
7315
Bence Béky05dcb0382017-09-15 20:07:587316// Regression test for https://crbug.com/732019.
Ryan Hamilton0239aac2018-05-19 00:03:137317// RFC7540 Section 6.9.2: A spdy::SETTINGS_INITIAL_WINDOW_SIZE change that
7318// causes any stream flow control window to overflow MUST be treated as a
7319// connection error.
Bence Béky05dcb0382017-09-15 20:07:587320TEST_F(SpdyNetworkTransactionTest, InitialWindowSizeOverflow) {
Ryan Hamilton0239aac2018-05-19 00:03:137321 spdy::SpdySerializedFrame window_update(
Bence Béky05dcb0382017-09-15 20:07:587322 spdy_util_.ConstructSpdyWindowUpdate(1, 0x60000000));
Ryan Hamilton0239aac2018-05-19 00:03:137323 spdy::SettingsMap settings;
7324 settings[spdy::SETTINGS_INITIAL_WINDOW_SIZE] = 0x60000000;
7325 spdy::SpdySerializedFrame settings_frame(
Bence Béky05dcb0382017-09-15 20:07:587326 spdy_util_.ConstructSpdySettings(settings));
7327 MockRead reads[] = {CreateMockRead(window_update, 1),
7328 CreateMockRead(settings_frame, 2)};
7329
Ryan Hamilton0239aac2018-05-19 00:03:137330 spdy::SpdySerializedFrame req(
7331 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
7332 spdy::SpdySerializedFrame settings_ack(spdy_util_.ConstructSpdySettingsAck());
7333 spdy::SpdySerializedFrame goaway(
7334 spdy_util_.ConstructSpdyGoAway(0, spdy::ERROR_CODE_FLOW_CONTROL_ERROR,
7335 "New spdy::SETTINGS_INITIAL_WINDOW_SIZE "
7336 "value overflows flow control window of "
7337 "stream 1."));
Bence Béky05dcb0382017-09-15 20:07:587338 MockWrite writes[] = {CreateMockWrite(req, 0),
7339 CreateMockWrite(settings_ack, 3),
7340 CreateMockWrite(goaway, 4)};
7341
Ryan Sleevib8d7ea02018-05-07 20:01:017342 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:107343 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
Bence Béky05dcb0382017-09-15 20:07:587344 helper.RunToCompletion(&data);
7345 TransactionHelperResult out = helper.output();
Bence Békyd0d69502019-06-25 19:47:187346 EXPECT_THAT(out.rv, IsError(ERR_HTTP2_FLOW_CONTROL_ERROR));
Bence Béky05dcb0382017-09-15 20:07:587347}
7348
David Schinazi410676a2019-08-13 22:31:057349// Tests that we close the connection if we try to enqueue more frames than
7350// the cap allows.
7351TEST_F(SpdyNetworkTransactionTest, SessionMaxQueuedCappedFramesExceeded) {
7352 const int kTestSessionMaxQueuedCappedFrames = 5;
7353 const int kTestNumPings = kTestSessionMaxQueuedCappedFrames + 1;
7354 spdy::SettingsMap settings;
7355 settings[spdy::SETTINGS_INITIAL_WINDOW_SIZE] = 0xffff;
7356 spdy::SpdySerializedFrame settings_frame(
7357 spdy_util_.ConstructSpdySettings(settings));
7358 std::vector<spdy::SpdySerializedFrame> ping_frames;
7359
7360 spdy::SpdySerializedFrame req(
7361 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
7362 spdy::SpdySerializedFrame settings_ack(spdy_util_.ConstructSpdySettingsAck());
7363
7364 std::vector<MockWrite> writes;
7365 std::vector<MockRead> reads;
7366 // Send request, receive SETTINGS and send a SETTINGS ACK.
7367 writes.push_back(CreateMockWrite(req, writes.size() + reads.size()));
7368 reads.push_back(CreateMockRead(settings_frame, writes.size() + reads.size()));
7369 writes.push_back(CreateMockWrite(settings_ack, writes.size() + reads.size()));
7370 // Receive more pings than our limit allows.
7371 for (int i = 1; i <= kTestNumPings; ++i) {
7372 ping_frames.push_back(
7373 spdy_util_.ConstructSpdyPing(/*ping_id=*/i, /*is_ack=*/false));
7374 reads.push_back(
7375 CreateMockRead(ping_frames.back(), writes.size() + reads.size()));
7376 }
7377 // Only write PING ACKs after receiving all of them to ensure they are all in
7378 // the write queue.
7379 for (int i = 1; i <= kTestNumPings; ++i) {
7380 ping_frames.push_back(
7381 spdy_util_.ConstructSpdyPing(/*ping_id=*/i, /*is_ack=*/true));
7382 writes.push_back(
7383 CreateMockWrite(ping_frames.back(), writes.size() + reads.size()));
7384 }
7385 // Stop reading.
7386 reads.push_back(MockRead(ASYNC, 0, writes.size() + reads.size()));
7387
7388 SequencedSocketData data(reads, writes);
7389 auto session_deps = std::make_unique<SpdySessionDependencies>();
7390 session_deps->session_max_queued_capped_frames =
7391 kTestSessionMaxQueuedCappedFrames;
7392 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
7393 std::move(session_deps));
7394 helper.RunToCompletion(&data);
7395 TransactionHelperResult out = helper.output();
7396 EXPECT_THAT(out.rv, IsError(ERR_CONNECTION_CLOSED));
7397}
7398
[email protected]d11b6912013-06-27 23:07:327399// Test that after hitting a send window size of 0, the write process
7400// stalls and upon receiving WINDOW_UPDATE frame write resumes.
7401
7402// This test constructs a POST request followed by enough data frames
7403// containing 'a' that would make the window size 0, followed by another
7404// data frame containing default content (which is "hello!") and this frame
rchacdcbdc2015-05-16 17:16:007405// also contains a FIN flag. SequencedSocketData is used to enforce all
7406// writes, save the last, go through before a read could happen. The last frame
7407// ("hello!") is not permitted to go through since by the time its turn
[email protected]d11b6912013-06-27 23:07:327408// arrives, window size is 0. At this point MessageLoop::Run() called via
7409// callback would block. Therefore we call MessageLoop::RunUntilIdle()
7410// which returns after performing all possible writes. We use DCHECKS to
7411// ensure that last data frame is still there and stream has stalled.
7412// After that, next read is artifically enforced, which causes a
7413// WINDOW_UPDATE to be read and I/O process resumes.
bncd16676a2016-07-20 16:23:017414TEST_F(SpdyNetworkTransactionTest, FlowControlStallResume) {
bncbca843ba2016-07-14 13:05:487415 const int32_t initial_window_size = kDefaultInitialWindowSize;
xunjieli179a6e72016-04-26 19:47:457416 // Number of upload data buffers we need to send to zero out the window size
7417 // is the minimal number of upload buffers takes to be bigger than
7418 // |initial_window_size|.
7419 size_t num_upload_buffers =
7420 ceil(static_cast<double>(initial_window_size) / kBufferSize);
7421 // Each upload data buffer consists of |num_frames_in_one_upload_buffer|
7422 // frames, each with |kMaxSpdyFrameChunkSize| bytes except the last frame,
7423 // which has kBufferSize % kMaxSpdyChunkSize bytes.
7424 size_t num_frames_in_one_upload_buffer =
7425 ceil(static_cast<double>(kBufferSize) / kMaxSpdyFrameChunkSize);
[email protected]d11b6912013-06-27 23:07:327426
7427 // Construct content for a data frame of maximum size.
Bence Béky4e83f492018-05-13 23:14:257428 std::string content(kMaxSpdyFrameChunkSize, 'a');
[email protected]d11b6912013-06-27 23:07:327429
Ryan Hamilton0239aac2018-05-19 00:03:137430 spdy::SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
bncb26024382016-06-29 02:39:457431 kDefaultUrl, 1,
xunjieli179a6e72016-04-26 19:47:457432 /*content_length=*/kBufferSize * num_upload_buffers + kUploadDataSize,
tombergan5d22c182017-01-11 02:05:357433 LOWEST, nullptr, 0));
[email protected]d11b6912013-06-27 23:07:327434
7435 // Full frames.
Ryan Hamilton0239aac2018-05-19 00:03:137436 spdy::SpdySerializedFrame body1(
Bence Békyd74f4382018-02-20 18:26:197437 spdy_util_.ConstructSpdyDataFrame(1, content, false));
[email protected]d11b6912013-06-27 23:07:327438
xunjieli179a6e72016-04-26 19:47:457439 // Last frame in each upload data buffer.
Ryan Hamilton0239aac2018-05-19 00:03:137440 spdy::SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(
Bence Békyd74f4382018-02-20 18:26:197441 1,
7442 base::StringPiece(content.data(), kBufferSize % kMaxSpdyFrameChunkSize),
7443 false));
[email protected]d11b6912013-06-27 23:07:327444
xunjieli179a6e72016-04-26 19:47:457445 // The very last frame before the stalled frames.
Ryan Hamilton0239aac2018-05-19 00:03:137446 spdy::SpdySerializedFrame body3(spdy_util_.ConstructSpdyDataFrame(
Bence Békyd74f4382018-02-20 18:26:197447 1,
7448 base::StringPiece(content.data(), initial_window_size % kBufferSize %
7449 kMaxSpdyFrameChunkSize),
7450 false));
xunjieli179a6e72016-04-26 19:47:457451
7452 // Data frames to be sent once WINDOW_UPDATE frame is received.
7453
7454 // If kBufferSize * num_upload_buffers > initial_window_size,
7455 // we need one additional frame to send the rest of 'a'.
Bence Béky4e83f492018-05-13 23:14:257456 std::string last_body(kBufferSize * num_upload_buffers - initial_window_size,
7457 'a');
Ryan Hamilton0239aac2018-05-19 00:03:137458 spdy::SpdySerializedFrame body4(
Bence Békyd74f4382018-02-20 18:26:197459 spdy_util_.ConstructSpdyDataFrame(1, last_body, false));
xunjieli179a6e72016-04-26 19:47:457460
7461 // Also send a "hello!" after WINDOW_UPDATE.
Ryan Hamilton0239aac2018-05-19 00:03:137462 spdy::SpdySerializedFrame body5(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]d11b6912013-06-27 23:07:327463
7464 // Fill in mock writes.
[email protected]d11b6912013-06-27 23:07:327465 size_t i = 0;
xunjieli179a6e72016-04-26 19:47:457466 std::vector<MockWrite> writes;
bncdf80d44fd2016-07-15 20:27:417467 writes.push_back(CreateMockWrite(req, i++));
xunjieli179a6e72016-04-26 19:47:457468 for (size_t j = 0; j < num_upload_buffers; j++) {
7469 for (size_t k = 0; k < num_frames_in_one_upload_buffer; k++) {
7470 if (k == num_frames_in_one_upload_buffer - 1 &&
7471 kBufferSize % kMaxSpdyFrameChunkSize != 0) {
7472 if (j == num_upload_buffers - 1 &&
7473 (initial_window_size % kBufferSize != 0)) {
bncdf80d44fd2016-07-15 20:27:417474 writes.push_back(CreateMockWrite(body3, i++));
xunjieli179a6e72016-04-26 19:47:457475 } else {
bncdf80d44fd2016-07-15 20:27:417476 writes.push_back(CreateMockWrite(body2, i++));
xunjieli179a6e72016-04-26 19:47:457477 }
7478 } else {
bncdf80d44fd2016-07-15 20:27:417479 writes.push_back(CreateMockWrite(body1, i++));
xunjieli179a6e72016-04-26 19:47:457480 }
7481 }
7482 }
[email protected]d11b6912013-06-27 23:07:327483
xunjieli179a6e72016-04-26 19:47:457484 // Fill in mock reads.
7485 std::vector<MockRead> reads;
7486 // Force a pause.
7487 reads.push_back(MockRead(ASYNC, ERR_IO_PENDING, i++));
7488 // Construct read frame for window updates that gives enough space to upload
7489 // the rest of the data.
Ryan Hamilton0239aac2018-05-19 00:03:137490 spdy::SpdySerializedFrame session_window_update(
xunjieli179a6e72016-04-26 19:47:457491 spdy_util_.ConstructSpdyWindowUpdate(0,
7492 kUploadDataSize + last_body.size()));
Ryan Hamilton0239aac2018-05-19 00:03:137493 spdy::SpdySerializedFrame window_update(spdy_util_.ConstructSpdyWindowUpdate(
bncdf80d44fd2016-07-15 20:27:417494 1, kUploadDataSize + last_body.size()));
xunjieli179a6e72016-04-26 19:47:457495
bncdf80d44fd2016-07-15 20:27:417496 reads.push_back(CreateMockRead(session_window_update, i++));
7497 reads.push_back(CreateMockRead(window_update, i++));
xunjieli179a6e72016-04-26 19:47:457498
7499 // Stalled frames which can be sent after receiving window updates.
7500 if (last_body.size() > 0)
bncdf80d44fd2016-07-15 20:27:417501 writes.push_back(CreateMockWrite(body4, i++));
7502 writes.push_back(CreateMockWrite(body5, i++));
xunjieli179a6e72016-04-26 19:47:457503
Ryan Hamilton0239aac2018-05-19 00:03:137504 spdy::SpdySerializedFrame reply(
7505 spdy_util_.ConstructSpdyPostReply(nullptr, 0));
bncdf80d44fd2016-07-15 20:27:417506 reads.push_back(CreateMockRead(reply, i++));
7507 reads.push_back(CreateMockRead(body2, i++));
7508 reads.push_back(CreateMockRead(body5, i++));
xunjieli179a6e72016-04-26 19:47:457509 reads.push_back(MockRead(ASYNC, 0, i++)); // EOF
[email protected]d11b6912013-06-27 23:07:327510
Ryan Sleevib8d7ea02018-05-07 20:01:017511 SequencedSocketData data(reads, writes);
[email protected]d11b6912013-06-27 23:07:327512
danakjaee3e1ec2016-04-16 00:23:187513 std::vector<std::unique_ptr<UploadElementReader>> element_readers;
Bence Béky4e83f492018-05-13 23:14:257514 std::string upload_data_string(kBufferSize * num_upload_buffers, 'a');
[email protected]d11b6912013-06-27 23:07:327515 upload_data_string.append(kUploadData, kUploadDataSize);
Jeremy Roman0579ed62017-08-29 15:56:197516 element_readers.push_back(std::make_unique<UploadBytesElementReader>(
bnc3f6a8552017-05-17 13:40:347517 upload_data_string.c_str(), upload_data_string.size()));
olli.raula6df48b2a2015-11-26 07:40:227518 ElementsUploadDataStream upload_data_stream(std::move(element_readers), 0);
[email protected]d11b6912013-06-27 23:07:327519
Bence Békydb3cf652017-10-10 15:22:107520 request_.method = "POST";
7521 request_.upload_data_stream = &upload_data_stream;
7522 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
7523
[email protected]d11b6912013-06-27 23:07:327524 helper.AddData(&data);
7525 helper.RunPreTestSetup();
7526
7527 HttpNetworkTransaction* trans = helper.trans();
7528
7529 TestCompletionCallback callback;
Bence Békydb3cf652017-10-10 15:22:107530 int rv = trans->Start(&request_, callback.callback(), log_);
robpercival214763f2016-07-01 23:27:017531 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]d11b6912013-06-27 23:07:327532
[email protected]fc9d88472013-08-14 02:31:177533 base::RunLoop().RunUntilIdle(); // Write as much as we can.
[email protected]d11b6912013-06-27 23:07:327534
7535 SpdyHttpStream* stream = static_cast<SpdyHttpStream*>(trans->stream_.get());
wezca1070932016-05-26 20:30:527536 ASSERT_TRUE(stream);
7537 ASSERT_TRUE(stream->stream());
[email protected]d11b6912013-06-27 23:07:327538 EXPECT_EQ(0, stream->stream()->send_window_size());
xunjieli179a6e72016-04-26 19:47:457539 if (initial_window_size % kBufferSize != 0) {
7540 // If it does not take whole number of full upload buffer to zero out
7541 // initial window size, then the upload data is not at EOF, because the
7542 // last read must be stalled.
7543 EXPECT_FALSE(upload_data_stream.IsEOF());
7544 } else {
7545 // All the body data should have been read.
7546 // TODO(satorux): This is because of the weirdness in reading the request
7547 // body in OnSendBodyComplete(). See crbug.com/113107.
7548 EXPECT_TRUE(upload_data_stream.IsEOF());
7549 }
[email protected]d11b6912013-06-27 23:07:327550 // But the body is not yet fully sent (kUploadData is not yet sent)
7551 // since we're send-stalled.
7552 EXPECT_TRUE(stream->stream()->send_stalled_by_flow_control());
7553
mmenkee24011922015-12-17 22:12:597554 data.Resume(); // Read in WINDOW_UPDATE frame.
[email protected]d11b6912013-06-27 23:07:327555 rv = callback.WaitForResult();
bnceb9aa7112017-01-05 01:03:467556 EXPECT_THAT(rv, IsOk());
7557
7558 // Finish async network reads.
7559 base::RunLoop().RunUntilIdle();
[email protected]d11b6912013-06-27 23:07:327560 helper.VerifyDataConsumed();
7561}
7562
7563// Test we correctly handle the case where the SETTINGS frame results in
7564// unstalling the send window.
bncd16676a2016-07-20 16:23:017565TEST_F(SpdyNetworkTransactionTest, FlowControlStallResumeAfterSettings) {
bncbca843ba2016-07-14 13:05:487566 const int32_t initial_window_size = kDefaultInitialWindowSize;
xunjieli179a6e72016-04-26 19:47:457567 // Number of upload data buffers we need to send to zero out the window size
7568 // is the minimal number of upload buffers takes to be bigger than
7569 // |initial_window_size|.
7570 size_t num_upload_buffers =
7571 ceil(static_cast<double>(initial_window_size) / kBufferSize);
7572 // Each upload data buffer consists of |num_frames_in_one_upload_buffer|
7573 // frames, each with |kMaxSpdyFrameChunkSize| bytes except the last frame,
7574 // which has kBufferSize % kMaxSpdyChunkSize bytes.
7575 size_t num_frames_in_one_upload_buffer =
7576 ceil(static_cast<double>(kBufferSize) / kMaxSpdyFrameChunkSize);
[email protected]d11b6912013-06-27 23:07:327577
7578 // Construct content for a data frame of maximum size.
Bence Béky4e83f492018-05-13 23:14:257579 std::string content(kMaxSpdyFrameChunkSize, 'a');
[email protected]d11b6912013-06-27 23:07:327580
Ryan Hamilton0239aac2018-05-19 00:03:137581 spdy::SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
bncb26024382016-06-29 02:39:457582 kDefaultUrl, 1,
xunjieli179a6e72016-04-26 19:47:457583 /*content_length=*/kBufferSize * num_upload_buffers + kUploadDataSize,
tombergan5d22c182017-01-11 02:05:357584 LOWEST, nullptr, 0));
[email protected]d11b6912013-06-27 23:07:327585
7586 // Full frames.
Ryan Hamilton0239aac2018-05-19 00:03:137587 spdy::SpdySerializedFrame body1(
Bence Békyd74f4382018-02-20 18:26:197588 spdy_util_.ConstructSpdyDataFrame(1, content, false));
[email protected]d11b6912013-06-27 23:07:327589
xunjieli179a6e72016-04-26 19:47:457590 // Last frame in each upload data buffer.
Ryan Hamilton0239aac2018-05-19 00:03:137591 spdy::SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(
Bence Békyd74f4382018-02-20 18:26:197592 1,
7593 base::StringPiece(content.data(), kBufferSize % kMaxSpdyFrameChunkSize),
7594 false));
[email protected]d11b6912013-06-27 23:07:327595
xunjieli179a6e72016-04-26 19:47:457596 // The very last frame before the stalled frames.
Ryan Hamilton0239aac2018-05-19 00:03:137597 spdy::SpdySerializedFrame body3(spdy_util_.ConstructSpdyDataFrame(
Bence Békyd74f4382018-02-20 18:26:197598 1,
7599 base::StringPiece(content.data(), initial_window_size % kBufferSize %
7600 kMaxSpdyFrameChunkSize),
7601 false));
xunjieli179a6e72016-04-26 19:47:457602
7603 // Data frames to be sent once WINDOW_UPDATE frame is received.
7604
7605 // If kBufferSize * num_upload_buffers > initial_window_size,
7606 // we need one additional frame to send the rest of 'a'.
Bence Béky4e83f492018-05-13 23:14:257607 std::string last_body(kBufferSize * num_upload_buffers - initial_window_size,
7608 'a');
Ryan Hamilton0239aac2018-05-19 00:03:137609 spdy::SpdySerializedFrame body4(
Bence Békyd74f4382018-02-20 18:26:197610 spdy_util_.ConstructSpdyDataFrame(1, last_body, false));
xunjieli179a6e72016-04-26 19:47:457611
7612 // Also send a "hello!" after WINDOW_UPDATE.
Ryan Hamilton0239aac2018-05-19 00:03:137613 spdy::SpdySerializedFrame body5(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]d11b6912013-06-27 23:07:327614
xunjieli179a6e72016-04-26 19:47:457615 // Fill in mock writes.
[email protected]d11b6912013-06-27 23:07:327616 size_t i = 0;
xunjieli179a6e72016-04-26 19:47:457617 std::vector<MockWrite> writes;
bncdf80d44fd2016-07-15 20:27:417618 writes.push_back(CreateMockWrite(req, i++));
xunjieli179a6e72016-04-26 19:47:457619 for (size_t j = 0; j < num_upload_buffers; j++) {
7620 for (size_t k = 0; k < num_frames_in_one_upload_buffer; k++) {
7621 if (k == num_frames_in_one_upload_buffer - 1 &&
7622 kBufferSize % kMaxSpdyFrameChunkSize != 0) {
7623 if (j == num_upload_buffers - 1 &&
7624 (initial_window_size % kBufferSize != 0)) {
bncdf80d44fd2016-07-15 20:27:417625 writes.push_back(CreateMockWrite(body3, i++));
xunjieli179a6e72016-04-26 19:47:457626 } else {
bncdf80d44fd2016-07-15 20:27:417627 writes.push_back(CreateMockWrite(body2, i++));
xunjieli179a6e72016-04-26 19:47:457628 }
7629 } else {
bncdf80d44fd2016-07-15 20:27:417630 writes.push_back(CreateMockWrite(body1, i++));
xunjieli179a6e72016-04-26 19:47:457631 }
7632 }
7633 }
[email protected]d11b6912013-06-27 23:07:327634
xunjieli179a6e72016-04-26 19:47:457635 // Fill in mock reads.
7636 std::vector<MockRead> reads;
7637 // Force a pause.
mmenke666a6fea2015-12-19 04:16:337638 reads.push_back(MockRead(ASYNC, ERR_IO_PENDING, i++));
7639
[email protected]d11b6912013-06-27 23:07:327640 // Construct read frame for SETTINGS that gives enough space to upload the
7641 // rest of the data.
Ryan Hamilton0239aac2018-05-19 00:03:137642 spdy::SettingsMap settings;
7643 settings[spdy::SETTINGS_INITIAL_WINDOW_SIZE] = initial_window_size * 2;
7644 spdy::SpdySerializedFrame settings_frame_large(
[email protected]d11b6912013-06-27 23:07:327645 spdy_util_.ConstructSpdySettings(settings));
7646
bncdf80d44fd2016-07-15 20:27:417647 reads.push_back(CreateMockRead(settings_frame_large, i++));
[email protected]d11b6912013-06-27 23:07:327648
Ryan Hamilton0239aac2018-05-19 00:03:137649 spdy::SpdySerializedFrame session_window_update(
xunjieli179a6e72016-04-26 19:47:457650 spdy_util_.ConstructSpdyWindowUpdate(0,
7651 last_body.size() + kUploadDataSize));
bncdf80d44fd2016-07-15 20:27:417652 reads.push_back(CreateMockRead(session_window_update, i++));
[email protected]d11b6912013-06-27 23:07:327653
Ryan Hamilton0239aac2018-05-19 00:03:137654 spdy::SpdySerializedFrame settings_ack(spdy_util_.ConstructSpdySettingsAck());
bncdf80d44fd2016-07-15 20:27:417655 writes.push_back(CreateMockWrite(settings_ack, i++));
[email protected]d4a77c12014-05-15 20:45:217656
xunjieli179a6e72016-04-26 19:47:457657 // Stalled frames which can be sent after |settings_ack|.
7658 if (last_body.size() > 0)
bncdf80d44fd2016-07-15 20:27:417659 writes.push_back(CreateMockWrite(body4, i++));
7660 writes.push_back(CreateMockWrite(body5, i++));
[email protected]d11b6912013-06-27 23:07:327661
Ryan Hamilton0239aac2018-05-19 00:03:137662 spdy::SpdySerializedFrame reply(
7663 spdy_util_.ConstructSpdyPostReply(nullptr, 0));
bncdf80d44fd2016-07-15 20:27:417664 reads.push_back(CreateMockRead(reply, i++));
7665 reads.push_back(CreateMockRead(body2, i++));
7666 reads.push_back(CreateMockRead(body5, i++));
[email protected]d11b6912013-06-27 23:07:327667 reads.push_back(MockRead(ASYNC, 0, i++)); // EOF
7668
7669 // Force all writes to happen before any read, last write will not
7670 // actually queue a frame, due to window size being 0.
Ryan Sleevib8d7ea02018-05-07 20:01:017671 SequencedSocketData data(reads, writes);
[email protected]d11b6912013-06-27 23:07:327672
danakjaee3e1ec2016-04-16 00:23:187673 std::vector<std::unique_ptr<UploadElementReader>> element_readers;
Bence Béky4e83f492018-05-13 23:14:257674 std::string upload_data_string(kBufferSize * num_upload_buffers, 'a');
[email protected]d11b6912013-06-27 23:07:327675 upload_data_string.append(kUploadData, kUploadDataSize);
Jeremy Roman0579ed62017-08-29 15:56:197676 element_readers.push_back(std::make_unique<UploadBytesElementReader>(
bnc3f6a8552017-05-17 13:40:347677 upload_data_string.c_str(), upload_data_string.size()));
olli.raula6df48b2a2015-11-26 07:40:227678 ElementsUploadDataStream upload_data_stream(std::move(element_readers), 0);
[email protected]d11b6912013-06-27 23:07:327679
Bence Békydb3cf652017-10-10 15:22:107680 request_.method = "POST";
7681 request_.upload_data_stream = &upload_data_stream;
7682 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
7683
[email protected]d11b6912013-06-27 23:07:327684 helper.RunPreTestSetup();
mmenke666a6fea2015-12-19 04:16:337685 helper.AddData(&data);
[email protected]d11b6912013-06-27 23:07:327686
7687 HttpNetworkTransaction* trans = helper.trans();
7688
7689 TestCompletionCallback callback;
Bence Békydb3cf652017-10-10 15:22:107690 int rv = trans->Start(&request_, callback.callback(), log_);
robpercival214763f2016-07-01 23:27:017691 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]d11b6912013-06-27 23:07:327692
mmenke666a6fea2015-12-19 04:16:337693 data.RunUntilPaused(); // Write as much as we can.
7694 base::RunLoop().RunUntilIdle();
[email protected]d11b6912013-06-27 23:07:327695
7696 SpdyHttpStream* stream = static_cast<SpdyHttpStream*>(trans->stream_.get());
wezca1070932016-05-26 20:30:527697 ASSERT_TRUE(stream);
7698 ASSERT_TRUE(stream->stream());
[email protected]d11b6912013-06-27 23:07:327699 EXPECT_EQ(0, stream->stream()->send_window_size());
7700
xunjieli179a6e72016-04-26 19:47:457701 if (initial_window_size % kBufferSize != 0) {
7702 // If it does not take whole number of full upload buffer to zero out
7703 // initial window size, then the upload data is not at EOF, because the
7704 // last read must be stalled.
7705 EXPECT_FALSE(upload_data_stream.IsEOF());
7706 } else {
7707 // All the body data should have been read.
7708 // TODO(satorux): This is because of the weirdness in reading the request
7709 // body in OnSendBodyComplete(). See crbug.com/113107.
7710 EXPECT_TRUE(upload_data_stream.IsEOF());
7711 }
[email protected]d11b6912013-06-27 23:07:327712 // But the body is not yet fully sent (kUploadData is not yet sent)
7713 // since we're send-stalled.
7714 EXPECT_TRUE(stream->stream()->send_stalled_by_flow_control());
7715
mmenke666a6fea2015-12-19 04:16:337716 // Read in SETTINGS frame to unstall.
7717 data.Resume();
7718 base::RunLoop().RunUntilIdle();
7719
[email protected]d11b6912013-06-27 23:07:327720 rv = callback.WaitForResult();
7721 helper.VerifyDataConsumed();
tombergan5d22c182017-01-11 02:05:357722 // If stream is nullptr, that means it was unstalled and closed.
7723 EXPECT_TRUE(stream->stream() == nullptr);
[email protected]d11b6912013-06-27 23:07:327724}
7725
7726// Test we correctly handle the case where the SETTINGS frame results in a
7727// negative send window size.
bncd16676a2016-07-20 16:23:017728TEST_F(SpdyNetworkTransactionTest, FlowControlNegativeSendWindowSize) {
bncbca843ba2016-07-14 13:05:487729 const int32_t initial_window_size = kDefaultInitialWindowSize;
xunjieli179a6e72016-04-26 19:47:457730 // Number of upload data buffers we need to send to zero out the window size
7731 // is the minimal number of upload buffers takes to be bigger than
7732 // |initial_window_size|.
7733 size_t num_upload_buffers =
7734 ceil(static_cast<double>(initial_window_size) / kBufferSize);
7735 // Each upload data buffer consists of |num_frames_in_one_upload_buffer|
7736 // frames, each with |kMaxSpdyFrameChunkSize| bytes except the last frame,
7737 // which has kBufferSize % kMaxSpdyChunkSize bytes.
7738 size_t num_frames_in_one_upload_buffer =
7739 ceil(static_cast<double>(kBufferSize) / kMaxSpdyFrameChunkSize);
[email protected]d11b6912013-06-27 23:07:327740
7741 // Construct content for a data frame of maximum size.
Bence Béky4e83f492018-05-13 23:14:257742 std::string content(kMaxSpdyFrameChunkSize, 'a');
[email protected]d11b6912013-06-27 23:07:327743
Ryan Hamilton0239aac2018-05-19 00:03:137744 spdy::SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
bncb26024382016-06-29 02:39:457745 kDefaultUrl, 1,
xunjieli179a6e72016-04-26 19:47:457746 /*content_length=*/kBufferSize * num_upload_buffers + kUploadDataSize,
tombergan5d22c182017-01-11 02:05:357747 LOWEST, nullptr, 0));
[email protected]d11b6912013-06-27 23:07:327748
7749 // Full frames.
Ryan Hamilton0239aac2018-05-19 00:03:137750 spdy::SpdySerializedFrame body1(
Bence Békyd74f4382018-02-20 18:26:197751 spdy_util_.ConstructSpdyDataFrame(1, content, false));
[email protected]d11b6912013-06-27 23:07:327752
xunjieli179a6e72016-04-26 19:47:457753 // Last frame in each upload data buffer.
Ryan Hamilton0239aac2018-05-19 00:03:137754 spdy::SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(
Bence Békyd74f4382018-02-20 18:26:197755 1,
7756 base::StringPiece(content.data(), kBufferSize % kMaxSpdyFrameChunkSize),
7757 false));
[email protected]d11b6912013-06-27 23:07:327758
xunjieli179a6e72016-04-26 19:47:457759 // The very last frame before the stalled frames.
Ryan Hamilton0239aac2018-05-19 00:03:137760 spdy::SpdySerializedFrame body3(spdy_util_.ConstructSpdyDataFrame(
Bence Békyd74f4382018-02-20 18:26:197761 1,
7762 base::StringPiece(content.data(), initial_window_size % kBufferSize %
7763 kMaxSpdyFrameChunkSize),
7764 false));
xunjieli179a6e72016-04-26 19:47:457765
7766 // Data frames to be sent once WINDOW_UPDATE frame is received.
7767
7768 // If kBufferSize * num_upload_buffers > initial_window_size,
7769 // we need one additional frame to send the rest of 'a'.
Bence Béky4e83f492018-05-13 23:14:257770 std::string last_body(kBufferSize * num_upload_buffers - initial_window_size,
7771 'a');
Ryan Hamilton0239aac2018-05-19 00:03:137772 spdy::SpdySerializedFrame body4(
Bence Békyd74f4382018-02-20 18:26:197773 spdy_util_.ConstructSpdyDataFrame(1, last_body, false));
xunjieli179a6e72016-04-26 19:47:457774
7775 // Also send a "hello!" after WINDOW_UPDATE.
Ryan Hamilton0239aac2018-05-19 00:03:137776 spdy::SpdySerializedFrame body5(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]d11b6912013-06-27 23:07:327777
xunjieli179a6e72016-04-26 19:47:457778 // Fill in mock writes.
[email protected]d11b6912013-06-27 23:07:327779 size_t i = 0;
xunjieli179a6e72016-04-26 19:47:457780 std::vector<MockWrite> writes;
bncdf80d44fd2016-07-15 20:27:417781 writes.push_back(CreateMockWrite(req, i++));
xunjieli179a6e72016-04-26 19:47:457782 for (size_t j = 0; j < num_upload_buffers; j++) {
7783 for (size_t k = 0; k < num_frames_in_one_upload_buffer; k++) {
7784 if (k == num_frames_in_one_upload_buffer - 1 &&
7785 kBufferSize % kMaxSpdyFrameChunkSize != 0) {
7786 if (j == num_upload_buffers - 1 &&
7787 (initial_window_size % kBufferSize != 0)) {
bncdf80d44fd2016-07-15 20:27:417788 writes.push_back(CreateMockWrite(body3, i++));
xunjieli179a6e72016-04-26 19:47:457789 } else {
bncdf80d44fd2016-07-15 20:27:417790 writes.push_back(CreateMockWrite(body2, i++));
xunjieli179a6e72016-04-26 19:47:457791 }
7792 } else {
bncdf80d44fd2016-07-15 20:27:417793 writes.push_back(CreateMockWrite(body1, i++));
xunjieli179a6e72016-04-26 19:47:457794 }
7795 }
7796 }
[email protected]d11b6912013-06-27 23:07:327797
xunjieli179a6e72016-04-26 19:47:457798 // Fill in mock reads.
7799 std::vector<MockRead> reads;
7800 // Force a pause.
mmenke666a6fea2015-12-19 04:16:337801 reads.push_back(MockRead(ASYNC, ERR_IO_PENDING, i++));
[email protected]d11b6912013-06-27 23:07:327802 // Construct read frame for SETTINGS that makes the send_window_size
7803 // negative.
Ryan Hamilton0239aac2018-05-19 00:03:137804 spdy::SettingsMap new_settings;
7805 new_settings[spdy::SETTINGS_INITIAL_WINDOW_SIZE] = initial_window_size / 2;
7806 spdy::SpdySerializedFrame settings_frame_small(
[email protected]d11b6912013-06-27 23:07:327807 spdy_util_.ConstructSpdySettings(new_settings));
7808 // Construct read frames for WINDOW_UPDATE that makes the send_window_size
7809 // positive.
Ryan Hamilton0239aac2018-05-19 00:03:137810 spdy::SpdySerializedFrame session_window_update_init_size(
bnc2f54c832014-12-01 13:31:197811 spdy_util_.ConstructSpdyWindowUpdate(0, initial_window_size));
Ryan Hamilton0239aac2018-05-19 00:03:137812 spdy::SpdySerializedFrame window_update_init_size(
bnc2f54c832014-12-01 13:31:197813 spdy_util_.ConstructSpdyWindowUpdate(1, initial_window_size));
[email protected]d11b6912013-06-27 23:07:327814
bncdf80d44fd2016-07-15 20:27:417815 reads.push_back(CreateMockRead(settings_frame_small, i++));
7816 reads.push_back(CreateMockRead(session_window_update_init_size, i++));
7817 reads.push_back(CreateMockRead(window_update_init_size, i++));
[email protected]d11b6912013-06-27 23:07:327818
Ryan Hamilton0239aac2018-05-19 00:03:137819 spdy::SpdySerializedFrame settings_ack(spdy_util_.ConstructSpdySettingsAck());
bncdf80d44fd2016-07-15 20:27:417820 writes.push_back(CreateMockWrite(settings_ack, i++));
[email protected]d4a77c12014-05-15 20:45:217821
xunjieli179a6e72016-04-26 19:47:457822 // Stalled frames which can be sent after |settings_ack|.
7823 if (last_body.size() > 0)
bncdf80d44fd2016-07-15 20:27:417824 writes.push_back(CreateMockWrite(body4, i++));
7825 writes.push_back(CreateMockWrite(body5, i++));
[email protected]d11b6912013-06-27 23:07:327826
Ryan Hamilton0239aac2018-05-19 00:03:137827 spdy::SpdySerializedFrame reply(
7828 spdy_util_.ConstructSpdyPostReply(nullptr, 0));
bncdf80d44fd2016-07-15 20:27:417829 reads.push_back(CreateMockRead(reply, i++));
7830 reads.push_back(CreateMockRead(body2, i++));
7831 reads.push_back(CreateMockRead(body5, i++));
[email protected]d11b6912013-06-27 23:07:327832 reads.push_back(MockRead(ASYNC, 0, i++)); // EOF
7833
7834 // Force all writes to happen before any read, last write will not
7835 // actually queue a frame, due to window size being 0.
Ryan Sleevib8d7ea02018-05-07 20:01:017836 SequencedSocketData data(reads, writes);
[email protected]d11b6912013-06-27 23:07:327837
danakjaee3e1ec2016-04-16 00:23:187838 std::vector<std::unique_ptr<UploadElementReader>> element_readers;
Bence Béky4e83f492018-05-13 23:14:257839 std::string upload_data_string(kBufferSize * num_upload_buffers, 'a');
[email protected]d11b6912013-06-27 23:07:327840 upload_data_string.append(kUploadData, kUploadDataSize);
Jeremy Roman0579ed62017-08-29 15:56:197841 element_readers.push_back(std::make_unique<UploadBytesElementReader>(
bnc3f6a8552017-05-17 13:40:347842 upload_data_string.c_str(), upload_data_string.size()));
olli.raula6df48b2a2015-11-26 07:40:227843 ElementsUploadDataStream upload_data_stream(std::move(element_readers), 0);
[email protected]d11b6912013-06-27 23:07:327844
Bence Békydb3cf652017-10-10 15:22:107845 request_.method = "POST";
7846 request_.upload_data_stream = &upload_data_stream;
7847 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
7848
[email protected]d11b6912013-06-27 23:07:327849 helper.RunPreTestSetup();
mmenke666a6fea2015-12-19 04:16:337850 helper.AddData(&data);
[email protected]d11b6912013-06-27 23:07:327851
7852 HttpNetworkTransaction* trans = helper.trans();
7853
7854 TestCompletionCallback callback;
Bence Békydb3cf652017-10-10 15:22:107855 int rv = trans->Start(&request_, callback.callback(), log_);
robpercival214763f2016-07-01 23:27:017856 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]d11b6912013-06-27 23:07:327857
mmenke666a6fea2015-12-19 04:16:337858 data.RunUntilPaused(); // Write as much as we can.
7859 base::RunLoop().RunUntilIdle();
[email protected]d11b6912013-06-27 23:07:327860
7861 SpdyHttpStream* stream = static_cast<SpdyHttpStream*>(trans->stream_.get());
wezca1070932016-05-26 20:30:527862 ASSERT_TRUE(stream);
7863 ASSERT_TRUE(stream->stream());
[email protected]d11b6912013-06-27 23:07:327864 EXPECT_EQ(0, stream->stream()->send_window_size());
7865
xunjieli179a6e72016-04-26 19:47:457866 if (initial_window_size % kBufferSize != 0) {
7867 // If it does not take whole number of full upload buffer to zero out
7868 // initial window size, then the upload data is not at EOF, because the
7869 // last read must be stalled.
7870 EXPECT_FALSE(upload_data_stream.IsEOF());
7871 } else {
7872 // All the body data should have been read.
7873 // TODO(satorux): This is because of the weirdness in reading the request
7874 // body in OnSendBodyComplete(). See crbug.com/113107.
7875 EXPECT_TRUE(upload_data_stream.IsEOF());
7876 }
[email protected]d11b6912013-06-27 23:07:327877
7878 // Read in WINDOW_UPDATE or SETTINGS frame.
mmenke666a6fea2015-12-19 04:16:337879 data.Resume();
7880 base::RunLoop().RunUntilIdle();
[email protected]d11b6912013-06-27 23:07:327881 rv = callback.WaitForResult();
7882 helper.VerifyDataConsumed();
7883}
7884
bncd16676a2016-07-20 16:23:017885TEST_F(SpdyNetworkTransactionTest, GoAwayOnOddPushStreamId) {
Bence Békyeacd48f2018-05-14 11:34:337886 base::HistogramTester histogram_tester;
7887
Ryan Hamilton0239aac2018-05-19 00:03:137888 spdy::SpdyHeaderBlock push_headers;
bnc086b39e12016-06-24 13:05:267889 spdy_util_.AddUrlToHeaderBlock("http://www.example.org/a.dat", &push_headers);
Ryan Hamilton0239aac2018-05-19 00:03:137890 spdy::SpdySerializedFrame push(
Bence Békyf1d78522018-01-11 01:16:507891 spdy_util_.ConstructSpdyPushPromise(1, 3, std::move(push_headers)));
bncdf80d44fd2016-07-15 20:27:417892 MockRead reads[] = {CreateMockRead(push, 1)};
baranovich212a1292014-09-02 21:45:317893
Ryan Hamilton0239aac2018-05-19 00:03:137894 spdy::SpdySerializedFrame req(
7895 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
7896 spdy::SpdySerializedFrame goaway(spdy_util_.ConstructSpdyGoAway(
7897 0, spdy::ERROR_CODE_PROTOCOL_ERROR,
Bence Béky602c40c2017-07-26 05:22:567898 "Received invalid pushed stream id 3 (must be even) on stream id 1."));
baranovich212a1292014-09-02 21:45:317899 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:417900 CreateMockWrite(req, 0), CreateMockWrite(goaway, 2),
baranovich212a1292014-09-02 21:45:317901 };
7902
Ryan Sleevib8d7ea02018-05-07 20:01:017903 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:107904 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
baranovich212a1292014-09-02 21:45:317905 helper.RunToCompletion(&data);
7906 TransactionHelperResult out = helper.output();
Bence Békyd0d69502019-06-25 19:47:187907 EXPECT_THAT(out.rv, IsError(ERR_HTTP2_PROTOCOL_ERROR));
Bence Békyeacd48f2018-05-14 11:34:337908
7909 histogram_tester.ExpectBucketCount(
7910 "Net.SpdyPushedStreamFate",
7911 static_cast<int>(SpdyPushedStreamFate::kPromisedStreamIdParityError), 1);
7912 histogram_tester.ExpectTotalCount("Net.SpdyPushedStreamFate", 1);
baranovich212a1292014-09-02 21:45:317913}
7914
bncd16676a2016-07-20 16:23:017915TEST_F(SpdyNetworkTransactionTest,
baranovich212a1292014-09-02 21:45:317916 GoAwayOnPushStreamIdLesserOrEqualThanLastAccepted) {
Bence Békyeacd48f2018-05-14 11:34:337917 base::HistogramTester histogram_tester;
7918
Ryan Hamilton0239aac2018-05-19 00:03:137919 spdy::SpdySerializedFrame push_a(spdy_util_.ConstructSpdyPush(
Bence Béky3e01b532018-02-06 23:04:517920 nullptr, 0, 4, 1, "https://www.example.org/a.dat"));
Ryan Hamilton0239aac2018-05-19 00:03:137921 spdy::SpdyHeaderBlock push_b_headers;
Bence Béky3e01b532018-02-06 23:04:517922 spdy_util_.AddUrlToHeaderBlock("https://www.example.org/b.dat",
bnc086b39e12016-06-24 13:05:267923 &push_b_headers);
Ryan Hamilton0239aac2018-05-19 00:03:137924 spdy::SpdySerializedFrame push_b(
Bence Békyf1d78522018-01-11 01:16:507925 spdy_util_.ConstructSpdyPushPromise(1, 2, std::move(push_b_headers)));
baranovich212a1292014-09-02 21:45:317926 MockRead reads[] = {
tombergan5d22c182017-01-11 02:05:357927 CreateMockRead(push_a, 1), CreateMockRead(push_b, 3),
baranovich212a1292014-09-02 21:45:317928 };
7929
Ryan Hamilton0239aac2018-05-19 00:03:137930 spdy::SpdySerializedFrame req(
7931 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
7932 spdy::SpdySerializedFrame priority_a(
tombergan5d22c182017-01-11 02:05:357933 spdy_util_.ConstructSpdyPriority(4, 1, IDLE, true));
Ryan Hamilton0239aac2018-05-19 00:03:137934 spdy::SpdySerializedFrame goaway(spdy_util_.ConstructSpdyGoAway(
7935 4, spdy::ERROR_CODE_PROTOCOL_ERROR,
Bence Béky602c40c2017-07-26 05:22:567936 "Received pushed stream id 2 must be larger than last accepted id 4."));
baranovich212a1292014-09-02 21:45:317937 MockWrite writes[] = {
tombergan5d22c182017-01-11 02:05:357938 CreateMockWrite(req, 0), CreateMockWrite(priority_a, 2),
7939 CreateMockWrite(goaway, 4),
baranovich212a1292014-09-02 21:45:317940 };
7941
Ryan Sleevib8d7ea02018-05-07 20:01:017942 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:107943 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
baranovich212a1292014-09-02 21:45:317944 helper.RunToCompletion(&data);
7945 TransactionHelperResult out = helper.output();
Bence Békyd0d69502019-06-25 19:47:187946 EXPECT_THAT(out.rv, IsError(ERR_HTTP2_PROTOCOL_ERROR));
Bence Békyeacd48f2018-05-14 11:34:337947
7948 histogram_tester.ExpectBucketCount(
7949 "Net.SpdyPushedStreamFate",
7950 static_cast<int>(SpdyPushedStreamFate::kStreamIdOutOfOrder), 1);
7951 histogram_tester.ExpectTotalCount("Net.SpdyPushedStreamFate", 1);
baranovich212a1292014-09-02 21:45:317952}
7953
bnc76598ab2015-06-29 12:43:077954// Regression test for https://crbug.com/493348: request header exceeds 16 kB
7955// and thus sent in multiple frames when using HTTP/2.
bncd16676a2016-07-20 16:23:017956TEST_F(SpdyNetworkTransactionTest, LargeRequest) {
Bence Béky4e83f492018-05-13 23:14:257957 const std::string kKey("foo");
7958 const std::string kValue(1 << 15, 'z');
bnc76598ab2015-06-29 12:43:077959
Bence Békydb3cf652017-10-10 15:22:107960 request_.extra_headers.SetHeader(kKey, kValue);
bnc76598ab2015-06-29 12:43:077961
Ryan Hamilton0239aac2018-05-19 00:03:137962 spdy::SpdyHeaderBlock headers(
7963 spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
bnc086b39e12016-06-24 13:05:267964 headers[kKey] = kValue;
Ryan Hamilton0239aac2018-05-19 00:03:137965 spdy::SpdySerializedFrame req(
bnc42331402016-07-25 13:36:157966 spdy_util_.ConstructSpdyHeaders(1, std::move(headers), LOWEST, true));
bnc76598ab2015-06-29 12:43:077967 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:417968 CreateMockWrite(req, 0),
bnc76598ab2015-06-29 12:43:077969 };
7970
Ryan Hamilton0239aac2018-05-19 00:03:137971 spdy::SpdySerializedFrame resp(
7972 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
7973 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
bnc76598ab2015-06-29 12:43:077974 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:417975 CreateMockRead(resp, 1), CreateMockRead(body, 2),
bnc76598ab2015-06-29 12:43:077976 MockRead(ASYNC, 0, 3) // EOF
7977 };
7978
Ryan Sleevib8d7ea02018-05-07 20:01:017979 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:107980 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
bnc76598ab2015-06-29 12:43:077981 helper.RunToCompletion(&data);
7982 TransactionHelperResult out = helper.output();
7983
robpercival214763f2016-07-01 23:27:017984 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:027985 EXPECT_EQ("HTTP/1.1 200", out.status_line);
bnc76598ab2015-06-29 12:43:077986 EXPECT_EQ("hello!", out.response_data);
7987}
7988
bncd67383342016-01-08 21:58:437989// Regression test for https://crbug.com/535629: response header exceeds 16 kB.
bncd16676a2016-07-20 16:23:017990TEST_F(SpdyNetworkTransactionTest, LargeResponseHeader) {
Ryan Hamilton0239aac2018-05-19 00:03:137991 spdy::SpdyHeaderBlock headers(
7992 spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
7993 spdy::SpdySerializedFrame req(
bnc42331402016-07-25 13:36:157994 spdy_util_.ConstructSpdyHeaders(1, std::move(headers), LOWEST, true));
bncd67383342016-01-08 21:58:437995 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:417996 CreateMockWrite(req, 0),
bncd67383342016-01-08 21:58:437997 };
7998
7999 // HPACK decoder implementation limits string literal length to 16 kB.
8000 const char* response_headers[2];
Bence Béky4e83f492018-05-13 23:14:258001 const std::string kKey(16 * 1024, 'a');
bncd67383342016-01-08 21:58:438002 response_headers[0] = kKey.data();
Bence Béky4e83f492018-05-13 23:14:258003 const std::string kValue(16 * 1024, 'b');
bncd67383342016-01-08 21:58:438004 response_headers[1] = kValue.data();
8005
Ryan Hamilton0239aac2018-05-19 00:03:138006 spdy::SpdySerializedFrame resp(
bnc42331402016-07-25 13:36:158007 spdy_util_.ConstructSpdyGetReply(response_headers, 1, 1));
Ryan Hamilton0239aac2018-05-19 00:03:138008 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
bncd67383342016-01-08 21:58:438009 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:418010 CreateMockRead(resp, 1), CreateMockRead(body, 2),
bncd67383342016-01-08 21:58:438011 MockRead(ASYNC, 0, 3) // EOF
8012 };
8013
Bence Békydb3cf652017-10-10 15:22:108014 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
bncd67383342016-01-08 21:58:438015
Ryan Sleevib8d7ea02018-05-07 20:01:018016 SequencedSocketData data(reads, writes);
bncd67383342016-01-08 21:58:438017 helper.RunToCompletion(&data);
8018 TransactionHelperResult out = helper.output();
8019
robpercival214763f2016-07-01 23:27:018020 EXPECT_THAT(out.rv, IsOk());
bncd67383342016-01-08 21:58:438021 EXPECT_EQ("HTTP/1.1 200", out.status_line);
8022 EXPECT_EQ("hello!", out.response_data);
8023 ASSERT_TRUE(out.response_info.headers->HasHeaderValue(kKey, kValue));
8024}
8025
bnc204a6d02016-08-01 14:34:278026// End of line delimiter is forbidden according to RFC 7230 Section 3.2.
8027TEST_F(SpdyNetworkTransactionTest, CRLFInHeaderValue) {
Ryan Hamilton0239aac2018-05-19 00:03:138028 spdy::SpdySerializedFrame req(
8029 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
8030 spdy::SpdySerializedFrame rst(
8031 spdy_util_.ConstructSpdyRstStream(1, spdy::ERROR_CODE_PROTOCOL_ERROR));
bnc204a6d02016-08-01 14:34:278032 MockWrite writes[] = {CreateMockWrite(req, 0), CreateMockWrite(rst, 2)};
8033
8034 const char* response_headers[] = {"folded", "foo\r\nbar"};
Ryan Hamilton0239aac2018-05-19 00:03:138035 spdy::SpdySerializedFrame resp(
bnc204a6d02016-08-01 14:34:278036 spdy_util_.ConstructSpdyGetReply(response_headers, 1, 1));
8037 MockRead reads[] = {CreateMockRead(resp, 1), MockRead(ASYNC, 0, 3)};
8038
Ryan Sleevib8d7ea02018-05-07 20:01:018039 SequencedSocketData data(reads, writes);
bnc204a6d02016-08-01 14:34:278040
Bence Békydb3cf652017-10-10 15:22:108041 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
bnc204a6d02016-08-01 14:34:278042 helper.RunToCompletion(&data);
8043 TransactionHelperResult out = helper.output();
8044
Bence Békyd0d69502019-06-25 19:47:188045 EXPECT_THAT(out.rv, IsError(ERR_HTTP2_PROTOCOL_ERROR));
bnc204a6d02016-08-01 14:34:278046}
8047
bncc22b581e82016-10-27 04:45:428048// Regression test for https://crbug.com/603182.
8049// No response headers received before RST_STREAM: error.
8050TEST_F(SpdyNetworkTransactionTest, RstStreamNoError) {
Ryan Hamilton0239aac2018-05-19 00:03:138051 spdy::SpdySerializedFrame req(
8052 spdy_util_.ConstructChunkedSpdyPost(nullptr, 0));
bncc22b581e82016-10-27 04:45:428053 MockWrite writes[] = {CreateMockWrite(req, 0, ASYNC)};
8054
Ryan Hamilton0239aac2018-05-19 00:03:138055 spdy::SpdySerializedFrame rst(
8056 spdy_util_.ConstructSpdyRstStream(1, spdy::ERROR_CODE_NO_ERROR));
bncc22b581e82016-10-27 04:45:428057 MockRead reads[] = {CreateMockRead(rst, 1), MockRead(ASYNC, 0, 2)};
8058
Ryan Sleevib8d7ea02018-05-07 20:01:018059 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:108060 UseChunkedPostRequest();
8061 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
bncc22b581e82016-10-27 04:45:428062 helper.RunToCompletion(&data);
8063 TransactionHelperResult out = helper.output();
Bence Békyd0d69502019-06-25 19:47:188064 EXPECT_THAT(out.rv, IsError(ERR_HTTP2_PROTOCOL_ERROR));
bncc22b581e82016-10-27 04:45:428065}
8066
8067// Regression test for https://crbug.com/603182.
8068// Response headers and data, then RST_STREAM received,
8069// before request body is sent: success.
8070TEST_F(SpdyNetworkTransactionTest, RstStreamNoErrorAfterResponse) {
Ryan Hamilton0239aac2018-05-19 00:03:138071 spdy::SpdySerializedFrame req(
8072 spdy_util_.ConstructChunkedSpdyPost(nullptr, 0));
bncc22b581e82016-10-27 04:45:428073 MockWrite writes[] = {CreateMockWrite(req, 0, ASYNC)};
8074
Ryan Hamilton0239aac2018-05-19 00:03:138075 spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
8076 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
8077 spdy::SpdySerializedFrame rst(
8078 spdy_util_.ConstructSpdyRstStream(1, spdy::ERROR_CODE_NO_ERROR));
bncc22b581e82016-10-27 04:45:428079 MockRead reads[] = {CreateMockRead(resp, 1), CreateMockRead(body, 2),
8080 CreateMockRead(rst, 3), MockRead(ASYNC, 0, 4)};
8081
Ryan Sleevib8d7ea02018-05-07 20:01:018082 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:108083 UseChunkedPostRequest();
8084 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
bncc22b581e82016-10-27 04:45:428085 helper.RunToCompletion(&data);
8086 TransactionHelperResult out = helper.output();
8087 EXPECT_THAT(out.rv, IsOk());
8088 EXPECT_EQ("HTTP/1.1 200", out.status_line);
8089 EXPECT_EQ("hello!", out.response_data);
8090}
8091
bncc9f762a2016-12-06 20:38:238092TEST_F(SpdyNetworkTransactionTest, 100Continue) {
Ryan Hamilton0239aac2018-05-19 00:03:138093 spdy::SpdySerializedFrame req(
8094 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
bncc9f762a2016-12-06 20:38:238095 MockWrite writes[] = {CreateMockWrite(req, 0)};
8096
Ryan Hamilton0239aac2018-05-19 00:03:138097 spdy::SpdyHeaderBlock informational_headers;
8098 informational_headers[spdy::kHttp2StatusHeader] = "100";
8099 spdy::SpdySerializedFrame informational_response(
bncc9f762a2016-12-06 20:38:238100 spdy_util_.ConstructSpdyReply(1, std::move(informational_headers)));
Ryan Hamilton0239aac2018-05-19 00:03:138101 spdy::SpdySerializedFrame resp(
8102 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
8103 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
bncc9f762a2016-12-06 20:38:238104 MockRead reads[] = {
8105 CreateMockRead(informational_response, 1), CreateMockRead(resp, 2),
8106 CreateMockRead(body, 3), MockRead(ASYNC, 0, 4) // EOF
8107 };
8108
Ryan Sleevib8d7ea02018-05-07 20:01:018109 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:108110 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
bncc9f762a2016-12-06 20:38:238111 helper.RunToCompletion(&data);
8112 TransactionHelperResult out = helper.output();
8113 EXPECT_THAT(out.rv, IsOk());
8114 EXPECT_EQ("HTTP/1.1 200", out.status_line);
8115 EXPECT_EQ("hello!", out.response_data);
8116}
8117
bnc1ff80872016-12-16 20:57:578118// "A server can send a complete response prior to the client sending an entire
8119// request if the response does not depend on any portion of the request that
8120// has not been sent and received." (RFC7540 Section 8.1)
8121// Regression test for https://crbug.com/606990. Server responds before POST
8122// data are sent and closes connection: this must result in
Bence Békyd0d69502019-06-25 19:47:188123// ERR_CONNECTION_CLOSED (as opposed to ERR_HTTP2_PROTOCOL_ERROR).
bnc1ff80872016-12-16 20:57:578124TEST_F(SpdyNetworkTransactionTest, ResponseBeforePostDataSent) {
Ryan Hamilton0239aac2018-05-19 00:03:138125 spdy::SpdySerializedFrame req(
8126 spdy_util_.ConstructChunkedSpdyPost(nullptr, 0));
bnc1ff80872016-12-16 20:57:578127 MockWrite writes[] = {CreateMockWrite(req, 0)};
8128
Ryan Hamilton0239aac2018-05-19 00:03:138129 spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
8130 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
bnc1ff80872016-12-16 20:57:578131 MockRead reads[] = {CreateMockRead(resp, 1), CreateMockRead(body, 2),
8132 MockRead(ASYNC, 0, 3)};
8133
Ryan Sleevib8d7ea02018-05-07 20:01:018134 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:108135 UseChunkedPostRequest();
8136 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
bnc1ff80872016-12-16 20:57:578137
8138 helper.RunPreTestSetup();
8139 helper.AddData(&data);
8140 helper.StartDefaultTest();
8141 EXPECT_THAT(helper.output().rv, IsError(ERR_IO_PENDING));
8142 helper.WaitForCallbackToComplete();
8143 EXPECT_THAT(helper.output().rv, IsError(ERR_CONNECTION_CLOSED));
8144}
8145
8146// Regression test for https://crbug.com/606990.
8147// Server responds before POST data are sent and resets stream with NO_ERROR.
8148TEST_F(SpdyNetworkTransactionTest, ResponseAndRstStreamBeforePostDataSent) {
Ryan Hamilton0239aac2018-05-19 00:03:138149 spdy::SpdySerializedFrame req(
8150 spdy_util_.ConstructChunkedSpdyPost(nullptr, 0));
bnc1ff80872016-12-16 20:57:578151 MockWrite writes[] = {CreateMockWrite(req, 0)};
8152
Ryan Hamilton0239aac2018-05-19 00:03:138153 spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
8154 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
8155 spdy::SpdySerializedFrame rst(
8156 spdy_util_.ConstructSpdyRstStream(1, spdy::ERROR_CODE_NO_ERROR));
bnc1ff80872016-12-16 20:57:578157 MockRead reads[] = {CreateMockRead(resp, 1), CreateMockRead(body, 2),
8158 CreateMockRead(rst, 3), MockRead(ASYNC, 0, 4)};
8159
Ryan Sleevib8d7ea02018-05-07 20:01:018160 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:108161 UseChunkedPostRequest();
8162 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
bnc1ff80872016-12-16 20:57:578163
8164 helper.RunToCompletion(&data);
8165
8166 TransactionHelperResult out = helper.output();
8167 EXPECT_THAT(out.rv, IsOk());
8168 EXPECT_EQ("HTTP/1.1 200", out.status_line);
8169 EXPECT_EQ("hello!", out.response_data);
8170}
8171
bnc96487ec2017-03-29 19:40:238172// Unsupported frames must be ignored. This is especially important for frame
8173// type 0xb, which used to be the BLOCKED frame in previous versions of SPDY,
8174// but is going to be used for the ORIGIN frame.
8175// TODO(bnc): Implement ORIGIN frame support. https://crbug.com/697333
8176TEST_F(SpdyNetworkTransactionTest, IgnoreUnsupportedOriginFrame) {
Ryan Hamilton0239aac2018-05-19 00:03:138177 spdy::SpdySerializedFrame req(
8178 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
bnc96487ec2017-03-29 19:40:238179 MockWrite writes[] = {CreateMockWrite(req, 0)};
8180
8181 const char origin_frame_on_stream_zero[] = {
8182 0x00, 0x00, 0x05, // Length
8183 0x0b, // Type
8184 0x00, // Flags
8185 0x00, 0x00, 0x00, 0x00, // Stream ID
8186 0x00, 0x03, // Origin-Len
8187 'f', 'o', 'o' // ASCII-Origin
8188 };
8189
8190 const char origin_frame_on_stream_one[] = {
8191 0x00, 0x00, 0x05, // Length
8192 0x0b, // Type
8193 0x00, // Flags
8194 0x00, 0x00, 0x00, 0x01, // Stream ID
8195 0x00, 0x03, // Origin-Len
8196 'b', 'a', 'r' // ASCII-Origin
8197 };
8198
Ryan Hamilton0239aac2018-05-19 00:03:138199 spdy::SpdySerializedFrame resp(
8200 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
8201 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
bnc96487ec2017-03-29 19:40:238202 MockRead reads[] = {MockRead(ASYNC, origin_frame_on_stream_zero,
Avi Drissman4365a4782018-12-28 19:26:248203 base::size(origin_frame_on_stream_zero), 1),
bnc96487ec2017-03-29 19:40:238204 CreateMockRead(resp, 2),
8205 MockRead(ASYNC, origin_frame_on_stream_one,
Avi Drissman4365a4782018-12-28 19:26:248206 base::size(origin_frame_on_stream_one), 3),
bnc96487ec2017-03-29 19:40:238207 CreateMockRead(body, 4), MockRead(ASYNC, 0, 5)};
8208
Ryan Sleevib8d7ea02018-05-07 20:01:018209 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:108210 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
bnc96487ec2017-03-29 19:40:238211 helper.RunToCompletion(&data);
8212 TransactionHelperResult out = helper.output();
8213 EXPECT_THAT(out.rv, IsOk());
8214 EXPECT_EQ("HTTP/1.1 200", out.status_line);
8215 EXPECT_EQ("hello!", out.response_data);
8216}
8217
[email protected]514aeaf2014-05-23 10:31:518218class SpdyNetworkTransactionTLSUsageCheckTest
8219 : public SpdyNetworkTransactionTest {
8220 protected:
danakjaee3e1ec2016-04-16 00:23:188221 void RunTLSUsageCheckTest(
8222 std::unique_ptr<SSLSocketDataProvider> ssl_provider) {
Ryan Hamilton0239aac2018-05-19 00:03:138223 spdy::SpdySerializedFrame goaway(spdy_util_.ConstructSpdyGoAway(
8224 0, spdy::ERROR_CODE_INADEQUATE_SECURITY, ""));
bncdf80d44fd2016-07-15 20:27:418225 MockWrite writes[] = {CreateMockWrite(goaway)};
[email protected]514aeaf2014-05-23 10:31:518226
Ryan Sleevib8d7ea02018-05-07 20:01:018227 StaticSocketDataProvider data(base::span<MockRead>(), writes);
Bence Békydb3cf652017-10-10 15:22:108228 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
Bence Békyd3dde832017-09-19 19:02:318229 nullptr);
dchengc7eeda422015-12-26 03:56:488230 helper.RunToCompletionWithSSLData(&data, std::move(ssl_provider));
[email protected]514aeaf2014-05-23 10:31:518231 TransactionHelperResult out = helper.output();
Bence Békyd0d69502019-06-25 19:47:188232 EXPECT_THAT(out.rv, IsError(ERR_HTTP2_INADEQUATE_TRANSPORT_SECURITY));
[email protected]514aeaf2014-05-23 10:31:518233 }
8234};
8235
bncd16676a2016-07-20 16:23:018236TEST_F(SpdyNetworkTransactionTLSUsageCheckTest, TLSVersionTooOld) {
Jeremy Roman0579ed62017-08-29 15:56:198237 auto ssl_provider = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
[email protected]514aeaf2014-05-23 10:31:518238 SSLConnectionStatusSetVersion(SSL_CONNECTION_VERSION_SSL3,
Ryan Sleevi4f832092017-11-21 23:25:498239 &ssl_provider->ssl_info.connection_status);
[email protected]514aeaf2014-05-23 10:31:518240
dchengc7eeda422015-12-26 03:56:488241 RunTLSUsageCheckTest(std::move(ssl_provider));
[email protected]514aeaf2014-05-23 10:31:518242}
8243
bncd16676a2016-07-20 16:23:018244TEST_F(SpdyNetworkTransactionTLSUsageCheckTest, TLSCipherSuiteSucky) {
Jeremy Roman0579ed62017-08-29 15:56:198245 auto ssl_provider = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
[email protected]514aeaf2014-05-23 10:31:518246 // Set to TLS_RSA_WITH_NULL_MD5
Ryan Sleevi4f832092017-11-21 23:25:498247 SSLConnectionStatusSetCipherSuite(0x1,
8248 &ssl_provider->ssl_info.connection_status);
[email protected]514aeaf2014-05-23 10:31:518249
dchengc7eeda422015-12-26 03:56:488250 RunTLSUsageCheckTest(std::move(ssl_provider));
[email protected]514aeaf2014-05-23 10:31:518251}
8252
Bence Béky306378f2017-06-30 12:09:568253// Regression test for https://crbug.com/737143.
8254// This test sets up an old TLS version just like in TLSVersionTooOld,
Ryan Hamilton0239aac2018-05-19 00:03:138255// and makes sure that it results in an spdy::ERROR_CODE_INADEQUATE_SECURITY
Bence Béky306378f2017-06-30 12:09:568256// even for a non-secure request URL.
8257TEST_F(SpdyNetworkTransactionTest, InsecureUrlCreatesSecureSpdySession) {
Jeremy Roman0579ed62017-08-29 15:56:198258 auto ssl_provider = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
Bence Béky306378f2017-06-30 12:09:568259 SSLConnectionStatusSetVersion(SSL_CONNECTION_VERSION_SSL3,
Ryan Sleevi4f832092017-11-21 23:25:498260 &ssl_provider->ssl_info.connection_status);
Bence Béky306378f2017-06-30 12:09:568261
Ryan Hamilton0239aac2018-05-19 00:03:138262 spdy::SpdySerializedFrame goaway(spdy_util_.ConstructSpdyGoAway(
8263 0, spdy::ERROR_CODE_INADEQUATE_SECURITY, ""));
Bence Béky306378f2017-06-30 12:09:568264 MockWrite writes[] = {CreateMockWrite(goaway)};
Ryan Sleevib8d7ea02018-05-07 20:01:018265 StaticSocketDataProvider data(base::span<MockRead>(), writes);
Bence Béky306378f2017-06-30 12:09:568266
Bence Békydb3cf652017-10-10 15:22:108267 request_.url = GURL("http://www.example.org/");
Bence Béky306378f2017-06-30 12:09:568268
8269 // Need secure proxy so that insecure URL can use HTTP/2.
Jeremy Roman0579ed62017-08-29 15:56:198270 auto session_deps = std::make_unique<SpdySessionDependencies>(
Nicolas Arciniegad2013f92020-02-07 23:00:568271 ConfiguredProxyResolutionService::CreateFixedFromPacResult(
Ramin Halavatica8d5252018-03-12 05:33:498272 "HTTPS myproxy:70", TRAFFIC_ANNOTATION_FOR_TESTS));
Bence Békydb3cf652017-10-10 15:22:108273 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
Bence Békyd3dde832017-09-19 19:02:318274 std::move(session_deps));
Bence Béky306378f2017-06-30 12:09:568275
8276 helper.RunToCompletionWithSSLData(&data, std::move(ssl_provider));
8277 TransactionHelperResult out = helper.output();
Bence Békyd0d69502019-06-25 19:47:188278 EXPECT_THAT(out.rv, IsError(ERR_HTTP2_INADEQUATE_TRANSPORT_SECURITY));
Bence Békydb3cf652017-10-10 15:22:108279}
Bence Béky306378f2017-06-30 12:09:568280
Andrey Kosyakov83a6eee2017-08-14 19:20:048281TEST_F(SpdyNetworkTransactionTest, RequestHeadersCallback) {
Ryan Hamilton0239aac2018-05-19 00:03:138282 spdy::SpdySerializedFrame req(
Bence Béky27ad0a12018-02-08 00:35:488283 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, DEFAULT_PRIORITY));
Andrey Kosyakov83a6eee2017-08-14 19:20:048284 MockWrite writes[] = {CreateMockWrite(req, 0)};
8285
Ryan Hamilton0239aac2018-05-19 00:03:138286 spdy::SpdySerializedFrame resp(
8287 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
8288 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
Andrey Kosyakov83a6eee2017-08-14 19:20:048289 MockRead reads[] = {
8290 CreateMockRead(resp, 1), CreateMockRead(body, 2),
8291 MockRead(ASYNC, 0, 3) // EOF
8292 };
8293
8294 HttpRawRequestHeaders raw_headers;
8295
Ryan Sleevib8d7ea02018-05-07 20:01:018296 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:108297 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
Andrey Kosyakov83a6eee2017-08-14 19:20:048298 helper.RunPreTestSetup();
8299 helper.AddData(&data);
8300 helper.trans()->SetRequestHeadersCallback(base::Bind(
8301 &HttpRawRequestHeaders::Assign, base::Unretained(&raw_headers)));
8302 helper.StartDefaultTest();
8303 helper.FinishDefaultTestWithoutVerification();
8304 EXPECT_FALSE(raw_headers.headers().empty());
8305 std::string value;
8306 EXPECT_TRUE(raw_headers.FindHeaderForTest(":path", &value));
8307 EXPECT_EQ("/", value);
8308 EXPECT_TRUE(raw_headers.FindHeaderForTest(":method", &value));
8309 EXPECT_EQ("GET", value);
8310 EXPECT_TRUE(raw_headers.request_line().empty());
8311}
8312
Yoav Weiss9693572f2018-01-04 09:37:348313// A request that has adopted a push promise and later got reset by the server
8314// should be retried on a new stream.
8315// Regression test for https://crbug.com/798508.
8316TEST_F(SpdyNetworkTransactionTest, PushCanceledByServerAfterClaimed) {
8317 const char pushed_url[] = "https://www.example.org/a.dat";
8318 // Construct a request to the default URL on stream 1.
Ryan Hamilton0239aac2018-05-19 00:03:138319 spdy::SpdySerializedFrame req(
8320 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
8321 spdy::SpdySerializedFrame req2(
8322 spdy_util_.ConstructSpdyGet(pushed_url, 3, LOWEST));
Yoav Weiss9693572f2018-01-04 09:37:348323 // Construct a priority frame for stream 2.
Ryan Hamilton0239aac2018-05-19 00:03:138324 spdy::SpdySerializedFrame priority(
Yoav Weiss9693572f2018-01-04 09:37:348325 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true));
8326 MockWrite writes[] = {CreateMockWrite(req, 0), CreateMockWrite(priority, 3),
8327 CreateMockWrite(req2, 6)};
8328
8329 // Construct a Push Promise frame, with no response.
Ryan Hamilton0239aac2018-05-19 00:03:138330 spdy::SpdySerializedFrame push_promise(spdy_util_.ConstructSpdyPushPromise(
Bence Békyf1d78522018-01-11 01:16:508331 1, 2, spdy_util_.ConstructGetHeaderBlock(pushed_url)));
Yoav Weiss9693572f2018-01-04 09:37:348332 // Construct a RST frame, canceling stream 2.
Ryan Hamilton0239aac2018-05-19 00:03:138333 spdy::SpdySerializedFrame rst_server(
8334 spdy_util_.ConstructSpdyRstStream(2, spdy::ERROR_CODE_CANCEL));
Yoav Weiss9693572f2018-01-04 09:37:348335 // Construct response headers and bodies.
Ryan Hamilton0239aac2018-05-19 00:03:138336 spdy::SpdySerializedFrame resp1(
8337 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
8338 spdy::SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true));
8339 spdy::SpdySerializedFrame resp2(
8340 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
8341 spdy::SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(3, true));
Yoav Weiss9693572f2018-01-04 09:37:348342 MockRead reads[] = {
8343 CreateMockRead(push_promise, 1), MockRead(ASYNC, ERR_IO_PENDING, 2),
8344 CreateMockRead(rst_server, 4), MockRead(ASYNC, ERR_IO_PENDING, 5),
8345 CreateMockRead(resp1, 7), CreateMockRead(body1, 8),
8346 CreateMockRead(resp2, 9), CreateMockRead(body2, 10),
8347 MockRead(ASYNC, 0, 11)};
8348
Ryan Sleevib8d7ea02018-05-07 20:01:018349 SequencedSocketData data(reads, writes);
Yoav Weiss9693572f2018-01-04 09:37:348350
8351 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
8352
8353 helper.RunPreTestSetup();
8354 helper.AddData(&data);
8355
8356 HttpNetworkTransaction* trans = helper.trans();
8357
8358 // First request to start the connection.
8359 TestCompletionCallback callback1;
8360 int rv = trans->Start(&request_, callback1.callback(), log_);
8361 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
8362
8363 data.RunUntilPaused();
8364
8365 // Get a SpdySession.
8366 SpdySessionKey key(HostPortPair::FromURL(request_.url), ProxyServer::Direct(),
Matt Menke2436b2f2018-12-11 18:07:118367 PRIVACY_MODE_DISABLED,
dalyk51ab46b2019-10-15 15:14:348368 SpdySessionKey::IsProxySession::kFalse, SocketTag(),
8369 NetworkIsolationKey(), false /* disable_secure_dns */);
Yoav Weiss9693572f2018-01-04 09:37:348370 HttpNetworkSession* session = helper.session();
8371 base::WeakPtr<SpdySession> spdy_session =
8372 session->spdy_session_pool()->FindAvailableSession(
Bence Békyd885b2b2018-02-03 00:58:318373 key, /* enable_ip_based_pooling = */ true,
8374 /* is_websocket = */ false, log_);
Yoav Weiss9693572f2018-01-04 09:37:348375
8376 // Verify that there is one unclaimed push stream.
8377 EXPECT_EQ(1u, num_unclaimed_pushed_streams(spdy_session));
8378
8379 // Claim the pushed stream.
8380 HttpNetworkTransaction transaction2(DEFAULT_PRIORITY, session);
8381 TestCompletionCallback callback2;
8382 HttpRequestInfo request2;
8383 request2.method = "GET";
8384 request2.url = GURL(pushed_url);
Ramin Halavatib5e433e62018-02-07 07:41:108385 request2.traffic_annotation =
8386 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
Yoav Weiss9693572f2018-01-04 09:37:348387 transaction2.Start(&request2, callback2.callback(), log_);
8388 base::RunLoop().RunUntilIdle();
8389 EXPECT_EQ(3u, spdy_stream_hi_water_mark(spdy_session));
8390
8391 EXPECT_EQ(0u, num_unclaimed_pushed_streams(spdy_session));
8392
8393 // Continue reading and get the RST.
8394 data.Resume();
8395 base::RunLoop().RunUntilIdle();
8396
8397 // Make sure we got the RST and retried the request.
8398 EXPECT_EQ(2u, num_active_streams(spdy_session));
8399 EXPECT_EQ(0u, num_unclaimed_pushed_streams(spdy_session));
8400 EXPECT_EQ(5u, spdy_stream_hi_water_mark(spdy_session));
8401
8402 data.Resume();
8403
8404 // Test that transactions succeeded.
8405 rv = callback1.WaitForResult();
8406 ASSERT_THAT(rv, IsOk());
8407
8408 rv = callback2.WaitForResult();
8409 ASSERT_THAT(rv, IsOk());
8410
8411 // Read EOF.
8412 base::RunLoop().RunUntilIdle();
8413
8414 // Verify that all data was read and written.
8415 helper.VerifyDataConsumed();
8416}
8417
Bence Béky0ca719f2018-01-31 13:41:198418#if BUILDFLAG(ENABLE_WEBSOCKETS)
Bence Béky8bfacd42018-02-23 13:05:138419
8420TEST_F(SpdyNetworkTransactionTest, WebSocketOpensNewConnection) {
Bence Békyb09dddf12018-07-31 18:52:048421 base::HistogramTester histogram_tester;
Bence Béky0ca719f2018-01-31 13:41:198422 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
8423 helper.RunPreTestSetup();
8424
8425 // First request opens up an HTTP/2 connection.
Ryan Hamilton0239aac2018-05-19 00:03:138426 spdy::SpdySerializedFrame req(
Bence Béky8bfacd42018-02-23 13:05:138427 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, DEFAULT_PRIORITY));
Bence Béky0ca719f2018-01-31 13:41:198428 MockWrite writes1[] = {CreateMockWrite(req, 0)};
8429
Ryan Hamilton0239aac2018-05-19 00:03:138430 spdy::SpdySerializedFrame resp(
8431 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
8432 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
Bence Béky0ca719f2018-01-31 13:41:198433 MockRead reads1[] = {CreateMockRead(resp, 1), CreateMockRead(body, 2),
8434 MockRead(ASYNC, ERR_IO_PENDING, 3),
8435 MockRead(ASYNC, 0, 4)};
8436
Ryan Sleevib8d7ea02018-05-07 20:01:018437 SequencedSocketData data1(reads1, writes1);
Bence Béky0ca719f2018-01-31 13:41:198438 helper.AddData(&data1);
8439
Bence Béky8bfacd42018-02-23 13:05:138440 // WebSocket request opens a new connection with HTTP/2 disabled.
Bence Béky0ca719f2018-01-31 13:41:198441 MockWrite writes2[] = {
8442 MockWrite("GET / HTTP/1.1\r\n"
8443 "Host: www.example.org\r\n"
8444 "Connection: Upgrade\r\n"
8445 "Upgrade: websocket\r\n"
8446 "Origin: http://www.example.org\r\n"
8447 "Sec-WebSocket-Version: 13\r\n"
Bence Béky8d1c6052018-02-07 12:48:158448 "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
8449 "Sec-WebSocket-Extensions: permessage-deflate; "
8450 "client_max_window_bits\r\n\r\n")};
Bence Béky0ca719f2018-01-31 13:41:198451
Bence Béky8d1c6052018-02-07 12:48:158452 MockRead reads2[] = {
8453 MockRead("HTTP/1.1 101 Switching Protocols\r\n"
8454 "Upgrade: websocket\r\n"
8455 "Connection: Upgrade\r\n"
8456 "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n\r\n")};
8457
Ryan Sleevib8d7ea02018-05-07 20:01:018458 StaticSocketDataProvider data2(reads2, writes2);
Bence Béky0ca719f2018-01-31 13:41:198459
8460 auto ssl_provider2 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
8461 // Test that request has empty |alpn_protos|, that is, HTTP/2 is disabled.
8462 ssl_provider2->next_protos_expected_in_ssl_config = NextProtoVector{};
8463 // Force socket to use HTTP/1.1, the default protocol without ALPN.
8464 ssl_provider2->next_proto = kProtoHTTP11;
8465 ssl_provider2->ssl_info.cert =
8466 ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem");
8467 helper.AddDataWithSSLSocketDataProvider(&data2, std::move(ssl_provider2));
8468
8469 TestCompletionCallback callback1;
8470 HttpNetworkTransaction trans1(DEFAULT_PRIORITY, helper.session());
8471 int rv = trans1.Start(&request_, callback1.callback(), log_);
8472 ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
8473 rv = callback1.WaitForResult();
8474 ASSERT_THAT(rv, IsOk());
8475
8476 const HttpResponseInfo* response = trans1.GetResponseInfo();
8477 ASSERT_TRUE(response->headers);
8478 EXPECT_TRUE(response->was_fetched_via_spdy);
8479 EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
8480
8481 std::string response_data;
8482 rv = ReadTransaction(&trans1, &response_data);
8483 EXPECT_THAT(rv, IsOk());
8484 EXPECT_EQ("hello!", response_data);
8485
8486 SpdySessionKey key(HostPortPair::FromURL(request_.url), ProxyServer::Direct(),
Matt Menke2436b2f2018-12-11 18:07:118487 PRIVACY_MODE_DISABLED,
dalyk51ab46b2019-10-15 15:14:348488 SpdySessionKey::IsProxySession::kFalse, SocketTag(),
8489 NetworkIsolationKey(), false /* disable_secure_dns */);
Bence Béky0ca719f2018-01-31 13:41:198490 base::WeakPtr<SpdySession> spdy_session =
8491 helper.session()->spdy_session_pool()->FindAvailableSession(
Bence Békyd885b2b2018-02-03 00:58:318492 key, /* enable_ip_based_pooling = */ true,
8493 /* is_websocket = */ false, log_);
Bence Béky0ca719f2018-01-31 13:41:198494 ASSERT_TRUE(spdy_session);
Bence Békyd885b2b2018-02-03 00:58:318495 EXPECT_FALSE(spdy_session->support_websocket());
Bence Béky0ca719f2018-01-31 13:41:198496
8497 HttpRequestInfo request2;
8498 request2.method = "GET";
8499 request2.url = GURL("wss://www.example.org/");
Ramin Halavatib5e433e62018-02-07 07:41:108500 request2.traffic_annotation =
8501 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
Bence Béky0ca719f2018-01-31 13:41:198502 EXPECT_TRUE(HostPortPair::FromURL(request_.url)
8503 .Equals(HostPortPair::FromURL(request2.url)));
8504 request2.extra_headers.SetHeader("Connection", "Upgrade");
8505 request2.extra_headers.SetHeader("Upgrade", "websocket");
8506 request2.extra_headers.SetHeader("Origin", "http://www.example.org");
8507 request2.extra_headers.SetHeader("Sec-WebSocket-Version", "13");
Bence Béky8d1c6052018-02-07 12:48:158508
8509 TestWebSocketHandshakeStreamCreateHelper websocket_stream_create_helper;
Bence Béky0ca719f2018-01-31 13:41:198510
8511 HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session());
Bence Béky0ca719f2018-01-31 13:41:198512 trans2.SetWebSocketHandshakeStreamCreateHelper(
8513 &websocket_stream_create_helper);
8514
8515 TestCompletionCallback callback2;
8516 rv = trans2.Start(&request2, callback2.callback(), log_);
8517 ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
8518 rv = callback2.WaitForResult();
8519 ASSERT_THAT(rv, IsOk());
8520
Bence Béky8bfacd42018-02-23 13:05:138521 // HTTP/2 connection is still open, but WebSocket request did not pool to it.
Bence Béky0ca719f2018-01-31 13:41:198522 ASSERT_TRUE(spdy_session);
8523
Bence Béky0ca719f2018-01-31 13:41:198524 data1.Resume();
Bence Békyb09dddf12018-07-31 18:52:048525 base::RunLoop().RunUntilIdle();
Bence Béky0ca719f2018-01-31 13:41:198526 helper.VerifyDataConsumed();
Bence Békyb09dddf12018-07-31 18:52:048527
8528 // Server did not advertise WebSocket support.
8529 histogram_tester.ExpectUniqueSample("Net.SpdySession.ServerSupportsWebSocket",
8530 /* support_websocket = false */ 0,
8531 /* expected_count = */ 1);
Bence Béky0ca719f2018-01-31 13:41:198532}
Bence Béky8bfacd42018-02-23 13:05:138533
Matt Menke77173952019-04-18 17:42:148534// Make sure that a WebSocket job doesn't pick up a newly created SpdySession
8535// that doesn't support WebSockets through
8536// HttpStreamFactory::Job::OnSpdySessionAvailable().
8537TEST_F(SpdyNetworkTransactionTest,
8538 WebSocketDoesUseNewH2SessionWithoutWebSocketSupport) {
8539 base::HistogramTester histogram_tester;
8540 auto session_deps = std::make_unique<SpdySessionDependencies>();
8541 session_deps->enable_websocket_over_http2 = true;
8542 NormalSpdyTransactionHelper helper(request_, HIGHEST, log_,
8543 std::move(session_deps));
8544 helper.RunPreTestSetup();
8545
8546 spdy::SpdySerializedFrame req(
8547 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, HIGHEST));
8548
8549 MockWrite writes[] = {CreateMockWrite(req, 0)};
8550
8551 spdy::SpdySerializedFrame resp1(
8552 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
8553 spdy::SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true));
8554 MockRead reads[] = {CreateMockRead(resp1, 1), CreateMockRead(body1, 2),
8555 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 3)};
8556
8557 SequencedSocketData data(
8558 // Just as with other operations, this means to pause during connection
8559 // establishment.
8560 MockConnect(ASYNC, ERR_IO_PENDING), reads, writes);
8561 helper.AddData(&data);
8562
8563 MockWrite writes2[] = {
8564 MockWrite(SYNCHRONOUS, 0,
8565 "GET / HTTP/1.1\r\n"
8566 "Host: www.example.org\r\n"
8567 "Connection: Upgrade\r\n"
8568 "Upgrade: websocket\r\n"
8569 "Origin: http://www.example.org\r\n"
8570 "Sec-WebSocket-Version: 13\r\n"
8571 "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
8572 "Sec-WebSocket-Extensions: permessage-deflate; "
8573 "client_max_window_bits\r\n\r\n")};
8574
8575 MockRead reads2[] = {
8576 MockRead(SYNCHRONOUS, 1,
8577 "HTTP/1.1 101 Switching Protocols\r\n"
8578 "Upgrade: websocket\r\n"
8579 "Connection: Upgrade\r\n"
8580 "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n\r\n")};
8581 SequencedSocketData data2(MockConnect(ASYNC, ERR_IO_PENDING), reads2,
8582 writes2);
8583 auto ssl_provider2 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
8584 // Test that request has empty |alpn_protos|, that is, HTTP/2 is disabled.
8585 ssl_provider2->next_protos_expected_in_ssl_config = NextProtoVector{};
8586 // Force socket to use HTTP/1.1, the default protocol without ALPN.
8587 ssl_provider2->next_proto = kProtoHTTP11;
Matt Menke77173952019-04-18 17:42:148588 helper.AddDataWithSSLSocketDataProvider(&data2, std::move(ssl_provider2));
8589
8590 TestCompletionCallback callback1;
8591 int rv = helper.trans()->Start(&request_, callback1.callback(), log_);
8592 ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
8593
8594 // Create HTTP/2 connection.
8595 base::RunLoop().RunUntilIdle();
8596
8597 HttpRequestInfo request2;
8598 request2.method = "GET";
8599 request2.url = GURL("wss://www.example.org/");
8600 request2.traffic_annotation =
8601 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
8602 EXPECT_TRUE(HostPortPair::FromURL(request_.url)
8603 .Equals(HostPortPair::FromURL(request2.url)));
8604 request2.extra_headers.SetHeader("Connection", "Upgrade");
8605 request2.extra_headers.SetHeader("Upgrade", "websocket");
8606 request2.extra_headers.SetHeader("Origin", "http://www.example.org");
8607 request2.extra_headers.SetHeader("Sec-WebSocket-Version", "13");
8608
8609 TestWebSocketHandshakeStreamCreateHelper websocket_stream_create_helper;
8610
8611 HttpNetworkTransaction trans2(MEDIUM, helper.session());
8612 trans2.SetWebSocketHandshakeStreamCreateHelper(
8613 &websocket_stream_create_helper);
8614
8615 TestCompletionCallback callback2;
8616 rv = trans2.Start(&request2, callback2.callback(), log_);
8617 ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
8618
8619 // Run until waiting on both connections.
8620 base::RunLoop().RunUntilIdle();
8621
8622 // The H2 connection completes.
8623 data.socket()->OnConnectComplete(MockConnect(SYNCHRONOUS, OK));
8624 EXPECT_EQ(OK, callback1.WaitForResult());
8625 const HttpResponseInfo* response = helper.trans()->GetResponseInfo();
8626 ASSERT_TRUE(response->headers);
8627 EXPECT_TRUE(response->was_fetched_via_spdy);
8628 EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
8629 std::string response_data;
8630 rv = ReadTransaction(helper.trans(), &response_data);
8631 EXPECT_THAT(rv, IsOk());
8632 EXPECT_EQ("hello!", response_data);
8633
8634 SpdySessionKey key(HostPortPair::FromURL(request_.url), ProxyServer::Direct(),
8635 PRIVACY_MODE_DISABLED,
dalyk51ab46b2019-10-15 15:14:348636 SpdySessionKey::IsProxySession::kFalse, SocketTag(),
8637 NetworkIsolationKey(), false /* disable_secure_dns */);
Matt Menke77173952019-04-18 17:42:148638
8639 base::WeakPtr<SpdySession> spdy_session =
8640 helper.session()->spdy_session_pool()->FindAvailableSession(
8641 key, /* enable_ip_based_pooling = */ true,
8642 /* is_websocket = */ false, log_);
8643 ASSERT_TRUE(spdy_session);
8644 EXPECT_FALSE(spdy_session->support_websocket());
8645
8646 EXPECT_FALSE(callback2.have_result());
8647
8648 // Create WebSocket stream.
8649 data2.socket()->OnConnectComplete(MockConnect(SYNCHRONOUS, OK));
8650
8651 rv = callback2.WaitForResult();
8652 ASSERT_THAT(rv, IsOk());
8653 helper.VerifyDataConsumed();
8654}
8655
Bence Béky8bfacd42018-02-23 13:05:138656TEST_F(SpdyNetworkTransactionTest, WebSocketOverHTTP2) {
Bence Békyb09dddf12018-07-31 18:52:048657 base::HistogramTester histogram_tester;
Bence Béky8bfacd42018-02-23 13:05:138658 auto session_deps = std::make_unique<SpdySessionDependencies>();
8659 session_deps->enable_websocket_over_http2 = true;
Bence Béky7a4836c2018-05-08 03:52:488660 NormalSpdyTransactionHelper helper(request_, HIGHEST, log_,
Bence Béky8bfacd42018-02-23 13:05:138661 std::move(session_deps));
8662 helper.RunPreTestSetup();
8663
Ryan Hamilton0239aac2018-05-19 00:03:138664 spdy::SpdySerializedFrame req(
8665 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, HIGHEST));
8666 spdy::SpdySerializedFrame settings_ack(spdy_util_.ConstructSpdySettingsAck());
Bence Béky8bfacd42018-02-23 13:05:138667
Ryan Hamilton0239aac2018-05-19 00:03:138668 spdy::SpdyHeaderBlock websocket_request_headers;
8669 websocket_request_headers[spdy::kHttp2MethodHeader] = "CONNECT";
8670 websocket_request_headers[spdy::kHttp2AuthorityHeader] = "www.example.org";
8671 websocket_request_headers[spdy::kHttp2SchemeHeader] = "https";
8672 websocket_request_headers[spdy::kHttp2PathHeader] = "/";
8673 websocket_request_headers[spdy::kHttp2ProtocolHeader] = "websocket";
Bence Béky8bfacd42018-02-23 13:05:138674 websocket_request_headers["origin"] = "http://www.example.org";
8675 websocket_request_headers["sec-websocket-version"] = "13";
8676 websocket_request_headers["sec-websocket-extensions"] =
8677 "permessage-deflate; client_max_window_bits";
Ryan Hamilton0239aac2018-05-19 00:03:138678 spdy::SpdySerializedFrame websocket_request(spdy_util_.ConstructSpdyHeaders(
Bence Béky7a4836c2018-05-08 03:52:488679 3, std::move(websocket_request_headers), MEDIUM, false));
8680
Bence Béky73b85292018-06-14 04:56:438681 spdy::SpdySerializedFrame priority1(
8682 spdy_util_.ConstructSpdyPriority(3, 0, MEDIUM, true));
8683 spdy::SpdySerializedFrame priority2(
8684 spdy_util_.ConstructSpdyPriority(1, 3, LOWEST, true));
8685
8686 MockWrite writes[] = {
8687 CreateMockWrite(req, 0), CreateMockWrite(settings_ack, 2),
8688 CreateMockWrite(websocket_request, 4), CreateMockWrite(priority1, 5),
8689 CreateMockWrite(priority2, 6)};
Bence Béky8bfacd42018-02-23 13:05:138690
Ryan Hamilton0239aac2018-05-19 00:03:138691 spdy::SettingsMap settings;
8692 settings[spdy::SETTINGS_ENABLE_CONNECT_PROTOCOL] = 1;
8693 spdy::SpdySerializedFrame settings_frame(
Bence Béky8bfacd42018-02-23 13:05:138694 spdy_util_.ConstructSpdySettings(settings));
Ryan Hamilton0239aac2018-05-19 00:03:138695 spdy::SpdySerializedFrame resp1(
8696 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
8697 spdy::SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true));
8698 spdy::SpdySerializedFrame websocket_response(
Bence Béky8bfacd42018-02-23 13:05:138699 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
Bence Béky73b85292018-06-14 04:56:438700 MockRead reads[] = {CreateMockRead(settings_frame, 1),
8701 CreateMockRead(resp1, 3), CreateMockRead(body1, 7),
8702 CreateMockRead(websocket_response, 8),
8703 MockRead(ASYNC, 0, 9)};
Bence Béky8bfacd42018-02-23 13:05:138704
Ryan Sleevib8d7ea02018-05-07 20:01:018705 SequencedSocketData data(reads, writes);
Bence Béky8bfacd42018-02-23 13:05:138706 helper.AddData(&data);
8707
8708 TestCompletionCallback callback1;
Bence Béky7a4836c2018-05-08 03:52:488709 int rv = helper.trans()->Start(&request_, callback1.callback(), log_);
Bence Béky8bfacd42018-02-23 13:05:138710 ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
Bence Béky8bfacd42018-02-23 13:05:138711
Bence Béky7a4836c2018-05-08 03:52:488712 // Create HTTP/2 connection.
8713 base::RunLoop().RunUntilIdle();
Bence Béky8bfacd42018-02-23 13:05:138714
8715 SpdySessionKey key(HostPortPair::FromURL(request_.url), ProxyServer::Direct(),
Matt Menke2436b2f2018-12-11 18:07:118716 PRIVACY_MODE_DISABLED,
dalyk51ab46b2019-10-15 15:14:348717 SpdySessionKey::IsProxySession::kFalse, SocketTag(),
8718 NetworkIsolationKey(), false /* disable_secure_dns */);
Bence Béky8bfacd42018-02-23 13:05:138719 base::WeakPtr<SpdySession> spdy_session =
8720 helper.session()->spdy_session_pool()->FindAvailableSession(
8721 key, /* enable_ip_based_pooling = */ true,
8722 /* is_websocket = */ true, log_);
8723 ASSERT_TRUE(spdy_session);
8724 EXPECT_TRUE(spdy_session->support_websocket());
8725
8726 HttpRequestInfo request2;
8727 request2.method = "GET";
8728 request2.url = GURL("wss://www.example.org/");
8729 request2.traffic_annotation =
8730 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
8731 EXPECT_TRUE(HostPortPair::FromURL(request_.url)
8732 .Equals(HostPortPair::FromURL(request2.url)));
8733 request2.extra_headers.SetHeader("Origin", "http://www.example.org");
8734 request2.extra_headers.SetHeader("Sec-WebSocket-Version", "13");
8735 // The following two headers must be removed by WebSocketHttp2HandshakeStream.
8736 request2.extra_headers.SetHeader("Connection", "Upgrade");
8737 request2.extra_headers.SetHeader("Upgrade", "websocket");
8738
8739 TestWebSocketHandshakeStreamCreateHelper websocket_stream_create_helper;
8740
Bence Béky7a4836c2018-05-08 03:52:488741 HttpNetworkTransaction trans2(MEDIUM, helper.session());
Bence Béky8bfacd42018-02-23 13:05:138742 trans2.SetWebSocketHandshakeStreamCreateHelper(
8743 &websocket_stream_create_helper);
8744
8745 TestCompletionCallback callback2;
8746 rv = trans2.Start(&request2, callback2.callback(), log_);
8747 ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
Bence Béky7a4836c2018-05-08 03:52:488748
8749 // Create WebSocket stream.
8750 base::RunLoop().RunUntilIdle();
Bence Béky73b85292018-06-14 04:56:438751 ASSERT_TRUE(spdy_session);
8752
8753 // First request has HIGHEST priority, WebSocket request has MEDIUM priority.
8754 // Changing the priority of the first request to LOWEST changes their order,
8755 // and therefore triggers sending PRIORITY frames.
8756 helper.trans()->SetPriority(LOWEST);
Bence Béky7a4836c2018-05-08 03:52:488757
8758 rv = callback1.WaitForResult();
8759 ASSERT_THAT(rv, IsOk());
8760
8761 const HttpResponseInfo* response = helper.trans()->GetResponseInfo();
8762 ASSERT_TRUE(response->headers);
8763 EXPECT_TRUE(response->was_fetched_via_spdy);
8764 EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
8765
8766 std::string response_data;
8767 rv = ReadTransaction(helper.trans(), &response_data);
8768 EXPECT_THAT(rv, IsOk());
8769 EXPECT_EQ("hello!", response_data);
8770
Bence Béky8bfacd42018-02-23 13:05:138771 rv = callback2.WaitForResult();
8772 ASSERT_THAT(rv, IsOk());
8773
Bence Béky8bfacd42018-02-23 13:05:138774 helper.VerifyDataConsumed();
Bence Békyb09dddf12018-07-31 18:52:048775
8776 // Server advertised WebSocket support.
8777 histogram_tester.ExpectUniqueSample("Net.SpdySession.ServerSupportsWebSocket",
8778 /* support_websocket = true */ 1,
8779 /* expected_count = */ 1);
Bence Béky8bfacd42018-02-23 13:05:138780}
8781
Matt Menke7269f352019-10-03 17:05:298782// Make sure that a WebSocket job doesn't pick up a newly created SpdySession
8783// that supports WebSockets through an HTTPS proxy when an H2 server doesn't
8784// support websockets and |enable_websocket_over_http2| is false. See
8785// https://crbug.com/1010491.
8786TEST_F(SpdyNetworkTransactionTest,
8787 WebSocketDoesNotUseNewH2SessionWithoutWebSocketSupportOverHttpsProxy) {
8788 auto session_deps = std::make_unique<SpdySessionDependencies>(
Nicolas Arciniegad2013f92020-02-07 23:00:568789 ConfiguredProxyResolutionService::CreateFixed(
8790 "https://proxy:70", TRAFFIC_ANNOTATION_FOR_TESTS));
Matt Menke7269f352019-10-03 17:05:298791
8792 // Note: Once WebSocket over H2 is enabled by default, this line can be
8793 // deleted, and this test will still be useful to keep, though its description
8794 // will need to be updated.
8795 session_deps->enable_websocket_over_http2 = false;
8796
8797 NormalSpdyTransactionHelper helper(request_, HIGHEST, log_,
8798 std::move(session_deps));
8799 helper.RunPreTestSetup();
8800
8801 spdy::SpdySerializedFrame req(
8802 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, HIGHEST));
8803
8804 MockWrite writes[] = {MockWrite(SYNCHRONOUS, 0,
8805 "CONNECT www.example.org:443 HTTP/1.1\r\n"
8806 "Host: www.example.org:443\r\n"
8807 "Proxy-Connection: keep-alive\r\n\r\n"),
8808 CreateMockWrite(req, 2)};
8809
8810 spdy::SpdySerializedFrame resp1(
8811 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
8812 spdy::SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true));
8813 MockRead reads[] = {MockRead(SYNCHRONOUS, 1, "HTTP/1.1 200 OK\r\n\r\n"),
8814 CreateMockRead(resp1, 3), CreateMockRead(body1, 4),
8815 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 5)};
8816
8817 // SSL data for the proxy.
8818 SSLSocketDataProvider tunnel_ssl_data(ASYNC, OK);
8819 helper.session_deps()->socket_factory->AddSSLSocketDataProvider(
8820 &tunnel_ssl_data);
8821
8822 SequencedSocketData data(
8823 // Just as with other operations, this means to pause during connection
8824 // establishment.
8825 MockConnect(ASYNC, ERR_IO_PENDING), reads, writes);
8826 helper.AddData(&data);
8827
8828 MockWrite writes2[] = {
8829 MockWrite(SYNCHRONOUS, 0,
8830 "CONNECT www.example.org:443 HTTP/1.1\r\n"
8831 "Host: www.example.org:443\r\n"
8832 "Proxy-Connection: keep-alive\r\n\r\n"),
8833 MockWrite(SYNCHRONOUS, 2,
8834 "GET / HTTP/1.1\r\n"
8835 "Host: www.example.org\r\n"
8836 "Connection: Upgrade\r\n"
8837 "Upgrade: websocket\r\n"
8838 "Origin: http://www.example.org\r\n"
8839 "Sec-WebSocket-Version: 13\r\n"
8840 "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
8841 "Sec-WebSocket-Extensions: permessage-deflate; "
8842 "client_max_window_bits\r\n\r\n")};
8843
8844 MockRead reads2[] = {
8845 MockRead(SYNCHRONOUS, 1, "HTTP/1.1 200 OK\r\n\r\n"),
8846 MockRead(SYNCHRONOUS, 3,
8847 "HTTP/1.1 101 Switching Protocols\r\n"
8848 "Upgrade: websocket\r\n"
8849 "Connection: Upgrade\r\n"
8850 "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n\r\n")};
8851 SequencedSocketData data2(MockConnect(ASYNC, ERR_IO_PENDING), reads2,
8852 writes2);
8853
8854 // SSL data for the proxy.
8855 SSLSocketDataProvider tunnel_ssl_data2(ASYNC, OK);
8856 helper.session_deps()->socket_factory->AddSSLSocketDataProvider(
8857 &tunnel_ssl_data2);
8858
8859 auto ssl_provider2 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
8860 // Test that request has empty |alpn_protos|, that is, HTTP/2 is disabled.
8861 ssl_provider2->next_protos_expected_in_ssl_config = NextProtoVector{};
8862 // Force socket to use HTTP/1.1, the default protocol without ALPN.
8863 ssl_provider2->next_proto = kProtoHTTP11;
8864 helper.AddDataWithSSLSocketDataProvider(&data2, std::move(ssl_provider2));
8865
8866 TestCompletionCallback callback1;
8867 int rv = helper.trans()->Start(&request_, callback1.callback(), log_);
8868 ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
8869
8870 // Create HTTP/2 connection.
8871 base::RunLoop().RunUntilIdle();
8872
8873 HttpRequestInfo request2;
8874 request2.method = "GET";
8875 request2.url = GURL("wss://www.example.org/");
8876 request2.traffic_annotation =
8877 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
8878 EXPECT_TRUE(HostPortPair::FromURL(request_.url)
8879 .Equals(HostPortPair::FromURL(request2.url)));
8880 request2.extra_headers.SetHeader("Connection", "Upgrade");
8881 request2.extra_headers.SetHeader("Upgrade", "websocket");
8882 request2.extra_headers.SetHeader("Origin", "http://www.example.org");
8883 request2.extra_headers.SetHeader("Sec-WebSocket-Version", "13");
8884
8885 TestWebSocketHandshakeStreamCreateHelper websocket_stream_create_helper;
8886
8887 HttpNetworkTransaction trans2(MEDIUM, helper.session());
8888 trans2.SetWebSocketHandshakeStreamCreateHelper(
8889 &websocket_stream_create_helper);
8890
8891 TestCompletionCallback callback2;
8892 rv = trans2.Start(&request2, callback2.callback(), log_);
8893 ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
8894
8895 // Run until waiting on both connections.
8896 base::RunLoop().RunUntilIdle();
8897
8898 // The H2 connection completes.
8899 data.socket()->OnConnectComplete(MockConnect(SYNCHRONOUS, OK));
8900 EXPECT_EQ(OK, callback1.WaitForResult());
8901 const HttpResponseInfo* response = helper.trans()->GetResponseInfo();
8902 ASSERT_TRUE(response->headers);
8903 EXPECT_TRUE(response->was_fetched_via_spdy);
8904 EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
8905 std::string response_data;
8906 rv = ReadTransaction(helper.trans(), &response_data);
8907 EXPECT_THAT(rv, IsOk());
8908 EXPECT_EQ("hello!", response_data);
8909
8910 SpdySessionKey key(
8911 HostPortPair::FromURL(request_.url),
8912 ProxyServer::FromURI("https://proxy:70", ProxyServer::SCHEME_HTTPS),
8913 PRIVACY_MODE_DISABLED, SpdySessionKey::IsProxySession::kFalse,
dalyk51ab46b2019-10-15 15:14:348914 SocketTag(), NetworkIsolationKey(), false /* disable_secure_dns */);
Matt Menke7269f352019-10-03 17:05:298915
8916 base::WeakPtr<SpdySession> spdy_session =
8917 helper.session()->spdy_session_pool()->FindAvailableSession(
8918 key, /* enable_ip_based_pooling = */ true,
8919 /* is_websocket = */ false, log_);
8920 ASSERT_TRUE(spdy_session);
8921 EXPECT_FALSE(spdy_session->support_websocket());
8922
8923 EXPECT_FALSE(callback2.have_result());
8924
8925 // Create WebSocket stream.
8926 data2.socket()->OnConnectComplete(MockConnect(SYNCHRONOUS, OK));
8927
8928 rv = callback2.WaitForResult();
8929 ASSERT_THAT(rv, IsOk());
8930 helper.VerifyDataConsumed();
8931}
8932
Matt Menke5062be22019-05-01 17:50:248933// Same as above, but checks that a WebSocket connection avoids creating a new
8934// socket if it detects an H2 session when host resolution completes, and
8935// requests also use different hostnames.
8936TEST_F(SpdyNetworkTransactionTest,
8937 WebSocketOverHTTP2DetectsNewSessionWithAliasing) {
8938 base::HistogramTester histogram_tester;
8939 auto session_deps = std::make_unique<SpdySessionDependencies>();
8940 session_deps->enable_websocket_over_http2 = true;
8941 session_deps->host_resolver->set_ondemand_mode(true);
8942 NormalSpdyTransactionHelper helper(request_, HIGHEST, log_,
8943 std::move(session_deps));
8944 helper.RunPreTestSetup();
8945
8946 spdy::SpdySerializedFrame req(
8947 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, HIGHEST));
8948 spdy::SpdySerializedFrame settings_ack(spdy_util_.ConstructSpdySettingsAck());
8949
8950 spdy::SpdyHeaderBlock websocket_request_headers;
8951 websocket_request_headers[spdy::kHttp2MethodHeader] = "CONNECT";
8952 websocket_request_headers[spdy::kHttp2AuthorityHeader] = "example.test";
8953 websocket_request_headers[spdy::kHttp2SchemeHeader] = "https";
8954 websocket_request_headers[spdy::kHttp2PathHeader] = "/";
8955 websocket_request_headers[spdy::kHttp2ProtocolHeader] = "websocket";
8956 websocket_request_headers["origin"] = "http://example.test";
8957 websocket_request_headers["sec-websocket-version"] = "13";
8958 websocket_request_headers["sec-websocket-extensions"] =
8959 "permessage-deflate; client_max_window_bits";
8960 spdy::SpdySerializedFrame websocket_request(spdy_util_.ConstructSpdyHeaders(
8961 3, std::move(websocket_request_headers), MEDIUM, false));
8962
8963 spdy::SpdySerializedFrame priority1(
8964 spdy_util_.ConstructSpdyPriority(3, 0, MEDIUM, true));
8965 spdy::SpdySerializedFrame priority2(
8966 spdy_util_.ConstructSpdyPriority(1, 3, LOWEST, true));
8967
8968 MockWrite writes[] = {
8969 CreateMockWrite(req, 0), CreateMockWrite(settings_ack, 2),
8970 CreateMockWrite(websocket_request, 4), CreateMockWrite(priority1, 5),
8971 CreateMockWrite(priority2, 6)};
8972
8973 spdy::SettingsMap settings;
8974 settings[spdy::SETTINGS_ENABLE_CONNECT_PROTOCOL] = 1;
8975 spdy::SpdySerializedFrame settings_frame(
8976 spdy_util_.ConstructSpdySettings(settings));
8977 spdy::SpdySerializedFrame resp1(
8978 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
8979 spdy::SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true));
8980 spdy::SpdySerializedFrame websocket_response(
8981 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
8982 MockRead reads[] = {CreateMockRead(settings_frame, 1),
8983 CreateMockRead(resp1, 3), CreateMockRead(body1, 7),
8984 CreateMockRead(websocket_response, 8),
8985 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 9)};
8986
8987 SequencedSocketData data(reads, writes);
8988 helper.AddData(&data);
8989
8990 TestCompletionCallback callback1;
8991 int rv = helper.trans()->Start(&request_, callback1.callback(), log_);
8992 ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
8993
8994 HttpRequestInfo request2;
8995 request2.method = "GET";
8996 request2.url = GURL("wss://example.test/");
8997 request2.traffic_annotation =
8998 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
8999 request2.extra_headers.SetHeader("Origin", "http://example.test");
9000 request2.extra_headers.SetHeader("Sec-WebSocket-Version", "13");
9001 // The following two headers must be removed by WebSocketHttp2HandshakeStream.
9002 request2.extra_headers.SetHeader("Connection", "Upgrade");
9003 request2.extra_headers.SetHeader("Upgrade", "websocket");
9004
9005 TestWebSocketHandshakeStreamCreateHelper websocket_stream_create_helper;
9006
9007 HttpNetworkTransaction trans2(MEDIUM, helper.session());
9008 trans2.SetWebSocketHandshakeStreamCreateHelper(
9009 &websocket_stream_create_helper);
9010
9011 TestCompletionCallback callback2;
9012 rv = trans2.Start(&request2, callback2.callback(), log_);
9013 ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
9014
9015 // Make sure both requests are blocked on host resolution.
9016 base::RunLoop().RunUntilIdle();
9017
9018 EXPECT_TRUE(helper.session_deps()->host_resolver->has_pending_requests());
9019 // Complete the first DNS lookup, which should result in the first transaction
9020 // creating an H2 session (And completing successfully).
9021 helper.session_deps()->host_resolver->ResolveNow(1);
9022 base::RunLoop().RunUntilIdle();
9023
9024 SpdySessionKey key1(HostPortPair::FromURL(request_.url),
9025 ProxyServer::Direct(), PRIVACY_MODE_DISABLED,
dalyk51ab46b2019-10-15 15:14:349026 SpdySessionKey::IsProxySession::kFalse, SocketTag(),
9027 NetworkIsolationKey(), false /* disable_secure_dns */);
Matt Menke5062be22019-05-01 17:50:249028 base::WeakPtr<SpdySession> spdy_session1 =
9029 helper.session()->spdy_session_pool()->FindAvailableSession(
9030 key1, /* enable_ip_based_pooling = */ true,
9031 /* is_websocket = */ false, log_);
9032 ASSERT_TRUE(spdy_session1);
9033 EXPECT_TRUE(spdy_session1->support_websocket());
9034
9035 // Second DNS lookup completes, which results in creating a WebSocket stream.
9036 helper.session_deps()->host_resolver->ResolveNow(2);
9037 ASSERT_TRUE(spdy_session1);
9038
9039 SpdySessionKey key2(HostPortPair::FromURL(request2.url),
9040 ProxyServer::Direct(), PRIVACY_MODE_DISABLED,
dalyk51ab46b2019-10-15 15:14:349041 SpdySessionKey::IsProxySession::kFalse, SocketTag(),
9042 NetworkIsolationKey(), false /* disable_secure_dns */);
Matt Menke5062be22019-05-01 17:50:249043 base::WeakPtr<SpdySession> spdy_session2 =
9044 helper.session()->spdy_session_pool()->FindAvailableSession(
9045 key1, /* enable_ip_based_pooling = */ true,
9046 /* is_websocket = */ true, log_);
9047 ASSERT_TRUE(spdy_session2);
9048 EXPECT_EQ(spdy_session1.get(), spdy_session2.get());
9049
9050 base::RunLoop().RunUntilIdle();
9051
9052 // First request has HIGHEST priority, WebSocket request has MEDIUM priority.
9053 // Changing the priority of the first request to LOWEST changes their order,
9054 // and therefore triggers sending PRIORITY frames.
9055 helper.trans()->SetPriority(LOWEST);
9056
9057 rv = callback1.WaitForResult();
9058 ASSERT_THAT(rv, IsOk());
9059
9060 const HttpResponseInfo* response = helper.trans()->GetResponseInfo();
9061 ASSERT_TRUE(response->headers);
9062 EXPECT_TRUE(response->was_fetched_via_spdy);
9063 EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
9064
9065 std::string response_data;
9066 rv = ReadTransaction(helper.trans(), &response_data);
9067 EXPECT_THAT(rv, IsOk());
9068 EXPECT_EQ("hello!", response_data);
9069
9070 rv = callback2.WaitForResult();
9071 ASSERT_THAT(rv, IsOk());
9072
9073 helper.VerifyDataConsumed();
9074}
9075
9076// Same as above, but the SpdySession is closed just before use, so the
9077// WebSocket is sent over a new HTTP/1.x connection instead.
9078TEST_F(SpdyNetworkTransactionTest,
9079 WebSocketOverDetectsNewSessionWithAliasingButClosedBeforeUse) {
9080 base::HistogramTester histogram_tester;
9081 auto session_deps = std::make_unique<SpdySessionDependencies>();
9082 session_deps->enable_websocket_over_http2 = true;
9083 session_deps->host_resolver->set_ondemand_mode(true);
9084 NormalSpdyTransactionHelper helper(request_, HIGHEST, log_,
9085 std::move(session_deps));
9086 helper.RunPreTestSetup();
9087
9088 spdy::SpdySerializedFrame req(
9089 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, HIGHEST));
9090 spdy::SpdySerializedFrame settings_ack(spdy_util_.ConstructSpdySettingsAck());
9091
9092 MockWrite writes[] = {CreateMockWrite(req, 0),
9093 CreateMockWrite(settings_ack, 2)};
9094
9095 spdy::SettingsMap settings;
9096 settings[spdy::SETTINGS_ENABLE_CONNECT_PROTOCOL] = 1;
9097 spdy::SpdySerializedFrame settings_frame(
9098 spdy_util_.ConstructSpdySettings(settings));
9099 spdy::SpdySerializedFrame resp1(
9100 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
9101 spdy::SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true));
9102 MockRead reads[] = {CreateMockRead(settings_frame, 1),
9103 CreateMockRead(resp1, 3), CreateMockRead(body1, 4),
9104 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 5)};
9105
9106 SequencedSocketData data(reads, writes);
9107 helper.AddData(&data);
9108
9109 MockWrite writes2[] = {
9110 MockWrite("GET / HTTP/1.1\r\n"
9111 "Host: example.test\r\n"
9112 "Connection: Upgrade\r\n"
9113 "Upgrade: websocket\r\n"
9114 "Origin: http://example.test\r\n"
9115 "Sec-WebSocket-Version: 13\r\n"
9116 "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
9117 "Sec-WebSocket-Extensions: permessage-deflate; "
9118 "client_max_window_bits\r\n\r\n")};
9119 MockRead reads2[] = {
9120 MockRead("HTTP/1.1 101 Switching Protocols\r\n"
9121 "Upgrade: websocket\r\n"
9122 "Connection: Upgrade\r\n"
9123 "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n\r\n")};
9124 StaticSocketDataProvider data2(reads2, writes2);
9125 auto ssl_provider2 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
9126 // Test that request has empty |alpn_protos|, that is, HTTP/2 is disabled.
9127 ssl_provider2->next_protos_expected_in_ssl_config = NextProtoVector{};
9128 // Force socket to use HTTP/1.1, the default protocol without ALPN.
9129 ssl_provider2->next_proto = kProtoHTTP11;
9130 ssl_provider2->ssl_info.cert =
9131 ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem");
9132 helper.AddDataWithSSLSocketDataProvider(&data2, std::move(ssl_provider2));
9133
9134 TestCompletionCallback callback1;
9135 int rv = helper.trans()->Start(&request_, callback1.callback(), log_);
9136 ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
9137
9138 HttpRequestInfo request2;
9139 request2.method = "GET";
9140 request2.url = GURL("wss://example.test/");
9141 request2.traffic_annotation =
9142 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
9143 request2.extra_headers.SetHeader("Connection", "Upgrade");
9144 request2.extra_headers.SetHeader("Upgrade", "websocket");
9145 request2.extra_headers.SetHeader("Origin", "http://example.test");
9146 request2.extra_headers.SetHeader("Sec-WebSocket-Version", "13");
9147
9148 TestWebSocketHandshakeStreamCreateHelper websocket_stream_create_helper;
9149
9150 HttpNetworkTransaction trans2(MEDIUM, helper.session());
9151 trans2.SetWebSocketHandshakeStreamCreateHelper(
9152 &websocket_stream_create_helper);
9153
9154 TestCompletionCallback callback2;
9155 rv = trans2.Start(&request2, callback2.callback(), log_);
9156 ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
9157
9158 // Make sure both requests are blocked on host resolution.
9159 base::RunLoop().RunUntilIdle();
9160
9161 EXPECT_TRUE(helper.session_deps()->host_resolver->has_pending_requests());
9162 // Complete the first DNS lookup, which should result in the first transaction
9163 // creating an H2 session (And completing successfully).
9164 helper.session_deps()->host_resolver->ResolveNow(1);
9165
9166 // Complete first request.
9167 rv = callback1.WaitForResult();
9168 ASSERT_THAT(rv, IsOk());
9169 const HttpResponseInfo* response = helper.trans()->GetResponseInfo();
9170 ASSERT_TRUE(response->headers);
9171 EXPECT_TRUE(response->was_fetched_via_spdy);
9172 EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
9173 std::string response_data;
9174 rv = ReadTransaction(helper.trans(), &response_data);
9175 EXPECT_THAT(rv, IsOk());
9176 EXPECT_EQ("hello!", response_data);
9177
9178 SpdySessionKey key1(HostPortPair::FromURL(request_.url),
9179 ProxyServer::Direct(), PRIVACY_MODE_DISABLED,
dalyk51ab46b2019-10-15 15:14:349180 SpdySessionKey::IsProxySession::kFalse, SocketTag(),
9181 NetworkIsolationKey(), false /* disable_secure_dns */);
Matt Menke5062be22019-05-01 17:50:249182 base::WeakPtr<SpdySession> spdy_session1 =
9183 helper.session()->spdy_session_pool()->FindAvailableSession(
9184 key1, /* enable_ip_based_pooling = */ true,
9185 /* is_websocket = */ false, log_);
9186 ASSERT_TRUE(spdy_session1);
9187 EXPECT_TRUE(spdy_session1->support_websocket());
9188
9189 // Second DNS lookup completes, which results in creating an alias for the
9190 // SpdySession immediately, and a task is posted asynchronously to use the
9191 // alias..
9192 helper.session_deps()->host_resolver->ResolveNow(2);
9193
9194 SpdySessionKey key2(HostPortPair::FromURL(request2.url),
9195 ProxyServer::Direct(), PRIVACY_MODE_DISABLED,
dalyk51ab46b2019-10-15 15:14:349196 SpdySessionKey::IsProxySession::kFalse, SocketTag(),
9197 NetworkIsolationKey(), false /* disable_secure_dns */);
Matt Menke5062be22019-05-01 17:50:249198 base::WeakPtr<SpdySession> spdy_session2 =
9199 helper.session()->spdy_session_pool()->FindAvailableSession(
9200 key1, /* enable_ip_based_pooling = */ true,
9201 /* is_websocket = */ true, log_);
9202 ASSERT_TRUE(spdy_session2);
9203 EXPECT_EQ(spdy_session1.get(), spdy_session2.get());
9204
9205 // But the session is closed before it can be used.
9206 helper.session()->spdy_session_pool()->CloseAllSessions();
9207
9208 // The second request establishes another connection (without even doing
9209 // another DNS lookup) instead, and uses HTTP/1.x.
9210 rv = callback2.WaitForResult();
9211 ASSERT_THAT(rv, IsOk());
9212
9213 helper.VerifyDataConsumed();
9214}
9215
Bence Békyfbeb8832018-04-05 23:19:569216TEST_F(SpdyNetworkTransactionTest, WebSocketNegotiatesHttp2) {
9217 HttpRequestInfo request;
9218 request.method = "GET";
9219 request.url = GURL("wss://www.example.org/");
9220 request.traffic_annotation =
9221 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
9222 EXPECT_TRUE(HostPortPair::FromURL(request_.url)
9223 .Equals(HostPortPair::FromURL(request.url)));
9224 request.extra_headers.SetHeader("Connection", "Upgrade");
9225 request.extra_headers.SetHeader("Upgrade", "websocket");
9226 request.extra_headers.SetHeader("Origin", "http://www.example.org");
9227 request.extra_headers.SetHeader("Sec-WebSocket-Version", "13");
9228
9229 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
9230 helper.RunPreTestSetup();
9231
Ryan Sleevib8d7ea02018-05-07 20:01:019232 StaticSocketDataProvider data;
Bence Békyfbeb8832018-04-05 23:19:569233
9234 auto ssl_provider = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
9235 // Test that request has empty |alpn_protos|, that is, HTTP/2 is disabled.
9236 ssl_provider->next_protos_expected_in_ssl_config = NextProtoVector{};
Bence Békyb4a07f8f2018-05-17 14:31:559237 // Force socket to use HTTP/2, which should never happen (TLS implementation
9238 // should fail TLS handshake if server chooses HTTP/2 without client
9239 // advertising support).
Bence Békyfbeb8832018-04-05 23:19:569240 ssl_provider->next_proto = kProtoHTTP2;
9241 ssl_provider->ssl_info.cert =
9242 ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem");
9243 helper.AddDataWithSSLSocketDataProvider(&data, std::move(ssl_provider));
9244
9245 HttpNetworkTransaction* trans = helper.trans();
9246 TestWebSocketHandshakeStreamCreateHelper websocket_stream_create_helper;
9247 trans->SetWebSocketHandshakeStreamCreateHelper(
9248 &websocket_stream_create_helper);
9249
9250 TestCompletionCallback callback;
9251 int rv = trans->Start(&request, callback.callback(), log_);
9252 ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
9253 rv = callback.WaitForResult();
9254 ASSERT_THAT(rv, IsError(ERR_NOT_IMPLEMENTED));
9255
9256 helper.VerifyDataConsumed();
9257}
9258
Matt Menkef2ee07c2019-08-29 02:10:369259TEST_F(SpdyNetworkTransactionTest, WebSocketHttp11Required) {
9260 base::HistogramTester histogram_tester;
9261 auto session_deps = std::make_unique<SpdySessionDependencies>();
9262 session_deps->enable_websocket_over_http2 = true;
9263 NormalSpdyTransactionHelper helper(request_, HIGHEST, log_,
9264 std::move(session_deps));
9265 helper.RunPreTestSetup();
9266
9267 spdy::SpdySerializedFrame req(
9268 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, HIGHEST));
9269 spdy::SpdySerializedFrame settings_ack(spdy_util_.ConstructSpdySettingsAck());
9270
9271 spdy::SpdyHeaderBlock websocket_request_headers;
9272 websocket_request_headers[spdy::kHttp2MethodHeader] = "CONNECT";
9273 websocket_request_headers[spdy::kHttp2AuthorityHeader] = "www.example.org";
9274 websocket_request_headers[spdy::kHttp2SchemeHeader] = "https";
9275 websocket_request_headers[spdy::kHttp2PathHeader] = "/";
9276 websocket_request_headers[spdy::kHttp2ProtocolHeader] = "websocket";
9277 websocket_request_headers["origin"] = "http://www.example.org";
9278 websocket_request_headers["sec-websocket-version"] = "13";
9279 websocket_request_headers["sec-websocket-extensions"] =
9280 "permessage-deflate; client_max_window_bits";
9281 spdy::SpdySerializedFrame websocket_request(spdy_util_.ConstructSpdyHeaders(
9282 3, std::move(websocket_request_headers), MEDIUM, false));
9283
9284 spdy::SpdySerializedFrame priority1(
9285 spdy_util_.ConstructSpdyPriority(3, 0, MEDIUM, true));
9286 spdy::SpdySerializedFrame priority2(
9287 spdy_util_.ConstructSpdyPriority(1, 3, LOWEST, true));
9288
9289 MockWrite writes1[] = {CreateMockWrite(req, 0),
9290 CreateMockWrite(settings_ack, 2),
9291 CreateMockWrite(websocket_request, 4)};
9292
9293 spdy::SettingsMap settings;
9294 settings[spdy::SETTINGS_ENABLE_CONNECT_PROTOCOL] = 1;
9295 spdy::SpdySerializedFrame settings_frame(
9296 spdy_util_.ConstructSpdySettings(settings));
9297 spdy::SpdySerializedFrame resp1(
9298 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
9299 spdy::SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true));
9300 spdy::SpdySerializedFrame websocket_response_http11_required(
9301 spdy_util_.ConstructSpdyRstStream(3, spdy::ERROR_CODE_HTTP_1_1_REQUIRED));
9302 MockRead reads1[] = {CreateMockRead(settings_frame, 1),
9303 CreateMockRead(resp1, 3),
9304 CreateMockRead(websocket_response_http11_required, 5)};
9305
9306 SequencedSocketData data1(reads1, writes1);
9307 helper.AddData(&data1);
9308
9309 MockWrite writes2[] = {
9310 MockWrite("GET / HTTP/1.1\r\n"
9311 "Host: www.example.org\r\n"
9312 "Connection: Upgrade\r\n"
9313 "Origin: http://www.example.org\r\n"
9314 "Sec-WebSocket-Version: 13\r\n"
9315 "Upgrade: websocket\r\n"
9316 "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
9317 "Sec-WebSocket-Extensions: permessage-deflate; "
9318 "client_max_window_bits\r\n\r\n")};
9319 MockRead reads2[] = {
9320 MockRead("HTTP/1.1 101 Switching Protocols\r\n"
9321 "Upgrade: websocket\r\n"
9322 "Connection: Upgrade\r\n"
9323 "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n\r\n")};
9324 StaticSocketDataProvider data2(reads2, writes2);
9325 auto ssl_provider2 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
9326 // Test that request has empty |alpn_protos|, that is, HTTP/2 is disabled.
9327 ssl_provider2->next_protos_expected_in_ssl_config = NextProtoVector{};
9328 // Force socket to use HTTP/1.1, the default protocol without ALPN.
9329 ssl_provider2->next_proto = kProtoHTTP11;
9330 ssl_provider2->ssl_info.cert =
9331 ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem");
9332 helper.AddDataWithSSLSocketDataProvider(&data2, std::move(ssl_provider2));
9333
9334 // Create HTTP/2 connection.
9335 TestCompletionCallback callback1;
9336 int rv = helper.trans()->Start(&request_, callback1.callback(), log_);
9337 ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
9338
9339 // Create HTTP/2 connection.
9340 base::RunLoop().RunUntilIdle();
9341
9342 SpdySessionKey key(HostPortPair::FromURL(request_.url), ProxyServer::Direct(),
9343 PRIVACY_MODE_DISABLED,
dalyk51ab46b2019-10-15 15:14:349344 SpdySessionKey::IsProxySession::kFalse, SocketTag(),
9345 NetworkIsolationKey(), false /* disable_secure_dns */);
Matt Menkef2ee07c2019-08-29 02:10:369346 base::WeakPtr<SpdySession> spdy_session =
9347 helper.session()->spdy_session_pool()->FindAvailableSession(
9348 key, /* enable_ip_based_pooling = */ true,
9349 /* is_websocket = */ true, log_);
9350 ASSERT_TRUE(spdy_session);
9351 EXPECT_TRUE(spdy_session->support_websocket());
9352
9353 HttpRequestInfo request2;
9354 request2.method = "GET";
9355 request2.url = GURL("wss://www.example.org/");
9356 request2.traffic_annotation =
9357 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
9358 EXPECT_TRUE(HostPortPair::FromURL(request_.url)
9359 .Equals(HostPortPair::FromURL(request2.url)));
9360 request2.extra_headers.SetHeader("Origin", "http://www.example.org");
9361 request2.extra_headers.SetHeader("Sec-WebSocket-Version", "13");
9362 // The following two headers must be removed by WebSocketHttp2HandshakeStream.
9363 request2.extra_headers.SetHeader("Connection", "Upgrade");
9364 request2.extra_headers.SetHeader("Upgrade", "websocket");
9365
9366 TestWebSocketHandshakeStreamCreateHelper websocket_stream_create_helper;
9367
9368 HttpNetworkTransaction trans2(MEDIUM, helper.session());
9369 trans2.SetWebSocketHandshakeStreamCreateHelper(
9370 &websocket_stream_create_helper);
9371
9372 TestCompletionCallback callback2;
9373 rv = trans2.Start(&request2, callback2.callback(), log_);
9374 EXPECT_THAT(callback2.GetResult(rv), IsOk());
9375
9376 helper.VerifyDataConsumed();
9377
9378 // Server advertised WebSocket support.
9379 histogram_tester.ExpectUniqueSample("Net.SpdySession.ServerSupportsWebSocket",
9380 /* support_websocket = true */ 1,
9381 /* expected_count = */ 1);
9382}
9383
Bence Béky420bb2d2018-03-30 17:25:269384// Plaintext WebSocket over HTTP/2 is not implemented, see
9385// https://crbug.com/684681.
9386TEST_F(SpdyNetworkTransactionTest, PlaintextWebSocketOverHttp2Proxy) {
Ryan Hamilton0239aac2018-05-19 00:03:139387 spdy::SpdySerializedFrame req(spdy_util_.ConstructSpdyConnect(
Matt Menke6e879bd2019-03-18 17:26:049388 nullptr, 0, 1, HttpProxyConnectJob::kH2QuicTunnelPriority,
9389 HostPortPair("www.example.org", 80)));
Bence Béky420bb2d2018-03-30 17:25:269390 MockWrite writes[] = {CreateMockWrite(req, 0)};
9391
Ryan Hamilton0239aac2018-05-19 00:03:139392 spdy::SpdySerializedFrame resp(
9393 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
Bence Béky420bb2d2018-03-30 17:25:269394 MockRead reads[] = {CreateMockRead(resp, 1), MockRead(ASYNC, 0, 2)};
9395
Ryan Sleevib8d7ea02018-05-07 20:01:019396 SequencedSocketData data(reads, writes);
Bence Béky420bb2d2018-03-30 17:25:269397
9398 request_.url = GURL("ws://www.example.org/");
9399 auto session_deps = std::make_unique<SpdySessionDependencies>(
Nicolas Arciniegad2013f92020-02-07 23:00:569400 ConfiguredProxyResolutionService::CreateFixed(
9401 "https://proxy:70", TRAFFIC_ANNOTATION_FOR_TESTS));
Bence Béky420bb2d2018-03-30 17:25:269402 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
9403 std::move(session_deps));
9404 helper.RunPreTestSetup();
9405 helper.AddData(&data);
9406
9407 HttpNetworkTransaction* trans = helper.trans();
9408 TestWebSocketHandshakeStreamCreateHelper websocket_stream_create_helper;
9409 trans->SetWebSocketHandshakeStreamCreateHelper(
9410 &websocket_stream_create_helper);
9411
9412 EXPECT_TRUE(helper.StartDefaultTest());
9413 helper.WaitForCallbackToComplete();
9414 EXPECT_THAT(helper.output().rv, IsError(ERR_NOT_IMPLEMENTED));
9415
9416 helper.VerifyDataConsumed();
9417}
9418
Bence Béky6434d5e2018-04-03 13:43:119419// Regression test for https://crbug.com/819101. Open two identical plaintext
Xida Chen9bfe0b62018-04-24 19:52:219420// websocket requests over proxy. The HttpStreamFactory::Job for the second
Bence Béky6434d5e2018-04-03 13:43:119421// request should reuse the first connection.
9422TEST_F(SpdyNetworkTransactionTest, TwoWebSocketRequestsOverHttp2Proxy) {
Ryan Hamilton0239aac2018-05-19 00:03:139423 spdy::SpdySerializedFrame req(spdy_util_.ConstructSpdyConnect(
Matt Menke6e879bd2019-03-18 17:26:049424 nullptr, 0, 1, HttpProxyConnectJob::kH2QuicTunnelPriority,
9425 HostPortPair("www.example.org", 80)));
Bence Béky6434d5e2018-04-03 13:43:119426 MockWrite writes[] = {CreateMockWrite(req, 0)};
9427
Ryan Hamilton0239aac2018-05-19 00:03:139428 spdy::SpdySerializedFrame resp(
9429 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
Bence Béky6434d5e2018-04-03 13:43:119430 MockRead reads[] = {CreateMockRead(resp, 1),
9431 MockRead(ASYNC, ERR_IO_PENDING, 2),
9432 MockRead(ASYNC, 0, 3)};
9433
Ryan Sleevib8d7ea02018-05-07 20:01:019434 SequencedSocketData data(reads, writes);
Bence Béky6434d5e2018-04-03 13:43:119435
9436 request_.url = GURL("ws://www.example.org/");
9437 auto session_deps = std::make_unique<SpdySessionDependencies>(
Nicolas Arciniegad2013f92020-02-07 23:00:569438 ConfiguredProxyResolutionService::CreateFixed(
9439 "https://proxy:70", TRAFFIC_ANNOTATION_FOR_TESTS));
Bence Béky6434d5e2018-04-03 13:43:119440 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
9441 std::move(session_deps));
9442 helper.RunPreTestSetup();
9443 helper.AddData(&data);
9444
9445 HttpNetworkTransaction* trans1 = helper.trans();
9446 TestWebSocketHandshakeStreamCreateHelper websocket_stream_create_helper;
9447 trans1->SetWebSocketHandshakeStreamCreateHelper(
9448 &websocket_stream_create_helper);
9449
9450 EXPECT_TRUE(helper.StartDefaultTest());
9451 helper.WaitForCallbackToComplete();
9452 EXPECT_THAT(helper.output().rv, IsError(ERR_NOT_IMPLEMENTED));
9453
9454 HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session());
9455 trans2.SetWebSocketHandshakeStreamCreateHelper(
9456 &websocket_stream_create_helper);
9457
9458 TestCompletionCallback callback2;
9459 int rv = trans2.Start(&request_, callback2.callback(), log_);
9460 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
9461
9462 rv = callback2.WaitForResult();
9463 EXPECT_THAT(rv, IsError(ERR_NOT_IMPLEMENTED));
9464
9465 data.Resume();
9466 base::RunLoop().RunUntilIdle();
9467
9468 helper.VerifyDataConsumed();
9469}
9470
Bence Béky420bb2d2018-03-30 17:25:269471TEST_F(SpdyNetworkTransactionTest, SecureWebSocketOverHttp2Proxy) {
Ryan Hamilton0239aac2018-05-19 00:03:139472 spdy::SpdySerializedFrame connect_request(spdy_util_.ConstructSpdyConnect(
Matt Menke6e879bd2019-03-18 17:26:049473 nullptr, 0, 1, HttpProxyConnectJob::kH2QuicTunnelPriority,
9474 HostPortPair("www.example.org", 443)));
Bence Béky420bb2d2018-03-30 17:25:269475 const char kWebSocketRequest[] =
9476 "GET / HTTP/1.1\r\n"
9477 "Host: www.example.org\r\n"
9478 "Connection: Upgrade\r\n"
9479 "Upgrade: websocket\r\n"
9480 "Origin: http://www.example.org\r\n"
9481 "Sec-WebSocket-Version: 13\r\n"
9482 "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
9483 "Sec-WebSocket-Extensions: permessage-deflate; "
9484 "client_max_window_bits\r\n\r\n";
Ryan Hamilton0239aac2018-05-19 00:03:139485 spdy::SpdySerializedFrame websocket_request(
Bence Béky420bb2d2018-03-30 17:25:269486 spdy_util_.ConstructSpdyDataFrame(1, kWebSocketRequest, false));
9487 MockWrite writes[] = {CreateMockWrite(connect_request, 0),
9488 CreateMockWrite(websocket_request, 2)};
9489
Ryan Hamilton0239aac2018-05-19 00:03:139490 spdy::SpdySerializedFrame connect_response(
Bence Béky420bb2d2018-03-30 17:25:269491 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
9492 const char kWebSocketResponse[] =
9493 "HTTP/1.1 101 Switching Protocols\r\n"
9494 "Upgrade: websocket\r\n"
9495 "Connection: Upgrade\r\n"
9496 "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n\r\n";
Ryan Hamilton0239aac2018-05-19 00:03:139497 spdy::SpdySerializedFrame websocket_response(
Bence Béky420bb2d2018-03-30 17:25:269498 spdy_util_.ConstructSpdyDataFrame(1, kWebSocketResponse, false));
9499 MockRead reads[] = {CreateMockRead(connect_response, 1),
9500 CreateMockRead(websocket_response, 3),
9501 MockRead(ASYNC, 0, 4)};
9502
Ryan Sleevib8d7ea02018-05-07 20:01:019503 SequencedSocketData data(reads, writes);
Bence Béky420bb2d2018-03-30 17:25:269504
9505 request_.url = GURL("wss://www.example.org/");
9506 request_.extra_headers.SetHeader("Connection", "Upgrade");
9507 request_.extra_headers.SetHeader("Upgrade", "websocket");
9508 request_.extra_headers.SetHeader("Origin", "http://www.example.org");
9509 request_.extra_headers.SetHeader("Sec-WebSocket-Version", "13");
9510 auto session_deps = std::make_unique<SpdySessionDependencies>(
Nicolas Arciniegad2013f92020-02-07 23:00:569511 ConfiguredProxyResolutionService::CreateFixed(
9512 "https://proxy:70", TRAFFIC_ANNOTATION_FOR_TESTS));
Bence Béky420bb2d2018-03-30 17:25:269513 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
9514 std::move(session_deps));
9515 helper.RunPreTestSetup();
9516 helper.AddData(&data);
9517
9518 // Add SSL data for the tunneled connection.
9519 SSLSocketDataProvider ssl_provider(ASYNC, OK);
9520 ssl_provider.ssl_info.cert =
9521 ImportCertFromFile(GetTestCertsDirectory(), "wildcard.pem");
Bence Béky12943c62018-04-05 19:16:509522 // A WebSocket request should not advertise HTTP/2 support.
9523 ssl_provider.next_protos_expected_in_ssl_config = NextProtoVector{};
Bence Béky420bb2d2018-03-30 17:25:269524 // This test uses WebSocket over HTTP/1.1.
9525 ssl_provider.next_proto = kProtoHTTP11;
9526 helper.session_deps()->socket_factory->AddSSLSocketDataProvider(
9527 &ssl_provider);
9528
9529 HttpNetworkTransaction* trans = helper.trans();
9530 TestWebSocketHandshakeStreamCreateHelper websocket_stream_create_helper;
9531 trans->SetWebSocketHandshakeStreamCreateHelper(
9532 &websocket_stream_create_helper);
9533
9534 EXPECT_TRUE(helper.StartDefaultTest());
9535 helper.WaitForCallbackToComplete();
9536 EXPECT_THAT(helper.output().rv, IsOk());
9537 const HttpResponseInfo* response = trans->GetResponseInfo();
9538 ASSERT_TRUE(response);
9539 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP1_1,
9540 response->connection_info);
9541 EXPECT_TRUE(response->was_alpn_negotiated);
9542 EXPECT_FALSE(response->was_fetched_via_spdy);
Tsuyoshi Horo01faed62019-02-20 22:11:379543 EXPECT_EQ(70, response->remote_endpoint.port());
Bence Béky420bb2d2018-03-30 17:25:269544 ASSERT_TRUE(response->headers);
9545 EXPECT_EQ("HTTP/1.1 101 Switching Protocols",
9546 response->headers->GetStatusLine());
9547
9548 base::RunLoop().RunUntilIdle();
9549 helper.VerifyDataConsumed();
9550}
9551
Bence Béky12943c62018-04-05 19:16:509552// Regression test for https://crbug.com/828865.
9553TEST_F(SpdyNetworkTransactionTest,
9554 SecureWebSocketOverHttp2ProxyNegotiatesHttp2) {
Ryan Hamilton0239aac2018-05-19 00:03:139555 spdy::SpdySerializedFrame connect_request(spdy_util_.ConstructSpdyConnect(
Matt Menke6e879bd2019-03-18 17:26:049556 nullptr, 0, 1, HttpProxyConnectJob::kH2QuicTunnelPriority,
9557 HostPortPair("www.example.org", 443)));
Bence Béky12943c62018-04-05 19:16:509558 MockWrite writes[] = {CreateMockWrite(connect_request, 0)};
Ryan Hamilton0239aac2018-05-19 00:03:139559 spdy::SpdySerializedFrame connect_response(
Bence Béky12943c62018-04-05 19:16:509560 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
9561 MockRead reads[] = {CreateMockRead(connect_response, 1),
9562 MockRead(ASYNC, 0, 2)};
Ryan Sleevib8d7ea02018-05-07 20:01:019563 SequencedSocketData data(reads, writes);
Bence Béky12943c62018-04-05 19:16:509564
9565 request_.url = GURL("wss://www.example.org/");
9566 request_.extra_headers.SetHeader("Connection", "Upgrade");
9567 request_.extra_headers.SetHeader("Upgrade", "websocket");
9568 request_.extra_headers.SetHeader("Origin", "http://www.example.org");
9569 request_.extra_headers.SetHeader("Sec-WebSocket-Version", "13");
9570 auto session_deps = std::make_unique<SpdySessionDependencies>(
Nicolas Arciniegad2013f92020-02-07 23:00:569571 ConfiguredProxyResolutionService::CreateFixed(
9572 "https://proxy:70", TRAFFIC_ANNOTATION_FOR_TESTS));
Bence Béky12943c62018-04-05 19:16:509573 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
9574 std::move(session_deps));
9575 helper.RunPreTestSetup();
9576 helper.AddData(&data);
9577
9578 // Add SSL data for the tunneled connection.
9579 SSLSocketDataProvider ssl_provider(ASYNC, OK);
9580 ssl_provider.ssl_info.cert =
9581 ImportCertFromFile(GetTestCertsDirectory(), "wildcard.pem");
9582 // A WebSocket request should not advertise HTTP/2 support.
9583 ssl_provider.next_protos_expected_in_ssl_config = NextProtoVector{};
9584 // The server should not negotiate HTTP/2 over the tunnelled connection,
9585 // but it must be handled gracefully if it does.
9586 ssl_provider.next_proto = kProtoHTTP2;
9587 helper.session_deps()->socket_factory->AddSSLSocketDataProvider(
9588 &ssl_provider);
9589
9590 HttpNetworkTransaction* trans = helper.trans();
9591 TestWebSocketHandshakeStreamCreateHelper websocket_stream_create_helper;
9592 trans->SetWebSocketHandshakeStreamCreateHelper(
9593 &websocket_stream_create_helper);
9594
9595 EXPECT_TRUE(helper.StartDefaultTest());
9596 helper.WaitForCallbackToComplete();
9597 EXPECT_THAT(helper.output().rv, IsError(ERR_NOT_IMPLEMENTED));
9598
9599 base::RunLoop().RunUntilIdle();
9600 helper.VerifyDataConsumed();
9601}
9602
Bence Béky0ca719f2018-01-31 13:41:199603#endif // BUILDFLAG(ENABLE_WEBSOCKETS)
9604
Steven Valdez1c1859172019-04-10 15:33:289605TEST_F(SpdyNetworkTransactionTest, ZeroRTTDoesntConfirm) {
David Benjaminbae08ba2019-10-18 21:06:159606 static const base::TimeDelta kDelay = base::TimeDelta::FromMilliseconds(10);
Steven Valdez1c1859172019-04-10 15:33:289607 spdy::SpdySerializedFrame req(
9608 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
9609 MockWrite writes[] = {CreateMockWrite(req, 0)};
9610
9611 spdy::SpdySerializedFrame resp(
9612 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
9613 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
9614 MockRead reads[] = {
9615 CreateMockRead(resp, 1), CreateMockRead(body, 2),
9616 MockRead(ASYNC, 0, 3) // EOF
9617 };
9618
9619 SequencedSocketData data(reads, writes);
9620 auto session_deps = std::make_unique<SpdySessionDependencies>();
9621 session_deps->enable_early_data = true;
9622 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
9623 std::move(session_deps));
9624 auto ssl_provider = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
David Benjaminbae08ba2019-10-18 21:06:159625 ssl_provider->connect_callback = FastForwardByCallback(kDelay);
Steven Valdez1c1859172019-04-10 15:33:289626 // Configure |ssl_provider| to fail if ConfirmHandshake is called. The request
9627 // should still succeed.
9628 ssl_provider->confirm = MockConfirm(SYNCHRONOUS, ERR_SSL_PROTOCOL_ERROR);
David Benjaminbae08ba2019-10-18 21:06:159629 ssl_provider->confirm_callback = FastForwardByCallback(kDelay);
9630 base::TimeTicks start_time = base::TimeTicks::Now();
Steven Valdez1c1859172019-04-10 15:33:289631 helper.RunToCompletionWithSSLData(&data, std::move(ssl_provider));
9632 TransactionHelperResult out = helper.output();
9633 EXPECT_THAT(out.rv, IsOk());
9634 EXPECT_EQ("HTTP/1.1 200", out.status_line);
9635 EXPECT_EQ("hello!", out.response_data);
David Benjaminbae08ba2019-10-18 21:06:159636
9637 // The handshake time should include the time it took to run Connect(), but
9638 // not ConfirmHandshake().
9639 LoadTimingInfo load_timing_info;
9640 EXPECT_TRUE(helper.trans()->GetLoadTimingInfo(&load_timing_info));
9641 EXPECT_EQ(load_timing_info.connect_timing.connect_start, start_time);
9642 EXPECT_EQ(load_timing_info.connect_timing.ssl_start, start_time);
9643 EXPECT_EQ(load_timing_info.connect_timing.ssl_end, start_time + kDelay);
9644 EXPECT_EQ(load_timing_info.connect_timing.connect_end, start_time + kDelay);
Steven Valdez1c1859172019-04-10 15:33:289645}
9646
9647// Run multiple concurrent streams that don't require handshake confirmation.
9648TEST_F(SpdyNetworkTransactionTest, ZeroRTTNoConfirmMultipleStreams) {
9649 spdy::SpdySerializedFrame req1(
9650 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
9651 spdy::SpdySerializedFrame req2(
9652 spdy_util_.ConstructSpdyGet(nullptr, 0, 3, LOWEST));
9653 MockWrite writes1[] = {CreateMockWrite(req1, 0), CreateMockWrite(req2, 3)};
9654
9655 spdy::SpdySerializedFrame resp1(
9656 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
9657 spdy::SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true));
9658 spdy::SpdySerializedFrame resp2(
9659 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
9660 spdy::SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(3, true));
9661 MockRead reads1[] = {
9662 CreateMockRead(resp1, 1), CreateMockRead(body1, 2),
9663 CreateMockRead(resp2, 4), CreateMockRead(body2, 5),
9664 MockRead(ASYNC, 0, 6) // EOF
9665 };
9666
9667 SequencedSocketData data1(reads1, writes1);
9668 SequencedSocketData data2({}, {});
9669 auto session_deps = std::make_unique<SpdySessionDependencies>();
9670 session_deps->enable_early_data = true;
9671 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
9672 std::move(session_deps));
9673 auto ssl_provider1 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
9674 ssl_provider1->confirm = MockConfirm(SYNCHRONOUS, ERR_SSL_PROTOCOL_ERROR);
9675 auto ssl_provider2 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
9676 ssl_provider2->confirm = MockConfirm(SYNCHRONOUS, ERR_SSL_PROTOCOL_ERROR);
9677
9678 helper.RunPreTestSetup();
9679 helper.AddDataWithSSLSocketDataProvider(&data1, std::move(ssl_provider1));
9680 helper.AddDataWithSSLSocketDataProvider(&data2, std::move(ssl_provider2));
9681 EXPECT_TRUE(helper.StartDefaultTest());
9682
9683 HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session());
9684 HttpRequestInfo request2;
9685 request2.method = "GET";
9686 request2.url = GURL(kDefaultUrl);
9687 request2.traffic_annotation =
9688 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
9689 TestCompletionCallback callback2;
9690 int rv = trans2.Start(&request2, callback2.callback(), log_);
9691 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
9692
9693 helper.FinishDefaultTest();
9694 EXPECT_THAT(callback2.GetResult(ERR_IO_PENDING), IsOk());
9695 helper.VerifyDataConsumed();
9696
9697 TransactionHelperResult out = helper.output();
9698 EXPECT_THAT(out.rv, IsOk());
9699 EXPECT_EQ("HTTP/1.1 200", out.status_line);
9700 EXPECT_EQ("hello!", out.response_data);
9701}
9702
9703// Run multiple concurrent streams that require handshake confirmation.
9704TEST_F(SpdyNetworkTransactionTest, ZeroRTTConfirmMultipleStreams) {
9705 spdy::SpdyHeaderBlock req_block1(
9706 spdy_util_.ConstructPostHeaderBlock(kDefaultUrl, 0));
9707 spdy::SpdySerializedFrame req1(
9708 spdy_util_.ConstructSpdyHeaders(1, std::move(req_block1), LOWEST, true));
9709 spdy::SpdyHeaderBlock req_block2(
9710 spdy_util_.ConstructPostHeaderBlock(kDefaultUrl, 0));
9711 spdy::SpdySerializedFrame req2(
9712 spdy_util_.ConstructSpdyHeaders(3, std::move(req_block2), LOWEST, true));
9713 MockWrite writes[] = {
9714 CreateMockWrite(req1, 0),
9715 CreateMockWrite(req2, 3),
9716 };
9717 spdy::SpdySerializedFrame resp1(
9718 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
9719 spdy::SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true));
9720 spdy::SpdySerializedFrame resp2(
9721 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
9722 spdy::SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(3, true));
9723 MockRead reads[] = {
9724 CreateMockRead(resp1, 1), CreateMockRead(body1, 2),
9725 CreateMockRead(resp2, 4), CreateMockRead(body2, 5),
9726 MockRead(ASYNC, 0, 6) // EOF
9727 };
9728
9729 SequencedSocketData data1(reads, writes);
9730 SequencedSocketData data2({}, {});
9731 UsePostRequest();
9732 auto session_deps = std::make_unique<SpdySessionDependencies>();
9733 session_deps->enable_early_data = true;
9734 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
9735 std::move(session_deps));
9736 auto ssl_provider1 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
9737 ssl_provider1->confirm = MockConfirm(ASYNC, OK);
9738 auto ssl_provider2 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
9739 ssl_provider2->confirm = MockConfirm(ASYNC, OK);
9740
9741 helper.RunPreTestSetup();
9742 helper.AddDataWithSSLSocketDataProvider(&data1, std::move(ssl_provider1));
9743 helper.AddDataWithSSLSocketDataProvider(&data2, std::move(ssl_provider2));
9744
9745 HttpNetworkTransaction trans1(DEFAULT_PRIORITY, helper.session());
9746 HttpRequestInfo request1;
9747 request1.method = "POST";
9748 request1.url = GURL(kDefaultUrl);
9749 request1.traffic_annotation =
9750 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
9751 TestCompletionCallback callback1;
9752 int rv = trans1.Start(&request1, callback1.callback(), log_);
9753 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
9754
9755 HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session());
9756 HttpRequestInfo request2;
9757 request2.method = "POST";
9758 request2.url = GURL(kDefaultUrl);
9759 request2.traffic_annotation =
9760 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
9761 TestCompletionCallback callback2;
9762 rv = trans2.Start(&request2, callback2.callback(), log_);
9763 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
9764
9765 EXPECT_THAT(callback1.GetResult(ERR_IO_PENDING), IsOk());
9766 EXPECT_THAT(callback2.GetResult(ERR_IO_PENDING), IsOk());
9767
9768 const HttpResponseInfo* response1 = trans1.GetResponseInfo();
9769 ASSERT_TRUE(response1);
9770 ASSERT_TRUE(response1->headers);
9771 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP2,
9772 response1->connection_info);
9773 EXPECT_EQ("HTTP/1.1 200", response1->headers->GetStatusLine());
9774 std::string response_data;
9775 ReadTransaction(&trans1, &response_data);
9776 EXPECT_EQ("hello!", response_data);
9777
9778 const HttpResponseInfo* response2 = trans2.GetResponseInfo();
9779 ASSERT_TRUE(response2);
9780 ASSERT_TRUE(response2->headers);
9781 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP2,
9782 response2->connection_info);
9783 EXPECT_EQ("HTTP/1.1 200", response2->headers->GetStatusLine());
9784 ReadTransaction(&trans2, &response_data);
9785 EXPECT_EQ("hello!", response_data);
9786
9787 helper.VerifyDataConsumed();
9788}
9789
9790// Run multiple concurrent streams, the first require a confirmation and the
9791// second not requiring confirmation.
9792TEST_F(SpdyNetworkTransactionTest, ZeroRTTConfirmNoConfirmStreams) {
9793 // This test orders the writes such that the GET (no confirmation) is written
9794 // before the POST (confirmation required).
9795 spdy::SpdyHeaderBlock req_block1(
9796 spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
9797 spdy::SpdySerializedFrame req1(
9798 spdy_util_.ConstructSpdyHeaders(1, std::move(req_block1), LOWEST, true));
9799 spdy::SpdyHeaderBlock req_block2(
9800 spdy_util_.ConstructPostHeaderBlock(kDefaultUrl, 0));
9801 spdy::SpdySerializedFrame req2(
9802 spdy_util_.ConstructSpdyHeaders(3, std::move(req_block2), LOWEST, true));
9803 MockWrite writes[] = {
9804 CreateMockWrite(req1, 0),
9805 CreateMockWrite(req2, 3),
9806 };
9807 spdy::SpdySerializedFrame resp1(
9808 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
9809 spdy::SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true));
9810 spdy::SpdySerializedFrame resp2(
9811 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
9812 spdy::SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(3, true));
9813 MockRead reads[] = {
9814 CreateMockRead(resp1, 1), CreateMockRead(body1, 2),
9815 CreateMockRead(resp2, 4), CreateMockRead(body2, 5),
9816 MockRead(ASYNC, 0, 6) // EOF
9817 };
9818
9819 SequencedSocketData data1(reads, writes);
9820 SequencedSocketData data2({}, {});
9821 UsePostRequest();
9822 auto session_deps = std::make_unique<SpdySessionDependencies>();
9823 session_deps->enable_early_data = true;
9824 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
9825 std::move(session_deps));
9826 auto ssl_provider1 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
9827 ssl_provider1->confirm = MockConfirm(ASYNC, OK);
9828 auto ssl_provider2 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
9829 ssl_provider2->confirm = MockConfirm(ASYNC, OK);
9830
9831 helper.RunPreTestSetup();
9832 helper.AddDataWithSSLSocketDataProvider(&data1, std::move(ssl_provider1));
9833 helper.AddDataWithSSLSocketDataProvider(&data2, std::move(ssl_provider2));
9834
9835 // TODO(https://crbug.com/949724): Explicitly verify the ordering of
9836 // ConfirmHandshake and the second stream.
9837
9838 HttpNetworkTransaction trans1(DEFAULT_PRIORITY, helper.session());
9839 HttpRequestInfo request1;
9840 request1.method = "POST";
9841 request1.url = GURL(kDefaultUrl);
9842 request1.traffic_annotation =
9843 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
9844 TestCompletionCallback callback1;
9845 int rv = trans1.Start(&request1, callback1.callback(), log_);
9846 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
9847
9848 HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session());
9849 HttpRequestInfo request2;
9850 request2.method = "GET";
9851 request2.url = GURL(kDefaultUrl);
9852 request2.traffic_annotation =
9853 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
9854 TestCompletionCallback callback2;
9855 rv = trans2.Start(&request2, callback2.callback(), log_);
9856 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
9857
9858 EXPECT_THAT(callback1.GetResult(ERR_IO_PENDING), IsOk());
9859 EXPECT_THAT(callback2.GetResult(ERR_IO_PENDING), IsOk());
9860
9861 const HttpResponseInfo* response1 = trans1.GetResponseInfo();
9862 ASSERT_TRUE(response1);
9863 ASSERT_TRUE(response1->headers);
9864 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP2,
9865 response1->connection_info);
9866 EXPECT_EQ("HTTP/1.1 200", response1->headers->GetStatusLine());
9867 std::string response_data;
9868 ReadTransaction(&trans1, &response_data);
9869 EXPECT_EQ("hello!", response_data);
9870
9871 const HttpResponseInfo* response2 = trans2.GetResponseInfo();
9872 ASSERT_TRUE(response2);
9873 ASSERT_TRUE(response2->headers);
9874 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP2,
9875 response2->connection_info);
9876 EXPECT_EQ("HTTP/1.1 200", response2->headers->GetStatusLine());
9877 ReadTransaction(&trans2, &response_data);
9878 EXPECT_EQ("hello!", response_data);
9879
9880 helper.VerifyDataConsumed();
9881}
9882
9883// Run multiple concurrent streams, the first not requiring confirmation and the
9884// second requiring confirmation.
9885TEST_F(SpdyNetworkTransactionTest, ZeroRTTNoConfirmConfirmStreams) {
9886 // This test orders the writes such that the GET (no confirmation) is written
9887 // before the POST (confirmation required).
9888 spdy::SpdyHeaderBlock req_block1(
9889 spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
9890 spdy::SpdySerializedFrame req1(
9891 spdy_util_.ConstructSpdyHeaders(1, std::move(req_block1), LOWEST, true));
9892 spdy::SpdyHeaderBlock req_block2(
9893 spdy_util_.ConstructPostHeaderBlock(kDefaultUrl, 0));
9894 spdy::SpdySerializedFrame req2(
9895 spdy_util_.ConstructSpdyHeaders(3, std::move(req_block2), LOWEST, true));
9896 MockWrite writes[] = {
9897 CreateMockWrite(req1, 0),
9898 CreateMockWrite(req2, 3),
9899 };
9900 spdy::SpdySerializedFrame resp1(
9901 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
9902 spdy::SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true));
9903 spdy::SpdySerializedFrame resp2(
9904 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
9905 spdy::SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(3, true));
9906 MockRead reads[] = {
9907 CreateMockRead(resp1, 1), CreateMockRead(body1, 2),
9908 CreateMockRead(resp2, 4), CreateMockRead(body2, 5),
9909 MockRead(ASYNC, 0, 6) // EOF
9910 };
9911
9912 SequencedSocketData data1(reads, writes);
9913 SequencedSocketData data2({}, {});
9914 UsePostRequest();
9915 auto session_deps = std::make_unique<SpdySessionDependencies>();
9916 session_deps->enable_early_data = true;
9917 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
9918 std::move(session_deps));
9919 auto ssl_provider1 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
9920 ssl_provider1->confirm = MockConfirm(ASYNC, OK);
9921 auto ssl_provider2 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
9922 ssl_provider2->confirm = MockConfirm(ASYNC, OK);
9923
9924 helper.RunPreTestSetup();
9925 helper.AddDataWithSSLSocketDataProvider(&data1, std::move(ssl_provider1));
9926 helper.AddDataWithSSLSocketDataProvider(&data2, std::move(ssl_provider2));
9927
9928 // TODO(https://crbug.com/949724): Explicitly verify the ordering of
9929 // ConfirmHandshake and the second stream.
9930
9931 HttpNetworkTransaction trans1(DEFAULT_PRIORITY, helper.session());
9932 HttpRequestInfo request1;
9933 request1.method = "GET";
9934 request1.url = GURL(kDefaultUrl);
9935 request1.traffic_annotation =
9936 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
9937 TestCompletionCallback callback1;
9938 int rv = trans1.Start(&request1, callback1.callback(), log_);
9939 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
9940
9941 HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session());
9942 HttpRequestInfo request2;
9943 request2.method = "POST";
9944 request2.url = GURL(kDefaultUrl);
9945 request2.traffic_annotation =
9946 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
9947 TestCompletionCallback callback2;
9948 rv = trans2.Start(&request2, callback2.callback(), log_);
9949 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
9950
9951 EXPECT_THAT(callback1.GetResult(ERR_IO_PENDING), IsOk());
9952 EXPECT_THAT(callback2.GetResult(ERR_IO_PENDING), IsOk());
9953
9954 const HttpResponseInfo* response1 = trans1.GetResponseInfo();
9955 ASSERT_TRUE(response1);
9956 ASSERT_TRUE(response1->headers);
9957 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP2,
9958 response1->connection_info);
9959 EXPECT_EQ("HTTP/1.1 200", response1->headers->GetStatusLine());
9960 std::string response_data;
9961 ReadTransaction(&trans1, &response_data);
9962 EXPECT_EQ("hello!", response_data);
9963
9964 const HttpResponseInfo* response2 = trans2.GetResponseInfo();
9965 ASSERT_TRUE(response2);
9966 ASSERT_TRUE(response2->headers);
9967 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP2,
9968 response2->connection_info);
9969 EXPECT_EQ("HTTP/1.1 200", response2->headers->GetStatusLine());
9970 ReadTransaction(&trans2, &response_data);
9971 EXPECT_EQ("hello!", response_data);
9972
9973 helper.VerifyDataConsumed();
9974}
9975
9976TEST_F(SpdyNetworkTransactionTest, ZeroRTTSyncConfirmSyncWrite) {
David Benjaminbae08ba2019-10-18 21:06:159977 static const base::TimeDelta kDelay = base::TimeDelta::FromMilliseconds(10);
Steven Valdez1c1859172019-04-10 15:33:289978 spdy::SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
9979 kDefaultUrl, 1, kUploadDataSize, LOWEST, nullptr, 0));
9980 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
9981 MockWrite writes[] = {
9982 CreateMockWrite(req, 0, SYNCHRONOUS),
9983 CreateMockWrite(body, 1), // POST upload frame
9984 };
9985
9986 spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
9987 MockRead reads[] = {
9988 CreateMockRead(resp, 2), CreateMockRead(body, 3),
9989 MockRead(ASYNC, 0, 4) // EOF
9990 };
9991
9992 SequencedSocketData data(reads, writes);
9993 UsePostRequest();
9994 auto session_deps = std::make_unique<SpdySessionDependencies>();
9995 session_deps->enable_early_data = true;
9996 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
9997 std::move(session_deps));
9998 auto ssl_provider = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
David Benjaminbae08ba2019-10-18 21:06:159999 ssl_provider->connect_callback = FastForwardByCallback(kDelay);
Steven Valdez1c1859172019-04-10 15:33:2810000 ssl_provider->confirm = MockConfirm(SYNCHRONOUS, OK);
David Benjaminbae08ba2019-10-18 21:06:1510001 ssl_provider->confirm_callback = FastForwardByCallback(kDelay);
10002 base::TimeTicks start_time = base::TimeTicks::Now();
Steven Valdez1c1859172019-04-10 15:33:2810003 helper.RunToCompletionWithSSLData(&data, std::move(ssl_provider));
10004 TransactionHelperResult out = helper.output();
10005 EXPECT_THAT(out.rv, IsOk());
10006 EXPECT_EQ("HTTP/1.1 200", out.status_line);
10007 EXPECT_EQ("hello!", out.response_data);
David Benjaminbae08ba2019-10-18 21:06:1510008
10009 // The handshake time should include the time it took to run Connect(), but
10010 // not ConfirmHandshake(). If ConfirmHandshake() returns synchronously, we
10011 // assume the connection did not negotiate 0-RTT or the handshake was already
10012 // confirmed.
10013 LoadTimingInfo load_timing_info;
10014 EXPECT_TRUE(helper.trans()->GetLoadTimingInfo(&load_timing_info));
10015 EXPECT_EQ(load_timing_info.connect_timing.connect_start, start_time);
10016 EXPECT_EQ(load_timing_info.connect_timing.ssl_start, start_time);
10017 EXPECT_EQ(load_timing_info.connect_timing.ssl_end, start_time + kDelay);
10018 EXPECT_EQ(load_timing_info.connect_timing.connect_end, start_time + kDelay);
Steven Valdez1c1859172019-04-10 15:33:2810019}
10020
10021TEST_F(SpdyNetworkTransactionTest, ZeroRTTSyncConfirmAsyncWrite) {
10022 spdy::SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
10023 kDefaultUrl, 1, kUploadDataSize, LOWEST, nullptr, 0));
10024 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
10025 MockWrite writes[] = {
10026 CreateMockWrite(req, 0, ASYNC),
10027 CreateMockWrite(body, 1), // POST upload frame
10028 };
10029
10030 spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
10031 MockRead reads[] = {
10032 CreateMockRead(resp, 2), CreateMockRead(body, 3),
10033 MockRead(ASYNC, 0, 4) // EOF
10034 };
10035
10036 SequencedSocketData data(reads, writes);
10037 UsePostRequest();
10038 auto session_deps = std::make_unique<SpdySessionDependencies>();
10039 session_deps->enable_early_data = true;
10040 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
10041 std::move(session_deps));
10042 auto ssl_provider = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
10043 ssl_provider->confirm = MockConfirm(SYNCHRONOUS, OK);
10044 helper.RunToCompletionWithSSLData(&data, std::move(ssl_provider));
10045 TransactionHelperResult out = helper.output();
10046 EXPECT_THAT(out.rv, IsOk());
10047 EXPECT_EQ("HTTP/1.1 200", out.status_line);
10048 EXPECT_EQ("hello!", out.response_data);
10049}
10050
10051TEST_F(SpdyNetworkTransactionTest, ZeroRTTAsyncConfirmSyncWrite) {
David Benjaminbae08ba2019-10-18 21:06:1510052 static const base::TimeDelta kDelay = base::TimeDelta::FromMilliseconds(10);
Steven Valdez1c1859172019-04-10 15:33:2810053 spdy::SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
10054 kDefaultUrl, 1, kUploadDataSize, LOWEST, nullptr, 0));
10055 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
10056 MockWrite writes[] = {
10057 CreateMockWrite(req, 0, SYNCHRONOUS),
10058 CreateMockWrite(body, 1), // POST upload frame
10059 };
10060
10061 spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
10062 MockRead reads[] = {
10063 CreateMockRead(resp, 2), CreateMockRead(body, 3),
10064 MockRead(ASYNC, 0, 4) // EOF
10065 };
10066
10067 SequencedSocketData data(reads, writes);
10068 UsePostRequest();
10069 auto session_deps = std::make_unique<SpdySessionDependencies>();
10070 session_deps->enable_early_data = true;
10071 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
10072 std::move(session_deps));
10073 auto ssl_provider = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
David Benjaminbae08ba2019-10-18 21:06:1510074 ssl_provider->connect_callback = FastForwardByCallback(kDelay);
Steven Valdez1c1859172019-04-10 15:33:2810075 ssl_provider->confirm = MockConfirm(ASYNC, OK);
David Benjaminbae08ba2019-10-18 21:06:1510076 ssl_provider->confirm_callback = FastForwardByCallback(kDelay);
10077 base::TimeTicks start_time = base::TimeTicks::Now();
Steven Valdez1c1859172019-04-10 15:33:2810078 helper.RunToCompletionWithSSLData(&data, std::move(ssl_provider));
10079 TransactionHelperResult out = helper.output();
10080 EXPECT_THAT(out.rv, IsOk());
10081 EXPECT_EQ("HTTP/1.1 200", out.status_line);
10082 EXPECT_EQ("hello!", out.response_data);
David Benjaminbae08ba2019-10-18 21:06:1510083
10084 // The handshake time should include the time it took to run Connect() and
10085 // ConfirmHandshake().
10086 LoadTimingInfo load_timing_info;
10087 EXPECT_TRUE(helper.trans()->GetLoadTimingInfo(&load_timing_info));
10088 EXPECT_EQ(load_timing_info.connect_timing.connect_start, start_time);
10089 EXPECT_EQ(load_timing_info.connect_timing.ssl_start, start_time);
10090 EXPECT_EQ(load_timing_info.connect_timing.ssl_end, start_time + 2 * kDelay);
10091 EXPECT_EQ(load_timing_info.connect_timing.connect_end,
10092 start_time + 2 * kDelay);
Steven Valdez1c1859172019-04-10 15:33:2810093}
10094
10095TEST_F(SpdyNetworkTransactionTest, ZeroRTTAsyncConfirmAsyncWrite) {
10096 spdy::SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
10097 kDefaultUrl, 1, kUploadDataSize, LOWEST, nullptr, 0));
10098 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
10099 MockWrite writes[] = {
10100 CreateMockWrite(req, 0, ASYNC),
10101 CreateMockWrite(body, 1), // POST upload frame
10102 };
10103
10104 spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
10105 MockRead reads[] = {
10106 CreateMockRead(resp, 2), CreateMockRead(body, 3),
10107 MockRead(ASYNC, 0, 4) // EOF
10108 };
10109
10110 SequencedSocketData data(reads, writes);
10111 UsePostRequest();
10112 auto session_deps = std::make_unique<SpdySessionDependencies>();
10113 session_deps->enable_early_data = true;
10114 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
10115 std::move(session_deps));
10116 auto ssl_provider = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
10117 ssl_provider->confirm = MockConfirm(ASYNC, OK);
10118 helper.RunToCompletionWithSSLData(&data, std::move(ssl_provider));
10119 TransactionHelperResult out = helper.output();
10120 EXPECT_THAT(out.rv, IsOk());
10121 EXPECT_EQ("HTTP/1.1 200", out.status_line);
10122 EXPECT_EQ("hello!", out.response_data);
10123}
10124
10125TEST_F(SpdyNetworkTransactionTest, ZeroRTTConfirmErrorSync) {
10126 spdy::SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
10127 kDefaultUrl, 1, kUploadDataSize, LOWEST, nullptr, 0));
10128 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
10129 MockWrite writes[] = {
10130 CreateMockWrite(req, 0), CreateMockWrite(body, 1), // POST upload frame
10131 };
10132
10133 spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
10134 MockRead reads[] = {
10135 CreateMockRead(resp, 2), CreateMockRead(body, 3),
10136 MockRead(ASYNC, 0, 4) // EOF
10137 };
10138
10139 SequencedSocketData data(reads, writes);
10140 UsePostRequest();
10141 auto session_deps = std::make_unique<SpdySessionDependencies>();
10142 session_deps->enable_early_data = true;
10143 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
10144 std::move(session_deps));
10145 auto ssl_provider = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
10146 ssl_provider->confirm = MockConfirm(SYNCHRONOUS, ERR_SSL_PROTOCOL_ERROR);
10147 helper.RunPreTestSetup();
10148 helper.AddDataWithSSLSocketDataProvider(&data, std::move(ssl_provider));
10149 helper.RunDefaultTest();
10150 TransactionHelperResult out = helper.output();
10151 EXPECT_THAT(out.rv, IsError(ERR_SSL_PROTOCOL_ERROR));
10152}
10153
10154TEST_F(SpdyNetworkTransactionTest, ZeroRTTConfirmErrorAsync) {
10155 spdy::SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
10156 kDefaultUrl, 1, kUploadDataSize, LOWEST, nullptr, 0));
10157 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
10158 MockWrite writes[] = {
10159 CreateMockWrite(req, 0), CreateMockWrite(body, 1), // POST upload frame
10160 };
10161
10162 spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
10163 MockRead reads[] = {
10164 CreateMockRead(resp, 2), CreateMockRead(body, 3),
10165 MockRead(ASYNC, 0, 4) // EOF
10166 };
10167
10168 SequencedSocketData data(reads, writes);
10169 UsePostRequest();
10170 auto session_deps = std::make_unique<SpdySessionDependencies>();
10171 session_deps->enable_early_data = true;
10172 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
10173 std::move(session_deps));
10174 auto ssl_provider = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
10175 ssl_provider->confirm = MockConfirm(ASYNC, ERR_SSL_PROTOCOL_ERROR);
10176 helper.RunPreTestSetup();
10177 helper.AddDataWithSSLSocketDataProvider(&data, std::move(ssl_provider));
10178 helper.RunDefaultTest();
10179 TransactionHelperResult out = helper.output();
10180 EXPECT_THAT(out.rv, IsError(ERR_SSL_PROTOCOL_ERROR));
10181}
10182
Bence Béky9eb57f62019-11-13 14:47:2510183TEST_F(SpdyNetworkTransactionTest, GreaseFrameTypeWithGetRequest) {
10184 auto session_deps = std::make_unique<SpdySessionDependencies>();
10185
10186 const uint8_t type = 0x0b;
10187 const uint8_t flags = 0xcc;
10188 const std::string payload("foo");
10189 session_deps->greased_http2_frame =
10190 base::Optional<net::SpdySessionPool::GreasedHttp2Frame>(
10191 {type, flags, payload});
10192
10193 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
10194 std::move(session_deps));
10195
10196 spdy::SpdyHeaderBlock headers(
10197 spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
10198 spdy::SpdySerializedFrame req(
10199 spdy_util_.ConstructSpdyHeaders(1, std::move(headers), DEFAULT_PRIORITY,
10200 /* fin = */ false));
10201
10202 const char kRawFrameData[] = {
10203 0x00, 0x00, 0x03, // length
10204 0x0b, // type
10205 0xcc, // flags
10206 0x00, 0x00, 0x00, 0x01, // stream ID
10207 'f', 'o', 'o' // payload
10208 };
10209 spdy::SpdySerializedFrame grease(const_cast<char*>(kRawFrameData),
10210 base::size(kRawFrameData),
10211 /* owns_buffer = */ false);
10212 spdy::SpdySerializedFrame empty_body(
10213 spdy_util_.ConstructSpdyDataFrame(1, "", true));
10214
10215 MockWrite writes[] = {CreateMockWrite(req, 0), CreateMockWrite(grease, 1),
10216 CreateMockWrite(empty_body, 2)};
10217
10218 spdy::SpdySerializedFrame resp(
10219 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
10220 spdy::SpdySerializedFrame response_body(
10221 spdy_util_.ConstructSpdyDataFrame(1, true));
10222
10223 MockRead reads[] = {CreateMockRead(resp, 3), CreateMockRead(response_body, 4),
10224 MockRead(ASYNC, 0, 5)};
10225
10226 SequencedSocketData data(reads, writes);
10227 helper.RunPreTestSetup();
10228 helper.AddData(&data);
10229
10230 TestCompletionCallback callback;
10231 int rv = helper.trans()->Start(&request_, callback.callback(), log_);
10232 EXPECT_THAT(callback.GetResult(rv), IsOk());
10233
10234 base::RunLoop().RunUntilIdle();
10235
10236 helper.VerifyDataConsumed();
10237}
10238
10239TEST_F(SpdyNetworkTransactionTest, GreaseFrameTypeWithPostRequest) {
10240 UsePostRequest();
10241
10242 auto session_deps = std::make_unique<SpdySessionDependencies>();
10243
10244 const uint8_t type = 0x0b;
10245 const uint8_t flags = 0xcc;
10246 const std::string payload("foo");
10247 session_deps->greased_http2_frame =
10248 base::Optional<net::SpdySessionPool::GreasedHttp2Frame>(
10249 {type, flags, payload});
10250
10251 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
10252 std::move(session_deps));
10253
10254 spdy::SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
10255 kDefaultUrl, 1, kUploadDataSize, LOWEST, nullptr, 0));
10256
10257 const char kRawFrameData[] = {
10258 0x00, 0x00, 0x03, // length
10259 0x0b, // type
10260 0xcc, // flags
10261 0x00, 0x00, 0x00, 0x01, // stream ID
10262 'f', 'o', 'o' // payload
10263 };
10264 spdy::SpdySerializedFrame grease(const_cast<char*>(kRawFrameData),
10265 base::size(kRawFrameData),
10266 /* owns_buffer = */ false);
10267 spdy::SpdySerializedFrame request_body(
10268 spdy_util_.ConstructSpdyDataFrame(1, true));
10269
10270 MockWrite writes[] = {CreateMockWrite(req, 0), CreateMockWrite(grease, 1),
10271 CreateMockWrite(request_body, 2)};
10272
10273 spdy::SpdySerializedFrame resp(
10274 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
10275 spdy::SpdySerializedFrame response_body(
10276 spdy_util_.ConstructSpdyDataFrame(1, true));
10277
10278 MockRead reads[] = {CreateMockRead(resp, 3), CreateMockRead(response_body, 4),
10279 MockRead(ASYNC, 0, 5)};
10280
10281 SequencedSocketData data(reads, writes);
10282 helper.RunPreTestSetup();
10283 helper.AddData(&data);
10284
10285 TestCompletionCallback callback;
10286 int rv = helper.trans()->Start(&request_, callback.callback(), log_);
10287 EXPECT_THAT(callback.GetResult(rv), IsOk());
10288
10289 base::RunLoop().RunUntilIdle();
10290
10291 helper.VerifyDataConsumed();
10292}
10293
Bence Béky21755dd62019-11-19 13:47:3510294// According to https://httpwg.org/specs/rfc7540.html#CONNECT, "frame types
10295// other than DATA or stream management frames (RST_STREAM, WINDOW_UPDATE, and
10296// PRIORITY) MUST NOT be sent on a connected stream".
10297TEST_F(SpdyNetworkTransactionTest, DoNotGreaseFrameTypeWithConnect) {
10298 auto session_deps = std::make_unique<SpdySessionDependencies>(
Nicolas Arciniegad2013f92020-02-07 23:00:5610299 ConfiguredProxyResolutionService::CreateFixedFromPacResult(
Bence Béky21755dd62019-11-19 13:47:3510300 "HTTPS myproxy:70", TRAFFIC_ANNOTATION_FOR_TESTS));
10301
10302 const uint8_t type = 0x0b;
10303 const uint8_t flags = 0xcc;
10304 const std::string payload("foo");
10305 session_deps->greased_http2_frame =
10306 base::Optional<net::SpdySessionPool::GreasedHttp2Frame>(
10307 {type, flags, payload});
10308
10309 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
10310 std::move(session_deps));
10311
10312 // CONNECT to proxy.
10313 spdy::SpdySerializedFrame connect_req(spdy_util_.ConstructSpdyConnect(
10314 nullptr, 0, 1, HttpProxyConnectJob::kH2QuicTunnelPriority,
10315 HostPortPair("www.example.org", 443)));
10316 spdy::SpdySerializedFrame connect_response(
10317 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
10318
10319 // Tunneled transaction wrapped in DATA frames.
10320 const char req[] =
10321 "GET / HTTP/1.1\r\n"
10322 "Host: www.example.org\r\n"
10323 "Connection: keep-alive\r\n\r\n";
10324 spdy::SpdySerializedFrame tunneled_req(
10325 spdy_util_.ConstructSpdyDataFrame(1, req, false));
10326
10327 const char resp[] =
10328 "HTTP/1.1 200 OK\r\n"
10329 "Content-Length: 5\r\n\r\n"
10330 "hello";
10331 spdy::SpdySerializedFrame tunneled_response(
10332 spdy_util_.ConstructSpdyDataFrame(1, resp, false));
10333
10334 MockWrite writes[] = {CreateMockWrite(connect_req, 0),
10335 CreateMockWrite(tunneled_req, 2)};
10336
10337 MockRead reads[] = {CreateMockRead(connect_response, 1),
10338 CreateMockRead(tunneled_response, 3),
10339 MockRead(ASYNC, 0, 4)};
10340
10341 SequencedSocketData data0(reads, writes);
10342
10343 // HTTP/2 connection to proxy.
10344 auto ssl_provider0 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
10345 ssl_provider0->next_proto = kProtoHTTP2;
10346 helper.AddDataWithSSLSocketDataProvider(&data0, std::move(ssl_provider0));
10347
10348 // HTTP/1.1 to destination.
10349 SSLSocketDataProvider ssl_provider1(ASYNC, OK);
10350 ssl_provider1.next_proto = kProtoHTTP11;
10351 helper.session_deps()->socket_factory->AddSSLSocketDataProvider(
10352 &ssl_provider1);
10353
10354 helper.RunPreTestSetup();
10355 helper.StartDefaultTest();
10356 helper.FinishDefaultTestWithoutVerification();
10357 helper.VerifyDataConsumed();
10358
10359 const HttpResponseInfo* response = helper.trans()->GetResponseInfo();
10360 ASSERT_TRUE(response);
10361 ASSERT_TRUE(response->headers);
10362 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
10363 EXPECT_FALSE(response->was_fetched_via_spdy);
10364 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP1_1,
10365 response->connection_info);
10366 EXPECT_TRUE(response->was_alpn_negotiated);
10367 EXPECT_TRUE(request_.url.SchemeIs("https"));
10368 EXPECT_EQ("127.0.0.1", response->remote_endpoint.ToStringWithoutPort());
10369 EXPECT_EQ(70, response->remote_endpoint.port());
10370 std::string response_data;
10371 ASSERT_THAT(ReadTransaction(helper.trans(), &response_data), IsOk());
10372 EXPECT_EQ("hello", response_data);
10373}
10374
Bence Béky087d4ba2020-05-13 23:10:2810375// Regression test for https://crbug.com/1081955.
10376// Greasing frame types is enabled, the outgoing HEADERS frame is followed by a
10377// frame of reserved type, then an empty DATA frame to close the stream.
10378// Response arrives before reserved frame and DATA frame can be sent.
10379// SpdyHttpStream::OnDataSent() must not crash.
10380TEST_F(SpdyNetworkTransactionTest, OnDataSentDoesNotCrashWithGreasedFrameType) {
10381 auto session_deps = std::make_unique<SpdySessionDependencies>();
10382
10383 const uint8_t type = 0x0b;
10384 const uint8_t flags = 0xcc;
10385 const std::string payload("foo");
10386 session_deps->greased_http2_frame =
10387 base::Optional<net::SpdySessionPool::GreasedHttp2Frame>(
10388 {type, flags, payload});
10389
10390 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
10391 std::move(session_deps));
10392
10393 spdy::SpdyHeaderBlock headers(
10394 spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
10395 spdy::SpdySerializedFrame req(
10396 spdy_util_.ConstructSpdyHeaders(1, std::move(headers), DEFAULT_PRIORITY,
10397 /* fin = */ false));
10398
10399 const char kRawFrameData[] = {
10400 0x00, 0x00, 0x03, // length
10401 0x0b, // type
10402 0xcc, // flags
10403 0x00, 0x00, 0x00, 0x01, // stream ID
10404 'f', 'o', 'o' // payload
10405 };
10406 spdy::SpdySerializedFrame grease(const_cast<char*>(kRawFrameData),
10407 base::size(kRawFrameData),
10408 /* owns_buffer = */ false);
10409 spdy::SpdySerializedFrame empty_body(
10410 spdy_util_.ConstructSpdyDataFrame(1, "", true));
10411
10412 MockWrite writes[] = {
10413 CreateMockWrite(req, 0), MockWrite(ASYNC, ERR_IO_PENDING, 2),
10414 CreateMockWrite(grease, 3), CreateMockWrite(empty_body, 4)};
10415
10416 spdy::SpdySerializedFrame resp(
10417 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
10418 spdy::SpdySerializedFrame response_body(
10419 spdy_util_.ConstructSpdyDataFrame(1, true));
10420
10421 MockRead reads[] = {CreateMockRead(resp, 1), CreateMockRead(response_body, 5),
10422 MockRead(ASYNC, 0, 6)};
10423
10424 SequencedSocketData data(reads, writes);
10425 helper.RunPreTestSetup();
10426 helper.AddData(&data);
10427
10428 TestCompletionCallback callback;
10429 int rv = helper.trans()->Start(&request_, callback.callback(), log_);
10430 base::RunLoop().RunUntilIdle();
10431
10432 // Response headers received. Resume sending |grease| and |empty_body|.
10433 data.Resume();
10434 EXPECT_THAT(callback.GetResult(rv), IsOk());
10435
10436 base::RunLoop().RunUntilIdle();
10437
10438 helper.VerifyDataConsumed();
10439}
10440
[email protected]aea80602009-09-18 00:55:0810441} // namespace net