blob: 2106dce5adabd018a83bbfb0a170d9c920c51424 [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"
danakjdb9ae7942020-11-11 16:01:3510#include "base/callback_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"
Matt Menke4807a9a2020-11-21 00:14:4132#include "net/base/schemeful_site.h"
tbansal28e68f82016-02-04 02:56:1533#include "net/base/test_proxy_delegate.h"
[email protected]b2d26cfd2012-12-11 10:36:0634#include "net/base/upload_bytes_element_reader.h"
[email protected]b2d26cfd2012-12-11 10:36:0635#include "net/base/upload_file_element_reader.h"
Bence Béky1a5d8562018-01-05 17:29:2836#include "net/dns/mock_host_resolver.h"
Ben Schwartz3ff4dc1e62021-04-27 21:15:2337#include "net/dns/public/secure_dns_policy.h"
aberentbba302d2015-12-03 10:20:1938#include "net/http/http_auth_scheme.h"
bnc3171a2432016-12-28 18:40:2639#include "net/http/http_network_session.h"
[email protected]87bfa3f2010-09-30 14:54:5640#include "net/http/http_network_session_peer.h"
[email protected]513963e2013-06-15 01:53:0441#include "net/http/http_network_transaction.h"
Matt Menke6e879bd2019-03-18 17:26:0442#include "net/http/http_proxy_connect_job.h"
Bence Béky3a0c48532018-03-02 13:38:5143#include "net/http/http_response_info.h"
[email protected]513963e2013-06-15 01:53:0444#include "net/http/http_server_properties.h"
[email protected]c41737d2014-05-14 07:47:1945#include "net/http/http_transaction_test_util.h"
Yoichi Osato4c75c0c2020-06-24 08:03:5746#include "net/http/test_upload_data_stream_not_allow_http1.h"
Matt Menkec74a9262020-06-09 15:49:2147#include "net/http/transport_security_state.h"
mikecirone8b85c432016-09-08 19:11:0048#include "net/log/net_log_event_type.h"
mikecironef22f9812016-10-04 03:40:1949#include "net/log/net_log_with_source.h"
mmenke16a7cbdd2015-04-24 23:00:5650#include "net/log/test_net_log.h"
mmenke43758e62015-05-04 21:09:4651#include "net/log/test_net_log_util.h"
Nicolas Arciniega8ec5bfa2020-03-20 05:07:2652#include "net/proxy_resolution/configured_proxy_resolution_service.h"
[email protected]bb88e1d32013-05-03 23:11:0753#include "net/socket/next_proto.h"
Paul Jensena457017a2018-01-19 23:52:0454#include "net/socket/socket_tag.h"
Bence Béky78b542c2021-03-25 19:30:3755#include "net/spdy/alps_decoder.h"
Bence Béky94658bf2018-05-11 19:22:5856#include "net/spdy/buffered_spdy_framer.h"
57#include "net/spdy/spdy_http_stream.h"
58#include "net/spdy/spdy_http_utils.h"
59#include "net/spdy/spdy_session.h"
60#include "net/spdy/spdy_session_pool.h"
61#include "net/spdy/spdy_test_util_common.h"
[email protected]514aeaf2014-05-23 10:31:5162#include "net/ssl/ssl_connection_status_flags.h"
bncce36dca22015-04-21 22:11:2363#include "net/test/cert_test_util.h"
robpercival214763f2016-07-01 23:27:0164#include "net/test/gtest_util.h"
rsleevia69c79a2016-06-22 03:28:4365#include "net/test/test_data_directory.h"
Gabriel Charettec7108742019-08-23 03:31:4066#include "net/test/test_with_task_environment.h"
Victor Vasiliev27cc7712019-01-24 11:50:1467#include "net/third_party/quiche/src/spdy/core/spdy_protocol.h"
68#include "net/third_party/quiche/src/spdy/core/spdy_test_utils.h"
rhalavati9ebaba7e2017-04-27 06:16:2969#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
[email protected]d2db0292011-01-26 20:23:4470#include "net/url_request/url_request_test_util.h"
Bence Béky0ca719f2018-01-31 13:41:1971#include "net/websockets/websocket_test_util.h"
[email protected]251029e2014-03-19 06:04:4072#include "testing/gmock/include/gmock/gmock.h"
[email protected]aea80602009-09-18 00:55:0873#include "testing/platform_test.h"
Matt Menke4807a9a2020-11-21 00:14:4174#include "url/gurl.h"
[email protected]aea80602009-09-18 00:55:0875
robpercival214763f2016-07-01 23:27:0176using net::test::IsError;
77using net::test::IsOk;
78
[email protected]aea80602009-09-18 00:55:0879//-----------------------------------------------------------------------------
80
[email protected]d1eda932009-11-04 01:03:1081namespace net {
[email protected]dae22c52010-07-30 02:16:3582
[email protected]cbdd73162013-03-18 23:27:3383namespace {
[email protected]251029e2014-03-19 06:04:4084
85using testing::Each;
86using testing::Eq;
87
xunjieli179a6e72016-04-26 19:47:4588const int32_t kBufferSize = SpdyHttpStream::kRequestBodyBufferSize;
89
[email protected]513963e2013-06-15 01:53:0490} // namespace
91
Bence Békyd2df6c1c82018-04-20 22:52:0192const char kPushedUrl[] = "https://www.example.org/foo.dat";
93
Gabriel Charette694c3c332019-08-19 14:53:0594class SpdyNetworkTransactionTest : public TestWithTaskEnvironment {
[email protected]34437af82009-11-06 02:28:4995 protected:
rdsmithebb50aa2015-11-12 03:44:3896 SpdyNetworkTransactionTest()
David Benjaminbae08ba2019-10-18 21:06:1597 : TestWithTaskEnvironment(
98 base::test::TaskEnvironment::TimeSource::MOCK_TIME),
99 default_url_(kDefaultUrl),
bncd16676a2016-07-20 16:23:01100 host_port_pair_(HostPortPair::FromURL(default_url_)) {}
[email protected]2d6728692011-03-12 01:39:55101
bncd16676a2016-07-20 16:23:01102 ~SpdyNetworkTransactionTest() override {
Bence Békydb3cf652017-10-10 15:22:10103 // UploadDataStream may post a deletion task back to the message loop on
[email protected]fc9d88472013-08-14 02:31:17104 // destruction.
105 upload_data_stream_.reset();
106 base::RunLoop().RunUntilIdle();
107 }
108
dcheng67be2b1f2014-10-27 21:47:29109 void SetUp() override {
Bence Békydb3cf652017-10-10 15:22:10110 request_.method = "GET";
111 request_.url = GURL(kDefaultUrl);
Ramin Halavatib5e433e62018-02-07 07:41:10112 request_.traffic_annotation =
113 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
[email protected]69e6b4a2012-10-18 08:03:01114 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
[email protected]aea80602009-09-18 00:55:08115 }
116
[email protected]72552f02009-10-28 15:25:01117 struct TransactionHelperResult {
[email protected]aea80602009-09-18 00:55:08118 int rv;
Bence Béky4e83f492018-05-13 23:14:25119 std::string status_line;
120 std::string response_data;
[email protected]8b070372009-11-16 22:01:25121 HttpResponseInfo response_info;
[email protected]aea80602009-09-18 00:55:08122 };
123
[email protected]3caf5542010-07-16 15:19:47124 // A helper class that handles all the initial npn/ssl setup.
125 class NormalSpdyTransactionHelper {
126 public:
rdsmith82957ad2015-09-16 19:42:03127 NormalSpdyTransactionHelper(
128 const HttpRequestInfo& request,
129 RequestPriority priority,
tfarina428341112016-09-22 13:38:20130 const NetLogWithSource& log,
danakjaee3e1ec2016-04-16 00:23:18131 std::unique_ptr<SpdySessionDependencies> session_deps)
[email protected]30c942b2010-07-21 16:59:59132 : request_(request),
[email protected]262eec82013-03-19 21:01:36133 priority_(priority),
tombergan5d22c182017-01-11 02:05:35134 session_deps_(session_deps.get() == nullptr
Jeremy Roman0579ed62017-08-29 15:56:19135 ? std::make_unique<SpdySessionDependencies>()
bncd16676a2016-07-20 16:23:01136 : std::move(session_deps)),
xunjieli925519532017-01-30 15:33:17137 log_(log) {
138 session_deps_->net_log = log.net_log();
139 session_ =
140 SpdySessionDependencies::SpdyCreateSession(session_deps_.get());
141 }
[email protected]61b4efc2012-04-27 18:12:50142
[email protected]19ec8a72010-08-23 03:38:23143 ~NormalSpdyTransactionHelper() {
144 // Any test which doesn't close the socket by sending it an EOF will
145 // have a valid session left open, which leaks the entire session pool.
146 // This is just fine - in fact, some of our tests intentionally do this
147 // so that we can check consistency of the SpdySessionPool as the test
148 // finishes. If we had put an EOF on the socket, the SpdySession would
149 // have closed and we wouldn't be able to check the consistency.
150
151 // Forcefully close existing sessions here.
152 session()->spdy_session_pool()->CloseAllSessions();
153 }
154
[email protected]3caf5542010-07-16 15:19:47155 void RunPreTestSetup() {
[email protected]3caf5542010-07-16 15:19:47156 // We're now ready to use SSL-npn SPDY.
bnc3f6a8552017-05-17 13:40:34157 trans_ =
Jeremy Roman0579ed62017-08-29 15:56:19158 std::make_unique<HttpNetworkTransaction>(priority_, session_.get());
[email protected]cb54b3b22010-06-03 16:28:55159 }
[email protected]aea80602009-09-18 00:55:08160
[email protected]3caf5542010-07-16 15:19:47161 // Start the transaction, read some data, finish.
162 void RunDefaultTest() {
[email protected]34b345f92013-02-22 03:27:26163 if (!StartDefaultTest())
164 return;
165 FinishDefaultTest();
166 }
167
168 bool StartDefaultTest() {
[email protected]514aeaf2014-05-23 10:31:51169 output_.rv = trans_->Start(&request_, callback_.callback(), log_);
[email protected]aea80602009-09-18 00:55:08170
[email protected]3caf5542010-07-16 15:19:47171 // We expect an IO Pending or some sort of error.
172 EXPECT_LT(output_.rv, 0);
[email protected]34b345f92013-02-22 03:27:26173 return output_.rv == ERR_IO_PENDING;
174 }
[email protected]aea80602009-09-18 00:55:08175
[email protected]34b345f92013-02-22 03:27:26176 void FinishDefaultTest() {
[email protected]514aeaf2014-05-23 10:31:51177 output_.rv = callback_.WaitForResult();
bnceb9aa7112017-01-05 01:03:46178 // Finish async network reads/writes.
179 base::RunLoop().RunUntilIdle();
[email protected]3caf5542010-07-16 15:19:47180 if (output_.rv != OK) {
bnc301745a2015-03-10 03:22:16181 session_->spdy_session_pool()->CloseCurrentSessions(ERR_ABORTED);
[email protected]3caf5542010-07-16 15:19:47182 return;
183 }
[email protected]ff57bb82009-11-12 06:52:14184
[email protected]3caf5542010-07-16 15:19:47185 // Verify responses.
186 const HttpResponseInfo* response = trans_->GetResponseInfo();
wezca1070932016-05-26 20:30:52187 ASSERT_TRUE(response);
188 ASSERT_TRUE(response->headers);
bnc80bb1d42016-10-26 18:11:34189 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP2,
bnc927c4962016-07-21 14:45:59190 response->connection_info);
191 EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
192 EXPECT_TRUE(response->was_fetched_via_spdy);
bnc94c92842016-09-21 15:22:52193 EXPECT_TRUE(response->was_alpn_negotiated);
Tsuyoshi Horo01faed62019-02-20 22:11:37194 EXPECT_EQ("127.0.0.1", response->remote_endpoint.ToStringWithoutPort());
195 EXPECT_EQ(443, response->remote_endpoint.port());
[email protected]3caf5542010-07-16 15:19:47196 output_.status_line = response->headers->GetStatusLine();
197 output_.response_info = *response; // Make a copy so we can verify.
198 output_.rv = ReadTransaction(trans_.get(), &output_.response_data);
[email protected]3caf5542010-07-16 15:19:47199 }
200
bncfacdd852015-01-09 19:22:54201 void FinishDefaultTestWithoutVerification() {
202 output_.rv = callback_.WaitForResult();
bnceb9aa7112017-01-05 01:03:46203 // Finish async network reads/writes.
204 base::RunLoop().RunUntilIdle();
bncfacdd852015-01-09 19:22:54205 if (output_.rv != OK)
bnc301745a2015-03-10 03:22:16206 session_->spdy_session_pool()->CloseCurrentSessions(ERR_ABORTED);
bncfacdd852015-01-09 19:22:54207 }
208
maksim.sisov8d2df66d2016-06-20 07:07:11209 void WaitForCallbackToComplete() { output_.rv = callback_.WaitForResult(); }
mmenke666a6fea2015-12-19 04:16:33210
[email protected]3caf5542010-07-16 15:19:47211 // Most tests will want to call this function. In particular, the MockReads
212 // should end with an empty read, and that read needs to be processed to
213 // ensure proper deletion of the spdy_session_pool.
214 void VerifyDataConsumed() {
rch08e3aa3e2015-05-16 14:27:52215 for (const SocketDataProvider* provider : data_vector_) {
216 EXPECT_TRUE(provider->AllReadDataConsumed());
217 EXPECT_TRUE(provider->AllWriteDataConsumed());
[email protected]3caf5542010-07-16 15:19:47218 }
219 }
220
221 // Occasionally a test will expect to error out before certain reads are
222 // processed. In that case we want to explicitly ensure that the reads were
223 // not processed.
224 void VerifyDataNotConsumed() {
rch08e3aa3e2015-05-16 14:27:52225 for (const SocketDataProvider* provider : data_vector_) {
226 EXPECT_FALSE(provider->AllReadDataConsumed());
227 EXPECT_FALSE(provider->AllWriteDataConsumed());
[email protected]3caf5542010-07-16 15:19:47228 }
229 }
230
rch08e3aa3e2015-05-16 14:27:52231 void RunToCompletion(SocketDataProvider* data) {
[email protected]3caf5542010-07-16 15:19:47232 RunPreTestSetup();
[email protected]e3ebba0f2010-08-05 17:59:58233 AddData(data);
[email protected]3caf5542010-07-16 15:19:47234 RunDefaultTest();
235 VerifyDataConsumed();
236 }
[email protected]e6b06862010-07-20 16:32:58237
[email protected]514aeaf2014-05-23 10:31:51238 void RunToCompletionWithSSLData(
rch08e3aa3e2015-05-16 14:27:52239 SocketDataProvider* data,
danakjaee3e1ec2016-04-16 00:23:18240 std::unique_ptr<SSLSocketDataProvider> ssl_provider) {
[email protected]514aeaf2014-05-23 10:31:51241 RunPreTestSetup();
dchengc7eeda422015-12-26 03:56:48242 AddDataWithSSLSocketDataProvider(data, std::move(ssl_provider));
[email protected]514aeaf2014-05-23 10:31:51243 RunDefaultTest();
244 VerifyDataConsumed();
245 }
246
rch08e3aa3e2015-05-16 14:27:52247 void AddData(SocketDataProvider* data) {
Jeremy Roman0579ed62017-08-29 15:56:19248 auto ssl_provider = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
Ryan Sleevi4f832092017-11-21 23:25:49249 ssl_provider->ssl_info.cert =
bncce36dca22015-04-21 22:11:23250 ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem");
dchengc7eeda422015-12-26 03:56:48251 AddDataWithSSLSocketDataProvider(data, std::move(ssl_provider));
[email protected]514aeaf2014-05-23 10:31:51252 }
253
254 void AddDataWithSSLSocketDataProvider(
rch08e3aa3e2015-05-16 14:27:52255 SocketDataProvider* data,
danakjaee3e1ec2016-04-16 00:23:18256 std::unique_ptr<SSLSocketDataProvider> ssl_provider) {
[email protected]3caf5542010-07-16 15:19:47257 data_vector_.push_back(data);
bnc3cf2a592016-08-11 14:48:36258 if (ssl_provider->next_proto == kProtoUnknown)
259 ssl_provider->next_proto = kProtoHTTP2;
rchebf12982015-04-10 01:15:00260
261 session_deps_->socket_factory->AddSSLSocketDataProvider(
262 ssl_provider.get());
olli.raulaae011c422015-12-10 07:38:51263 ssl_vector_.push_back(std::move(ssl_provider));
[email protected]d4f00222012-07-10 06:24:51264
[email protected]3b7828432010-08-18 18:33:27265 session_deps_->socket_factory->AddSocketDataProvider(data);
266 }
267
Cammie Smith Barnes5191037b72021-03-01 22:06:53268 size_t GetSpdySessionCount() {
269 std::unique_ptr<base::Value> value(
270 session_->spdy_session_pool()->SpdySessionPoolInfoToValue());
271 CHECK(value && value->is_list());
272 return value->GetList().size();
273 }
274
[email protected]3caf5542010-07-16 15:19:47275 HttpNetworkTransaction* trans() { return trans_.get(); }
276 void ResetTrans() { trans_.reset(); }
bnc4d782f492016-08-18 13:50:00277 const TransactionHelperResult& output() { return output_; }
mmenkee65e7af2015-10-13 17:16:42278 HttpNetworkSession* session() const { return session_.get(); }
bncd16676a2016-07-20 16:23:01279 SpdySessionDependencies* session_deps() { return session_deps_.get(); }
[email protected]3caf5542010-07-16 15:19:47280
281 private:
rch08e3aa3e2015-05-16 14:27:52282 typedef std::vector<SocketDataProvider*> DataVector;
danakjaee3e1ec2016-04-16 00:23:18283 typedef std::vector<std::unique_ptr<SSLSocketDataProvider>> SSLVector;
284 typedef std::vector<std::unique_ptr<SocketDataProvider>> AlternateVector;
Bence Békydb3cf652017-10-10 15:22:10285 const HttpRequestInfo request_;
286 const RequestPriority priority_;
danakjaee3e1ec2016-04-16 00:23:18287 std::unique_ptr<SpdySessionDependencies> session_deps_;
288 std::unique_ptr<HttpNetworkSession> session_;
[email protected]3caf5542010-07-16 15:19:47289 TransactionHelperResult output_;
[email protected]3caf5542010-07-16 15:19:47290 SSLVector ssl_vector_;
[email protected]514aeaf2014-05-23 10:31:51291 TestCompletionCallback callback_;
danakjaee3e1ec2016-04-16 00:23:18292 std::unique_ptr<HttpNetworkTransaction> trans_;
[email protected]3caf5542010-07-16 15:19:47293 DataVector data_vector_;
tfarina428341112016-09-22 13:38:20294 const NetLogWithSource log_;
[email protected]3caf5542010-07-16 15:19:47295 };
[email protected]aea80602009-09-18 00:55:08296
297 void ConnectStatusHelperWithExpectedStatus(const MockRead& status,
298 int expected_status);
299
300 void ConnectStatusHelper(const MockRead& status);
[email protected]d3cee19d2010-06-22 18:42:18301
Bence Békydb3cf652017-10-10 15:22:10302 HttpRequestInfo CreateGetPushRequest() const WARN_UNUSED_RESULT {
303 HttpRequestInfo request;
304 request.method = "GET";
Bence Békyd2df6c1c82018-04-20 22:52:01305 request.url = GURL(kPushedUrl);
Ramin Halavatib5e433e62018-02-07 07:41:10306 request.traffic_annotation =
307 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
Bence Békydb3cf652017-10-10 15:22:10308 return request;
[email protected]e3ebba0f2010-08-05 17:59:58309 }
310
Bence Békydb3cf652017-10-10 15:22:10311 void UsePostRequest() {
312 ASSERT_FALSE(upload_data_stream_);
313 std::vector<std::unique_ptr<UploadElementReader>> element_readers;
314 element_readers.push_back(std::make_unique<UploadBytesElementReader>(
315 kUploadData, kUploadDataSize));
316 upload_data_stream_ = std::make_unique<ElementsUploadDataStream>(
317 std::move(element_readers), 0);
318
319 request_.method = "POST";
320 request_.upload_data_stream = upload_data_stream_.get();
[email protected]d3cee19d2010-06-22 18:42:18321 }
322
Bence Békydb3cf652017-10-10 15:22:10323 void UseFilePostRequest() {
324 ASSERT_FALSE(upload_data_stream_);
325 base::FilePath file_path;
326 CHECK(base::CreateTemporaryFileInDir(temp_dir_.GetPath(), &file_path));
327 CHECK_EQ(static_cast<int>(kUploadDataSize),
328 base::WriteFile(file_path, kUploadData, kUploadDataSize));
329
330 std::vector<std::unique_ptr<UploadElementReader>> element_readers;
331 element_readers.push_back(std::make_unique<UploadFileElementReader>(
332 base::ThreadTaskRunnerHandle::Get().get(), file_path, 0,
333 kUploadDataSize, base::Time()));
334 upload_data_stream_ = std::make_unique<ElementsUploadDataStream>(
335 std::move(element_readers), 0);
336
337 request_.method = "POST";
338 request_.upload_data_stream = upload_data_stream_.get();
Ramin Halavatib5e433e62018-02-07 07:41:10339 request_.traffic_annotation =
340 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
[email protected]3deb9a52010-11-11 00:24:40341 }
342
Bence Békydb3cf652017-10-10 15:22:10343 void UseUnreadableFilePostRequest() {
344 ASSERT_FALSE(upload_data_stream_);
[email protected]999dd8c2013-11-12 06:45:54345 base::FilePath file_path;
vabrb8582322016-09-09 08:05:37346 CHECK(base::CreateTemporaryFileInDir(temp_dir_.GetPath(), &file_path));
[email protected]999dd8c2013-11-12 06:45:54347 CHECK_EQ(static_cast<int>(kUploadDataSize),
[email protected]e5c2a22e2014-03-06 20:42:30348 base::WriteFile(file_path, kUploadData, kUploadDataSize));
[email protected]92be8eb2014-08-07 22:57:11349 CHECK(base::MakeFileUnreadable(file_path));
[email protected]999dd8c2013-11-12 06:45:54350
danakjaee3e1ec2016-04-16 00:23:18351 std::vector<std::unique_ptr<UploadElementReader>> element_readers;
Jeremy Roman0579ed62017-08-29 15:56:19352 element_readers.push_back(std::make_unique<UploadFileElementReader>(
skyostil4891b25b2015-06-11 11:43:45353 base::ThreadTaskRunnerHandle::Get().get(), file_path, 0,
ricea2deef682016-09-09 08:04:07354 kUploadDataSize, base::Time()));
Jeremy Roman0579ed62017-08-29 15:56:19355 upload_data_stream_ = std::make_unique<ElementsUploadDataStream>(
bnc3f6a8552017-05-17 13:40:34356 std::move(element_readers), 0);
[email protected]999dd8c2013-11-12 06:45:54357
Bence Békydb3cf652017-10-10 15:22:10358 request_.method = "POST";
359 request_.upload_data_stream = upload_data_stream_.get();
[email protected]999dd8c2013-11-12 06:45:54360 }
361
Bence Békydb3cf652017-10-10 15:22:10362 void UseComplexPostRequest() {
363 ASSERT_FALSE(upload_data_stream_);
364 const int kFileRangeOffset = 1;
365 const int kFileRangeLength = 3;
366 CHECK_LT(kFileRangeOffset + kFileRangeLength, kUploadDataSize);
[email protected]69e6b4a2012-10-18 08:03:01367
Bence Békydb3cf652017-10-10 15:22:10368 base::FilePath file_path;
369 CHECK(base::CreateTemporaryFileInDir(temp_dir_.GetPath(), &file_path));
370 CHECK_EQ(static_cast<int>(kUploadDataSize),
371 base::WriteFile(file_path, kUploadData, kUploadDataSize));
[email protected]69e6b4a2012-10-18 08:03:01372
Bence Békydb3cf652017-10-10 15:22:10373 std::vector<std::unique_ptr<UploadElementReader>> element_readers;
374 element_readers.push_back(std::make_unique<UploadBytesElementReader>(
375 kUploadData, kFileRangeOffset));
376 element_readers.push_back(std::make_unique<UploadFileElementReader>(
377 base::ThreadTaskRunnerHandle::Get().get(), file_path, kFileRangeOffset,
378 kFileRangeLength, base::Time()));
379 element_readers.push_back(std::make_unique<UploadBytesElementReader>(
380 kUploadData + kFileRangeOffset + kFileRangeLength,
381 kUploadDataSize - (kFileRangeOffset + kFileRangeLength)));
382 upload_data_stream_ = std::make_unique<ElementsUploadDataStream>(
383 std::move(element_readers), 0);
[email protected]329b68b2012-11-14 17:54:27384
Bence Békydb3cf652017-10-10 15:22:10385 request_.method = "POST";
386 request_.upload_data_stream = upload_data_stream_.get();
[email protected]69e6b4a2012-10-18 08:03:01387 }
388
Bence Békydb3cf652017-10-10 15:22:10389 void UseChunkedPostRequest() {
390 ASSERT_FALSE(upload_chunked_data_stream_);
391 upload_chunked_data_stream_ = std::make_unique<ChunkedUploadDataStream>(0);
392 request_.method = "POST";
393 request_.upload_data_stream = upload_chunked_data_stream_.get();
[email protected]0c9bf872011-03-04 17:53:22394 }
395
[email protected]19ec8a72010-08-23 03:38:23396 // Read the result of a particular transaction, knowing that we've got
397 // multiple transactions in the read pipeline; so as we read, we may have
398 // to skip over data destined for other transactions while we consume
399 // the data for |trans|.
Bence Béky4e83f492018-05-13 23:14:25400 int ReadResult(HttpNetworkTransaction* trans, std::string* result) {
[email protected]19ec8a72010-08-23 03:38:23401 const int kSize = 3000;
[email protected]e3ebba0f2010-08-05 17:59:58402
[email protected]19ec8a72010-08-23 03:38:23403 int bytes_read = 0;
Victor Costan9c7302b2018-08-27 16:39:44404 scoped_refptr<IOBufferWithSize> buf =
405 base::MakeRefCounted<IOBufferWithSize>(kSize);
[email protected]49639fa2011-12-20 23:22:41406 TestCompletionCallback callback;
[email protected]19ec8a72010-08-23 03:38:23407 while (true) {
[email protected]90499482013-06-01 00:39:50408 int rv = trans->Read(buf.get(), kSize, callback.callback());
[email protected]19ec8a72010-08-23 03:38:23409 if (rv == ERR_IO_PENDING) {
[email protected]19ec8a72010-08-23 03:38:23410 rv = callback.WaitForResult();
411 } else if (rv <= 0) {
412 break;
413 }
414 result->append(buf->data(), rv);
415 bytes_read += rv;
[email protected]e3ebba0f2010-08-05 17:59:58416 }
[email protected]19ec8a72010-08-23 03:38:23417 return bytes_read;
418 }
[email protected]e3ebba0f2010-08-05 17:59:58419
[email protected]19ec8a72010-08-23 03:38:23420 void VerifyStreamsClosed(const NormalSpdyTransactionHelper& helper) {
421 // This lengthy block is reaching into the pool to dig out the active
422 // session. Once we have the session, we verify that the streams are
423 // all closed and not leaked at this point.
Bence Békydb3cf652017-10-10 15:22:10424 SpdySessionKey key(HostPortPair::FromURL(request_.url),
Paul Jensena457017a2018-01-19 23:52:04425 ProxyServer::Direct(), PRIVACY_MODE_DISABLED,
dalyk51ab46b2019-10-15 15:14:34426 SpdySessionKey::IsProxySession::kFalse, SocketTag(),
Ben Schwartz3ff4dc1e62021-04-27 21:15:23427 request_.network_isolation_key, SecureDnsPolicy::kAllow);
mmenkee65e7af2015-10-13 17:16:42428 HttpNetworkSession* session = helper.session();
[email protected]795cbf82013-07-22 09:37:27429 base::WeakPtr<SpdySession> spdy_session =
bnc9ead3ae2017-03-16 00:48:15430 session->spdy_session_pool()->FindAvailableSession(
Bence Békyd885b2b2018-02-03 00:58:31431 key, /* enable_ip_based_pooling = */ true,
432 /* is_websocket = */ false, log_);
wezca1070932016-05-26 20:30:52433 ASSERT_TRUE(spdy_session);
Bence Béky285e7d42017-12-04 20:22:11434 EXPECT_EQ(0u, num_active_streams(spdy_session));
435 EXPECT_EQ(0u, num_unclaimed_pushed_streams(spdy_session));
[email protected]19ec8a72010-08-23 03:38:23436 }
[email protected]e3ebba0f2010-08-05 17:59:58437
rch08e3aa3e2015-05-16 14:27:52438 void RunServerPushTest(SequencedSocketData* data,
[email protected]e3ebba0f2010-08-05 17:59:58439 HttpResponseInfo* response,
[email protected]a7a265ef2010-12-08 18:05:57440 HttpResponseInfo* push_response,
Bence Béky4e83f492018-05-13 23:14:25441 const std::string& expected) {
Bence Békydb3cf652017-10-10 15:22:10442 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
443 nullptr);
[email protected]e3ebba0f2010-08-05 17:59:58444 helper.RunPreTestSetup();
[email protected]d08358502010-12-03 22:04:03445 helper.AddData(data);
[email protected]e3ebba0f2010-08-05 17:59:58446
447 HttpNetworkTransaction* trans = helper.trans();
448
449 // Start the transaction with basic parameters.
[email protected]49639fa2011-12-20 23:22:41450 TestCompletionCallback callback;
Bence Békydb3cf652017-10-10 15:22:10451 int rv = trans->Start(&request_, callback.callback(), log_);
robpercival214763f2016-07-01 23:27:01452 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]e3ebba0f2010-08-05 17:59:58453 rv = callback.WaitForResult();
454
bnceb9aa7112017-01-05 01:03:46455 // Finish async network reads/writes.
456 base::RunLoop().RunUntilIdle();
457
[email protected]e3ebba0f2010-08-05 17:59:58458 // Request the pushed path.
bnc691fda62016-08-12 00:43:16459 HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session());
Bence Békydb3cf652017-10-10 15:22:10460 HttpRequestInfo request = CreateGetPushRequest();
461 rv = trans2.Start(&request, callback.callback(), log_);
robpercival214763f2016-07-01 23:27:01462 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]fc9d88472013-08-14 02:31:17463 base::RunLoop().RunUntilIdle();
[email protected]e3ebba0f2010-08-05 17:59:58464
[email protected]513963e2013-06-15 01:53:04465 // The data for the pushed path may be coming in more than 1 frame. Compile
[email protected]e3ebba0f2010-08-05 17:59:58466 // the results into a single string.
[email protected]19ec8a72010-08-23 03:38:23467
468 // Read the server push body.
Bence Béky4e83f492018-05-13 23:14:25469 std::string result2;
bnc691fda62016-08-12 00:43:16470 ReadResult(&trans2, &result2);
[email protected]19ec8a72010-08-23 03:38:23471 // Read the response body.
Bence Béky4e83f492018-05-13 23:14:25472 std::string result;
rch0aecfd82015-05-19 17:22:32473 ReadResult(trans, &result);
[email protected]e3ebba0f2010-08-05 17:59:58474
475 // Verify that we consumed all test data.
rch37de576c2015-05-17 20:28:17476 EXPECT_TRUE(data->AllReadDataConsumed());
477 EXPECT_TRUE(data->AllWriteDataConsumed());
[email protected]e3ebba0f2010-08-05 17:59:58478
caseqe8340bc92016-04-20 00:02:57479 LoadTimingInfo load_timing_info;
480 EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info));
481 EXPECT_TRUE(load_timing_info.push_start.is_null());
482 EXPECT_TRUE(load_timing_info.push_end.is_null());
483
484 LoadTimingInfo load_timing_info2;
bnc691fda62016-08-12 00:43:16485 EXPECT_TRUE(trans2.GetLoadTimingInfo(&load_timing_info2));
caseqe8340bc92016-04-20 00:02:57486 EXPECT_FALSE(load_timing_info2.push_start.is_null());
487 EXPECT_FALSE(load_timing_info2.push_end.is_null());
488
[email protected]e3ebba0f2010-08-05 17:59:58489 // Verify that the received push data is same as the expected push data.
[email protected]19ec8a72010-08-23 03:38:23490 EXPECT_EQ(result2.compare(expected), 0) << "Received data: "
491 << result2
492 << "||||| Expected data: "
493 << expected;
[email protected]e3ebba0f2010-08-05 17:59:58494
bnc42331402016-07-25 13:36:15495 // Verify the response HEADERS.
[email protected]e3ebba0f2010-08-05 17:59:58496 // Copy the response info, because trans goes away.
497 *response = *trans->GetResponseInfo();
bnc691fda62016-08-12 00:43:16498 *push_response = *trans2.GetResponseInfo();
[email protected]19ec8a72010-08-23 03:38:23499
500 VerifyStreamsClosed(helper);
[email protected]e3ebba0f2010-08-05 17:59:58501 }
502
morlovichab1d1c1e2017-02-07 19:59:28503 void RunBrokenPushTest(SequencedSocketData* data, int expected_rv) {
Bence Békydb3cf652017-10-10 15:22:10504 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
505 nullptr);
morlovichab1d1c1e2017-02-07 19:59:28506 helper.RunPreTestSetup();
507 helper.AddData(data);
508
509 HttpNetworkTransaction* trans = helper.trans();
510
511 // Start the transaction with basic parameters.
512 TestCompletionCallback callback;
Bence Békydb3cf652017-10-10 15:22:10513 int rv = trans->Start(&request_, callback.callback(), log_);
morlovichab1d1c1e2017-02-07 19:59:28514 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
515 rv = callback.WaitForResult();
516 EXPECT_EQ(expected_rv, rv);
517
518 // Finish async network reads/writes.
519 base::RunLoop().RunUntilIdle();
520
521 // Verify that we consumed all test data.
522 EXPECT_TRUE(data->AllReadDataConsumed());
523 EXPECT_TRUE(data->AllWriteDataConsumed());
524
525 if (expected_rv == OK) {
526 // Expected main request to succeed, even if push failed.
527 HttpResponseInfo response = *trans->GetResponseInfo();
528 EXPECT_TRUE(response.headers);
529 EXPECT_EQ("HTTP/1.1 200", response.headers->GetStatusLine());
530 }
531 }
532
[email protected]49639fa2011-12-20 23:22:41533 static void DeleteSessionCallback(NormalSpdyTransactionHelper* helper,
534 int result) {
535 helper->ResetTrans();
536 }
537
mmenkee65e7af2015-10-13 17:16:42538 static void StartTransactionCallback(HttpNetworkSession* session,
539 GURL url,
Bence Békyd3dde832017-09-19 19:02:31540 NetLogWithSource log,
mmenkee65e7af2015-10-13 17:16:42541 int result) {
krasin0bfeb6b2017-01-13 21:48:04542 HttpRequestInfo request;
bnc691fda62016-08-12 00:43:16543 HttpNetworkTransaction trans(DEFAULT_PRIORITY, session);
[email protected]49639fa2011-12-20 23:22:41544 TestCompletionCallback callback;
[email protected]49639fa2011-12-20 23:22:41545 request.method = "GET";
rchebf12982015-04-10 01:15:00546 request.url = url;
Ramin Halavatib5e433e62018-02-07 07:41:10547 request.traffic_annotation =
548 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
Bence Békyd3dde832017-09-19 19:02:31549 int rv = trans.Start(&request, callback.callback(), log);
robpercival214763f2016-07-01 23:27:01550 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]49639fa2011-12-20 23:22:41551 callback.WaitForResult();
552 }
553
Bence Békydb3cf652017-10-10 15:22:10554 ChunkedUploadDataStream* upload_chunked_data_stream() {
mmenkecbc2b712014-10-09 20:29:07555 return upload_chunked_data_stream_.get();
556 }
557
Bence Béky285e7d42017-12-04 20:22:11558 size_t num_active_streams(base::WeakPtr<SpdySession> session) {
559 return session->active_streams_.size();
560 }
561
Bence Békyfd2c1fd2017-12-15 02:32:03562 static size_t num_unclaimed_pushed_streams(
563 base::WeakPtr<SpdySession> session) {
564 return session->pool_->push_promise_index()->CountStreamsForSession(
565 session.get());
Bence Béky285e7d42017-12-04 20:22:11566 }
567
Bence Békyfd2c1fd2017-12-15 02:32:03568 static bool has_unclaimed_pushed_stream_for_url(
569 base::WeakPtr<SpdySession> session,
570 const GURL& url) {
571 return session->pool_->push_promise_index()->FindStream(
572 url, session.get()) != kNoPushedStreamFound;
Bence Béky285e7d42017-12-04 20:22:11573 }
574
Ryan Hamilton0239aac2018-05-19 00:03:13575 static spdy::SpdyStreamId spdy_stream_hi_water_mark(
Yoav Weiss9693572f2018-01-04 09:37:34576 base::WeakPtr<SpdySession> session) {
577 return session->stream_hi_water_mark_;
578 }
579
David Benjaminbae08ba2019-10-18 21:06:15580 base::RepeatingClosure FastForwardByCallback(base::TimeDelta delta) {
581 return base::BindRepeating(&SpdyNetworkTransactionTest::FastForwardBy,
582 base::Unretained(this), delta);
583 }
584
bncb26024382016-06-29 02:39:45585 const GURL default_url_;
586 const HostPortPair host_port_pair_;
Bence Békydb3cf652017-10-10 15:22:10587 HttpRequestInfo request_;
[email protected]9ec54f82013-05-10 02:53:05588 SpdyTestUtil spdy_util_;
Bence Békyd3dde832017-09-19 19:02:31589 const NetLogWithSource log_;
[email protected]9ec54f82013-05-10 02:53:05590
[email protected]d3cee19d2010-06-22 18:42:18591 private:
danakjaee3e1ec2016-04-16 00:23:18592 std::unique_ptr<ChunkedUploadDataStream> upload_chunked_data_stream_;
593 std::unique_ptr<UploadDataStream> upload_data_stream_;
[email protected]ea1a3f62012-11-16 20:34:23594 base::ScopedTempDir temp_dir_;
[email protected]aea80602009-09-18 00:55:08595};
596
[email protected]3caf5542010-07-16 15:19:47597// Verify HttpNetworkTransaction constructor.
bncd16676a2016-07-20 16:23:01598TEST_F(SpdyNetworkTransactionTest, Constructor) {
Jeremy Roman0579ed62017-08-29 15:56:19599 auto session_deps = std::make_unique<SpdySessionDependencies>();
danakjaee3e1ec2016-04-16 00:23:18600 std::unique_ptr<HttpNetworkSession> session(
[email protected]bb88e1d32013-05-03 23:11:07601 SpdySessionDependencies::SpdyCreateSession(session_deps.get()));
bncd16676a2016-07-20 16:23:01602 auto trans =
Jeremy Roman0579ed62017-08-29 15:56:19603 std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
[email protected]aea80602009-09-18 00:55:08604}
605
bncd16676a2016-07-20 16:23:01606TEST_F(SpdyNetworkTransactionTest, Get) {
[email protected]75f30cc22010-06-28 21:41:38607 // Construct the request.
Ryan Hamilton0239aac2018-05-19 00:03:13608 spdy::SpdySerializedFrame req(
609 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
bncdf80d44fd2016-07-15 20:27:41610 MockWrite writes[] = {CreateMockWrite(req, 0)};
[email protected]72552f02009-10-28 15:25:01611
Ryan Hamilton0239aac2018-05-19 00:03:13612 spdy::SpdySerializedFrame resp(
613 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
614 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]72552f02009-10-28 15:25:01615 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:41616 CreateMockRead(resp, 1), CreateMockRead(body, 2),
rch08e3aa3e2015-05-16 14:27:52617 MockRead(ASYNC, 0, 3) // EOF
[email protected]72552f02009-10-28 15:25:01618 };
619
Ryan Sleevib8d7ea02018-05-07 20:01:01620 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:10621 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]dd54bd82012-07-19 23:44:57622 helper.RunToCompletion(&data);
[email protected]3caf5542010-07-16 15:19:47623 TransactionHelperResult out = helper.output();
robpercival214763f2016-07-01 23:27:01624 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:02625 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]72552f02009-10-28 15:25:01626 EXPECT_EQ("hello!", out.response_data);
627}
628
Bence Béky2fcf4fa2018-04-06 20:06:01629TEST_F(SpdyNetworkTransactionTest, SetPriority) {
630 for (bool set_priority_before_starting_transaction : {true, false}) {
631 SpdyTestUtil spdy_test_util;
Ryan Hamilton0239aac2018-05-19 00:03:13632 spdy::SpdySerializedFrame req(
Bence Béky2fcf4fa2018-04-06 20:06:01633 spdy_test_util.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
634 MockWrite writes[] = {CreateMockWrite(req, 0)};
635
Ryan Hamilton0239aac2018-05-19 00:03:13636 spdy::SpdySerializedFrame resp(
Bence Béky2fcf4fa2018-04-06 20:06:01637 spdy_test_util.ConstructSpdyGetReply(nullptr, 0, 1));
Ryan Hamilton0239aac2018-05-19 00:03:13638 spdy::SpdySerializedFrame body(
639 spdy_test_util.ConstructSpdyDataFrame(1, true));
Bence Béky2fcf4fa2018-04-06 20:06:01640 MockRead reads[] = {CreateMockRead(resp, 1), CreateMockRead(body, 2),
641 MockRead(ASYNC, 0, 3)};
642
Ryan Sleevib8d7ea02018-05-07 20:01:01643 SequencedSocketData data(reads, writes);
Bence Béky2fcf4fa2018-04-06 20:06:01644 NormalSpdyTransactionHelper helper(request_, HIGHEST, log_, nullptr);
645 helper.RunPreTestSetup();
646 helper.AddData(&data);
647
648 if (set_priority_before_starting_transaction) {
649 helper.trans()->SetPriority(LOWEST);
650 EXPECT_TRUE(helper.StartDefaultTest());
651 } else {
652 EXPECT_TRUE(helper.StartDefaultTest());
653 helper.trans()->SetPriority(LOWEST);
654 }
655
656 helper.FinishDefaultTest();
657 helper.VerifyDataConsumed();
658
659 TransactionHelperResult out = helper.output();
660 EXPECT_THAT(out.rv, IsOk());
661 EXPECT_EQ("HTTP/1.1 200", out.status_line);
662 EXPECT_EQ("hello!", out.response_data);
663 }
664}
665
Bence Béky7a4836c2018-05-08 03:52:48666// Test that changing the request priority of an existing stream triggers
Bence Béky73b85292018-06-14 04:56:43667// sending PRIORITY frames in case there are multiple open streams and their
Bence Béky7a4836c2018-05-08 03:52:48668// relative priorities change.
Bence Béky73b85292018-06-14 04:56:43669TEST_F(SpdyNetworkTransactionTest, SetPriorityOnExistingStream) {
Bence Béky7a4836c2018-05-08 03:52:48670 const char* kUrl2 = "https://www.example.org/bar";
671
Ryan Hamilton0239aac2018-05-19 00:03:13672 spdy::SpdySerializedFrame req1(
673 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, HIGHEST));
674 spdy::SpdySerializedFrame req2(spdy_util_.ConstructSpdyGet(kUrl2, 3, MEDIUM));
675 spdy::SpdySerializedFrame priority1(
Bence Béky7a4836c2018-05-08 03:52:48676 spdy_util_.ConstructSpdyPriority(3, 0, MEDIUM, true));
Ryan Hamilton0239aac2018-05-19 00:03:13677 spdy::SpdySerializedFrame priority2(
Bence Béky7a4836c2018-05-08 03:52:48678 spdy_util_.ConstructSpdyPriority(1, 3, LOWEST, true));
679 MockWrite writes[] = {CreateMockWrite(req1, 0), CreateMockWrite(req2, 2),
680 CreateMockWrite(priority1, 4),
681 CreateMockWrite(priority2, 5)};
682
Ryan Hamilton0239aac2018-05-19 00:03:13683 spdy::SpdySerializedFrame resp1(
684 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
685 spdy::SpdySerializedFrame resp2(
686 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
687 spdy::SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true));
688 spdy::SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(3, true));
Bence Béky7a4836c2018-05-08 03:52:48689 MockRead reads[] = {CreateMockRead(resp1, 1), CreateMockRead(resp2, 3),
690 CreateMockRead(body1, 6), CreateMockRead(body2, 7),
691 MockRead(ASYNC, 0, 8)};
692
693 SequencedSocketData data(reads, writes);
694 NormalSpdyTransactionHelper helper(request_, HIGHEST, log_, nullptr);
695 helper.RunPreTestSetup();
696 helper.AddData(&data);
697 EXPECT_TRUE(helper.StartDefaultTest());
698
699 // Open HTTP/2 connection and create first stream.
700 base::RunLoop().RunUntilIdle();
701
702 HttpNetworkTransaction trans2(MEDIUM, helper.session());
703 HttpRequestInfo request2;
704 request2.url = GURL(kUrl2);
705 request2.method = "GET";
706 request2.traffic_annotation =
707 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
708 TestCompletionCallback callback2;
709 int rv = trans2.Start(&request2, callback2.callback(), log_);
710 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
711
712 // Create second stream.
713 base::RunLoop().RunUntilIdle();
714
715 // First request has HIGHEST priority, second request has MEDIUM priority.
716 // Changing the priority of the first request to LOWEST changes their order,
717 // and therefore triggers sending PRIORITY frames.
718 helper.trans()->SetPriority(LOWEST);
719
720 helper.FinishDefaultTest();
721 helper.VerifyDataConsumed();
722
723 TransactionHelperResult out = helper.output();
724 EXPECT_THAT(out.rv, IsOk());
725 EXPECT_EQ("HTTP/1.1 200", out.status_line);
726 EXPECT_EQ("hello!", out.response_data);
727
728 rv = callback2.WaitForResult();
729 ASSERT_THAT(rv, IsOk());
730 const HttpResponseInfo* response2 = trans2.GetResponseInfo();
731 ASSERT_TRUE(response2);
732 ASSERT_TRUE(response2->headers);
733 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP2,
734 response2->connection_info);
735 EXPECT_EQ("HTTP/1.1 200", response2->headers->GetStatusLine());
736}
737
Bence Béky73b85292018-06-14 04:56:43738// Create two requests: a lower priority one first, then a higher priority one.
739// Test that the second request gets sent out first.
740TEST_F(SpdyNetworkTransactionTest, RequestsOrderedByPriority) {
741 const char* kUrl2 = "https://www.example.org/foo";
742
743 // First send second request on stream 1, then first request on stream 3.
744 spdy::SpdySerializedFrame req2(
745 spdy_util_.ConstructSpdyGet(kUrl2, 1, HIGHEST));
746 spdy::SpdySerializedFrame req1(
747 spdy_util_.ConstructSpdyGet(nullptr, 0, 3, LOW));
748 MockWrite writes[] = {CreateMockWrite(req2, 0), CreateMockWrite(req1, 1)};
749
750 spdy::SpdySerializedFrame resp2(
751 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
752 spdy::SpdySerializedFrame resp1(
753 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
754 spdy::SpdySerializedFrame body2(
755 spdy_util_.ConstructSpdyDataFrame(1, "stream 1", true));
756 spdy::SpdySerializedFrame body1(
757 spdy_util_.ConstructSpdyDataFrame(3, "stream 3", true));
758 MockRead reads[] = {CreateMockRead(resp2, 2), CreateMockRead(body2, 3),
759 CreateMockRead(resp1, 4), CreateMockRead(body1, 5),
760 MockRead(ASYNC, 0, 6)};
761
762 SequencedSocketData data(reads, writes);
763 NormalSpdyTransactionHelper helper(request_, LOW, log_, nullptr);
764 helper.RunPreTestSetup();
765 helper.AddData(&data);
766
767 // Create HTTP/2 connection. This is necessary because starting the first
768 // transaction does not create the connection yet, so the second request
769 // could not use the same connection, whereas running the message loop after
770 // starting the first transaction would call Socket::Write() with the first
771 // HEADERS frame, so the second transaction could not get ahead of it.
772 SpdySessionKey key(HostPortPair("www.example.org", 443),
Matt Menke2436b2f2018-12-11 18:07:11773 ProxyServer::Direct(), PRIVACY_MODE_DISABLED,
dalyk51ab46b2019-10-15 15:14:34774 SpdySessionKey::IsProxySession::kFalse, SocketTag(),
Ben Schwartz3ff4dc1e62021-04-27 21:15:23775 NetworkIsolationKey(), SecureDnsPolicy::kAllow);
Bence Béky73b85292018-06-14 04:56:43776 auto spdy_session = CreateSpdySession(helper.session(), key, log_);
777 EXPECT_TRUE(spdy_session);
778
779 // Start first transaction.
780 EXPECT_TRUE(helper.StartDefaultTest());
781
782 // Start second transaction.
783 HttpNetworkTransaction trans2(HIGHEST, helper.session());
784 HttpRequestInfo request2;
785 request2.url = GURL(kUrl2);
786 request2.method = "GET";
787 request2.traffic_annotation =
788 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
789 TestCompletionCallback callback2;
790 int rv = trans2.Start(&request2, callback2.callback(), log_);
791 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
792
793 // Complete first transaction and verify results.
794 helper.FinishDefaultTest();
795 helper.VerifyDataConsumed();
796
797 TransactionHelperResult out = helper.output();
798 EXPECT_THAT(out.rv, IsOk());
799 EXPECT_EQ("HTTP/1.1 200", out.status_line);
800 EXPECT_EQ("stream 3", out.response_data);
801
802 // Complete second transaction and verify results.
803 rv = callback2.WaitForResult();
804 ASSERT_THAT(rv, IsOk());
805 const HttpResponseInfo* response2 = trans2.GetResponseInfo();
806 ASSERT_TRUE(response2);
807 ASSERT_TRUE(response2->headers);
808 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP2,
809 response2->connection_info);
810 EXPECT_EQ("HTTP/1.1 200", response2->headers->GetStatusLine());
811 std::string response_data;
812 ReadTransaction(&trans2, &response_data);
813 EXPECT_EQ("stream 1", response_data);
814}
815
816// Test that already enqueued HEADERS frames are reordered if their relative
817// priority changes.
818TEST_F(SpdyNetworkTransactionTest, QueuedFramesReorderedOnPriorityChange) {
819 const char* kUrl2 = "https://www.example.org/foo";
820 const char* kUrl3 = "https://www.example.org/bar";
821
822 spdy::SpdySerializedFrame req1(
823 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, DEFAULT_PRIORITY));
824 spdy::SpdySerializedFrame req3(spdy_util_.ConstructSpdyGet(kUrl3, 3, MEDIUM));
825 spdy::SpdySerializedFrame req2(spdy_util_.ConstructSpdyGet(kUrl2, 5, LOWEST));
826 MockWrite writes[] = {MockWrite(ASYNC, ERR_IO_PENDING, 0),
827 CreateMockWrite(req1, 1), CreateMockWrite(req3, 2),
828 CreateMockWrite(req2, 3)};
829
830 spdy::SpdySerializedFrame resp1(
831 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
832 spdy::SpdySerializedFrame resp3(
833 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
834 spdy::SpdySerializedFrame resp2(
835 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 5));
836 spdy::SpdySerializedFrame body1(
837 spdy_util_.ConstructSpdyDataFrame(1, "stream 1", true));
838 spdy::SpdySerializedFrame body3(
839 spdy_util_.ConstructSpdyDataFrame(3, "stream 3", true));
840 spdy::SpdySerializedFrame body2(
841 spdy_util_.ConstructSpdyDataFrame(5, "stream 5", true));
842 MockRead reads[] = {CreateMockRead(resp1, 4), CreateMockRead(body1, 5),
843 CreateMockRead(resp3, 6), CreateMockRead(body3, 7),
844 CreateMockRead(resp2, 8), CreateMockRead(body2, 9),
845 MockRead(ASYNC, 0, 10)};
846
847 SequencedSocketData data(reads, writes);
848 // Priority of first request does not matter, because Socket::Write() will be
849 // called with its HEADERS frame before the other requests start.
850 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
851 helper.RunPreTestSetup();
852 helper.AddData(&data);
853 EXPECT_TRUE(helper.StartDefaultTest());
854
855 // Open HTTP/2 connection, create HEADERS frame for first request, and call
856 // Socket::Write() with that frame. After this, no other request can get
857 // ahead of the first one.
858 base::RunLoop().RunUntilIdle();
859
860 HttpNetworkTransaction trans2(HIGHEST, helper.session());
861 HttpRequestInfo request2;
862 request2.url = GURL(kUrl2);
863 request2.method = "GET";
864 request2.traffic_annotation =
865 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
866 TestCompletionCallback callback2;
867 int rv = trans2.Start(&request2, callback2.callback(), log_);
868 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
869
870 HttpNetworkTransaction trans3(MEDIUM, helper.session());
871 HttpRequestInfo request3;
872 request3.url = GURL(kUrl3);
873 request3.method = "GET";
874 request3.traffic_annotation =
875 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
876 TestCompletionCallback callback3;
877 rv = trans3.Start(&request3, callback3.callback(), log_);
878 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
879
880 // Create HEADERS frames for second and third request and enqueue them in
881 // SpdyWriteQueue with their original priorities. Writing of the first
882 // HEADERS frame to the socked still has not completed.
883 base::RunLoop().RunUntilIdle();
884
885 // Second request is of HIGHEST, third of MEDIUM priority. Changing second
886 // request to LOWEST changes their relative order. This should result in
887 // already enqueued frames being reordered within SpdyWriteQueue.
888 trans2.SetPriority(LOWEST);
889
890 // Complete async write of the first HEADERS frame.
891 data.Resume();
892
893 helper.FinishDefaultTest();
894 TransactionHelperResult out = helper.output();
895 EXPECT_THAT(out.rv, IsOk());
896 EXPECT_EQ("HTTP/1.1 200", out.status_line);
897 EXPECT_EQ("stream 1", out.response_data);
898
899 rv = callback2.WaitForResult();
900 ASSERT_THAT(rv, IsOk());
901 const HttpResponseInfo* response2 = trans2.GetResponseInfo();
902 ASSERT_TRUE(response2);
903 ASSERT_TRUE(response2->headers);
904 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP2,
905 response2->connection_info);
906 EXPECT_EQ("HTTP/1.1 200", response2->headers->GetStatusLine());
907 std::string response_data;
908 ReadTransaction(&trans2, &response_data);
909 EXPECT_EQ("stream 5", response_data);
910
911 rv = callback3.WaitForResult();
912 ASSERT_THAT(rv, IsOk());
913 const HttpResponseInfo* response3 = trans3.GetResponseInfo();
914 ASSERT_TRUE(response3);
915 ASSERT_TRUE(response3->headers);
916 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP2,
917 response3->connection_info);
918 EXPECT_EQ("HTTP/1.1 200", response3->headers->GetStatusLine());
919 ReadTransaction(&trans3, &response_data);
920 EXPECT_EQ("stream 3", response_data);
921
922 helper.VerifyDataConsumed();
923}
924
bncd16676a2016-07-20 16:23:01925TEST_F(SpdyNetworkTransactionTest, GetAtEachPriority) {
[email protected]3d08dd382013-10-19 00:13:11926 for (RequestPriority p = MINIMUM_PRIORITY; p <= MAXIMUM_PRIORITY;
[email protected]31ae7ab2012-04-24 21:09:05927 p = RequestPriority(p + 1)) {
bncd16676a2016-07-20 16:23:01928 SpdyTestUtil spdy_test_util;
bnc38dcd392016-02-09 23:19:49929
[email protected]c9c6f5c2010-07-31 01:30:03930 // Construct the request.
Ryan Hamilton0239aac2018-05-19 00:03:13931 spdy::SpdySerializedFrame req(
932 spdy_test_util.ConstructSpdyGet(nullptr, 0, 1, p));
bncdf80d44fd2016-07-15 20:27:41933 MockWrite writes[] = {CreateMockWrite(req, 0)};
[email protected]c9c6f5c2010-07-31 01:30:03934
Ryan Hamilton0239aac2018-05-19 00:03:13935 spdy::SpdyPriority spdy_prio = 0;
bncdf80d44fd2016-07-15 20:27:41936 EXPECT_TRUE(GetSpdyPriority(req, &spdy_prio));
Ryan Hamilton0239aac2018-05-19 00:03:13937 // this repeats the RequestPriority-->spdy::SpdyPriority mapping from
938 // spdy::SpdyFramer::ConvertRequestPriorityToSpdyPriority to make
[email protected]c9c6f5c2010-07-31 01:30:03939 // sure it's being done right.
bnc05808ff42016-01-08 23:48:25940 switch (p) {
941 case HIGHEST:
942 EXPECT_EQ(0, spdy_prio);
943 break;
944 case MEDIUM:
945 EXPECT_EQ(1, spdy_prio);
946 break;
947 case LOW:
948 EXPECT_EQ(2, spdy_prio);
949 break;
950 case LOWEST:
951 EXPECT_EQ(3, spdy_prio);
952 break;
953 case IDLE:
954 EXPECT_EQ(4, spdy_prio);
955 break;
rdsmith5eb6fbc2016-10-21 17:36:08956 case THROTTLED:
957 EXPECT_EQ(5, spdy_prio);
958 break;
bnc05808ff42016-01-08 23:48:25959 default:
960 FAIL();
[email protected]c9c6f5c2010-07-31 01:30:03961 }
962
Ryan Hamilton0239aac2018-05-19 00:03:13963 spdy::SpdySerializedFrame resp(
bnc42331402016-07-25 13:36:15964 spdy_test_util.ConstructSpdyGetReply(nullptr, 0, 1));
Ryan Hamilton0239aac2018-05-19 00:03:13965 spdy::SpdySerializedFrame body(
966 spdy_test_util.ConstructSpdyDataFrame(1, true));
[email protected]c9c6f5c2010-07-31 01:30:03967 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:41968 CreateMockRead(resp, 1), CreateMockRead(body, 2),
rch08e3aa3e2015-05-16 14:27:52969 MockRead(ASYNC, 0, 3) // EOF
[email protected]c9c6f5c2010-07-31 01:30:03970 };
971
Ryan Sleevib8d7ea02018-05-07 20:01:01972 SequencedSocketData data(reads, writes);
[email protected]c9c6f5c2010-07-31 01:30:03973
Bence Békydb3cf652017-10-10 15:22:10974 NormalSpdyTransactionHelper helper(request_, p, log_, nullptr);
[email protected]dd54bd82012-07-19 23:44:57975 helper.RunToCompletion(&data);
[email protected]c9c6f5c2010-07-31 01:30:03976 TransactionHelperResult out = helper.output();
robpercival214763f2016-07-01 23:27:01977 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:02978 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]c9c6f5c2010-07-31 01:30:03979 EXPECT_EQ("hello!", out.response_data);
980 }
981}
982
[email protected]2bd93022010-07-17 00:58:44983// Start three gets simultaniously; making sure that multiplexed
984// streams work properly.
985
986// This can't use the TransactionHelper method, since it only
987// handles a single transaction, and finishes them as soon
988// as it launches them.
989
990// TODO(gavinp): create a working generalized TransactionHelper that
991// can allow multiple streams in flight.
992
bncd16676a2016-07-20 16:23:01993TEST_F(SpdyNetworkTransactionTest, ThreeGets) {
Ryan Hamilton0239aac2018-05-19 00:03:13994 spdy::SpdySerializedFrame req(
995 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
996 spdy::SpdySerializedFrame resp(
997 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
998 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, false));
999 spdy::SpdySerializedFrame fbody(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]2bd93022010-07-17 00:58:441000
Ryan Hamilton0239aac2018-05-19 00:03:131001 spdy::SpdySerializedFrame req2(
1002 spdy_util_.ConstructSpdyGet(nullptr, 0, 3, LOWEST));
1003 spdy::SpdySerializedFrame resp2(
1004 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
1005 spdy::SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(3, false));
1006 spdy::SpdySerializedFrame fbody2(spdy_util_.ConstructSpdyDataFrame(3, true));
[email protected]2bd93022010-07-17 00:58:441007
Ryan Hamilton0239aac2018-05-19 00:03:131008 spdy::SpdySerializedFrame req3(
1009 spdy_util_.ConstructSpdyGet(nullptr, 0, 5, LOWEST));
1010 spdy::SpdySerializedFrame resp3(
1011 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 5));
1012 spdy::SpdySerializedFrame body3(spdy_util_.ConstructSpdyDataFrame(5, false));
1013 spdy::SpdySerializedFrame fbody3(spdy_util_.ConstructSpdyDataFrame(5, true));
[email protected]2bd93022010-07-17 00:58:441014
[email protected]1b323172011-03-01 17:50:171015 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:411016 CreateMockWrite(req, 0), CreateMockWrite(req2, 3),
1017 CreateMockWrite(req3, 6),
[email protected]2bd93022010-07-17 00:58:441018 };
1019 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:411020 CreateMockRead(resp, 1), CreateMockRead(body, 2),
1021 CreateMockRead(resp2, 4), CreateMockRead(body2, 5),
1022 CreateMockRead(resp3, 7), CreateMockRead(body3, 8),
[email protected]2bd93022010-07-17 00:58:441023
bncdf80d44fd2016-07-15 20:27:411024 CreateMockRead(fbody, 9), CreateMockRead(fbody2, 10),
1025 CreateMockRead(fbody3, 11),
[email protected]2bd93022010-07-17 00:58:441026
rch08e3aa3e2015-05-16 14:27:521027 MockRead(ASYNC, 0, 12), // EOF
[email protected]2bd93022010-07-17 00:58:441028 };
Ryan Sleevib8d7ea02018-05-07 20:01:011029 SequencedSocketData data(reads, writes);
1030 SequencedSocketData data_placeholder1;
1031 SequencedSocketData data_placeholder2;
[email protected]2bd93022010-07-17 00:58:441032
[email protected]2bd93022010-07-17 00:58:441033 TransactionHelperResult out;
Bence Békydb3cf652017-10-10 15:22:101034 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]bdebd1b2010-08-09 20:18:081035 helper.RunPreTestSetup();
[email protected]dd54bd82012-07-19 23:44:571036 helper.AddData(&data);
rchaeb3f052015-04-14 16:02:491037 // We require placeholder data because three get requests are sent out at
1038 // the same time which results in three sockets being connected. The first
1039 // on will negotiate SPDY and will be used for all requests.
mmenkecc2298e2015-12-07 18:20:181040 helper.AddData(&data_placeholder1);
1041 helper.AddData(&data_placeholder2);
[email protected]49639fa2011-12-20 23:22:411042 TestCompletionCallback callback1;
1043 TestCompletionCallback callback2;
1044 TestCompletionCallback callback3;
[email protected]2bd93022010-07-17 00:58:441045
krasin0bfeb6b2017-01-13 21:48:041046 HttpNetworkTransaction trans1(DEFAULT_PRIORITY, helper.session());
1047 HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session());
1048 HttpNetworkTransaction trans3(DEFAULT_PRIORITY, helper.session());
1049
Bence Békydb3cf652017-10-10 15:22:101050 out.rv = trans1.Start(&request_, callback1.callback(), log_);
robpercival214763f2016-07-01 23:27:011051 ASSERT_THAT(out.rv, IsError(ERR_IO_PENDING));
Bence Békydb3cf652017-10-10 15:22:101052 out.rv = trans2.Start(&request_, callback2.callback(), log_);
robpercival214763f2016-07-01 23:27:011053 ASSERT_THAT(out.rv, IsError(ERR_IO_PENDING));
Bence Békydb3cf652017-10-10 15:22:101054 out.rv = trans3.Start(&request_, callback3.callback(), log_);
robpercival214763f2016-07-01 23:27:011055 ASSERT_THAT(out.rv, IsError(ERR_IO_PENDING));
[email protected]2bd93022010-07-17 00:58:441056
[email protected]bdebd1b2010-08-09 20:18:081057 out.rv = callback1.WaitForResult();
robpercival214763f2016-07-01 23:27:011058 ASSERT_THAT(out.rv, IsOk());
[email protected]bdebd1b2010-08-09 20:18:081059 out.rv = callback3.WaitForResult();
robpercival214763f2016-07-01 23:27:011060 ASSERT_THAT(out.rv, IsOk());
[email protected]2bd93022010-07-17 00:58:441061
bnc691fda62016-08-12 00:43:161062 const HttpResponseInfo* response1 = trans1.GetResponseInfo();
wezca1070932016-05-26 20:30:521063 EXPECT_TRUE(response1->headers);
[email protected]bdebd1b2010-08-09 20:18:081064 EXPECT_TRUE(response1->was_fetched_via_spdy);
1065 out.status_line = response1->headers->GetStatusLine();
1066 out.response_info = *response1;
[email protected]2bd93022010-07-17 00:58:441067
bnc691fda62016-08-12 00:43:161068 trans2.GetResponseInfo();
[email protected]2bd93022010-07-17 00:58:441069
bnc691fda62016-08-12 00:43:161070 out.rv = ReadTransaction(&trans1, &out.response_data);
[email protected]bdebd1b2010-08-09 20:18:081071 helper.VerifyDataConsumed();
robpercival214763f2016-07-01 23:27:011072 EXPECT_THAT(out.rv, IsOk());
[email protected]2bd93022010-07-17 00:58:441073
robpercival214763f2016-07-01 23:27:011074 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:021075 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]2bd93022010-07-17 00:58:441076 EXPECT_EQ("hello!hello!", out.response_data);
1077}
1078
bncd16676a2016-07-20 16:23:011079TEST_F(SpdyNetworkTransactionTest, TwoGetsLateBinding) {
Ryan Hamilton0239aac2018-05-19 00:03:131080 spdy::SpdySerializedFrame req(
1081 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
1082 spdy::SpdySerializedFrame resp(
1083 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
1084 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, false));
1085 spdy::SpdySerializedFrame fbody(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]1b323172011-03-01 17:50:171086
Ryan Hamilton0239aac2018-05-19 00:03:131087 spdy::SpdySerializedFrame req2(
1088 spdy_util_.ConstructSpdyGet(nullptr, 0, 3, LOWEST));
1089 spdy::SpdySerializedFrame resp2(
1090 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
1091 spdy::SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(3, false));
1092 spdy::SpdySerializedFrame fbody2(spdy_util_.ConstructSpdyDataFrame(3, true));
[email protected]1b323172011-03-01 17:50:171093
1094 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:411095 CreateMockWrite(req, 0), CreateMockWrite(req2, 3),
[email protected]1b323172011-03-01 17:50:171096 };
1097 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:411098 CreateMockRead(resp, 1), CreateMockRead(body, 2),
1099 CreateMockRead(resp2, 4), CreateMockRead(body2, 5),
1100 CreateMockRead(fbody, 6), CreateMockRead(fbody2, 7),
rch08e3aa3e2015-05-16 14:27:521101 MockRead(ASYNC, 0, 8), // EOF
[email protected]1b323172011-03-01 17:50:171102 };
Ryan Sleevib8d7ea02018-05-07 20:01:011103 SequencedSocketData data(reads, writes);
[email protected]1b323172011-03-01 17:50:171104
[email protected]d973e99a2012-02-17 21:02:361105 MockConnect never_finishing_connect(SYNCHRONOUS, ERR_IO_PENDING);
Ryan Sleevib8d7ea02018-05-07 20:01:011106 SequencedSocketData data_placeholder;
[email protected]dd54bd82012-07-19 23:44:571107 data_placeholder.set_connect_data(never_finishing_connect);
[email protected]1b323172011-03-01 17:50:171108
[email protected]1b323172011-03-01 17:50:171109 TransactionHelperResult out;
Bence Békydb3cf652017-10-10 15:22:101110 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]1b323172011-03-01 17:50:171111 helper.RunPreTestSetup();
[email protected]dd54bd82012-07-19 23:44:571112 helper.AddData(&data);
rchaeb3f052015-04-14 16:02:491113 // We require placeholder data because two requests are sent out at
1114 // the same time which results in two sockets being connected. The first
1115 // on will negotiate SPDY and will be used for all requests.
[email protected]dd54bd82012-07-19 23:44:571116 helper.AddData(&data_placeholder);
bnc691fda62016-08-12 00:43:161117 HttpNetworkTransaction trans1(DEFAULT_PRIORITY, helper.session());
1118 HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session());
[email protected]1b323172011-03-01 17:50:171119
[email protected]49639fa2011-12-20 23:22:411120 TestCompletionCallback callback1;
1121 TestCompletionCallback callback2;
[email protected]1b323172011-03-01 17:50:171122
Bence Békydb3cf652017-10-10 15:22:101123 out.rv = trans1.Start(&request_, callback1.callback(), log_);
robpercival214763f2016-07-01 23:27:011124 ASSERT_THAT(out.rv, IsError(ERR_IO_PENDING));
Bence Békydb3cf652017-10-10 15:22:101125 out.rv = trans2.Start(&request_, callback2.callback(), log_);
robpercival214763f2016-07-01 23:27:011126 ASSERT_THAT(out.rv, IsError(ERR_IO_PENDING));
[email protected]1b323172011-03-01 17:50:171127
1128 out.rv = callback1.WaitForResult();
robpercival214763f2016-07-01 23:27:011129 ASSERT_THAT(out.rv, IsOk());
[email protected]1b323172011-03-01 17:50:171130 out.rv = callback2.WaitForResult();
robpercival214763f2016-07-01 23:27:011131 ASSERT_THAT(out.rv, IsOk());
[email protected]1b323172011-03-01 17:50:171132
bnc691fda62016-08-12 00:43:161133 const HttpResponseInfo* response1 = trans1.GetResponseInfo();
wezca1070932016-05-26 20:30:521134 EXPECT_TRUE(response1->headers);
[email protected]1b323172011-03-01 17:50:171135 EXPECT_TRUE(response1->was_fetched_via_spdy);
1136 out.status_line = response1->headers->GetStatusLine();
1137 out.response_info = *response1;
bnc691fda62016-08-12 00:43:161138 out.rv = ReadTransaction(&trans1, &out.response_data);
robpercival214763f2016-07-01 23:27:011139 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:021140 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]1b323172011-03-01 17:50:171141 EXPECT_EQ("hello!hello!", out.response_data);
1142
bnc691fda62016-08-12 00:43:161143 const HttpResponseInfo* response2 = trans2.GetResponseInfo();
wezca1070932016-05-26 20:30:521144 EXPECT_TRUE(response2->headers);
[email protected]1b323172011-03-01 17:50:171145 EXPECT_TRUE(response2->was_fetched_via_spdy);
1146 out.status_line = response2->headers->GetStatusLine();
1147 out.response_info = *response2;
bnc691fda62016-08-12 00:43:161148 out.rv = ReadTransaction(&trans2, &out.response_data);
robpercival214763f2016-07-01 23:27:011149 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:021150 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]1b323172011-03-01 17:50:171151 EXPECT_EQ("hello!hello!", out.response_data);
1152
1153 helper.VerifyDataConsumed();
1154}
1155
bncd16676a2016-07-20 16:23:011156TEST_F(SpdyNetworkTransactionTest, TwoGetsLateBindingFromPreconnect) {
Ryan Hamilton0239aac2018-05-19 00:03:131157 spdy::SpdySerializedFrame req(
1158 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
1159 spdy::SpdySerializedFrame resp(
1160 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
1161 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, false));
1162 spdy::SpdySerializedFrame fbody(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]1b323172011-03-01 17:50:171163
Ryan Hamilton0239aac2018-05-19 00:03:131164 spdy::SpdySerializedFrame req2(
1165 spdy_util_.ConstructSpdyGet(nullptr, 0, 3, LOWEST));
1166 spdy::SpdySerializedFrame resp2(
1167 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
1168 spdy::SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(3, false));
1169 spdy::SpdySerializedFrame fbody2(spdy_util_.ConstructSpdyDataFrame(3, true));
[email protected]1b323172011-03-01 17:50:171170
1171 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:411172 CreateMockWrite(req, 0), CreateMockWrite(req2, 3),
[email protected]1b323172011-03-01 17:50:171173 };
1174 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:411175 CreateMockRead(resp, 1), CreateMockRead(body, 2),
1176 CreateMockRead(resp2, 4), CreateMockRead(body2, 5),
1177 CreateMockRead(fbody, 6), CreateMockRead(fbody2, 7),
rch08e3aa3e2015-05-16 14:27:521178 MockRead(ASYNC, 0, 8), // EOF
[email protected]1b323172011-03-01 17:50:171179 };
Ryan Sleevib8d7ea02018-05-07 20:01:011180 SequencedSocketData preconnect_data(reads, writes);
[email protected]1b323172011-03-01 17:50:171181
[email protected]d973e99a2012-02-17 21:02:361182 MockConnect never_finishing_connect(ASYNC, ERR_IO_PENDING);
[email protected]1b323172011-03-01 17:50:171183
Ryan Sleevib8d7ea02018-05-07 20:01:011184 SequencedSocketData data_placeholder;
[email protected]dd54bd82012-07-19 23:44:571185 data_placeholder.set_connect_data(never_finishing_connect);
[email protected]1b323172011-03-01 17:50:171186
[email protected]1b323172011-03-01 17:50:171187 TransactionHelperResult out;
Bence Békydb3cf652017-10-10 15:22:101188 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]1b323172011-03-01 17:50:171189 helper.RunPreTestSetup();
[email protected]dd54bd82012-07-19 23:44:571190 helper.AddData(&preconnect_data);
[email protected]1b323172011-03-01 17:50:171191 // We require placeholder data because 3 connections are attempted (first is
1192 // the preconnect, 2nd and 3rd are the never finished connections.
[email protected]dd54bd82012-07-19 23:44:571193 helper.AddData(&data_placeholder);
1194 helper.AddData(&data_placeholder);
[email protected]1b323172011-03-01 17:50:171195
bnc691fda62016-08-12 00:43:161196 HttpNetworkTransaction trans1(DEFAULT_PRIORITY, helper.session());
1197 HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session());
[email protected]1b323172011-03-01 17:50:171198
[email protected]49639fa2011-12-20 23:22:411199 TestCompletionCallback callback1;
1200 TestCompletionCallback callback2;
[email protected]1b323172011-03-01 17:50:171201
[email protected]1b323172011-03-01 17:50:171202 // Preconnect the first.
[email protected]1b323172011-03-01 17:50:171203 HttpStreamFactory* http_stream_factory =
1204 helper.session()->http_stream_factory();
[email protected]1b323172011-03-01 17:50:171205
Bence Békydb3cf652017-10-10 15:22:101206 http_stream_factory->PreconnectStreams(1, request_);
[email protected]1b323172011-03-01 17:50:171207
Bence Békydb3cf652017-10-10 15:22:101208 out.rv = trans1.Start(&request_, callback1.callback(), log_);
robpercival214763f2016-07-01 23:27:011209 ASSERT_THAT(out.rv, IsError(ERR_IO_PENDING));
Bence Békydb3cf652017-10-10 15:22:101210 out.rv = trans2.Start(&request_, callback2.callback(), log_);
robpercival214763f2016-07-01 23:27:011211 ASSERT_THAT(out.rv, IsError(ERR_IO_PENDING));
[email protected]1b323172011-03-01 17:50:171212
1213 out.rv = callback1.WaitForResult();
robpercival214763f2016-07-01 23:27:011214 ASSERT_THAT(out.rv, IsOk());
[email protected]1b323172011-03-01 17:50:171215 out.rv = callback2.WaitForResult();
robpercival214763f2016-07-01 23:27:011216 ASSERT_THAT(out.rv, IsOk());
[email protected]1b323172011-03-01 17:50:171217
bnc691fda62016-08-12 00:43:161218 const HttpResponseInfo* response1 = trans1.GetResponseInfo();
wezca1070932016-05-26 20:30:521219 EXPECT_TRUE(response1->headers);
[email protected]1b323172011-03-01 17:50:171220 EXPECT_TRUE(response1->was_fetched_via_spdy);
1221 out.status_line = response1->headers->GetStatusLine();
1222 out.response_info = *response1;
bnc691fda62016-08-12 00:43:161223 out.rv = ReadTransaction(&trans1, &out.response_data);
robpercival214763f2016-07-01 23:27:011224 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:021225 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]1b323172011-03-01 17:50:171226 EXPECT_EQ("hello!hello!", out.response_data);
1227
bnc691fda62016-08-12 00:43:161228 const HttpResponseInfo* response2 = trans2.GetResponseInfo();
wezca1070932016-05-26 20:30:521229 EXPECT_TRUE(response2->headers);
[email protected]1b323172011-03-01 17:50:171230 EXPECT_TRUE(response2->was_fetched_via_spdy);
1231 out.status_line = response2->headers->GetStatusLine();
1232 out.response_info = *response2;
bnc691fda62016-08-12 00:43:161233 out.rv = ReadTransaction(&trans2, &out.response_data);
robpercival214763f2016-07-01 23:27:011234 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:021235 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]1b323172011-03-01 17:50:171236 EXPECT_EQ("hello!hello!", out.response_data);
1237
1238 helper.VerifyDataConsumed();
1239}
1240
[email protected]2bd93022010-07-17 00:58:441241// Similar to ThreeGets above, however this test adds a SETTINGS
1242// frame. The SETTINGS frame is read during the IO loop waiting on
1243// the first transaction completion, and sets a maximum concurrent
1244// stream limit of 1. This means that our IO loop exists after the
1245// second transaction completes, so we can assert on read_index().
bncd16676a2016-07-20 16:23:011246TEST_F(SpdyNetworkTransactionTest, ThreeGetsWithMaxConcurrent) {
[email protected]2bd93022010-07-17 00:58:441247 // Construct the request.
rdsmithebb50aa2015-11-12 03:44:381248 // Each request fully completes before the next starts.
Ryan Hamilton0239aac2018-05-19 00:03:131249 spdy::SpdySerializedFrame req(
1250 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
1251 spdy::SpdySerializedFrame resp(
1252 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
1253 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, false));
1254 spdy::SpdySerializedFrame fbody(spdy_util_.ConstructSpdyDataFrame(1, true));
rdsmithebb50aa2015-11-12 03:44:381255 spdy_util_.UpdateWithStreamDestruction(1);
[email protected]2bd93022010-07-17 00:58:441256
Ryan Hamilton0239aac2018-05-19 00:03:131257 spdy::SpdySerializedFrame req2(
1258 spdy_util_.ConstructSpdyGet(nullptr, 0, 3, LOWEST));
1259 spdy::SpdySerializedFrame resp2(
1260 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
1261 spdy::SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(3, false));
1262 spdy::SpdySerializedFrame fbody2(spdy_util_.ConstructSpdyDataFrame(3, true));
rdsmithebb50aa2015-11-12 03:44:381263 spdy_util_.UpdateWithStreamDestruction(3);
[email protected]2bd93022010-07-17 00:58:441264
Ryan Hamilton0239aac2018-05-19 00:03:131265 spdy::SpdySerializedFrame req3(
1266 spdy_util_.ConstructSpdyGet(nullptr, 0, 5, LOWEST));
1267 spdy::SpdySerializedFrame resp3(
1268 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 5));
1269 spdy::SpdySerializedFrame body3(spdy_util_.ConstructSpdyDataFrame(5, false));
1270 spdy::SpdySerializedFrame fbody3(spdy_util_.ConstructSpdyDataFrame(5, true));
[email protected]2bd93022010-07-17 00:58:441271
Ryan Hamilton0239aac2018-05-19 00:03:131272 spdy::SettingsMap settings;
Avi Drissman13fc8932015-12-20 04:40:461273 const uint32_t max_concurrent_streams = 1;
Ryan Hamilton0239aac2018-05-19 00:03:131274 settings[spdy::SETTINGS_MAX_CONCURRENT_STREAMS] = max_concurrent_streams;
1275 spdy::SpdySerializedFrame settings_frame(
[email protected]c10b20852013-05-15 21:29:201276 spdy_util_.ConstructSpdySettings(settings));
Ryan Hamilton0239aac2018-05-19 00:03:131277 spdy::SpdySerializedFrame settings_ack(spdy_util_.ConstructSpdySettingsAck());
[email protected]2bd93022010-07-17 00:58:441278
[email protected]2d6728692011-03-12 01:39:551279 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:411280 CreateMockWrite(req, 0), CreateMockWrite(settings_ack, 5),
1281 CreateMockWrite(req2, 6), CreateMockWrite(req3, 10),
[email protected]2bd93022010-07-17 00:58:441282 };
[email protected]2d6728692011-03-12 01:39:551283
[email protected]2bd93022010-07-17 00:58:441284 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:411285 CreateMockRead(settings_frame, 1),
1286 CreateMockRead(resp, 2),
1287 CreateMockRead(body, 3),
1288 CreateMockRead(fbody, 4),
1289 CreateMockRead(resp2, 7),
1290 CreateMockRead(body2, 8),
1291 CreateMockRead(fbody2, 9),
1292 CreateMockRead(resp3, 11),
1293 CreateMockRead(body3, 12),
1294 CreateMockRead(fbody3, 13),
[email protected]2bd93022010-07-17 00:58:441295
rch08e3aa3e2015-05-16 14:27:521296 MockRead(ASYNC, 0, 14), // EOF
[email protected]2bd93022010-07-17 00:58:441297 };
1298
Ryan Sleevib8d7ea02018-05-07 20:01:011299 SequencedSocketData data(reads, writes);
[email protected]2bd93022010-07-17 00:58:441300
[email protected]2bd93022010-07-17 00:58:441301 TransactionHelperResult out;
1302 {
Bence Békydb3cf652017-10-10 15:22:101303 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
1304 nullptr);
[email protected]2d6728692011-03-12 01:39:551305 helper.RunPreTestSetup();
[email protected]dd54bd82012-07-19 23:44:571306 helper.AddData(&data);
bnc691fda62016-08-12 00:43:161307 HttpNetworkTransaction trans1(DEFAULT_PRIORITY, helper.session());
1308 HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session());
1309 HttpNetworkTransaction trans3(DEFAULT_PRIORITY, helper.session());
[email protected]2bd93022010-07-17 00:58:441310
[email protected]49639fa2011-12-20 23:22:411311 TestCompletionCallback callback1;
1312 TestCompletionCallback callback2;
1313 TestCompletionCallback callback3;
[email protected]2bd93022010-07-17 00:58:441314
Bence Békydb3cf652017-10-10 15:22:101315 out.rv = trans1.Start(&request_, callback1.callback(), log_);
[email protected]2bd93022010-07-17 00:58:441316 ASSERT_EQ(out.rv, ERR_IO_PENDING);
[email protected]513963e2013-06-15 01:53:041317 // Run transaction 1 through quickly to force a read of our SETTINGS
1318 // frame.
[email protected]2bd93022010-07-17 00:58:441319 out.rv = callback1.WaitForResult();
robpercival214763f2016-07-01 23:27:011320 ASSERT_THAT(out.rv, IsOk());
[email protected]2bd93022010-07-17 00:58:441321
Bence Békydb3cf652017-10-10 15:22:101322 out.rv = trans2.Start(&request_, callback2.callback(), log_);
[email protected]2bd93022010-07-17 00:58:441323 ASSERT_EQ(out.rv, ERR_IO_PENDING);
Bence Békydb3cf652017-10-10 15:22:101324 out.rv = trans3.Start(&request_, callback3.callback(), log_);
[email protected]2bd93022010-07-17 00:58:441325 ASSERT_EQ(out.rv, ERR_IO_PENDING);
1326 out.rv = callback2.WaitForResult();
robpercival214763f2016-07-01 23:27:011327 ASSERT_THAT(out.rv, IsOk());
[email protected]2bd93022010-07-17 00:58:441328
1329 out.rv = callback3.WaitForResult();
robpercival214763f2016-07-01 23:27:011330 ASSERT_THAT(out.rv, IsOk());
[email protected]2bd93022010-07-17 00:58:441331
bnc691fda62016-08-12 00:43:161332 const HttpResponseInfo* response1 = trans1.GetResponseInfo();
wezca1070932016-05-26 20:30:521333 ASSERT_TRUE(response1);
1334 EXPECT_TRUE(response1->headers);
[email protected]2bd93022010-07-17 00:58:441335 EXPECT_TRUE(response1->was_fetched_via_spdy);
1336 out.status_line = response1->headers->GetStatusLine();
1337 out.response_info = *response1;
bnc691fda62016-08-12 00:43:161338 out.rv = ReadTransaction(&trans1, &out.response_data);
robpercival214763f2016-07-01 23:27:011339 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:021340 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]2bd93022010-07-17 00:58:441341 EXPECT_EQ("hello!hello!", out.response_data);
1342
bnc691fda62016-08-12 00:43:161343 const HttpResponseInfo* response2 = trans2.GetResponseInfo();
[email protected]2bd93022010-07-17 00:58:441344 out.status_line = response2->headers->GetStatusLine();
1345 out.response_info = *response2;
bnc691fda62016-08-12 00:43:161346 out.rv = ReadTransaction(&trans2, &out.response_data);
robpercival214763f2016-07-01 23:27:011347 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:021348 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]2bd93022010-07-17 00:58:441349 EXPECT_EQ("hello!hello!", out.response_data);
1350
bnc691fda62016-08-12 00:43:161351 const HttpResponseInfo* response3 = trans3.GetResponseInfo();
[email protected]2bd93022010-07-17 00:58:441352 out.status_line = response3->headers->GetStatusLine();
1353 out.response_info = *response3;
bnc691fda62016-08-12 00:43:161354 out.rv = ReadTransaction(&trans3, &out.response_data);
robpercival214763f2016-07-01 23:27:011355 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:021356 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]2bd93022010-07-17 00:58:441357 EXPECT_EQ("hello!hello!", out.response_data);
[email protected]044dcc52010-09-17 15:44:261358
1359 helper.VerifyDataConsumed();
[email protected]2bd93022010-07-17 00:58:441360 }
robpercival214763f2016-07-01 23:27:011361 EXPECT_THAT(out.rv, IsOk());
[email protected]2bd93022010-07-17 00:58:441362}
1363
1364// Similar to ThreeGetsWithMaxConcurrent above, however this test adds
1365// a fourth transaction. The third and fourth transactions have
1366// different data ("hello!" vs "hello!hello!") and because of the
1367// user specified priority, we expect to see them inverted in
1368// the response from the server.
bncd16676a2016-07-20 16:23:011369TEST_F(SpdyNetworkTransactionTest, FourGetsWithMaxConcurrentPriority) {
[email protected]2bd93022010-07-17 00:58:441370 // Construct the request.
Ryan Hamilton0239aac2018-05-19 00:03:131371 spdy::SpdySerializedFrame req(
1372 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
1373 spdy::SpdySerializedFrame resp(
1374 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
1375 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, false));
1376 spdy::SpdySerializedFrame fbody(spdy_util_.ConstructSpdyDataFrame(1, true));
rdsmithebb50aa2015-11-12 03:44:381377 spdy_util_.UpdateWithStreamDestruction(1);
[email protected]2bd93022010-07-17 00:58:441378
Ryan Hamilton0239aac2018-05-19 00:03:131379 spdy::SpdySerializedFrame req2(
1380 spdy_util_.ConstructSpdyGet(nullptr, 0, 3, LOWEST));
1381 spdy::SpdySerializedFrame resp2(
1382 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
1383 spdy::SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(3, false));
1384 spdy::SpdySerializedFrame fbody2(spdy_util_.ConstructSpdyDataFrame(3, true));
rdsmithebb50aa2015-11-12 03:44:381385 spdy_util_.UpdateWithStreamDestruction(3);
[email protected]2bd93022010-07-17 00:58:441386
Ryan Hamilton0239aac2018-05-19 00:03:131387 spdy::SpdySerializedFrame req4(
1388 spdy_util_.ConstructSpdyGet(nullptr, 0, 5, HIGHEST));
1389 spdy::SpdySerializedFrame resp4(
1390 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 5));
1391 spdy::SpdySerializedFrame fbody4(spdy_util_.ConstructSpdyDataFrame(5, true));
rdsmithebb50aa2015-11-12 03:44:381392 spdy_util_.UpdateWithStreamDestruction(5);
[email protected]2bd93022010-07-17 00:58:441393
Ryan Hamilton0239aac2018-05-19 00:03:131394 spdy::SpdySerializedFrame req3(
1395 spdy_util_.ConstructSpdyGet(nullptr, 0, 7, LOWEST));
1396 spdy::SpdySerializedFrame resp3(
1397 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 7));
1398 spdy::SpdySerializedFrame body3(spdy_util_.ConstructSpdyDataFrame(7, false));
1399 spdy::SpdySerializedFrame fbody3(spdy_util_.ConstructSpdyDataFrame(7, true));
[email protected]2bd93022010-07-17 00:58:441400
Ryan Hamilton0239aac2018-05-19 00:03:131401 spdy::SettingsMap settings;
Avi Drissman13fc8932015-12-20 04:40:461402 const uint32_t max_concurrent_streams = 1;
Ryan Hamilton0239aac2018-05-19 00:03:131403 settings[spdy::SETTINGS_MAX_CONCURRENT_STREAMS] = max_concurrent_streams;
1404 spdy::SpdySerializedFrame settings_frame(
[email protected]c10b20852013-05-15 21:29:201405 spdy_util_.ConstructSpdySettings(settings));
Ryan Hamilton0239aac2018-05-19 00:03:131406 spdy::SpdySerializedFrame settings_ack(spdy_util_.ConstructSpdySettingsAck());
rch08e3aa3e2015-05-16 14:27:521407 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:411408 CreateMockWrite(req, 0), CreateMockWrite(settings_ack, 5),
rch08e3aa3e2015-05-16 14:27:521409 // By making these synchronous, it guarantees that they are not *started*
1410 // before their sequence number, which in turn verifies that only a single
1411 // request is in-flight at a time.
bncdf80d44fd2016-07-15 20:27:411412 CreateMockWrite(req2, 6, SYNCHRONOUS),
1413 CreateMockWrite(req4, 10, SYNCHRONOUS),
1414 CreateMockWrite(req3, 13, SYNCHRONOUS),
[email protected]2bd93022010-07-17 00:58:441415 };
1416 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:411417 CreateMockRead(settings_frame, 1),
1418 CreateMockRead(resp, 2),
1419 CreateMockRead(body, 3),
1420 CreateMockRead(fbody, 4),
1421 CreateMockRead(resp2, 7),
1422 CreateMockRead(body2, 8),
1423 CreateMockRead(fbody2, 9),
1424 CreateMockRead(resp4, 11),
1425 CreateMockRead(fbody4, 12),
1426 CreateMockRead(resp3, 14),
1427 CreateMockRead(body3, 15),
1428 CreateMockRead(fbody3, 16),
[email protected]2bd93022010-07-17 00:58:441429
rch08e3aa3e2015-05-16 14:27:521430 MockRead(ASYNC, 0, 17), // EOF
[email protected]2bd93022010-07-17 00:58:441431 };
Ryan Sleevib8d7ea02018-05-07 20:01:011432 SequencedSocketData data(reads, writes);
[email protected]2bd93022010-07-17 00:58:441433 TransactionHelperResult out;
Bence Békydb3cf652017-10-10 15:22:101434 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]bdebd1b2010-08-09 20:18:081435 helper.RunPreTestSetup();
[email protected]dd54bd82012-07-19 23:44:571436 helper.AddData(&data);
rch08e3aa3e2015-05-16 14:27:521437
bnc691fda62016-08-12 00:43:161438 HttpNetworkTransaction trans1(DEFAULT_PRIORITY, helper.session());
1439 HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session());
1440 HttpNetworkTransaction trans3(DEFAULT_PRIORITY, helper.session());
1441 HttpNetworkTransaction trans4(HIGHEST, helper.session());
[email protected]2bd93022010-07-17 00:58:441442
[email protected]49639fa2011-12-20 23:22:411443 TestCompletionCallback callback1;
1444 TestCompletionCallback callback2;
1445 TestCompletionCallback callback3;
1446 TestCompletionCallback callback4;
[email protected]2bd93022010-07-17 00:58:441447
Bence Békydb3cf652017-10-10 15:22:101448 out.rv = trans1.Start(&request_, callback1.callback(), log_);
robpercival214763f2016-07-01 23:27:011449 ASSERT_THAT(out.rv, IsError(ERR_IO_PENDING));
[email protected]e0935cc2012-03-24 14:12:481450 // Run transaction 1 through quickly to force a read of our SETTINGS frame.
[email protected]bdebd1b2010-08-09 20:18:081451 out.rv = callback1.WaitForResult();
robpercival214763f2016-07-01 23:27:011452 ASSERT_THAT(out.rv, IsOk());
[email protected]2bd93022010-07-17 00:58:441453
bnceb9aa7112017-01-05 01:03:461454 // Finish async network reads and writes associated with |trans1|.
1455 base::RunLoop().RunUntilIdle();
1456
Bence Békydb3cf652017-10-10 15:22:101457 out.rv = trans2.Start(&request_, callback2.callback(), log_);
robpercival214763f2016-07-01 23:27:011458 ASSERT_THAT(out.rv, IsError(ERR_IO_PENDING));
Bence Békydb3cf652017-10-10 15:22:101459 out.rv = trans3.Start(&request_, callback3.callback(), log_);
robpercival214763f2016-07-01 23:27:011460 ASSERT_THAT(out.rv, IsError(ERR_IO_PENDING));
Bence Békydb3cf652017-10-10 15:22:101461 out.rv = trans4.Start(&request_, callback4.callback(), log_);
robpercival214763f2016-07-01 23:27:011462 ASSERT_THAT(out.rv, IsError(ERR_IO_PENDING));
[email protected]2bd93022010-07-17 00:58:441463
[email protected]bdebd1b2010-08-09 20:18:081464 out.rv = callback2.WaitForResult();
robpercival214763f2016-07-01 23:27:011465 ASSERT_THAT(out.rv, IsOk());
[email protected]2bd93022010-07-17 00:58:441466
[email protected]bdebd1b2010-08-09 20:18:081467 out.rv = callback3.WaitForResult();
robpercival214763f2016-07-01 23:27:011468 ASSERT_THAT(out.rv, IsOk());
[email protected]2bd93022010-07-17 00:58:441469
bnc691fda62016-08-12 00:43:161470 const HttpResponseInfo* response1 = trans1.GetResponseInfo();
wezca1070932016-05-26 20:30:521471 EXPECT_TRUE(response1->headers);
[email protected]bdebd1b2010-08-09 20:18:081472 EXPECT_TRUE(response1->was_fetched_via_spdy);
1473 out.status_line = response1->headers->GetStatusLine();
1474 out.response_info = *response1;
bnc691fda62016-08-12 00:43:161475 out.rv = ReadTransaction(&trans1, &out.response_data);
robpercival214763f2016-07-01 23:27:011476 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:021477 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]bdebd1b2010-08-09 20:18:081478 EXPECT_EQ("hello!hello!", out.response_data);
[email protected]2bd93022010-07-17 00:58:441479
bnc691fda62016-08-12 00:43:161480 const HttpResponseInfo* response2 = trans2.GetResponseInfo();
[email protected]bdebd1b2010-08-09 20:18:081481 out.status_line = response2->headers->GetStatusLine();
1482 out.response_info = *response2;
bnc691fda62016-08-12 00:43:161483 out.rv = ReadTransaction(&trans2, &out.response_data);
robpercival214763f2016-07-01 23:27:011484 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:021485 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]bdebd1b2010-08-09 20:18:081486 EXPECT_EQ("hello!hello!", out.response_data);
[email protected]2bd93022010-07-17 00:58:441487
[email protected]bdebd1b2010-08-09 20:18:081488 // notice: response3 gets two hellos, response4 gets one
1489 // hello, so we know dequeuing priority was respected.
bnc691fda62016-08-12 00:43:161490 const HttpResponseInfo* response3 = trans3.GetResponseInfo();
[email protected]bdebd1b2010-08-09 20:18:081491 out.status_line = response3->headers->GetStatusLine();
1492 out.response_info = *response3;
bnc691fda62016-08-12 00:43:161493 out.rv = ReadTransaction(&trans3, &out.response_data);
robpercival214763f2016-07-01 23:27:011494 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:021495 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]bdebd1b2010-08-09 20:18:081496 EXPECT_EQ("hello!hello!", out.response_data);
[email protected]2bd93022010-07-17 00:58:441497
[email protected]bdebd1b2010-08-09 20:18:081498 out.rv = callback4.WaitForResult();
robpercival214763f2016-07-01 23:27:011499 EXPECT_THAT(out.rv, IsOk());
bnc691fda62016-08-12 00:43:161500 const HttpResponseInfo* response4 = trans4.GetResponseInfo();
[email protected]bdebd1b2010-08-09 20:18:081501 out.status_line = response4->headers->GetStatusLine();
1502 out.response_info = *response4;
bnc691fda62016-08-12 00:43:161503 out.rv = ReadTransaction(&trans4, &out.response_data);
robpercival214763f2016-07-01 23:27:011504 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:021505 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]bdebd1b2010-08-09 20:18:081506 EXPECT_EQ("hello!", out.response_data);
1507 helper.VerifyDataConsumed();
robpercival214763f2016-07-01 23:27:011508 EXPECT_THAT(out.rv, IsOk());
[email protected]2bd93022010-07-17 00:58:441509}
1510
1511// Similar to ThreeGetsMaxConcurrrent above, however, this test
rch08e3aa3e2015-05-16 14:27:521512// deletes a session in the middle of the transaction to ensure
[email protected]2bd93022010-07-17 00:58:441513// that we properly remove pendingcreatestream objects from
1514// the spdy_session
bncd16676a2016-07-20 16:23:011515TEST_F(SpdyNetworkTransactionTest, ThreeGetsWithMaxConcurrentDelete) {
[email protected]2bd93022010-07-17 00:58:441516 // Construct the request.
Ryan Hamilton0239aac2018-05-19 00:03:131517 spdy::SpdySerializedFrame req(
1518 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
1519 spdy::SpdySerializedFrame resp(
1520 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
1521 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, false));
1522 spdy::SpdySerializedFrame fbody(spdy_util_.ConstructSpdyDataFrame(1, true));
rdsmithebb50aa2015-11-12 03:44:381523 spdy_util_.UpdateWithStreamDestruction(1);
[email protected]2bd93022010-07-17 00:58:441524
Ryan Hamilton0239aac2018-05-19 00:03:131525 spdy::SpdySerializedFrame req2(
1526 spdy_util_.ConstructSpdyGet(nullptr, 0, 3, LOWEST));
1527 spdy::SpdySerializedFrame resp2(
1528 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
1529 spdy::SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(3, false));
1530 spdy::SpdySerializedFrame fbody2(spdy_util_.ConstructSpdyDataFrame(3, true));
[email protected]2bd93022010-07-17 00:58:441531
Ryan Hamilton0239aac2018-05-19 00:03:131532 spdy::SettingsMap settings;
Avi Drissman13fc8932015-12-20 04:40:461533 const uint32_t max_concurrent_streams = 1;
Ryan Hamilton0239aac2018-05-19 00:03:131534 settings[spdy::SETTINGS_MAX_CONCURRENT_STREAMS] = max_concurrent_streams;
1535 spdy::SpdySerializedFrame settings_frame(
[email protected]c10b20852013-05-15 21:29:201536 spdy_util_.ConstructSpdySettings(settings));
Ryan Hamilton0239aac2018-05-19 00:03:131537 spdy::SpdySerializedFrame settings_ack(spdy_util_.ConstructSpdySettingsAck());
[email protected]2bd93022010-07-17 00:58:441538
[email protected]d4a77c12014-05-15 20:45:211539 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:411540 CreateMockWrite(req, 0), CreateMockWrite(settings_ack, 5),
1541 CreateMockWrite(req2, 6),
[email protected]2bd93022010-07-17 00:58:441542 };
1543 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:411544 CreateMockRead(settings_frame, 1), CreateMockRead(resp, 2),
1545 CreateMockRead(body, 3), CreateMockRead(fbody, 4),
1546 CreateMockRead(resp2, 7), CreateMockRead(body2, 8),
1547 CreateMockRead(fbody2, 9), MockRead(ASYNC, 0, 10), // EOF
[email protected]2bd93022010-07-17 00:58:441548 };
1549
Ryan Sleevib8d7ea02018-05-07 20:01:011550 SequencedSocketData data(reads, writes);
[email protected]2bd93022010-07-17 00:58:441551
[email protected]2bd93022010-07-17 00:58:441552 TransactionHelperResult out;
Bence Békydb3cf652017-10-10 15:22:101553 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]bdebd1b2010-08-09 20:18:081554 helper.RunPreTestSetup();
[email protected]dd54bd82012-07-19 23:44:571555 helper.AddData(&data);
Jeremy Roman0579ed62017-08-29 15:56:191556 auto trans1 = std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY,
bnc3f6a8552017-05-17 13:40:341557 helper.session());
Jeremy Roman0579ed62017-08-29 15:56:191558 auto trans2 = std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY,
bnc3f6a8552017-05-17 13:40:341559 helper.session());
Jeremy Roman0579ed62017-08-29 15:56:191560 auto trans3 = std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY,
bnc3f6a8552017-05-17 13:40:341561 helper.session());
[email protected]2bd93022010-07-17 00:58:441562
[email protected]49639fa2011-12-20 23:22:411563 TestCompletionCallback callback1;
1564 TestCompletionCallback callback2;
1565 TestCompletionCallback callback3;
[email protected]2bd93022010-07-17 00:58:441566
Bence Békydb3cf652017-10-10 15:22:101567 out.rv = trans1->Start(&request_, callback1.callback(), log_);
[email protected]bdebd1b2010-08-09 20:18:081568 ASSERT_EQ(out.rv, ERR_IO_PENDING);
[email protected]e0935cc2012-03-24 14:12:481569 // Run transaction 1 through quickly to force a read of our SETTINGS frame.
[email protected]bdebd1b2010-08-09 20:18:081570 out.rv = callback1.WaitForResult();
robpercival214763f2016-07-01 23:27:011571 ASSERT_THAT(out.rv, IsOk());
[email protected]2bd93022010-07-17 00:58:441572
Bence Békydb3cf652017-10-10 15:22:101573 out.rv = trans2->Start(&request_, callback2.callback(), log_);
[email protected]bdebd1b2010-08-09 20:18:081574 ASSERT_EQ(out.rv, ERR_IO_PENDING);
Bence Békydb3cf652017-10-10 15:22:101575 out.rv = trans3->Start(&request_, callback3.callback(), log_);
olli.raula7ca9cd1d2016-01-04 06:50:371576 trans3.reset();
[email protected]bdebd1b2010-08-09 20:18:081577 ASSERT_EQ(out.rv, ERR_IO_PENDING);
1578 out.rv = callback2.WaitForResult();
robpercival214763f2016-07-01 23:27:011579 ASSERT_THAT(out.rv, IsOk());
[email protected]2bd93022010-07-17 00:58:441580
[email protected]bdebd1b2010-08-09 20:18:081581 const HttpResponseInfo* response1 = trans1->GetResponseInfo();
wezca1070932016-05-26 20:30:521582 ASSERT_TRUE(response1);
1583 EXPECT_TRUE(response1->headers);
[email protected]bdebd1b2010-08-09 20:18:081584 EXPECT_TRUE(response1->was_fetched_via_spdy);
1585 out.status_line = response1->headers->GetStatusLine();
1586 out.response_info = *response1;
1587 out.rv = ReadTransaction(trans1.get(), &out.response_data);
robpercival214763f2016-07-01 23:27:011588 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:021589 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]bdebd1b2010-08-09 20:18:081590 EXPECT_EQ("hello!hello!", out.response_data);
[email protected]2bd93022010-07-17 00:58:441591
[email protected]bdebd1b2010-08-09 20:18:081592 const HttpResponseInfo* response2 = trans2->GetResponseInfo();
wezca1070932016-05-26 20:30:521593 ASSERT_TRUE(response2);
[email protected]bdebd1b2010-08-09 20:18:081594 out.status_line = response2->headers->GetStatusLine();
1595 out.response_info = *response2;
1596 out.rv = ReadTransaction(trans2.get(), &out.response_data);
robpercival214763f2016-07-01 23:27:011597 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:021598 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]bdebd1b2010-08-09 20:18:081599 EXPECT_EQ("hello!hello!", out.response_data);
1600 helper.VerifyDataConsumed();
robpercival214763f2016-07-01 23:27:011601 EXPECT_THAT(out.rv, IsOk());
[email protected]044dcc52010-09-17 15:44:261602}
[email protected]2bd93022010-07-17 00:58:441603
[email protected]448d4ca52012-03-04 04:12:231604namespace {
1605
Bence Béky8ddc2492018-06-13 01:02:041606// A helper class that will delete |transaction| on error when the callback is
1607// invoked.
[email protected]49639fa2011-12-20 23:22:411608class KillerCallback : public TestCompletionCallbackBase {
[email protected]044dcc52010-09-17 15:44:261609 public:
1610 explicit KillerCallback(HttpNetworkTransaction* transaction)
Bence Béky8ddc2492018-06-13 01:02:041611 : transaction_(transaction) {}
[email protected]044dcc52010-09-17 15:44:261612
Chris Watkins61914cb2017-12-01 19:59:001613 ~KillerCallback() override = default;
[email protected]49639fa2011-12-20 23:22:411614
Bence Béky8ddc2492018-06-13 01:02:041615 CompletionOnceCallback callback() {
1616 return base::BindOnce(&KillerCallback::OnComplete, base::Unretained(this));
1617 }
[email protected]49639fa2011-12-20 23:22:411618
[email protected]044dcc52010-09-17 15:44:261619 private:
[email protected]49639fa2011-12-20 23:22:411620 void OnComplete(int result) {
1621 if (result < 0)
1622 delete transaction_;
1623
1624 SetResult(result);
1625 }
1626
[email protected]044dcc52010-09-17 15:44:261627 HttpNetworkTransaction* transaction_;
1628};
1629
[email protected]448d4ca52012-03-04 04:12:231630} // namespace
1631
[email protected]044dcc52010-09-17 15:44:261632// Similar to ThreeGetsMaxConcurrrentDelete above, however, this test
1633// closes the socket while we have a pending transaction waiting for
1634// a pending stream creation. http://crbug.com/52901
bncd16676a2016-07-20 16:23:011635TEST_F(SpdyNetworkTransactionTest, ThreeGetsWithMaxConcurrentSocketClose) {
Matt Menke66e502a72019-04-15 13:34:381636 // Construct the request. Each stream uses a different priority to provide
1637 // more useful failure information if the requests are made in an unexpected
1638 // order.
Ryan Hamilton0239aac2018-05-19 00:03:131639 spdy::SpdySerializedFrame req(
Matt Menke66e502a72019-04-15 13:34:381640 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, HIGHEST));
Ryan Hamilton0239aac2018-05-19 00:03:131641 spdy::SpdySerializedFrame resp(
1642 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
1643 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, false));
1644 spdy::SpdySerializedFrame fin_body(
1645 spdy_util_.ConstructSpdyDataFrame(1, true));
rdsmithebb50aa2015-11-12 03:44:381646 spdy_util_.UpdateWithStreamDestruction(1);
[email protected]044dcc52010-09-17 15:44:261647
Ryan Hamilton0239aac2018-05-19 00:03:131648 spdy::SpdySerializedFrame req2(
Matt Menke66e502a72019-04-15 13:34:381649 spdy_util_.ConstructSpdyGet(nullptr, 0, 3, MEDIUM));
Ryan Hamilton0239aac2018-05-19 00:03:131650 spdy::SpdySerializedFrame resp2(
1651 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
[email protected]044dcc52010-09-17 15:44:261652
Ryan Hamilton0239aac2018-05-19 00:03:131653 spdy::SettingsMap settings;
Avi Drissman13fc8932015-12-20 04:40:461654 const uint32_t max_concurrent_streams = 1;
Ryan Hamilton0239aac2018-05-19 00:03:131655 settings[spdy::SETTINGS_MAX_CONCURRENT_STREAMS] = max_concurrent_streams;
1656 spdy::SpdySerializedFrame settings_frame(
[email protected]c10b20852013-05-15 21:29:201657 spdy_util_.ConstructSpdySettings(settings));
Ryan Hamilton0239aac2018-05-19 00:03:131658 spdy::SpdySerializedFrame settings_ack(spdy_util_.ConstructSpdySettingsAck());
[email protected]044dcc52010-09-17 15:44:261659
Matt Menke66e502a72019-04-15 13:34:381660 MockWrite writes[] = {CreateMockWrite(req, 0),
1661 CreateMockWrite(settings_ack, 6),
1662 CreateMockWrite(req2, 7)};
[email protected]044dcc52010-09-17 15:44:261663 MockRead reads[] = {
Matt Menke66e502a72019-04-15 13:34:381664 CreateMockRead(settings_frame, 1), CreateMockRead(resp, 2),
bncdf80d44fd2016-07-15 20:27:411665 CreateMockRead(body, 3),
Matt Menke66e502a72019-04-15 13:34:381666 // Delay the request here. For this test to pass, the three HTTP streams
1667 // have to be created in order, but SpdySession doesn't actually guarantee
1668 // that (See note in SpdySession::ProcessPendingStreamRequests). As a
1669 // workaround, delay finishing up the first stream until the second and
1670 // third streams are waiting in the SPDY stream request queue.
1671 MockRead(ASYNC, ERR_IO_PENDING, 4), CreateMockRead(fin_body, 5),
1672 CreateMockRead(resp2, 8),
David Benjamin73dc5242019-05-15 21:59:281673 // The exact error does not matter, but some errors, such as
1674 // ERR_CONNECTION_RESET, may trigger a retry, which this test does not
1675 // account for.
1676 MockRead(ASYNC, ERR_SSL_BAD_RECORD_MAC_ALERT, 9), // Abort!
[email protected]044dcc52010-09-17 15:44:261677 };
1678
Ryan Sleevib8d7ea02018-05-07 20:01:011679 SequencedSocketData data(reads, writes);
1680 SequencedSocketData data_placeholder;
[email protected]044dcc52010-09-17 15:44:261681
[email protected]044dcc52010-09-17 15:44:261682 TransactionHelperResult out;
Matt Menke66e502a72019-04-15 13:34:381683 NormalSpdyTransactionHelper helper(request_, HIGHEST, log_, nullptr);
[email protected]044dcc52010-09-17 15:44:261684 helper.RunPreTestSetup();
[email protected]dd54bd82012-07-19 23:44:571685 helper.AddData(&data);
[email protected]044dcc52010-09-17 15:44:261686 // We require placeholder data because three get requests are sent out, so
1687 // there needs to be three sets of SSL connection data.
[email protected]dd54bd82012-07-19 23:44:571688 helper.AddData(&data_placeholder);
1689 helper.AddData(&data_placeholder);
Matt Menke66e502a72019-04-15 13:34:381690 HttpNetworkTransaction trans1(HIGHEST, helper.session());
1691 HttpNetworkTransaction trans2(MEDIUM, helper.session());
[email protected]262eec82013-03-19 21:01:361692 HttpNetworkTransaction* trans3(
mmenkee65e7af2015-10-13 17:16:421693 new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session()));
[email protected]044dcc52010-09-17 15:44:261694
[email protected]49639fa2011-12-20 23:22:411695 TestCompletionCallback callback1;
1696 TestCompletionCallback callback2;
[email protected]044dcc52010-09-17 15:44:261697 KillerCallback callback3(trans3);
1698
Bence Békydb3cf652017-10-10 15:22:101699 out.rv = trans1.Start(&request_, callback1.callback(), log_);
[email protected]044dcc52010-09-17 15:44:261700 ASSERT_EQ(out.rv, ERR_IO_PENDING);
[email protected]e0935cc2012-03-24 14:12:481701 // Run transaction 1 through quickly to force a read of our SETTINGS frame.
[email protected]044dcc52010-09-17 15:44:261702 out.rv = callback1.WaitForResult();
robpercival214763f2016-07-01 23:27:011703 ASSERT_THAT(out.rv, IsOk());
[email protected]044dcc52010-09-17 15:44:261704
Bence Békydb3cf652017-10-10 15:22:101705 out.rv = trans2.Start(&request_, callback2.callback(), log_);
[email protected]044dcc52010-09-17 15:44:261706 ASSERT_EQ(out.rv, ERR_IO_PENDING);
Bence Békydb3cf652017-10-10 15:22:101707 out.rv = trans3->Start(&request_, callback3.callback(), log_);
[email protected]044dcc52010-09-17 15:44:261708 ASSERT_EQ(out.rv, ERR_IO_PENDING);
Matt Menke66e502a72019-04-15 13:34:381709
1710 // Run until both transactions are in the SpdySession's queue, waiting for the
1711 // final request to complete.
1712 base::RunLoop().RunUntilIdle();
1713 data.Resume();
1714
[email protected]044dcc52010-09-17 15:44:261715 out.rv = callback3.WaitForResult();
David Benjamin73dc5242019-05-15 21:59:281716 EXPECT_THAT(out.rv, IsError(ERR_SSL_BAD_RECORD_MAC_ALERT));
[email protected]044dcc52010-09-17 15:44:261717
[email protected]044dcc52010-09-17 15:44:261718 const HttpResponseInfo* response1 = trans1.GetResponseInfo();
wezca1070932016-05-26 20:30:521719 ASSERT_TRUE(response1);
1720 EXPECT_TRUE(response1->headers);
[email protected]044dcc52010-09-17 15:44:261721 EXPECT_TRUE(response1->was_fetched_via_spdy);
1722 out.status_line = response1->headers->GetStatusLine();
1723 out.response_info = *response1;
1724 out.rv = ReadTransaction(&trans1, &out.response_data);
robpercival214763f2016-07-01 23:27:011725 EXPECT_THAT(out.rv, IsOk());
[email protected]044dcc52010-09-17 15:44:261726
1727 const HttpResponseInfo* response2 = trans2.GetResponseInfo();
wezca1070932016-05-26 20:30:521728 ASSERT_TRUE(response2);
[email protected]044dcc52010-09-17 15:44:261729 out.status_line = response2->headers->GetStatusLine();
1730 out.response_info = *response2;
1731 out.rv = ReadTransaction(&trans2, &out.response_data);
David Benjamin73dc5242019-05-15 21:59:281732 EXPECT_THAT(out.rv, IsError(ERR_SSL_BAD_RECORD_MAC_ALERT));
[email protected]044dcc52010-09-17 15:44:261733
1734 helper.VerifyDataConsumed();
[email protected]2bd93022010-07-17 00:58:441735}
1736
[email protected]d8ef27b2010-08-06 17:34:391737// Test that a simple PUT request works.
bncd16676a2016-07-20 16:23:011738TEST_F(SpdyNetworkTransactionTest, Put) {
Bence Békydb3cf652017-10-10 15:22:101739 // Setup the request.
1740 request_.method = "PUT";
[email protected]d8ef27b2010-08-06 17:34:391741
Bence Béky4c325e52020-10-22 20:48:011742 spdy::Http2HeaderBlock put_headers(
bncb26024382016-06-29 02:39:451743 spdy_util_.ConstructPutHeaderBlock(kDefaultUrl, 0));
Ryan Hamilton0239aac2018-05-19 00:03:131744 spdy::SpdySerializedFrame req(
bnc42331402016-07-25 13:36:151745 spdy_util_.ConstructSpdyHeaders(1, std::move(put_headers), LOWEST, true));
[email protected]d8ef27b2010-08-06 17:34:391746 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:411747 CreateMockWrite(req, 0),
[email protected]d8ef27b2010-08-06 17:34:391748 };
1749
Ryan Hamilton0239aac2018-05-19 00:03:131750 spdy::SpdySerializedFrame resp(
1751 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
1752 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]d8ef27b2010-08-06 17:34:391753 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:411754 CreateMockRead(resp, 1), CreateMockRead(body, 2),
rch08e3aa3e2015-05-16 14:27:521755 MockRead(ASYNC, 0, 3) // EOF
[email protected]d8ef27b2010-08-06 17:34:391756 };
1757
Ryan Sleevib8d7ea02018-05-07 20:01:011758 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:101759 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]dd54bd82012-07-19 23:44:571760 helper.RunToCompletion(&data);
[email protected]d8ef27b2010-08-06 17:34:391761 TransactionHelperResult out = helper.output();
1762
robpercival214763f2016-07-01 23:27:011763 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:021764 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]d8ef27b2010-08-06 17:34:391765}
1766
1767// Test that a simple HEAD request works.
bncd16676a2016-07-20 16:23:011768TEST_F(SpdyNetworkTransactionTest, Head) {
Bence Békydb3cf652017-10-10 15:22:101769 // Setup the request.
1770 request_.method = "HEAD";
[email protected]d8ef27b2010-08-06 17:34:391771
Bence Béky4c325e52020-10-22 20:48:011772 spdy::Http2HeaderBlock head_headers(
bncb26024382016-06-29 02:39:451773 spdy_util_.ConstructHeadHeaderBlock(kDefaultUrl, 0));
Ryan Hamilton0239aac2018-05-19 00:03:131774 spdy::SpdySerializedFrame req(spdy_util_.ConstructSpdyHeaders(
bnc42331402016-07-25 13:36:151775 1, std::move(head_headers), LOWEST, true));
[email protected]d8ef27b2010-08-06 17:34:391776 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:411777 CreateMockWrite(req, 0),
[email protected]d8ef27b2010-08-06 17:34:391778 };
1779
Ryan Hamilton0239aac2018-05-19 00:03:131780 spdy::SpdySerializedFrame resp(
1781 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
1782 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]d8ef27b2010-08-06 17:34:391783 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:411784 CreateMockRead(resp, 1), CreateMockRead(body, 2),
rch08e3aa3e2015-05-16 14:27:521785 MockRead(ASYNC, 0, 3) // EOF
[email protected]d8ef27b2010-08-06 17:34:391786 };
1787
Ryan Sleevib8d7ea02018-05-07 20:01:011788 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:101789 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]dd54bd82012-07-19 23:44:571790 helper.RunToCompletion(&data);
[email protected]d8ef27b2010-08-06 17:34:391791 TransactionHelperResult out = helper.output();
1792
robpercival214763f2016-07-01 23:27:011793 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:021794 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]d8ef27b2010-08-06 17:34:391795}
1796
[email protected]72552f02009-10-28 15:25:011797// Test that a simple POST works.
bncd16676a2016-07-20 16:23:011798TEST_F(SpdyNetworkTransactionTest, Post) {
Ryan Hamilton0239aac2018-05-19 00:03:131799 spdy::SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
tombergan5d22c182017-01-11 02:05:351800 kDefaultUrl, 1, kUploadDataSize, LOWEST, nullptr, 0));
Ryan Hamilton0239aac2018-05-19 00:03:131801 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]ff57bb82009-11-12 06:52:141802 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:411803 CreateMockWrite(req, 0), CreateMockWrite(body, 1), // POST upload frame
[email protected]ff57bb82009-11-12 06:52:141804 };
[email protected]72552f02009-10-28 15:25:011805
Ryan Hamilton0239aac2018-05-19 00:03:131806 spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
[email protected]ff57bb82009-11-12 06:52:141807 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:411808 CreateMockRead(resp, 2), CreateMockRead(body, 3),
rch08e3aa3e2015-05-16 14:27:521809 MockRead(ASYNC, 0, 4) // EOF
[email protected]aea80602009-09-18 00:55:081810 };
1811
Ryan Sleevib8d7ea02018-05-07 20:01:011812 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:101813 UsePostRequest();
1814 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]dd54bd82012-07-19 23:44:571815 helper.RunToCompletion(&data);
[email protected]3caf5542010-07-16 15:19:471816 TransactionHelperResult out = helper.output();
robpercival214763f2016-07-01 23:27:011817 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:021818 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]aea80602009-09-18 00:55:081819 EXPECT_EQ("hello!", out.response_data);
1820}
1821
[email protected]69e6b4a2012-10-18 08:03:011822// Test that a POST with a file works.
bncd16676a2016-07-20 16:23:011823TEST_F(SpdyNetworkTransactionTest, FilePost) {
Ryan Hamilton0239aac2018-05-19 00:03:131824 spdy::SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
tombergan5d22c182017-01-11 02:05:351825 kDefaultUrl, 1, kUploadDataSize, LOWEST, nullptr, 0));
Ryan Hamilton0239aac2018-05-19 00:03:131826 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]69e6b4a2012-10-18 08:03:011827 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:411828 CreateMockWrite(req, 0), CreateMockWrite(body, 1), // POST upload frame
[email protected]69e6b4a2012-10-18 08:03:011829 };
1830
Ryan Hamilton0239aac2018-05-19 00:03:131831 spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
[email protected]69e6b4a2012-10-18 08:03:011832 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:411833 CreateMockRead(resp, 2), CreateMockRead(body, 3),
rch08e3aa3e2015-05-16 14:27:521834 MockRead(ASYNC, 0, 4) // EOF
[email protected]69e6b4a2012-10-18 08:03:011835 };
1836
Ryan Sleevib8d7ea02018-05-07 20:01:011837 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:101838 UseFilePostRequest();
1839 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]69e6b4a2012-10-18 08:03:011840 helper.RunToCompletion(&data);
1841 TransactionHelperResult out = helper.output();
robpercival214763f2016-07-01 23:27:011842 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:021843 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]69e6b4a2012-10-18 08:03:011844 EXPECT_EQ("hello!", out.response_data);
1845}
1846
[email protected]999dd8c2013-11-12 06:45:541847// Test that a POST with a unreadable file fails.
bncd16676a2016-07-20 16:23:011848TEST_F(SpdyNetworkTransactionTest, UnreadableFilePost) {
[email protected]999dd8c2013-11-12 06:45:541849 MockWrite writes[] = {
rch08e3aa3e2015-05-16 14:27:521850 MockWrite(ASYNC, 0, 0) // EOF
[email protected]999dd8c2013-11-12 06:45:541851 };
1852 MockRead reads[] = {
rch08e3aa3e2015-05-16 14:27:521853 MockRead(ASYNC, 0, 1) // EOF
[email protected]999dd8c2013-11-12 06:45:541854 };
1855
Ryan Sleevib8d7ea02018-05-07 20:01:011856 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:101857 UseUnreadableFilePostRequest();
1858 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]999dd8c2013-11-12 06:45:541859 helper.RunPreTestSetup();
1860 helper.AddData(&data);
1861 helper.RunDefaultTest();
1862
1863 base::RunLoop().RunUntilIdle();
1864 helper.VerifyDataNotConsumed();
robpercival214763f2016-07-01 23:27:011865 EXPECT_THAT(helper.output().rv, IsError(ERR_ACCESS_DENIED));
[email protected]999dd8c2013-11-12 06:45:541866}
1867
[email protected]69e6b4a2012-10-18 08:03:011868// Test that a complex POST works.
bncd16676a2016-07-20 16:23:011869TEST_F(SpdyNetworkTransactionTest, ComplexPost) {
Ryan Hamilton0239aac2018-05-19 00:03:131870 spdy::SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
tombergan5d22c182017-01-11 02:05:351871 kDefaultUrl, 1, kUploadDataSize, LOWEST, nullptr, 0));
Ryan Hamilton0239aac2018-05-19 00:03:131872 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]69e6b4a2012-10-18 08:03:011873 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:411874 CreateMockWrite(req, 0), CreateMockWrite(body, 1), // POST upload frame
[email protected]69e6b4a2012-10-18 08:03:011875 };
1876
Ryan Hamilton0239aac2018-05-19 00:03:131877 spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
[email protected]69e6b4a2012-10-18 08:03:011878 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:411879 CreateMockRead(resp, 2), CreateMockRead(body, 3),
rch08e3aa3e2015-05-16 14:27:521880 MockRead(ASYNC, 0, 4) // EOF
[email protected]69e6b4a2012-10-18 08:03:011881 };
1882
Ryan Sleevib8d7ea02018-05-07 20:01:011883 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:101884 UseComplexPostRequest();
1885 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]69e6b4a2012-10-18 08:03:011886 helper.RunToCompletion(&data);
1887 TransactionHelperResult out = helper.output();
robpercival214763f2016-07-01 23:27:011888 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:021889 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]69e6b4a2012-10-18 08:03:011890 EXPECT_EQ("hello!", out.response_data);
1891}
1892
[email protected]0c9bf872011-03-04 17:53:221893// Test that a chunked POST works.
bncd16676a2016-07-20 16:23:011894TEST_F(SpdyNetworkTransactionTest, ChunkedPost) {
Ryan Hamilton0239aac2018-05-19 00:03:131895 spdy::SpdySerializedFrame req(
1896 spdy_util_.ConstructChunkedSpdyPost(nullptr, 0));
1897 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]0c9bf872011-03-04 17:53:221898 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:411899 CreateMockWrite(req, 0), CreateMockWrite(body, 1),
[email protected]0c9bf872011-03-04 17:53:221900 };
1901
Ryan Hamilton0239aac2018-05-19 00:03:131902 spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
[email protected]0c9bf872011-03-04 17:53:221903 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:411904 CreateMockRead(resp, 2), CreateMockRead(body, 3),
rch08e3aa3e2015-05-16 14:27:521905 MockRead(ASYNC, 0, 4) // EOF
[email protected]0c9bf872011-03-04 17:53:221906 };
1907
Ryan Sleevib8d7ea02018-05-07 20:01:011908 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:101909 UseChunkedPostRequest();
1910 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]34b345f92013-02-22 03:27:261911
1912 // These chunks get merged into a single frame when being sent.
1913 const int kFirstChunkSize = kUploadDataSize/2;
mmenkecbc2b712014-10-09 20:29:071914 upload_chunked_data_stream()->AppendData(kUploadData, kFirstChunkSize, false);
1915 upload_chunked_data_stream()->AppendData(
[email protected]34b345f92013-02-22 03:27:261916 kUploadData + kFirstChunkSize, kUploadDataSize - kFirstChunkSize, true);
1917
[email protected]dd54bd82012-07-19 23:44:571918 helper.RunToCompletion(&data);
[email protected]0c9bf872011-03-04 17:53:221919 TransactionHelperResult out = helper.output();
robpercival214763f2016-07-01 23:27:011920 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:021921 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]34b345f92013-02-22 03:27:261922 EXPECT_EQ(kUploadData, out.response_data);
1923}
1924
1925// Test that a chunked POST works with chunks appended after transaction starts.
bncd16676a2016-07-20 16:23:011926TEST_F(SpdyNetworkTransactionTest, DelayedChunkedPost) {
Ryan Hamilton0239aac2018-05-19 00:03:131927 spdy::SpdySerializedFrame req(
1928 spdy_util_.ConstructChunkedSpdyPost(nullptr, 0));
1929 spdy::SpdySerializedFrame chunk1(spdy_util_.ConstructSpdyDataFrame(1, false));
1930 spdy::SpdySerializedFrame chunk2(spdy_util_.ConstructSpdyDataFrame(1, false));
1931 spdy::SpdySerializedFrame chunk3(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]34b345f92013-02-22 03:27:261932 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:411933 CreateMockWrite(req, 0), CreateMockWrite(chunk1, 1),
1934 CreateMockWrite(chunk2, 2), CreateMockWrite(chunk3, 3),
[email protected]34b345f92013-02-22 03:27:261935 };
1936
Ryan Hamilton0239aac2018-05-19 00:03:131937 spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
[email protected]34b345f92013-02-22 03:27:261938 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:411939 CreateMockRead(resp, 4), CreateMockRead(chunk1, 5),
1940 CreateMockRead(chunk2, 6), CreateMockRead(chunk3, 7),
rch08e3aa3e2015-05-16 14:27:521941 MockRead(ASYNC, 0, 8) // EOF
[email protected]34b345f92013-02-22 03:27:261942 };
1943
Ryan Sleevib8d7ea02018-05-07 20:01:011944 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:101945 UseChunkedPostRequest();
1946 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]34b345f92013-02-22 03:27:261947
mmenkecbc2b712014-10-09 20:29:071948 upload_chunked_data_stream()->AppendData(kUploadData, kUploadDataSize, false);
[email protected]34b345f92013-02-22 03:27:261949
1950 helper.RunPreTestSetup();
1951 helper.AddData(&data);
1952 ASSERT_TRUE(helper.StartDefaultTest());
1953
[email protected]fc9d88472013-08-14 02:31:171954 base::RunLoop().RunUntilIdle();
mmenkecbc2b712014-10-09 20:29:071955 upload_chunked_data_stream()->AppendData(kUploadData, kUploadDataSize, false);
[email protected]fc9d88472013-08-14 02:31:171956 base::RunLoop().RunUntilIdle();
mmenkecbc2b712014-10-09 20:29:071957 upload_chunked_data_stream()->AppendData(kUploadData, kUploadDataSize, true);
[email protected]34b345f92013-02-22 03:27:261958
1959 helper.FinishDefaultTest();
1960 helper.VerifyDataConsumed();
1961
Bence Béky4e83f492018-05-13 23:14:251962 std::string expected_response;
[email protected]34b345f92013-02-22 03:27:261963 expected_response += kUploadData;
1964 expected_response += kUploadData;
1965 expected_response += kUploadData;
1966
1967 TransactionHelperResult out = helper.output();
robpercival214763f2016-07-01 23:27:011968 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:021969 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]34b345f92013-02-22 03:27:261970 EXPECT_EQ(expected_response, out.response_data);
[email protected]0c9bf872011-03-04 17:53:221971}
1972
[email protected]a33cad2b62010-07-30 22:24:391973// Test that a POST without any post data works.
bncd16676a2016-07-20 16:23:011974TEST_F(SpdyNetworkTransactionTest, NullPost) {
Bence Békydb3cf652017-10-10 15:22:101975 // Setup the request.
1976 request_.method = "POST";
[email protected]a33cad2b62010-07-30 22:24:391977 // Create an empty UploadData.
Bence Békydb3cf652017-10-10 15:22:101978 request_.upload_data_stream = nullptr;
[email protected]a33cad2b62010-07-30 22:24:391979
[email protected]329b68b2012-11-14 17:54:271980 // When request.upload_data_stream is NULL for post, content-length is
[email protected]a33cad2b62010-07-30 22:24:391981 // expected to be 0.
Bence Béky4c325e52020-10-22 20:48:011982 spdy::Http2HeaderBlock req_block(
bncb26024382016-06-29 02:39:451983 spdy_util_.ConstructPostHeaderBlock(kDefaultUrl, 0));
Ryan Hamilton0239aac2018-05-19 00:03:131984 spdy::SpdySerializedFrame req(
bnc42331402016-07-25 13:36:151985 spdy_util_.ConstructSpdyHeaders(1, std::move(req_block), LOWEST, true));
[email protected]d2c1a97b2014-03-03 19:25:091986
[email protected]a33cad2b62010-07-30 22:24:391987 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:411988 CreateMockWrite(req, 0),
[email protected]a33cad2b62010-07-30 22:24:391989 };
1990
Ryan Hamilton0239aac2018-05-19 00:03:131991 spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
1992 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]a33cad2b62010-07-30 22:24:391993 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:411994 CreateMockRead(resp, 1), CreateMockRead(body, 2),
rch08e3aa3e2015-05-16 14:27:521995 MockRead(ASYNC, 0, 3) // EOF
[email protected]a33cad2b62010-07-30 22:24:391996 };
1997
Ryan Sleevib8d7ea02018-05-07 20:01:011998 SequencedSocketData data(reads, writes);
[email protected]a33cad2b62010-07-30 22:24:391999
Bence Békydb3cf652017-10-10 15:22:102000 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]dd54bd82012-07-19 23:44:572001 helper.RunToCompletion(&data);
[email protected]a33cad2b62010-07-30 22:24:392002 TransactionHelperResult out = helper.output();
robpercival214763f2016-07-01 23:27:012003 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:022004 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]a33cad2b62010-07-30 22:24:392005 EXPECT_EQ("hello!", out.response_data);
2006}
2007
[email protected]edd3b0a52009-11-24 18:56:362008// Test that a simple POST works.
bncd16676a2016-07-20 16:23:012009TEST_F(SpdyNetworkTransactionTest, EmptyPost) {
[email protected]329b68b2012-11-14 17:54:272010 // Create an empty UploadDataStream.
danakjaee3e1ec2016-04-16 00:23:182011 std::vector<std::unique_ptr<UploadElementReader>> element_readers;
olli.raula6df48b2a2015-11-26 07:40:222012 ElementsUploadDataStream stream(std::move(element_readers), 0);
[email protected]329b68b2012-11-14 17:54:272013
Bence Békydb3cf652017-10-10 15:22:102014 // Setup the request.
2015 request_.method = "POST";
2016 request_.upload_data_stream = &stream;
[email protected]edd3b0a52009-11-24 18:56:362017
Avi Drissman13fc8932015-12-20 04:40:462018 const uint64_t kContentLength = 0;
[email protected]d2c1a97b2014-03-03 19:25:092019
Bence Béky4c325e52020-10-22 20:48:012020 spdy::Http2HeaderBlock req_block(
bncb26024382016-06-29 02:39:452021 spdy_util_.ConstructPostHeaderBlock(kDefaultUrl, kContentLength));
Ryan Hamilton0239aac2018-05-19 00:03:132022 spdy::SpdySerializedFrame req(
bnc42331402016-07-25 13:36:152023 spdy_util_.ConstructSpdyHeaders(1, std::move(req_block), LOWEST, true));
[email protected]d2c1a97b2014-03-03 19:25:092024
[email protected]edd3b0a52009-11-24 18:56:362025 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:412026 CreateMockWrite(req, 0),
[email protected]edd3b0a52009-11-24 18:56:362027 };
2028
Ryan Hamilton0239aac2018-05-19 00:03:132029 spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
2030 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]edd3b0a52009-11-24 18:56:362031 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:412032 CreateMockRead(resp, 1), CreateMockRead(body, 2),
rch08e3aa3e2015-05-16 14:27:522033 MockRead(ASYNC, 0, 3) // EOF
[email protected]edd3b0a52009-11-24 18:56:362034 };
2035
Ryan Sleevib8d7ea02018-05-07 20:01:012036 SequencedSocketData data(reads, writes);
[email protected]bf2491a92009-11-29 16:39:482037
Bence Békydb3cf652017-10-10 15:22:102038 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]dd54bd82012-07-19 23:44:572039 helper.RunToCompletion(&data);
[email protected]3caf5542010-07-16 15:19:472040 TransactionHelperResult out = helper.output();
robpercival214763f2016-07-01 23:27:012041 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:022042 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]edd3b0a52009-11-24 18:56:362043 EXPECT_EQ("hello!", out.response_data);
2044}
2045
[email protected]35c3fc732014-02-15 00:16:072046// While we're doing a post, the server sends the reply before upload completes.
bncd16676a2016-07-20 16:23:012047TEST_F(SpdyNetworkTransactionTest, ResponseBeforePostCompletes) {
Ryan Hamilton0239aac2018-05-19 00:03:132048 spdy::SpdySerializedFrame req(
2049 spdy_util_.ConstructChunkedSpdyPost(nullptr, 0));
2050 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]35c3fc732014-02-15 00:16:072051 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:412052 CreateMockWrite(req, 0), CreateMockWrite(body, 3),
[email protected]35c3fc732014-02-15 00:16:072053 };
Ryan Hamilton0239aac2018-05-19 00:03:132054 spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
[email protected]a5566f9702010-05-05 22:25:432055 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:412056 CreateMockRead(resp, 1), CreateMockRead(body, 2),
2057 MockRead(ASYNC, 0, 4) // EOF
[email protected]a5566f9702010-05-05 22:25:432058 };
2059
[email protected]35c3fc732014-02-15 00:16:072060 // Write the request headers, and read the complete response
2061 // while still waiting for chunked request data.
Ryan Sleevib8d7ea02018-05-07 20:01:012062 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:102063 UseChunkedPostRequest();
2064 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]c92f4b4542012-07-26 23:53:212065 helper.RunPreTestSetup();
mmenke666a6fea2015-12-19 04:16:332066 helper.AddData(&data);
[email protected]c92f4b4542012-07-26 23:53:212067
[email protected]35c3fc732014-02-15 00:16:072068 ASSERT_TRUE(helper.StartDefaultTest());
[email protected]c92f4b4542012-07-26 23:53:212069
maksim.sisov8d2df66d2016-06-20 07:07:112070 base::RunLoop().RunUntilIdle();
mmenke666a6fea2015-12-19 04:16:332071
bnc42331402016-07-25 13:36:152072 // Process the request headers, response headers, and response body.
[email protected]35c3fc732014-02-15 00:16:072073 // The request body is still in flight.
[email protected]35c3fc732014-02-15 00:16:072074 const HttpResponseInfo* response = helper.trans()->GetResponseInfo();
bnc84e7fb52015-12-02 11:50:022075 EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
[email protected]35c3fc732014-02-15 00:16:072076
2077 // Finish sending the request body.
mmenkecbc2b712014-10-09 20:29:072078 upload_chunked_data_stream()->AppendData(kUploadData, kUploadDataSize, true);
maksim.sisov8d2df66d2016-06-20 07:07:112079 helper.WaitForCallbackToComplete();
robpercival214763f2016-07-01 23:27:012080 EXPECT_THAT(helper.output().rv, IsOk());
[email protected]35c3fc732014-02-15 00:16:072081
Bence Béky4e83f492018-05-13 23:14:252082 std::string response_body;
robpercival214763f2016-07-01 23:27:012083 EXPECT_THAT(ReadTransaction(helper.trans(), &response_body), IsOk());
[email protected]35c3fc732014-02-15 00:16:072084 EXPECT_EQ(kUploadData, response_body);
bnceb9aa7112017-01-05 01:03:462085
2086 // Finish async network reads/writes.
2087 base::RunLoop().RunUntilIdle();
[email protected]35c3fc732014-02-15 00:16:072088 helper.VerifyDataConsumed();
[email protected]a5566f9702010-05-05 22:25:432089}
2090
[email protected]f9a26d72010-08-03 18:07:132091// The client upon cancellation tries to send a RST_STREAM frame. The mock
2092// socket causes the TCP write to return zero. This test checks that the client
2093// tries to queue up the RST_STREAM frame again.
bncd16676a2016-07-20 16:23:012094TEST_F(SpdyNetworkTransactionTest, SocketWriteReturnsZero) {
Ryan Hamilton0239aac2018-05-19 00:03:132095 spdy::SpdySerializedFrame req(
2096 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
2097 spdy::SpdySerializedFrame rst(
2098 spdy_util_.ConstructSpdyRstStream(1, spdy::ERROR_CODE_CANCEL));
[email protected]f9a26d72010-08-03 18:07:132099 MockWrite writes[] = {
Raul Tambre94493c652019-03-11 17:18:352100 CreateMockWrite(req, 0, SYNCHRONOUS),
2101 MockWrite(SYNCHRONOUS, nullptr, 0, 2),
bncdf80d44fd2016-07-15 20:27:412102 CreateMockWrite(rst, 3, SYNCHRONOUS),
[email protected]f9a26d72010-08-03 18:07:132103 };
2104
Ryan Hamilton0239aac2018-05-19 00:03:132105 spdy::SpdySerializedFrame resp(
2106 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
[email protected]f9a26d72010-08-03 18:07:132107 MockRead reads[] = {
Raul Tambre94493c652019-03-11 17:18:352108 CreateMockRead(resp, 1, ASYNC), MockRead(ASYNC, nullptr, 0, 4) // EOF
[email protected]f9a26d72010-08-03 18:07:132109 };
2110
Ryan Sleevib8d7ea02018-05-07 20:01:012111 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:102112 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]f9a26d72010-08-03 18:07:132113 helper.RunPreTestSetup();
mmenke666a6fea2015-12-19 04:16:332114 helper.AddData(&data);
bnc4d782f492016-08-18 13:50:002115 helper.StartDefaultTest();
2116 EXPECT_THAT(helper.output().rv, IsError(ERR_IO_PENDING));
[email protected]f9a26d72010-08-03 18:07:132117
bnc4d782f492016-08-18 13:50:002118 helper.WaitForCallbackToComplete();
2119 EXPECT_THAT(helper.output().rv, IsOk());
[email protected]3b7828432010-08-18 18:33:272120
[email protected]f9a26d72010-08-03 18:07:132121 helper.ResetTrans();
mmenke666a6fea2015-12-19 04:16:332122 base::RunLoop().RunUntilIdle();
[email protected]3b7828432010-08-18 18:33:272123
[email protected]f9a26d72010-08-03 18:07:132124 helper.VerifyDataConsumed();
2125}
2126
[email protected]93300672009-10-24 13:22:512127// Test that the transaction doesn't crash when we don't have a reply.
bnc42331402016-07-25 13:36:152128TEST_F(SpdyNetworkTransactionTest, ResponseWithoutHeaders) {
Ryan Hamilton0239aac2018-05-19 00:03:132129 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]ff57bb82009-11-12 06:52:142130 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:412131 CreateMockRead(body, 1), MockRead(ASYNC, 0, 3) // EOF
[email protected]93300672009-10-24 13:22:512132 };
2133
Ryan Hamilton0239aac2018-05-19 00:03:132134 spdy::SpdySerializedFrame req(
2135 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
2136 spdy::SpdySerializedFrame rst(
2137 spdy_util_.ConstructSpdyRstStream(1, spdy::ERROR_CODE_PROTOCOL_ERROR));
rch08e3aa3e2015-05-16 14:27:522138 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:412139 CreateMockWrite(req, 0), CreateMockWrite(rst, 2),
rch08e3aa3e2015-05-16 14:27:522140 };
Ryan Sleevib8d7ea02018-05-07 20:01:012141 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:102142 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]dd54bd82012-07-19 23:44:572143 helper.RunToCompletion(&data);
[email protected]3caf5542010-07-16 15:19:472144 TransactionHelperResult out = helper.output();
Bence Békyd0d69502019-06-25 19:47:182145 EXPECT_THAT(out.rv, IsError(ERR_HTTP2_PROTOCOL_ERROR));
[email protected]93300672009-10-24 13:22:512146}
2147
[email protected]d30022352010-06-24 19:17:582148// Test that the transaction doesn't crash when we get two replies on the same
2149// stream ID. See http://crbug.com/45639.
bncd16676a2016-07-20 16:23:012150TEST_F(SpdyNetworkTransactionTest, ResponseWithTwoSynReplies) {
Ryan Hamilton0239aac2018-05-19 00:03:132151 spdy::SpdySerializedFrame req(
2152 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
2153 spdy::SpdySerializedFrame rst(
2154 spdy_util_.ConstructSpdyRstStream(1, spdy::ERROR_CODE_PROTOCOL_ERROR));
[email protected]2aeef782013-06-21 18:30:562155 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:412156 CreateMockWrite(req, 0), CreateMockWrite(rst, 4),
[email protected]2aeef782013-06-21 18:30:562157 };
[email protected]d30022352010-06-24 19:17:582158
Ryan Hamilton0239aac2018-05-19 00:03:132159 spdy::SpdySerializedFrame resp0(
2160 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
2161 spdy::SpdySerializedFrame resp1(
2162 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
2163 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]d30022352010-06-24 19:17:582164 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:412165 CreateMockRead(resp0, 1), CreateMockRead(resp1, 2),
2166 CreateMockRead(body, 3), MockRead(ASYNC, 0, 5) // EOF
[email protected]d30022352010-06-24 19:17:582167 };
2168
Ryan Sleevib8d7ea02018-05-07 20:01:012169 SequencedSocketData data(reads, writes);
[email protected]d30022352010-06-24 19:17:582170
Bence Békydb3cf652017-10-10 15:22:102171 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]3caf5542010-07-16 15:19:472172 helper.RunPreTestSetup();
[email protected]dd54bd82012-07-19 23:44:572173 helper.AddData(&data);
[email protected]3caf5542010-07-16 15:19:472174
2175 HttpNetworkTransaction* trans = helper.trans();
[email protected]d30022352010-06-24 19:17:582176
[email protected]49639fa2011-12-20 23:22:412177 TestCompletionCallback callback;
Bence Békydb3cf652017-10-10 15:22:102178 int rv = trans->Start(&request_, callback.callback(), log_);
robpercival214763f2016-07-01 23:27:012179 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]d30022352010-06-24 19:17:582180 rv = callback.WaitForResult();
robpercival214763f2016-07-01 23:27:012181 EXPECT_THAT(rv, IsOk());
[email protected]d30022352010-06-24 19:17:582182
2183 const HttpResponseInfo* response = trans->GetResponseInfo();
wezca1070932016-05-26 20:30:522184 ASSERT_TRUE(response);
2185 EXPECT_TRUE(response->headers);
[email protected]d30022352010-06-24 19:17:582186 EXPECT_TRUE(response->was_fetched_via_spdy);
Bence Béky4e83f492018-05-13 23:14:252187 std::string response_data;
[email protected]3caf5542010-07-16 15:19:472188 rv = ReadTransaction(trans, &response_data);
Bence Békyd0d69502019-06-25 19:47:182189 EXPECT_THAT(rv, IsError(ERR_HTTP2_PROTOCOL_ERROR));
[email protected]3caf5542010-07-16 15:19:472190
2191 helper.VerifyDataConsumed();
[email protected]d30022352010-06-24 19:17:582192}
2193
bncd16676a2016-07-20 16:23:012194TEST_F(SpdyNetworkTransactionTest, ResetReplyWithTransferEncoding) {
[email protected]b3503002012-03-27 04:57:252195 // Construct the request.
Ryan Hamilton0239aac2018-05-19 00:03:132196 spdy::SpdySerializedFrame req(
2197 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
2198 spdy::SpdySerializedFrame rst(
2199 spdy_util_.ConstructSpdyRstStream(1, spdy::ERROR_CODE_PROTOCOL_ERROR));
[email protected]b3503002012-03-27 04:57:252200 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:412201 CreateMockWrite(req, 0), CreateMockWrite(rst, 2),
[email protected]b3503002012-03-27 04:57:252202 };
2203
2204 const char* const headers[] = {
[email protected]513963e2013-06-15 01:53:042205 "transfer-encoding", "chunked"
[email protected]b3503002012-03-27 04:57:252206 };
Ryan Hamilton0239aac2018-05-19 00:03:132207 spdy::SpdySerializedFrame resp(
2208 spdy_util_.ConstructSpdyGetReply(headers, 1, 1));
2209 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]b3503002012-03-27 04:57:252210 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:412211 CreateMockRead(resp, 1), CreateMockRead(body, 3),
rch08e3aa3e2015-05-16 14:27:522212 MockRead(ASYNC, 0, 4) // EOF
[email protected]b3503002012-03-27 04:57:252213 };
2214
Ryan Sleevib8d7ea02018-05-07 20:01:012215 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:102216 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]dd54bd82012-07-19 23:44:572217 helper.RunToCompletion(&data);
[email protected]b3503002012-03-27 04:57:252218 TransactionHelperResult out = helper.output();
Bence Békyd0d69502019-06-25 19:47:182219 EXPECT_THAT(out.rv, IsError(ERR_HTTP2_PROTOCOL_ERROR));
[email protected]b3503002012-03-27 04:57:252220
2221 helper.session()->spdy_session_pool()->CloseAllSessions();
2222 helper.VerifyDataConsumed();
2223}
2224
bncd16676a2016-07-20 16:23:012225TEST_F(SpdyNetworkTransactionTest, ResetPushWithTransferEncoding) {
[email protected]b3503002012-03-27 04:57:252226 // Construct the request.
Ryan Hamilton0239aac2018-05-19 00:03:132227 spdy::SpdySerializedFrame req(
2228 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
2229 spdy::SpdySerializedFrame priority(
tombergan5d22c182017-01-11 02:05:352230 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true));
Ryan Hamilton0239aac2018-05-19 00:03:132231 spdy::SpdySerializedFrame rst(
2232 spdy_util_.ConstructSpdyRstStream(2, spdy::ERROR_CODE_PROTOCOL_ERROR));
[email protected]b3503002012-03-27 04:57:252233 MockWrite writes[] = {
tombergan5d22c182017-01-11 02:05:352234 CreateMockWrite(req, 0), CreateMockWrite(priority, 3),
2235 CreateMockWrite(rst, 5),
[email protected]b3503002012-03-27 04:57:252236 };
2237
Ryan Hamilton0239aac2018-05-19 00:03:132238 spdy::SpdySerializedFrame resp(
2239 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
[email protected]513963e2013-06-15 01:53:042240 const char* const headers[] = {
2241 "transfer-encoding", "chunked"
2242 };
Ryan Hamilton0239aac2018-05-19 00:03:132243 spdy::SpdySerializedFrame push(spdy_util_.ConstructSpdyPush(
Avi Drissman4365a4782018-12-28 19:26:242244 headers, base::size(headers) / 2, 2, 1, "https://www.example.org/1"));
Ryan Hamilton0239aac2018-05-19 00:03:132245 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]b3503002012-03-27 04:57:252246 MockRead reads[] = {
tombergan5d22c182017-01-11 02:05:352247 CreateMockRead(resp, 1), CreateMockRead(push, 2), CreateMockRead(body, 4),
2248 MockRead(ASYNC, 0, 6) // EOF
[email protected]b3503002012-03-27 04:57:252249 };
2250
Ryan Sleevib8d7ea02018-05-07 20:01:012251 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:102252 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]dd54bd82012-07-19 23:44:572253 helper.RunToCompletion(&data);
[email protected]b3503002012-03-27 04:57:252254 TransactionHelperResult out = helper.output();
robpercival214763f2016-07-01 23:27:012255 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:022256 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]b3503002012-03-27 04:57:252257 EXPECT_EQ("hello!", out.response_data);
2258
2259 helper.session()->spdy_session_pool()->CloseAllSessions();
2260 helper.VerifyDataConsumed();
2261}
2262
bncd16676a2016-07-20 16:23:012263TEST_F(SpdyNetworkTransactionTest, CancelledTransaction) {
[email protected]75f30cc22010-06-28 21:41:382264 // Construct the request.
Ryan Hamilton0239aac2018-05-19 00:03:132265 spdy::SpdySerializedFrame req(
2266 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
[email protected]34437af82009-11-06 02:28:492267 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:412268 CreateMockWrite(req),
[email protected]34437af82009-11-06 02:28:492269 };
2270
Ryan Hamilton0239aac2018-05-19 00:03:132271 spdy::SpdySerializedFrame resp(
2272 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
[email protected]34437af82009-11-06 02:28:492273 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:412274 CreateMockRead(resp),
2275 // This following read isn't used by the test, except during the
2276 // RunUntilIdle() call at the end since the SpdySession survives the
2277 // HttpNetworkTransaction and still tries to continue Read()'ing. Any
2278 // MockRead will do here.
2279 MockRead(ASYNC, 0, 0) // EOF
[email protected]34437af82009-11-06 02:28:492280 };
2281
Ryan Sleevib8d7ea02018-05-07 20:01:012282 StaticSocketDataProvider data(reads, writes);
[email protected]3caf5542010-07-16 15:19:472283
Bence Békydb3cf652017-10-10 15:22:102284 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]3caf5542010-07-16 15:19:472285 helper.RunPreTestSetup();
[email protected]e3ebba0f2010-08-05 17:59:582286 helper.AddData(&data);
[email protected]3caf5542010-07-16 15:19:472287 HttpNetworkTransaction* trans = helper.trans();
[email protected]34437af82009-11-06 02:28:492288
[email protected]49639fa2011-12-20 23:22:412289 TestCompletionCallback callback;
Bence Békydb3cf652017-10-10 15:22:102290 int rv = trans->Start(&request_, callback.callback(), log_);
robpercival214763f2016-07-01 23:27:012291 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]3caf5542010-07-16 15:19:472292 helper.ResetTrans(); // Cancel the transaction.
[email protected]34437af82009-11-06 02:28:492293
[email protected]30c942b2010-07-21 16:59:592294 // Flush the MessageLoop while the SpdySessionDependencies (in particular, the
[email protected]34437af82009-11-06 02:28:492295 // MockClientSocketFactory) are still alive.
[email protected]fc9d88472013-08-14 02:31:172296 base::RunLoop().RunUntilIdle();
[email protected]3caf5542010-07-16 15:19:472297 helper.VerifyDataNotConsumed();
[email protected]34437af82009-11-06 02:28:492298}
[email protected]72552f02009-10-28 15:25:012299
[email protected]6c6ea172010-07-27 20:04:032300// Verify that the client sends a Rst Frame upon cancelling the stream.
bncd16676a2016-07-20 16:23:012301TEST_F(SpdyNetworkTransactionTest, CancelledTransactionSendRst) {
Ryan Hamilton0239aac2018-05-19 00:03:132302 spdy::SpdySerializedFrame req(
2303 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
2304 spdy::SpdySerializedFrame rst(
2305 spdy_util_.ConstructSpdyRstStream(1, spdy::ERROR_CODE_CANCEL));
[email protected]6c6ea172010-07-27 20:04:032306 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:412307 CreateMockWrite(req, 0, SYNCHRONOUS),
2308 CreateMockWrite(rst, 2, SYNCHRONOUS),
[email protected]6c6ea172010-07-27 20:04:032309 };
2310
Ryan Hamilton0239aac2018-05-19 00:03:132311 spdy::SpdySerializedFrame resp(
2312 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
[email protected]6c6ea172010-07-27 20:04:032313 MockRead reads[] = {
Raul Tambre94493c652019-03-11 17:18:352314 CreateMockRead(resp, 1, ASYNC), MockRead(ASYNC, nullptr, 0, 3) // EOF
[email protected]6c6ea172010-07-27 20:04:032315 };
2316
Ryan Sleevib8d7ea02018-05-07 20:01:012317 SequencedSocketData data(reads, writes);
[email protected]6c6ea172010-07-27 20:04:032318
Bence Békydb3cf652017-10-10 15:22:102319 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]6c6ea172010-07-27 20:04:032320 helper.RunPreTestSetup();
mmenke666a6fea2015-12-19 04:16:332321 helper.AddData(&data);
[email protected]6c6ea172010-07-27 20:04:032322 HttpNetworkTransaction* trans = helper.trans();
2323
[email protected]49639fa2011-12-20 23:22:412324 TestCompletionCallback callback;
[email protected]6c6ea172010-07-27 20:04:032325
Bence Békydb3cf652017-10-10 15:22:102326 int rv = trans->Start(&request_, callback.callback(), log_);
robpercival214763f2016-07-01 23:27:012327 EXPECT_THAT(callback.GetResult(rv), IsOk());
[email protected]6c6ea172010-07-27 20:04:032328
[email protected]3b7828432010-08-18 18:33:272329 helper.ResetTrans();
mmenke666a6fea2015-12-19 04:16:332330 base::RunLoop().RunUntilIdle();
[email protected]3b7828432010-08-18 18:33:272331
[email protected]6c6ea172010-07-27 20:04:032332 helper.VerifyDataConsumed();
2333}
2334
[email protected]b278eb72010-07-09 20:17:002335// Verify that the client can correctly deal with the user callback attempting
2336// to start another transaction on a session that is closing down. See
2337// http://crbug.com/47455
bncd16676a2016-07-20 16:23:012338TEST_F(SpdyNetworkTransactionTest, StartTransactionOnReadCallback) {
Ryan Hamilton0239aac2018-05-19 00:03:132339 spdy::SpdySerializedFrame req(
2340 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
bncdf80d44fd2016-07-15 20:27:412341 MockWrite writes[] = {CreateMockWrite(req)};
bnceb9aa7112017-01-05 01:03:462342 MockWrite writes2[] = {CreateMockWrite(req, 0),
2343 MockWrite(SYNCHRONOUS, ERR_IO_PENDING, 3)};
[email protected]b278eb72010-07-09 20:17:002344
[email protected]cbdd73162013-03-18 23:27:332345 // The indicated length of this frame is longer than its actual length. When
2346 // the session receives an empty frame after this one, it shuts down the
[email protected]b278eb72010-07-09 20:17:002347 // session, and calls the read callback with the incomplete data.
Avi Drissman13fc8932015-12-20 04:40:462348 const uint8_t kGetBodyFrame2[] = {
2349 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00,
2350 0x07, 'h', 'e', 'l', 'l', 'o', '!',
[email protected]b278eb72010-07-09 20:17:002351 };
2352
Ryan Hamilton0239aac2018-05-19 00:03:132353 spdy::SpdySerializedFrame resp(
2354 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
[email protected]b278eb72010-07-09 20:17:002355 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:412356 CreateMockRead(resp, 1),
rch32320842015-05-16 15:57:092357 MockRead(ASYNC, ERR_IO_PENDING, 2), // Force a pause
2358 MockRead(ASYNC, reinterpret_cast<const char*>(kGetBodyFrame2),
Avi Drissman4365a4782018-12-28 19:26:242359 base::size(kGetBodyFrame2), 3),
rch32320842015-05-16 15:57:092360 MockRead(ASYNC, ERR_IO_PENDING, 4), // Force a pause
Raul Tambre94493c652019-03-11 17:18:352361 MockRead(ASYNC, nullptr, 0, 5), // EOF
[email protected]b278eb72010-07-09 20:17:002362 };
2363 MockRead reads2[] = {
Raul Tambre94493c652019-03-11 17:18:352364 CreateMockRead(resp, 1), MockRead(ASYNC, nullptr, 0, 2), // EOF
[email protected]b278eb72010-07-09 20:17:002365 };
2366
Ryan Sleevib8d7ea02018-05-07 20:01:012367 SequencedSocketData data(reads, writes);
2368 SequencedSocketData data2(reads2, writes2);
[email protected]3caf5542010-07-16 15:19:472369
Bence Békydb3cf652017-10-10 15:22:102370 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]e3ebba0f2010-08-05 17:59:582371 helper.RunPreTestSetup();
[email protected]dd54bd82012-07-19 23:44:572372 helper.AddData(&data);
2373 helper.AddData(&data2);
[email protected]3caf5542010-07-16 15:19:472374 HttpNetworkTransaction* trans = helper.trans();
[email protected]b278eb72010-07-09 20:17:002375
2376 // Start the transaction with basic parameters.
[email protected]49639fa2011-12-20 23:22:412377 TestCompletionCallback callback;
Bence Békydb3cf652017-10-10 15:22:102378 int rv = trans->Start(&request_, callback.callback(), log_);
robpercival214763f2016-07-01 23:27:012379 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]b278eb72010-07-09 20:17:002380 rv = callback.WaitForResult();
2381
[email protected]b278eb72010-07-09 20:17:002382 const int kSize = 3000;
Victor Costan9c7302b2018-08-27 16:39:442383 scoped_refptr<IOBuffer> buf = base::MakeRefCounted<IOBuffer>(kSize);
[email protected]49639fa2011-12-20 23:22:412384 rv = trans->Read(
rchebf12982015-04-10 01:15:002385 buf.get(), kSize,
Yannic Bonenberger00e09842019-08-31 20:46:192386 base::BindOnce(&SpdyNetworkTransactionTest::StartTransactionCallback,
2387 helper.session(), default_url_, log_));
robpercival214763f2016-07-01 23:27:012388 ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]3caf5542010-07-16 15:19:472389 // This forces an err_IO_pending, which sets the callback.
mmenkee24011922015-12-17 22:12:592390 data.Resume();
2391 data.RunUntilPaused();
2392
[email protected]3caf5542010-07-16 15:19:472393 // This finishes the read.
mmenkee24011922015-12-17 22:12:592394 data.Resume();
2395 base::RunLoop().RunUntilIdle();
[email protected]3caf5542010-07-16 15:19:472396 helper.VerifyDataConsumed();
[email protected]b278eb72010-07-09 20:17:002397}
2398
Mostyn Bramley-Moore699c5312018-05-01 10:48:092399// Verify that the client can correctly deal with the user callback deleting
2400// the transaction. Failures will usually be flagged by thread and/or memory
2401// checking tools. See http://crbug.com/46925
bncd16676a2016-07-20 16:23:012402TEST_F(SpdyNetworkTransactionTest, DeleteSessionOnReadCallback) {
Ryan Hamilton0239aac2018-05-19 00:03:132403 spdy::SpdySerializedFrame req(
2404 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
bncdf80d44fd2016-07-15 20:27:412405 MockWrite writes[] = {CreateMockWrite(req, 0)};
[email protected]9be804c82010-06-24 17:59:462406
Ryan Hamilton0239aac2018-05-19 00:03:132407 spdy::SpdySerializedFrame resp(
2408 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
2409 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]9be804c82010-06-24 17:59:462410 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:412411 CreateMockRead(resp, 1),
Raul Tambre94493c652019-03-11 17:18:352412 MockRead(ASYNC, ERR_IO_PENDING, 2), // Force a pause
2413 CreateMockRead(body, 3), MockRead(ASYNC, nullptr, 0, 4), // EOF
[email protected]9be804c82010-06-24 17:59:462414 };
2415
Ryan Sleevib8d7ea02018-05-07 20:01:012416 SequencedSocketData data(reads, writes);
[email protected]3caf5542010-07-16 15:19:472417
Bence Békydb3cf652017-10-10 15:22:102418 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]3caf5542010-07-16 15:19:472419 helper.RunPreTestSetup();
[email protected]dd54bd82012-07-19 23:44:572420 helper.AddData(&data);
[email protected]3caf5542010-07-16 15:19:472421 HttpNetworkTransaction* trans = helper.trans();
[email protected]9be804c82010-06-24 17:59:462422
2423 // Start the transaction with basic parameters.
[email protected]49639fa2011-12-20 23:22:412424 TestCompletionCallback callback;
Bence Békydb3cf652017-10-10 15:22:102425 int rv = trans->Start(&request_, callback.callback(), log_);
robpercival214763f2016-07-01 23:27:012426 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]9be804c82010-06-24 17:59:462427 rv = callback.WaitForResult();
2428
2429 // Setup a user callback which will delete the session, and clear out the
2430 // memory holding the stream object. Note that the callback deletes trans.
[email protected]9be804c82010-06-24 17:59:462431 const int kSize = 3000;
Victor Costan9c7302b2018-08-27 16:39:442432 scoped_refptr<IOBuffer> buf = base::MakeRefCounted<IOBuffer>(kSize);
[email protected]49639fa2011-12-20 23:22:412433 rv = trans->Read(
Yannic Bonenberger00e09842019-08-31 20:46:192434 buf.get(), kSize,
2435 base::BindOnce(&SpdyNetworkTransactionTest::DeleteSessionCallback,
2436 base::Unretained(&helper)));
robpercival214763f2016-07-01 23:27:012437 ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
mmenkee24011922015-12-17 22:12:592438 data.Resume();
[email protected]9be804c82010-06-24 17:59:462439
2440 // Finish running rest of tasks.
[email protected]fc9d88472013-08-14 02:31:172441 base::RunLoop().RunUntilIdle();
[email protected]3caf5542010-07-16 15:19:472442 helper.VerifyDataConsumed();
[email protected]9be804c82010-06-24 17:59:462443}
2444
bncf2ba58832017-06-07 00:22:282445TEST_F(SpdyNetworkTransactionTest, RedirectGetRequest) {
2446 SpdyURLRequestContext spdy_url_request_context;
Matt Menke5062be22019-05-01 17:50:242447 // Use a different port to avoid trying to reuse the initial H2 session.
2448 const char kRedirectUrl[] = "https://www.foo.com:8080/index.php";
[email protected]e3ebba0f2010-08-05 17:59:582449
bncf2ba58832017-06-07 00:22:282450 SSLSocketDataProvider ssl_provider0(ASYNC, OK);
2451 ssl_provider0.next_proto = kProtoHTTP2;
2452 spdy_url_request_context.socket_factory().AddSSLSocketDataProvider(
2453 &ssl_provider0);
[email protected]e3ebba0f2010-08-05 17:59:582454
Bence Béky4c325e52020-10-22 20:48:012455 spdy::Http2HeaderBlock headers0(
Ryan Hamilton0239aac2018-05-19 00:03:132456 spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
bncf2ba58832017-06-07 00:22:282457 headers0["user-agent"] = "";
2458 headers0["accept-encoding"] = "gzip, deflate";
bnc086b39e12016-06-24 13:05:262459
Ryan Hamilton0239aac2018-05-19 00:03:132460 spdy::SpdySerializedFrame req0(
bncf2ba58832017-06-07 00:22:282461 spdy_util_.ConstructSpdyHeaders(1, std::move(headers0), LOWEST, true));
Ryan Hamilton0239aac2018-05-19 00:03:132462 spdy::SpdySerializedFrame rst(
2463 spdy_util_.ConstructSpdyRstStream(1, spdy::ERROR_CODE_CANCEL));
Shivani Sharmac18f9762017-10-23 16:43:232464 MockWrite writes0[] = {CreateMockWrite(req0, 0), CreateMockWrite(rst, 2)};
bnc086b39e12016-06-24 13:05:262465
Matt Menke5062be22019-05-01 17:50:242466 const char* const kExtraHeaders[] = {"location", kRedirectUrl};
Ryan Hamilton0239aac2018-05-19 00:03:132467 spdy::SpdySerializedFrame resp0(spdy_util_.ConstructSpdyReplyError(
Avi Drissman4365a4782018-12-28 19:26:242468 "301", kExtraHeaders, base::size(kExtraHeaders) / 2, 1));
Shivani Sharmac18f9762017-10-23 16:43:232469 MockRead reads0[] = {CreateMockRead(resp0, 1), MockRead(ASYNC, 0, 3)};
[email protected]e3ebba0f2010-08-05 17:59:582470
Ryan Sleevib8d7ea02018-05-07 20:01:012471 SequencedSocketData data0(reads0, writes0);
bncf2ba58832017-06-07 00:22:282472 spdy_url_request_context.socket_factory().AddSocketDataProvider(&data0);
[email protected]e3ebba0f2010-08-05 17:59:582473
bncf2ba58832017-06-07 00:22:282474 SSLSocketDataProvider ssl_provider1(ASYNC, OK);
2475 ssl_provider1.next_proto = kProtoHTTP2;
2476 spdy_url_request_context.socket_factory().AddSSLSocketDataProvider(
2477 &ssl_provider1);
[email protected]513963e2013-06-15 01:53:042478
bncf2ba58832017-06-07 00:22:282479 SpdyTestUtil spdy_util1;
Bence Béky4c325e52020-10-22 20:48:012480 spdy::Http2HeaderBlock headers1(
Matt Menke5062be22019-05-01 17:50:242481 spdy_util1.ConstructGetHeaderBlock(kRedirectUrl));
bncf2ba58832017-06-07 00:22:282482 headers1["user-agent"] = "";
2483 headers1["accept-encoding"] = "gzip, deflate";
Ryan Hamilton0239aac2018-05-19 00:03:132484 spdy::SpdySerializedFrame req1(
bncf2ba58832017-06-07 00:22:282485 spdy_util1.ConstructSpdyHeaders(1, std::move(headers1), LOWEST, true));
2486 MockWrite writes1[] = {CreateMockWrite(req1, 0)};
[email protected]e3ebba0f2010-08-05 17:59:582487
Ryan Hamilton0239aac2018-05-19 00:03:132488 spdy::SpdySerializedFrame resp1(
2489 spdy_util1.ConstructSpdyGetReply(nullptr, 0, 1));
2490 spdy::SpdySerializedFrame body1(spdy_util1.ConstructSpdyDataFrame(1, true));
bncf2ba58832017-06-07 00:22:282491 MockRead reads1[] = {CreateMockRead(resp1, 1), CreateMockRead(body1, 2),
2492 MockRead(ASYNC, 0, 3)};
2493
Ryan Sleevib8d7ea02018-05-07 20:01:012494 SequencedSocketData data1(reads1, writes1);
bncf2ba58832017-06-07 00:22:282495 spdy_url_request_context.socket_factory().AddSocketDataProvider(&data1);
2496
2497 TestDelegate delegate;
bncf2ba58832017-06-07 00:22:282498
2499 std::unique_ptr<URLRequest> request = spdy_url_request_context.CreateRequest(
2500 default_url_, DEFAULT_PRIORITY, &delegate, TRAFFIC_ANNOTATION_FOR_TESTS);
2501 request->Start();
Wez0e717112018-06-18 23:09:222502 delegate.RunUntilRedirect();
bncf2ba58832017-06-07 00:22:282503
2504 EXPECT_EQ(1, delegate.received_redirect_count());
2505
Anton Bikineev068d2912021-05-15 20:43:522506 request->FollowDeferredRedirect(absl::nullopt /* removed_headers */,
2507 absl::nullopt /* modified_headers */);
Wez0e717112018-06-18 23:09:222508 delegate.RunUntilComplete();
bncf2ba58832017-06-07 00:22:282509
2510 EXPECT_EQ(1, delegate.response_started_count());
2511 EXPECT_FALSE(delegate.received_data_before_response());
2512 EXPECT_THAT(delegate.request_status(), IsOk());
2513 EXPECT_EQ("hello!", delegate.data_received());
2514
Wez0e717112018-06-18 23:09:222515 // Pump the message loop to allow read data to be consumed.
2516 base::RunLoop().RunUntilIdle();
2517
bncf2ba58832017-06-07 00:22:282518 EXPECT_TRUE(data0.AllReadDataConsumed());
2519 EXPECT_TRUE(data0.AllWriteDataConsumed());
2520 EXPECT_TRUE(data1.AllReadDataConsumed());
2521 EXPECT_TRUE(data1.AllWriteDataConsumed());
[email protected]e3ebba0f2010-08-05 17:59:582522}
2523
bncf2ba58832017-06-07 00:22:282524TEST_F(SpdyNetworkTransactionTest, RedirectServerPush) {
bncf2ba58832017-06-07 00:22:282525 const char redirected_url[] = "https://www.foo.com/index.php";
2526 SpdyURLRequestContext spdy_url_request_context;
[email protected]3a8d6852011-03-11 23:43:442527
bncf2ba58832017-06-07 00:22:282528 SSLSocketDataProvider ssl_provider0(ASYNC, OK);
2529 ssl_provider0.next_proto = kProtoHTTP2;
Ryan Sleevi4f832092017-11-21 23:25:492530 ssl_provider0.ssl_info.cert =
bncf2ba58832017-06-07 00:22:282531 ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem");
Ryan Sleevi4f832092017-11-21 23:25:492532 ASSERT_TRUE(ssl_provider0.ssl_info.cert);
bncf2ba58832017-06-07 00:22:282533 spdy_url_request_context.socket_factory().AddSSLSocketDataProvider(
2534 &ssl_provider0);
2535
Bence Béky4c325e52020-10-22 20:48:012536 spdy::Http2HeaderBlock headers0(
Ryan Hamilton0239aac2018-05-19 00:03:132537 spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
bncf2ba58832017-06-07 00:22:282538 headers0["user-agent"] = "";
2539 headers0["accept-encoding"] = "gzip, deflate";
Ryan Hamilton0239aac2018-05-19 00:03:132540 spdy::SpdySerializedFrame req0(
bncf2ba58832017-06-07 00:22:282541 spdy_util_.ConstructSpdyHeaders(1, std::move(headers0), LOWEST, true));
Ryan Hamilton0239aac2018-05-19 00:03:132542 spdy::SpdySerializedFrame priority(
bncf2ba58832017-06-07 00:22:282543 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true));
Ryan Hamilton0239aac2018-05-19 00:03:132544 spdy::SpdySerializedFrame rst(
2545 spdy_util_.ConstructSpdyRstStream(2, spdy::ERROR_CODE_CANCEL));
bncf2ba58832017-06-07 00:22:282546 MockWrite writes[] = {CreateMockWrite(req0, 0), CreateMockWrite(priority, 3),
2547 CreateMockWrite(rst, 5)};
[email protected]3a8d6852011-03-11 23:43:442548
Ryan Hamilton0239aac2018-05-19 00:03:132549 spdy::SpdySerializedFrame resp0(
2550 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
2551 spdy::SpdySerializedFrame push(spdy_util_.ConstructSpdyPush(
Bence Békyd2df6c1c82018-04-20 22:52:012552 nullptr, 0, 2, 1, kPushedUrl, "301", redirected_url));
Ryan Hamilton0239aac2018-05-19 00:03:132553 spdy::SpdySerializedFrame body0(spdy_util_.ConstructSpdyDataFrame(1, true));
bncf2ba58832017-06-07 00:22:282554 MockRead reads[] = {CreateMockRead(resp0, 1), CreateMockRead(push, 2),
2555 CreateMockRead(body0, 4), MockRead(ASYNC, 0, 6)};
[email protected]e3ebba0f2010-08-05 17:59:582556
Ryan Sleevib8d7ea02018-05-07 20:01:012557 SequencedSocketData data0(reads, writes);
bncf2ba58832017-06-07 00:22:282558 spdy_url_request_context.socket_factory().AddSocketDataProvider(&data0);
[email protected]e3ebba0f2010-08-05 17:59:582559
bncf2ba58832017-06-07 00:22:282560 SSLSocketDataProvider ssl_provider1(ASYNC, OK);
2561 ssl_provider1.next_proto = kProtoHTTP2;
2562 spdy_url_request_context.socket_factory().AddSSLSocketDataProvider(
2563 &ssl_provider1);
[email protected]e3ebba0f2010-08-05 17:59:582564
bncf2ba58832017-06-07 00:22:282565 SpdyTestUtil spdy_util1;
Bence Béky4c325e52020-10-22 20:48:012566 spdy::Http2HeaderBlock headers1(
Ryan Hamilton0239aac2018-05-19 00:03:132567 spdy_util1.ConstructGetHeaderBlock(redirected_url));
bncf2ba58832017-06-07 00:22:282568 headers1["user-agent"] = "";
2569 headers1["accept-encoding"] = "gzip, deflate";
Ryan Hamilton0239aac2018-05-19 00:03:132570 spdy::SpdySerializedFrame req1(
bncf2ba58832017-06-07 00:22:282571 spdy_util1.ConstructSpdyHeaders(1, std::move(headers1), LOWEST, true));
2572 MockWrite writes1[] = {CreateMockWrite(req1, 0)};
[email protected]e3ebba0f2010-08-05 17:59:582573
Ryan Hamilton0239aac2018-05-19 00:03:132574 spdy::SpdySerializedFrame resp1(
2575 spdy_util1.ConstructSpdyGetReply(nullptr, 0, 1));
2576 spdy::SpdySerializedFrame body1(spdy_util1.ConstructSpdyDataFrame(1, true));
bncf2ba58832017-06-07 00:22:282577 MockRead reads1[] = {CreateMockRead(resp1, 1), CreateMockRead(body1, 2),
2578 MockRead(ASYNC, 0, 3)};
[email protected]e3ebba0f2010-08-05 17:59:582579
Ryan Sleevib8d7ea02018-05-07 20:01:012580 SequencedSocketData data1(reads1, writes1);
bncf2ba58832017-06-07 00:22:282581 spdy_url_request_context.socket_factory().AddSocketDataProvider(&data1);
[email protected]e3ebba0f2010-08-05 17:59:582582
bncf2ba58832017-06-07 00:22:282583 TestDelegate delegate0;
2584 std::unique_ptr<URLRequest> request = spdy_url_request_context.CreateRequest(
2585 default_url_, DEFAULT_PRIORITY, &delegate0, TRAFFIC_ANNOTATION_FOR_TESTS);
2586
2587 request->Start();
Wez0e717112018-06-18 23:09:222588 delegate0.RunUntilComplete();
bncf2ba58832017-06-07 00:22:282589
2590 EXPECT_EQ(0, delegate0.received_redirect_count());
2591 EXPECT_EQ("hello!", delegate0.data_received());
2592
2593 TestDelegate delegate1;
2594 std::unique_ptr<URLRequest> request1 = spdy_url_request_context.CreateRequest(
Bence Békyd2df6c1c82018-04-20 22:52:012595 GURL(kPushedUrl), DEFAULT_PRIORITY, &delegate1,
2596 TRAFFIC_ANNOTATION_FOR_TESTS);
bncf2ba58832017-06-07 00:22:282597
bncf2ba58832017-06-07 00:22:282598 request1->Start();
Wez0e717112018-06-18 23:09:222599 delegate1.RunUntilRedirect();
bncf2ba58832017-06-07 00:22:282600 EXPECT_EQ(1, delegate1.received_redirect_count());
2601
Anton Bikineev068d2912021-05-15 20:43:522602 request1->FollowDeferredRedirect(absl::nullopt /* removed_headers */,
2603 absl::nullopt /* modified_headers */);
Wez0e717112018-06-18 23:09:222604 delegate1.RunUntilComplete();
bncf2ba58832017-06-07 00:22:282605 EXPECT_EQ(1, delegate1.response_started_count());
2606 EXPECT_FALSE(delegate1.received_data_before_response());
2607 EXPECT_EQ(OK, delegate1.request_status());
2608 EXPECT_EQ("hello!", delegate1.data_received());
2609
Wez0e717112018-06-18 23:09:222610 // Pump the message loop to allow read data to be consumed.
2611 base::RunLoop().RunUntilIdle();
2612
bncf2ba58832017-06-07 00:22:282613 EXPECT_TRUE(data0.AllReadDataConsumed());
2614 EXPECT_TRUE(data0.AllWriteDataConsumed());
2615 EXPECT_TRUE(data1.AllReadDataConsumed());
2616 EXPECT_TRUE(data1.AllWriteDataConsumed());
[email protected]e3ebba0f2010-08-05 17:59:582617}
2618
bncd16676a2016-07-20 16:23:012619TEST_F(SpdyNetworkTransactionTest, ServerPushSingleDataFrame) {
Ryan Hamilton0239aac2018-05-19 00:03:132620 spdy::SpdySerializedFrame stream1_syn(
Bence Béky27ad0a12018-02-08 00:35:482621 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
Ryan Hamilton0239aac2018-05-19 00:03:132622 spdy::SpdySerializedFrame stream2_priority(
tombergan5d22c182017-01-11 02:05:352623 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true));
[email protected]e3ebba0f2010-08-05 17:59:582624 MockWrite writes[] = {
tombergan5d22c182017-01-11 02:05:352625 CreateMockWrite(stream1_syn, 0), CreateMockWrite(stream2_priority, 3),
[email protected]e3ebba0f2010-08-05 17:59:582626 };
2627
Ryan Hamilton0239aac2018-05-19 00:03:132628 spdy::SpdySerializedFrame stream1_reply(
tombergan5d22c182017-01-11 02:05:352629 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
Ryan Hamilton0239aac2018-05-19 00:03:132630 spdy::SpdySerializedFrame stream2_syn(
Bence Békyd2df6c1c82018-04-20 22:52:012631 spdy_util_.ConstructSpdyPush(nullptr, 0, 2, 1, kPushedUrl));
Ryan Hamilton0239aac2018-05-19 00:03:132632 spdy::SpdySerializedFrame stream1_body(
2633 spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]8a0fc822013-06-27 20:52:432634 const char kPushedData[] = "pushed";
Ryan Hamilton0239aac2018-05-19 00:03:132635 spdy::SpdySerializedFrame stream2_body(
Bence Békyd74f4382018-02-20 18:26:192636 spdy_util_.ConstructSpdyDataFrame(2, kPushedData, true));
[email protected]e3ebba0f2010-08-05 17:59:582637 MockRead reads[] = {
tombergan5d22c182017-01-11 02:05:352638 CreateMockRead(stream1_reply, 1), CreateMockRead(stream2_syn, 2),
2639 CreateMockRead(stream1_body, 4), CreateMockRead(stream2_body, 5),
2640 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 6), // Force a pause
[email protected]e3ebba0f2010-08-05 17:59:582641 };
2642
2643 HttpResponseInfo response;
2644 HttpResponseInfo response2;
Bence Béky4e83f492018-05-13 23:14:252645 std::string expected_push_result("pushed");
Ryan Sleevib8d7ea02018-05-07 20:01:012646 SequencedSocketData data(reads, writes);
[email protected]dd54bd82012-07-19 23:44:572647 RunServerPushTest(&data,
[email protected]d08358502010-12-03 22:04:032648 &response,
2649 &response2,
2650 expected_push_result);
[email protected]e3ebba0f2010-08-05 17:59:582651
bnc42331402016-07-25 13:36:152652 // Verify the response headers.
wezca1070932016-05-26 20:30:522653 EXPECT_TRUE(response.headers);
bnc84e7fb52015-12-02 11:50:022654 EXPECT_EQ("HTTP/1.1 200", response.headers->GetStatusLine());
[email protected]e3ebba0f2010-08-05 17:59:582655
2656 // Verify the pushed stream.
wezca1070932016-05-26 20:30:522657 EXPECT_TRUE(response2.headers);
bnccdc749f2016-01-27 16:39:042658 EXPECT_EQ("HTTP/1.1 200", response2.headers->GetStatusLine());
[email protected]e3ebba0f2010-08-05 17:59:582659}
2660
Bence Béky02b906a2018-07-18 21:03:392661// When server push is disabled by
2662// HttpNetworkSession::initial_settings[SETTINGS_ENABLE_PUSH] = 0, verify that
2663// such a setting is sent out in the initial SETTINGS frame, and if the server
2664// creates a pushed stream despite of this, it is immediately reset.
2665TEST_F(SpdyNetworkTransactionTest, ServerPushDisabled) {
Bence Békyda83e052018-07-20 01:03:322666 base::HistogramTester histogram_tester;
2667
Bence Béky02b906a2018-07-18 21:03:392668 spdy::SpdySerializedFrame preface(
2669 const_cast<char*>(spdy::kHttp2ConnectionHeaderPrefix),
2670 spdy::kHttp2ConnectionHeaderPrefixSize,
2671 /* owns_buffer = */ false);
2672
2673 spdy::SettingsMap initial_settings;
2674 initial_settings[spdy::SETTINGS_HEADER_TABLE_SIZE] = kSpdyMaxHeaderTableSize;
2675 initial_settings[spdy::SETTINGS_ENABLE_PUSH] = 0;
2676 initial_settings[spdy::SETTINGS_MAX_CONCURRENT_STREAMS] =
2677 kSpdyMaxConcurrentPushedStreams;
Bence Béky6cee52f2019-10-24 16:52:332678 initial_settings[spdy::SETTINGS_MAX_HEADER_LIST_SIZE] =
2679 kSpdyMaxHeaderListSize;
Bence Béky02b906a2018-07-18 21:03:392680 spdy::SpdySerializedFrame initial_settings_frame(
2681 spdy_util_.ConstructSpdySettings(initial_settings));
2682
2683 spdy::SpdySerializedFrame req(
2684 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
2685 spdy::SpdySerializedFrame rst(
2686 spdy_util_.ConstructSpdyRstStream(2, spdy::ERROR_CODE_REFUSED_STREAM));
2687
2688 MockWrite writes[] = {CreateMockWrite(preface, 0),
2689 CreateMockWrite(initial_settings_frame, 1),
2690 CreateMockWrite(req, 2), CreateMockWrite(rst, 5)};
2691
2692 spdy::SpdySerializedFrame reply(
2693 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
2694 spdy::SpdySerializedFrame push(
2695 spdy_util_.ConstructSpdyPush(nullptr, 0, 2, 1, kPushedUrl));
2696 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
2697 MockRead reads[] = {CreateMockRead(reply, 3), CreateMockRead(push, 4),
2698 CreateMockRead(body, 6), MockRead(ASYNC, OK, 7)};
2699
2700 SequencedSocketData data(reads, writes);
2701
2702 auto session_deps = std::make_unique<SpdySessionDependencies>();
2703 session_deps->http2_settings[spdy::SETTINGS_ENABLE_PUSH] = 0;
2704 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
2705 std::move(session_deps));
2706
2707 SpdySessionPool* spdy_session_pool = helper.session()->spdy_session_pool();
2708 SpdySessionPoolPeer pool_peer(spdy_session_pool);
2709 pool_peer.SetEnableSendingInitialData(true);
2710
2711 helper.RunToCompletion(&data);
Bence Békyda83e052018-07-20 01:03:322712
2713 histogram_tester.ExpectBucketCount(
2714 "Net.SpdyPushedStreamFate",
2715 static_cast<int>(SpdyPushedStreamFate::kPushDisabled), 1);
2716 histogram_tester.ExpectTotalCount("Net.SpdyPushedStreamFate", 1);
Bence Béky02b906a2018-07-18 21:03:392717}
2718
Bence Béky5b1e4ce72018-01-11 14:55:152719TEST_F(SpdyNetworkTransactionTest, ServerPushHeadMethod) {
Ryan Hamilton0239aac2018-05-19 00:03:132720 spdy::SpdySerializedFrame req(
2721 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
2722 spdy::SpdySerializedFrame priority(
Bence Béky5b1e4ce72018-01-11 14:55:152723 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true));
2724 MockWrite writes[] = {CreateMockWrite(req, 0), CreateMockWrite(priority, 2)};
2725
Bence Béky4c325e52020-10-22 20:48:012726 spdy::Http2HeaderBlock push_promise_header_block;
Ryan Hamilton0239aac2018-05-19 00:03:132727 push_promise_header_block[spdy::kHttp2MethodHeader] = "HEAD";
Bence Békyd2df6c1c82018-04-20 22:52:012728 spdy_util_.AddUrlToHeaderBlock(kPushedUrl, &push_promise_header_block);
Ryan Hamilton0239aac2018-05-19 00:03:132729 spdy::SpdySerializedFrame push_promise(spdy_util_.ConstructSpdyPushPromise(
Bence Béky5b1e4ce72018-01-11 14:55:152730 1, 2, std::move(push_promise_header_block)));
2731
Bence Béky4c325e52020-10-22 20:48:012732 spdy::Http2HeaderBlock push_response_headers;
Ryan Hamilton0239aac2018-05-19 00:03:132733 push_response_headers[spdy::kHttp2StatusHeader] = "200";
Bence Béky5b1e4ce72018-01-11 14:55:152734 push_response_headers["foo"] = "bar";
Ryan Hamilton0239aac2018-05-19 00:03:132735 spdy::SpdyHeadersIR headers_ir(2, std::move(push_response_headers));
2736 spdy::SpdySerializedFrame push_headers(spdy_util_.SerializeFrame(headers_ir));
Bence Béky5b1e4ce72018-01-11 14:55:152737
Ryan Hamilton0239aac2018-05-19 00:03:132738 spdy::SpdySerializedFrame resp(
2739 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
2740 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
Bence Béky5b1e4ce72018-01-11 14:55:152741 MockRead reads[] = {
2742 CreateMockRead(push_promise, 1), CreateMockRead(push_headers, 3),
2743 CreateMockRead(resp, 4), CreateMockRead(body, 5),
2744 // Do not close the connection after first request is done.
2745 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 6)};
2746
Ryan Sleevib8d7ea02018-05-07 20:01:012747 SequencedSocketData data(reads, writes);
Bence Béky5b1e4ce72018-01-11 14:55:152748
2749 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
2750 helper.RunPreTestSetup();
2751 helper.AddData(&data);
2752
2753 // Run first request. This reads PUSH_PROMISE.
2754 helper.RunDefaultTest();
2755
2756 // Request the pushed resource.
2757 HttpNetworkTransaction trans(DEFAULT_PRIORITY, helper.session());
2758 HttpRequestInfo request = CreateGetPushRequest();
2759 request.method = "HEAD";
Ramin Halavatib5e433e62018-02-07 07:41:102760 request.traffic_annotation =
2761 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
Bence Béky5b1e4ce72018-01-11 14:55:152762 TestCompletionCallback callback;
2763 int rv = trans.Start(&request, callback.callback(), log_);
2764 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
2765 rv = callback.WaitForResult();
2766 EXPECT_THAT(rv, IsOk());
2767
2768 const HttpResponseInfo* response = trans.GetResponseInfo();
2769 ASSERT_TRUE(response);
2770 EXPECT_TRUE(response->was_fetched_via_spdy);
2771 EXPECT_TRUE(response->was_alpn_negotiated);
2772 ASSERT_TRUE(response->headers);
2773 EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
2774 std::string value;
2775 EXPECT_TRUE(response->headers->GetNormalizedHeader("foo", &value));
2776 EXPECT_EQ("bar", value);
2777
2778 helper.VerifyDataConsumed();
2779}
2780
2781TEST_F(SpdyNetworkTransactionTest, ServerPushHeadDoesNotMatchGetRequest) {
Ryan Hamilton0239aac2018-05-19 00:03:132782 spdy::SpdySerializedFrame req1(
2783 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
2784 spdy::SpdySerializedFrame priority(
Bence Béky5b1e4ce72018-01-11 14:55:152785 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true));
2786 spdy_util_.UpdateWithStreamDestruction(1);
Ryan Hamilton0239aac2018-05-19 00:03:132787 spdy::SpdySerializedFrame req2(
2788 spdy_util_.ConstructSpdyGet(kPushedUrl, 3, LOWEST));
Bence Béky5b1e4ce72018-01-11 14:55:152789 MockWrite writes[] = {CreateMockWrite(req1, 0), CreateMockWrite(priority, 2),
2790 CreateMockWrite(req2, 6)};
2791
Bence Béky4c325e52020-10-22 20:48:012792 spdy::Http2HeaderBlock push_promise_header_block;
Ryan Hamilton0239aac2018-05-19 00:03:132793 push_promise_header_block[spdy::kHttp2MethodHeader] = "HEAD";
Bence Békyd2df6c1c82018-04-20 22:52:012794 spdy_util_.AddUrlToHeaderBlock(kPushedUrl, &push_promise_header_block);
Ryan Hamilton0239aac2018-05-19 00:03:132795 spdy::SpdySerializedFrame push_promise(spdy_util_.ConstructSpdyPushPromise(
Bence Béky5b1e4ce72018-01-11 14:55:152796 1, 2, std::move(push_promise_header_block)));
2797
Bence Béky4c325e52020-10-22 20:48:012798 spdy::Http2HeaderBlock push_response_headers;
Ryan Hamilton0239aac2018-05-19 00:03:132799 push_response_headers[spdy::kHttp2StatusHeader] = "200";
Bence Béky5b1e4ce72018-01-11 14:55:152800 push_response_headers["foo"] = "bar";
Ryan Hamilton0239aac2018-05-19 00:03:132801 spdy::SpdyHeadersIR headers_ir(2, std::move(push_response_headers));
2802 spdy::SpdySerializedFrame push_headers(spdy_util_.SerializeFrame(headers_ir));
Bence Béky5b1e4ce72018-01-11 14:55:152803
Ryan Hamilton0239aac2018-05-19 00:03:132804 spdy::SpdySerializedFrame resp1(
2805 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
2806 spdy::SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true));
2807 spdy::SpdySerializedFrame resp2(
2808 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
2809 spdy::SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(3, true));
Bence Béky5b1e4ce72018-01-11 14:55:152810 MockRead reads[] = {CreateMockRead(push_promise, 1),
2811 CreateMockRead(push_headers, 3),
2812 CreateMockRead(resp1, 4),
2813 CreateMockRead(body1, 5),
2814 CreateMockRead(resp2, 7),
2815 CreateMockRead(body2, 8),
2816 MockRead(ASYNC, 0, 9)};
2817
Ryan Sleevib8d7ea02018-05-07 20:01:012818 SequencedSocketData data(reads, writes);
Bence Béky5b1e4ce72018-01-11 14:55:152819
2820 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
2821 helper.RunPreTestSetup();
2822 helper.AddData(&data);
2823
2824 // Run first request. This reads PUSH_PROMISE.
2825 helper.RunDefaultTest();
2826
2827 // Request the pushed resource.
2828 HttpNetworkTransaction trans(DEFAULT_PRIORITY, helper.session());
2829 HttpRequestInfo request = CreateGetPushRequest();
2830 TestCompletionCallback callback;
2831 int rv = trans.Start(&request, callback.callback(), log_);
2832 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
2833 rv = callback.WaitForResult();
2834 EXPECT_THAT(rv, IsOk());
2835
2836 const HttpResponseInfo* response = trans.GetResponseInfo();
2837 ASSERT_TRUE(response);
2838 EXPECT_TRUE(response->was_fetched_via_spdy);
2839 EXPECT_TRUE(response->was_alpn_negotiated);
2840 ASSERT_TRUE(response->headers);
2841 EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
2842 std::string value;
2843 EXPECT_FALSE(response->headers->GetNormalizedHeader("foo", &value));
2844 std::string result;
2845 ReadResult(&trans, &result);
2846 EXPECT_EQ("hello!", result);
2847
2848 // Read EOF.
2849 base::RunLoop().RunUntilIdle();
2850
2851 helper.VerifyDataConsumed();
2852}
2853
bncd16676a2016-07-20 16:23:012854TEST_F(SpdyNetworkTransactionTest, ServerPushSingleDataFrame2) {
Ryan Hamilton0239aac2018-05-19 00:03:132855 spdy::SpdySerializedFrame stream1_syn(
Bence Béky27ad0a12018-02-08 00:35:482856 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
Ryan Hamilton0239aac2018-05-19 00:03:132857 spdy::SpdySerializedFrame stream2_priority(
tombergan5d22c182017-01-11 02:05:352858 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true));
rch08e3aa3e2015-05-16 14:27:522859 MockWrite writes[] = {
tombergan5d22c182017-01-11 02:05:352860 CreateMockWrite(stream1_syn, 0), CreateMockWrite(stream2_priority, 3),
rch08e3aa3e2015-05-16 14:27:522861 };
[email protected]82918cc2010-08-25 17:24:502862
Ryan Hamilton0239aac2018-05-19 00:03:132863 spdy::SpdySerializedFrame stream1_reply(
tombergan5d22c182017-01-11 02:05:352864 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
Ryan Hamilton0239aac2018-05-19 00:03:132865 spdy::SpdySerializedFrame stream2_syn(
Bence Békyd2df6c1c82018-04-20 22:52:012866 spdy_util_.ConstructSpdyPush(nullptr, 0, 2, 1, kPushedUrl));
[email protected]8a0fc822013-06-27 20:52:432867 const char kPushedData[] = "pushed";
Ryan Hamilton0239aac2018-05-19 00:03:132868 spdy::SpdySerializedFrame stream2_body(
Bence Békyd74f4382018-02-20 18:26:192869 spdy_util_.ConstructSpdyDataFrame(2, kPushedData, true));
Ryan Hamilton0239aac2018-05-19 00:03:132870 spdy::SpdySerializedFrame stream1_body(
2871 spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]82918cc2010-08-25 17:24:502872 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:412873 CreateMockRead(stream1_reply, 1),
2874 CreateMockRead(stream2_syn, 2),
tombergan5d22c182017-01-11 02:05:352875 CreateMockRead(stream2_body, 4),
2876 CreateMockRead(stream1_body, 5, SYNCHRONOUS),
2877 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 6), // Force a pause
[email protected]82918cc2010-08-25 17:24:502878 };
2879
2880 HttpResponseInfo response;
2881 HttpResponseInfo response2;
Bence Béky4e83f492018-05-13 23:14:252882 std::string expected_push_result("pushed");
Ryan Sleevib8d7ea02018-05-07 20:01:012883 SequencedSocketData data(reads, writes);
[email protected]dd54bd82012-07-19 23:44:572884 RunServerPushTest(&data,
[email protected]d08358502010-12-03 22:04:032885 &response,
2886 &response2,
2887 expected_push_result);
[email protected]82918cc2010-08-25 17:24:502888
bnc42331402016-07-25 13:36:152889 // Verify the response headers.
wezca1070932016-05-26 20:30:522890 EXPECT_TRUE(response.headers);
bnc84e7fb52015-12-02 11:50:022891 EXPECT_EQ("HTTP/1.1 200", response.headers->GetStatusLine());
[email protected]82918cc2010-08-25 17:24:502892
2893 // Verify the pushed stream.
wezca1070932016-05-26 20:30:522894 EXPECT_TRUE(response2.headers);
bnccdc749f2016-01-27 16:39:042895 EXPECT_EQ("HTTP/1.1 200", response2.headers->GetStatusLine());
[email protected]82918cc2010-08-25 17:24:502896}
2897
tombergan5d22c182017-01-11 02:05:352898TEST_F(SpdyNetworkTransactionTest, ServerPushUpdatesPriority) {
Ryan Hamilton0239aac2018-05-19 00:03:132899 spdy::SpdySerializedFrame stream1_headers(
Bence Béky27ad0a12018-02-08 00:35:482900 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, HIGHEST));
Ryan Hamilton0239aac2018-05-19 00:03:132901 spdy::SpdySerializedFrame stream3_headers(
Bence Béky27ad0a12018-02-08 00:35:482902 spdy_util_.ConstructSpdyGet(nullptr, 0, 3, MEDIUM));
Ryan Hamilton0239aac2018-05-19 00:03:132903 spdy::SpdySerializedFrame stream5_headers(
Bence Béky27ad0a12018-02-08 00:35:482904 spdy_util_.ConstructSpdyGet(nullptr, 0, 5, MEDIUM));
tombergan5d22c182017-01-11 02:05:352905
2906 // Stream 1 pushes two streams that are initially prioritized below stream 5.
2907 // Stream 2 is later prioritized below stream 1 after it matches a request.
Ryan Hamilton0239aac2018-05-19 00:03:132908 spdy::SpdySerializedFrame stream2_priority(
tombergan5d22c182017-01-11 02:05:352909 spdy_util_.ConstructSpdyPriority(2, 5, IDLE, true));
Ryan Hamilton0239aac2018-05-19 00:03:132910 spdy::SpdySerializedFrame stream4_priority(
tombergan5d22c182017-01-11 02:05:352911 spdy_util_.ConstructSpdyPriority(4, 2, IDLE, true));
Ryan Hamilton0239aac2018-05-19 00:03:132912 spdy::SpdySerializedFrame stream4_priority_update(
tombergan5d22c182017-01-11 02:05:352913 spdy_util_.ConstructSpdyPriority(4, 5, IDLE, true));
Ryan Hamilton0239aac2018-05-19 00:03:132914 spdy::SpdySerializedFrame stream2_priority_update(
tombergan5d22c182017-01-11 02:05:352915 spdy_util_.ConstructSpdyPriority(2, 1, HIGHEST, true));
2916
[email protected]e3ebba0f2010-08-05 17:59:582917 MockWrite writes[] = {
tombergan5d22c182017-01-11 02:05:352918 CreateMockWrite(stream1_headers, 0),
2919 CreateMockWrite(stream3_headers, 1),
2920 CreateMockWrite(stream5_headers, 2),
2921 CreateMockWrite(stream2_priority, 7),
2922 CreateMockWrite(stream4_priority, 9),
2923 CreateMockWrite(stream4_priority_update, 11),
2924 CreateMockWrite(stream2_priority_update, 12),
[email protected]e3ebba0f2010-08-05 17:59:582925 };
2926
Ryan Hamilton0239aac2018-05-19 00:03:132927 spdy::SpdySerializedFrame stream1_reply(
tombergan5d22c182017-01-11 02:05:352928 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
Ryan Hamilton0239aac2018-05-19 00:03:132929 spdy::SpdySerializedFrame stream3_reply(
tombergan5d22c182017-01-11 02:05:352930 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
Ryan Hamilton0239aac2018-05-19 00:03:132931 spdy::SpdySerializedFrame stream5_reply(
tombergan5d22c182017-01-11 02:05:352932 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 5));
2933
Ryan Hamilton0239aac2018-05-19 00:03:132934 spdy::SpdySerializedFrame stream2_push(
Bence Békyd2df6c1c82018-04-20 22:52:012935 spdy_util_.ConstructSpdyPush(nullptr, 0, 2, 1, kPushedUrl));
Ryan Hamilton0239aac2018-05-19 00:03:132936 spdy::SpdySerializedFrame stream4_push(spdy_util_.ConstructSpdyPush(
Bence Béky3e01b532018-02-06 23:04:512937 nullptr, 0, 4, 1, "https://www.example.org/bar.dat"));
tombergan5d22c182017-01-11 02:05:352938
Ryan Hamilton0239aac2018-05-19 00:03:132939 spdy::SpdySerializedFrame stream1_body(
2940 spdy_util_.ConstructSpdyDataFrame(1, true));
2941 spdy::SpdySerializedFrame stream2_body(
2942 spdy_util_.ConstructSpdyDataFrame(2, true));
2943 spdy::SpdySerializedFrame stream3_body(
2944 spdy_util_.ConstructSpdyDataFrame(3, true));
2945 spdy::SpdySerializedFrame stream5_body(
2946 spdy_util_.ConstructSpdyDataFrame(5, true));
tombergan5d22c182017-01-11 02:05:352947
2948 MockRead reads[] = {
2949 CreateMockRead(stream1_reply, 3),
2950 CreateMockRead(stream3_reply, 4),
2951 CreateMockRead(stream5_reply, 5),
2952 CreateMockRead(stream2_push, 6),
2953 CreateMockRead(stream4_push, 8),
2954 MockRead(ASYNC, ERR_IO_PENDING, 10),
2955 CreateMockRead(stream1_body, 13),
2956 CreateMockRead(stream2_body, 14),
2957 CreateMockRead(stream3_body, 15),
2958 CreateMockRead(stream5_body, 16),
2959 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 17), // Force a pause
2960 };
2961
Ryan Sleevib8d7ea02018-05-07 20:01:012962 SequencedSocketData data(reads, writes);
2963 SequencedSocketData data_placeholder1;
2964 SequencedSocketData data_placeholder2;
2965 SequencedSocketData data_placeholder3;
tombergan5d22c182017-01-11 02:05:352966
Bence Békydb3cf652017-10-10 15:22:102967 NormalSpdyTransactionHelper helper(request_, LOWEST, log_, nullptr);
tombergan5d22c182017-01-11 02:05:352968 helper.RunPreTestSetup();
2969 helper.AddData(&data);
2970 helper.AddData(&data_placeholder1); // other requests reuse the same socket
2971 helper.AddData(&data_placeholder2);
2972 helper.AddData(&data_placeholder3);
2973 HttpNetworkTransaction trans1(HIGHEST, helper.session());
2974 HttpNetworkTransaction trans3(MEDIUM, helper.session());
2975 HttpNetworkTransaction trans5(MEDIUM, helper.session());
2976
2977 TestCompletionCallback callback1;
2978 TestCompletionCallback callback3;
2979 TestCompletionCallback callback5;
2980
2981 // Start the ordinary requests.
Bence Békydb3cf652017-10-10 15:22:102982 ASSERT_THAT(trans1.Start(&request_, callback1.callback(), log_),
tombergan5d22c182017-01-11 02:05:352983 IsError(ERR_IO_PENDING));
Bence Békydb3cf652017-10-10 15:22:102984 ASSERT_THAT(trans3.Start(&request_, callback3.callback(), log_),
tombergan5d22c182017-01-11 02:05:352985 IsError(ERR_IO_PENDING));
Bence Békydb3cf652017-10-10 15:22:102986 ASSERT_THAT(trans5.Start(&request_, callback5.callback(), log_),
tombergan5d22c182017-01-11 02:05:352987 IsError(ERR_IO_PENDING));
2988 data.RunUntilPaused();
2989
tombergan5d22c182017-01-11 02:05:352990 // Start a request that matches the push.
Bence Békydb3cf652017-10-10 15:22:102991 HttpRequestInfo push_req = CreateGetPushRequest();
krasin0bfeb6b2017-01-13 21:48:042992
2993 HttpNetworkTransaction trans2(HIGHEST, helper.session());
2994 TestCompletionCallback callback2;
Bence Békyd3dde832017-09-19 19:02:312995 ASSERT_THAT(trans2.Start(&push_req, callback2.callback(), log_),
tombergan5d22c182017-01-11 02:05:352996 IsError(ERR_IO_PENDING));
2997 data.Resume();
2998
2999 base::RunLoop().RunUntilIdle();
3000 ASSERT_THAT(callback1.WaitForResult(), IsOk());
3001 ASSERT_THAT(callback2.WaitForResult(), IsOk());
3002 ASSERT_THAT(callback3.WaitForResult(), IsOk());
3003 ASSERT_THAT(callback5.WaitForResult(), IsOk());
3004 helper.VerifyDataConsumed();
3005}
3006
3007TEST_F(SpdyNetworkTransactionTest, ServerPushServerAborted) {
Ryan Hamilton0239aac2018-05-19 00:03:133008 spdy::SpdySerializedFrame stream1_syn(
Bence Béky27ad0a12018-02-08 00:35:483009 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
Ryan Hamilton0239aac2018-05-19 00:03:133010 spdy::SpdySerializedFrame stream2_priority(
tombergan5d22c182017-01-11 02:05:353011 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true));
3012 MockWrite writes[] = {
3013 CreateMockWrite(stream1_syn, 0), CreateMockWrite(stream2_priority, 3),
3014 };
3015
Ryan Hamilton0239aac2018-05-19 00:03:133016 spdy::SpdySerializedFrame stream1_reply(
tombergan5d22c182017-01-11 02:05:353017 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
Ryan Hamilton0239aac2018-05-19 00:03:133018 spdy::SpdySerializedFrame stream2_syn(
Bence Békyd2df6c1c82018-04-20 22:52:013019 spdy_util_.ConstructSpdyPush(nullptr, 0, 2, 1, kPushedUrl));
Ryan Hamilton0239aac2018-05-19 00:03:133020 spdy::SpdySerializedFrame stream2_rst(
3021 spdy_util_.ConstructSpdyRstStream(2, spdy::ERROR_CODE_PROTOCOL_ERROR));
3022 spdy::SpdySerializedFrame stream1_body(
3023 spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]e3ebba0f2010-08-05 17:59:583024 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:413025 CreateMockRead(stream1_reply, 1),
bnceb9aa7112017-01-05 01:03:463026 CreateMockRead(stream2_syn, 2, SYNCHRONOUS),
tombergan5d22c182017-01-11 02:05:353027 CreateMockRead(stream2_rst, 4),
3028 CreateMockRead(stream1_body, 5, SYNCHRONOUS),
3029 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 6), // Force a pause
[email protected]e3ebba0f2010-08-05 17:59:583030 };
3031
Ryan Sleevib8d7ea02018-05-07 20:01:013032 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:103033 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]e3ebba0f2010-08-05 17:59:583034
3035 helper.RunPreTestSetup();
[email protected]dd54bd82012-07-19 23:44:573036 helper.AddData(&data);
[email protected]e3ebba0f2010-08-05 17:59:583037
3038 HttpNetworkTransaction* trans = helper.trans();
3039
3040 // Start the transaction with basic parameters.
[email protected]49639fa2011-12-20 23:22:413041 TestCompletionCallback callback;
Bence Békydb3cf652017-10-10 15:22:103042 int rv = trans->Start(&request_, callback.callback(), log_);
robpercival214763f2016-07-01 23:27:013043 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]e3ebba0f2010-08-05 17:59:583044 rv = callback.WaitForResult();
robpercival214763f2016-07-01 23:27:013045 EXPECT_THAT(rv, IsOk());
[email protected]19ec8a72010-08-23 03:38:233046
3047 // Verify that we consumed all test data.
tombergan5d22c182017-01-11 02:05:353048 base::RunLoop().RunUntilIdle();
rch08e3aa3e2015-05-16 14:27:523049 EXPECT_TRUE(data.AllReadDataConsumed());
3050 EXPECT_TRUE(data.AllWriteDataConsumed());
[email protected]19ec8a72010-08-23 03:38:233051
bnc42331402016-07-25 13:36:153052 // Verify the response headers.
[email protected]19ec8a72010-08-23 03:38:233053 HttpResponseInfo response = *trans->GetResponseInfo();
wezca1070932016-05-26 20:30:523054 EXPECT_TRUE(response.headers);
bnc84e7fb52015-12-02 11:50:023055 EXPECT_EQ("HTTP/1.1 200", response.headers->GetStatusLine());
[email protected]19ec8a72010-08-23 03:38:233056}
3057
[email protected]8a0fc822013-06-27 20:52:433058// Verify that we don't leak streams and that we properly send a reset
3059// if the server pushes the same stream twice.
bncd16676a2016-07-20 16:23:013060TEST_F(SpdyNetworkTransactionTest, ServerPushDuplicate) {
Bence Békyeacd48f2018-05-14 11:34:333061 base::HistogramTester histogram_tester;
3062
Ryan Hamilton0239aac2018-05-19 00:03:133063 spdy::SpdySerializedFrame stream1_syn(
Bence Béky27ad0a12018-02-08 00:35:483064 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
Ryan Hamilton0239aac2018-05-19 00:03:133065 spdy::SpdySerializedFrame stream2_priority(
tombergan5d22c182017-01-11 02:05:353066 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true));
Ryan Hamilton0239aac2018-05-19 00:03:133067 spdy::SpdySerializedFrame stream3_rst(
3068 spdy_util_.ConstructSpdyRstStream(4, spdy::ERROR_CODE_REFUSED_STREAM));
[email protected]fdc165a2010-09-03 03:51:293069 MockWrite writes[] = {
tombergan5d22c182017-01-11 02:05:353070 CreateMockWrite(stream1_syn, 0), CreateMockWrite(stream2_priority, 3),
3071 CreateMockWrite(stream3_rst, 5),
[email protected]fdc165a2010-09-03 03:51:293072 };
3073
Ryan Hamilton0239aac2018-05-19 00:03:133074 spdy::SpdySerializedFrame stream1_reply(
tombergan5d22c182017-01-11 02:05:353075 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
Ryan Hamilton0239aac2018-05-19 00:03:133076 spdy::SpdySerializedFrame stream2_syn(
Bence Békyd2df6c1c82018-04-20 22:52:013077 spdy_util_.ConstructSpdyPush(nullptr, 0, 2, 1, kPushedUrl));
Ryan Hamilton0239aac2018-05-19 00:03:133078 spdy::SpdySerializedFrame stream3_syn(
Bence Békyd2df6c1c82018-04-20 22:52:013079 spdy_util_.ConstructSpdyPush(nullptr, 0, 4, 1, kPushedUrl));
tombergan5d22c182017-01-11 02:05:353080
[email protected]8a0fc822013-06-27 20:52:433081 const char kPushedData[] = "pushed";
Ryan Hamilton0239aac2018-05-19 00:03:133082 spdy::SpdySerializedFrame stream1_body(
3083 spdy_util_.ConstructSpdyDataFrame(1, true));
3084 spdy::SpdySerializedFrame stream2_body(
Bence Békyd74f4382018-02-20 18:26:193085 spdy_util_.ConstructSpdyDataFrame(2, kPushedData, true));
tombergan5d22c182017-01-11 02:05:353086
[email protected]fdc165a2010-09-03 03:51:293087 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:413088 CreateMockRead(stream1_reply, 1),
3089 CreateMockRead(stream2_syn, 2),
tombergan5d22c182017-01-11 02:05:353090 CreateMockRead(stream3_syn, 4),
3091 CreateMockRead(stream1_body, 6),
3092 CreateMockRead(stream2_body, 7),
3093 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 8), // Force a pause
[email protected]fdc165a2010-09-03 03:51:293094 };
3095
3096 HttpResponseInfo response;
3097 HttpResponseInfo response2;
Bence Béky4e83f492018-05-13 23:14:253098 std::string expected_push_result("pushed");
Ryan Sleevib8d7ea02018-05-07 20:01:013099 SequencedSocketData data(reads, writes);
[email protected]dd54bd82012-07-19 23:44:573100 RunServerPushTest(&data,
[email protected]d08358502010-12-03 22:04:033101 &response,
3102 &response2,
3103 expected_push_result);
[email protected]fdc165a2010-09-03 03:51:293104
bnc42331402016-07-25 13:36:153105 // Verify the response headers.
wezca1070932016-05-26 20:30:523106 EXPECT_TRUE(response.headers);
bnc84e7fb52015-12-02 11:50:023107 EXPECT_EQ("HTTP/1.1 200", response.headers->GetStatusLine());
[email protected]fdc165a2010-09-03 03:51:293108
3109 // Verify the pushed stream.
wezca1070932016-05-26 20:30:523110 EXPECT_TRUE(response2.headers);
bnccdc749f2016-01-27 16:39:043111 EXPECT_EQ("HTTP/1.1 200", response2.headers->GetStatusLine());
Bence Békyeacd48f2018-05-14 11:34:333112
3113 histogram_tester.ExpectBucketCount(
3114 "Net.SpdyPushedStreamFate",
3115 static_cast<int>(SpdyPushedStreamFate::kAcceptedNoVary), 1);
3116 histogram_tester.ExpectBucketCount(
3117 "Net.SpdyPushedStreamFate",
3118 static_cast<int>(SpdyPushedStreamFate::kDuplicateUrl), 1);
3119 histogram_tester.ExpectTotalCount("Net.SpdyPushedStreamFate", 2);
[email protected]fdc165a2010-09-03 03:51:293120}
3121
bncd16676a2016-07-20 16:23:013122TEST_F(SpdyNetworkTransactionTest, ServerPushMultipleDataFrame) {
Ryan Hamilton0239aac2018-05-19 00:03:133123 spdy::SpdySerializedFrame stream1_syn(
Bence Béky27ad0a12018-02-08 00:35:483124 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
Ryan Hamilton0239aac2018-05-19 00:03:133125 spdy::SpdySerializedFrame stream2_priority(
tombergan5d22c182017-01-11 02:05:353126 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true));
[email protected]19ec8a72010-08-23 03:38:233127 MockWrite writes[] = {
tombergan5d22c182017-01-11 02:05:353128 CreateMockWrite(stream1_syn, 0), CreateMockWrite(stream2_priority, 3),
[email protected]19ec8a72010-08-23 03:38:233129 };
3130
Ryan Hamilton0239aac2018-05-19 00:03:133131 spdy::SpdySerializedFrame stream1_reply(
tombergan5d22c182017-01-11 02:05:353132 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
Ryan Hamilton0239aac2018-05-19 00:03:133133 spdy::SpdySerializedFrame stream2_syn(
Bence Békyd2df6c1c82018-04-20 22:52:013134 spdy_util_.ConstructSpdyPush(nullptr, 0, 2, 1, kPushedUrl));
Bence Békyd74f4382018-02-20 18:26:193135 static const char kPushedData[] = "pushed payload for chunked test";
Ryan Hamilton0239aac2018-05-19 00:03:133136 spdy::SpdySerializedFrame stream2_body_base(
Bence Békyd74f4382018-02-20 18:26:193137 spdy_util_.ConstructSpdyDataFrame(2, kPushedData, true));
[email protected]8a0fc822013-06-27 20:52:433138 const size_t kChunkSize = strlen(kPushedData) / 4;
Ryan Hamilton0239aac2018-05-19 00:03:133139 spdy::SpdySerializedFrame stream2_body1(stream2_body_base.data(), kChunkSize,
3140 false);
3141 spdy::SpdySerializedFrame stream2_body2(stream2_body_base.data() + kChunkSize,
3142 kChunkSize, false);
3143 spdy::SpdySerializedFrame stream2_body3(
3144 stream2_body_base.data() + 2 * kChunkSize, kChunkSize, false);
3145 spdy::SpdySerializedFrame stream2_body4(
3146 stream2_body_base.data() + 3 * kChunkSize,
3147 stream2_body_base.size() - 3 * kChunkSize, false);
3148 spdy::SpdySerializedFrame stream1_body(
3149 spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]19ec8a72010-08-23 03:38:233150 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:413151 CreateMockRead(stream1_reply, 1),
3152 CreateMockRead(stream2_syn, 2),
tombergan5d22c182017-01-11 02:05:353153 CreateMockRead(stream2_body1, 4),
3154 CreateMockRead(stream2_body2, 5),
3155 CreateMockRead(stream2_body3, 6),
3156 CreateMockRead(stream2_body4, 7),
3157 CreateMockRead(stream1_body, 8, SYNCHRONOUS),
3158 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 9), // Force a pause
[email protected]19ec8a72010-08-23 03:38:233159 };
3160
3161 HttpResponseInfo response;
3162 HttpResponseInfo response2;
Bence Béky4e83f492018-05-13 23:14:253163 std::string expected_push_result(kPushedData);
Ryan Sleevib8d7ea02018-05-07 20:01:013164 SequencedSocketData data(reads, writes);
[email protected]8a0fc822013-06-27 20:52:433165 RunServerPushTest(&data, &response, &response2, kPushedData);
[email protected]19ec8a72010-08-23 03:38:233166
bnc42331402016-07-25 13:36:153167 // Verify the response headers.
wezca1070932016-05-26 20:30:523168 EXPECT_TRUE(response.headers);
bnc84e7fb52015-12-02 11:50:023169 EXPECT_EQ("HTTP/1.1 200", response.headers->GetStatusLine());
[email protected]19ec8a72010-08-23 03:38:233170
3171 // Verify the pushed stream.
wezca1070932016-05-26 20:30:523172 EXPECT_TRUE(response2.headers);
bnccdc749f2016-01-27 16:39:043173 EXPECT_EQ("HTTP/1.1 200", response2.headers->GetStatusLine());
[email protected]19ec8a72010-08-23 03:38:233174}
3175
bncd16676a2016-07-20 16:23:013176TEST_F(SpdyNetworkTransactionTest, ServerPushMultipleDataFrameInterrupted) {
Ryan Hamilton0239aac2018-05-19 00:03:133177 spdy::SpdySerializedFrame stream1_syn(
Bence Béky27ad0a12018-02-08 00:35:483178 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
Ryan Hamilton0239aac2018-05-19 00:03:133179 spdy::SpdySerializedFrame stream2_priority(
tombergan5d22c182017-01-11 02:05:353180 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true));
[email protected]19ec8a72010-08-23 03:38:233181 MockWrite writes[] = {
tombergan5d22c182017-01-11 02:05:353182 CreateMockWrite(stream1_syn, 0), CreateMockWrite(stream2_priority, 3),
[email protected]19ec8a72010-08-23 03:38:233183 };
3184
Ryan Hamilton0239aac2018-05-19 00:03:133185 spdy::SpdySerializedFrame stream1_reply(
tombergan5d22c182017-01-11 02:05:353186 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
Ryan Hamilton0239aac2018-05-19 00:03:133187 spdy::SpdySerializedFrame stream2_syn(
Bence Békyd2df6c1c82018-04-20 22:52:013188 spdy_util_.ConstructSpdyPush(nullptr, 0, 2, 1, kPushedUrl));
Bence Békyd74f4382018-02-20 18:26:193189 static const char kPushedData[] = "pushed payload for chunked test";
Ryan Hamilton0239aac2018-05-19 00:03:133190 spdy::SpdySerializedFrame stream2_body_base(
Bence Békyd74f4382018-02-20 18:26:193191 spdy_util_.ConstructSpdyDataFrame(2, kPushedData, true));
[email protected]8a0fc822013-06-27 20:52:433192 const size_t kChunkSize = strlen(kPushedData) / 4;
Ryan Hamilton0239aac2018-05-19 00:03:133193 spdy::SpdySerializedFrame stream2_body1(stream2_body_base.data(), kChunkSize,
3194 false);
3195 spdy::SpdySerializedFrame stream2_body2(stream2_body_base.data() + kChunkSize,
3196 kChunkSize, false);
3197 spdy::SpdySerializedFrame stream2_body3(
3198 stream2_body_base.data() + 2 * kChunkSize, kChunkSize, false);
3199 spdy::SpdySerializedFrame stream2_body4(
3200 stream2_body_base.data() + 3 * kChunkSize,
3201 stream2_body_base.size() - 3 * kChunkSize, false);
3202 spdy::SpdySerializedFrame stream1_body(
3203 spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]19ec8a72010-08-23 03:38:233204 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:413205 CreateMockRead(stream1_reply, 1),
3206 CreateMockRead(stream2_syn, 2),
tombergan5d22c182017-01-11 02:05:353207 CreateMockRead(stream2_body1, 4),
3208 CreateMockRead(stream2_body2, 5),
3209 CreateMockRead(stream2_body3, 6),
3210 CreateMockRead(stream2_body4, 7),
3211 CreateMockRead(stream1_body, 8, SYNCHRONOUS),
3212 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 9) // Force a pause.
[email protected]19ec8a72010-08-23 03:38:233213 };
3214
3215 HttpResponseInfo response;
3216 HttpResponseInfo response2;
Ryan Sleevib8d7ea02018-05-07 20:01:013217 SequencedSocketData data(reads, writes);
[email protected]8a0fc822013-06-27 20:52:433218 RunServerPushTest(&data, &response, &response2, kPushedData);
[email protected]19ec8a72010-08-23 03:38:233219
bnc42331402016-07-25 13:36:153220 // Verify the response headers.
wezca1070932016-05-26 20:30:523221 EXPECT_TRUE(response.headers);
bnc84e7fb52015-12-02 11:50:023222 EXPECT_EQ("HTTP/1.1 200", response.headers->GetStatusLine());
[email protected]19ec8a72010-08-23 03:38:233223
3224 // Verify the pushed stream.
wezca1070932016-05-26 20:30:523225 EXPECT_TRUE(response2.headers);
bnccdc749f2016-01-27 16:39:043226 EXPECT_EQ("HTTP/1.1 200", response2.headers->GetStatusLine());
[email protected]19ec8a72010-08-23 03:38:233227}
3228
morlovichab1d1c1e2017-02-07 19:59:283229TEST_F(SpdyNetworkTransactionTest, ServerPushInvalidUrl) {
Bence Békyeacd48f2018-05-14 11:34:333230 base::HistogramTester histogram_tester;
3231
morlovichab1d1c1e2017-02-07 19:59:283232 // Coverage on how a non-empty invalid GURL in a PUSH_PROMISE is handled.
Bence Béky4c325e52020-10-22 20:48:013233 spdy::Http2HeaderBlock headers(
Ryan Hamilton0239aac2018-05-19 00:03:133234 spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
3235 spdy::SpdySerializedFrame req(
morlovichab1d1c1e2017-02-07 19:59:283236 spdy_util_.ConstructSpdyHeaders(1, std::move(headers), LOWEST, true));
3237
3238 // Can't use ConstructSpdyPush here since it wants to parse a URL and
3239 // split it into the appropriate :header pieces. So we have to hand-fill
3240 // those pieces in.
Bence Béky4c325e52020-10-22 20:48:013241 spdy::Http2HeaderBlock push_promise_header_block;
Ryan Hamilton0239aac2018-05-19 00:03:133242 push_promise_header_block[spdy::kHttp2AuthorityHeader] = "";
3243 push_promise_header_block[spdy::kHttp2SchemeHeader] = "";
3244 push_promise_header_block[spdy::kHttp2PathHeader] = "/index.html";
morlovichab1d1c1e2017-02-07 19:59:283245
Ryan Hamilton0239aac2018-05-19 00:03:133246 spdy::SpdySerializedFrame push_promise(spdy_util_.ConstructSpdyPushPromise(
Bence Békyf1d78522018-01-11 01:16:503247 1, 2, std::move(push_promise_header_block)));
morlovichab1d1c1e2017-02-07 19:59:283248
Ryan Hamilton0239aac2018-05-19 00:03:133249 spdy::SpdySerializedFrame stream2_rst(
3250 spdy_util_.ConstructSpdyRstStream(2, spdy::ERROR_CODE_REFUSED_STREAM));
morlovichab1d1c1e2017-02-07 19:59:283251
3252 MockWrite writes[] = {CreateMockWrite(req, 0),
3253 CreateMockWrite(stream2_rst, 2)};
3254 MockRead reads[] = {
Bence Békyf1d78522018-01-11 01:16:503255 CreateMockRead(push_promise, 1), MockRead(ASYNC, 0, 3) /* EOF */
morlovichab1d1c1e2017-02-07 19:59:283256 };
Ryan Sleevib8d7ea02018-05-07 20:01:013257 SequencedSocketData data(reads, writes);
morlovichab1d1c1e2017-02-07 19:59:283258 RunBrokenPushTest(&data, ERR_CONNECTION_CLOSED);
Bence Békyeacd48f2018-05-14 11:34:333259
3260 histogram_tester.ExpectBucketCount(
3261 "Net.SpdyPushedStreamFate",
3262 static_cast<int>(SpdyPushedStreamFate::kInvalidUrl), 1);
3263 histogram_tester.ExpectTotalCount("Net.SpdyPushedStreamFate", 1);
morlovichab1d1c1e2017-02-07 19:59:283264}
3265
bncd16676a2016-07-20 16:23:013266TEST_F(SpdyNetworkTransactionTest, ServerPushInvalidAssociatedStreamID0) {
Ryan Hamilton0239aac2018-05-19 00:03:133267 spdy::SpdySerializedFrame stream1_syn(
Bence Béky27ad0a12018-02-08 00:35:483268 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
Ryan Hamilton0239aac2018-05-19 00:03:133269 spdy::SpdySerializedFrame goaway(
3270 spdy_util_.ConstructSpdyGoAway(0, spdy::ERROR_CODE_PROTOCOL_ERROR,
3271 "Framer error: 1 (INVALID_STREAM_ID)."));
[email protected]19ec8a72010-08-23 03:38:233272 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:413273 CreateMockWrite(stream1_syn, 0), CreateMockWrite(goaway, 3),
[email protected]19ec8a72010-08-23 03:38:233274 };
3275
Ryan Hamilton0239aac2018-05-19 00:03:133276 spdy::SpdySerializedFrame stream1_reply(
tombergan5d22c182017-01-11 02:05:353277 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
Ryan Hamilton0239aac2018-05-19 00:03:133278 spdy::SpdySerializedFrame stream2_syn(
Bence Békyd2df6c1c82018-04-20 22:52:013279 spdy_util_.ConstructSpdyPush(nullptr, 0, 2, 0, kPushedUrl));
[email protected]19ec8a72010-08-23 03:38:233280 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:413281 CreateMockRead(stream1_reply, 1), CreateMockRead(stream2_syn, 2),
[email protected]19ec8a72010-08-23 03:38:233282 };
Ryan Sleevib8d7ea02018-05-07 20:01:013283 SequencedSocketData data(reads, writes);
morlovichab1d1c1e2017-02-07 19:59:283284 RunBrokenPushTest(&data, OK);
[email protected]e3ebba0f2010-08-05 17:59:583285}
3286
bncd16676a2016-07-20 16:23:013287TEST_F(SpdyNetworkTransactionTest, ServerPushInvalidAssociatedStreamID9) {
Bence Békyeacd48f2018-05-14 11:34:333288 base::HistogramTester histogram_tester;
3289
Ryan Hamilton0239aac2018-05-19 00:03:133290 spdy::SpdySerializedFrame stream1_syn(
Bence Béky27ad0a12018-02-08 00:35:483291 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
Ryan Hamilton0239aac2018-05-19 00:03:133292 spdy::SpdySerializedFrame stream1_body(
3293 spdy_util_.ConstructSpdyDataFrame(1, true));
3294 spdy::SpdySerializedFrame stream2_rst(
3295 spdy_util_.ConstructSpdyRstStream(2, spdy::ERROR_CODE_STREAM_CLOSED));
[email protected]e3ebba0f2010-08-05 17:59:583296 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:413297 CreateMockWrite(stream1_syn, 0), CreateMockWrite(stream2_rst, 3),
[email protected]e3ebba0f2010-08-05 17:59:583298 };
3299
Ryan Hamilton0239aac2018-05-19 00:03:133300 spdy::SpdySerializedFrame stream1_reply(
tombergan5d22c182017-01-11 02:05:353301 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
Ryan Hamilton0239aac2018-05-19 00:03:133302 spdy::SpdySerializedFrame stream2_syn(
Bence Békyd2df6c1c82018-04-20 22:52:013303 spdy_util_.ConstructSpdyPush(nullptr, 0, 2, 9, kPushedUrl));
[email protected]e3ebba0f2010-08-05 17:59:583304 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:413305 CreateMockRead(stream1_reply, 1), CreateMockRead(stream2_syn, 2),
3306 CreateMockRead(stream1_body, 4),
rch08e3aa3e2015-05-16 14:27:523307 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 5), // Force a pause
[email protected]e3ebba0f2010-08-05 17:59:583308 };
3309
Ryan Sleevib8d7ea02018-05-07 20:01:013310 SequencedSocketData data(reads, writes);
morlovichab1d1c1e2017-02-07 19:59:283311 RunBrokenPushTest(&data, OK);
Bence Békyeacd48f2018-05-14 11:34:333312
3313 histogram_tester.ExpectBucketCount(
3314 "Net.SpdyPushedStreamFate",
3315 static_cast<int>(SpdyPushedStreamFate::kInactiveAssociatedStream), 1);
3316 histogram_tester.ExpectTotalCount("Net.SpdyPushedStreamFate", 1);
[email protected]e3ebba0f2010-08-05 17:59:583317}
3318
bncd16676a2016-07-20 16:23:013319TEST_F(SpdyNetworkTransactionTest, ServerPushNoURL) {
Bence Békyeacd48f2018-05-14 11:34:333320 base::HistogramTester histogram_tester;
3321
Ryan Hamilton0239aac2018-05-19 00:03:133322 spdy::SpdySerializedFrame stream1_syn(
Bence Béky27ad0a12018-02-08 00:35:483323 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
Ryan Hamilton0239aac2018-05-19 00:03:133324 spdy::SpdySerializedFrame stream1_body(
3325 spdy_util_.ConstructSpdyDataFrame(1, true));
3326 spdy::SpdySerializedFrame stream2_rst(
3327 spdy_util_.ConstructSpdyRstStream(2, spdy::ERROR_CODE_REFUSED_STREAM));
[email protected]e3ebba0f2010-08-05 17:59:583328 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:413329 CreateMockWrite(stream1_syn, 0), CreateMockWrite(stream2_rst, 3),
[email protected]e3ebba0f2010-08-05 17:59:583330 };
3331
Ryan Hamilton0239aac2018-05-19 00:03:133332 spdy::SpdySerializedFrame stream1_reply(
tombergan5d22c182017-01-11 02:05:353333 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
Bence Béky4c325e52020-10-22 20:48:013334 spdy::Http2HeaderBlock incomplete_headers;
Ryan Hamilton0239aac2018-05-19 00:03:133335 incomplete_headers[spdy::kHttp2StatusHeader] = "200 OK";
bnc086b39e12016-06-24 13:05:263336 incomplete_headers["hello"] = "bye";
Ryan Hamilton0239aac2018-05-19 00:03:133337 spdy::SpdySerializedFrame stream2_syn(
Bence Békyf1d78522018-01-11 01:16:503338 spdy_util_.ConstructSpdyPushPromise(1, 2, std::move(incomplete_headers)));
[email protected]e3ebba0f2010-08-05 17:59:583339 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:413340 CreateMockRead(stream1_reply, 1), CreateMockRead(stream2_syn, 2),
3341 CreateMockRead(stream1_body, 4),
rch08e3aa3e2015-05-16 14:27:523342 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 5) // Force a pause
[email protected]e3ebba0f2010-08-05 17:59:583343 };
3344
Ryan Sleevib8d7ea02018-05-07 20:01:013345 SequencedSocketData data(reads, writes);
morlovichab1d1c1e2017-02-07 19:59:283346 RunBrokenPushTest(&data, OK);
Bence Békyeacd48f2018-05-14 11:34:333347
3348 histogram_tester.ExpectBucketCount(
3349 "Net.SpdyPushedStreamFate",
3350 static_cast<int>(SpdyPushedStreamFate::kInvalidUrl), 1);
3351 histogram_tester.ExpectTotalCount("Net.SpdyPushedStreamFate", 1);
[email protected]e3ebba0f2010-08-05 17:59:583352}
3353
bnc0cb98b22016-03-04 17:10:523354// PUSH_PROMISE on a server-initiated stream should trigger GOAWAY.
bncd16676a2016-07-20 16:23:013355TEST_F(SpdyNetworkTransactionTest, ServerPushOnPushedStream) {
Bence Békyeacd48f2018-05-14 11:34:333356 base::HistogramTester histogram_tester;
3357
Ryan Hamilton0239aac2018-05-19 00:03:133358 spdy::SpdySerializedFrame stream1_syn(
Bence Béky27ad0a12018-02-08 00:35:483359 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
Ryan Hamilton0239aac2018-05-19 00:03:133360 spdy::SpdySerializedFrame stream2_priority(
tombergan5d22c182017-01-11 02:05:353361 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true));
Ryan Hamilton0239aac2018-05-19 00:03:133362 spdy::SpdySerializedFrame goaway(spdy_util_.ConstructSpdyGoAway(
3363 2, spdy::ERROR_CODE_PROTOCOL_ERROR,
Bence Béky602c40c2017-07-26 05:22:563364 "Received pushed stream id 4 on invalid stream id 2 (must be odd)."));
bnc0cb98b22016-03-04 17:10:523365 MockWrite writes[] = {
tombergan5d22c182017-01-11 02:05:353366 CreateMockWrite(stream1_syn, 0), CreateMockWrite(stream2_priority, 3),
3367 CreateMockWrite(goaway, 5),
bnc0cb98b22016-03-04 17:10:523368 };
3369
Ryan Hamilton0239aac2018-05-19 00:03:133370 spdy::SpdySerializedFrame stream1_reply(
tombergan5d22c182017-01-11 02:05:353371 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
Ryan Hamilton0239aac2018-05-19 00:03:133372 spdy::SpdySerializedFrame stream2_syn(
Bence Békyd2df6c1c82018-04-20 22:52:013373 spdy_util_.ConstructSpdyPush(nullptr, 0, 2, 1, kPushedUrl));
Ryan Hamilton0239aac2018-05-19 00:03:133374 spdy::SpdySerializedFrame stream3_syn(spdy_util_.ConstructSpdyPush(
Bence Béky3e01b532018-02-06 23:04:513375 nullptr, 0, 4, 2, "https://www.example.org/bar.dat"));
bnc0cb98b22016-03-04 17:10:523376 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:413377 CreateMockRead(stream1_reply, 1), CreateMockRead(stream2_syn, 2),
tombergan5d22c182017-01-11 02:05:353378 CreateMockRead(stream3_syn, 4),
bnc0cb98b22016-03-04 17:10:523379 };
3380
Ryan Sleevib8d7ea02018-05-07 20:01:013381 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:103382 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
bnc0cb98b22016-03-04 17:10:523383 helper.RunToCompletion(&data);
Bence Békyeacd48f2018-05-14 11:34:333384
3385 histogram_tester.ExpectBucketCount(
3386 "Net.SpdyPushedStreamFate",
3387 static_cast<int>(SpdyPushedStreamFate::kAssociatedStreamIdParityError),
3388 1);
3389 histogram_tester.ExpectTotalCount("Net.SpdyPushedStreamFate", 1);
bnc0cb98b22016-03-04 17:10:523390}
3391
3392// PUSH_PROMISE on a closed client-initiated stream should trigger RST_STREAM.
bncd16676a2016-07-20 16:23:013393TEST_F(SpdyNetworkTransactionTest, ServerPushOnClosedStream) {
Bence Békyeacd48f2018-05-14 11:34:333394 base::HistogramTester histogram_tester;
3395
Ryan Hamilton0239aac2018-05-19 00:03:133396 spdy::SpdySerializedFrame stream1_syn(
Bence Béky27ad0a12018-02-08 00:35:483397 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
Ryan Hamilton0239aac2018-05-19 00:03:133398 spdy::SpdySerializedFrame rst(
3399 spdy_util_.ConstructSpdyRstStream(2, spdy::ERROR_CODE_STREAM_CLOSED));
bnc0cb98b22016-03-04 17:10:523400 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:413401 CreateMockWrite(stream1_syn, 0), CreateMockWrite(rst, 5),
bnc0cb98b22016-03-04 17:10:523402 };
3403
Ryan Hamilton0239aac2018-05-19 00:03:133404 spdy::SpdySerializedFrame stream1_reply(
bnc42331402016-07-25 13:36:153405 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
Ryan Hamilton0239aac2018-05-19 00:03:133406 spdy::SpdySerializedFrame stream1_body(
3407 spdy_util_.ConstructSpdyDataFrame(1, true));
3408 spdy::SpdySerializedFrame stream2_syn(
Bence Békyd2df6c1c82018-04-20 22:52:013409 spdy_util_.ConstructSpdyPush(nullptr, 0, 2, 1, kPushedUrl));
bnc0cb98b22016-03-04 17:10:523410 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:413411 CreateMockRead(stream1_reply, 1), CreateMockRead(stream1_body, 2),
3412 CreateMockRead(stream2_syn, 3), MockRead(SYNCHRONOUS, ERR_IO_PENDING, 4),
bnc0cb98b22016-03-04 17:10:523413 };
3414
Ryan Sleevib8d7ea02018-05-07 20:01:013415 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:103416 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
bnc0cb98b22016-03-04 17:10:523417 helper.RunPreTestSetup();
3418 helper.AddData(&data);
3419
3420 HttpNetworkTransaction* trans = helper.trans();
3421
3422 TestCompletionCallback callback;
Bence Békydb3cf652017-10-10 15:22:103423 int rv = trans->Start(&request_, callback.callback(), log_);
bnc0cb98b22016-03-04 17:10:523424 rv = callback.GetResult(rv);
robpercival214763f2016-07-01 23:27:013425 EXPECT_THAT(rv, IsOk());
bnceb9aa7112017-01-05 01:03:463426
3427 // Finish async network reads/writes.
3428 base::RunLoop().RunUntilIdle();
3429
bnc0cb98b22016-03-04 17:10:523430 HttpResponseInfo response = *trans->GetResponseInfo();
wezca1070932016-05-26 20:30:523431 EXPECT_TRUE(response.headers);
bnc0cb98b22016-03-04 17:10:523432 EXPECT_EQ("HTTP/1.1 200", response.headers->GetStatusLine());
3433
3434 EXPECT_TRUE(data.AllReadDataConsumed());
3435 EXPECT_TRUE(data.AllWriteDataConsumed());
3436 VerifyStreamsClosed(helper);
Bence Békyeacd48f2018-05-14 11:34:333437
3438 histogram_tester.ExpectBucketCount(
3439 "Net.SpdyPushedStreamFate",
3440 static_cast<int>(SpdyPushedStreamFate::kInactiveAssociatedStream), 1);
3441 histogram_tester.ExpectTotalCount("Net.SpdyPushedStreamFate", 1);
bnc0cb98b22016-03-04 17:10:523442}
3443
3444// PUSH_PROMISE on a server-initiated stream should trigger GOAWAY even if
3445// stream is closed.
bncd16676a2016-07-20 16:23:013446TEST_F(SpdyNetworkTransactionTest, ServerPushOnClosedPushedStream) {
Bence Békyeacd48f2018-05-14 11:34:333447 base::HistogramTester histogram_tester;
3448
Ryan Hamilton0239aac2018-05-19 00:03:133449 spdy::SpdySerializedFrame stream1_syn(
Bence Béky27ad0a12018-02-08 00:35:483450 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
Ryan Hamilton0239aac2018-05-19 00:03:133451 spdy::SpdySerializedFrame stream2_priority(
tombergan5d22c182017-01-11 02:05:353452 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true));
Ryan Hamilton0239aac2018-05-19 00:03:133453 spdy::SpdySerializedFrame goaway(spdy_util_.ConstructSpdyGoAway(
3454 2, spdy::ERROR_CODE_PROTOCOL_ERROR,
Bence Béky602c40c2017-07-26 05:22:563455 "Received pushed stream id 4 on invalid stream id 2 (must be odd)."));
Bence Béky7bf94362018-01-10 13:19:363456 MockWrite writes[] = {CreateMockWrite(stream1_syn, 0),
3457 CreateMockWrite(stream2_priority, 3),
3458 CreateMockWrite(goaway, 8)};
bnc0cb98b22016-03-04 17:10:523459
Ryan Hamilton0239aac2018-05-19 00:03:133460 spdy::SpdySerializedFrame stream2_syn(
Bence Békyd2df6c1c82018-04-20 22:52:013461 spdy_util_.ConstructSpdyPush(nullptr, 0, 2, 1, kPushedUrl));
Ryan Hamilton0239aac2018-05-19 00:03:133462 spdy::SpdySerializedFrame stream1_reply(
Bence Béky7bf94362018-01-10 13:19:363463 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
Ryan Hamilton0239aac2018-05-19 00:03:133464 spdy::SpdySerializedFrame stream1_body(
3465 spdy_util_.ConstructSpdyDataFrame(1, true));
bnc0cb98b22016-03-04 17:10:523466 const char kPushedData[] = "pushed";
Ryan Hamilton0239aac2018-05-19 00:03:133467 spdy::SpdySerializedFrame stream2_body(
Bence Békyd74f4382018-02-20 18:26:193468 spdy_util_.ConstructSpdyDataFrame(2, kPushedData, true));
Ryan Hamilton0239aac2018-05-19 00:03:133469 spdy::SpdySerializedFrame stream3_syn(spdy_util_.ConstructSpdyPush(
Bence Béky3e01b532018-02-06 23:04:513470 nullptr, 0, 4, 2, "https://www.example.org/bar.dat"));
bnc0cb98b22016-03-04 17:10:523471
3472 MockRead reads[] = {
Bence Béky7bf94362018-01-10 13:19:363473 CreateMockRead(stream2_syn, 1), CreateMockRead(stream1_reply, 2),
tombergan5d22c182017-01-11 02:05:353474 CreateMockRead(stream1_body, 4), CreateMockRead(stream2_body, 5),
Bence Béky7bf94362018-01-10 13:19:363475 MockRead(ASYNC, ERR_IO_PENDING, 6), CreateMockRead(stream3_syn, 7)};
bnc0cb98b22016-03-04 17:10:523476
Ryan Sleevib8d7ea02018-05-07 20:01:013477 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:103478 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
bnc0cb98b22016-03-04 17:10:523479 helper.RunPreTestSetup();
3480 helper.AddData(&data);
3481
3482 HttpNetworkTransaction* trans1 = helper.trans();
3483 TestCompletionCallback callback1;
Bence Békydb3cf652017-10-10 15:22:103484 int rv = trans1->Start(&request_, callback1.callback(), log_);
bnc0cb98b22016-03-04 17:10:523485 rv = callback1.GetResult(rv);
robpercival214763f2016-07-01 23:27:013486 EXPECT_THAT(rv, IsOk());
bnc0cb98b22016-03-04 17:10:523487 HttpResponseInfo response = *trans1->GetResponseInfo();
wezca1070932016-05-26 20:30:523488 EXPECT_TRUE(response.headers);
bnc0cb98b22016-03-04 17:10:523489 EXPECT_EQ("HTTP/1.1 200", response.headers->GetStatusLine());
3490
bnc691fda62016-08-12 00:43:163491 HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session());
bnc0cb98b22016-03-04 17:10:523492 TestCompletionCallback callback2;
Bence Békydb3cf652017-10-10 15:22:103493 HttpRequestInfo request = CreateGetPushRequest();
3494 rv = trans2.Start(&request, callback2.callback(), log_);
bnc0cb98b22016-03-04 17:10:523495 rv = callback2.GetResult(rv);
robpercival214763f2016-07-01 23:27:013496 EXPECT_THAT(rv, IsOk());
bnc691fda62016-08-12 00:43:163497 response = *trans2.GetResponseInfo();
wezca1070932016-05-26 20:30:523498 EXPECT_TRUE(response.headers);
bnc0cb98b22016-03-04 17:10:523499 EXPECT_EQ("HTTP/1.1 200", response.headers->GetStatusLine());
Bence Béky4e83f492018-05-13 23:14:253500 std::string result;
bnc691fda62016-08-12 00:43:163501 ReadResult(&trans2, &result);
bnc0cb98b22016-03-04 17:10:523502 EXPECT_EQ(kPushedData, result);
3503
3504 data.Resume();
3505 base::RunLoop().RunUntilIdle();
3506
3507 EXPECT_TRUE(data.AllReadDataConsumed());
3508 EXPECT_TRUE(data.AllWriteDataConsumed());
Bence Békyeacd48f2018-05-14 11:34:333509
3510 histogram_tester.ExpectBucketCount(
3511 "Net.SpdyPushedStreamFate",
3512 static_cast<int>(SpdyPushedStreamFate::kAssociatedStreamIdParityError),
3513 1);
3514 histogram_tester.ExpectBucketCount(
3515 "Net.SpdyPushedStreamFate",
3516 static_cast<int>(SpdyPushedStreamFate::kAcceptedNoVary), 1);
3517 histogram_tester.ExpectTotalCount("Net.SpdyPushedStreamFate", 2);
bnc0cb98b22016-03-04 17:10:523518}
3519
Bence Békye8955cf22018-01-02 17:31:293520TEST_F(SpdyNetworkTransactionTest, ServerCancelsPush) {
Ryan Hamilton0239aac2018-05-19 00:03:133521 spdy::SpdySerializedFrame req1(
3522 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
3523 spdy::SpdySerializedFrame priority(
Bence Békye8955cf22018-01-02 17:31:293524 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true));
Bence Béky1a5d8562018-01-05 17:29:283525 spdy_util_.UpdateWithStreamDestruction(1);
Ryan Hamilton0239aac2018-05-19 00:03:133526 spdy::SpdySerializedFrame req2(
3527 spdy_util_.ConstructSpdyGet(kPushedUrl, 3, LOWEST));
Bence Béky1a5d8562018-01-05 17:29:283528 MockWrite writes1[] = {CreateMockWrite(req1, 0), CreateMockWrite(priority, 3),
3529 CreateMockWrite(req2, 6)};
Bence Békye8955cf22018-01-02 17:31:293530
Ryan Hamilton0239aac2018-05-19 00:03:133531 spdy::SpdySerializedFrame reply1(
3532 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
3533 spdy::SpdySerializedFrame push(
Bence Békyd2df6c1c82018-04-20 22:52:013534 spdy_util_.ConstructSpdyPush(nullptr, 0, 2, 1, kPushedUrl));
Ryan Hamilton0239aac2018-05-19 00:03:133535 spdy::SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true));
3536 spdy::SpdySerializedFrame rst(
3537 spdy_util_.ConstructSpdyRstStream(2, spdy::ERROR_CODE_INTERNAL_ERROR));
3538 spdy::SpdySerializedFrame reply2(
3539 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
3540 spdy::SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(3, true));
Bence Béky1a5d8562018-01-05 17:29:283541 MockRead reads1[] = {CreateMockRead(reply1, 1), CreateMockRead(push, 2),
3542 CreateMockRead(body1, 4), CreateMockRead(rst, 5),
3543 CreateMockRead(reply2, 7), CreateMockRead(body2, 8),
3544 MockRead(ASYNC, 0, 9)};
Bence Békye8955cf22018-01-02 17:31:293545
Ryan Sleevib8d7ea02018-05-07 20:01:013546 SequencedSocketData data(reads1, writes1);
Bence Békye8955cf22018-01-02 17:31:293547
3548 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
3549 helper.RunPreTestSetup();
3550 helper.AddData(&data);
3551
Bence Béky1a5d8562018-01-05 17:29:283552 // First request opens up connection.
Bence Békye8955cf22018-01-02 17:31:293553 HttpNetworkTransaction* trans1 = helper.trans();
3554 TestCompletionCallback callback1;
3555 int rv = trans1->Start(&request_, callback1.callback(), log_);
3556 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
3557
3558 // Read until response body arrives. PUSH_PROMISE comes earlier.
3559 rv = callback1.WaitForResult();
3560 EXPECT_THAT(rv, IsOk());
Bence Béky1a5d8562018-01-05 17:29:283561 const HttpResponseInfo* response = trans1->GetResponseInfo();
3562 EXPECT_TRUE(response->headers);
3563 EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
3564 std::string result1;
3565 ReadResult(trans1, &result1);
3566 EXPECT_EQ("hello!", result1);
3567
3568 SpdySessionPool* spdy_session_pool = helper.session()->spdy_session_pool();
3569 SpdySessionKey key(host_port_pair_, ProxyServer::Direct(),
Matt Menke2436b2f2018-12-11 18:07:113570 PRIVACY_MODE_DISABLED,
dalyk51ab46b2019-10-15 15:14:343571 SpdySessionKey::IsProxySession::kFalse, SocketTag(),
Ben Schwartz3ff4dc1e62021-04-27 21:15:233572 NetworkIsolationKey(), SecureDnsPolicy::kAllow);
Bence Béky1a5d8562018-01-05 17:29:283573 base::WeakPtr<SpdySession> spdy_session =
3574 spdy_session_pool->FindAvailableSession(
Bence Békyd885b2b2018-02-03 00:58:313575 key, /* enable_ip_based_pooling = */ true,
3576 /* is_websocket = */ false, log_);
Bence Béky1a5d8562018-01-05 17:29:283577 EXPECT_EQ(1u, num_unclaimed_pushed_streams(spdy_session));
Bence Békye8955cf22018-01-02 17:31:293578
3579 // Create request matching pushed stream.
Bence Békye8955cf22018-01-02 17:31:293580 HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session());
Bence Béky1a5d8562018-01-05 17:29:283581 HttpRequestInfo request2 = CreateGetPushRequest();
Bence Békye8955cf22018-01-02 17:31:293582 TestCompletionCallback callback2;
Bence Béky1a5d8562018-01-05 17:29:283583 rv = trans2.Start(&request2, callback2.callback(), log_);
Bence Békye8955cf22018-01-02 17:31:293584 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
3585
Bence Béky1a5d8562018-01-05 17:29:283586 // Pushed stream is now claimed by second request.
3587 EXPECT_EQ(0u, num_unclaimed_pushed_streams(spdy_session));
3588
3589 // Second request receives RST_STREAM and is retried on the same connection.
Bence Békye8955cf22018-01-02 17:31:293590 rv = callback2.WaitForResult();
Bence Béky1a5d8562018-01-05 17:29:283591 EXPECT_THAT(rv, IsOk());
3592 response = trans2.GetResponseInfo();
3593 EXPECT_TRUE(response->headers);
3594 EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
3595 std::string result2;
3596 ReadResult(&trans2, &result2);
3597 EXPECT_EQ("hello!", result2);
Bence Békye8955cf22018-01-02 17:31:293598
3599 // Read EOF.
3600 base::RunLoop().RunUntilIdle();
3601
Bence Béky1a5d8562018-01-05 17:29:283602 helper.VerifyDataConsumed();
3603}
3604
3605// Regression test for https://crbug.com/776415.
3606// A client-initiated request can only pool to an existing HTTP/2 connection if
3607// the IP address matches. However, a resource can be pushed by the server on a
3608// connection even if the IP address does not match. This test verifies that if
3609// the request binds to such a pushed stream, and after that the server resets
3610// the stream before SpdySession::GetPushedStream() is called, then the retry
3611// (using a client-initiated stream) does not pool to this connection.
3612TEST_F(SpdyNetworkTransactionTest, ServerCancelsCrossOriginPush) {
3613 const char* kUrl1 = "https://www.example.org";
3614 const char* kUrl2 = "https://mail.example.org";
3615
3616 auto resolver = std::make_unique<MockHostResolver>();
3617 resolver->rules()->ClearRules();
3618 resolver->rules()->AddRule("www.example.org", "127.0.0.1");
3619 resolver->rules()->AddRule("mail.example.org", "127.0.0.2");
3620
3621 auto session_deps = std::make_unique<SpdySessionDependencies>();
3622 session_deps->host_resolver = std::move(resolver);
3623 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
3624 std::move(session_deps));
3625
Ryan Hamilton0239aac2018-05-19 00:03:133626 spdy::SpdySerializedFrame req1(spdy_util_.ConstructSpdyGet(kUrl1, 1, LOWEST));
3627 spdy::SpdySerializedFrame priority(
Bence Béky1a5d8562018-01-05 17:29:283628 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true));
3629 MockWrite writes1[] = {CreateMockWrite(req1, 0),
3630 CreateMockWrite(priority, 3)};
3631
Ryan Hamilton0239aac2018-05-19 00:03:133632 spdy::SpdySerializedFrame reply1(
3633 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
3634 spdy::SpdySerializedFrame push(
Bence Béky1a5d8562018-01-05 17:29:283635 spdy_util_.ConstructSpdyPush(nullptr, 0, 2, 1, kUrl2));
Ryan Hamilton0239aac2018-05-19 00:03:133636 spdy::SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true));
3637 spdy::SpdySerializedFrame rst(
3638 spdy_util_.ConstructSpdyRstStream(2, spdy::ERROR_CODE_INTERNAL_ERROR));
Bence Béky1a5d8562018-01-05 17:29:283639 MockRead reads1[] = {
3640 CreateMockRead(reply1, 1), CreateMockRead(push, 2),
3641 CreateMockRead(body1, 4), CreateMockRead(rst, 5),
3642 MockRead(ASYNC, ERR_IO_PENDING, 6), MockRead(ASYNC, 0, 7)};
3643
Ryan Sleevib8d7ea02018-05-07 20:01:013644 SequencedSocketData data1(reads1, writes1);
Bence Béky1a5d8562018-01-05 17:29:283645
3646 SpdyTestUtil spdy_util2;
Ryan Hamilton0239aac2018-05-19 00:03:133647 spdy::SpdySerializedFrame req2(spdy_util2.ConstructSpdyGet(kUrl2, 1, LOWEST));
Bence Béky1a5d8562018-01-05 17:29:283648 MockWrite writes2[] = {CreateMockWrite(req2, 0)};
3649
Ryan Hamilton0239aac2018-05-19 00:03:133650 spdy::SpdySerializedFrame reply2(
3651 spdy_util2.ConstructSpdyGetReply(nullptr, 0, 1));
3652 spdy::SpdySerializedFrame body2(spdy_util2.ConstructSpdyDataFrame(
Bence Békyd74f4382018-02-20 18:26:193653 1, "Response on the second connection.", true));
Bence Béky1a5d8562018-01-05 17:29:283654 MockRead reads2[] = {CreateMockRead(reply2, 1), CreateMockRead(body2, 2),
3655 MockRead(ASYNC, 0, 3)};
3656
Ryan Sleevib8d7ea02018-05-07 20:01:013657 SequencedSocketData data2(reads2, writes2);
Bence Béky1a5d8562018-01-05 17:29:283658
3659 helper.RunPreTestSetup();
3660 helper.AddData(&data1);
3661 helper.AddData(&data2);
3662
3663 // First request opens up connection to www.example.org.
3664 HttpNetworkTransaction* trans1 = helper.trans();
3665 HttpRequestInfo request1;
3666 request1.method = "GET";
3667 request1.url = GURL(kUrl1);
Ramin Halavatib5e433e62018-02-07 07:41:103668 request1.traffic_annotation =
3669 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
Bence Béky1a5d8562018-01-05 17:29:283670 TestCompletionCallback callback1;
3671 int rv = trans1->Start(&request1, callback1.callback(), log_);
3672 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
3673
3674 // Read until response body arrives. PUSH_PROMISE comes earlier.
3675 rv = callback1.WaitForResult();
3676 EXPECT_THAT(rv, IsOk());
3677 const HttpResponseInfo* response = trans1->GetResponseInfo();
3678 EXPECT_TRUE(response->headers);
3679 EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
3680 std::string result1;
3681 ReadResult(trans1, &result1);
3682 EXPECT_EQ("hello!", result1);
3683
3684 SpdySessionPool* spdy_session_pool = helper.session()->spdy_session_pool();
3685 SpdySessionKey key1(HostPortPair::FromURL(GURL(kUrl1)), ProxyServer::Direct(),
Matt Menke2436b2f2018-12-11 18:07:113686 PRIVACY_MODE_DISABLED,
dalyk51ab46b2019-10-15 15:14:343687 SpdySessionKey::IsProxySession::kFalse, SocketTag(),
Ben Schwartz3ff4dc1e62021-04-27 21:15:233688 NetworkIsolationKey(), SecureDnsPolicy::kAllow);
Bence Béky1a5d8562018-01-05 17:29:283689 base::WeakPtr<SpdySession> spdy_session1 =
3690 spdy_session_pool->FindAvailableSession(
Bence Békyd885b2b2018-02-03 00:58:313691 key1, /* enable_ip_based_pooling = */ true,
3692 /* is_websocket = */ false, log_);
Bence Béky1a5d8562018-01-05 17:29:283693 EXPECT_EQ(1u, num_unclaimed_pushed_streams(spdy_session1));
3694
3695 // While cross-origin push for kUrl2 is allowed on spdy_session1,
3696 // a client-initiated request would not pool to this connection,
3697 // because the IP address does not match.
3698 SpdySessionKey key2(HostPortPair::FromURL(GURL(kUrl2)), ProxyServer::Direct(),
Matt Menke2436b2f2018-12-11 18:07:113699 PRIVACY_MODE_DISABLED,
dalyk51ab46b2019-10-15 15:14:343700 SpdySessionKey::IsProxySession::kFalse, SocketTag(),
Ben Schwartz3ff4dc1e62021-04-27 21:15:233701 NetworkIsolationKey(), SecureDnsPolicy::kAllow);
Bence Béky1a5d8562018-01-05 17:29:283702 EXPECT_FALSE(spdy_session_pool->FindAvailableSession(
Bence Békyd885b2b2018-02-03 00:58:313703 key2, /* enable_ip_based_pooling = */ true,
3704 /* is_websocket = */ false, log_));
Bence Béky1a5d8562018-01-05 17:29:283705
3706 // Create request matching pushed stream.
3707 HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session());
3708 HttpRequestInfo request2;
3709 request2.method = "GET";
3710 request2.url = GURL(kUrl2);
Ramin Halavatib5e433e62018-02-07 07:41:103711 request2.traffic_annotation =
3712 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
Bence Béky1a5d8562018-01-05 17:29:283713 TestCompletionCallback callback2;
3714 rv = trans2.Start(&request2, callback2.callback(), log_);
3715 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
3716
3717 // Pushed stream is now claimed by second request.
3718 EXPECT_EQ(0u, num_unclaimed_pushed_streams(spdy_session1));
3719
3720 // Second request receives RST_STREAM and is retried on a new connection.
3721 rv = callback2.WaitForResult();
3722 EXPECT_THAT(rv, IsOk());
3723 response = trans2.GetResponseInfo();
3724 EXPECT_TRUE(response->headers);
3725 EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
3726 std::string result2;
3727 ReadResult(&trans2, &result2);
3728 EXPECT_EQ("Response on the second connection.", result2);
3729
3730 // Make sure that the first connection is still open. This is important in
3731 // order to test that the retry created its own connection (because the IP
3732 // address does not match), instead of using the connection of the cancelled
3733 // pushed stream.
3734 EXPECT_TRUE(spdy_session1);
3735
3736 // Read EOF.
3737 data1.Resume();
3738 base::RunLoop().RunUntilIdle();
3739
3740 helper.VerifyDataConsumed();
Bence Békye8955cf22018-01-02 17:31:293741}
3742
Matt Menke5062be22019-05-01 17:50:243743TEST_F(SpdyNetworkTransactionTest, NoConnectionPoolingOverTunnel) {
3744 // Use port 443 for two reasons: This makes the endpoint is port 443 check in
3745 // NormalSpdyTransactionHelper pass, and this means that the tunnel uses the
3746 // same port as the servers, to further confuse things.
3747 const char kPacString[] = "PROXY myproxy:443";
3748
3749 auto session_deps = std::make_unique<SpdySessionDependencies>(
Nicolas Arciniegad2013f92020-02-07 23:00:563750 ConfiguredProxyResolutionService::CreateFixedFromPacResult(
Matt Menke5062be22019-05-01 17:50:243751 kPacString, TRAFFIC_ANNOTATION_FOR_TESTS));
3752 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
3753 std::move(session_deps));
3754
3755 // Only one request uses the first connection.
3756 spdy::SpdySerializedFrame req1(
3757 spdy_util_.ConstructSpdyGet("https://www.example.org", 1, LOWEST));
3758 MockWrite writes1[] = {
3759 MockWrite(ASYNC, 0,
3760 "CONNECT www.example.org:443 HTTP/1.1\r\n"
3761 "Host: www.example.org:443\r\n"
3762 "Proxy-Connection: keep-alive\r\n\r\n"),
3763 CreateMockWrite(req1, 2),
3764 };
3765
3766 spdy::SpdySerializedFrame resp1(
3767 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
3768 spdy::SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true));
3769 MockRead reads1[] = {MockRead(ASYNC, 1, "HTTP/1.1 200 OK\r\n\r\n"),
3770 CreateMockRead(resp1, 3), CreateMockRead(body1, 4),
3771 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 5)};
3772
3773 MockConnect connect1(ASYNC, OK);
3774 SequencedSocketData data1(connect1, reads1, writes1);
3775
3776 // Run a transaction to completion to set up a SPDY session.
3777 helper.RunToCompletion(&data1);
3778 TransactionHelperResult out = helper.output();
3779 EXPECT_THAT(out.rv, IsOk());
3780 EXPECT_EQ("HTTP/1.1 200", out.status_line);
3781 EXPECT_EQ("hello!", out.response_data);
3782
3783 // A new SPDY session should have been created.
3784 SpdySessionKey key1(HostPortPair("www.example.org", 443),
3785 ProxyServer::FromPacString(kPacString),
3786 PRIVACY_MODE_DISABLED,
dalyk51ab46b2019-10-15 15:14:343787 SpdySessionKey::IsProxySession::kFalse, SocketTag(),
Ben Schwartz3ff4dc1e62021-04-27 21:15:233788 NetworkIsolationKey(), SecureDnsPolicy::kAllow);
Matt Menke5062be22019-05-01 17:50:243789 base::WeakPtr<SpdySession> session1 =
3790 helper.session()->spdy_session_pool()->FindAvailableSession(
Cammie Smith Barnes5191037b72021-03-01 22:06:533791 key1, true /* enable_ip_based_pooling */, false /* is_websocket */,
Matt Menke5062be22019-05-01 17:50:243792 NetLogWithSource());
3793 ASSERT_TRUE(session1);
3794
3795 // The second request uses a second connection.
3796 SpdyTestUtil spdy_util2;
3797 spdy::SpdySerializedFrame req2(
3798 spdy_util2.ConstructSpdyGet("https://example.test", 1, LOWEST));
3799 MockWrite writes2[] = {
3800 MockWrite(ASYNC, 0,
3801 "CONNECT example.test:443 HTTP/1.1\r\n"
3802 "Host: example.test:443\r\n"
3803 "Proxy-Connection: keep-alive\r\n\r\n"),
3804 CreateMockWrite(req2, 2),
3805 };
3806
3807 spdy::SpdySerializedFrame resp2(
3808 spdy_util2.ConstructSpdyGetReply(nullptr, 0, 1));
3809 spdy::SpdySerializedFrame body2(spdy_util2.ConstructSpdyDataFrame(1, true));
3810 MockRead reads2[] = {MockRead(ASYNC, 1, "HTTP/1.1 200 OK\r\n\r\n"),
3811 CreateMockRead(resp2, 3), CreateMockRead(body2, 4),
3812 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 5)};
3813
3814 MockConnect connect2(ASYNC, OK);
3815 SequencedSocketData data2(connect2, reads2, writes2);
3816 helper.AddData(&data2);
3817
3818 HttpRequestInfo request2;
3819 request2.method = "GET";
3820 request2.url = GURL("https://example.test/");
3821 request2.load_flags = 0;
3822 request2.traffic_annotation =
3823 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
3824 auto trans2 = std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY,
3825 helper.session());
3826
3827 TestCompletionCallback callback;
3828 EXPECT_THAT(trans2->Start(&request2, callback.callback(), NetLogWithSource()),
3829 IsError(ERR_IO_PENDING));
3830
3831 // Wait for the second request to get headers. It should create a new H2
3832 // session to do so.
3833 EXPECT_THAT(callback.WaitForResult(), IsOk());
3834
3835 const HttpResponseInfo* response = trans2->GetResponseInfo();
3836 ASSERT_TRUE(response);
3837 ASSERT_TRUE(response->headers);
3838 EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
3839 EXPECT_TRUE(response->was_fetched_via_spdy);
3840 EXPECT_TRUE(response->was_alpn_negotiated);
3841 std::string response_data;
3842 ASSERT_THAT(ReadTransaction(trans2.get(), &response_data), IsOk());
3843 EXPECT_EQ("hello!", response_data);
3844
3845 // Inspect the new session.
dalyk51ab46b2019-10-15 15:14:343846 SpdySessionKey key2(
3847 HostPortPair("example.test", 443), ProxyServer::FromPacString(kPacString),
3848 PRIVACY_MODE_DISABLED, SpdySessionKey::IsProxySession::kFalse,
Ben Schwartz3ff4dc1e62021-04-27 21:15:233849 SocketTag(), NetworkIsolationKey(), SecureDnsPolicy::kAllow);
Matt Menke5062be22019-05-01 17:50:243850 base::WeakPtr<SpdySession> session2 =
3851 helper.session()->spdy_session_pool()->FindAvailableSession(
Cammie Smith Barnes5191037b72021-03-01 22:06:533852 key2, true /* enable_ip_based_pooling */, false /* is_websocket */,
Matt Menke5062be22019-05-01 17:50:243853 NetLogWithSource());
3854 ASSERT_TRUE(session2);
3855 ASSERT_TRUE(session1);
3856 EXPECT_NE(session1.get(), session2.get());
3857}
3858
3859// Check that if a session is found after host resolution, but is closed before
3860// the task to try to use it executes, the request will continue to create a new
3861// socket and use it.
3862TEST_F(SpdyNetworkTransactionTest, ConnectionPoolingSessionClosedBeforeUse) {
3863 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
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 CreateMockWrite(req1, 0),
3870 };
3871
3872 spdy::SpdySerializedFrame resp1(
3873 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
3874 spdy::SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true));
3875 MockRead reads1[] = {CreateMockRead(resp1, 1), CreateMockRead(body1, 2),
3876 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 3)};
3877
3878 MockConnect connect1(ASYNC, OK);
3879 SequencedSocketData data1(connect1, reads1, writes1);
3880
3881 // Run a transaction to completion to set up a SPDY session.
3882 helper.RunToCompletion(&data1);
3883 TransactionHelperResult out = helper.output();
3884 EXPECT_THAT(out.rv, IsOk());
3885 EXPECT_EQ("HTTP/1.1 200", out.status_line);
3886 EXPECT_EQ("hello!", out.response_data);
3887
3888 // A new SPDY session should have been created.
3889 SpdySessionKey key1(HostPortPair("www.example.org", 443),
3890 ProxyServer::Direct(), PRIVACY_MODE_DISABLED,
dalyk51ab46b2019-10-15 15:14:343891 SpdySessionKey::IsProxySession::kFalse, SocketTag(),
Ben Schwartz3ff4dc1e62021-04-27 21:15:233892 NetworkIsolationKey(), SecureDnsPolicy::kAllow);
Matt Menke5062be22019-05-01 17:50:243893 EXPECT_TRUE(helper.session()->spdy_session_pool()->FindAvailableSession(
Cammie Smith Barnes5191037b72021-03-01 22:06:533894 key1, true /* enable_ip_based_pooling */, false /* is_websocket */,
Matt Menke5062be22019-05-01 17:50:243895 NetLogWithSource()));
3896
3897 // The second request uses a second connection.
3898 SpdyTestUtil spdy_util2;
3899 spdy::SpdySerializedFrame req2(
3900 spdy_util2.ConstructSpdyGet("https://example.test", 1, LOWEST));
3901 MockWrite writes2[] = {
3902 CreateMockWrite(req2, 0),
3903 };
3904
3905 spdy::SpdySerializedFrame resp2(
3906 spdy_util2.ConstructSpdyGetReply(nullptr, 0, 1));
3907 spdy::SpdySerializedFrame body2(spdy_util2.ConstructSpdyDataFrame(1, true));
3908 MockRead reads2[] = {CreateMockRead(resp2, 1), CreateMockRead(body2, 2),
3909 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 3)};
3910
3911 MockConnect connect2(ASYNC, OK);
3912 SequencedSocketData data2(connect2, reads2, writes2);
3913 helper.AddData(&data2);
3914
3915 HttpRequestInfo request2;
3916 request2.method = "GET";
3917 request2.url = GURL("https://example.test/");
3918 request2.load_flags = 0;
3919 request2.traffic_annotation =
3920 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
3921 auto trans2 = std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY,
3922 helper.session());
3923
3924 // Set on-demand mode and run the second request to the DNS lookup.
3925 helper.session_deps()->host_resolver->set_ondemand_mode(true);
3926 TestCompletionCallback callback;
3927 EXPECT_THAT(trans2->Start(&request2, callback.callback(), NetLogWithSource()),
3928 IsError(ERR_IO_PENDING));
3929 base::RunLoop().RunUntilIdle();
3930 ASSERT_TRUE(helper.session_deps()->host_resolver->has_pending_requests());
3931
3932 // Resolve the request now, which should create an alias for the SpdySession
3933 // immediately, but the task to use the session for the second request should
3934 // run asynchronously, so it hasn't run yet.
3935 helper.session_deps()->host_resolver->ResolveOnlyRequestNow();
3936 SpdySessionKey key2(HostPortPair("example.test", 443), ProxyServer::Direct(),
3937 PRIVACY_MODE_DISABLED,
dalyk51ab46b2019-10-15 15:14:343938 SpdySessionKey::IsProxySession::kFalse, SocketTag(),
Ben Schwartz3ff4dc1e62021-04-27 21:15:233939 NetworkIsolationKey(), SecureDnsPolicy::kAllow);
Matt Menke5062be22019-05-01 17:50:243940 base::WeakPtr<SpdySession> session1 =
3941 helper.session()->spdy_session_pool()->FindAvailableSession(
Cammie Smith Barnes5191037b72021-03-01 22:06:533942 key2, true /* enable_ip_based_pooling */, false /* is_websocket */,
Matt Menke5062be22019-05-01 17:50:243943 NetLogWithSource());
3944 ASSERT_TRUE(session1);
3945 EXPECT_EQ(key1, session1->spdy_session_key());
3946 // Remove the session before the second request can try to use it.
3947 helper.session()->spdy_session_pool()->CloseAllSessions();
3948
3949 // Wait for the second request to get headers. It should create a new H2
3950 // session to do so.
3951 EXPECT_THAT(callback.WaitForResult(), IsOk());
3952
3953 const HttpResponseInfo* response = trans2->GetResponseInfo();
3954 ASSERT_TRUE(response);
3955 ASSERT_TRUE(response->headers);
3956 EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
3957 EXPECT_TRUE(response->was_fetched_via_spdy);
3958 EXPECT_TRUE(response->was_alpn_negotiated);
3959 std::string response_data;
3960 ASSERT_THAT(ReadTransaction(trans2.get(), &response_data), IsOk());
3961 EXPECT_EQ("hello!", response_data);
3962
3963 // Inspect the new session.
3964 base::WeakPtr<SpdySession> session2 =
3965 helper.session()->spdy_session_pool()->FindAvailableSession(
Cammie Smith Barnes5191037b72021-03-01 22:06:533966 key2, true /* enable_ip_based_pooling */, false /* is_websocket */,
Matt Menke5062be22019-05-01 17:50:243967 NetLogWithSource());
3968 ASSERT_TRUE(session2);
3969 EXPECT_EQ(key2, session2->spdy_session_key());
3970 helper.VerifyDataConsumed();
3971}
3972
3973#if defined(OS_ANDROID)
3974
3975// Test this if two HttpNetworkTransactions try to repurpose the same
3976// SpdySession with two different SocketTags, only one request gets the session,
3977// while the other makes a new SPDY session.
3978TEST_F(SpdyNetworkTransactionTest, ConnectionPoolingMultipleSocketTags) {
3979 const SocketTag kSocketTag1(SocketTag::UNSET_UID, 1);
3980 const SocketTag kSocketTag2(SocketTag::UNSET_UID, 2);
3981 const SocketTag kSocketTag3(SocketTag::UNSET_UID, 3);
3982
3983 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
3984
3985 // The first and third requests use the first connection.
3986 spdy::SpdySerializedFrame req1(
3987 spdy_util_.ConstructSpdyGet("https://www.example.org", 1, LOWEST));
3988 spdy_util_.UpdateWithStreamDestruction(1);
3989 spdy::SpdySerializedFrame req3(
3990 spdy_util_.ConstructSpdyGet("https://example.test/request3", 3, LOWEST));
3991 MockWrite writes1[] = {
3992 CreateMockWrite(req1, 0),
3993 CreateMockWrite(req3, 3),
3994 };
3995
3996 spdy::SpdySerializedFrame resp1(
3997 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
3998 spdy::SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true));
3999 spdy::SpdySerializedFrame resp3(
4000 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
4001 spdy::SpdySerializedFrame body3(spdy_util_.ConstructSpdyDataFrame(3, true));
4002 MockRead reads1[] = {CreateMockRead(resp1, 1), CreateMockRead(body1, 2),
4003 CreateMockRead(resp3, 4), CreateMockRead(body3, 5),
4004 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 6)};
4005
4006 SequencedSocketData data1(MockConnect(ASYNC, OK), reads1, writes1);
4007 helper.AddData(&data1);
4008
4009 // Due to the vagaries of how the socket pools work, in this particular case,
4010 // the second ConnectJob will be cancelled, but only after it tries to start
4011 // connecting. This does not happen in the general case of a bunch of requests
4012 // using the same socket tag.
4013 SequencedSocketData data2(MockConnect(SYNCHRONOUS, ERR_IO_PENDING),
4014 base::span<const MockRead>(),
4015 base::span<const MockWrite>());
4016 helper.AddData(&data2);
4017
4018 // The second request uses a second connection.
4019 SpdyTestUtil spdy_util2;
4020 spdy::SpdySerializedFrame req2(
4021 spdy_util2.ConstructSpdyGet("https://example.test/request2", 1, LOWEST));
4022 MockWrite writes2[] = {
4023 CreateMockWrite(req2, 0),
4024 };
4025
4026 spdy::SpdySerializedFrame resp2(
4027 spdy_util2.ConstructSpdyGetReply(nullptr, 0, 1));
4028 spdy::SpdySerializedFrame body2(spdy_util2.ConstructSpdyDataFrame(1, true));
4029 MockRead reads2[] = {CreateMockRead(resp2, 1), CreateMockRead(body2, 2),
4030 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 3)};
4031
4032 SequencedSocketData data3(MockConnect(ASYNC, OK), reads2, writes2);
4033 helper.AddData(&data3);
4034
4035 // Run a transaction to completion to set up a SPDY session. This can't use
4036 // RunToCompletion(), since it can't call VerifyDataConsumed() yet.
4037 helper.RunPreTestSetup();
4038 helper.RunDefaultTest();
4039 TransactionHelperResult out = helper.output();
4040 EXPECT_THAT(out.rv, IsOk());
4041 EXPECT_EQ("HTTP/1.1 200", out.status_line);
4042 EXPECT_EQ("hello!", out.response_data);
4043
4044 // A new SPDY session should have been created.
4045 SpdySessionKey key1(HostPortPair("www.example.org", 443),
4046 ProxyServer::Direct(), PRIVACY_MODE_DISABLED,
dalyk51ab46b2019-10-15 15:14:344047 SpdySessionKey::IsProxySession::kFalse, SocketTag(),
Ben Schwartz3ff4dc1e62021-04-27 21:15:234048 NetworkIsolationKey(), SecureDnsPolicy::kAllow);
Matt Menke5062be22019-05-01 17:50:244049 EXPECT_TRUE(helper.session()->spdy_session_pool()->FindAvailableSession(
Cammie Smith Barnes5191037b72021-03-01 22:06:534050 key1, true /* enable_ip_based_pooling */, false /* is_websocket */,
Matt Menke5062be22019-05-01 17:50:244051 NetLogWithSource()));
4052
4053 // Set on-demand mode for the next two requests.
4054 helper.session_deps()->host_resolver->set_ondemand_mode(true);
4055
4056 HttpRequestInfo request2;
4057 request2.socket_tag = kSocketTag2;
4058 request2.method = "GET";
4059 request2.url = GURL("https://example.test/request2");
4060 request2.load_flags = 0;
4061 request2.traffic_annotation =
4062 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
4063 auto trans2 = std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY,
4064 helper.session());
4065 TestCompletionCallback callback2;
4066 EXPECT_THAT(
4067 trans2->Start(&request2, callback2.callback(), NetLogWithSource()),
4068 IsError(ERR_IO_PENDING));
4069
4070 HttpRequestInfo request3;
4071 request3.socket_tag = kSocketTag3;
4072 request3.method = "GET";
4073 request3.url = GURL("https://example.test/request3");
4074 request3.load_flags = 0;
4075 request3.traffic_annotation =
4076 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
4077 auto trans3 = std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY,
4078 helper.session());
4079 TestCompletionCallback callback3;
4080 EXPECT_THAT(
4081 trans3->Start(&request3, callback3.callback(), NetLogWithSource()),
4082 IsError(ERR_IO_PENDING));
4083
4084 // Run the message loop until both requests are waiting on the host resolver.
4085 base::RunLoop().RunUntilIdle();
4086 ASSERT_TRUE(helper.session_deps()->host_resolver->has_pending_requests());
4087
4088 // Complete the second requests's DNS lookup now, which should create an alias
4089 // for the SpdySession immediately, but the task to use the session for the
4090 // second request should run asynchronously, so it hasn't run yet.
4091 helper.session_deps()->host_resolver->ResolveNow(2);
4092 SpdySessionKey key2(HostPortPair("example.test", 443), ProxyServer::Direct(),
4093 PRIVACY_MODE_DISABLED,
dalyk51ab46b2019-10-15 15:14:344094 SpdySessionKey::IsProxySession::kFalse, kSocketTag2,
Ben Schwartz3ff4dc1e62021-04-27 21:15:234095 NetworkIsolationKey(), SecureDnsPolicy::kAllow);
Matt Menke5062be22019-05-01 17:50:244096
4097 // Complete the third requests's DNS lookup now, which should hijack the
4098 // SpdySession from the second request.
4099 helper.session_deps()->host_resolver->ResolveNow(3);
4100 SpdySessionKey key3(HostPortPair("example.test", 443), ProxyServer::Direct(),
4101 PRIVACY_MODE_DISABLED,
dalyk51ab46b2019-10-15 15:14:344102 SpdySessionKey::IsProxySession::kFalse, kSocketTag3,
Ben Schwartz3ff4dc1e62021-04-27 21:15:234103 NetworkIsolationKey(), SecureDnsPolicy::kAllow);
Matt Menke5062be22019-05-01 17:50:244104
4105 // Wait for the second request to get headers. It should create a new H2
4106 // session to do so.
4107 EXPECT_THAT(callback2.WaitForResult(), IsOk());
4108
4109 const HttpResponseInfo* response = trans2->GetResponseInfo();
4110 ASSERT_TRUE(response);
4111 ASSERT_TRUE(response->headers);
4112 EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
4113 EXPECT_TRUE(response->was_fetched_via_spdy);
4114 EXPECT_TRUE(response->was_alpn_negotiated);
4115 std::string response_data;
4116 ASSERT_THAT(ReadTransaction(trans2.get(), &response_data), IsOk());
4117 EXPECT_EQ("hello!", response_data);
4118
4119 // Wait for the third request to get headers. It should have reused the first
4120 // session.
4121 EXPECT_THAT(callback3.WaitForResult(), IsOk());
4122
4123 response = trans3->GetResponseInfo();
4124 ASSERT_TRUE(response);
4125 ASSERT_TRUE(response->headers);
4126 EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
4127 EXPECT_TRUE(response->was_fetched_via_spdy);
4128 EXPECT_TRUE(response->was_alpn_negotiated);
4129 ASSERT_THAT(ReadTransaction(trans3.get(), &response_data), IsOk());
4130 EXPECT_EQ("hello!", response_data);
4131
4132 helper.VerifyDataConsumed();
4133}
4134
Cammie Smith Barnes5191037b72021-03-01 22:06:534135TEST_F(SpdyNetworkTransactionTest, SocketTagChangeSessionTagWithDnsAliases) {
4136 SocketTag socket_tag_1(SocketTag::UNSET_UID, 1);
4137 SocketTag socket_tag_2(SocketTag::UNSET_UID, 2);
4138 request_.socket_tag = socket_tag_1;
Cammie Smith Barnes6b93b992021-02-03 21:25:404139
Cammie Smith Barnes5191037b72021-03-01 22:06:534140 std::unique_ptr<SpdySessionDependencies> session_deps =
4141 std::make_unique<SpdySessionDependencies>();
4142 std::unique_ptr<MockCachingHostResolver> host_resolver =
4143 std::make_unique<MockCachingHostResolver>(2 /* cache_invalidation_num */);
4144 session_deps->host_resolver = std::move(host_resolver);
Cammie Smith Barnes6b93b992021-02-03 21:25:404145
Cammie Smith Barnes5191037b72021-03-01 22:06:534146 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
4147 std::move(session_deps));
4148
4149 GURL url = request_.url;
4150 std::vector<std::string> dns_aliases({"alias1", "alias2", "alias3"});
4151 helper.session_deps()->host_resolver->rules()->AddIPLiteralRuleWithDnsAliases(
4152 url.host(), "127.0.0.1", dns_aliases);
4153
Cammie Smith Barnes6b93b992021-02-03 21:25:404154 spdy::SpdySerializedFrame req1(
Cammie Smith Barnes5191037b72021-03-01 22:06:534155 spdy_util_.ConstructSpdyGet(url.spec().c_str(), 1, DEFAULT_PRIORITY));
Cammie Smith Barnes6b93b992021-02-03 21:25:404156 spdy_util_.UpdateWithStreamDestruction(1);
Cammie Smith Barnes5191037b72021-03-01 22:06:534157 spdy::SpdySerializedFrame req2(
4158 spdy_util_.ConstructSpdyGet(url.spec().c_str(), 3, DEFAULT_PRIORITY));
4159 MockWrite writes[] = {
Cammie Smith Barnes6b93b992021-02-03 21:25:404160 CreateMockWrite(req1, 0),
Cammie Smith Barnes5191037b72021-03-01 22:06:534161 CreateMockWrite(req2, 3),
Cammie Smith Barnes6b93b992021-02-03 21:25:404162 };
4163
4164 spdy::SpdySerializedFrame resp1(
4165 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
4166 spdy::SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true));
Cammie Smith Barnes6b93b992021-02-03 21:25:404167 spdy::SpdySerializedFrame resp2(
Cammie Smith Barnes5191037b72021-03-01 22:06:534168 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
4169 spdy::SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(3, true));
4170 MockRead reads[] = {CreateMockRead(resp1, 1), CreateMockRead(body1, 2),
4171 CreateMockRead(resp2, 4), CreateMockRead(body2, 5),
4172 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 6)};
Cammie Smith Barnes6b93b992021-02-03 21:25:404173
Cammie Smith Barnes5191037b72021-03-01 22:06:534174 SequencedSocketData data(MockConnect(ASYNC, OK), reads, writes);
4175 helper.AddData(&data);
Cammie Smith Barnes6b93b992021-02-03 21:25:404176
4177 // Run a transaction to completion to set up a SPDY session. This can't use
Cammie Smith Barnes5191037b72021-03-01 22:06:534178 // RunToCompletion(), since it can't call VerifyDataConsumed() yet because
4179 // there are still further requests expected.
Cammie Smith Barnes6b93b992021-02-03 21:25:404180 helper.RunPreTestSetup();
4181 helper.RunDefaultTest();
4182 TransactionHelperResult out = helper.output();
4183 EXPECT_THAT(out.rv, IsOk());
4184 EXPECT_EQ("HTTP/1.1 200", out.status_line);
4185 EXPECT_EQ("hello!", out.response_data);
4186
4187 // A new SPDY session should have been created.
Cammie Smith Barnes5191037b72021-03-01 22:06:534188 EXPECT_EQ(1u, helper.GetSpdySessionCount());
4189 SpdySessionKey key1(HostPortPair(url.host(), 443), ProxyServer::Direct(),
4190 PRIVACY_MODE_DISABLED,
4191 SpdySessionKey::IsProxySession::kFalse, socket_tag_1,
Ben Schwartz3ff4dc1e62021-04-27 21:15:234192 NetworkIsolationKey(), SecureDnsPolicy::kAllow);
Cammie Smith Barnes6b93b992021-02-03 21:25:404193 EXPECT_TRUE(helper.session()->spdy_session_pool()->FindAvailableSession(
Cammie Smith Barnes5191037b72021-03-01 22:06:534194 key1, true /* enable_ip_based_pooling */, false /* is_websocket */,
Cammie Smith Barnes6b93b992021-02-03 21:25:404195 NetLogWithSource()));
Cammie Smith Barnes5191037b72021-03-01 22:06:534196 EXPECT_EQ(
4197 dns_aliases,
4198 helper.session()->spdy_session_pool()->GetDnsAliasesForSessionKey(key1));
Cammie Smith Barnes6b93b992021-02-03 21:25:404199
Cammie Smith Barnes5191037b72021-03-01 22:06:534200 // Clear host resolver rules to ensure that cached values for DNS aliases
4201 // are used.
4202 helper.session_deps()->host_resolver->rules()->ClearRules();
Cammie Smith Barnes6b93b992021-02-03 21:25:404203
4204 HttpRequestInfo request2;
Cammie Smith Barnes5191037b72021-03-01 22:06:534205 request2.socket_tag = socket_tag_2;
Cammie Smith Barnes6b93b992021-02-03 21:25:404206 request2.method = "GET";
Cammie Smith Barnes5191037b72021-03-01 22:06:534207 request2.url = url;
Cammie Smith Barnes6b93b992021-02-03 21:25:404208 request2.load_flags = 0;
4209 request2.traffic_annotation =
4210 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
Cammie Smith Barnes5191037b72021-03-01 22:06:534211 SpdySessionKey key2(HostPortPair(url.host(), 443), ProxyServer::Direct(),
4212 PRIVACY_MODE_DISABLED,
4213 SpdySessionKey::IsProxySession::kFalse, socket_tag_2,
Ben Schwartz3ff4dc1e62021-04-27 21:15:234214 NetworkIsolationKey(), SecureDnsPolicy::kAllow);
Cammie Smith Barnes6b93b992021-02-03 21:25:404215 auto trans2 = std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY,
4216 helper.session());
4217 TestCompletionCallback callback2;
4218 EXPECT_THAT(
4219 trans2->Start(&request2, callback2.callback(), NetLogWithSource()),
4220 IsError(ERR_IO_PENDING));
4221
Cammie Smith Barnes5191037b72021-03-01 22:06:534222 // Wait for the second request to get headers. It should have reused the
4223 // first session but changed the tag.
Cammie Smith Barnes6b93b992021-02-03 21:25:404224 EXPECT_THAT(callback2.WaitForResult(), IsOk());
4225
Cammie Smith Barnes5191037b72021-03-01 22:06:534226 EXPECT_EQ(1u, helper.GetSpdySessionCount());
4227 EXPECT_FALSE(helper.session()->spdy_session_pool()->FindAvailableSession(
4228 key1, true /* enable_ip_based_pooling */, false /* is_websocket */,
4229 NetLogWithSource()));
4230 EXPECT_TRUE(helper.session()
4231 ->spdy_session_pool()
4232 ->GetDnsAliasesForSessionKey(key1)
4233 .empty());
4234 EXPECT_TRUE(helper.session()->spdy_session_pool()->FindAvailableSession(
4235 key2, true /* enable_ip_based_pooling */, false /* is_websocket */,
4236 NetLogWithSource()));
4237 EXPECT_EQ(
4238 dns_aliases,
4239 helper.session()->spdy_session_pool()->GetDnsAliasesForSessionKey(key2));
4240
Cammie Smith Barnes6b93b992021-02-03 21:25:404241 const HttpResponseInfo* response = trans2->GetResponseInfo();
4242 ASSERT_TRUE(response);
4243 ASSERT_TRUE(response->headers);
4244 EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
4245 EXPECT_TRUE(response->was_fetched_via_spdy);
4246 EXPECT_TRUE(response->was_alpn_negotiated);
4247 std::string response_data;
4248 ASSERT_THAT(ReadTransaction(trans2.get(), &response_data), IsOk());
4249 EXPECT_EQ("hello!", response_data);
4250
Cammie Smith Barnes5191037b72021-03-01 22:06:534251 helper.VerifyDataConsumed();
4252}
4253
4254TEST_F(SpdyNetworkTransactionTest,
4255 SocketTagChangeFromIPAliasedSessionWithDnsAliases) {
4256 SocketTag socket_tag_1(SocketTag::UNSET_UID, 1);
4257 SocketTag socket_tag_2(SocketTag::UNSET_UID, 2);
4258 request_.socket_tag = socket_tag_1;
4259
4260 std::unique_ptr<SpdySessionDependencies> session_deps =
4261 std::make_unique<SpdySessionDependencies>();
4262 std::unique_ptr<MockCachingHostResolver> host_resolver =
4263 std::make_unique<MockCachingHostResolver>(2 /* cache_invalidation_num */);
4264 session_deps->host_resolver = std::move(host_resolver);
4265
4266 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
4267 std::move(session_deps));
4268 GURL url1 = request_.url;
4269 std::vector<std::string> dns_aliases1({"alias1", "alias2", "alias3"});
4270 GURL url2("https://example.test/");
4271 std::vector<std::string> dns_aliases2({"example.net", "example.com"});
4272
4273 helper.session_deps()->host_resolver->rules()->AddIPLiteralRuleWithDnsAliases(
4274 url1.host(), "127.0.0.1", dns_aliases1);
4275 helper.session_deps()->host_resolver->rules()->AddIPLiteralRuleWithDnsAliases(
4276 url2.host(), "127.0.0.1", dns_aliases2);
4277
4278 spdy::SpdySerializedFrame req1(
4279 spdy_util_.ConstructSpdyGet(url1.spec().c_str(), 1, DEFAULT_PRIORITY));
4280 spdy_util_.UpdateWithStreamDestruction(1);
4281 spdy::SpdySerializedFrame req2(
4282 spdy_util_.ConstructSpdyGet(url2.spec().c_str(), 3, DEFAULT_PRIORITY));
4283 spdy_util_.UpdateWithStreamDestruction(3);
4284 spdy::SpdySerializedFrame req3(
4285 spdy_util_.ConstructSpdyGet(url2.spec().c_str(), 5, DEFAULT_PRIORITY));
4286 spdy_util_.UpdateWithStreamDestruction(5);
4287 spdy::SpdySerializedFrame req4(
4288 spdy_util_.ConstructSpdyGet(url1.spec().c_str(), 7, DEFAULT_PRIORITY));
4289 MockWrite writes[] = {
4290 CreateMockWrite(req1, 0),
4291 CreateMockWrite(req2, 3),
4292 CreateMockWrite(req3, 6),
4293 CreateMockWrite(req4, 9),
4294 };
4295
4296 spdy::SpdySerializedFrame resp1(
4297 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
4298 spdy::SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true));
4299 spdy::SpdySerializedFrame resp2(
4300 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
4301 spdy::SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(3, true));
4302 spdy::SpdySerializedFrame resp3(
4303 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 5));
4304 spdy::SpdySerializedFrame body3(spdy_util_.ConstructSpdyDataFrame(5, true));
4305 spdy::SpdySerializedFrame resp4(
4306 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 7));
4307 spdy::SpdySerializedFrame body4(spdy_util_.ConstructSpdyDataFrame(7, true));
4308 MockRead reads[] = {CreateMockRead(resp1, 1),
4309 CreateMockRead(body1, 2),
4310 CreateMockRead(resp2, 4),
4311 CreateMockRead(body2, 5),
4312 CreateMockRead(resp3, 7),
4313 CreateMockRead(body3, 8),
4314 CreateMockRead(resp4, 10),
4315 CreateMockRead(body4, 11),
4316 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 12)};
4317
4318 SequencedSocketData data(MockConnect(ASYNC, OK), reads, writes);
4319 helper.AddData(&data);
4320
4321 // Run a transaction to completion to set up a SPDY session. This can't use
4322 // RunToCompletion(), since it can't call VerifyDataConsumed() yet.
4323 helper.RunPreTestSetup();
4324 helper.RunDefaultTest();
4325 TransactionHelperResult out = helper.output();
4326 EXPECT_THAT(out.rv, IsOk());
4327 EXPECT_EQ("HTTP/1.1 200", out.status_line);
4328 EXPECT_EQ("hello!", out.response_data);
4329
4330 // A new SPDY session should have been created.
4331 EXPECT_EQ(1u, helper.GetSpdySessionCount());
4332 SpdySessionKey key1(HostPortPair(url1.host(), 443), ProxyServer::Direct(),
4333 PRIVACY_MODE_DISABLED,
4334 SpdySessionKey::IsProxySession::kFalse, socket_tag_1,
Ben Schwartz3ff4dc1e62021-04-27 21:15:234335 NetworkIsolationKey(), SecureDnsPolicy::kAllow);
Cammie Smith Barnes5191037b72021-03-01 22:06:534336 EXPECT_TRUE(helper.session()->spdy_session_pool()->FindAvailableSession(
4337 key1, true /* enable_ip_based_pooling */, false /* is_websocket */,
4338 NetLogWithSource()));
4339 EXPECT_EQ(
4340 dns_aliases1,
4341 helper.session()->spdy_session_pool()->GetDnsAliasesForSessionKey(key1));
4342
4343 HttpRequestInfo request2;
4344 request2.socket_tag = socket_tag_1;
4345 request2.method = "GET";
4346 request2.url = url2;
4347 request2.load_flags = 0;
4348 request2.traffic_annotation =
4349 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
4350 SpdySessionKey key2(HostPortPair(url2.host(), 443), ProxyServer::Direct(),
4351 PRIVACY_MODE_DISABLED,
4352 SpdySessionKey::IsProxySession::kFalse, socket_tag_1,
Ben Schwartz3ff4dc1e62021-04-27 21:15:234353 NetworkIsolationKey(), SecureDnsPolicy::kAllow);
Cammie Smith Barnes5191037b72021-03-01 22:06:534354 auto trans2 = std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY,
4355 helper.session());
4356 TestCompletionCallback callback2;
4357 EXPECT_THAT(
4358 trans2->Start(&request2, callback2.callback(), NetLogWithSource()),
4359 IsError(ERR_IO_PENDING));
4360
4361 // Wait for the second request to get headers. It should have reused the
4362 // first session.
4363 EXPECT_THAT(callback2.WaitForResult(), IsOk());
4364
4365 EXPECT_EQ(1u, helper.GetSpdySessionCount());
4366 EXPECT_TRUE(helper.session()->spdy_session_pool()->FindAvailableSession(
4367 key2, true /* enable_ip_based_pooling */, false /* is_websocket */,
4368 NetLogWithSource()));
4369 EXPECT_EQ(
4370 dns_aliases2,
4371 helper.session()->spdy_session_pool()->GetDnsAliasesForSessionKey(key2));
4372
4373 const HttpResponseInfo* response = trans2->GetResponseInfo();
4374 ASSERT_TRUE(response);
4375 ASSERT_TRUE(response->headers);
4376 EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
4377 EXPECT_TRUE(response->was_fetched_via_spdy);
4378 EXPECT_TRUE(response->was_alpn_negotiated);
4379 std::string response_data;
4380 ASSERT_THAT(ReadTransaction(trans2.get(), &response_data), IsOk());
4381 EXPECT_EQ("hello!", response_data);
4382
4383 // Clear host resolver rules to ensure that cached values for DNS aliases
4384 // are used.
4385 helper.session_deps()->host_resolver->rules()->ClearRules();
4386 trans2.reset();
4387
4388 HttpRequestInfo request3;
4389 request3.socket_tag = socket_tag_2;
4390 request3.method = "GET";
4391 request3.url = url2;
4392 request3.load_flags = 0;
4393 request3.traffic_annotation =
4394 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
4395 SpdySessionKey key3(HostPortPair(url2.host(), 443), ProxyServer::Direct(),
4396 PRIVACY_MODE_DISABLED,
4397 SpdySessionKey::IsProxySession::kFalse, socket_tag_2,
Ben Schwartz3ff4dc1e62021-04-27 21:15:234398 NetworkIsolationKey(), SecureDnsPolicy::kAllow);
Cammie Smith Barnes5191037b72021-03-01 22:06:534399 auto trans3 = std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY,
4400 helper.session());
4401 TestCompletionCallback callback3;
4402 EXPECT_THAT(
4403 trans3->Start(&request3, callback3.callback(), NetLogWithSource()),
4404 IsError(ERR_IO_PENDING));
4405
4406 // Wait for the third request to get headers. It should have reused the
4407 // first session but changed the socket tag.
Cammie Smith Barnes6b93b992021-02-03 21:25:404408 EXPECT_THAT(callback3.WaitForResult(), IsOk());
4409
Cammie Smith Barnes5191037b72021-03-01 22:06:534410 EXPECT_EQ(1u, helper.GetSpdySessionCount());
4411 EXPECT_FALSE(helper.session()->spdy_session_pool()->FindAvailableSession(
4412 key2, true /* enable_ip_based_pooling */, false /* is_websocket */,
4413 NetLogWithSource()));
4414 EXPECT_TRUE(helper.session()
4415 ->spdy_session_pool()
4416 ->GetDnsAliasesForSessionKey(key2)
4417 .empty());
4418 EXPECT_TRUE(helper.session()->spdy_session_pool()->FindAvailableSession(
4419 key3, true /* enable_ip_based_pooling */, false /* is_websocket */,
4420 NetLogWithSource()));
4421 EXPECT_EQ(
4422 dns_aliases2,
4423 helper.session()->spdy_session_pool()->GetDnsAliasesForSessionKey(key3));
4424
Cammie Smith Barnes6b93b992021-02-03 21:25:404425 response = trans3->GetResponseInfo();
4426 ASSERT_TRUE(response);
4427 ASSERT_TRUE(response->headers);
4428 EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
4429 EXPECT_TRUE(response->was_fetched_via_spdy);
4430 EXPECT_TRUE(response->was_alpn_negotiated);
4431 ASSERT_THAT(ReadTransaction(trans3.get(), &response_data), IsOk());
4432 EXPECT_EQ("hello!", response_data);
4433
Cammie Smith Barnes5191037b72021-03-01 22:06:534434 trans3.reset();
4435
4436 HttpRequestInfo request4;
4437 request4.socket_tag = socket_tag_2;
4438 request4.method = "GET";
4439 request4.url = url1;
4440 request4.load_flags = 0;
4441 request4.traffic_annotation =
4442 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
4443 SpdySessionKey key4(HostPortPair(url1.host(), 443), ProxyServer::Direct(),
4444 PRIVACY_MODE_DISABLED,
4445 SpdySessionKey::IsProxySession::kFalse, socket_tag_2,
Ben Schwartz3ff4dc1e62021-04-27 21:15:234446 NetworkIsolationKey(), SecureDnsPolicy::kAllow);
Cammie Smith Barnes5191037b72021-03-01 22:06:534447 auto trans4 = std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY,
4448 helper.session());
4449 TestCompletionCallback callback4;
4450 EXPECT_THAT(
4451 trans4->Start(&request4, callback4.callback(), NetLogWithSource()),
4452 IsError(ERR_IO_PENDING));
4453
4454 // Wait for the third request to get headers. It should have reused the
4455 // first session but changed the socket tag.
4456 EXPECT_THAT(callback4.WaitForResult(), IsOk());
4457
4458 EXPECT_EQ(1u, helper.GetSpdySessionCount());
4459 EXPECT_FALSE(helper.session()->spdy_session_pool()->FindAvailableSession(
4460 key1, true /* enable_ip_based_pooling */, false /* is_websocket */,
4461 NetLogWithSource()));
4462 EXPECT_TRUE(helper.session()
4463 ->spdy_session_pool()
4464 ->GetDnsAliasesForSessionKey(key1)
4465 .empty());
4466 EXPECT_TRUE(helper.session()->spdy_session_pool()->FindAvailableSession(
4467 key4, true /* enable_ip_based_pooling */, false /* is_websocket */,
4468 NetLogWithSource()));
4469 EXPECT_EQ(
4470 dns_aliases1,
4471 helper.session()->spdy_session_pool()->GetDnsAliasesForSessionKey(key4));
4472
4473 response = trans4->GetResponseInfo();
4474 ASSERT_TRUE(response);
4475 ASSERT_TRUE(response->headers);
4476 EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
4477 EXPECT_TRUE(response->was_fetched_via_spdy);
4478 EXPECT_TRUE(response->was_alpn_negotiated);
4479 ASSERT_THAT(ReadTransaction(trans4.get(), &response_data), IsOk());
4480 EXPECT_EQ("hello!", response_data);
4481
Cammie Smith Barnes6b93b992021-02-03 21:25:404482 helper.VerifyDataConsumed();
4483}
4484
Matt Menke5062be22019-05-01 17:50:244485#endif // defined(OS_ANDROID)
4486
bncc055fa32017-06-19 13:44:424487// Regression test for https://crbug.com/727653.
4488TEST_F(SpdyNetworkTransactionTest, RejectServerPushWithNoMethod) {
Bence Békyeacd48f2018-05-14 11:34:334489 base::HistogramTester histogram_tester;
4490
Ryan Hamilton0239aac2018-05-19 00:03:134491 spdy::SpdySerializedFrame req(
4492 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
4493 spdy::SpdySerializedFrame rst(
4494 spdy_util_.ConstructSpdyRstStream(2, spdy::ERROR_CODE_REFUSED_STREAM));
bncc055fa32017-06-19 13:44:424495 MockWrite writes[] = {CreateMockWrite(req, 0), CreateMockWrite(rst, 3)};
4496
Ryan Hamilton0239aac2018-05-19 00:03:134497 spdy::SpdySerializedFrame reply(
4498 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
bncc055fa32017-06-19 13:44:424499
Bence Béky4c325e52020-10-22 20:48:014500 spdy::Http2HeaderBlock push_promise_header_block;
Bence Békyd2df6c1c82018-04-20 22:52:014501 spdy_util_.AddUrlToHeaderBlock(kPushedUrl, &push_promise_header_block);
Ryan Hamilton0239aac2018-05-19 00:03:134502 spdy::SpdySerializedFrame push_promise(spdy_util_.ConstructSpdyPushPromise(
Bence Békyf1d78522018-01-11 01:16:504503 1, 2, std::move(push_promise_header_block)));
bncc055fa32017-06-19 13:44:424504
Ryan Hamilton0239aac2018-05-19 00:03:134505 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
Bence Békyf1d78522018-01-11 01:16:504506 MockRead reads[] = {CreateMockRead(reply, 1), CreateMockRead(push_promise, 2),
4507 CreateMockRead(body, 4),
4508 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 5)};
bncc055fa32017-06-19 13:44:424509
Ryan Sleevib8d7ea02018-05-07 20:01:014510 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:104511 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
bncc055fa32017-06-19 13:44:424512 helper.RunToCompletion(&data);
Bence Békyeacd48f2018-05-14 11:34:334513
4514 histogram_tester.ExpectBucketCount(
4515 "Net.SpdyPushedStreamFate",
4516 static_cast<int>(SpdyPushedStreamFate::kInvalidUrl), 1);
4517 histogram_tester.ExpectTotalCount("Net.SpdyPushedStreamFate", 1);
bncc055fa32017-06-19 13:44:424518}
4519
4520// Regression test for https://crbug.com/727653.
4521TEST_F(SpdyNetworkTransactionTest, RejectServerPushWithInvalidMethod) {
Bence Békyeacd48f2018-05-14 11:34:334522 base::HistogramTester histogram_tester;
4523
Ryan Hamilton0239aac2018-05-19 00:03:134524 spdy::SpdySerializedFrame req(
4525 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
4526 spdy::SpdySerializedFrame rst(
4527 spdy_util_.ConstructSpdyRstStream(2, spdy::ERROR_CODE_REFUSED_STREAM));
bncc055fa32017-06-19 13:44:424528 MockWrite writes[] = {CreateMockWrite(req, 0), CreateMockWrite(rst, 3)};
4529
Ryan Hamilton0239aac2018-05-19 00:03:134530 spdy::SpdySerializedFrame reply(
4531 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
bncc055fa32017-06-19 13:44:424532
Bence Béky4c325e52020-10-22 20:48:014533 spdy::Http2HeaderBlock push_promise_header_block;
bncc055fa32017-06-19 13:44:424534 push_promise_header_block[":method"] = "POST";
Bence Békyd2df6c1c82018-04-20 22:52:014535 spdy_util_.AddUrlToHeaderBlock(kPushedUrl, &push_promise_header_block);
Ryan Hamilton0239aac2018-05-19 00:03:134536 spdy::SpdySerializedFrame push_promise(spdy_util_.ConstructSpdyPushPromise(
Bence Békyf1d78522018-01-11 01:16:504537 1, 2, std::move(push_promise_header_block)));
bncc055fa32017-06-19 13:44:424538
Ryan Hamilton0239aac2018-05-19 00:03:134539 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
Bence Békyf1d78522018-01-11 01:16:504540 MockRead reads[] = {CreateMockRead(reply, 1), CreateMockRead(push_promise, 2),
4541 CreateMockRead(body, 4),
4542 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 5)};
bncc055fa32017-06-19 13:44:424543
Ryan Sleevib8d7ea02018-05-07 20:01:014544 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:104545 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
bncc055fa32017-06-19 13:44:424546 helper.RunToCompletion(&data);
Bence Békyeacd48f2018-05-14 11:34:334547
4548 histogram_tester.ExpectBucketCount(
4549 "Net.SpdyPushedStreamFate",
4550 static_cast<int>(SpdyPushedStreamFate::kInvalidUrl), 1);
4551 histogram_tester.ExpectTotalCount("Net.SpdyPushedStreamFate", 1);
bncc055fa32017-06-19 13:44:424552}
4553
bnc42331402016-07-25 13:36:154554// Verify that various response headers parse correctly through the HTTP layer.
4555TEST_F(SpdyNetworkTransactionTest, ResponseHeaders) {
4556 struct ResponseHeadersTests {
Bence Békye5438512017-11-22 23:07:424557 int extra_header_count;
4558 const char* extra_headers[4];
4559 size_t expected_header_count;
Bence Béky4e83f492018-05-13 23:14:254560 base::StringPiece expected_headers[8];
Bence Békye5438512017-11-22 23:07:424561 } test_cases[] = {
4562 // No extra headers.
Yoichi Osato85350eb72020-09-11 02:14:304563 {0, {}, 1, {"hello", "bye"}},
Bence Békye5438512017-11-22 23:07:424564 // Comma-separated header value.
4565 {1,
4566 {"cookie", "val1, val2"},
Yoichi Osato85350eb72020-09-11 02:14:304567 2,
4568 {"hello", "bye", "cookie", "val1, val2"}},
Bence Békye5438512017-11-22 23:07:424569 // Multiple headers are preserved: they are joined with \0 separator in
Bence Béky4c325e52020-10-22 20:48:014570 // spdy::Http2HeaderBlock.AppendValueOrAddHeader(), then split up in
Bence Békye5438512017-11-22 23:07:424571 // HpackEncoder, then joined with \0 separator when
Ryan Hamilton0239aac2018-05-19 00:03:134572 // spdy::HpackDecoderAdapter::ListenerAdapter::OnHeader() calls
Bence Béky4c325e52020-10-22 20:48:014573 // spdy::Http2HeaderBlock.AppendValueOrAddHeader(), then split up again in
Bence Békye5438512017-11-22 23:07:424574 // HttpResponseHeaders.
4575 {2,
4576 {"content-encoding", "val1", "content-encoding", "val2"},
Yoichi Osato85350eb72020-09-11 02:14:304577 3,
4578 {"hello", "bye", "content-encoding", "val1", "content-encoding",
4579 "val2"}},
Bence Békye5438512017-11-22 23:07:424580 // Cookie header is not split up by HttpResponseHeaders.
4581 {2,
4582 {"cookie", "val1", "cookie", "val2"},
Yoichi Osato85350eb72020-09-11 02:14:304583 2,
4584 {"hello", "bye", "cookie", "val1; val2"}}};
bnc7ecc1122015-09-28 13:22:494585
Avi Drissman4365a4782018-12-28 19:26:244586 for (size_t i = 0; i < base::size(test_cases); ++i) {
Bence Békyad9eb1622020-09-17 16:29:174587 SCOPED_TRACE(i);
bncd16676a2016-07-20 16:23:014588 SpdyTestUtil spdy_test_util;
Ryan Hamilton0239aac2018-05-19 00:03:134589 spdy::SpdySerializedFrame req(
Bence Béky27ad0a12018-02-08 00:35:484590 spdy_test_util.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
bncdf80d44fd2016-07-15 20:27:414591 MockWrite writes[] = {CreateMockWrite(req, 0)};
[email protected]8b070372009-11-16 22:01:254592
Ryan Hamilton0239aac2018-05-19 00:03:134593 spdy::SpdySerializedFrame resp(spdy_test_util.ConstructSpdyGetReply(
Bence Békye5438512017-11-22 23:07:424594 test_cases[i].extra_headers, test_cases[i].extra_header_count, 1));
Ryan Hamilton0239aac2018-05-19 00:03:134595 spdy::SpdySerializedFrame body(
4596 spdy_test_util.ConstructSpdyDataFrame(1, true));
[email protected]8b070372009-11-16 22:01:254597 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:414598 CreateMockRead(resp, 1), CreateMockRead(body, 2),
rch08e3aa3e2015-05-16 14:27:524599 MockRead(ASYNC, 0, 3) // EOF
[email protected]8b070372009-11-16 22:01:254600 };
4601
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_,
4604 nullptr);
[email protected]dd54bd82012-07-19 23:44:574605 helper.RunToCompletion(&data);
[email protected]3caf5542010-07-16 15:19:474606 TransactionHelperResult out = helper.output();
4607
robpercival214763f2016-07-01 23:27:014608 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:024609 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]8b070372009-11-16 22:01:254610 EXPECT_EQ("hello!", out.response_data);
4611
4612 scoped_refptr<HttpResponseHeaders> headers = out.response_info.headers;
Bence Békyad9eb1622020-09-17 16:29:174613 ASSERT_TRUE(headers);
4614 EXPECT_EQ("HTTP/1.1 200", headers->GetStatusLine());
olli.raula33c282f2016-01-21 12:12:494615 size_t iter = 0;
Bence Béky4e83f492018-05-13 23:14:254616 std::string name, value;
Bence Békye5438512017-11-22 23:07:424617 size_t expected_header_index = 0;
[email protected]8b070372009-11-16 22:01:254618 while (headers->EnumerateHeaderLines(&iter, &name, &value)) {
Bence Békyad9eb1622020-09-17 16:29:174619 ASSERT_LT(expected_header_index, test_cases[i].expected_header_count);
4620 EXPECT_EQ(name,
4621 test_cases[i].expected_headers[2 * expected_header_index]);
Bence Békye5438512017-11-22 23:07:424622 EXPECT_EQ(value,
Bence Békyad9eb1622020-09-17 16:29:174623 test_cases[i].expected_headers[2 * expected_header_index + 1]);
Bence Békye5438512017-11-22 23:07:424624 ++expected_header_index;
[email protected]8b070372009-11-16 22:01:254625 }
Bence Békyad9eb1622020-09-17 16:29:174626 EXPECT_EQ(expected_header_index, test_cases[i].expected_header_count);
[email protected]3f662f12010-03-25 19:56:124627 }
4628}
4629
bnc42331402016-07-25 13:36:154630// Verify that we don't crash on invalid response headers.
4631TEST_F(SpdyNetworkTransactionTest, InvalidResponseHeaders) {
4632 struct InvalidResponseHeadersTests {
[email protected]e7f75092010-07-01 22:39:134633 int num_headers;
4634 const char* headers[10];
Bence Békyad9eb1622020-09-17 16:29:174635 } test_cases[] = {// Response headers missing status header
4636 {2, {"cookie", "val1", "cookie", "val2", nullptr}},
4637 // Response headers with no headers
4638 {0, {nullptr}}};
[email protected]dd11b932009-11-30 19:39:484639
Avi Drissman4365a4782018-12-28 19:26:244640 for (size_t i = 0; i < base::size(test_cases); ++i) {
Bence Békyad9eb1622020-09-17 16:29:174641 SCOPED_TRACE(i);
bncd16676a2016-07-20 16:23:014642 SpdyTestUtil spdy_test_util;
bnc38dcd392016-02-09 23:19:494643
Ryan Hamilton0239aac2018-05-19 00:03:134644 spdy::SpdySerializedFrame req(
Bence Béky27ad0a12018-02-08 00:35:484645 spdy_test_util.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
Ryan Hamilton0239aac2018-05-19 00:03:134646 spdy::SpdySerializedFrame rst(spdy_test_util.ConstructSpdyRstStream(
4647 1, spdy::ERROR_CODE_PROTOCOL_ERROR));
[email protected]dd11b932009-11-30 19:39:484648 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:414649 CreateMockWrite(req, 0), CreateMockWrite(rst, 2),
[email protected]dd11b932009-11-30 19:39:484650 };
4651
[email protected]745aa9c2014-06-27 02:21:294652 // Construct the reply.
Bence Béky4c325e52020-10-22 20:48:014653 spdy::Http2HeaderBlock reply_headers;
[email protected]745aa9c2014-06-27 02:21:294654 AppendToHeaderBlock(
4655 test_cases[i].headers, test_cases[i].num_headers, &reply_headers);
Ryan Hamilton0239aac2018-05-19 00:03:134656 spdy::SpdySerializedFrame resp(
bnc086b39e12016-06-24 13:05:264657 spdy_test_util.ConstructSpdyReply(1, std::move(reply_headers)));
[email protected]dd11b932009-11-30 19:39:484658 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:414659 CreateMockRead(resp, 1), MockRead(ASYNC, 0, 3) // EOF
[email protected]dd11b932009-11-30 19:39:484660 };
4661
Ryan Sleevib8d7ea02018-05-07 20:01:014662 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:104663 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
4664 nullptr);
[email protected]dd54bd82012-07-19 23:44:574665 helper.RunToCompletion(&data);
[email protected]3caf5542010-07-16 15:19:474666 TransactionHelperResult out = helper.output();
Bence Békyd0d69502019-06-25 19:47:184667 EXPECT_THAT(out.rv, IsError(ERR_HTTP2_PROTOCOL_ERROR));
[email protected]dd11b932009-11-30 19:39:484668 }
4669}
4670
bncd16676a2016-07-20 16:23:014671TEST_F(SpdyNetworkTransactionTest, CorruptFrameSessionError) {
Ryan Hamilton0239aac2018-05-19 00:03:134672 spdy::SpdySerializedFrame req(
4673 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
Zhongyi Shi495af8072020-02-28 04:43:484674 spdy::SpdySerializedFrame goaway(spdy_util_.ConstructSpdyGoAway(
4675 0, spdy::ERROR_CODE_COMPRESSION_ERROR,
4676 "Framer error: 30 (HPACK_TRUNCATED_BLOCK)."));
bncdf80d44fd2016-07-15 20:27:414677 MockWrite writes[] = {CreateMockWrite(req, 0), CreateMockWrite(goaway, 2)};
[email protected]e3352df2014-03-19 05:55:424678
bnc38dcd392016-02-09 23:19:494679 // This is the length field that's too short.
Ryan Hamilton0239aac2018-05-19 00:03:134680 spdy::SpdySerializedFrame reply_wrong_length(
bnc42331402016-07-25 13:36:154681 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
Ryan Hamilton0239aac2018-05-19 00:03:134682 size_t right_size = reply_wrong_length.size() - spdy::kFrameHeaderSize;
bnc38dcd392016-02-09 23:19:494683 size_t wrong_size = right_size - 4;
Ryan Hamilton0239aac2018-05-19 00:03:134684 spdy::test::SetFrameLength(&reply_wrong_length, wrong_size);
bnc38dcd392016-02-09 23:19:494685
[email protected]e3352df2014-03-19 05:55:424686 MockRead reads[] = {
bnc42331402016-07-25 13:36:154687 MockRead(ASYNC, reply_wrong_length.data(), reply_wrong_length.size() - 4,
4688 1),
[email protected]e3352df2014-03-19 05:55:424689 };
4690
Ryan Sleevib8d7ea02018-05-07 20:01:014691 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:104692 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]e3352df2014-03-19 05:55:424693 helper.RunToCompletion(&data);
4694 TransactionHelperResult out = helper.output();
Bence Békyd0d69502019-06-25 19:47:184695 EXPECT_THAT(out.rv, IsError(ERR_HTTP2_COMPRESSION_ERROR));
[email protected]bdd1b222014-06-10 11:08:394696}
4697
bncd16676a2016-07-20 16:23:014698TEST_F(SpdyNetworkTransactionTest, GoAwayOnDecompressionFailure) {
Ryan Hamilton0239aac2018-05-19 00:03:134699 spdy::SpdySerializedFrame req(
4700 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
Zhongyi Shi495af8072020-02-28 04:43:484701 spdy::SpdySerializedFrame goaway(spdy_util_.ConstructSpdyGoAway(
4702 0, spdy::ERROR_CODE_COMPRESSION_ERROR,
4703 "Framer error: 30 (HPACK_TRUNCATED_BLOCK)."));
bncdf80d44fd2016-07-15 20:27:414704 MockWrite writes[] = {CreateMockWrite(req, 0), CreateMockWrite(goaway, 2)};
[email protected]bdd1b222014-06-10 11:08:394705
4706 // Read HEADERS with corrupted payload.
Ryan Hamilton0239aac2018-05-19 00:03:134707 spdy::SpdySerializedFrame resp(
4708 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
bncdf80d44fd2016-07-15 20:27:414709 memset(resp.data() + 12, 0xcf, resp.size() - 12);
4710 MockRead reads[] = {CreateMockRead(resp, 1)};
[email protected]bdd1b222014-06-10 11:08:394711
Ryan Sleevib8d7ea02018-05-07 20:01:014712 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:104713 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]bdd1b222014-06-10 11:08:394714 helper.RunToCompletion(&data);
4715 TransactionHelperResult out = helper.output();
Bence Békyd0d69502019-06-25 19:47:184716 EXPECT_THAT(out.rv, IsError(ERR_HTTP2_COMPRESSION_ERROR));
[email protected]bdd1b222014-06-10 11:08:394717}
4718
bncd16676a2016-07-20 16:23:014719TEST_F(SpdyNetworkTransactionTest, GoAwayOnFrameSizeError) {
Ryan Hamilton0239aac2018-05-19 00:03:134720 spdy::SpdySerializedFrame req(
4721 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
4722 spdy::SpdySerializedFrame goaway(spdy_util_.ConstructSpdyGoAway(
4723 0, spdy::ERROR_CODE_FRAME_SIZE_ERROR,
dahollingsaf3796492016-05-25 19:21:354724 "Framer error: 15 (INVALID_CONTROL_FRAME_SIZE)."));
bncdf80d44fd2016-07-15 20:27:414725 MockWrite writes[] = {CreateMockWrite(req, 0), CreateMockWrite(goaway, 2)};
[email protected]bdd1b222014-06-10 11:08:394726
4727 // Read WINDOW_UPDATE with incorrectly-sized payload.
Ryan Hamilton0239aac2018-05-19 00:03:134728 spdy::SpdySerializedFrame bad_window_update(
[email protected]bdd1b222014-06-10 11:08:394729 spdy_util_.ConstructSpdyWindowUpdate(1, 1));
Ryan Hamilton0239aac2018-05-19 00:03:134730 spdy::test::SetFrameLength(&bad_window_update, bad_window_update.size() - 1);
bncdf80d44fd2016-07-15 20:27:414731 MockRead reads[] = {CreateMockRead(bad_window_update, 1)};
[email protected]bdd1b222014-06-10 11:08:394732
Ryan Sleevib8d7ea02018-05-07 20:01:014733 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:104734 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]bdd1b222014-06-10 11:08:394735 helper.RunToCompletion(&data);
4736 TransactionHelperResult out = helper.output();
Bence Békyd0d69502019-06-25 19:47:184737 EXPECT_THAT(out.rv, IsError(ERR_HTTP2_FRAME_SIZE_ERROR));
[email protected]e3352df2014-03-19 05:55:424738}
4739
[email protected]bf2491a92009-11-29 16:39:484740// Test that we shutdown correctly on write errors.
bncd16676a2016-07-20 16:23:014741TEST_F(SpdyNetworkTransactionTest, WriteError) {
Ryan Hamilton0239aac2018-05-19 00:03:134742 spdy::SpdySerializedFrame req(
4743 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
[email protected]bf2491a92009-11-29 16:39:484744 MockWrite writes[] = {
[email protected]bdd1b222014-06-10 11:08:394745 // We'll write 10 bytes successfully
bncdf80d44fd2016-07-15 20:27:414746 MockWrite(ASYNC, req.data(), 10, 1),
[email protected]bdd1b222014-06-10 11:08:394747 // Followed by ERROR!
[email protected]bdd1b222014-06-10 11:08:394748 MockWrite(ASYNC, ERR_FAILED, 2),
mmenke666a6fea2015-12-19 04:16:334749 // Session drains and attempts to write a GOAWAY: Another ERROR!
4750 MockWrite(ASYNC, ERR_FAILED, 3),
[email protected]bf2491a92009-11-29 16:39:484751 };
4752
mmenke666a6fea2015-12-19 04:16:334753 MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
[email protected]238002d2013-10-17 02:01:404754
Ryan Sleevib8d7ea02018-05-07 20:01:014755 SequencedSocketData data(reads, writes);
[email protected]238002d2013-10-17 02:01:404756
Bence Békydb3cf652017-10-10 15:22:104757 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]238002d2013-10-17 02:01:404758 helper.RunPreTestSetup();
mmenke666a6fea2015-12-19 04:16:334759 helper.AddData(&data);
[email protected]238002d2013-10-17 02:01:404760 EXPECT_TRUE(helper.StartDefaultTest());
[email protected]238002d2013-10-17 02:01:404761 helper.FinishDefaultTest();
rch37de576c2015-05-17 20:28:174762 EXPECT_TRUE(data.AllWriteDataConsumed());
mmenke666a6fea2015-12-19 04:16:334763 EXPECT_TRUE(data.AllReadDataConsumed());
[email protected]3caf5542010-07-16 15:19:474764 TransactionHelperResult out = helper.output();
robpercival214763f2016-07-01 23:27:014765 EXPECT_THAT(out.rv, IsError(ERR_FAILED));
[email protected]bf2491a92009-11-29 16:39:484766}
4767
4768// Test that partial writes work.
bncd16676a2016-07-20 16:23:014769TEST_F(SpdyNetworkTransactionTest, PartialWrite) {
bnc42331402016-07-25 13:36:154770 // Chop the HEADERS frame into 5 chunks.
Ryan Hamilton0239aac2018-05-19 00:03:134771 spdy::SpdySerializedFrame req(
4772 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
[email protected]bf2491a92009-11-29 16:39:484773 const int kChunks = 5;
bnc3f6a8552017-05-17 13:40:344774 std::unique_ptr<MockWrite[]> writes = ChopWriteFrame(req, kChunks);
rch08e3aa3e2015-05-16 14:27:524775 for (int i = 0; i < kChunks; ++i) {
4776 writes[i].sequence_number = i;
4777 }
[email protected]bf2491a92009-11-29 16:39:484778
Ryan Hamilton0239aac2018-05-19 00:03:134779 spdy::SpdySerializedFrame resp(
4780 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
4781 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]bf2491a92009-11-29 16:39:484782 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:414783 CreateMockRead(resp, kChunks), CreateMockRead(body, kChunks + 1),
rch08e3aa3e2015-05-16 14:27:524784 MockRead(ASYNC, 0, kChunks + 2) // EOF
[email protected]bf2491a92009-11-29 16:39:484785 };
4786
Ryan Sleevib8d7ea02018-05-07 20:01:014787 SequencedSocketData data(reads, base::make_span(writes.get(), kChunks));
Bence Békydb3cf652017-10-10 15:22:104788 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]dd54bd82012-07-19 23:44:574789 helper.RunToCompletion(&data);
[email protected]3caf5542010-07-16 15:19:474790 TransactionHelperResult out = helper.output();
robpercival214763f2016-07-01 23:27:014791 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:024792 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]bf2491a92009-11-29 16:39:484793 EXPECT_EQ("hello!", out.response_data);
4794}
4795
[email protected]9e743cd2010-03-16 07:03:534796// Test that the NetLog contains good data for a simple GET request.
bncd16676a2016-07-20 16:23:014797TEST_F(SpdyNetworkTransactionTest, NetLog) {
[email protected]3deb9a52010-11-11 00:24:404798 static const char* const kExtraHeaders[] = {
4799 "user-agent", "Chrome",
4800 };
Ryan Hamilton0239aac2018-05-19 00:03:134801 spdy::SpdySerializedFrame req(
Bence Béky27ad0a12018-02-08 00:35:484802 spdy_util_.ConstructSpdyGet(kExtraHeaders, 1, 1, LOWEST));
bncdf80d44fd2016-07-15 20:27:414803 MockWrite writes[] = {CreateMockWrite(req, 0)};
[email protected]dac358042009-12-18 02:07:484804
Ryan Hamilton0239aac2018-05-19 00:03:134805 spdy::SpdySerializedFrame resp(
4806 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
4807 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]dac358042009-12-18 02:07:484808 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:414809 CreateMockRead(resp, 1), CreateMockRead(body, 2),
rch08e3aa3e2015-05-16 14:27:524810 MockRead(ASYNC, 0, 3) // EOF
[email protected]dac358042009-12-18 02:07:484811 };
4812
Matt Muellerd9342e3a2019-11-26 01:41:144813 RecordingBoundTestNetLog log;
[email protected]dac358042009-12-18 02:07:484814
Ryan Sleevib8d7ea02018-05-07 20:01:014815 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:104816 request_.extra_headers.SetHeader("User-Agent", "Chrome");
4817 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log.bound(),
4818 nullptr);
[email protected]dd54bd82012-07-19 23:44:574819 helper.RunToCompletion(&data);
[email protected]3caf5542010-07-16 15:19:474820 TransactionHelperResult out = helper.output();
robpercival214763f2016-07-01 23:27:014821 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:024822 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]dac358042009-12-18 02:07:484823 EXPECT_EQ("hello!", out.response_data);
4824
[email protected]9e743cd2010-03-16 07:03:534825 // Check that the NetLog was filled reasonably.
[email protected]3caf5542010-07-16 15:19:474826 // This test is intentionally non-specific about the exact ordering of the
4827 // log; instead we just check to make sure that certain events exist, and that
4828 // they are in the right order.
Eric Roman79cc7552019-07-19 02:17:544829 auto entries = log.GetEntries();
[email protected]b2fcd0e2010-12-01 15:19:404830
4831 EXPECT_LT(0u, entries.size());
[email protected]dac358042009-12-18 02:07:484832 int pos = 0;
mikecirone8b85c432016-09-08 19:11:004833 pos = ExpectLogContainsSomewhere(
4834 entries, 0, NetLogEventType::HTTP_TRANSACTION_SEND_REQUEST,
4835 NetLogEventPhase::BEGIN);
4836 pos = ExpectLogContainsSomewhere(
4837 entries, pos + 1, NetLogEventType::HTTP_TRANSACTION_SEND_REQUEST,
4838 NetLogEventPhase::END);
4839 pos = ExpectLogContainsSomewhere(
4840 entries, pos + 1, NetLogEventType::HTTP_TRANSACTION_READ_HEADERS,
4841 NetLogEventPhase::BEGIN);
4842 pos = ExpectLogContainsSomewhere(
4843 entries, pos + 1, NetLogEventType::HTTP_TRANSACTION_READ_HEADERS,
4844 NetLogEventPhase::END);
bnc301745a2015-03-10 03:22:164845 pos = ExpectLogContainsSomewhere(entries, pos + 1,
mikecirone8b85c432016-09-08 19:11:004846 NetLogEventType::HTTP_TRANSACTION_READ_BODY,
4847 NetLogEventPhase::BEGIN);
bnc301745a2015-03-10 03:22:164848 pos = ExpectLogContainsSomewhere(entries, pos + 1,
mikecirone8b85c432016-09-08 19:11:004849 NetLogEventType::HTTP_TRANSACTION_READ_BODY,
4850 NetLogEventPhase::END);
[email protected]3deb9a52010-11-11 00:24:404851
4852 // Check that we logged all the headers correctly
mikecirone8b85c432016-09-08 19:11:004853 pos = ExpectLogContainsSomewhere(entries, 0,
4854 NetLogEventType::HTTP2_SESSION_SEND_HEADERS,
4855 NetLogEventPhase::NONE);
[email protected]3deb9a52010-11-11 00:24:404856
Eric Roman79cc7552019-07-19 02:17:544857 ASSERT_TRUE(entries[pos].HasParams());
4858 auto* header_list = entries[pos].params.FindKey("headers");
Bence Béky66871e32018-12-06 21:11:244859 ASSERT_TRUE(header_list);
4860 ASSERT_TRUE(header_list->is_list());
4861 ASSERT_EQ(5u, header_list->GetList().size());
[email protected]f3da152d2012-06-02 01:00:574862
Bence Béky66871e32018-12-06 21:11:244863 ASSERT_TRUE(header_list->GetList()[0].is_string());
4864 EXPECT_EQ(":method: GET", header_list->GetList()[0].GetString());
4865
4866 ASSERT_TRUE(header_list->GetList()[1].is_string());
4867 EXPECT_EQ(":authority: www.example.org",
4868 header_list->GetList()[1].GetString());
4869
4870 ASSERT_TRUE(header_list->GetList()[2].is_string());
4871 EXPECT_EQ(":scheme: https", header_list->GetList()[2].GetString());
4872
4873 ASSERT_TRUE(header_list->GetList()[3].is_string());
4874 EXPECT_EQ(":path: /", header_list->GetList()[3].GetString());
4875
4876 ASSERT_TRUE(header_list->GetList()[4].is_string());
4877 EXPECT_EQ("user-agent: Chrome", header_list->GetList()[4].GetString());
[email protected]dac358042009-12-18 02:07:484878}
4879
[email protected]79d84222010-02-26 00:01:444880// Since we buffer the IO from the stream to the renderer, this test verifies
4881// that when we read out the maximum amount of data (e.g. we received 50 bytes
4882// on the network, but issued a Read for only 5 of those bytes) that the data
4883// flow still works correctly.
bncd16676a2016-07-20 16:23:014884TEST_F(SpdyNetworkTransactionTest, BufferFull) {
Ryan Hamilton0239aac2018-05-19 00:03:134885 spdy::SpdySerializedFrame req(
4886 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
bncdf80d44fd2016-07-15 20:27:414887 MockWrite writes[] = {CreateMockWrite(req, 0)};
[email protected]79d84222010-02-26 00:01:444888
[email protected]20d005f2010-07-02 19:55:434889 // 2 data frames in a single read.
Ryan Hamilton0239aac2018-05-19 00:03:134890 spdy::SpdySerializedFrame data_frame_1(
Bence Békyd74f4382018-02-20 18:26:194891 spdy_util_.ConstructSpdyDataFrame(1, "goodby", /*fin=*/false));
Ryan Hamilton0239aac2018-05-19 00:03:134892 spdy::SpdySerializedFrame data_frame_2(
Bence Békyd74f4382018-02-20 18:26:194893 spdy_util_.ConstructSpdyDataFrame(1, "e worl", /*fin=*/false));
Ryan Hamilton0239aac2018-05-19 00:03:134894 spdy::SpdySerializedFrame combined_data_frames =
bncef26b602017-06-12 22:08:194895 CombineFrames({&data_frame_1, &data_frame_2});
4896
Ryan Hamilton0239aac2018-05-19 00:03:134897 spdy::SpdySerializedFrame last_frame(
Bence Békyd74f4382018-02-20 18:26:194898 spdy_util_.ConstructSpdyDataFrame(1, "d", /*fin=*/true));
[email protected]79d84222010-02-26 00:01:444899
Ryan Hamilton0239aac2018-05-19 00:03:134900 spdy::SpdySerializedFrame resp(
4901 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
[email protected]79d84222010-02-26 00:01:444902 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:414903 CreateMockRead(resp, 1),
rch32320842015-05-16 15:57:094904 MockRead(ASYNC, ERR_IO_PENDING, 2), // Force a pause
bncef26b602017-06-12 22:08:194905 CreateMockRead(combined_data_frames, 3),
rch32320842015-05-16 15:57:094906 MockRead(ASYNC, ERR_IO_PENDING, 4), // Force a pause
bncdf80d44fd2016-07-15 20:27:414907 CreateMockRead(last_frame, 5),
rch32320842015-05-16 15:57:094908 MockRead(ASYNC, 0, 6) // EOF
[email protected]79d84222010-02-26 00:01:444909 };
4910
Ryan Sleevib8d7ea02018-05-07 20:01:014911 SequencedSocketData data(reads, writes);
[email protected]79d84222010-02-26 00:01:444912
[email protected]49639fa2011-12-20 23:22:414913 TestCompletionCallback callback;
[email protected]79d84222010-02-26 00:01:444914
Bence Békydb3cf652017-10-10 15:22:104915 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]3caf5542010-07-16 15:19:474916 helper.RunPreTestSetup();
[email protected]dd54bd82012-07-19 23:44:574917 helper.AddData(&data);
[email protected]3caf5542010-07-16 15:19:474918 HttpNetworkTransaction* trans = helper.trans();
Bence Békydb3cf652017-10-10 15:22:104919 int rv = trans->Start(&request_, callback.callback(), log_);
robpercival214763f2016-07-01 23:27:014920 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]79d84222010-02-26 00:01:444921
[email protected]3caf5542010-07-16 15:19:474922 TransactionHelperResult out = helper.output();
[email protected]79d84222010-02-26 00:01:444923 out.rv = callback.WaitForResult();
4924 EXPECT_EQ(out.rv, OK);
4925
4926 const HttpResponseInfo* response = trans->GetResponseInfo();
wezca1070932016-05-26 20:30:524927 EXPECT_TRUE(response->headers);
[email protected]79d84222010-02-26 00:01:444928 EXPECT_TRUE(response->was_fetched_via_spdy);
4929 out.status_line = response->headers->GetStatusLine();
4930 out.response_info = *response; // Make a copy so we can verify.
4931
4932 // Read Data
[email protected]49639fa2011-12-20 23:22:414933 TestCompletionCallback read_callback;
[email protected]79d84222010-02-26 00:01:444934
Bence Béky4e83f492018-05-13 23:14:254935 std::string content;
[email protected]79d84222010-02-26 00:01:444936 do {
4937 // Read small chunks at a time.
4938 const int kSmallReadSize = 3;
Victor Costan9c7302b2018-08-27 16:39:444939 scoped_refptr<IOBuffer> buf =
4940 base::MakeRefCounted<IOBuffer>(kSmallReadSize);
[email protected]90499482013-06-01 00:39:504941 rv = trans->Read(buf.get(), kSmallReadSize, read_callback.callback());
bnc301745a2015-03-10 03:22:164942 if (rv == ERR_IO_PENDING) {
mmenkee24011922015-12-17 22:12:594943 data.Resume();
[email protected]79d84222010-02-26 00:01:444944 rv = read_callback.WaitForResult();
4945 }
4946 if (rv > 0) {
4947 content.append(buf->data(), rv);
4948 } else if (rv < 0) {
4949 NOTREACHED();
4950 }
4951 } while (rv > 0);
4952
4953 out.response_data.swap(content);
4954
[email protected]30c942b2010-07-21 16:59:594955 // Flush the MessageLoop while the SpdySessionDependencies (in particular, the
[email protected]8918d282010-03-02 00:57:554956 // MockClientSocketFactory) are still alive.
[email protected]fc9d88472013-08-14 02:31:174957 base::RunLoop().RunUntilIdle();
[email protected]8918d282010-03-02 00:57:554958
[email protected]79d84222010-02-26 00:01:444959 // Verify that we consumed all test data.
[email protected]3caf5542010-07-16 15:19:474960 helper.VerifyDataConsumed();
[email protected]79d84222010-02-26 00:01:444961
robpercival214763f2016-07-01 23:27:014962 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:024963 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]79d84222010-02-26 00:01:444964 EXPECT_EQ("goodbye world", out.response_data);
4965}
4966
[email protected]8918d282010-03-02 00:57:554967// Verify that basic buffering works; when multiple data frames arrive
4968// at the same time, ensure that we don't notify a read completion for
4969// each data frame individually.
bncd16676a2016-07-20 16:23:014970TEST_F(SpdyNetworkTransactionTest, Buffering) {
Ryan Hamilton0239aac2018-05-19 00:03:134971 spdy::SpdySerializedFrame req(
4972 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
bncdf80d44fd2016-07-15 20:27:414973 MockWrite writes[] = {CreateMockWrite(req, 0)};
[email protected]8918d282010-03-02 00:57:554974
4975 // 4 data frames in a single read.
Ryan Hamilton0239aac2018-05-19 00:03:134976 spdy::SpdySerializedFrame data_frame(
Bence Békyd74f4382018-02-20 18:26:194977 spdy_util_.ConstructSpdyDataFrame(1, "message", /*fin=*/false));
Ryan Hamilton0239aac2018-05-19 00:03:134978 spdy::SpdySerializedFrame data_frame_fin(
Bence Békyd74f4382018-02-20 18:26:194979 spdy_util_.ConstructSpdyDataFrame(1, "message", /*fin=*/true));
Ryan Hamilton0239aac2018-05-19 00:03:134980 spdy::SpdySerializedFrame combined_data_frames =
bncef26b602017-06-12 22:08:194981 CombineFrames({&data_frame, &data_frame, &data_frame, &data_frame_fin});
[email protected]8918d282010-03-02 00:57:554982
Ryan Hamilton0239aac2018-05-19 00:03:134983 spdy::SpdySerializedFrame resp(
4984 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
[email protected]8918d282010-03-02 00:57:554985 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:414986 CreateMockRead(resp, 1),
rch32320842015-05-16 15:57:094987 MockRead(ASYNC, ERR_IO_PENDING, 2), // Force a pause
bncef26b602017-06-12 22:08:194988 CreateMockRead(combined_data_frames, 3), MockRead(ASYNC, 0, 4) // EOF
[email protected]8918d282010-03-02 00:57:554989 };
4990
Ryan Sleevib8d7ea02018-05-07 20:01:014991 SequencedSocketData data(reads, writes);
[email protected]8918d282010-03-02 00:57:554992
Bence Békydb3cf652017-10-10 15:22:104993 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]3caf5542010-07-16 15:19:474994 helper.RunPreTestSetup();
[email protected]dd54bd82012-07-19 23:44:574995 helper.AddData(&data);
[email protected]3caf5542010-07-16 15:19:474996 HttpNetworkTransaction* trans = helper.trans();
[email protected]8918d282010-03-02 00:57:554997
[email protected]49639fa2011-12-20 23:22:414998 TestCompletionCallback callback;
Bence Békydb3cf652017-10-10 15:22:104999 int rv = trans->Start(&request_, callback.callback(), log_);
robpercival214763f2016-07-01 23:27:015000 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]8918d282010-03-02 00:57:555001
[email protected]3caf5542010-07-16 15:19:475002 TransactionHelperResult out = helper.output();
[email protected]8918d282010-03-02 00:57:555003 out.rv = callback.WaitForResult();
5004 EXPECT_EQ(out.rv, OK);
5005
5006 const HttpResponseInfo* response = trans->GetResponseInfo();
wezca1070932016-05-26 20:30:525007 EXPECT_TRUE(response->headers);
[email protected]8918d282010-03-02 00:57:555008 EXPECT_TRUE(response->was_fetched_via_spdy);
5009 out.status_line = response->headers->GetStatusLine();
5010 out.response_info = *response; // Make a copy so we can verify.
5011
5012 // Read Data
[email protected]49639fa2011-12-20 23:22:415013 TestCompletionCallback read_callback;
[email protected]8918d282010-03-02 00:57:555014
Bence Béky4e83f492018-05-13 23:14:255015 std::string content;
[email protected]8918d282010-03-02 00:57:555016 int reads_completed = 0;
5017 do {
5018 // Read small chunks at a time.
5019 const int kSmallReadSize = 14;
Victor Costan9c7302b2018-08-27 16:39:445020 scoped_refptr<IOBuffer> buf =
5021 base::MakeRefCounted<IOBuffer>(kSmallReadSize);
[email protected]90499482013-06-01 00:39:505022 rv = trans->Read(buf.get(), kSmallReadSize, read_callback.callback());
bnc301745a2015-03-10 03:22:165023 if (rv == ERR_IO_PENDING) {
mmenkee24011922015-12-17 22:12:595024 data.Resume();
[email protected]8918d282010-03-02 00:57:555025 rv = read_callback.WaitForResult();
5026 }
5027 if (rv > 0) {
5028 EXPECT_EQ(kSmallReadSize, rv);
5029 content.append(buf->data(), rv);
5030 } else if (rv < 0) {
5031 FAIL() << "Unexpected read error: " << rv;
5032 }
5033 reads_completed++;
5034 } while (rv > 0);
5035
5036 EXPECT_EQ(3, reads_completed); // Reads are: 14 bytes, 14 bytes, 0 bytes.
5037
5038 out.response_data.swap(content);
5039
[email protected]30c942b2010-07-21 16:59:595040 // Flush the MessageLoop while the SpdySessionDependencies (in particular, the
[email protected]8918d282010-03-02 00:57:555041 // MockClientSocketFactory) are still alive.
[email protected]fc9d88472013-08-14 02:31:175042 base::RunLoop().RunUntilIdle();
[email protected]8918d282010-03-02 00:57:555043
5044 // Verify that we consumed all test data.
[email protected]3caf5542010-07-16 15:19:475045 helper.VerifyDataConsumed();
[email protected]8918d282010-03-02 00:57:555046
robpercival214763f2016-07-01 23:27:015047 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:025048 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]8918d282010-03-02 00:57:555049 EXPECT_EQ("messagemessagemessagemessage", out.response_data);
5050}
5051
5052// Verify the case where we buffer data but read it after it has been buffered.
bncd16676a2016-07-20 16:23:015053TEST_F(SpdyNetworkTransactionTest, BufferedAll) {
Ryan Hamilton0239aac2018-05-19 00:03:135054 spdy::SpdySerializedFrame req(
5055 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
bncdf80d44fd2016-07-15 20:27:415056 MockWrite writes[] = {CreateMockWrite(req, 0)};
[email protected]8918d282010-03-02 00:57:555057
[email protected]20d005f2010-07-02 19:55:435058 // 5 data frames in a single read.
Ryan Hamilton0239aac2018-05-19 00:03:135059 spdy::SpdySerializedFrame reply(
5060 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
5061 spdy::SpdySerializedFrame data_frame(
Bence Békyd74f4382018-02-20 18:26:195062 spdy_util_.ConstructSpdyDataFrame(1, "message", /*fin=*/false));
Ryan Hamilton0239aac2018-05-19 00:03:135063 spdy::SpdySerializedFrame data_frame_fin(
Bence Békyd74f4382018-02-20 18:26:195064 spdy_util_.ConstructSpdyDataFrame(1, "message", /*fin=*/true));
Ryan Hamilton0239aac2018-05-19 00:03:135065 spdy::SpdySerializedFrame combined_frames = CombineFrames(
bncef26b602017-06-12 22:08:195066 {&reply, &data_frame, &data_frame, &data_frame, &data_frame_fin});
[email protected]8918d282010-03-02 00:57:555067
5068 MockRead reads[] = {
bncef26b602017-06-12 22:08:195069 CreateMockRead(combined_frames, 1), MockRead(ASYNC, 0, 2) // EOF
[email protected]8918d282010-03-02 00:57:555070 };
5071
Ryan Sleevib8d7ea02018-05-07 20:01:015072 SequencedSocketData data(reads, writes);
[email protected]8918d282010-03-02 00:57:555073
Bence Békydb3cf652017-10-10 15:22:105074 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]3caf5542010-07-16 15:19:475075 helper.RunPreTestSetup();
[email protected]dd54bd82012-07-19 23:44:575076 helper.AddData(&data);
[email protected]3caf5542010-07-16 15:19:475077 HttpNetworkTransaction* trans = helper.trans();
[email protected]8918d282010-03-02 00:57:555078
[email protected]49639fa2011-12-20 23:22:415079 TestCompletionCallback callback;
Bence Békydb3cf652017-10-10 15:22:105080 int rv = trans->Start(&request_, callback.callback(), log_);
robpercival214763f2016-07-01 23:27:015081 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]8918d282010-03-02 00:57:555082
[email protected]3caf5542010-07-16 15:19:475083 TransactionHelperResult out = helper.output();
[email protected]8918d282010-03-02 00:57:555084 out.rv = callback.WaitForResult();
5085 EXPECT_EQ(out.rv, OK);
5086
5087 const HttpResponseInfo* response = trans->GetResponseInfo();
wezca1070932016-05-26 20:30:525088 EXPECT_TRUE(response->headers);
[email protected]8918d282010-03-02 00:57:555089 EXPECT_TRUE(response->was_fetched_via_spdy);
5090 out.status_line = response->headers->GetStatusLine();
5091 out.response_info = *response; // Make a copy so we can verify.
5092
5093 // Read Data
[email protected]49639fa2011-12-20 23:22:415094 TestCompletionCallback read_callback;
[email protected]8918d282010-03-02 00:57:555095
Bence Béky4e83f492018-05-13 23:14:255096 std::string content;
[email protected]8918d282010-03-02 00:57:555097 int reads_completed = 0;
5098 do {
5099 // Read small chunks at a time.
5100 const int kSmallReadSize = 14;
Victor Costan9c7302b2018-08-27 16:39:445101 scoped_refptr<IOBuffer> buf =
5102 base::MakeRefCounted<IOBuffer>(kSmallReadSize);
[email protected]90499482013-06-01 00:39:505103 rv = trans->Read(buf.get(), kSmallReadSize, read_callback.callback());
[email protected]8918d282010-03-02 00:57:555104 if (rv > 0) {
5105 EXPECT_EQ(kSmallReadSize, rv);
5106 content.append(buf->data(), rv);
5107 } else if (rv < 0) {
5108 FAIL() << "Unexpected read error: " << rv;
5109 }
5110 reads_completed++;
5111 } while (rv > 0);
5112
5113 EXPECT_EQ(3, reads_completed);
5114
5115 out.response_data.swap(content);
5116
[email protected]30c942b2010-07-21 16:59:595117 // Flush the MessageLoop while the SpdySessionDependencies (in particular, the
[email protected]8918d282010-03-02 00:57:555118 // MockClientSocketFactory) are still alive.
[email protected]fc9d88472013-08-14 02:31:175119 base::RunLoop().RunUntilIdle();
[email protected]8918d282010-03-02 00:57:555120
5121 // Verify that we consumed all test data.
[email protected]3caf5542010-07-16 15:19:475122 helper.VerifyDataConsumed();
[email protected]8918d282010-03-02 00:57:555123
robpercival214763f2016-07-01 23:27:015124 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:025125 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]8918d282010-03-02 00:57:555126 EXPECT_EQ("messagemessagemessagemessage", out.response_data);
5127}
5128
5129// Verify the case where we buffer data and close the connection.
bncd16676a2016-07-20 16:23:015130TEST_F(SpdyNetworkTransactionTest, BufferedClosed) {
Ryan Hamilton0239aac2018-05-19 00:03:135131 spdy::SpdySerializedFrame req(
5132 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
bncdf80d44fd2016-07-15 20:27:415133 MockWrite writes[] = {CreateMockWrite(req, 0)};
[email protected]8918d282010-03-02 00:57:555134
5135 // All data frames in a single read.
[email protected]20d005f2010-07-02 19:55:435136 // NOTE: We don't FIN the stream.
Ryan Hamilton0239aac2018-05-19 00:03:135137 spdy::SpdySerializedFrame data_frame(
Bence Békyd74f4382018-02-20 18:26:195138 spdy_util_.ConstructSpdyDataFrame(1, "message", /*fin=*/false));
Ryan Hamilton0239aac2018-05-19 00:03:135139 spdy::SpdySerializedFrame combined_data_frames =
bncef26b602017-06-12 22:08:195140 CombineFrames({&data_frame, &data_frame, &data_frame, &data_frame});
Ryan Hamilton0239aac2018-05-19 00:03:135141 spdy::SpdySerializedFrame resp(
5142 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
[email protected]8918d282010-03-02 00:57:555143 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:415144 CreateMockRead(resp, 1),
rch32320842015-05-16 15:57:095145 MockRead(ASYNC, ERR_IO_PENDING, 2), // Force a wait
bncef26b602017-06-12 22:08:195146 CreateMockRead(combined_data_frames, 3), MockRead(ASYNC, 0, 4) // EOF
[email protected]8918d282010-03-02 00:57:555147 };
5148
Ryan Sleevib8d7ea02018-05-07 20:01:015149 SequencedSocketData data(reads, writes);
[email protected]8918d282010-03-02 00:57:555150
Bence Békydb3cf652017-10-10 15:22:105151 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]3caf5542010-07-16 15:19:475152 helper.RunPreTestSetup();
[email protected]dd54bd82012-07-19 23:44:575153 helper.AddData(&data);
[email protected]3caf5542010-07-16 15:19:475154 HttpNetworkTransaction* trans = helper.trans();
[email protected]8918d282010-03-02 00:57:555155
[email protected]49639fa2011-12-20 23:22:415156 TestCompletionCallback callback;
[email protected]8918d282010-03-02 00:57:555157
Bence Békydb3cf652017-10-10 15:22:105158 int rv = trans->Start(&request_, callback.callback(), log_);
robpercival214763f2016-07-01 23:27:015159 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]8918d282010-03-02 00:57:555160
[email protected]3caf5542010-07-16 15:19:475161 TransactionHelperResult out = helper.output();
[email protected]8918d282010-03-02 00:57:555162 out.rv = callback.WaitForResult();
5163 EXPECT_EQ(out.rv, OK);
5164
5165 const HttpResponseInfo* response = trans->GetResponseInfo();
wezca1070932016-05-26 20:30:525166 EXPECT_TRUE(response->headers);
[email protected]8918d282010-03-02 00:57:555167 EXPECT_TRUE(response->was_fetched_via_spdy);
5168 out.status_line = response->headers->GetStatusLine();
5169 out.response_info = *response; // Make a copy so we can verify.
5170
5171 // Read Data
[email protected]49639fa2011-12-20 23:22:415172 TestCompletionCallback read_callback;
[email protected]8918d282010-03-02 00:57:555173
Bence Béky4e83f492018-05-13 23:14:255174 std::string content;
[email protected]8918d282010-03-02 00:57:555175 int reads_completed = 0;
5176 do {
5177 // Read small chunks at a time.
5178 const int kSmallReadSize = 14;
Victor Costan9c7302b2018-08-27 16:39:445179 scoped_refptr<IOBuffer> buf =
5180 base::MakeRefCounted<IOBuffer>(kSmallReadSize);
[email protected]90499482013-06-01 00:39:505181 rv = trans->Read(buf.get(), kSmallReadSize, read_callback.callback());
bnc301745a2015-03-10 03:22:165182 if (rv == ERR_IO_PENDING) {
mmenkee24011922015-12-17 22:12:595183 data.Resume();
[email protected]8918d282010-03-02 00:57:555184 rv = read_callback.WaitForResult();
5185 }
5186 if (rv > 0) {
5187 content.append(buf->data(), rv);
5188 } else if (rv < 0) {
5189 // This test intentionally closes the connection, and will get an error.
robpercival214763f2016-07-01 23:27:015190 EXPECT_THAT(rv, IsError(ERR_CONNECTION_CLOSED));
[email protected]8918d282010-03-02 00:57:555191 break;
5192 }
5193 reads_completed++;
5194 } while (rv > 0);
5195
5196 EXPECT_EQ(0, reads_completed);
5197
5198 out.response_data.swap(content);
5199
[email protected]30c942b2010-07-21 16:59:595200 // Flush the MessageLoop while the SpdySessionDependencies (in particular, the
[email protected]8918d282010-03-02 00:57:555201 // MockClientSocketFactory) are still alive.
[email protected]fc9d88472013-08-14 02:31:175202 base::RunLoop().RunUntilIdle();
[email protected]8918d282010-03-02 00:57:555203
5204 // Verify that we consumed all test data.
[email protected]3caf5542010-07-16 15:19:475205 helper.VerifyDataConsumed();
[email protected]8918d282010-03-02 00:57:555206}
5207
[email protected]1ed7b3dc2010-03-04 05:41:455208// Verify the case where we buffer data and cancel the transaction.
bncd16676a2016-07-20 16:23:015209TEST_F(SpdyNetworkTransactionTest, BufferedCancelled) {
Ryan Hamilton0239aac2018-05-19 00:03:135210 spdy::SpdySerializedFrame req(
5211 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
5212 spdy::SpdySerializedFrame rst(
5213 spdy_util_.ConstructSpdyRstStream(1, spdy::ERROR_CODE_CANCEL));
bncdf80d44fd2016-07-15 20:27:415214 MockWrite writes[] = {CreateMockWrite(req, 0), CreateMockWrite(rst, 4)};
[email protected]1ed7b3dc2010-03-04 05:41:455215
[email protected]20d005f2010-07-02 19:55:435216 // NOTE: We don't FIN the stream.
Ryan Hamilton0239aac2018-05-19 00:03:135217 spdy::SpdySerializedFrame data_frame(
Bence Békyd74f4382018-02-20 18:26:195218 spdy_util_.ConstructSpdyDataFrame(1, "message", /*fin=*/false));
[email protected]1ed7b3dc2010-03-04 05:41:455219
Ryan Hamilton0239aac2018-05-19 00:03:135220 spdy::SpdySerializedFrame resp(
5221 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
[email protected]1ed7b3dc2010-03-04 05:41:455222 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:415223 CreateMockRead(resp, 1),
5224 MockRead(ASYNC, ERR_IO_PENDING, 2), // Force a wait
5225 CreateMockRead(data_frame, 3), MockRead(ASYNC, 0, 5) // EOF
[email protected]1ed7b3dc2010-03-04 05:41:455226 };
5227
Ryan Sleevib8d7ea02018-05-07 20:01:015228 SequencedSocketData data(reads, writes);
[email protected]1ed7b3dc2010-03-04 05:41:455229
Bence Békydb3cf652017-10-10 15:22:105230 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]3caf5542010-07-16 15:19:475231 helper.RunPreTestSetup();
[email protected]dd54bd82012-07-19 23:44:575232 helper.AddData(&data);
[email protected]3caf5542010-07-16 15:19:475233 HttpNetworkTransaction* trans = helper.trans();
[email protected]49639fa2011-12-20 23:22:415234 TestCompletionCallback callback;
[email protected]1ed7b3dc2010-03-04 05:41:455235
Bence Békydb3cf652017-10-10 15:22:105236 int rv = trans->Start(&request_, callback.callback(), log_);
robpercival214763f2016-07-01 23:27:015237 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]1ed7b3dc2010-03-04 05:41:455238
[email protected]3caf5542010-07-16 15:19:475239 TransactionHelperResult out = helper.output();
[email protected]1ed7b3dc2010-03-04 05:41:455240 out.rv = callback.WaitForResult();
5241 EXPECT_EQ(out.rv, OK);
5242
5243 const HttpResponseInfo* response = trans->GetResponseInfo();
wezca1070932016-05-26 20:30:525244 EXPECT_TRUE(response->headers);
[email protected]1ed7b3dc2010-03-04 05:41:455245 EXPECT_TRUE(response->was_fetched_via_spdy);
5246 out.status_line = response->headers->GetStatusLine();
5247 out.response_info = *response; // Make a copy so we can verify.
5248
5249 // Read Data
[email protected]49639fa2011-12-20 23:22:415250 TestCompletionCallback read_callback;
[email protected]1ed7b3dc2010-03-04 05:41:455251
[email protected]88c7b4be2014-03-19 23:04:015252 const int kReadSize = 256;
Victor Costan9c7302b2018-08-27 16:39:445253 scoped_refptr<IOBuffer> buf = base::MakeRefCounted<IOBuffer>(kReadSize);
[email protected]88c7b4be2014-03-19 23:04:015254 rv = trans->Read(buf.get(), kReadSize, read_callback.callback());
bnc301745a2015-03-10 03:22:165255 ASSERT_EQ(ERR_IO_PENDING, rv) << "Unexpected read: " << rv;
[email protected]88c7b4be2014-03-19 23:04:015256
5257 // Complete the read now, which causes buffering to start.
mmenkee24011922015-12-17 22:12:595258 data.Resume();
5259 base::RunLoop().RunUntilIdle();
[email protected]88c7b4be2014-03-19 23:04:015260 // Destroy the transaction, causing the stream to get cancelled
5261 // and orphaning the buffered IO task.
5262 helper.ResetTrans();
[email protected]1ed7b3dc2010-03-04 05:41:455263
5264 // Flush the MessageLoop; this will cause the buffered IO task
5265 // to run for the final time.
[email protected]fc9d88472013-08-14 02:31:175266 base::RunLoop().RunUntilIdle();
[email protected]3caf5542010-07-16 15:19:475267
5268 // Verify that we consumed all test data.
5269 helper.VerifyDataConsumed();
[email protected]1ed7b3dc2010-03-04 05:41:455270}
5271
bncc4769d412017-04-19 19:57:545272// Request should fail upon receiving a GOAWAY frame
5273// with Last-Stream-ID lower than the stream id corresponding to the request
5274// and with error code other than NO_ERROR.
5275TEST_F(SpdyNetworkTransactionTest, FailOnGoAway) {
Ryan Hamilton0239aac2018-05-19 00:03:135276 spdy::SpdySerializedFrame req(
5277 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
bncdf80d44fd2016-07-15 20:27:415278 MockWrite writes[] = {CreateMockWrite(req, 0)};
[email protected]69d717bd2010-04-21 18:43:215279
Ryan Hamilton0239aac2018-05-19 00:03:135280 spdy::SpdySerializedFrame go_away(
5281 spdy_util_.ConstructSpdyGoAway(0, spdy::ERROR_CODE_INTERNAL_ERROR, ""));
[email protected]69d717bd2010-04-21 18:43:215282 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:415283 CreateMockRead(go_away, 1),
[email protected]58cebf8f2010-07-31 19:20:165284 };
5285
Ryan Sleevib8d7ea02018-05-07 20:01:015286 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:105287 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]dd54bd82012-07-19 23:44:575288 helper.RunToCompletion(&data);
[email protected]58cebf8f2010-07-31 19:20:165289 TransactionHelperResult out = helper.output();
Matt Menke3b52f9f2020-06-08 20:04:035290 EXPECT_THAT(out.rv, IsError(ERR_HTTP2_PROTOCOL_ERROR));
[email protected]69d717bd2010-04-21 18:43:215291}
5292
bncc4769d412017-04-19 19:57:545293// Request should be retried on a new connection upon receiving a GOAWAY frame
5294// with Last-Stream-ID lower than the stream id corresponding to the request
5295// and with error code NO_ERROR.
5296TEST_F(SpdyNetworkTransactionTest, RetryOnGoAway) {
Bence Békydb3cf652017-10-10 15:22:105297 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
bncc4769d412017-04-19 19:57:545298
5299 // First connection.
Ryan Hamilton0239aac2018-05-19 00:03:135300 spdy::SpdySerializedFrame req(
5301 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
bncc4769d412017-04-19 19:57:545302 MockWrite writes1[] = {CreateMockWrite(req, 0)};
Ryan Hamilton0239aac2018-05-19 00:03:135303 spdy::SpdySerializedFrame go_away(
5304 spdy_util_.ConstructSpdyGoAway(0, spdy::ERROR_CODE_NO_ERROR, ""));
bncc4769d412017-04-19 19:57:545305 MockRead reads1[] = {CreateMockRead(go_away, 1)};
Ryan Sleevib8d7ea02018-05-07 20:01:015306 SequencedSocketData data1(reads1, writes1);
bncc4769d412017-04-19 19:57:545307 helper.AddData(&data1);
5308
5309 // Second connection.
5310 MockWrite writes2[] = {CreateMockWrite(req, 0)};
Ryan Hamilton0239aac2018-05-19 00:03:135311 spdy::SpdySerializedFrame resp(
5312 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
5313 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
bncc4769d412017-04-19 19:57:545314 MockRead reads2[] = {CreateMockRead(resp, 1), CreateMockRead(body, 2),
5315 MockRead(ASYNC, 0, 3)};
Ryan Sleevib8d7ea02018-05-07 20:01:015316 SequencedSocketData data2(reads2, writes2);
bncc4769d412017-04-19 19:57:545317 helper.AddData(&data2);
5318
5319 helper.RunPreTestSetup();
5320 helper.RunDefaultTest();
5321
5322 TransactionHelperResult out = helper.output();
5323 EXPECT_THAT(out.rv, IsOk());
5324
5325 helper.VerifyDataConsumed();
5326}
5327
bnc1fc7b352017-01-12 17:51:025328// A server can gracefully shut down by sending a GOAWAY frame
5329// with maximum last-stream-id value.
5330// Transactions started before receiving such a GOAWAY frame should succeed,
5331// but SpdySession should be unavailable for new streams.
5332TEST_F(SpdyNetworkTransactionTest, GracefulGoaway) {
Ryan Hamilton0239aac2018-05-19 00:03:135333 spdy::SpdySerializedFrame req1(
5334 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
bnc1fc7b352017-01-12 17:51:025335 spdy_util_.UpdateWithStreamDestruction(1);
Ryan Hamilton0239aac2018-05-19 00:03:135336 spdy::SpdySerializedFrame req2(
bnc1fc7b352017-01-12 17:51:025337 spdy_util_.ConstructSpdyGet("https://www.example.org/foo", 3, LOWEST));
5338 MockWrite writes[] = {CreateMockWrite(req1, 0), CreateMockWrite(req2, 3)};
5339
Ryan Hamilton0239aac2018-05-19 00:03:135340 spdy::SpdySerializedFrame resp1(
5341 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
5342 spdy::SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true));
5343 spdy::SpdySerializedFrame goaway(spdy_util_.ConstructSpdyGoAway(
5344 0x7fffffff, spdy::ERROR_CODE_NO_ERROR, "Graceful shutdown."));
5345 spdy::SpdySerializedFrame resp2(
5346 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
5347 spdy::SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(3, true));
bnc1fc7b352017-01-12 17:51:025348 MockRead reads[] = {CreateMockRead(resp1, 1), CreateMockRead(body1, 2),
5349 CreateMockRead(goaway, 4), CreateMockRead(resp2, 5),
5350 CreateMockRead(body2, 6), MockRead(ASYNC, 0, 7)};
5351
5352 // Run first transaction.
Ryan Sleevib8d7ea02018-05-07 20:01:015353 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:105354 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
bnc1fc7b352017-01-12 17:51:025355 helper.RunPreTestSetup();
5356 helper.AddData(&data);
5357 helper.RunDefaultTest();
5358
5359 // Verify first response.
5360 TransactionHelperResult out = helper.output();
5361 EXPECT_THAT(out.rv, IsOk());
5362 EXPECT_EQ("HTTP/1.1 200", out.status_line);
5363 EXPECT_EQ("hello!", out.response_data);
5364
5365 // GOAWAY frame has not yet been received, SpdySession should be available.
5366 SpdySessionPool* spdy_session_pool = helper.session()->spdy_session_pool();
5367 SpdySessionKey key(host_port_pair_, ProxyServer::Direct(),
Matt Menke2436b2f2018-12-11 18:07:115368 PRIVACY_MODE_DISABLED,
dalyk51ab46b2019-10-15 15:14:345369 SpdySessionKey::IsProxySession::kFalse, SocketTag(),
Ben Schwartz3ff4dc1e62021-04-27 21:15:235370 NetworkIsolationKey(), SecureDnsPolicy::kAllow);
bnc1fc7b352017-01-12 17:51:025371 base::WeakPtr<SpdySession> spdy_session =
bnc9ead3ae2017-03-16 00:48:155372 spdy_session_pool->FindAvailableSession(
Bence Békyd885b2b2018-02-03 00:58:315373 key, /* enable_ip_based_pooling = */ true,
5374 /* is_websocket = */ false, log_);
bnc1fc7b352017-01-12 17:51:025375 EXPECT_TRUE(spdy_session);
5376
5377 // Start second transaction.
5378 HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session());
5379 TestCompletionCallback callback;
5380 HttpRequestInfo request2;
5381 request2.method = "GET";
5382 request2.url = GURL("https://www.example.org/foo");
Ramin Halavatib5e433e62018-02-07 07:41:105383 request2.traffic_annotation =
5384 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
Bence Békyd3dde832017-09-19 19:02:315385 int rv = trans2.Start(&request2, callback.callback(), log_);
bnc1fc7b352017-01-12 17:51:025386 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
5387 rv = callback.WaitForResult();
5388 EXPECT_THAT(rv, IsOk());
5389
5390 // Verify second response.
5391 const HttpResponseInfo* response = trans2.GetResponseInfo();
5392 ASSERT_TRUE(response);
5393 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP2, response->connection_info);
5394 ASSERT_TRUE(response->headers);
5395 EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
5396 EXPECT_TRUE(response->was_fetched_via_spdy);
5397 EXPECT_TRUE(response->was_alpn_negotiated);
Tsuyoshi Horo01faed62019-02-20 22:11:375398 EXPECT_EQ("127.0.0.1", response->remote_endpoint.ToStringWithoutPort());
5399 EXPECT_EQ(443, response->remote_endpoint.port());
Bence Béky4e83f492018-05-13 23:14:255400 std::string response_data;
bnc1fc7b352017-01-12 17:51:025401 rv = ReadTransaction(&trans2, &response_data);
5402 EXPECT_THAT(rv, IsOk());
5403 EXPECT_EQ("hello!", response_data);
5404
5405 // Graceful GOAWAY was received, SpdySession should be unavailable.
bnc9ead3ae2017-03-16 00:48:155406 spdy_session = spdy_session_pool->FindAvailableSession(
Bence Békyd885b2b2018-02-03 00:58:315407 key, /* enable_ip_based_pooling = */ true,
5408 /* is_websocket = */ false, log_);
bnc1fc7b352017-01-12 17:51:025409 EXPECT_FALSE(spdy_session);
5410
5411 helper.VerifyDataConsumed();
5412}
5413
bncd16676a2016-07-20 16:23:015414TEST_F(SpdyNetworkTransactionTest, CloseWithActiveStream) {
Ryan Hamilton0239aac2018-05-19 00:03:135415 spdy::SpdySerializedFrame req(
5416 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
bncdf80d44fd2016-07-15 20:27:415417 MockWrite writes[] = {CreateMockWrite(req, 0)};
[email protected]f5ed21552010-05-04 18:39:545418
Ryan Hamilton0239aac2018-05-19 00:03:135419 spdy::SpdySerializedFrame resp(
5420 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
[email protected]f5ed21552010-05-04 18:39:545421 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:415422 CreateMockRead(resp, 1), MockRead(SYNCHRONOUS, 0, 2) // EOF
[email protected]f5ed21552010-05-04 18:39:545423 };
5424
Ryan Sleevib8d7ea02018-05-07 20:01:015425 SequencedSocketData data(reads, writes);
bnc4d782f492016-08-18 13:50:005426
Bence Békydb3cf652017-10-10 15:22:105427 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]3caf5542010-07-16 15:19:475428 helper.RunPreTestSetup();
[email protected]dd54bd82012-07-19 23:44:575429 helper.AddData(&data);
bnc4d782f492016-08-18 13:50:005430 helper.StartDefaultTest();
5431 EXPECT_THAT(helper.output().rv, IsError(ERR_IO_PENDING));
[email protected]f5ed21552010-05-04 18:39:545432
bnc4d782f492016-08-18 13:50:005433 helper.WaitForCallbackToComplete();
5434 EXPECT_THAT(helper.output().rv, IsError(ERR_CONNECTION_CLOSED));
[email protected]3caf5542010-07-16 15:19:475435
bnc4d782f492016-08-18 13:50:005436 const HttpResponseInfo* response = helper.trans()->GetResponseInfo();
wezca1070932016-05-26 20:30:525437 EXPECT_TRUE(response->headers);
[email protected]f5ed21552010-05-04 18:39:545438 EXPECT_TRUE(response->was_fetched_via_spdy);
[email protected]f5ed21552010-05-04 18:39:545439
5440 // Verify that we consumed all test data.
[email protected]3caf5542010-07-16 15:19:475441 helper.VerifyDataConsumed();
[email protected]f5ed21552010-05-04 18:39:545442}
[email protected]58cebf8f2010-07-31 19:20:165443
Bence Békyc2d37952017-11-20 16:58:165444TEST_F(SpdyNetworkTransactionTest, GoAwayImmediately) {
Ryan Hamilton0239aac2018-05-19 00:03:135445 spdy::SpdySerializedFrame goaway(spdy_util_.ConstructSpdyGoAway(1));
Bence Békyc2d37952017-11-20 16:58:165446 MockRead reads[] = {CreateMockRead(goaway, 0, SYNCHRONOUS)};
Ryan Sleevib8d7ea02018-05-07 20:01:015447 SequencedSocketData data(reads, base::span<MockWrite>());
Bence Békyc2d37952017-11-20 16:58:165448
5449 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
5450 helper.RunPreTestSetup();
5451 helper.AddData(&data);
5452 helper.StartDefaultTest();
5453 EXPECT_THAT(helper.output().rv, IsError(ERR_IO_PENDING));
5454
5455 helper.WaitForCallbackToComplete();
5456 EXPECT_THAT(helper.output().rv, IsError(ERR_CONNECTION_CLOSED));
5457
5458 const HttpResponseInfo* response = helper.trans()->GetResponseInfo();
5459 EXPECT_FALSE(response->headers);
5460 EXPECT_TRUE(response->was_fetched_via_spdy);
5461
5462 // Verify that we consumed all test data.
5463 helper.VerifyDataConsumed();
5464}
5465
bncfacdd852015-01-09 19:22:545466// Retry with HTTP/1.1 when receiving HTTP_1_1_REQUIRED. Note that no actual
5467// protocol negotiation happens, instead this test forces protocols for both
5468// sockets.
bncd16676a2016-07-20 16:23:015469TEST_F(SpdyNetworkTransactionTest, HTTP11RequiredRetry) {
Bence Békydb3cf652017-10-10 15:22:105470 request_.method = "GET";
bncfacdd852015-01-09 19:22:545471 // Do not force SPDY so that second socket can negotiate HTTP/1.1.
Bence Békydb3cf652017-10-10 15:22:105472 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
bncfacdd852015-01-09 19:22:545473
5474 // First socket: HTTP/2 request rejected with HTTP_1_1_REQUIRED.
Bence Béky4c325e52020-10-22 20:48:015475 spdy::Http2HeaderBlock headers(
Ryan Hamilton0239aac2018-05-19 00:03:135476 spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
5477 spdy::SpdySerializedFrame req(
bnc42331402016-07-25 13:36:155478 spdy_util_.ConstructSpdyHeaders(1, std::move(headers), LOWEST, true));
bncdf80d44fd2016-07-15 20:27:415479 MockWrite writes0[] = {CreateMockWrite(req, 0)};
Ryan Hamilton0239aac2018-05-19 00:03:135480 spdy::SpdySerializedFrame rst(
5481 spdy_util_.ConstructSpdyRstStream(1, spdy::ERROR_CODE_HTTP_1_1_REQUIRED));
Bence Békycb3613122017-09-19 17:06:575482 MockRead reads0[] = {CreateMockRead(rst, 1)};
Ryan Sleevib8d7ea02018-05-07 20:01:015483 SequencedSocketData data0(reads0, writes0);
bncfacdd852015-01-09 19:22:545484
Jeremy Roman0579ed62017-08-29 15:56:195485 auto ssl_provider0 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
bncfacdd852015-01-09 19:22:545486 // Expect HTTP/2 protocols too in SSLConfig.
Bence Béky27a19b82018-01-30 14:58:365487 ssl_provider0->next_protos_expected_in_ssl_config =
5488 NextProtoVector{kProtoHTTP2, kProtoHTTP11};
bncfacdd852015-01-09 19:22:545489 // Force SPDY.
bnc3cf2a592016-08-11 14:48:365490 ssl_provider0->next_proto = kProtoHTTP2;
dchengc7eeda422015-12-26 03:56:485491 helper.AddDataWithSSLSocketDataProvider(&data0, std::move(ssl_provider0));
bncfacdd852015-01-09 19:22:545492
5493 // Second socket: falling back to HTTP/1.1.
rch08e3aa3e2015-05-16 14:27:525494 MockWrite writes1[] = {MockWrite(ASYNC, 0,
5495 "GET / HTTP/1.1\r\n"
5496 "Host: www.example.org\r\n"
5497 "Connection: keep-alive\r\n\r\n")};
5498 MockRead reads1[] = {MockRead(ASYNC, 1,
5499 "HTTP/1.1 200 OK\r\n"
5500 "Content-Length: 5\r\n\r\n"
5501 "hello")};
Ryan Sleevib8d7ea02018-05-07 20:01:015502 SequencedSocketData data1(reads1, writes1);
bncfacdd852015-01-09 19:22:545503
Jeremy Roman0579ed62017-08-29 15:56:195504 auto ssl_provider1 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
bncfacdd852015-01-09 19:22:545505 // Expect only HTTP/1.1 protocol in SSLConfig.
Bence Béky27a19b82018-01-30 14:58:365506 ssl_provider1->next_protos_expected_in_ssl_config =
5507 NextProtoVector{kProtoHTTP11};
bncfacdd852015-01-09 19:22:545508 // Force HTTP/1.1.
bnc3cf2a592016-08-11 14:48:365509 ssl_provider1->next_proto = kProtoHTTP11;
dchengc7eeda422015-12-26 03:56:485510 helper.AddDataWithSSLSocketDataProvider(&data1, std::move(ssl_provider1));
bncfacdd852015-01-09 19:22:545511
bnc525e175a2016-06-20 12:36:405512 HttpServerProperties* http_server_properties =
bncfacdd852015-01-09 19:22:545513 helper.session()->spdy_session_pool()->http_server_properties();
Matt Menkef2ee07c2019-08-29 02:10:365514 EXPECT_FALSE(http_server_properties->RequiresHTTP11(
5515 url::SchemeHostPort(request_.url), NetworkIsolationKey()));
bncfacdd852015-01-09 19:22:545516
5517 helper.RunPreTestSetup();
5518 helper.StartDefaultTest();
5519 helper.FinishDefaultTestWithoutVerification();
5520 helper.VerifyDataConsumed();
Matt Menkef2ee07c2019-08-29 02:10:365521 EXPECT_TRUE(http_server_properties->RequiresHTTP11(
5522 url::SchemeHostPort(request_.url), NetworkIsolationKey()));
bncfacdd852015-01-09 19:22:545523
5524 const HttpResponseInfo* response = helper.trans()->GetResponseInfo();
wezca1070932016-05-26 20:30:525525 ASSERT_TRUE(response);
5526 ASSERT_TRUE(response->headers);
bncfacdd852015-01-09 19:22:545527 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
5528 EXPECT_FALSE(response->was_fetched_via_spdy);
mmenke8210acc2016-07-11 16:34:525529 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP1_1,
5530 response->connection_info);
bnc94c92842016-09-21 15:22:525531 EXPECT_TRUE(response->was_alpn_negotiated);
Bence Békydb3cf652017-10-10 15:22:105532 EXPECT_TRUE(request_.url.SchemeIs("https"));
Tsuyoshi Horo01faed62019-02-20 22:11:375533 EXPECT_EQ("127.0.0.1", response->remote_endpoint.ToStringWithoutPort());
5534 EXPECT_EQ(443, response->remote_endpoint.port());
Bence Béky4e83f492018-05-13 23:14:255535 std::string response_data;
robpercival214763f2016-07-01 23:27:015536 ASSERT_THAT(ReadTransaction(helper.trans(), &response_data), IsOk());
bncfacdd852015-01-09 19:22:545537 EXPECT_EQ("hello", response_data);
5538}
5539
Matt Menkef2ee07c2019-08-29 02:10:365540// Same as above test, but checks that NetworkIsolationKeys are respected.
5541TEST_F(SpdyNetworkTransactionTest, HTTP11RequiredRetryWithNetworkIsolationKey) {
Matt Menke4807a9a2020-11-21 00:14:415542 const SchemefulSite kSite1(GURL("https://foo.test/"));
5543 const SchemefulSite kSite2(GURL("https://bar.test/"));
5544 const NetworkIsolationKey kNetworkIsolationKey1(kSite1, kSite1);
5545 const NetworkIsolationKey kNetworkIsolationKey2(kSite2, kSite2);
Matt Menkef2ee07c2019-08-29 02:10:365546
5547 const NetworkIsolationKey kNetworkIsolationKeys[] = {
5548 kNetworkIsolationKey1, kNetworkIsolationKey2, NetworkIsolationKey()};
5549
5550 base::test::ScopedFeatureList feature_list;
5551 feature_list.InitWithFeatures(
5552 // enabled_features
5553 {features::kPartitionHttpServerPropertiesByNetworkIsolationKey,
5554 // Need to partition connections by NetworkIsolationKey for
5555 // SpdySessionKeys to include NetworkIsolationKeys.
5556 features::kPartitionConnectionsByNetworkIsolationKey},
5557 // disabled_features
5558 {});
5559
5560 // Do not force SPDY so that sockets can negotiate HTTP/1.1.
5561 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
5562
5563 // For each server, set up and tear down a QUIC session cleanly, and check
5564 // that stats have been added to HttpServerProperties using the correct
5565 // NetworkIsolationKey.
5566 for (size_t i = 0; i < base::size(kNetworkIsolationKeys); ++i) {
5567 SCOPED_TRACE(i);
5568
5569 request_.method = "GET";
5570 request_.network_isolation_key = kNetworkIsolationKeys[i];
5571
5572 // First socket: HTTP/2 request rejected with HTTP_1_1_REQUIRED.
5573 SpdyTestUtil spdy_util;
Bence Béky4c325e52020-10-22 20:48:015574 spdy::Http2HeaderBlock headers(
Matt Menkef2ee07c2019-08-29 02:10:365575 spdy_util.ConstructGetHeaderBlock(kDefaultUrl));
5576 spdy::SpdySerializedFrame req(
5577 spdy_util.ConstructSpdyHeaders(1, std::move(headers), LOWEST, true));
5578 MockWrite writes0[] = {CreateMockWrite(req, 0)};
5579 spdy::SpdySerializedFrame rst(spdy_util.ConstructSpdyRstStream(
5580 1, spdy::ERROR_CODE_HTTP_1_1_REQUIRED));
5581 MockRead reads0[] = {CreateMockRead(rst, 1)};
5582 SequencedSocketData data0(reads0, writes0);
5583
5584 auto ssl_provider0 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
5585 // Expect HTTP/2 protocols too in SSLConfig.
5586 ssl_provider0->next_protos_expected_in_ssl_config =
5587 NextProtoVector{kProtoHTTP2, kProtoHTTP11};
5588 // Force SPDY.
5589 ssl_provider0->next_proto = kProtoHTTP2;
5590 helper.AddDataWithSSLSocketDataProvider(&data0, std::move(ssl_provider0));
5591
5592 // Second socket: falling back to HTTP/1.1.
5593 MockWrite writes1[] = {MockWrite(ASYNC, 0,
5594 "GET / HTTP/1.1\r\n"
5595 "Host: www.example.org\r\n"
5596 "Connection: keep-alive\r\n\r\n")};
5597 MockRead reads1[] = {MockRead(ASYNC, 1,
5598 "HTTP/1.1 200 OK\r\n"
5599 "Content-Length: 5\r\n\r\n"
5600 "hello")};
5601 SequencedSocketData data1(reads1, writes1);
5602
5603 auto ssl_provider1 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
5604 // Expect only HTTP/1.1 protocol in SSLConfig.
5605 ssl_provider1->next_protos_expected_in_ssl_config =
5606 NextProtoVector{kProtoHTTP11};
5607 // Force HTTP/1.1.
5608 ssl_provider1->next_proto = kProtoHTTP11;
5609 helper.AddDataWithSSLSocketDataProvider(&data1, std::move(ssl_provider1));
5610
5611 HttpServerProperties* http_server_properties =
5612 helper.session()->spdy_session_pool()->http_server_properties();
5613 EXPECT_FALSE(http_server_properties->RequiresHTTP11(
5614 url::SchemeHostPort(request_.url), kNetworkIsolationKeys[i]));
5615
5616 HttpNetworkTransaction trans(DEFAULT_PRIORITY, helper.session());
5617
5618 TestCompletionCallback callback;
5619 int rv = trans.Start(&request_, callback.callback(), log_);
5620 EXPECT_THAT(callback.GetResult(rv), IsOk());
5621
5622 const HttpResponseInfo* response = trans.GetResponseInfo();
5623 ASSERT_TRUE(response);
5624 ASSERT_TRUE(response->headers);
5625 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
5626 EXPECT_FALSE(response->was_fetched_via_spdy);
5627 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP1_1,
5628 response->connection_info);
5629 EXPECT_TRUE(response->was_alpn_negotiated);
5630 EXPECT_TRUE(request_.url.SchemeIs("https"));
5631 EXPECT_EQ("127.0.0.1", response->remote_endpoint.ToStringWithoutPort());
5632 EXPECT_EQ(443, response->remote_endpoint.port());
5633 std::string response_data;
5634 ASSERT_THAT(ReadTransaction(&trans, &response_data), IsOk());
5635 EXPECT_EQ("hello", response_data);
5636
5637 for (size_t j = 0; j < base::size(kNetworkIsolationKeys); ++j) {
5638 // NetworkIsolationKeys up to kNetworkIsolationKeys[j] are known to
5639 // require HTTP/1.1, others are not.
5640 if (j <= i) {
5641 EXPECT_TRUE(http_server_properties->RequiresHTTP11(
5642 url::SchemeHostPort(request_.url), kNetworkIsolationKeys[j]));
5643 } else {
5644 EXPECT_FALSE(http_server_properties->RequiresHTTP11(
5645 url::SchemeHostPort(request_.url), kNetworkIsolationKeys[j]));
5646 }
5647 }
5648 }
5649}
5650
bncfacdd852015-01-09 19:22:545651// Retry with HTTP/1.1 to the proxy when receiving HTTP_1_1_REQUIRED from the
5652// proxy. Note that no actual protocol negotiation happens, instead this test
5653// forces protocols for both sockets.
bncd16676a2016-07-20 16:23:015654TEST_F(SpdyNetworkTransactionTest, HTTP11RequiredProxyRetry) {
Bence Békydb3cf652017-10-10 15:22:105655 request_.method = "GET";
Jeremy Roman0579ed62017-08-29 15:56:195656 auto session_deps = std::make_unique<SpdySessionDependencies>(
Nicolas Arciniegad2013f92020-02-07 23:00:565657 ConfiguredProxyResolutionService::CreateFixedFromPacResult(
Ramin Halavatica8d5252018-03-12 05:33:495658 "HTTPS myproxy:70", TRAFFIC_ANNOTATION_FOR_TESTS));
bncfacdd852015-01-09 19:22:545659 // Do not force SPDY so that second socket can negotiate HTTP/1.1.
Bence Békydb3cf652017-10-10 15:22:105660 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
Bence Békyd3dde832017-09-19 19:02:315661 std::move(session_deps));
bncfacdd852015-01-09 19:22:545662
5663 // First socket: HTTP/2 CONNECT rejected with HTTP_1_1_REQUIRED.
Ryan Hamilton0239aac2018-05-19 00:03:135664 spdy::SpdySerializedFrame req(spdy_util_.ConstructSpdyConnect(
Matt Menke6e879bd2019-03-18 17:26:045665 nullptr, 0, 1, HttpProxyConnectJob::kH2QuicTunnelPriority,
5666 HostPortPair("www.example.org", 443)));
bncdf80d44fd2016-07-15 20:27:415667 MockWrite writes0[] = {CreateMockWrite(req, 0)};
Ryan Hamilton0239aac2018-05-19 00:03:135668 spdy::SpdySerializedFrame rst(
5669 spdy_util_.ConstructSpdyRstStream(1, spdy::ERROR_CODE_HTTP_1_1_REQUIRED));
Bence Békycb3613122017-09-19 17:06:575670 MockRead reads0[] = {CreateMockRead(rst, 1)};
Ryan Sleevib8d7ea02018-05-07 20:01:015671 SequencedSocketData data0(reads0, writes0);
bncfacdd852015-01-09 19:22:545672
Jeremy Roman0579ed62017-08-29 15:56:195673 auto ssl_provider0 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
bncfacdd852015-01-09 19:22:545674 // Expect HTTP/2 protocols too in SSLConfig.
Bence Béky27a19b82018-01-30 14:58:365675 ssl_provider0->next_protos_expected_in_ssl_config =
5676 NextProtoVector{kProtoHTTP2, kProtoHTTP11};
bncfacdd852015-01-09 19:22:545677 // Force SPDY.
bnc3cf2a592016-08-11 14:48:365678 ssl_provider0->next_proto = kProtoHTTP2;
dchengc7eeda422015-12-26 03:56:485679 helper.AddDataWithSSLSocketDataProvider(&data0, std::move(ssl_provider0));
bncfacdd852015-01-09 19:22:545680
5681 // Second socket: retry using HTTP/1.1.
5682 MockWrite writes1[] = {
rch08e3aa3e2015-05-16 14:27:525683 MockWrite(ASYNC, 0,
bncce36dca22015-04-21 22:11:235684 "CONNECT www.example.org:443 HTTP/1.1\r\n"
rsleevidb16bb02015-11-12 23:47:175685 "Host: www.example.org:443\r\n"
bncfacdd852015-01-09 19:22:545686 "Proxy-Connection: keep-alive\r\n\r\n"),
rch08e3aa3e2015-05-16 14:27:525687 MockWrite(ASYNC, 2,
bncfacdd852015-01-09 19:22:545688 "GET / HTTP/1.1\r\n"
bncce36dca22015-04-21 22:11:235689 "Host: www.example.org\r\n"
bncfacdd852015-01-09 19:22:545690 "Connection: keep-alive\r\n\r\n"),
5691 };
5692
5693 MockRead reads1[] = {
rch08e3aa3e2015-05-16 14:27:525694 MockRead(ASYNC, 1, "HTTP/1.1 200 OK\r\n\r\n"),
5695 MockRead(ASYNC, 3,
bncfacdd852015-01-09 19:22:545696 "HTTP/1.1 200 OK\r\n"
5697 "Content-Length: 5\r\n\r\n"
5698 "hello"),
5699 };
Ryan Sleevib8d7ea02018-05-07 20:01:015700 SequencedSocketData data1(reads1, writes1);
bncfacdd852015-01-09 19:22:545701
Jeremy Roman0579ed62017-08-29 15:56:195702 auto ssl_provider1 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
bncfacdd852015-01-09 19:22:545703 // Expect only HTTP/1.1 protocol in SSLConfig.
Bence Béky27a19b82018-01-30 14:58:365704 ssl_provider1->next_protos_expected_in_ssl_config =
5705 NextProtoVector{kProtoHTTP11};
bncfacdd852015-01-09 19:22:545706 // Force HTTP/1.1.
bnc3cf2a592016-08-11 14:48:365707 ssl_provider1->next_proto = kProtoHTTP11;
dchengc7eeda422015-12-26 03:56:485708 helper.AddDataWithSSLSocketDataProvider(&data1, std::move(ssl_provider1));
bncfacdd852015-01-09 19:22:545709
5710 // A third socket is needed for the tunnelled connection.
Jeremy Roman0579ed62017-08-29 15:56:195711 auto ssl_provider2 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
bncfacdd852015-01-09 19:22:545712 helper.session_deps()->socket_factory->AddSSLSocketDataProvider(
5713 ssl_provider2.get());
5714
bnc525e175a2016-06-20 12:36:405715 HttpServerProperties* http_server_properties =
bncfacdd852015-01-09 19:22:545716 helper.session()->spdy_session_pool()->http_server_properties();
Matt Menkef2ee07c2019-08-29 02:10:365717 url::SchemeHostPort proxy_scheme_host_port(url::kHttpsScheme, "myproxy", 70);
5718 EXPECT_FALSE(http_server_properties->RequiresHTTP11(proxy_scheme_host_port,
5719 NetworkIsolationKey()));
bncfacdd852015-01-09 19:22:545720
5721 helper.RunPreTestSetup();
5722 helper.StartDefaultTest();
5723 helper.FinishDefaultTestWithoutVerification();
5724 helper.VerifyDataConsumed();
Matt Menkef2ee07c2019-08-29 02:10:365725 EXPECT_TRUE(http_server_properties->RequiresHTTP11(proxy_scheme_host_port,
5726 NetworkIsolationKey()));
bncfacdd852015-01-09 19:22:545727
5728 const HttpResponseInfo* response = helper.trans()->GetResponseInfo();
wezca1070932016-05-26 20:30:525729 ASSERT_TRUE(response);
5730 ASSERT_TRUE(response->headers);
bncfacdd852015-01-09 19:22:545731 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
5732 EXPECT_FALSE(response->was_fetched_via_spdy);
mmenke8210acc2016-07-11 16:34:525733 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP1_1,
5734 response->connection_info);
bnc94c92842016-09-21 15:22:525735 EXPECT_FALSE(response->was_alpn_negotiated);
Bence Békydb3cf652017-10-10 15:22:105736 EXPECT_TRUE(request_.url.SchemeIs("https"));
Tsuyoshi Horo01faed62019-02-20 22:11:375737 EXPECT_EQ("127.0.0.1", response->remote_endpoint.ToStringWithoutPort());
5738 EXPECT_EQ(70, response->remote_endpoint.port());
Bence Béky4e83f492018-05-13 23:14:255739 std::string response_data;
robpercival214763f2016-07-01 23:27:015740 ASSERT_THAT(ReadTransaction(helper.trans(), &response_data), IsOk());
bncfacdd852015-01-09 19:22:545741 EXPECT_EQ("hello", response_data);
5742}
5743
Matt Menkef2ee07c2019-08-29 02:10:365744// Same as above, but also test that NetworkIsolationKeys are respected.
5745TEST_F(SpdyNetworkTransactionTest,
5746 HTTP11RequiredProxyRetryWithNetworkIsolationKey) {
Matt Menke4807a9a2020-11-21 00:14:415747 const SchemefulSite kSite1(GURL("https://foo.test/"));
5748 const SchemefulSite kSite2(GURL("https://bar.test/"));
5749 const NetworkIsolationKey kNetworkIsolationKey1(kSite1, kSite1);
5750 const NetworkIsolationKey kNetworkIsolationKey2(kSite2, kSite2);
Matt Menkef2ee07c2019-08-29 02:10:365751
5752 const NetworkIsolationKey kNetworkIsolationKeys[] = {
5753 kNetworkIsolationKey1, kNetworkIsolationKey2, NetworkIsolationKey()};
5754
5755 base::test::ScopedFeatureList feature_list;
5756 feature_list.InitWithFeatures(
5757 // enabled_features
5758 {features::kPartitionHttpServerPropertiesByNetworkIsolationKey,
5759 // Need to partition connections by NetworkIsolationKey for
5760 // SpdySessionKeys to include NetworkIsolationKeys.
5761 features::kPartitionConnectionsByNetworkIsolationKey},
5762 // disabled_features
5763 {});
5764
5765 request_.method = "GET";
5766 auto session_deps = std::make_unique<SpdySessionDependencies>(
Nicolas Arciniegad2013f92020-02-07 23:00:565767 ConfiguredProxyResolutionService::CreateFixedFromPacResult(
Matt Menkef2ee07c2019-08-29 02:10:365768 "HTTPS myproxy:70", TRAFFIC_ANNOTATION_FOR_TESTS));
5769 // Do not force SPDY so that second socket can negotiate HTTP/1.1.
5770 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
5771 std::move(session_deps));
5772 helper.RunPreTestSetup();
5773
5774 for (size_t i = 0; i < base::size(kNetworkIsolationKeys); ++i) {
5775 // First socket: HTTP/2 CONNECT rejected with HTTP_1_1_REQUIRED.
5776
5777 SpdyTestUtil spdy_util;
5778 spdy::SpdySerializedFrame req(spdy_util.ConstructSpdyConnect(
5779 nullptr, 0, 1, HttpProxyConnectJob::kH2QuicTunnelPriority,
5780 HostPortPair("www.example.org", 443)));
5781 MockWrite writes0[] = {CreateMockWrite(req, 0)};
5782 spdy::SpdySerializedFrame rst(spdy_util.ConstructSpdyRstStream(
5783 1, spdy::ERROR_CODE_HTTP_1_1_REQUIRED));
5784 MockRead reads0[] = {CreateMockRead(rst, 1)};
5785 SequencedSocketData data0(reads0, writes0);
5786
5787 auto ssl_provider0 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
5788 // Expect HTTP/2 protocols too in SSLConfig.
5789 ssl_provider0->next_protos_expected_in_ssl_config =
5790 NextProtoVector{kProtoHTTP2, kProtoHTTP11};
5791 // Force SPDY.
5792 ssl_provider0->next_proto = kProtoHTTP2;
5793 helper.AddDataWithSSLSocketDataProvider(&data0, std::move(ssl_provider0));
5794
5795 // Second socket: retry using HTTP/1.1.
5796 MockWrite writes1[] = {
5797 MockWrite(ASYNC, 0,
5798 "CONNECT www.example.org:443 HTTP/1.1\r\n"
5799 "Host: www.example.org:443\r\n"
5800 "Proxy-Connection: keep-alive\r\n\r\n"),
5801 MockWrite(ASYNC, 2,
5802 "GET / HTTP/1.1\r\n"
5803 "Host: www.example.org\r\n"
5804 "Connection: keep-alive\r\n\r\n"),
5805 };
5806
5807 MockRead reads1[] = {
5808 MockRead(ASYNC, 1, "HTTP/1.1 200 OK\r\n\r\n"),
5809 MockRead(ASYNC, 3,
5810 "HTTP/1.1 200 OK\r\n"
5811 "Content-Length: 5\r\n\r\n"
5812 "hello"),
5813 };
5814 SequencedSocketData data1(reads1, writes1);
5815
5816 auto ssl_provider1 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
5817 // Expect only HTTP/1.1 protocol in SSLConfig.
5818 ssl_provider1->next_protos_expected_in_ssl_config =
5819 NextProtoVector{kProtoHTTP11};
5820 // Force HTTP/1.1.
5821 ssl_provider1->next_proto = kProtoHTTP11;
5822 helper.AddDataWithSSLSocketDataProvider(&data1, std::move(ssl_provider1));
5823
5824 // A third socket is needed for the tunnelled connection.
5825 auto ssl_provider2 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
5826 helper.session_deps()->socket_factory->AddSSLSocketDataProvider(
5827 ssl_provider2.get());
5828
5829 HttpServerProperties* http_server_properties =
5830 helper.session()->spdy_session_pool()->http_server_properties();
5831 url::SchemeHostPort proxy_scheme_host_port(url::kHttpsScheme, "myproxy",
5832 70);
5833 EXPECT_FALSE(http_server_properties->RequiresHTTP11(
5834 proxy_scheme_host_port, kNetworkIsolationKeys[i]));
5835
5836 request_.network_isolation_key = kNetworkIsolationKeys[i];
5837 HttpNetworkTransaction trans(DEFAULT_PRIORITY, helper.session());
5838 TestCompletionCallback callback;
5839 int rv = trans.Start(&request_, callback.callback(), log_);
5840 EXPECT_THAT(callback.GetResult(rv), IsOk());
5841 helper.VerifyDataConsumed();
5842
5843 const HttpResponseInfo* response = trans.GetResponseInfo();
5844 ASSERT_TRUE(response);
5845 ASSERT_TRUE(response->headers);
5846 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
5847 EXPECT_FALSE(response->was_fetched_via_spdy);
5848 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP1_1,
5849 response->connection_info);
5850 EXPECT_FALSE(response->was_alpn_negotiated);
5851 EXPECT_TRUE(request_.url.SchemeIs("https"));
5852 EXPECT_EQ("127.0.0.1", response->remote_endpoint.ToStringWithoutPort());
5853 EXPECT_EQ(70, response->remote_endpoint.port());
5854 std::string response_data;
5855 ASSERT_THAT(ReadTransaction(&trans, &response_data), IsOk());
5856 EXPECT_EQ("hello", response_data);
5857
5858 for (size_t j = 0; j < base::size(kNetworkIsolationKeys); ++j) {
5859 // The proxy SchemeHostPort URL should not be marked as requiring HTTP/1.1
5860 // using the current NetworkIsolationKey, and the state of others should
5861 // be unchanged since the last loop iteration..
5862 if (j <= i) {
5863 EXPECT_TRUE(http_server_properties->RequiresHTTP11(
5864 proxy_scheme_host_port, kNetworkIsolationKeys[j]));
5865 } else {
5866 EXPECT_FALSE(http_server_properties->RequiresHTTP11(
5867 proxy_scheme_host_port, kNetworkIsolationKeys[j]));
5868 }
5869 }
5870
5871 // The destination SchemeHostPort should not be marked as requiring
5872 // HTTP/1.1.
5873 EXPECT_FALSE(http_server_properties->RequiresHTTP11(
5874 url::SchemeHostPort(request_.url), kNetworkIsolationKeys[i]));
5875 }
5876}
5877
[email protected]b261d0e2010-08-02 19:13:245878// Test to make sure we can correctly connect through a proxy.
bncd16676a2016-07-20 16:23:015879TEST_F(SpdyNetworkTransactionTest, ProxyConnect) {
Jeremy Roman0579ed62017-08-29 15:56:195880 auto session_deps = std::make_unique<SpdySessionDependencies>(
Nicolas Arciniegad2013f92020-02-07 23:00:565881 ConfiguredProxyResolutionService::CreateFixedFromPacResult(
Ramin Halavatica8d5252018-03-12 05:33:495882 "PROXY myproxy:70", TRAFFIC_ANNOTATION_FOR_TESTS));
Bence Békydb3cf652017-10-10 15:22:105883 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
tfarina428341112016-09-22 13:38:205884 std::move(session_deps));
[email protected]b261d0e2010-08-02 19:13:245885 helper.RunPreTestSetup();
5886 HttpNetworkTransaction* trans = helper.trans();
5887
rchebf12982015-04-10 01:15:005888 const char kConnect443[] = {
bncce36dca22015-04-21 22:11:235889 "CONNECT www.example.org:443 HTTP/1.1\r\n"
rsleevidb16bb02015-11-12 23:47:175890 "Host: www.example.org:443\r\n"
rchcb934f562015-04-07 16:25:125891 "Proxy-Connection: keep-alive\r\n\r\n"};
[email protected]b261d0e2010-08-02 19:13:245892 const char kHTTP200[] = {"HTTP/1.1 200 OK\r\n\r\n"};
Ryan Hamilton0239aac2018-05-19 00:03:135893 spdy::SpdySerializedFrame req(
5894 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
5895 spdy::SpdySerializedFrame resp(
5896 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
5897 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]b261d0e2010-08-02 19:13:245898
rchebf12982015-04-10 01:15:005899 MockWrite writes[] = {
Avi Drissman4365a4782018-12-28 19:26:245900 MockWrite(SYNCHRONOUS, kConnect443, base::size(kConnect443) - 1, 0),
bncdf80d44fd2016-07-15 20:27:415901 CreateMockWrite(req, 2),
[email protected]b261d0e2010-08-02 19:13:245902 };
rchebf12982015-04-10 01:15:005903 MockRead reads[] = {
Avi Drissman4365a4782018-12-28 19:26:245904 MockRead(SYNCHRONOUS, kHTTP200, base::size(kHTTP200) - 1, 1),
5905 CreateMockRead(resp, 3),
5906 CreateMockRead(body, 4),
Raul Tambre94493c652019-03-11 17:18:355907 MockRead(ASYNC, nullptr, 0, 5),
[email protected]b261d0e2010-08-02 19:13:245908 };
Ryan Sleevib8d7ea02018-05-07 20:01:015909 SequencedSocketData data(reads, writes);
[email protected]b261d0e2010-08-02 19:13:245910
Bence Béky53a5aef2018-03-29 21:54:125911 helper.AddData(&data);
[email protected]49639fa2011-12-20 23:22:415912 TestCompletionCallback callback;
[email protected]b261d0e2010-08-02 19:13:245913
Bence Békydb3cf652017-10-10 15:22:105914 int rv = trans->Start(&request_, callback.callback(), log_);
robpercival214763f2016-07-01 23:27:015915 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]b261d0e2010-08-02 19:13:245916
5917 rv = callback.WaitForResult();
5918 EXPECT_EQ(0, rv);
5919
bnc42331402016-07-25 13:36:155920 // Verify the response headers.
[email protected]b261d0e2010-08-02 19:13:245921 HttpResponseInfo response = *trans->GetResponseInfo();
wezca1070932016-05-26 20:30:525922 ASSERT_TRUE(response.headers);
bnc84e7fb52015-12-02 11:50:025923 EXPECT_EQ("HTTP/1.1 200", response.headers->GetStatusLine());
[email protected]b261d0e2010-08-02 19:13:245924
Bence Béky4e83f492018-05-13 23:14:255925 std::string response_data;
robpercival214763f2016-07-01 23:27:015926 ASSERT_THAT(ReadTransaction(trans, &response_data), IsOk());
[email protected]b261d0e2010-08-02 19:13:245927 EXPECT_EQ("hello!", response_data);
5928 helper.VerifyDataConsumed();
5929}
5930
bncce36dca22015-04-21 22:11:235931// Test to make sure we can correctly connect through a proxy to
5932// www.example.org, if there already exists a direct spdy connection to
5933// www.example.org. See https://crbug.com/49874.
bncd16676a2016-07-20 16:23:015934TEST_F(SpdyNetworkTransactionTest, DirectConnectProxyReconnect) {
[email protected]733b7a6d2010-08-25 01:38:435935 // Use a proxy service which returns a proxy fallback list from DIRECT to
5936 // myproxy:70. For this test there will be no fallback, so it is equivalent
5937 // to simply DIRECT. The reason for appending the second proxy is to verify
5938 // that the session pool key used does is just "DIRECT".
Jeremy Roman0579ed62017-08-29 15:56:195939 auto session_deps = std::make_unique<SpdySessionDependencies>(
Nicolas Arciniegad2013f92020-02-07 23:00:565940 ConfiguredProxyResolutionService::CreateFixedFromPacResult(
Ramin Halavatica8d5252018-03-12 05:33:495941 "DIRECT; PROXY myproxy:70", TRAFFIC_ANNOTATION_FOR_TESTS));
bncd16676a2016-07-20 16:23:015942 // When setting up the first transaction, we store the SpdySessionPool so that
5943 // we can use the same pool in the second transaction.
Bence Békydb3cf652017-10-10 15:22:105944 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
tfarina428341112016-09-22 13:38:205945 std::move(session_deps));
[email protected]733b7a6d2010-08-25 01:38:435946
[email protected]87bfa3f2010-09-30 14:54:565947 SpdySessionPool* spdy_session_pool = helper.session()->spdy_session_pool();
[email protected]b261d0e2010-08-02 19:13:245948 helper.RunPreTestSetup();
5949
5950 // Construct and send a simple GET request.
Ryan Hamilton0239aac2018-05-19 00:03:135951 spdy::SpdySerializedFrame req(
5952 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
[email protected]b261d0e2010-08-02 19:13:245953 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:415954 CreateMockWrite(req, 0),
[email protected]b261d0e2010-08-02 19:13:245955 };
5956
Ryan Hamilton0239aac2018-05-19 00:03:135957 spdy::SpdySerializedFrame resp(
5958 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
5959 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]b261d0e2010-08-02 19:13:245960 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:415961 CreateMockRead(resp, 1), CreateMockRead(body, 2),
rch08e3aa3e2015-05-16 14:27:525962 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 3), // Force a pause
[email protected]b261d0e2010-08-02 19:13:245963 };
Ryan Sleevib8d7ea02018-05-07 20:01:015964 SequencedSocketData data(reads, writes);
[email protected]dd54bd82012-07-19 23:44:575965 helper.AddData(&data);
[email protected]b261d0e2010-08-02 19:13:245966 HttpNetworkTransaction* trans = helper.trans();
5967
[email protected]49639fa2011-12-20 23:22:415968 TestCompletionCallback callback;
[email protected]b261d0e2010-08-02 19:13:245969 TransactionHelperResult out;
Bence Békydb3cf652017-10-10 15:22:105970 out.rv = trans->Start(&request_, callback.callback(), log_);
[email protected]b261d0e2010-08-02 19:13:245971
5972 EXPECT_EQ(out.rv, ERR_IO_PENDING);
5973 out.rv = callback.WaitForResult();
5974 EXPECT_EQ(out.rv, OK);
5975
5976 const HttpResponseInfo* response = trans->GetResponseInfo();
wezca1070932016-05-26 20:30:525977 EXPECT_TRUE(response->headers);
[email protected]b261d0e2010-08-02 19:13:245978 EXPECT_TRUE(response->was_fetched_via_spdy);
5979 out.rv = ReadTransaction(trans, &out.response_data);
robpercival214763f2016-07-01 23:27:015980 EXPECT_THAT(out.rv, IsOk());
[email protected]b261d0e2010-08-02 19:13:245981 out.status_line = response->headers->GetStatusLine();
bnc84e7fb52015-12-02 11:50:025982 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]b261d0e2010-08-02 19:13:245983 EXPECT_EQ("hello!", out.response_data);
5984
5985 // Check that the SpdySession is still in the SpdySessionPool.
Matt Menke2436b2f2018-12-11 18:07:115986 SpdySessionKey session_pool_key_direct(
5987 host_port_pair_, ProxyServer::Direct(), PRIVACY_MODE_DISABLED,
dalyk51ab46b2019-10-15 15:14:345988 SpdySessionKey::IsProxySession::kFalse, SocketTag(),
Ben Schwartz3ff4dc1e62021-04-27 21:15:235989 NetworkIsolationKey(), SecureDnsPolicy::kAllow);
[email protected]41d64e82013-07-03 22:44:265990 EXPECT_TRUE(HasSpdySession(spdy_session_pool, session_pool_key_direct));
[email protected]e6d017652013-05-17 18:01:405991 SpdySessionKey session_pool_key_proxy(
bncb26024382016-06-29 02:39:455992 host_port_pair_,
[email protected]e6d017652013-05-17 18:01:405993 ProxyServer::FromURI("www.foo.com", ProxyServer::SCHEME_HTTP),
Matt Menke2436b2f2018-12-11 18:07:115994 PRIVACY_MODE_DISABLED, SpdySessionKey::IsProxySession::kFalse,
Ben Schwartz3ff4dc1e62021-04-27 21:15:235995 SocketTag(), NetworkIsolationKey(), SecureDnsPolicy::kAllow);
[email protected]41d64e82013-07-03 22:44:265996 EXPECT_FALSE(HasSpdySession(spdy_session_pool, session_pool_key_proxy));
[email protected]b261d0e2010-08-02 19:13:245997
rdsmithebb50aa2015-11-12 03:44:385998 // New SpdyTestUtil instance for the session that will be used for the
5999 // proxy connection.
bncd16676a2016-07-20 16:23:016000 SpdyTestUtil spdy_util_2;
rdsmithebb50aa2015-11-12 03:44:386001
[email protected]b261d0e2010-08-02 19:13:246002 // Set up data for the proxy connection.
bncce36dca22015-04-21 22:11:236003 const char kConnect443[] = {
6004 "CONNECT www.example.org:443 HTTP/1.1\r\n"
rsleevidb16bb02015-11-12 23:47:176005 "Host: www.example.org:443\r\n"
bncce36dca22015-04-21 22:11:236006 "Proxy-Connection: keep-alive\r\n\r\n"};
[email protected]b261d0e2010-08-02 19:13:246007 const char kHTTP200[] = {"HTTP/1.1 200 OK\r\n\r\n"};
Ryan Hamilton0239aac2018-05-19 00:03:136008 spdy::SpdySerializedFrame req2(
6009 spdy_util_2.ConstructSpdyGet(kPushedUrl, 1, LOWEST));
6010 spdy::SpdySerializedFrame resp2(
6011 spdy_util_2.ConstructSpdyGetReply(nullptr, 0, 1));
6012 spdy::SpdySerializedFrame body2(spdy_util_2.ConstructSpdyDataFrame(1, true));
[email protected]b261d0e2010-08-02 19:13:246013
rchebf12982015-04-10 01:15:006014 MockWrite writes2[] = {
Avi Drissman4365a4782018-12-28 19:26:246015 MockWrite(SYNCHRONOUS, kConnect443, base::size(kConnect443) - 1, 0),
bncdf80d44fd2016-07-15 20:27:416016 CreateMockWrite(req2, 2),
[email protected]b261d0e2010-08-02 19:13:246017 };
rchebf12982015-04-10 01:15:006018 MockRead reads2[] = {
Avi Drissman4365a4782018-12-28 19:26:246019 MockRead(SYNCHRONOUS, kHTTP200, base::size(kHTTP200) - 1, 1),
bncdf80d44fd2016-07-15 20:27:416020 CreateMockRead(resp2, 3), CreateMockRead(body2, 4),
rchebf12982015-04-10 01:15:006021 MockRead(ASYNC, 0, 5) // EOF
[email protected]b261d0e2010-08-02 19:13:246022 };
6023
Ryan Sleevib8d7ea02018-05-07 20:01:016024 SequencedSocketData data_proxy(reads2, writes2);
[email protected]b261d0e2010-08-02 19:13:246025
bncce36dca22015-04-21 22:11:236026 // Create another request to www.example.org, but this time through a proxy.
Bence Békydb3cf652017-10-10 15:22:106027 request_.method = "GET";
Bence Békyd2df6c1c82018-04-20 22:52:016028 request_.url = GURL(kPushedUrl);
Jeremy Roman0579ed62017-08-29 15:56:196029 auto session_deps_proxy = std::make_unique<SpdySessionDependencies>(
Nicolas Arciniegad2013f92020-02-07 23:00:566030 ConfiguredProxyResolutionService::CreateFixedFromPacResult(
Ramin Halavatica8d5252018-03-12 05:33:496031 "PROXY myproxy:70", TRAFFIC_ANNOTATION_FOR_TESTS));
Bence Békydb3cf652017-10-10 15:22:106032 NormalSpdyTransactionHelper helper_proxy(request_, DEFAULT_PRIORITY, log_,
6033 std::move(session_deps_proxy));
6034
[email protected]b261d0e2010-08-02 19:13:246035 helper_proxy.RunPreTestSetup();
Bence Béky53a5aef2018-03-29 21:54:126036 helper_proxy.AddData(&data_proxy);
[email protected]b261d0e2010-08-02 19:13:246037
6038 HttpNetworkTransaction* trans_proxy = helper_proxy.trans();
[email protected]49639fa2011-12-20 23:22:416039 TestCompletionCallback callback_proxy;
Bence Békydb3cf652017-10-10 15:22:106040 int rv = trans_proxy->Start(&request_, callback_proxy.callback(), log_);
robpercival214763f2016-07-01 23:27:016041 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]b261d0e2010-08-02 19:13:246042 rv = callback_proxy.WaitForResult();
6043 EXPECT_EQ(0, rv);
6044
6045 HttpResponseInfo response_proxy = *trans_proxy->GetResponseInfo();
wezca1070932016-05-26 20:30:526046 ASSERT_TRUE(response_proxy.headers);
bnc84e7fb52015-12-02 11:50:026047 EXPECT_EQ("HTTP/1.1 200", response_proxy.headers->GetStatusLine());
[email protected]b261d0e2010-08-02 19:13:246048
Bence Béky4e83f492018-05-13 23:14:256049 std::string response_data;
robpercival214763f2016-07-01 23:27:016050 ASSERT_THAT(ReadTransaction(trans_proxy, &response_data), IsOk());
[email protected]b261d0e2010-08-02 19:13:246051 EXPECT_EQ("hello!", response_data);
6052
[email protected]b261d0e2010-08-02 19:13:246053 helper_proxy.VerifyDataConsumed();
6054}
6055
[email protected]58cebf8f2010-07-31 19:20:166056// When we get a TCP-level RST, we need to retry a HttpNetworkTransaction
6057// on a new connection, if the connection was previously known to be good.
6058// This can happen when a server reboots without saying goodbye, or when
6059// we're behind a NAT that masked the RST.
bncd16676a2016-07-20 16:23:016060TEST_F(SpdyNetworkTransactionTest, VerifyRetryOnConnectionReset) {
Ryan Hamilton0239aac2018-05-19 00:03:136061 spdy::SpdySerializedFrame resp(
6062 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
6063 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]58cebf8f2010-07-31 19:20:166064 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:416065 CreateMockRead(resp, 1), CreateMockRead(body, 2),
rch32320842015-05-16 15:57:096066 MockRead(ASYNC, ERR_IO_PENDING, 3),
6067 MockRead(ASYNC, ERR_CONNECTION_RESET, 4),
[email protected]58cebf8f2010-07-31 19:20:166068 };
6069
6070 MockRead reads2[] = {
bncdf80d44fd2016-07-15 20:27:416071 CreateMockRead(resp, 1), CreateMockRead(body, 2),
rch32320842015-05-16 15:57:096072 MockRead(ASYNC, 0, 3) // EOF
[email protected]58cebf8f2010-07-31 19:20:166073 };
6074
Ryan Hamilton0239aac2018-05-19 00:03:136075 spdy::SpdySerializedFrame req(
6076 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
rdsmithebb50aa2015-11-12 03:44:386077 // In all cases the connection will be reset before req3 can be
6078 // dispatched, destroying both streams.
6079 spdy_util_.UpdateWithStreamDestruction(1);
Ryan Hamilton0239aac2018-05-19 00:03:136080 spdy::SpdySerializedFrame req3(
6081 spdy_util_.ConstructSpdyGet(nullptr, 0, 3, LOWEST));
bncdf80d44fd2016-07-15 20:27:416082 MockWrite writes1[] = {CreateMockWrite(req, 0), CreateMockWrite(req3, 5)};
6083 MockWrite writes2[] = {CreateMockWrite(req, 0)};
rchacdcbdc2015-05-16 17:16:006084
[email protected]58cebf8f2010-07-31 19:20:166085 // This test has a couple of variants.
6086 enum {
6087 // Induce the RST while waiting for our transaction to send.
rchacdcbdc2015-05-16 17:16:006088 VARIANT_RST_DURING_SEND_COMPLETION = 0,
[email protected]58cebf8f2010-07-31 19:20:166089 // Induce the RST while waiting for our transaction to read.
6090 // In this case, the send completed - everything copied into the SNDBUF.
rchacdcbdc2015-05-16 17:16:006091 VARIANT_RST_DURING_READ_COMPLETION = 1
[email protected]58cebf8f2010-07-31 19:20:166092 };
6093
6094 for (int variant = VARIANT_RST_DURING_SEND_COMPLETION;
6095 variant <= VARIANT_RST_DURING_READ_COMPLETION;
6096 ++variant) {
Ryan Sleevib8d7ea02018-05-07 20:01:016097 SequencedSocketData data1(reads,
6098 base::make_span(writes1).first(1 + variant));
[email protected]58cebf8f2010-07-31 19:20:166099
Ryan Sleevib8d7ea02018-05-07 20:01:016100 SequencedSocketData data2(reads2, writes2);
[email protected]58cebf8f2010-07-31 19:20:166101
Bence Békydb3cf652017-10-10 15:22:106102 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
6103 nullptr);
[email protected]dd54bd82012-07-19 23:44:576104 helper.AddData(&data1);
6105 helper.AddData(&data2);
[email protected]58cebf8f2010-07-31 19:20:166106 helper.RunPreTestSetup();
6107
6108 for (int i = 0; i < 2; ++i) {
bnc691fda62016-08-12 00:43:166109 HttpNetworkTransaction trans(DEFAULT_PRIORITY, helper.session());
[email protected]58cebf8f2010-07-31 19:20:166110
[email protected]49639fa2011-12-20 23:22:416111 TestCompletionCallback callback;
Bence Békydb3cf652017-10-10 15:22:106112 int rv = trans.Start(&request_, callback.callback(), log_);
robpercival214763f2016-07-01 23:27:016113 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]58cebf8f2010-07-31 19:20:166114 // On the second transaction, we trigger the RST.
6115 if (i == 1) {
6116 if (variant == VARIANT_RST_DURING_READ_COMPLETION) {
6117 // Writes to the socket complete asynchronously on SPDY by running
6118 // through the message loop. Complete the write here.
[email protected]fc9d88472013-08-14 02:31:176119 base::RunLoop().RunUntilIdle();
[email protected]58cebf8f2010-07-31 19:20:166120 }
6121
6122 // Now schedule the ERR_CONNECTION_RESET.
mmenkee24011922015-12-17 22:12:596123 data1.Resume();
[email protected]58cebf8f2010-07-31 19:20:166124 }
6125 rv = callback.WaitForResult();
robpercival214763f2016-07-01 23:27:016126 EXPECT_THAT(rv, IsOk());
[email protected]58cebf8f2010-07-31 19:20:166127
bnc691fda62016-08-12 00:43:166128 const HttpResponseInfo* response = trans.GetResponseInfo();
wezca1070932016-05-26 20:30:526129 ASSERT_TRUE(response);
6130 EXPECT_TRUE(response->headers);
[email protected]58cebf8f2010-07-31 19:20:166131 EXPECT_TRUE(response->was_fetched_via_spdy);
Bence Béky4e83f492018-05-13 23:14:256132 std::string response_data;
bnc691fda62016-08-12 00:43:166133 rv = ReadTransaction(&trans, &response_data);
robpercival214763f2016-07-01 23:27:016134 EXPECT_THAT(rv, IsOk());
bnc84e7fb52015-12-02 11:50:026135 EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
[email protected]58cebf8f2010-07-31 19:20:166136 EXPECT_EQ("hello!", response_data);
rchacdcbdc2015-05-16 17:16:006137 base::RunLoop().RunUntilIdle();
[email protected]58cebf8f2010-07-31 19:20:166138 }
6139
6140 helper.VerifyDataConsumed();
rchacdcbdc2015-05-16 17:16:006141 base::RunLoop().RunUntilIdle();
[email protected]58cebf8f2010-07-31 19:20:166142 }
6143}
[email protected]1f418ee2010-10-16 19:46:566144
[email protected]018aabc2010-10-29 16:16:596145// Tests that Basic authentication works over SPDY
bncd16676a2016-07-20 16:23:016146TEST_F(SpdyNetworkTransactionTest, SpdyBasicAuth) {
[email protected]018aabc2010-10-29 16:16:596147 // The first request will be a bare GET, the second request will be a
6148 // GET with an Authorization header.
Ryan Hamilton0239aac2018-05-19 00:03:136149 spdy::SpdySerializedFrame req_get(
Bence Béky27ad0a12018-02-08 00:35:486150 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
rdsmithebb50aa2015-11-12 03:44:386151 // Will be refused for lack of auth.
6152 spdy_util_.UpdateWithStreamDestruction(1);
[email protected]018aabc2010-10-29 16:16:596153 const char* const kExtraAuthorizationHeaders[] = {
[email protected]cdf8f7e72013-05-23 10:56:466154 "authorization", "Basic Zm9vOmJhcg=="
[email protected]018aabc2010-10-29 16:16:596155 };
Ryan Hamilton0239aac2018-05-19 00:03:136156 spdy::SpdySerializedFrame req_get_authorization(spdy_util_.ConstructSpdyGet(
Avi Drissman4365a4782018-12-28 19:26:246157 kExtraAuthorizationHeaders, base::size(kExtraAuthorizationHeaders) / 2, 3,
Bence Béky27ad0a12018-02-08 00:35:486158 LOWEST));
[email protected]018aabc2010-10-29 16:16:596159 MockWrite spdy_writes[] = {
bncdf80d44fd2016-07-15 20:27:416160 CreateMockWrite(req_get, 0), CreateMockWrite(req_get_authorization, 3),
[email protected]018aabc2010-10-29 16:16:596161 };
6162
6163 // The first response is a 401 authentication challenge, and the second
6164 // response will be a 200 response since the second request includes a valid
6165 // Authorization header.
6166 const char* const kExtraAuthenticationHeaders[] = {
[email protected]fb9e4312012-02-17 06:27:266167 "www-authenticate",
[email protected]018aabc2010-10-29 16:16:596168 "Basic realm=\"MyRealm\""
6169 };
Ryan Hamilton0239aac2018-05-19 00:03:136170 spdy::SpdySerializedFrame resp_authentication(
6171 spdy_util_.ConstructSpdyReplyError(
6172 "401", kExtraAuthenticationHeaders,
Avi Drissman4365a4782018-12-28 19:26:246173 base::size(kExtraAuthenticationHeaders) / 2, 1));
Ryan Hamilton0239aac2018-05-19 00:03:136174 spdy::SpdySerializedFrame body_authentication(
bncdf80d44fd2016-07-15 20:27:416175 spdy_util_.ConstructSpdyDataFrame(1, true));
Ryan Hamilton0239aac2018-05-19 00:03:136176 spdy::SpdySerializedFrame resp_data(
tombergan5d22c182017-01-11 02:05:356177 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
Ryan Hamilton0239aac2018-05-19 00:03:136178 spdy::SpdySerializedFrame body_data(
6179 spdy_util_.ConstructSpdyDataFrame(3, true));
tombergan5d22c182017-01-11 02:05:356180
[email protected]018aabc2010-10-29 16:16:596181 MockRead spdy_reads[] = {
bncdf80d44fd2016-07-15 20:27:416182 CreateMockRead(resp_authentication, 1),
bnceb9aa7112017-01-05 01:03:466183 CreateMockRead(body_authentication, 2, SYNCHRONOUS),
bncdf80d44fd2016-07-15 20:27:416184 CreateMockRead(resp_data, 4),
6185 CreateMockRead(body_data, 5),
rch08e3aa3e2015-05-16 14:27:526186 MockRead(ASYNC, 0, 6),
[email protected]018aabc2010-10-29 16:16:596187 };
6188
Ryan Sleevib8d7ea02018-05-07 20:01:016189 SequencedSocketData data(spdy_reads, spdy_writes);
Bence Békydb3cf652017-10-10 15:22:106190 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]018aabc2010-10-29 16:16:596191
6192 helper.RunPreTestSetup();
[email protected]dd54bd82012-07-19 23:44:576193 helper.AddData(&data);
bnc4d782f492016-08-18 13:50:006194 helper.StartDefaultTest();
6195 EXPECT_THAT(helper.output().rv, IsError(ERR_IO_PENDING));
6196
6197 helper.WaitForCallbackToComplete();
6198 EXPECT_THAT(helper.output().rv, IsOk());
[email protected]018aabc2010-10-29 16:16:596199
6200 // Make sure the response has an auth challenge.
bnc4d782f492016-08-18 13:50:006201 HttpNetworkTransaction* trans = helper.trans();
[email protected]018aabc2010-10-29 16:16:596202 const HttpResponseInfo* const response_start = trans->GetResponseInfo();
wezca1070932016-05-26 20:30:526203 ASSERT_TRUE(response_start);
6204 ASSERT_TRUE(response_start->headers);
[email protected]018aabc2010-10-29 16:16:596205 EXPECT_EQ(401, response_start->headers->response_code());
6206 EXPECT_TRUE(response_start->was_fetched_via_spdy);
Anton Bikineev068d2912021-05-15 20:43:526207 const absl::optional<AuthChallengeInfo>& auth_challenge =
Emily Starkf2c9bbd2019-04-09 17:08:586208 response_start->auth_challenge;
wezca1070932016-05-26 20:30:526209 ASSERT_TRUE(auth_challenge);
[email protected]79cb5c12011-09-12 13:12:046210 EXPECT_FALSE(auth_challenge->is_proxy);
aberentbba302d2015-12-03 10:20:196211 EXPECT_EQ(kBasicAuthScheme, auth_challenge->scheme);
[email protected]79cb5c12011-09-12 13:12:046212 EXPECT_EQ("MyRealm", auth_challenge->realm);
[email protected]018aabc2010-10-29 16:16:596213
6214 // Restart with a username/password.
Jan Wilken Dörriec92a6d7242021-03-23 17:43:486215 AuthCredentials credentials(u"foo", u"bar");
[email protected]49639fa2011-12-20 23:22:416216 TestCompletionCallback callback_restart;
6217 const int rv_restart = trans->RestartWithAuth(
6218 credentials, callback_restart.callback());
robpercival214763f2016-07-01 23:27:016219 EXPECT_THAT(rv_restart, IsError(ERR_IO_PENDING));
[email protected]018aabc2010-10-29 16:16:596220 const int rv_restart_complete = callback_restart.WaitForResult();
robpercival214763f2016-07-01 23:27:016221 EXPECT_THAT(rv_restart_complete, IsOk());
[email protected]018aabc2010-10-29 16:16:596222 // TODO(cbentzel): This is actually the same response object as before, but
6223 // data has changed.
6224 const HttpResponseInfo* const response_restart = trans->GetResponseInfo();
wezca1070932016-05-26 20:30:526225 ASSERT_TRUE(response_restart);
6226 ASSERT_TRUE(response_restart->headers);
[email protected]018aabc2010-10-29 16:16:596227 EXPECT_EQ(200, response_restart->headers->response_code());
Emily Starkf2c9bbd2019-04-09 17:08:586228 EXPECT_FALSE(response_restart->auth_challenge);
[email protected]018aabc2010-10-29 16:16:596229}
6230
Bence Békye7023f82018-05-14 01:53:036231struct PushHeaderTestParams {
Victor Vasiliev502ba582020-09-15 23:16:156232 std::vector<std::pair<std::string, std::string>> extra_request_headers;
6233 std::vector<std::pair<std::string, std::string>> extra_pushed_request_headers;
6234 std::vector<std::pair<std::string, std::string>>
Bence Béky49db0e22018-05-11 00:54:056235 extra_pushed_response_headers;
Victor Vasiliev502ba582020-09-15 23:16:156236 std::string pushed_status_code;
Bence Béky49db0e22018-05-11 00:54:056237 bool push_accepted;
Bence Békyeacd48f2018-05-14 11:34:336238 SpdyPushedStreamFate expected_fate;
Bence Békye7023f82018-05-14 01:53:036239} push_header_test_cases[] = {
Bence Béky49db0e22018-05-11 00:54:056240 // Base case: no extra headers.
Bence Békyeacd48f2018-05-14 11:34:336241 {{}, {}, {}, "200", true, SpdyPushedStreamFate::kAcceptedNoVary},
Bence Béky49db0e22018-05-11 00:54:056242 // Cookie headers match.
6243 {{{"cookie", "value=foo"}},
6244 {{"cookie", "value=foo"}},
6245 {{"vary", "Cookie"}},
6246 "200",
Bence Békyeacd48f2018-05-14 11:34:336247 true,
6248 SpdyPushedStreamFate::kAcceptedMatchingVary},
Bence Béky49db0e22018-05-11 00:54:056249 // Cookie headers mismatch.
6250 {{{"cookie", "value=foo"}},
6251 {{"cookie", "value=bar"}},
6252 {{"vary", "Cookie"}},
6253 "200",
Bence Békyeacd48f2018-05-14 11:34:336254 false,
6255 SpdyPushedStreamFate::kVaryMismatch},
Bence Béky49db0e22018-05-11 00:54:056256 // Partial Content response, no Range headers.
Bence Békyeacd48f2018-05-14 11:34:336257 {{}, {}, {}, "206", false, SpdyPushedStreamFate::kClientRequestNotRange},
Bence Béky49db0e22018-05-11 00:54:056258 // Partial Content response, no Range headers in pushed request.
Bence Békyeacd48f2018-05-14 11:34:336259 {{{"range", "0-42"}},
6260 {},
6261 {},
6262 "206",
6263 false,
6264 SpdyPushedStreamFate::kPushedRequestNotRange},
Bence Béky49db0e22018-05-11 00:54:056265 // Partial Content response, no Range headers in client request.
Bence Békyeacd48f2018-05-14 11:34:336266 {{},
6267 {{"range", "0-42"}},
6268 {},
6269 "206",
6270 false,
6271 SpdyPushedStreamFate::kClientRequestNotRange},
Bence Béky49db0e22018-05-11 00:54:056272 // Partial Content response, mismatching Range headers.
Bence Békyeacd48f2018-05-14 11:34:336273 {{{"range", "0-42"}},
6274 {{"range", "10-42"}},
6275 {},
6276 "206",
6277 false,
6278 SpdyPushedStreamFate::kRangeMismatch},
Bence Béky49db0e22018-05-11 00:54:056279 // Partial Content response, matching Range headers.
Bence Békyeacd48f2018-05-14 11:34:336280 {{{"range", "0-42"}},
6281 {{"range", "0-42"}},
6282 {},
6283 "206",
6284 true,
6285 SpdyPushedStreamFate::kAcceptedNoVary},
6286};
[email protected]d08358502010-12-03 22:04:036287
Bence Békye7023f82018-05-14 01:53:036288class SpdyNetworkTransactionPushHeaderTest
Bence Béky49db0e22018-05-11 00:54:056289 : public SpdyNetworkTransactionTest,
Bence Békye7023f82018-05-14 01:53:036290 public ::testing::WithParamInterface<PushHeaderTestParams> {
Bence Béky49db0e22018-05-11 00:54:056291 protected:
6292 void RunTest(bool pushed_response_headers_received_before_request) {
Bence Békyeacd48f2018-05-14 11:34:336293 base::HistogramTester histogram_tester;
6294
Bence Békyc4caf072018-04-20 22:27:306295 int seq = 0;
6296 std::vector<MockWrite> writes;
6297 std::vector<MockRead> reads;
bnc38dcd392016-02-09 23:19:496298
Ryan Hamilton0239aac2018-05-19 00:03:136299 spdy::SpdySerializedFrame req1(
Bence Béky49db0e22018-05-11 00:54:056300 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
Bence Békyc4caf072018-04-20 22:27:306301 writes.push_back(CreateMockWrite(req1, seq++));
[email protected]513963e2013-06-15 01:53:046302
Bence Béky4c325e52020-10-22 20:48:016303 spdy::Http2HeaderBlock pushed_request_headers;
Ryan Hamilton0239aac2018-05-19 00:03:136304 pushed_request_headers[spdy::kHttp2MethodHeader] = "GET";
Bence Béky49db0e22018-05-11 00:54:056305 for (const auto& header : GetParam().extra_pushed_request_headers) {
Bence Békyc4caf072018-04-20 22:27:306306 pushed_request_headers.insert(header);
6307 }
Bence Béky49db0e22018-05-11 00:54:056308 spdy_util_.AddUrlToHeaderBlock(kPushedUrl, &pushed_request_headers);
Ryan Hamilton0239aac2018-05-19 00:03:136309 spdy::SpdySerializedFrame pushed_request(
6310 spdy_util_.ConstructSpdyPushPromise(1, 2,
6311 std::move(pushed_request_headers)));
Bence Békyc4caf072018-04-20 22:27:306312 reads.push_back(CreateMockRead(pushed_request, seq++));
[email protected]d08358502010-12-03 22:04:036313
Ryan Hamilton0239aac2018-05-19 00:03:136314 spdy::SpdySerializedFrame priority(
Bence Béky49db0e22018-05-11 00:54:056315 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true));
Bence Békyc4caf072018-04-20 22:27:306316 writes.push_back(CreateMockWrite(priority, seq++));
bnc38dcd392016-02-09 23:19:496317
Bence Béky49db0e22018-05-11 00:54:056318 reads.push_back(MockRead(ASYNC, ERR_IO_PENDING, seq++));
6319
Bence Béky4c325e52020-10-22 20:48:016320 spdy::Http2HeaderBlock pushed_response_headers;
Ryan Hamilton0239aac2018-05-19 00:03:136321 pushed_response_headers[spdy::kHttp2StatusHeader] =
6322 GetParam().pushed_status_code;
Bence Béky49db0e22018-05-11 00:54:056323 for (const auto& header : GetParam().extra_pushed_response_headers) {
Bence Békyc4caf072018-04-20 22:27:306324 pushed_response_headers.insert(header);
6325 }
Ryan Hamilton0239aac2018-05-19 00:03:136326 spdy::SpdySerializedFrame pushed_response(
Bence Béky49db0e22018-05-11 00:54:056327 spdy_util_.ConstructSpdyReply(2, std::move(pushed_response_headers)));
Bence Békyc4caf072018-04-20 22:27:306328 reads.push_back(CreateMockRead(pushed_response, seq++));
bnc38dcd392016-02-09 23:19:496329
Ryan Hamilton0239aac2018-05-19 00:03:136330 spdy::SpdySerializedFrame resp1(
6331 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
Bence Békyc4caf072018-04-20 22:27:306332 reads.push_back(CreateMockRead(resp1, seq++));
[email protected]d08358502010-12-03 22:04:036333
Ryan Hamilton0239aac2018-05-19 00:03:136334 spdy::SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true));
Bence Békyc4caf072018-04-20 22:27:306335 reads.push_back(CreateMockRead(body1, seq++));
Bence Béky49db0e22018-05-11 00:54:056336 spdy_util_.UpdateWithStreamDestruction(1);
[email protected]d08358502010-12-03 22:04:036337
Ryan Hamilton0239aac2018-05-19 00:03:136338 spdy::SpdySerializedFrame pushed_body(
Bence Béky49db0e22018-05-11 00:54:056339 spdy_util_.ConstructSpdyDataFrame(2, "This is pushed.", true));
Bence Békyc4caf072018-04-20 22:27:306340 reads.push_back(CreateMockRead(pushed_body, seq++));
[email protected]d08358502010-12-03 22:04:036341
Bence Békyc4caf072018-04-20 22:27:306342 // If push is not accepted, a new request is sent on the wire.
Ryan Hamilton0239aac2018-05-19 00:03:136343 spdy::SpdySerializedFrame rst;
6344 spdy::SpdySerializedFrame req2;
6345 spdy::SpdySerializedFrame resp2;
6346 spdy::SpdySerializedFrame body2;
Bence Béky49db0e22018-05-11 00:54:056347 if (!GetParam().push_accepted) {
Ryan Hamilton0239aac2018-05-19 00:03:136348 rst = spdy_util_.ConstructSpdyRstStream(2, spdy::ERROR_CODE_CANCEL);
Bence Béky49db0e22018-05-11 00:54:056349 writes.push_back(CreateMockWrite(rst, seq++));
6350
Bence Béky4c325e52020-10-22 20:48:016351 spdy::Http2HeaderBlock request_headers2(
Bence Béky49db0e22018-05-11 00:54:056352 spdy_util_.ConstructGetHeaderBlock(kPushedUrl));
6353 for (const auto& header : GetParam().extra_request_headers) {
Bence Békyc4caf072018-04-20 22:27:306354 request_headers2.insert(header);
6355 }
Bence Béky49db0e22018-05-11 00:54:056356 req2 = spdy_util_.ConstructSpdyHeaders(3, std::move(request_headers2),
6357 LOWEST, true);
Bence Békyc4caf072018-04-20 22:27:306358 writes.push_back(CreateMockWrite(req2, seq++));
[email protected]d08358502010-12-03 22:04:036359
Bence Béky49db0e22018-05-11 00:54:056360 resp2 = spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3);
Bence Békyc4caf072018-04-20 22:27:306361 reads.push_back(CreateMockRead(resp2, seq++));
Bence Béky04268b022018-04-19 01:17:416362
Bence Béky49db0e22018-05-11 00:54:056363 body2 = spdy_util_.ConstructSpdyDataFrame(3, "This is not pushed.", true);
Bence Békyc4caf072018-04-20 22:27:306364 reads.push_back(CreateMockRead(body2, seq++));
6365 }
Bence Béky04268b022018-04-19 01:17:416366
Bence Békyc4caf072018-04-20 22:27:306367 reads.push_back(MockRead(ASYNC, ERR_IO_PENDING, seq++));
Bence Béky04268b022018-04-19 01:17:416368
Bence Békyc4caf072018-04-20 22:27:306369 reads.push_back(MockRead(ASYNC, 0, seq++));
Bence Béky04268b022018-04-19 01:17:416370
Ryan Sleevib8d7ea02018-05-07 20:01:016371 SequencedSocketData data(reads, writes);
Bence Béky04268b022018-04-19 01:17:416372
Bence Békyc4caf072018-04-20 22:27:306373 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
6374 nullptr);
6375 helper.RunPreTestSetup();
6376 helper.AddData(&data);
Bence Béky04268b022018-04-19 01:17:416377
Bence Békyc4caf072018-04-20 22:27:306378 HttpNetworkTransaction* trans = helper.trans();
6379 TestCompletionCallback callback1;
6380 int rv = trans->Start(&request_, callback1.callback(), log_);
6381 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
Bence Béky49db0e22018-05-11 00:54:056382
6383 // Open connection.
6384 base::RunLoop().RunUntilIdle();
6385
6386 if (pushed_response_headers_received_before_request) {
6387 // Read pushed response headers.
6388 data.Resume();
6389 base::RunLoop().RunUntilIdle();
6390 }
6391
6392 HttpRequestInfo request2 = CreateGetPushRequest();
6393 for (const auto& header : GetParam().extra_request_headers) {
6394 request2.extra_headers.SetHeader(header.first, header.second);
6395 }
6396 HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session());
6397 TestCompletionCallback callback2;
6398 rv = trans2.Start(&request2, callback2.callback(), log_);
6399 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
6400 base::RunLoop().RunUntilIdle();
6401
6402 if (!pushed_response_headers_received_before_request) {
6403 // Read pushed response headers.
6404 data.Resume();
6405 base::RunLoop().RunUntilIdle();
6406 }
6407
Bence Békyc4caf072018-04-20 22:27:306408 rv = callback1.WaitForResult();
6409 EXPECT_THAT(rv, IsOk());
Bence Béky04268b022018-04-19 01:17:416410
Bence Békyc4caf072018-04-20 22:27:306411 const HttpResponseInfo* const response1 = trans->GetResponseInfo();
6412 EXPECT_TRUE(response1->headers);
6413 EXPECT_EQ("HTTP/1.1 200", response1->headers->GetStatusLine());
Bence Béky04268b022018-04-19 01:17:416414
Bence Béky4e83f492018-05-13 23:14:256415 std::string result1;
Bence Békyc4caf072018-04-20 22:27:306416 ReadResult(trans, &result1);
6417 EXPECT_EQ(result1, "hello!");
Bence Béky04268b022018-04-19 01:17:416418
Bence Békyc4caf072018-04-20 22:27:306419 rv = callback2.WaitForResult();
6420 EXPECT_THAT(rv, IsOk());
Bence Béky04268b022018-04-19 01:17:416421
Bence Béky4e83f492018-05-13 23:14:256422 std::string result2;
Bence Békyc4caf072018-04-20 22:27:306423 ReadResult(&trans2, &result2);
Bence Béky49db0e22018-05-11 00:54:056424 EXPECT_EQ(result2, GetParam().push_accepted ? "This is pushed."
6425 : "This is not pushed.");
Bence Béky04268b022018-04-19 01:17:416426
Bence Békyc4caf072018-04-20 22:27:306427 data.Resume();
6428 base::RunLoop().RunUntilIdle();
6429 helper.VerifyDataConsumed();
Bence Békyeacd48f2018-05-14 11:34:336430
6431 histogram_tester.ExpectBucketCount(
6432 "Net.SpdyPushedStreamFate", static_cast<int>(GetParam().expected_fate),
6433 1);
6434 histogram_tester.ExpectTotalCount("Net.SpdyPushedStreamFate", 1);
Bence Békyc4caf072018-04-20 22:27:306435 }
Bence Béky49db0e22018-05-11 00:54:056436};
6437
Ilia Samsonov958c9fef2019-11-20 21:37:316438INSTANTIATE_TEST_SUITE_P(All,
Victor Costan2309ea02019-02-13 21:35:476439 SpdyNetworkTransactionPushHeaderTest,
6440 ::testing::ValuesIn(push_header_test_cases));
Bence Béky49db0e22018-05-11 00:54:056441
Bence Békye7023f82018-05-14 01:53:036442TEST_P(SpdyNetworkTransactionPushHeaderTest,
Bence Béky49db0e22018-05-11 00:54:056443 PushedResponseHeadersReceivedBeforeRequest) {
6444 RunTest(/* pushed_response_headers_received_before_request = */ true);
Bence Béky04268b022018-04-19 01:17:416445}
6446
Bence Békye7023f82018-05-14 01:53:036447TEST_P(SpdyNetworkTransactionPushHeaderTest,
Bence Béky49db0e22018-05-11 00:54:056448 PushedResponseHeadersReceivedAfterRequest) {
6449 RunTest(/* pushed_response_headers_received_before_request = */ false);
[email protected]d08358502010-12-03 22:04:036450}
6451
bnc42331402016-07-25 13:36:156452TEST_F(SpdyNetworkTransactionTest, ResponseHeadersTwice) {
Ryan Hamilton0239aac2018-05-19 00:03:136453 spdy::SpdySerializedFrame req(
6454 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
6455 spdy::SpdySerializedFrame rst(
6456 spdy_util_.ConstructSpdyRstStream(1, spdy::ERROR_CODE_PROTOCOL_ERROR));
[email protected]b771bb72013-06-24 09:55:416457 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:416458 CreateMockWrite(req, 0), CreateMockWrite(rst, 4),
[email protected]745aa9c2014-06-27 02:21:296459 };
[email protected]d08358502010-12-03 22:04:036460
Ryan Hamilton0239aac2018-05-19 00:03:136461 spdy::SpdySerializedFrame stream1_reply(
tombergan5d22c182017-01-11 02:05:356462 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
[email protected]513963e2013-06-15 01:53:046463
Bence Béky4c325e52020-10-22 20:48:016464 spdy::Http2HeaderBlock late_headers;
bnc38dcd392016-02-09 23:19:496465 late_headers["hello"] = "bye";
Ryan Hamilton0239aac2018-05-19 00:03:136466 spdy::SpdySerializedFrame stream1_headers(
6467 spdy_util_.ConstructSpdyResponseHeaders(1, std::move(late_headers),
6468 false));
6469 spdy::SpdySerializedFrame stream1_body(
6470 spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]d08358502010-12-03 22:04:036471 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:416472 CreateMockRead(stream1_reply, 1), CreateMockRead(stream1_headers, 2),
6473 CreateMockRead(stream1_body, 3), MockRead(ASYNC, 0, 5) // EOF
[email protected]d08358502010-12-03 22:04:036474 };
6475
Ryan Sleevib8d7ea02018-05-07 20:01:016476 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:106477 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]dd54bd82012-07-19 23:44:576478 helper.RunToCompletion(&data);
[email protected]d08358502010-12-03 22:04:036479 TransactionHelperResult out = helper.output();
Bence Békyd0d69502019-06-25 19:47:186480 EXPECT_THAT(out.rv, IsError(ERR_HTTP2_PROTOCOL_ERROR));
[email protected]d08358502010-12-03 22:04:036481}
6482
xunjieli294da722015-08-11 19:15:026483// Tests that receiving HEADERS, DATA, HEADERS, and DATA in that sequence will
Bence Békyd0d69502019-06-25 19:47:186484// trigger a ERR_HTTP2_PROTOCOL_ERROR because trailing HEADERS must not be
xunjieli294da722015-08-11 19:15:026485// followed by any DATA frames.
bncd16676a2016-07-20 16:23:016486TEST_F(SpdyNetworkTransactionTest, SyncReplyDataAfterTrailers) {
Ryan Hamilton0239aac2018-05-19 00:03:136487 spdy::SpdySerializedFrame req(
6488 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
6489 spdy::SpdySerializedFrame rst(
6490 spdy_util_.ConstructSpdyRstStream(1, spdy::ERROR_CODE_PROTOCOL_ERROR));
[email protected]b771bb72013-06-24 09:55:416491 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:416492 CreateMockWrite(req, 0), CreateMockWrite(rst, 5),
[email protected]b771bb72013-06-24 09:55:416493 };
[email protected]d08358502010-12-03 22:04:036494
Ryan Hamilton0239aac2018-05-19 00:03:136495 spdy::SpdySerializedFrame stream1_reply(
tombergan5d22c182017-01-11 02:05:356496 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
Ryan Hamilton0239aac2018-05-19 00:03:136497 spdy::SpdySerializedFrame stream1_body(
6498 spdy_util_.ConstructSpdyDataFrame(1, false));
bnc38dcd392016-02-09 23:19:496499
Bence Béky4c325e52020-10-22 20:48:016500 spdy::Http2HeaderBlock late_headers;
bnc38dcd392016-02-09 23:19:496501 late_headers["hello"] = "bye";
Ryan Hamilton0239aac2018-05-19 00:03:136502 spdy::SpdySerializedFrame stream1_headers(
6503 spdy_util_.ConstructSpdyResponseHeaders(1, std::move(late_headers),
6504 false));
6505 spdy::SpdySerializedFrame stream1_body2(
6506 spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]d08358502010-12-03 22:04:036507 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:416508 CreateMockRead(stream1_reply, 1), CreateMockRead(stream1_body, 2),
6509 CreateMockRead(stream1_headers, 3), CreateMockRead(stream1_body2, 4),
rch08e3aa3e2015-05-16 14:27:526510 MockRead(ASYNC, 0, 6) // EOF
[email protected]d08358502010-12-03 22:04:036511 };
6512
Ryan Sleevib8d7ea02018-05-07 20:01:016513 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:106514 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]dd54bd82012-07-19 23:44:576515 helper.RunToCompletion(&data);
[email protected]d08358502010-12-03 22:04:036516 TransactionHelperResult out = helper.output();
Bence Békyd0d69502019-06-25 19:47:186517 EXPECT_THAT(out.rv, IsError(ERR_HTTP2_PROTOCOL_ERROR));
[email protected]d08358502010-12-03 22:04:036518}
6519
Bence Békye7023f82018-05-14 01:53:036520struct PushUrlTestParams {
6521 const char* url_to_fetch;
6522 const char* url_to_push;
Bence Békyb2f76672018-06-11 21:10:136523 bool client_cert_sent;
Matt Menkec74a9262020-06-09 15:49:216524 bool expect_ct_error;
Bence Békyeacd48f2018-05-14 11:34:336525 SpdyPushedStreamFate expected_fate;
Bence Békye7023f82018-05-14 01:53:036526} push_url_test_cases[] = {
6527 // http scheme cannot be pushed (except by trusted proxy).
Matt Menkec74a9262020-06-09 15:49:216528 {"https://www.example.org/foo.html", "http://www.example.org/foo.js",
6529 false /* client_cert_sent */, false /* expect_ct_error */,
Bence Békyeacd48f2018-05-14 11:34:336530 SpdyPushedStreamFate::kNonHttpsPushedScheme},
Bence Békye7023f82018-05-14 01:53:036531 // ftp scheme cannot be pushed.
Matt Menkec74a9262020-06-09 15:49:216532 {"https://www.example.org/foo.html", "ftp://www.example.org/foo.js",
6533 false /* client_cert_sent */, false /* expect_ct_error */,
Bence Békyeacd48f2018-05-14 11:34:336534 SpdyPushedStreamFate::kInvalidUrl},
Bence Békye7023f82018-05-14 01:53:036535 // Cross subdomain, certificate not valid.
Bence Békyeacd48f2018-05-14 11:34:336536 {"https://www.example.org/foo.html", "https://blat.www.example.org/foo.js",
Matt Menkec74a9262020-06-09 15:49:216537 false /* client_cert_sent */, false /* expect_ct_error */,
6538 SpdyPushedStreamFate::kCertificateMismatch},
Bence Békye7023f82018-05-14 01:53:036539 // Cross domain, certificate not valid.
Matt Menkec74a9262020-06-09 15:49:216540 {"https://www.example.org/foo.html", "https://www.foo.com/foo.js",
6541 false /* client_cert_sent */, false /* expect_ct_error */,
Bence Békyb2f76672018-06-11 21:10:136542 SpdyPushedStreamFate::kCertificateMismatch},
6543 // Cross domain, certificate valid, but cross-origin push is rejected on a
6544 // connection with client certificate.
6545 {"https://www.example.org/foo.html", "https://mail.example.org/foo.js",
Matt Menkec74a9262020-06-09 15:49:216546 true /* client_cert_sent */, false /* expect_ct_error */,
6547 SpdyPushedStreamFate::kCertificateMismatch},
6548 // Cross domain, certificate valid, but cross-origin push is rejected on a
6549 // connection with an Expect-CT error.
6550 {"https://www.example.org/foo.html", "https://mail.example.org/foo.js",
6551 false /* client_cert_sent */, true /* expect_ct_error */,
6552 SpdyPushedStreamFate::kCertificateMismatch}};
Bence Békye7023f82018-05-14 01:53:036553
6554class SpdyNetworkTransactionPushUrlTest
6555 : public SpdyNetworkTransactionTest,
6556 public ::testing::WithParamInterface<PushUrlTestParams> {
Matt Menkec74a9262020-06-09 15:49:216557 public:
6558 SpdyNetworkTransactionPushUrlTest() {
6559 // Set features needed for the |expect_ct_error| case, where it's important
6560 // to check that NetworkIsolationKeys are respected.
6561 feature_list_.InitWithFeatures(
6562 /* enabled_features */
6563 {TransportSecurityState::kDynamicExpectCTFeature,
6564 features::kPartitionExpectCTStateByNetworkIsolationKey,
6565 features::kPartitionConnectionsByNetworkIsolationKey,
6566 features::kPartitionSSLSessionsByNetworkIsolationKey},
6567 /* disabled_features */
6568 {});
6569 }
6570
Bence Békye7023f82018-05-14 01:53:036571 protected:
[email protected]a7a265ef2010-12-08 18:05:576572 // In this test we want to verify that we can't accidentally push content
6573 // which can't be pushed by this content server.
6574 // This test assumes that:
6575 // - if we're requesting http://www.foo.com/barbaz
6576 // - the browser has made a connection to "www.foo.com".
Bence Békye7023f82018-05-14 01:53:036577 void RunTest() {
Bence Békyeacd48f2018-05-14 11:34:336578 base::HistogramTester histogram_tester;
6579
bncd16676a2016-07-20 16:23:016580 SpdyTestUtil spdy_test_util;
Ryan Hamilton0239aac2018-05-19 00:03:136581 spdy::SpdySerializedFrame stream1_syn(
Bence Békye7023f82018-05-14 01:53:036582 spdy_test_util.ConstructSpdyGet(GetParam().url_to_fetch, 1, LOWEST));
Ryan Hamilton0239aac2018-05-19 00:03:136583 spdy::SpdySerializedFrame stream1_body(
bncdf80d44fd2016-07-15 20:27:416584 spdy_test_util.ConstructSpdyDataFrame(1, true));
Ryan Hamilton0239aac2018-05-19 00:03:136585 spdy::SpdySerializedFrame push_rst(spdy_test_util.ConstructSpdyRstStream(
6586 2, spdy::ERROR_CODE_REFUSED_STREAM));
[email protected]a7a265ef2010-12-08 18:05:576587 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:416588 CreateMockWrite(stream1_syn, 0), CreateMockWrite(push_rst, 3),
[email protected]a7a265ef2010-12-08 18:05:576589 };
6590
Ryan Hamilton0239aac2018-05-19 00:03:136591 spdy::SpdySerializedFrame stream1_reply(
bnc42331402016-07-25 13:36:156592 spdy_test_util.ConstructSpdyGetReply(nullptr, 0, 1));
Ryan Hamilton0239aac2018-05-19 00:03:136593 spdy::SpdySerializedFrame stream2_syn(spdy_test_util.ConstructSpdyPush(
Bence Békye7023f82018-05-14 01:53:036594 nullptr, 0, 2, 1, GetParam().url_to_push));
[email protected]8a0fc822013-06-27 20:52:436595 const char kPushedData[] = "pushed";
Ryan Hamilton0239aac2018-05-19 00:03:136596 spdy::SpdySerializedFrame stream2_body(
Bence Békyd74f4382018-02-20 18:26:196597 spdy_test_util.ConstructSpdyDataFrame(2, kPushedData, true));
Ryan Hamilton0239aac2018-05-19 00:03:136598 spdy::SpdySerializedFrame rst(
6599 spdy_test_util.ConstructSpdyRstStream(2, spdy::ERROR_CODE_CANCEL));
[email protected]a7a265ef2010-12-08 18:05:576600
6601 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:416602 CreateMockRead(stream1_reply, 1),
6603 CreateMockRead(stream2_syn, 2),
6604 CreateMockRead(stream1_body, 4),
6605 CreateMockRead(stream2_body, 5),
rch08e3aa3e2015-05-16 14:27:526606 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 6), // Force a pause
[email protected]a7a265ef2010-12-08 18:05:576607 };
6608
6609 HttpResponseInfo response;
Ryan Sleevib8d7ea02018-05-07 20:01:016610 SequencedSocketData data(reads, writes);
[email protected]a7a265ef2010-12-08 18:05:576611
Bence Békye7023f82018-05-14 01:53:036612 request_.url = GURL(GetParam().url_to_fetch);
Matt Menkec74a9262020-06-09 15:49:216613 // Set a NetworkIsolationKey for the |expect_ct_error| case, to make sure
6614 // NetworkIsolationKeys are respected.
6615 request_.network_isolation_key = NetworkIsolationKey::CreateTransient();
[email protected]a7a265ef2010-12-08 18:05:576616
Bence Békyb2f76672018-06-11 21:10:136617 auto ssl_provider = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
6618 ssl_provider->ssl_info.client_cert_sent = GetParam().client_cert_sent;
6619 ssl_provider->ssl_info.cert =
6620 ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem");
Eric Orthfc0583b2021-05-18 19:13:596621 auto session_deps = std::make_unique<SpdySessionDependencies>();
Matt Menkec74a9262020-06-09 15:49:216622 if (GetParam().expect_ct_error) {
6623 ssl_provider->ssl_info.ct_policy_compliance =
6624 ct::CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS;
6625 ssl_provider->ssl_info.is_issued_by_known_root = true;
6626
6627 session_deps->transport_security_state->AddExpectCT(
6628 "mail.example.org",
6629 base::Time::Now() + base::TimeDelta::FromDays(1) /* expiry */, true,
6630 GURL(), request_.network_isolation_key);
6631 }
6632
6633 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
6634 std::move(session_deps));
6635
6636 helper.RunPreTestSetup();
6637
6638 if (GetParam().expect_ct_error) {
6639 ssl_provider->ssl_info.ct_policy_compliance =
6640 ct::CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS;
6641 ssl_provider->ssl_info.is_issued_by_known_root = true;
6642 }
6643
Bence Békyb2f76672018-06-11 21:10:136644 helper.AddDataWithSSLSocketDataProvider(&data, std::move(ssl_provider));
[email protected]7c6f7ba2012-04-03 04:09:296645
[email protected]a7a265ef2010-12-08 18:05:576646 HttpNetworkTransaction* trans = helper.trans();
6647
6648 // Start the transaction with basic parameters.
[email protected]49639fa2011-12-20 23:22:416649 TestCompletionCallback callback;
[email protected]a7a265ef2010-12-08 18:05:576650
Bence Békydb3cf652017-10-10 15:22:106651 int rv = trans->Start(&request_, callback.callback(), log_);
robpercival214763f2016-07-01 23:27:016652 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]a7a265ef2010-12-08 18:05:576653 rv = callback.WaitForResult();
6654
bnceb9aa7112017-01-05 01:03:466655 // Finish async network reads/writes.
6656 base::RunLoop().RunUntilIdle();
6657
[email protected]a7a265ef2010-12-08 18:05:576658 // Read the response body.
Bence Béky4e83f492018-05-13 23:14:256659 std::string result;
rch0aecfd82015-05-19 17:22:326660 ReadResult(trans, &result);
[email protected]a7a265ef2010-12-08 18:05:576661
6662 // Verify that we consumed all test data.
rch37de576c2015-05-17 20:28:176663 EXPECT_TRUE(data.AllReadDataConsumed());
6664 EXPECT_TRUE(data.AllWriteDataConsumed());
[email protected]a7a265ef2010-12-08 18:05:576665
bnc42331402016-07-25 13:36:156666 // Verify the response headers.
[email protected]a7a265ef2010-12-08 18:05:576667 // Copy the response info, because trans goes away.
6668 response = *trans->GetResponseInfo();
6669
6670 VerifyStreamsClosed(helper);
6671
bnc42331402016-07-25 13:36:156672 // Verify the response headers.
wezca1070932016-05-26 20:30:526673 EXPECT_TRUE(response.headers);
bnc84e7fb52015-12-02 11:50:026674 EXPECT_EQ("HTTP/1.1 200", response.headers->GetStatusLine());
Bence Békyeacd48f2018-05-14 11:34:336675
6676 histogram_tester.ExpectBucketCount(
6677 "Net.SpdyPushedStreamFate", static_cast<int>(GetParam().expected_fate),
6678 1);
6679 histogram_tester.ExpectTotalCount("Net.SpdyPushedStreamFate", 1);
[email protected]a7a265ef2010-12-08 18:05:576680 }
Matt Menkec74a9262020-06-09 15:49:216681
6682 base::test::ScopedFeatureList feature_list_;
Bence Békye7023f82018-05-14 01:53:036683};
6684
Ilia Samsonov958c9fef2019-11-20 21:37:316685INSTANTIATE_TEST_SUITE_P(All,
Victor Costan2309ea02019-02-13 21:35:476686 SpdyNetworkTransactionPushUrlTest,
6687 ::testing::ValuesIn(push_url_test_cases));
Bence Békye7023f82018-05-14 01:53:036688
6689TEST_P(SpdyNetworkTransactionPushUrlTest, PushUrlTest) {
6690 RunTest();
[email protected]a7a265ef2010-12-08 18:05:576691}
6692
bnc3e79387f2016-03-15 14:49:206693// Verify that push works cross origin as long as the certificate is valid for
6694// the pushed authority.
bncd16676a2016-07-20 16:23:016695TEST_F(SpdyNetworkTransactionTest, ServerPushValidCrossOrigin) {
bnc3e79387f2016-03-15 14:49:206696 // "spdy_pooling.pem" is valid for both www.example.org and mail.example.org.
6697 const char* url_to_fetch = "https://www.example.org";
6698 const char* url_to_push = "https://mail.example.org";
6699
Ryan Hamilton0239aac2018-05-19 00:03:136700 spdy::SpdySerializedFrame headers(
bnc3e79387f2016-03-15 14:49:206701 spdy_util_.ConstructSpdyGet(url_to_fetch, 1, LOWEST));
Ryan Hamilton0239aac2018-05-19 00:03:136702 spdy::SpdySerializedFrame push_priority(
tombergan5d22c182017-01-11 02:05:356703 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true));
bnc3e79387f2016-03-15 14:49:206704 MockWrite writes[] = {
tombergan5d22c182017-01-11 02:05:356705 CreateMockWrite(headers, 0), CreateMockWrite(push_priority, 3),
bnc3e79387f2016-03-15 14:49:206706 };
6707
Ryan Hamilton0239aac2018-05-19 00:03:136708 spdy::SpdySerializedFrame reply(
6709 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
6710 spdy::SpdySerializedFrame push(
bnc3e79387f2016-03-15 14:49:206711 spdy_util_.ConstructSpdyPush(nullptr, 0, 2, 1, url_to_push));
Ryan Hamilton0239aac2018-05-19 00:03:136712 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
bnc3e79387f2016-03-15 14:49:206713 const char kPushedData[] = "pushed";
Ryan Hamilton0239aac2018-05-19 00:03:136714 spdy::SpdySerializedFrame pushed_body(
Bence Békyd74f4382018-02-20 18:26:196715 spdy_util_.ConstructSpdyDataFrame(2, kPushedData, true));
bnc3e79387f2016-03-15 14:49:206716 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:416717 CreateMockRead(reply, 1),
bnceb9aa7112017-01-05 01:03:466718 CreateMockRead(push, 2, SYNCHRONOUS),
tombergan5d22c182017-01-11 02:05:356719 CreateMockRead(body, 4),
6720 CreateMockRead(pushed_body, 5, SYNCHRONOUS),
6721 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 6),
bnc3e79387f2016-03-15 14:49:206722 };
6723
Ryan Sleevib8d7ea02018-05-07 20:01:016724 SequencedSocketData data(reads, writes);
bnc3e79387f2016-03-15 14:49:206725
Bence Békydb3cf652017-10-10 15:22:106726 request_.url = GURL(url_to_fetch);
bnc3e79387f2016-03-15 14:49:206727
Bence Békydb3cf652017-10-10 15:22:106728 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
bnc3e79387f2016-03-15 14:49:206729 helper.RunPreTestSetup();
6730 helper.AddData(&data);
6731
6732 HttpNetworkTransaction* trans0 = helper.trans();
6733 TestCompletionCallback callback0;
Bence Békydb3cf652017-10-10 15:22:106734 int rv = trans0->Start(&request_, callback0.callback(), log_);
bnc3e79387f2016-03-15 14:49:206735 rv = callback0.GetResult(rv);
robpercival214763f2016-07-01 23:27:016736 EXPECT_THAT(rv, IsOk());
bnc3e79387f2016-03-15 14:49:206737
6738 SpdySessionPool* spdy_session_pool = helper.session()->spdy_session_pool();
bncb26024382016-06-29 02:39:456739 SpdySessionKey key(host_port_pair_, ProxyServer::Direct(),
Matt Menke2436b2f2018-12-11 18:07:116740 PRIVACY_MODE_DISABLED,
dalyk51ab46b2019-10-15 15:14:346741 SpdySessionKey::IsProxySession::kFalse, SocketTag(),
Ben Schwartz3ff4dc1e62021-04-27 21:15:236742 NetworkIsolationKey(), SecureDnsPolicy::kAllow);
bnc3e79387f2016-03-15 14:49:206743 base::WeakPtr<SpdySession> spdy_session =
bnc9ead3ae2017-03-16 00:48:156744 spdy_session_pool->FindAvailableSession(
Bence Békyd885b2b2018-02-03 00:58:316745 key, /* enable_ip_based_pooling = */ true,
6746 /* is_websocket = */ false, log_);
bnc3e79387f2016-03-15 14:49:206747
Bence Béky285e7d42017-12-04 20:22:116748 EXPECT_EQ(1u, num_unclaimed_pushed_streams(spdy_session));
Bence Béky3b609012017-12-04 15:19:356749 EXPECT_TRUE(
Bence Béky285e7d42017-12-04 20:22:116750 has_unclaimed_pushed_stream_for_url(spdy_session, GURL(url_to_push)));
bnc3e79387f2016-03-15 14:49:206751
bnc691fda62016-08-12 00:43:166752 HttpNetworkTransaction trans1(DEFAULT_PRIORITY, helper.session());
bnc3e79387f2016-03-15 14:49:206753 HttpRequestInfo push_request;
6754 push_request.method = "GET";
6755 push_request.url = GURL(url_to_push);
Ramin Halavatib5e433e62018-02-07 07:41:106756 push_request.traffic_annotation =
6757 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
bnc3e79387f2016-03-15 14:49:206758 TestCompletionCallback callback1;
Bence Békyd3dde832017-09-19 19:02:316759 rv = trans1.Start(&push_request, callback1.callback(), log_);
bnc3e79387f2016-03-15 14:49:206760 rv = callback1.GetResult(rv);
robpercival214763f2016-07-01 23:27:016761 EXPECT_THAT(rv, IsOk());
bnc3e79387f2016-03-15 14:49:206762
Bence Béky285e7d42017-12-04 20:22:116763 EXPECT_EQ(0u, num_unclaimed_pushed_streams(spdy_session));
bnc3e79387f2016-03-15 14:49:206764
bnc3e79387f2016-03-15 14:49:206765 HttpResponseInfo response = *trans0->GetResponseInfo();
wezca1070932016-05-26 20:30:526766 EXPECT_TRUE(response.headers);
bnc3e79387f2016-03-15 14:49:206767 EXPECT_EQ("HTTP/1.1 200", response.headers->GetStatusLine());
6768
Bence Béky4e83f492018-05-13 23:14:256769 std::string result0;
bnc3e79387f2016-03-15 14:49:206770 ReadResult(trans0, &result0);
6771 EXPECT_EQ("hello!", result0);
6772
bnc691fda62016-08-12 00:43:166773 HttpResponseInfo push_response = *trans1.GetResponseInfo();
wezca1070932016-05-26 20:30:526774 EXPECT_TRUE(push_response.headers);
bnc3e79387f2016-03-15 14:49:206775 EXPECT_EQ("HTTP/1.1 200", push_response.headers->GetStatusLine());
6776
Bence Béky4e83f492018-05-13 23:14:256777 std::string result1;
bnc691fda62016-08-12 00:43:166778 ReadResult(&trans1, &result1);
bnc3e79387f2016-03-15 14:49:206779 EXPECT_EQ(kPushedData, result1);
tombergan5d22c182017-01-11 02:05:356780
6781 base::RunLoop().RunUntilIdle();
6782 helper.VerifyDataConsumed();
6783 VerifyStreamsClosed(helper);
bnc3e79387f2016-03-15 14:49:206784}
6785
Matt Menkedf93ff72020-07-16 02:23:036786// Verify that push does not work cross origin when NetworkIsolationKeys don't
6787// match.
6788TEST_F(SpdyNetworkTransactionTest,
6789 ServerPushCrossOriginNetworkIsolationKeyMistmatch) {
6790 base::test::ScopedFeatureList feature_list;
6791 feature_list.InitWithFeatures(
6792 // enabled_features
6793 {features::kPartitionHttpServerPropertiesByNetworkIsolationKey,
6794 // Need to partition connections by NetworkIsolationKey for
6795 // SpdySessionKeys to include NetworkIsolationKeys.
6796 features::kPartitionConnectionsByNetworkIsolationKey},
6797 // disabled_features
6798 {});
6799
6800 // "spdy_pooling.pem" is valid for both www.example.org and mail.example.org.
6801 const char* url_to_fetch = "https://www.example.org";
6802 const char* url_to_push = "https://mail.example.org";
6803
6804 spdy::SpdySerializedFrame headers(
6805 spdy_util_.ConstructSpdyGet(url_to_fetch, 1, LOWEST));
6806 spdy::SpdySerializedFrame push_priority(
6807 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true));
6808 MockWrite writes[] = {
6809 CreateMockWrite(headers, 0),
6810 CreateMockWrite(push_priority, 3),
6811 };
6812
6813 spdy::SpdySerializedFrame reply(
6814 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
6815 spdy::SpdySerializedFrame push(
6816 spdy_util_.ConstructSpdyPush(nullptr, 0, 2, 1, url_to_push));
6817 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
6818 const char kPushedData[] = "pushed";
6819 spdy::SpdySerializedFrame pushed_body(
6820 spdy_util_.ConstructSpdyDataFrame(2, kPushedData, true));
6821 MockRead reads[] = {
6822 CreateMockRead(reply, 1),
6823 CreateMockRead(push, 2, SYNCHRONOUS),
6824 CreateMockRead(body, 4),
6825 CreateMockRead(pushed_body, 5, SYNCHRONOUS),
6826 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 6),
6827 };
6828
6829 SequencedSocketData data(reads, writes);
6830
6831 request_.url = GURL(url_to_fetch);
6832
6833 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
6834 helper.RunPreTestSetup();
6835 helper.AddData(&data);
6836
6837 SequencedSocketData data2(net::MockConnect(ASYNC, net::ERR_FAILED),
6838 base::span<MockRead>(), base::span<MockWrite>());
6839 helper.AddData(&data2);
6840
6841 HttpNetworkTransaction* trans0 = helper.trans();
6842 TestCompletionCallback callback0;
6843 int rv = trans0->Start(&request_, callback0.callback(), log_);
6844 rv = callback0.GetResult(rv);
6845 EXPECT_THAT(rv, IsOk());
6846
6847 SpdySessionPool* spdy_session_pool = helper.session()->spdy_session_pool();
6848 SpdySessionKey key(host_port_pair_, ProxyServer::Direct(),
6849 PRIVACY_MODE_DISABLED,
6850 SpdySessionKey::IsProxySession::kFalse, SocketTag(),
Ben Schwartz3ff4dc1e62021-04-27 21:15:236851 NetworkIsolationKey(), SecureDnsPolicy::kAllow);
Matt Menkedf93ff72020-07-16 02:23:036852 base::WeakPtr<SpdySession> spdy_session =
6853 spdy_session_pool->FindAvailableSession(
6854 key, /* enable_ip_based_pooling = */ true,
6855 /* is_websocket = */ false, log_);
6856
6857 EXPECT_EQ(1u, num_unclaimed_pushed_streams(spdy_session));
6858 EXPECT_TRUE(
6859 has_unclaimed_pushed_stream_for_url(spdy_session, GURL(url_to_push)));
6860
6861 HttpNetworkTransaction trans1(DEFAULT_PRIORITY, helper.session());
6862 HttpRequestInfo push_request;
6863 // Use a different NetworkIsolationKey than |spdy_session| (which uses an
6864 // empty one).
6865 push_request.network_isolation_key = NetworkIsolationKey::CreateTransient();
6866 push_request.method = "GET";
6867 push_request.url = GURL(url_to_push);
6868 push_request.traffic_annotation =
6869 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
6870 TestCompletionCallback callback1;
6871 rv = trans1.Start(&push_request, callback1.callback(), log_);
6872 // This transaction should try and use a new socket, which fails.
6873 EXPECT_THAT(callback1.GetResult(rv), IsError(net::ERR_FAILED));
6874
6875 // The pushed stream should still be pending.
6876 EXPECT_EQ(1u, num_unclaimed_pushed_streams(spdy_session));
6877
6878 // Try again, this time with an empty NetworkIsolationKey, matching the
6879 // SpdySession's. This request should successfully get the pushed stream.
6880 HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session());
6881 push_request.network_isolation_key = NetworkIsolationKey();
6882 TestCompletionCallback callback2;
6883 rv = trans1.Start(&push_request, callback2.callback(), log_);
6884 EXPECT_THAT(callback2.GetResult(rv), IsOk());
6885
6886 HttpResponseInfo response = *trans0->GetResponseInfo();
6887 EXPECT_TRUE(response.headers);
6888 EXPECT_EQ("HTTP/1.1 200", response.headers->GetStatusLine());
6889
6890 std::string result0;
6891 ReadResult(trans0, &result0);
6892 EXPECT_EQ("hello!", result0);
6893
6894 HttpResponseInfo push_response = *trans1.GetResponseInfo();
6895 EXPECT_TRUE(push_response.headers);
6896 EXPECT_EQ("HTTP/1.1 200", push_response.headers->GetStatusLine());
6897
6898 std::string result1;
6899 ReadResult(&trans1, &result1);
6900 EXPECT_EQ(kPushedData, result1);
6901
6902 base::RunLoop().RunUntilIdle();
6903 helper.VerifyDataConsumed();
6904 VerifyStreamsClosed(helper);
6905}
6906
Bence Békyb2f76672018-06-11 21:10:136907// Regression test for https://crbug.com/832859: Server push is accepted on a
6908// connection with client certificate, as long as SpdySessionKey matches.
6909TEST_F(SpdyNetworkTransactionTest, ServerPushWithClientCert) {
6910 spdy::SpdySerializedFrame req(
6911 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, DEFAULT_PRIORITY));
6912 spdy::SpdySerializedFrame priority(
6913 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true));
6914 MockWrite writes[] = {CreateMockWrite(req, 0), CreateMockWrite(priority, 3)};
6915
6916 spdy::SpdySerializedFrame resp(
6917 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
6918 spdy::SpdySerializedFrame push(
6919 spdy_util_.ConstructSpdyPush(nullptr, 0, 2, 1, kPushedUrl));
6920 spdy::SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true));
6921 spdy::SpdySerializedFrame body2(
6922 spdy_util_.ConstructSpdyDataFrame(2, "pushed", true));
6923 MockRead reads[] = {CreateMockRead(resp, 1), CreateMockRead(push, 2),
6924 CreateMockRead(body1, 4), CreateMockRead(body2, 5),
6925 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 6)};
6926
6927 SequencedSocketData data(reads, writes);
6928
6929 auto ssl_provider = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
6930 ssl_provider->ssl_info.client_cert_sent = true;
6931 ssl_provider->ssl_info.cert =
6932 ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem");
6933
6934 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
6935 helper.RunPreTestSetup();
6936 helper.AddDataWithSSLSocketDataProvider(&data, std::move(ssl_provider));
6937
6938 EXPECT_TRUE(helper.StartDefaultTest());
6939 helper.FinishDefaultTest();
6940
6941 HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session());
6942 HttpRequestInfo request = CreateGetPushRequest();
6943 TestCompletionCallback callback;
6944 int rv = trans2.Start(&request, callback.callback(), log_);
6945 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
6946
6947 rv = callback.WaitForResult();
6948 EXPECT_THAT(rv, IsOk());
6949
6950 const HttpResponseInfo* const response = trans2.GetResponseInfo();
6951 EXPECT_TRUE(response->headers);
6952 EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
6953
6954 std::string result;
6955 ReadResult(&trans2, &result);
6956 EXPECT_EQ("pushed", result);
6957
6958 EXPECT_TRUE(data.AllReadDataConsumed());
6959 EXPECT_TRUE(data.AllWriteDataConsumed());
6960
6961 VerifyStreamsClosed(helper);
6962}
6963
bnc3e79387f2016-03-15 14:49:206964// Verify that push works cross origin, even if there is already a connection
6965// open to origin of pushed resource.
bncd16676a2016-07-20 16:23:016966TEST_F(SpdyNetworkTransactionTest, ServerPushValidCrossOriginWithOpenSession) {
bnc3e79387f2016-03-15 14:49:206967 const char* url_to_fetch0 = "https://mail.example.org/foo";
6968 const char* url_to_fetch1 = "https://docs.example.org";
6969 const char* url_to_push = "https://mail.example.org/bar";
6970
bncd16676a2016-07-20 16:23:016971 SpdyTestUtil spdy_util_0;
bnc3e79387f2016-03-15 14:49:206972
Ryan Hamilton0239aac2018-05-19 00:03:136973 spdy::SpdySerializedFrame headers0(
bnc3e79387f2016-03-15 14:49:206974 spdy_util_0.ConstructSpdyGet(url_to_fetch0, 1, LOWEST));
6975 MockWrite writes0[] = {
bncdf80d44fd2016-07-15 20:27:416976 CreateMockWrite(headers0, 0),
bnc3e79387f2016-03-15 14:49:206977 };
6978
Ryan Hamilton0239aac2018-05-19 00:03:136979 spdy::SpdySerializedFrame reply0(
6980 spdy_util_0.ConstructSpdyGetReply(nullptr, 0, 1));
bnc3e79387f2016-03-15 14:49:206981 const char kData0[] = "first";
Ryan Hamilton0239aac2018-05-19 00:03:136982 spdy::SpdySerializedFrame body0(
Bence Békyd74f4382018-02-20 18:26:196983 spdy_util_0.ConstructSpdyDataFrame(1, kData0, true));
bncdf80d44fd2016-07-15 20:27:416984 MockRead reads0[] = {CreateMockRead(reply0, 1), CreateMockRead(body0, 2),
6985 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 3)};
bnc3e79387f2016-03-15 14:49:206986
Ryan Sleevib8d7ea02018-05-07 20:01:016987 SequencedSocketData data0(reads0, writes0);
bnc3e79387f2016-03-15 14:49:206988
bncd16676a2016-07-20 16:23:016989 SpdyTestUtil spdy_util_1;
bnc3e79387f2016-03-15 14:49:206990
Ryan Hamilton0239aac2018-05-19 00:03:136991 spdy::SpdySerializedFrame headers1(
bnc3e79387f2016-03-15 14:49:206992 spdy_util_1.ConstructSpdyGet(url_to_fetch1, 1, LOWEST));
Ryan Hamilton0239aac2018-05-19 00:03:136993 spdy::SpdySerializedFrame push_priority(
tombergan5d22c182017-01-11 02:05:356994 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true));
bnc3e79387f2016-03-15 14:49:206995 MockWrite writes1[] = {
bncdf80d44fd2016-07-15 20:27:416996 CreateMockWrite(headers1, 0),
tombergan5d22c182017-01-11 02:05:356997 CreateMockWrite(push_priority, 3, SYNCHRONOUS),
bnc3e79387f2016-03-15 14:49:206998 };
6999
Ryan Hamilton0239aac2018-05-19 00:03:137000 spdy::SpdySerializedFrame reply1(
7001 spdy_util_1.ConstructSpdyGetReply(nullptr, 0, 1));
7002 spdy::SpdySerializedFrame push(
bnc3e79387f2016-03-15 14:49:207003 spdy_util_1.ConstructSpdyPush(nullptr, 0, 2, 1, url_to_push));
7004 const char kData1[] = "second";
Ryan Hamilton0239aac2018-05-19 00:03:137005 spdy::SpdySerializedFrame body1(
Bence Békyd74f4382018-02-20 18:26:197006 spdy_util_1.ConstructSpdyDataFrame(1, kData1, true));
bnc3e79387f2016-03-15 14:49:207007 const char kPushedData[] = "pushed";
Ryan Hamilton0239aac2018-05-19 00:03:137008 spdy::SpdySerializedFrame pushed_body(
Bence Békyd74f4382018-02-20 18:26:197009 spdy_util_1.ConstructSpdyDataFrame(2, kPushedData, true));
bnc3e79387f2016-03-15 14:49:207010
7011 MockRead reads1[] = {
bncdf80d44fd2016-07-15 20:27:417012 CreateMockRead(reply1, 1),
bnceb9aa7112017-01-05 01:03:467013 CreateMockRead(push, 2, SYNCHRONOUS),
tombergan5d22c182017-01-11 02:05:357014 CreateMockRead(body1, 4),
7015 CreateMockRead(pushed_body, 5, SYNCHRONOUS),
7016 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 6),
bnc3e79387f2016-03-15 14:49:207017 };
7018
Ryan Sleevib8d7ea02018-05-07 20:01:017019 SequencedSocketData data1(reads1, writes1);
bnc3e79387f2016-03-15 14:49:207020
7021 // Request |url_to_fetch0| to open connection to mail.example.org.
Bence Békydb3cf652017-10-10 15:22:107022 request_.url = GURL(url_to_fetch0);
bnc3e79387f2016-03-15 14:49:207023
Bence Békydb3cf652017-10-10 15:22:107024 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
bnc3e79387f2016-03-15 14:49:207025 helper.RunPreTestSetup();
7026
7027 // "spdy_pooling.pem" is valid for www.example.org, but not for
7028 // docs.example.org.
Jeremy Roman0579ed62017-08-29 15:56:197029 auto ssl_provider0 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
Ryan Sleevi4f832092017-11-21 23:25:497030 ssl_provider0->ssl_info.cert =
bnc3e79387f2016-03-15 14:49:207031 ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem");
Ryan Sleevi4f832092017-11-21 23:25:497032 ASSERT_TRUE(ssl_provider0->ssl_info.cert);
bnc3e79387f2016-03-15 14:49:207033 helper.AddDataWithSSLSocketDataProvider(&data0, std::move(ssl_provider0));
7034
7035 // "wildcard.pem" is valid for both www.example.org and docs.example.org.
Jeremy Roman0579ed62017-08-29 15:56:197036 auto ssl_provider1 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
Ryan Sleevi4f832092017-11-21 23:25:497037 ssl_provider1->ssl_info.cert =
bnc3e79387f2016-03-15 14:49:207038 ImportCertFromFile(GetTestCertsDirectory(), "wildcard.pem");
Ryan Sleevi4f832092017-11-21 23:25:497039 ASSERT_TRUE(ssl_provider1->ssl_info.cert);
bnc3e79387f2016-03-15 14:49:207040 helper.AddDataWithSSLSocketDataProvider(&data1, std::move(ssl_provider1));
7041
7042 HttpNetworkTransaction* trans0 = helper.trans();
7043 TestCompletionCallback callback0;
Bence Békydb3cf652017-10-10 15:22:107044 int rv = trans0->Start(&request_, callback0.callback(), log_);
bnc3e79387f2016-03-15 14:49:207045 rv = callback0.GetResult(rv);
robpercival214763f2016-07-01 23:27:017046 EXPECT_THAT(rv, IsOk());
bnc3e79387f2016-03-15 14:49:207047
7048 // Request |url_to_fetch1|, during which docs.example.org pushes
7049 // |url_to_push|, which happens to be for www.example.org, to which there is
7050 // already an open connection.
bnc691fda62016-08-12 00:43:167051 HttpNetworkTransaction trans1(DEFAULT_PRIORITY, helper.session());
bnc3e79387f2016-03-15 14:49:207052 HttpRequestInfo request1;
7053 request1.method = "GET";
7054 request1.url = GURL(url_to_fetch1);
Ramin Halavatib5e433e62018-02-07 07:41:107055 request1.traffic_annotation =
7056 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
bnc3e79387f2016-03-15 14:49:207057 TestCompletionCallback callback1;
Bence Békyd3dde832017-09-19 19:02:317058 rv = trans1.Start(&request1, callback1.callback(), log_);
bnc3e79387f2016-03-15 14:49:207059 rv = callback1.GetResult(rv);
robpercival214763f2016-07-01 23:27:017060 EXPECT_THAT(rv, IsOk());
bnc3e79387f2016-03-15 14:49:207061
7062 SpdySessionPool* spdy_session_pool = helper.session()->spdy_session_pool();
7063 HostPortPair host_port_pair0("mail.example.org", 443);
7064 SpdySessionKey key0(host_port_pair0, ProxyServer::Direct(),
Matt Menke2436b2f2018-12-11 18:07:117065 PRIVACY_MODE_DISABLED,
dalyk51ab46b2019-10-15 15:14:347066 SpdySessionKey::IsProxySession::kFalse, SocketTag(),
Ben Schwartz3ff4dc1e62021-04-27 21:15:237067 NetworkIsolationKey(), SecureDnsPolicy::kAllow);
bnc3e79387f2016-03-15 14:49:207068 base::WeakPtr<SpdySession> spdy_session0 =
bnc9ead3ae2017-03-16 00:48:157069 spdy_session_pool->FindAvailableSession(
Bence Békyd885b2b2018-02-03 00:58:317070 key0, /* enable_ip_based_pooling = */ true,
7071 /* is_websocket = */ false, log_);
bnc3e79387f2016-03-15 14:49:207072
Bence Béky285e7d42017-12-04 20:22:117073 EXPECT_EQ(0u, num_unclaimed_pushed_streams(spdy_session0));
bnc3e79387f2016-03-15 14:49:207074
7075 HostPortPair host_port_pair1("docs.example.org", 443);
7076 SpdySessionKey key1(host_port_pair1, ProxyServer::Direct(),
Matt Menke2436b2f2018-12-11 18:07:117077 PRIVACY_MODE_DISABLED,
dalyk51ab46b2019-10-15 15:14:347078 SpdySessionKey::IsProxySession::kFalse, SocketTag(),
Ben Schwartz3ff4dc1e62021-04-27 21:15:237079 NetworkIsolationKey(), SecureDnsPolicy::kAllow);
bnc3e79387f2016-03-15 14:49:207080 base::WeakPtr<SpdySession> spdy_session1 =
bnc9ead3ae2017-03-16 00:48:157081 spdy_session_pool->FindAvailableSession(
Bence Békyd885b2b2018-02-03 00:58:317082 key1, /* enable_ip_based_pooling = */ true,
7083 /* is_websocket = */ false, log_);
bnc3e79387f2016-03-15 14:49:207084
Bence Béky285e7d42017-12-04 20:22:117085 EXPECT_EQ(1u, num_unclaimed_pushed_streams(spdy_session1));
Bence Béky3b609012017-12-04 15:19:357086 EXPECT_TRUE(
Bence Béky285e7d42017-12-04 20:22:117087 has_unclaimed_pushed_stream_for_url(spdy_session1, GURL(url_to_push)));
bnc3e79387f2016-03-15 14:49:207088
7089 // Request |url_to_push|, which should be served from the pushed resource.
bnc691fda62016-08-12 00:43:167090 HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session());
bnc3e79387f2016-03-15 14:49:207091 HttpRequestInfo push_request;
7092 push_request.method = "GET";
7093 push_request.url = GURL(url_to_push);
Ramin Halavatib5e433e62018-02-07 07:41:107094 push_request.traffic_annotation =
7095 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
bnc3e79387f2016-03-15 14:49:207096 TestCompletionCallback callback2;
Bence Békyd3dde832017-09-19 19:02:317097 rv = trans2.Start(&push_request, callback2.callback(), log_);
bnc3e79387f2016-03-15 14:49:207098 rv = callback2.GetResult(rv);
robpercival214763f2016-07-01 23:27:017099 EXPECT_THAT(rv, IsOk());
bnc3e79387f2016-03-15 14:49:207100
Bence Béky285e7d42017-12-04 20:22:117101 EXPECT_EQ(0u, num_unclaimed_pushed_streams(spdy_session0));
7102 EXPECT_EQ(0u, num_unclaimed_pushed_streams(spdy_session1));
bnc3e79387f2016-03-15 14:49:207103
bnc3e79387f2016-03-15 14:49:207104 HttpResponseInfo response0 = *trans0->GetResponseInfo();
wezca1070932016-05-26 20:30:527105 EXPECT_TRUE(response0.headers);
bnc3e79387f2016-03-15 14:49:207106 EXPECT_EQ("HTTP/1.1 200", response0.headers->GetStatusLine());
7107
Bence Béky4e83f492018-05-13 23:14:257108 std::string result0;
bnc3e79387f2016-03-15 14:49:207109 ReadResult(trans0, &result0);
7110 EXPECT_EQ(kData0, result0);
7111
bnc691fda62016-08-12 00:43:167112 HttpResponseInfo response1 = *trans1.GetResponseInfo();
wezca1070932016-05-26 20:30:527113 EXPECT_TRUE(response1.headers);
bnc3e79387f2016-03-15 14:49:207114 EXPECT_EQ("HTTP/1.1 200", response1.headers->GetStatusLine());
7115
Bence Béky4e83f492018-05-13 23:14:257116 std::string result1;
bnc691fda62016-08-12 00:43:167117 ReadResult(&trans1, &result1);
bnc3e79387f2016-03-15 14:49:207118 EXPECT_EQ(kData1, result1);
7119
bnc691fda62016-08-12 00:43:167120 HttpResponseInfo push_response = *trans2.GetResponseInfo();
wezca1070932016-05-26 20:30:527121 EXPECT_TRUE(push_response.headers);
bnc3e79387f2016-03-15 14:49:207122 EXPECT_EQ("HTTP/1.1 200", push_response.headers->GetStatusLine());
7123
Bence Béky4e83f492018-05-13 23:14:257124 std::string result2;
bnc691fda62016-08-12 00:43:167125 ReadResult(&trans2, &result2);
bnc3e79387f2016-03-15 14:49:207126 EXPECT_EQ(kPushedData, result2);
tombergan5d22c182017-01-11 02:05:357127
7128 base::RunLoop().RunUntilIdle();
7129 helper.VerifyDataConsumed();
7130 VerifyStreamsClosed(helper);
bnc3e79387f2016-03-15 14:49:207131}
7132
bncd16676a2016-07-20 16:23:017133TEST_F(SpdyNetworkTransactionTest, RetryAfterRefused) {
[email protected]721c0ce2011-10-13 02:41:007134 // Construct the request.
Ryan Hamilton0239aac2018-05-19 00:03:137135 spdy::SpdySerializedFrame req(
7136 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
rdsmithebb50aa2015-11-12 03:44:387137 // Will be destroyed by the RST before stream 3 starts.
7138 spdy_util_.UpdateWithStreamDestruction(1);
Ryan Hamilton0239aac2018-05-19 00:03:137139 spdy::SpdySerializedFrame req2(
7140 spdy_util_.ConstructSpdyGet(nullptr, 0, 3, LOWEST));
[email protected]721c0ce2011-10-13 02:41:007141 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:417142 CreateMockWrite(req, 0), CreateMockWrite(req2, 2),
[email protected]721c0ce2011-10-13 02:41:007143 };
7144
Ryan Hamilton0239aac2018-05-19 00:03:137145 spdy::SpdySerializedFrame refused(
7146 spdy_util_.ConstructSpdyRstStream(1, spdy::ERROR_CODE_REFUSED_STREAM));
7147 spdy::SpdySerializedFrame resp(
7148 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
7149 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(3, true));
[email protected]721c0ce2011-10-13 02:41:007150 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:417151 CreateMockRead(refused, 1), CreateMockRead(resp, 3),
7152 CreateMockRead(body, 4), MockRead(ASYNC, 0, 5) // EOF
[email protected]721c0ce2011-10-13 02:41:007153 };
7154
Ryan Sleevib8d7ea02018-05-07 20:01:017155 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:107156 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]721c0ce2011-10-13 02:41:007157
7158 helper.RunPreTestSetup();
[email protected]dd54bd82012-07-19 23:44:577159 helper.AddData(&data);
[email protected]721c0ce2011-10-13 02:41:007160
7161 HttpNetworkTransaction* trans = helper.trans();
7162
7163 // Start the transaction with basic parameters.
[email protected]49639fa2011-12-20 23:22:417164 TestCompletionCallback callback;
Bence Békydb3cf652017-10-10 15:22:107165 int rv = trans->Start(&request_, callback.callback(), log_);
robpercival214763f2016-07-01 23:27:017166 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]721c0ce2011-10-13 02:41:007167 rv = callback.WaitForResult();
robpercival214763f2016-07-01 23:27:017168 EXPECT_THAT(rv, IsOk());
[email protected]721c0ce2011-10-13 02:41:007169
bnceb9aa7112017-01-05 01:03:467170 // Finish async network reads.
7171 base::RunLoop().RunUntilIdle();
7172
[email protected]721c0ce2011-10-13 02:41:007173 // Verify that we consumed all test data.
rch08e3aa3e2015-05-16 14:27:527174 EXPECT_TRUE(data.AllReadDataConsumed());
7175 EXPECT_TRUE(data.AllWriteDataConsumed());
[email protected]721c0ce2011-10-13 02:41:007176
bnc42331402016-07-25 13:36:157177 // Verify the response headers.
[email protected]721c0ce2011-10-13 02:41:007178 HttpResponseInfo response = *trans->GetResponseInfo();
wezca1070932016-05-26 20:30:527179 EXPECT_TRUE(response.headers);
bnc84e7fb52015-12-02 11:50:027180 EXPECT_EQ("HTTP/1.1 200", response.headers->GetStatusLine());
[email protected]721c0ce2011-10-13 02:41:007181}
7182
bnc42331402016-07-25 13:36:157183TEST_F(SpdyNetworkTransactionTest, OutOfOrderHeaders) {
[email protected]e1f58efa2012-05-15 18:23:407184 // This first request will start to establish the SpdySession.
7185 // Then we will start the second (MEDIUM priority) and then third
7186 // (HIGHEST priority) request in such a way that the third will actually
[email protected]c92f4b4542012-07-26 23:53:217187 // start before the second, causing the second to be numbered differently
[email protected]513963e2013-06-15 01:53:047188 // than the order they were created.
rdsmithebb50aa2015-11-12 03:44:387189 //
7190 // Note that the requests and responses created below are expectations
7191 // of what the above will produce on the wire, and hence are in the
7192 // initial->HIGHEST->LOWEST priority.
7193 //
7194 // Frames are created by SpdySession just before the write associated
7195 // with the frame is attempted, so stream dependencies will be based
7196 // on the streams alive at the point of the request write attempt. Thus
7197 // req1 is alive when req2 is attempted (during but not after the
7198 // |data.RunFor(2);| statement below) but not when req3 is attempted.
7199 // The call to spdy_util_.UpdateWithStreamDestruction() reflects this.
Ryan Hamilton0239aac2018-05-19 00:03:137200 spdy::SpdySerializedFrame req1(
7201 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
7202 spdy::SpdySerializedFrame req2(
7203 spdy_util_.ConstructSpdyGet(nullptr, 0, 3, HIGHEST));
rdsmithebb50aa2015-11-12 03:44:387204 spdy_util_.UpdateWithStreamDestruction(1);
Ryan Hamilton0239aac2018-05-19 00:03:137205 spdy::SpdySerializedFrame req3(
7206 spdy_util_.ConstructSpdyGet(nullptr, 0, 5, MEDIUM));
[email protected]e1f58efa2012-05-15 18:23:407207 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:417208 MockWrite(ASYNC, ERR_IO_PENDING, 0), CreateMockWrite(req1, 1),
7209 CreateMockWrite(req2, 5), CreateMockWrite(req3, 6),
[email protected]e1f58efa2012-05-15 18:23:407210 };
7211
Ryan Hamilton0239aac2018-05-19 00:03:137212 spdy::SpdySerializedFrame resp1(
7213 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
7214 spdy::SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true));
7215 spdy::SpdySerializedFrame resp2(
7216 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
7217 spdy::SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(3, true));
7218 spdy::SpdySerializedFrame resp3(
7219 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 5));
7220 spdy::SpdySerializedFrame body3(spdy_util_.ConstructSpdyDataFrame(5, true));
[email protected]e1f58efa2012-05-15 18:23:407221 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:417222 CreateMockRead(resp1, 2), MockRead(ASYNC, ERR_IO_PENDING, 3),
7223 CreateMockRead(body1, 4), CreateMockRead(resp2, 7),
7224 CreateMockRead(body2, 8), CreateMockRead(resp3, 9),
7225 CreateMockRead(body3, 10), MockRead(ASYNC, 0, 11) // EOF
[email protected]e1f58efa2012-05-15 18:23:407226 };
7227
Ryan Sleevib8d7ea02018-05-07 20:01:017228 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:107229 NormalSpdyTransactionHelper helper(request_, LOWEST, log_, nullptr);
[email protected]e1f58efa2012-05-15 18:23:407230 helper.RunPreTestSetup();
mmenke666a6fea2015-12-19 04:16:337231 helper.AddData(&data);
[email protected]e1f58efa2012-05-15 18:23:407232
7233 // Start the first transaction to set up the SpdySession
7234 HttpNetworkTransaction* trans = helper.trans();
7235 TestCompletionCallback callback;
Bence Békydb3cf652017-10-10 15:22:107236 int rv = trans->Start(&request_, callback.callback(), log_);
robpercival214763f2016-07-01 23:27:017237 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]e1f58efa2012-05-15 18:23:407238
7239 // Run the message loop, but do not allow the write to complete.
7240 // This leaves the SpdySession with a write pending, which prevents
7241 // SpdySession from attempting subsequent writes until this write completes.
[email protected]fc9d88472013-08-14 02:31:177242 base::RunLoop().RunUntilIdle();
[email protected]e1f58efa2012-05-15 18:23:407243
7244 // Now, start both new transactions
[email protected]e1f58efa2012-05-15 18:23:407245 TestCompletionCallback callback2;
bnc691fda62016-08-12 00:43:167246 HttpNetworkTransaction trans2(MEDIUM, helper.session());
Bence Békydb3cf652017-10-10 15:22:107247 rv = trans2.Start(&request_, callback2.callback(), log_);
robpercival214763f2016-07-01 23:27:017248 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]fc9d88472013-08-14 02:31:177249 base::RunLoop().RunUntilIdle();
[email protected]e1f58efa2012-05-15 18:23:407250
[email protected]e1f58efa2012-05-15 18:23:407251 TestCompletionCallback callback3;
bnc691fda62016-08-12 00:43:167252 HttpNetworkTransaction trans3(HIGHEST, helper.session());
Bence Békydb3cf652017-10-10 15:22:107253 rv = trans3.Start(&request_, callback3.callback(), log_);
robpercival214763f2016-07-01 23:27:017254 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]fc9d88472013-08-14 02:31:177255 base::RunLoop().RunUntilIdle();
[email protected]e1f58efa2012-05-15 18:23:407256
bnc42331402016-07-25 13:36:157257 // We now have two HEADERS frames queued up which will be
[email protected]e1f58efa2012-05-15 18:23:407258 // dequeued only once the first write completes, which we
7259 // now allow to happen.
mmenke666a6fea2015-12-19 04:16:337260 ASSERT_TRUE(data.IsPaused());
7261 data.Resume();
robpercival214763f2016-07-01 23:27:017262 EXPECT_THAT(callback.WaitForResult(), IsOk());
[email protected]e1f58efa2012-05-15 18:23:407263
7264 // And now we can allow everything else to run to completion.
mmenke666a6fea2015-12-19 04:16:337265 data.Resume();
7266 base::RunLoop().RunUntilIdle();
robpercival214763f2016-07-01 23:27:017267 EXPECT_THAT(callback2.WaitForResult(), IsOk());
7268 EXPECT_THAT(callback3.WaitForResult(), IsOk());
[email protected]e1f58efa2012-05-15 18:23:407269
7270 helper.VerifyDataConsumed();
krasin0bfeb6b2017-01-13 21:48:047271
7272 // At this point the test is completed and we need to safely destroy
7273 // all allocated structures. Helper stores a transaction that has a
7274 // reference to a stack allocated request, which has a short lifetime,
7275 // and is accessed during the transaction destruction. We need to delete
7276 // the transaction while the request is still a valid object.
7277 helper.ResetTrans();
[email protected]e1f58efa2012-05-15 18:23:407278}
7279
[email protected]d11b6912013-06-27 23:07:327280// Test that sent data frames and received WINDOW_UPDATE frames change
7281// the send_window_size_ correctly.
7282
7283// WINDOW_UPDATE is different than most other frames in that it can arrive
7284// while the client is still sending the request body. In order to enforce
7285// this scenario, we feed a couple of dummy frames and give a delay of 0 to
7286// socket data provider, so that initial read that is done as soon as the
7287// stream is created, succeeds and schedules another read. This way reads
7288// and writes are interleaved; after doing a full frame write, SpdyStream
7289// will break out of DoLoop and will read and process a WINDOW_UPDATE.
bnc42331402016-07-25 13:36:157290// Once our WINDOW_UPDATE is read, we cannot send HEADERS right away
[email protected]d11b6912013-06-27 23:07:327291// since request has not been completely written, therefore we feed
7292// enough number of WINDOW_UPDATEs to finish the first read and cause a
7293// write, leading to a complete write of request body; after that we send
7294// a reply with a body, to cause a graceful shutdown.
7295
7296// TODO(agayev): develop a socket data provider where both, reads and
7297// writes are ordered so that writing tests like these are easy and rewrite
7298// all these tests using it. Right now we are working around the
7299// limitations as described above and it's not deterministic, tests may
7300// fail under specific circumstances.
bncd16676a2016-07-20 16:23:017301TEST_F(SpdyNetworkTransactionTest, WindowUpdateReceived) {
[email protected]d11b6912013-06-27 23:07:327302 static int kFrameCount = 2;
Bence Békyd74f4382018-02-20 18:26:197303 std::string content(kMaxSpdyFrameChunkSize, 'a');
Ryan Hamilton0239aac2018-05-19 00:03:137304 spdy::SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
tombergan5d22c182017-01-11 02:05:357305 kDefaultUrl, 1, kMaxSpdyFrameChunkSize * kFrameCount, LOWEST, nullptr,
7306 0));
Ryan Hamilton0239aac2018-05-19 00:03:137307 spdy::SpdySerializedFrame body(
Bence Békyd74f4382018-02-20 18:26:197308 spdy_util_.ConstructSpdyDataFrame(1, content, false));
Ryan Hamilton0239aac2018-05-19 00:03:137309 spdy::SpdySerializedFrame body_end(
Bence Békyd74f4382018-02-20 18:26:197310 spdy_util_.ConstructSpdyDataFrame(1, content, true));
[email protected]d11b6912013-06-27 23:07:327311
7312 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:417313 CreateMockWrite(req, 0), CreateMockWrite(body, 1),
7314 CreateMockWrite(body_end, 2),
[email protected]d11b6912013-06-27 23:07:327315 };
7316
Avi Drissman13fc8932015-12-20 04:40:467317 static const int32_t kDeltaWindowSize = 0xff;
[email protected]d11b6912013-06-27 23:07:327318 static const int kDeltaCount = 4;
Ryan Hamilton0239aac2018-05-19 00:03:137319 spdy::SpdySerializedFrame window_update(
[email protected]d11b6912013-06-27 23:07:327320 spdy_util_.ConstructSpdyWindowUpdate(1, kDeltaWindowSize));
Ryan Hamilton0239aac2018-05-19 00:03:137321 spdy::SpdySerializedFrame window_update_dummy(
[email protected]d11b6912013-06-27 23:07:327322 spdy_util_.ConstructSpdyWindowUpdate(2, kDeltaWindowSize));
Ryan Hamilton0239aac2018-05-19 00:03:137323 spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
[email protected]d11b6912013-06-27 23:07:327324 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:417325 CreateMockRead(window_update_dummy, 3),
7326 CreateMockRead(window_update_dummy, 4),
7327 CreateMockRead(window_update_dummy, 5),
7328 CreateMockRead(window_update, 6), // Four updates, therefore window
7329 CreateMockRead(window_update, 7), // size should increase by
7330 CreateMockRead(window_update, 8), // kDeltaWindowSize * 4
7331 CreateMockRead(window_update, 9),
7332 CreateMockRead(resp, 10),
7333 MockRead(ASYNC, ERR_IO_PENDING, 11),
7334 CreateMockRead(body_end, 12),
mmenke666a6fea2015-12-19 04:16:337335 MockRead(ASYNC, 0, 13) // EOF
[email protected]d11b6912013-06-27 23:07:327336 };
7337
Ryan Sleevib8d7ea02018-05-07 20:01:017338 SequencedSocketData data(reads, writes);
[email protected]d11b6912013-06-27 23:07:327339
danakjaee3e1ec2016-04-16 00:23:187340 std::vector<std::unique_ptr<UploadElementReader>> element_readers;
[email protected]d11b6912013-06-27 23:07:327341 for (int i = 0; i < kFrameCount; ++i) {
Jeremy Roman0579ed62017-08-29 15:56:197342 element_readers.push_back(std::make_unique<UploadBytesElementReader>(
Bence Békyd74f4382018-02-20 18:26:197343 content.data(), content.size()));
[email protected]d11b6912013-06-27 23:07:327344 }
olli.raula6df48b2a2015-11-26 07:40:227345 ElementsUploadDataStream upload_data_stream(std::move(element_readers), 0);
[email protected]d11b6912013-06-27 23:07:327346
Bence Békydb3cf652017-10-10 15:22:107347 // Setup the request.
7348 request_.method = "POST";
7349 request_.upload_data_stream = &upload_data_stream;
[email protected]d11b6912013-06-27 23:07:327350
Bence Békydb3cf652017-10-10 15:22:107351 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
mmenke666a6fea2015-12-19 04:16:337352 helper.AddData(&data);
[email protected]d11b6912013-06-27 23:07:327353 helper.RunPreTestSetup();
7354
7355 HttpNetworkTransaction* trans = helper.trans();
7356
7357 TestCompletionCallback callback;
Bence Békydb3cf652017-10-10 15:22:107358 int rv = trans->Start(&request_, callback.callback(), log_);
[email protected]d11b6912013-06-27 23:07:327359
robpercival214763f2016-07-01 23:27:017360 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]d11b6912013-06-27 23:07:327361
mmenke666a6fea2015-12-19 04:16:337362 data.RunUntilPaused();
7363 base::RunLoop().RunUntilIdle();
[email protected]d11b6912013-06-27 23:07:327364
7365 SpdyHttpStream* stream = static_cast<SpdyHttpStream*>(trans->stream_.get());
wezca1070932016-05-26 20:30:527366 ASSERT_TRUE(stream);
7367 ASSERT_TRUE(stream->stream());
bncbca843ba2016-07-14 13:05:487368 EXPECT_EQ(static_cast<int>(kDefaultInitialWindowSize) +
7369 kDeltaWindowSize * kDeltaCount -
7370 kMaxSpdyFrameChunkSize * kFrameCount,
7371 stream->stream()->send_window_size());
[email protected]d11b6912013-06-27 23:07:327372
mmenke666a6fea2015-12-19 04:16:337373 data.Resume();
7374 base::RunLoop().RunUntilIdle();
[email protected]d11b6912013-06-27 23:07:327375
7376 rv = callback.WaitForResult();
robpercival214763f2016-07-01 23:27:017377 EXPECT_THAT(rv, IsOk());
[email protected]d11b6912013-06-27 23:07:327378
7379 helper.VerifyDataConsumed();
7380}
7381
7382// Test that received data frames and sent WINDOW_UPDATE frames change
7383// the recv_window_size_ correctly.
bncd16676a2016-07-20 16:23:017384TEST_F(SpdyNetworkTransactionTest, WindowUpdateSent) {
bnc8f0f3b62015-04-08 04:37:237385 // Session level maximum window size that is more than twice the default
7386 // initial window size so that an initial window update is sent.
Avi Drissman13fc8932015-12-20 04:40:467387 const int32_t session_max_recv_window_size = 5 * 64 * 1024;
bncbca843ba2016-07-14 13:05:487388 ASSERT_LT(2 * kDefaultInitialWindowSize, session_max_recv_window_size);
bnc8f0f3b62015-04-08 04:37:237389 // Stream level maximum window size that is less than the session level
7390 // maximum window size so that we test for confusion between the two.
Avi Drissman13fc8932015-12-20 04:40:467391 const int32_t stream_max_recv_window_size = 4 * 64 * 1024;
bnc8f0f3b62015-04-08 04:37:237392 ASSERT_GT(session_max_recv_window_size, stream_max_recv_window_size);
7393 // Size of body to be sent. Has to be less than or equal to both window sizes
7394 // so that we do not run out of receiving window. Also has to be greater than
7395 // half of them so that it triggers both a session level and a stream level
7396 // window update frame.
Avi Drissman13fc8932015-12-20 04:40:467397 const int32_t kTargetSize = 3 * 64 * 1024;
bnc8f0f3b62015-04-08 04:37:237398 ASSERT_GE(session_max_recv_window_size, kTargetSize);
7399 ASSERT_GE(stream_max_recv_window_size, kTargetSize);
7400 ASSERT_LT(session_max_recv_window_size / 2, kTargetSize);
7401 ASSERT_LT(stream_max_recv_window_size / 2, kTargetSize);
7402 // Size of each DATA frame.
Avi Drissman13fc8932015-12-20 04:40:467403 const int32_t kChunkSize = 4096;
bnc8f0f3b62015-04-08 04:37:237404 // Size of window updates.
7405 ASSERT_EQ(0, session_max_recv_window_size / 2 % kChunkSize);
Avi Drissman13fc8932015-12-20 04:40:467406 const int32_t session_window_update_delta =
bnc8f0f3b62015-04-08 04:37:237407 session_max_recv_window_size / 2 + kChunkSize;
7408 ASSERT_EQ(0, stream_max_recv_window_size / 2 % kChunkSize);
Avi Drissman13fc8932015-12-20 04:40:467409 const int32_t stream_window_update_delta =
bnc8f0f3b62015-04-08 04:37:237410 stream_max_recv_window_size / 2 + kChunkSize;
[email protected]d11b6912013-06-27 23:07:327411
Ryan Hamilton0239aac2018-05-19 00:03:137412 spdy::SpdySerializedFrame preface(
7413 const_cast<char*>(spdy::kHttp2ConnectionHeaderPrefix),
7414 spdy::kHttp2ConnectionHeaderPrefixSize,
7415 /* owns_buffer = */ false);
bnc8abf64af2017-06-07 20:18:547416
Ryan Hamilton0239aac2018-05-19 00:03:137417 spdy::SettingsMap initial_settings;
7418 initial_settings[spdy::SETTINGS_HEADER_TABLE_SIZE] = kSpdyMaxHeaderTableSize;
7419 initial_settings[spdy::SETTINGS_MAX_CONCURRENT_STREAMS] =
bnc3171a2432016-12-28 18:40:267420 kSpdyMaxConcurrentPushedStreams;
Ryan Hamilton0239aac2018-05-19 00:03:137421 initial_settings[spdy::SETTINGS_INITIAL_WINDOW_SIZE] =
7422 stream_max_recv_window_size;
Bence Béky6cee52f2019-10-24 16:52:337423 initial_settings[spdy::SETTINGS_MAX_HEADER_LIST_SIZE] =
7424 kSpdyMaxHeaderListSize;
Ryan Hamilton0239aac2018-05-19 00:03:137425 spdy::SpdySerializedFrame initial_settings_frame(
bnc8f0f3b62015-04-08 04:37:237426 spdy_util_.ConstructSpdySettings(initial_settings));
bnc8abf64af2017-06-07 20:18:547427
Ryan Hamilton0239aac2018-05-19 00:03:137428 spdy::SpdySerializedFrame initial_window_update(
bnc8f0f3b62015-04-08 04:37:237429 spdy_util_.ConstructSpdyWindowUpdate(
Ryan Hamilton0239aac2018-05-19 00:03:137430 spdy::kSessionFlowControlStreamId,
bncbca843ba2016-07-14 13:05:487431 session_max_recv_window_size - kDefaultInitialWindowSize));
bnc8abf64af2017-06-07 20:18:547432
Ryan Hamilton0239aac2018-05-19 00:03:137433 spdy::SpdySerializedFrame combined_frames = CombineFrames(
bncef26b602017-06-12 22:08:197434 {&preface, &initial_settings_frame, &initial_window_update});
[email protected]d11b6912013-06-27 23:07:327435
7436 std::vector<MockWrite> writes;
bncef26b602017-06-12 22:08:197437 writes.push_back(CreateMockWrite(combined_frames));
bnc8abf64af2017-06-07 20:18:547438
Ryan Hamilton0239aac2018-05-19 00:03:137439 spdy::SpdySerializedFrame req(
7440 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
bncdf80d44fd2016-07-15 20:27:417441 writes.push_back(CreateMockWrite(req, writes.size()));
[email protected]d11b6912013-06-27 23:07:327442
[email protected]251029e2014-03-19 06:04:407443 std::vector<MockRead> reads;
Ryan Hamilton0239aac2018-05-19 00:03:137444 spdy::SpdySerializedFrame resp(
7445 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
bncdf80d44fd2016-07-15 20:27:417446 reads.push_back(CreateMockRead(resp, writes.size() + reads.size()));
[email protected]d11b6912013-06-27 23:07:327447
Ryan Hamilton0239aac2018-05-19 00:03:137448 std::vector<spdy::SpdySerializedFrame> body_frames;
Bence Béky4e83f492018-05-13 23:14:257449 const std::string body_data(kChunkSize, 'x');
[email protected]251029e2014-03-19 06:04:407450 for (size_t remaining = kTargetSize; remaining != 0;) {
7451 size_t frame_size = std::min(remaining, body_data.size());
Bence Békyd74f4382018-02-20 18:26:197452 body_frames.push_back(spdy_util_.ConstructSpdyDataFrame(
7453 1, base::StringPiece(body_data.data(), frame_size), false));
rchacdcbdc2015-05-16 17:16:007454 reads.push_back(
bncdf80d44fd2016-07-15 20:27:417455 CreateMockRead(body_frames.back(), writes.size() + reads.size()));
[email protected]251029e2014-03-19 06:04:407456 remaining -= frame_size;
7457 }
mmenkee24011922015-12-17 22:12:597458 // Yield.
rchacdcbdc2015-05-16 17:16:007459 reads.push_back(
mmenkee24011922015-12-17 22:12:597460 MockRead(SYNCHRONOUS, ERR_IO_PENDING, writes.size() + reads.size()));
[email protected]251029e2014-03-19 06:04:407461
Ryan Hamilton0239aac2018-05-19 00:03:137462 spdy::SpdySerializedFrame session_window_update(
bnc8abf64af2017-06-07 20:18:547463 spdy_util_.ConstructSpdyWindowUpdate(0, session_window_update_delta));
rchacdcbdc2015-05-16 17:16:007464 writes.push_back(
bncdf80d44fd2016-07-15 20:27:417465 CreateMockWrite(session_window_update, writes.size() + reads.size()));
Ryan Hamilton0239aac2018-05-19 00:03:137466 spdy::SpdySerializedFrame stream_window_update(
bnc8abf64af2017-06-07 20:18:547467 spdy_util_.ConstructSpdyWindowUpdate(1, stream_window_update_delta));
rchacdcbdc2015-05-16 17:16:007468 writes.push_back(
bncdf80d44fd2016-07-15 20:27:417469 CreateMockWrite(stream_window_update, writes.size() + reads.size()));
rchacdcbdc2015-05-16 17:16:007470
Ryan Sleevib8d7ea02018-05-07 20:01:017471 SequencedSocketData data(reads, writes);
[email protected]d11b6912013-06-27 23:07:327472
Jeremy Roman0579ed62017-08-29 15:56:197473 auto session_deps = std::make_unique<SpdySessionDependencies>();
bnc903e8c12016-12-09 20:50:057474 session_deps->session_max_recv_window_size = session_max_recv_window_size;
Ryan Hamilton0239aac2018-05-19 00:03:137475 session_deps->http2_settings[spdy::SETTINGS_INITIAL_WINDOW_SIZE] =
bnc3171a2432016-12-28 18:40:267476 stream_max_recv_window_size;
bnc903e8c12016-12-09 20:50:057477
Bence Békydb3cf652017-10-10 15:22:107478 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
bnc903e8c12016-12-09 20:50:057479 std::move(session_deps));
[email protected]d11b6912013-06-27 23:07:327480 helper.AddData(&data);
7481 helper.RunPreTestSetup();
[email protected]d11b6912013-06-27 23:07:327482
bnc8f0f3b62015-04-08 04:37:237483 SpdySessionPool* spdy_session_pool = helper.session()->spdy_session_pool();
7484 SpdySessionPoolPeer pool_peer(spdy_session_pool);
7485 pool_peer.SetEnableSendingInitialData(true);
bnc8f0f3b62015-04-08 04:37:237486
7487 HttpNetworkTransaction* trans = helper.trans();
[email protected]d11b6912013-06-27 23:07:327488 TestCompletionCallback callback;
Bence Békydb3cf652017-10-10 15:22:107489 int rv = trans->Start(&request_, callback.callback(), log_);
[email protected]d11b6912013-06-27 23:07:327490
robpercival214763f2016-07-01 23:27:017491 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]d11b6912013-06-27 23:07:327492 rv = callback.WaitForResult();
robpercival214763f2016-07-01 23:27:017493 EXPECT_THAT(rv, IsOk());
[email protected]d11b6912013-06-27 23:07:327494
bnceb9aa7112017-01-05 01:03:467495 // Finish async network reads.
7496 base::RunLoop().RunUntilIdle();
7497
[email protected]d11b6912013-06-27 23:07:327498 SpdyHttpStream* stream =
7499 static_cast<SpdyHttpStream*>(trans->stream_.get());
wezca1070932016-05-26 20:30:527500 ASSERT_TRUE(stream);
7501 ASSERT_TRUE(stream->stream());
[email protected]d11b6912013-06-27 23:07:327502
[email protected]251029e2014-03-19 06:04:407503 // All data has been read, but not consumed. The window reflects this.
bnc8f0f3b62015-04-08 04:37:237504 EXPECT_EQ(static_cast<int>(stream_max_recv_window_size - kTargetSize),
[email protected]251029e2014-03-19 06:04:407505 stream->stream()->recv_window_size());
[email protected]d11b6912013-06-27 23:07:327506
7507 const HttpResponseInfo* response = trans->GetResponseInfo();
wezca1070932016-05-26 20:30:527508 ASSERT_TRUE(response);
7509 ASSERT_TRUE(response->headers);
bnc84e7fb52015-12-02 11:50:027510 EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
[email protected]d11b6912013-06-27 23:07:327511 EXPECT_TRUE(response->was_fetched_via_spdy);
7512
7513 // Issue a read which will cause a WINDOW_UPDATE to be sent and window
7514 // size increased to default.
Victor Costan9c7302b2018-08-27 16:39:447515 scoped_refptr<IOBuffer> buf = base::MakeRefCounted<IOBuffer>(kTargetSize);
[email protected]251029e2014-03-19 06:04:407516 EXPECT_EQ(static_cast<int>(kTargetSize),
Bence Békybdbb0e72018-08-07 21:42:597517 trans->Read(buf.get(), kTargetSize, CompletionOnceCallback()));
bnc8f0f3b62015-04-08 04:37:237518 EXPECT_EQ(static_cast<int>(stream_max_recv_window_size),
[email protected]251029e2014-03-19 06:04:407519 stream->stream()->recv_window_size());
Bence Béky4e83f492018-05-13 23:14:257520 EXPECT_THAT(base::StringPiece(buf->data(), kTargetSize), Each(Eq('x')));
[email protected]d11b6912013-06-27 23:07:327521
[email protected]251029e2014-03-19 06:04:407522 // Allow scheduled WINDOW_UPDATE frames to write.
[email protected]fc9d88472013-08-14 02:31:177523 base::RunLoop().RunUntilIdle();
[email protected]d11b6912013-06-27 23:07:327524 helper.VerifyDataConsumed();
7525}
7526
7527// Test that WINDOW_UPDATE frame causing overflow is handled correctly.
bncd16676a2016-07-20 16:23:017528TEST_F(SpdyNetworkTransactionTest, WindowUpdateOverflow) {
[email protected]d11b6912013-06-27 23:07:327529 // Number of full frames we hope to write (but will not, used to
7530 // set content-length header correctly)
7531 static int kFrameCount = 3;
7532
Bence Békyd74f4382018-02-20 18:26:197533 std::string content(kMaxSpdyFrameChunkSize, 'a');
Ryan Hamilton0239aac2018-05-19 00:03:137534 spdy::SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
tombergan5d22c182017-01-11 02:05:357535 kDefaultUrl, 1, kMaxSpdyFrameChunkSize * kFrameCount, LOWEST, nullptr,
7536 0));
Ryan Hamilton0239aac2018-05-19 00:03:137537 spdy::SpdySerializedFrame body(
Bence Békyd74f4382018-02-20 18:26:197538 spdy_util_.ConstructSpdyDataFrame(1, content, false));
Ryan Hamilton0239aac2018-05-19 00:03:137539 spdy::SpdySerializedFrame rst(spdy_util_.ConstructSpdyRstStream(
7540 1, spdy::ERROR_CODE_FLOW_CONTROL_ERROR));
[email protected]d11b6912013-06-27 23:07:327541
7542 // We're not going to write a data frame with FIN, we'll receive a bad
7543 // WINDOW_UPDATE while sending a request and will send a RST_STREAM frame.
7544 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:417545 CreateMockWrite(req, 0), CreateMockWrite(body, 2),
7546 CreateMockWrite(rst, 3),
[email protected]d11b6912013-06-27 23:07:327547 };
7548
Avi Drissman13fc8932015-12-20 04:40:467549 static const int32_t kDeltaWindowSize = 0x7fffffff; // cause an overflow
Ryan Hamilton0239aac2018-05-19 00:03:137550 spdy::SpdySerializedFrame window_update(
[email protected]d11b6912013-06-27 23:07:327551 spdy_util_.ConstructSpdyWindowUpdate(1, kDeltaWindowSize));
7552 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:417553 CreateMockRead(window_update, 1), MockRead(ASYNC, 0, 4) // EOF
[email protected]d11b6912013-06-27 23:07:327554 };
7555
Ryan Sleevib8d7ea02018-05-07 20:01:017556 SequencedSocketData data(reads, writes);
[email protected]d11b6912013-06-27 23:07:327557
danakjaee3e1ec2016-04-16 00:23:187558 std::vector<std::unique_ptr<UploadElementReader>> element_readers;
[email protected]d11b6912013-06-27 23:07:327559 for (int i = 0; i < kFrameCount; ++i) {
Jeremy Roman0579ed62017-08-29 15:56:197560 element_readers.push_back(std::make_unique<UploadBytesElementReader>(
Bence Békyd74f4382018-02-20 18:26:197561 content.data(), content.size()));
[email protected]d11b6912013-06-27 23:07:327562 }
olli.raula6df48b2a2015-11-26 07:40:227563 ElementsUploadDataStream upload_data_stream(std::move(element_readers), 0);
[email protected]d11b6912013-06-27 23:07:327564
Bence Békydb3cf652017-10-10 15:22:107565 // Setup the request.
7566 request_.method = "POST";
7567 request_.upload_data_stream = &upload_data_stream;
[email protected]d11b6912013-06-27 23:07:327568
Bence Békydb3cf652017-10-10 15:22:107569 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]d11b6912013-06-27 23:07:327570 helper.RunPreTestSetup();
mmenke666a6fea2015-12-19 04:16:337571 helper.AddData(&data);
[email protected]d11b6912013-06-27 23:07:327572 HttpNetworkTransaction* trans = helper.trans();
7573
7574 TestCompletionCallback callback;
Bence Békydb3cf652017-10-10 15:22:107575 int rv = trans->Start(&request_, callback.callback(), log_);
robpercival214763f2016-07-01 23:27:017576 ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]d11b6912013-06-27 23:07:327577
mmenke666a6fea2015-12-19 04:16:337578 base::RunLoop().RunUntilIdle();
[email protected]d11b6912013-06-27 23:07:327579 ASSERT_TRUE(callback.have_result());
Bence Békyd0d69502019-06-25 19:47:187580 EXPECT_THAT(callback.WaitForResult(), IsError(ERR_HTTP2_FLOW_CONTROL_ERROR));
[email protected]d11b6912013-06-27 23:07:327581 helper.VerifyDataConsumed();
7582}
7583
Bence Béky05dcb0382017-09-15 20:07:587584// Regression test for https://crbug.com/732019.
Ryan Hamilton0239aac2018-05-19 00:03:137585// RFC7540 Section 6.9.2: A spdy::SETTINGS_INITIAL_WINDOW_SIZE change that
7586// causes any stream flow control window to overflow MUST be treated as a
7587// connection error.
Bence Béky05dcb0382017-09-15 20:07:587588TEST_F(SpdyNetworkTransactionTest, InitialWindowSizeOverflow) {
Ryan Hamilton0239aac2018-05-19 00:03:137589 spdy::SpdySerializedFrame window_update(
Bence Béky05dcb0382017-09-15 20:07:587590 spdy_util_.ConstructSpdyWindowUpdate(1, 0x60000000));
Ryan Hamilton0239aac2018-05-19 00:03:137591 spdy::SettingsMap settings;
7592 settings[spdy::SETTINGS_INITIAL_WINDOW_SIZE] = 0x60000000;
7593 spdy::SpdySerializedFrame settings_frame(
Bence Béky05dcb0382017-09-15 20:07:587594 spdy_util_.ConstructSpdySettings(settings));
7595 MockRead reads[] = {CreateMockRead(window_update, 1),
7596 CreateMockRead(settings_frame, 2)};
7597
Ryan Hamilton0239aac2018-05-19 00:03:137598 spdy::SpdySerializedFrame req(
7599 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
7600 spdy::SpdySerializedFrame settings_ack(spdy_util_.ConstructSpdySettingsAck());
7601 spdy::SpdySerializedFrame goaway(
7602 spdy_util_.ConstructSpdyGoAway(0, spdy::ERROR_CODE_FLOW_CONTROL_ERROR,
7603 "New spdy::SETTINGS_INITIAL_WINDOW_SIZE "
7604 "value overflows flow control window of "
7605 "stream 1."));
Bence Béky05dcb0382017-09-15 20:07:587606 MockWrite writes[] = {CreateMockWrite(req, 0),
7607 CreateMockWrite(settings_ack, 3),
7608 CreateMockWrite(goaway, 4)};
7609
Ryan Sleevib8d7ea02018-05-07 20:01:017610 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:107611 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
Bence Béky05dcb0382017-09-15 20:07:587612 helper.RunToCompletion(&data);
7613 TransactionHelperResult out = helper.output();
Bence Békyd0d69502019-06-25 19:47:187614 EXPECT_THAT(out.rv, IsError(ERR_HTTP2_FLOW_CONTROL_ERROR));
Bence Béky05dcb0382017-09-15 20:07:587615}
7616
David Schinazi410676a2019-08-13 22:31:057617// Tests that we close the connection if we try to enqueue more frames than
7618// the cap allows.
7619TEST_F(SpdyNetworkTransactionTest, SessionMaxQueuedCappedFramesExceeded) {
7620 const int kTestSessionMaxQueuedCappedFrames = 5;
7621 const int kTestNumPings = kTestSessionMaxQueuedCappedFrames + 1;
7622 spdy::SettingsMap settings;
7623 settings[spdy::SETTINGS_INITIAL_WINDOW_SIZE] = 0xffff;
7624 spdy::SpdySerializedFrame settings_frame(
7625 spdy_util_.ConstructSpdySettings(settings));
7626 std::vector<spdy::SpdySerializedFrame> ping_frames;
7627
7628 spdy::SpdySerializedFrame req(
7629 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
7630 spdy::SpdySerializedFrame settings_ack(spdy_util_.ConstructSpdySettingsAck());
7631
7632 std::vector<MockWrite> writes;
7633 std::vector<MockRead> reads;
7634 // Send request, receive SETTINGS and send a SETTINGS ACK.
7635 writes.push_back(CreateMockWrite(req, writes.size() + reads.size()));
7636 reads.push_back(CreateMockRead(settings_frame, writes.size() + reads.size()));
7637 writes.push_back(CreateMockWrite(settings_ack, writes.size() + reads.size()));
7638 // Receive more pings than our limit allows.
7639 for (int i = 1; i <= kTestNumPings; ++i) {
7640 ping_frames.push_back(
7641 spdy_util_.ConstructSpdyPing(/*ping_id=*/i, /*is_ack=*/false));
7642 reads.push_back(
7643 CreateMockRead(ping_frames.back(), writes.size() + reads.size()));
7644 }
7645 // Only write PING ACKs after receiving all of them to ensure they are all in
7646 // the write queue.
7647 for (int i = 1; i <= kTestNumPings; ++i) {
7648 ping_frames.push_back(
7649 spdy_util_.ConstructSpdyPing(/*ping_id=*/i, /*is_ack=*/true));
7650 writes.push_back(
7651 CreateMockWrite(ping_frames.back(), writes.size() + reads.size()));
7652 }
7653 // Stop reading.
7654 reads.push_back(MockRead(ASYNC, 0, writes.size() + reads.size()));
7655
7656 SequencedSocketData data(reads, writes);
7657 auto session_deps = std::make_unique<SpdySessionDependencies>();
7658 session_deps->session_max_queued_capped_frames =
7659 kTestSessionMaxQueuedCappedFrames;
7660 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
7661 std::move(session_deps));
7662 helper.RunToCompletion(&data);
7663 TransactionHelperResult out = helper.output();
7664 EXPECT_THAT(out.rv, IsError(ERR_CONNECTION_CLOSED));
7665}
7666
[email protected]d11b6912013-06-27 23:07:327667// Test that after hitting a send window size of 0, the write process
7668// stalls and upon receiving WINDOW_UPDATE frame write resumes.
7669
7670// This test constructs a POST request followed by enough data frames
7671// containing 'a' that would make the window size 0, followed by another
7672// data frame containing default content (which is "hello!") and this frame
rchacdcbdc2015-05-16 17:16:007673// also contains a FIN flag. SequencedSocketData is used to enforce all
7674// writes, save the last, go through before a read could happen. The last frame
7675// ("hello!") is not permitted to go through since by the time its turn
[email protected]d11b6912013-06-27 23:07:327676// arrives, window size is 0. At this point MessageLoop::Run() called via
7677// callback would block. Therefore we call MessageLoop::RunUntilIdle()
7678// which returns after performing all possible writes. We use DCHECKS to
7679// ensure that last data frame is still there and stream has stalled.
7680// After that, next read is artifically enforced, which causes a
7681// WINDOW_UPDATE to be read and I/O process resumes.
bncd16676a2016-07-20 16:23:017682TEST_F(SpdyNetworkTransactionTest, FlowControlStallResume) {
bncbca843ba2016-07-14 13:05:487683 const int32_t initial_window_size = kDefaultInitialWindowSize;
xunjieli179a6e72016-04-26 19:47:457684 // Number of upload data buffers we need to send to zero out the window size
7685 // is the minimal number of upload buffers takes to be bigger than
7686 // |initial_window_size|.
7687 size_t num_upload_buffers =
7688 ceil(static_cast<double>(initial_window_size) / kBufferSize);
7689 // Each upload data buffer consists of |num_frames_in_one_upload_buffer|
7690 // frames, each with |kMaxSpdyFrameChunkSize| bytes except the last frame,
7691 // which has kBufferSize % kMaxSpdyChunkSize bytes.
7692 size_t num_frames_in_one_upload_buffer =
7693 ceil(static_cast<double>(kBufferSize) / kMaxSpdyFrameChunkSize);
[email protected]d11b6912013-06-27 23:07:327694
7695 // Construct content for a data frame of maximum size.
Bence Béky4e83f492018-05-13 23:14:257696 std::string content(kMaxSpdyFrameChunkSize, 'a');
[email protected]d11b6912013-06-27 23:07:327697
Ryan Hamilton0239aac2018-05-19 00:03:137698 spdy::SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
bncb26024382016-06-29 02:39:457699 kDefaultUrl, 1,
xunjieli179a6e72016-04-26 19:47:457700 /*content_length=*/kBufferSize * num_upload_buffers + kUploadDataSize,
tombergan5d22c182017-01-11 02:05:357701 LOWEST, nullptr, 0));
[email protected]d11b6912013-06-27 23:07:327702
7703 // Full frames.
Ryan Hamilton0239aac2018-05-19 00:03:137704 spdy::SpdySerializedFrame body1(
Bence Békyd74f4382018-02-20 18:26:197705 spdy_util_.ConstructSpdyDataFrame(1, content, false));
[email protected]d11b6912013-06-27 23:07:327706
xunjieli179a6e72016-04-26 19:47:457707 // Last frame in each upload data buffer.
Ryan Hamilton0239aac2018-05-19 00:03:137708 spdy::SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(
Bence Békyd74f4382018-02-20 18:26:197709 1,
7710 base::StringPiece(content.data(), kBufferSize % kMaxSpdyFrameChunkSize),
7711 false));
[email protected]d11b6912013-06-27 23:07:327712
xunjieli179a6e72016-04-26 19:47:457713 // The very last frame before the stalled frames.
Ryan Hamilton0239aac2018-05-19 00:03:137714 spdy::SpdySerializedFrame body3(spdy_util_.ConstructSpdyDataFrame(
Bence Békyd74f4382018-02-20 18:26:197715 1,
7716 base::StringPiece(content.data(), initial_window_size % kBufferSize %
7717 kMaxSpdyFrameChunkSize),
7718 false));
xunjieli179a6e72016-04-26 19:47:457719
7720 // Data frames to be sent once WINDOW_UPDATE frame is received.
7721
7722 // If kBufferSize * num_upload_buffers > initial_window_size,
7723 // we need one additional frame to send the rest of 'a'.
Bence Béky4e83f492018-05-13 23:14:257724 std::string last_body(kBufferSize * num_upload_buffers - initial_window_size,
7725 'a');
Ryan Hamilton0239aac2018-05-19 00:03:137726 spdy::SpdySerializedFrame body4(
Bence Békyd74f4382018-02-20 18:26:197727 spdy_util_.ConstructSpdyDataFrame(1, last_body, false));
xunjieli179a6e72016-04-26 19:47:457728
7729 // Also send a "hello!" after WINDOW_UPDATE.
Ryan Hamilton0239aac2018-05-19 00:03:137730 spdy::SpdySerializedFrame body5(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]d11b6912013-06-27 23:07:327731
7732 // Fill in mock writes.
[email protected]d11b6912013-06-27 23:07:327733 size_t i = 0;
xunjieli179a6e72016-04-26 19:47:457734 std::vector<MockWrite> writes;
bncdf80d44fd2016-07-15 20:27:417735 writes.push_back(CreateMockWrite(req, i++));
xunjieli179a6e72016-04-26 19:47:457736 for (size_t j = 0; j < num_upload_buffers; j++) {
7737 for (size_t k = 0; k < num_frames_in_one_upload_buffer; k++) {
Brandon Maslen6d59d912020-11-24 23:43:317738 if (j == num_upload_buffers - 1 &&
7739 (initial_window_size % kBufferSize != 0)) {
7740 writes.push_back(CreateMockWrite(body3, i++));
7741 } else if (k == num_frames_in_one_upload_buffer - 1 &&
7742 kBufferSize % kMaxSpdyFrameChunkSize != 0) {
7743 writes.push_back(CreateMockWrite(body2, i++));
xunjieli179a6e72016-04-26 19:47:457744 } else {
bncdf80d44fd2016-07-15 20:27:417745 writes.push_back(CreateMockWrite(body1, i++));
xunjieli179a6e72016-04-26 19:47:457746 }
7747 }
7748 }
[email protected]d11b6912013-06-27 23:07:327749
xunjieli179a6e72016-04-26 19:47:457750 // Fill in mock reads.
7751 std::vector<MockRead> reads;
7752 // Force a pause.
7753 reads.push_back(MockRead(ASYNC, ERR_IO_PENDING, i++));
7754 // Construct read frame for window updates that gives enough space to upload
7755 // the rest of the data.
Ryan Hamilton0239aac2018-05-19 00:03:137756 spdy::SpdySerializedFrame session_window_update(
xunjieli179a6e72016-04-26 19:47:457757 spdy_util_.ConstructSpdyWindowUpdate(0,
7758 kUploadDataSize + last_body.size()));
Ryan Hamilton0239aac2018-05-19 00:03:137759 spdy::SpdySerializedFrame window_update(spdy_util_.ConstructSpdyWindowUpdate(
bncdf80d44fd2016-07-15 20:27:417760 1, kUploadDataSize + last_body.size()));
xunjieli179a6e72016-04-26 19:47:457761
bncdf80d44fd2016-07-15 20:27:417762 reads.push_back(CreateMockRead(session_window_update, i++));
7763 reads.push_back(CreateMockRead(window_update, i++));
xunjieli179a6e72016-04-26 19:47:457764
7765 // Stalled frames which can be sent after receiving window updates.
7766 if (last_body.size() > 0)
bncdf80d44fd2016-07-15 20:27:417767 writes.push_back(CreateMockWrite(body4, i++));
7768 writes.push_back(CreateMockWrite(body5, i++));
xunjieli179a6e72016-04-26 19:47:457769
Ryan Hamilton0239aac2018-05-19 00:03:137770 spdy::SpdySerializedFrame reply(
7771 spdy_util_.ConstructSpdyPostReply(nullptr, 0));
bncdf80d44fd2016-07-15 20:27:417772 reads.push_back(CreateMockRead(reply, i++));
7773 reads.push_back(CreateMockRead(body2, i++));
7774 reads.push_back(CreateMockRead(body5, i++));
xunjieli179a6e72016-04-26 19:47:457775 reads.push_back(MockRead(ASYNC, 0, i++)); // EOF
[email protected]d11b6912013-06-27 23:07:327776
Ryan Sleevib8d7ea02018-05-07 20:01:017777 SequencedSocketData data(reads, writes);
[email protected]d11b6912013-06-27 23:07:327778
danakjaee3e1ec2016-04-16 00:23:187779 std::vector<std::unique_ptr<UploadElementReader>> element_readers;
Bence Béky4e83f492018-05-13 23:14:257780 std::string upload_data_string(kBufferSize * num_upload_buffers, 'a');
[email protected]d11b6912013-06-27 23:07:327781 upload_data_string.append(kUploadData, kUploadDataSize);
Jeremy Roman0579ed62017-08-29 15:56:197782 element_readers.push_back(std::make_unique<UploadBytesElementReader>(
bnc3f6a8552017-05-17 13:40:347783 upload_data_string.c_str(), upload_data_string.size()));
olli.raula6df48b2a2015-11-26 07:40:227784 ElementsUploadDataStream upload_data_stream(std::move(element_readers), 0);
[email protected]d11b6912013-06-27 23:07:327785
Bence Békydb3cf652017-10-10 15:22:107786 request_.method = "POST";
7787 request_.upload_data_stream = &upload_data_stream;
7788 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
7789
[email protected]d11b6912013-06-27 23:07:327790 helper.AddData(&data);
7791 helper.RunPreTestSetup();
7792
7793 HttpNetworkTransaction* trans = helper.trans();
7794
7795 TestCompletionCallback callback;
Bence Békydb3cf652017-10-10 15:22:107796 int rv = trans->Start(&request_, callback.callback(), log_);
robpercival214763f2016-07-01 23:27:017797 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]d11b6912013-06-27 23:07:327798
[email protected]fc9d88472013-08-14 02:31:177799 base::RunLoop().RunUntilIdle(); // Write as much as we can.
[email protected]d11b6912013-06-27 23:07:327800
7801 SpdyHttpStream* stream = static_cast<SpdyHttpStream*>(trans->stream_.get());
wezca1070932016-05-26 20:30:527802 ASSERT_TRUE(stream);
7803 ASSERT_TRUE(stream->stream());
[email protected]d11b6912013-06-27 23:07:327804 EXPECT_EQ(0, stream->stream()->send_window_size());
xunjieli179a6e72016-04-26 19:47:457805 if (initial_window_size % kBufferSize != 0) {
7806 // If it does not take whole number of full upload buffer to zero out
7807 // initial window size, then the upload data is not at EOF, because the
7808 // last read must be stalled.
7809 EXPECT_FALSE(upload_data_stream.IsEOF());
7810 } else {
7811 // All the body data should have been read.
7812 // TODO(satorux): This is because of the weirdness in reading the request
7813 // body in OnSendBodyComplete(). See crbug.com/113107.
7814 EXPECT_TRUE(upload_data_stream.IsEOF());
7815 }
[email protected]d11b6912013-06-27 23:07:327816 // But the body is not yet fully sent (kUploadData is not yet sent)
7817 // since we're send-stalled.
7818 EXPECT_TRUE(stream->stream()->send_stalled_by_flow_control());
7819
mmenkee24011922015-12-17 22:12:597820 data.Resume(); // Read in WINDOW_UPDATE frame.
[email protected]d11b6912013-06-27 23:07:327821 rv = callback.WaitForResult();
bnceb9aa7112017-01-05 01:03:467822 EXPECT_THAT(rv, IsOk());
7823
7824 // Finish async network reads.
7825 base::RunLoop().RunUntilIdle();
[email protected]d11b6912013-06-27 23:07:327826 helper.VerifyDataConsumed();
7827}
7828
7829// Test we correctly handle the case where the SETTINGS frame results in
7830// unstalling the send window.
bncd16676a2016-07-20 16:23:017831TEST_F(SpdyNetworkTransactionTest, FlowControlStallResumeAfterSettings) {
bncbca843ba2016-07-14 13:05:487832 const int32_t initial_window_size = kDefaultInitialWindowSize;
xunjieli179a6e72016-04-26 19:47:457833 // Number of upload data buffers we need to send to zero out the window size
7834 // is the minimal number of upload buffers takes to be bigger than
7835 // |initial_window_size|.
7836 size_t num_upload_buffers =
7837 ceil(static_cast<double>(initial_window_size) / kBufferSize);
7838 // Each upload data buffer consists of |num_frames_in_one_upload_buffer|
7839 // frames, each with |kMaxSpdyFrameChunkSize| bytes except the last frame,
7840 // which has kBufferSize % kMaxSpdyChunkSize bytes.
7841 size_t num_frames_in_one_upload_buffer =
7842 ceil(static_cast<double>(kBufferSize) / kMaxSpdyFrameChunkSize);
[email protected]d11b6912013-06-27 23:07:327843
7844 // Construct content for a data frame of maximum size.
Bence Béky4e83f492018-05-13 23:14:257845 std::string content(kMaxSpdyFrameChunkSize, 'a');
[email protected]d11b6912013-06-27 23:07:327846
Ryan Hamilton0239aac2018-05-19 00:03:137847 spdy::SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
bncb26024382016-06-29 02:39:457848 kDefaultUrl, 1,
xunjieli179a6e72016-04-26 19:47:457849 /*content_length=*/kBufferSize * num_upload_buffers + kUploadDataSize,
tombergan5d22c182017-01-11 02:05:357850 LOWEST, nullptr, 0));
[email protected]d11b6912013-06-27 23:07:327851
7852 // Full frames.
Ryan Hamilton0239aac2018-05-19 00:03:137853 spdy::SpdySerializedFrame body1(
Bence Békyd74f4382018-02-20 18:26:197854 spdy_util_.ConstructSpdyDataFrame(1, content, false));
[email protected]d11b6912013-06-27 23:07:327855
xunjieli179a6e72016-04-26 19:47:457856 // Last frame in each upload data buffer.
Ryan Hamilton0239aac2018-05-19 00:03:137857 spdy::SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(
Bence Békyd74f4382018-02-20 18:26:197858 1,
7859 base::StringPiece(content.data(), kBufferSize % kMaxSpdyFrameChunkSize),
7860 false));
[email protected]d11b6912013-06-27 23:07:327861
xunjieli179a6e72016-04-26 19:47:457862 // The very last frame before the stalled frames.
Ryan Hamilton0239aac2018-05-19 00:03:137863 spdy::SpdySerializedFrame body3(spdy_util_.ConstructSpdyDataFrame(
Bence Békyd74f4382018-02-20 18:26:197864 1,
7865 base::StringPiece(content.data(), initial_window_size % kBufferSize %
7866 kMaxSpdyFrameChunkSize),
7867 false));
xunjieli179a6e72016-04-26 19:47:457868
7869 // Data frames to be sent once WINDOW_UPDATE frame is received.
7870
7871 // If kBufferSize * num_upload_buffers > initial_window_size,
7872 // we need one additional frame to send the rest of 'a'.
Bence Béky4e83f492018-05-13 23:14:257873 std::string last_body(kBufferSize * num_upload_buffers - initial_window_size,
7874 'a');
Ryan Hamilton0239aac2018-05-19 00:03:137875 spdy::SpdySerializedFrame body4(
Bence Békyd74f4382018-02-20 18:26:197876 spdy_util_.ConstructSpdyDataFrame(1, last_body, false));
xunjieli179a6e72016-04-26 19:47:457877
7878 // Also send a "hello!" after WINDOW_UPDATE.
Ryan Hamilton0239aac2018-05-19 00:03:137879 spdy::SpdySerializedFrame body5(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]d11b6912013-06-27 23:07:327880
xunjieli179a6e72016-04-26 19:47:457881 // Fill in mock writes.
[email protected]d11b6912013-06-27 23:07:327882 size_t i = 0;
xunjieli179a6e72016-04-26 19:47:457883 std::vector<MockWrite> writes;
bncdf80d44fd2016-07-15 20:27:417884 writes.push_back(CreateMockWrite(req, i++));
xunjieli179a6e72016-04-26 19:47:457885 for (size_t j = 0; j < num_upload_buffers; j++) {
7886 for (size_t k = 0; k < num_frames_in_one_upload_buffer; k++) {
Brandon Maslen6d59d912020-11-24 23:43:317887 if (j == num_upload_buffers - 1 &&
7888 (initial_window_size % kBufferSize != 0)) {
7889 writes.push_back(CreateMockWrite(body3, i++));
7890 } else if (k == num_frames_in_one_upload_buffer - 1 &&
7891 kBufferSize % kMaxSpdyFrameChunkSize != 0) {
7892 writes.push_back(CreateMockWrite(body2, i++));
xunjieli179a6e72016-04-26 19:47:457893 } else {
bncdf80d44fd2016-07-15 20:27:417894 writes.push_back(CreateMockWrite(body1, i++));
xunjieli179a6e72016-04-26 19:47:457895 }
7896 }
7897 }
[email protected]d11b6912013-06-27 23:07:327898
xunjieli179a6e72016-04-26 19:47:457899 // Fill in mock reads.
7900 std::vector<MockRead> reads;
7901 // Force a pause.
mmenke666a6fea2015-12-19 04:16:337902 reads.push_back(MockRead(ASYNC, ERR_IO_PENDING, i++));
7903
[email protected]d11b6912013-06-27 23:07:327904 // Construct read frame for SETTINGS that gives enough space to upload the
7905 // rest of the data.
Ryan Hamilton0239aac2018-05-19 00:03:137906 spdy::SettingsMap settings;
7907 settings[spdy::SETTINGS_INITIAL_WINDOW_SIZE] = initial_window_size * 2;
7908 spdy::SpdySerializedFrame settings_frame_large(
[email protected]d11b6912013-06-27 23:07:327909 spdy_util_.ConstructSpdySettings(settings));
7910
bncdf80d44fd2016-07-15 20:27:417911 reads.push_back(CreateMockRead(settings_frame_large, i++));
[email protected]d11b6912013-06-27 23:07:327912
Ryan Hamilton0239aac2018-05-19 00:03:137913 spdy::SpdySerializedFrame session_window_update(
xunjieli179a6e72016-04-26 19:47:457914 spdy_util_.ConstructSpdyWindowUpdate(0,
7915 last_body.size() + kUploadDataSize));
bncdf80d44fd2016-07-15 20:27:417916 reads.push_back(CreateMockRead(session_window_update, i++));
[email protected]d11b6912013-06-27 23:07:327917
Ryan Hamilton0239aac2018-05-19 00:03:137918 spdy::SpdySerializedFrame settings_ack(spdy_util_.ConstructSpdySettingsAck());
bncdf80d44fd2016-07-15 20:27:417919 writes.push_back(CreateMockWrite(settings_ack, i++));
[email protected]d4a77c12014-05-15 20:45:217920
xunjieli179a6e72016-04-26 19:47:457921 // Stalled frames which can be sent after |settings_ack|.
7922 if (last_body.size() > 0)
bncdf80d44fd2016-07-15 20:27:417923 writes.push_back(CreateMockWrite(body4, i++));
7924 writes.push_back(CreateMockWrite(body5, i++));
[email protected]d11b6912013-06-27 23:07:327925
Ryan Hamilton0239aac2018-05-19 00:03:137926 spdy::SpdySerializedFrame reply(
7927 spdy_util_.ConstructSpdyPostReply(nullptr, 0));
bncdf80d44fd2016-07-15 20:27:417928 reads.push_back(CreateMockRead(reply, i++));
7929 reads.push_back(CreateMockRead(body2, i++));
7930 reads.push_back(CreateMockRead(body5, i++));
[email protected]d11b6912013-06-27 23:07:327931 reads.push_back(MockRead(ASYNC, 0, i++)); // EOF
7932
7933 // Force all writes to happen before any read, last write will not
7934 // actually queue a frame, due to window size being 0.
Ryan Sleevib8d7ea02018-05-07 20:01:017935 SequencedSocketData data(reads, writes);
[email protected]d11b6912013-06-27 23:07:327936
danakjaee3e1ec2016-04-16 00:23:187937 std::vector<std::unique_ptr<UploadElementReader>> element_readers;
Bence Béky4e83f492018-05-13 23:14:257938 std::string upload_data_string(kBufferSize * num_upload_buffers, 'a');
[email protected]d11b6912013-06-27 23:07:327939 upload_data_string.append(kUploadData, kUploadDataSize);
Jeremy Roman0579ed62017-08-29 15:56:197940 element_readers.push_back(std::make_unique<UploadBytesElementReader>(
bnc3f6a8552017-05-17 13:40:347941 upload_data_string.c_str(), upload_data_string.size()));
olli.raula6df48b2a2015-11-26 07:40:227942 ElementsUploadDataStream upload_data_stream(std::move(element_readers), 0);
[email protected]d11b6912013-06-27 23:07:327943
Bence Békydb3cf652017-10-10 15:22:107944 request_.method = "POST";
7945 request_.upload_data_stream = &upload_data_stream;
7946 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
7947
[email protected]d11b6912013-06-27 23:07:327948 helper.RunPreTestSetup();
mmenke666a6fea2015-12-19 04:16:337949 helper.AddData(&data);
[email protected]d11b6912013-06-27 23:07:327950
7951 HttpNetworkTransaction* trans = helper.trans();
7952
7953 TestCompletionCallback callback;
Bence Békydb3cf652017-10-10 15:22:107954 int rv = trans->Start(&request_, callback.callback(), log_);
robpercival214763f2016-07-01 23:27:017955 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]d11b6912013-06-27 23:07:327956
mmenke666a6fea2015-12-19 04:16:337957 data.RunUntilPaused(); // Write as much as we can.
7958 base::RunLoop().RunUntilIdle();
[email protected]d11b6912013-06-27 23:07:327959
7960 SpdyHttpStream* stream = static_cast<SpdyHttpStream*>(trans->stream_.get());
wezca1070932016-05-26 20:30:527961 ASSERT_TRUE(stream);
7962 ASSERT_TRUE(stream->stream());
[email protected]d11b6912013-06-27 23:07:327963 EXPECT_EQ(0, stream->stream()->send_window_size());
7964
xunjieli179a6e72016-04-26 19:47:457965 if (initial_window_size % kBufferSize != 0) {
7966 // If it does not take whole number of full upload buffer to zero out
7967 // initial window size, then the upload data is not at EOF, because the
7968 // last read must be stalled.
7969 EXPECT_FALSE(upload_data_stream.IsEOF());
7970 } else {
7971 // All the body data should have been read.
7972 // TODO(satorux): This is because of the weirdness in reading the request
7973 // body in OnSendBodyComplete(). See crbug.com/113107.
7974 EXPECT_TRUE(upload_data_stream.IsEOF());
7975 }
[email protected]d11b6912013-06-27 23:07:327976 // But the body is not yet fully sent (kUploadData is not yet sent)
7977 // since we're send-stalled.
7978 EXPECT_TRUE(stream->stream()->send_stalled_by_flow_control());
7979
mmenke666a6fea2015-12-19 04:16:337980 // Read in SETTINGS frame to unstall.
7981 data.Resume();
7982 base::RunLoop().RunUntilIdle();
7983
[email protected]d11b6912013-06-27 23:07:327984 rv = callback.WaitForResult();
7985 helper.VerifyDataConsumed();
tombergan5d22c182017-01-11 02:05:357986 // If stream is nullptr, that means it was unstalled and closed.
7987 EXPECT_TRUE(stream->stream() == nullptr);
[email protected]d11b6912013-06-27 23:07:327988}
7989
7990// Test we correctly handle the case where the SETTINGS frame results in a
7991// negative send window size.
bncd16676a2016-07-20 16:23:017992TEST_F(SpdyNetworkTransactionTest, FlowControlNegativeSendWindowSize) {
bncbca843ba2016-07-14 13:05:487993 const int32_t initial_window_size = kDefaultInitialWindowSize;
xunjieli179a6e72016-04-26 19:47:457994 // Number of upload data buffers we need to send to zero out the window size
7995 // is the minimal number of upload buffers takes to be bigger than
7996 // |initial_window_size|.
7997 size_t num_upload_buffers =
7998 ceil(static_cast<double>(initial_window_size) / kBufferSize);
7999 // Each upload data buffer consists of |num_frames_in_one_upload_buffer|
8000 // frames, each with |kMaxSpdyFrameChunkSize| bytes except the last frame,
8001 // which has kBufferSize % kMaxSpdyChunkSize bytes.
8002 size_t num_frames_in_one_upload_buffer =
8003 ceil(static_cast<double>(kBufferSize) / kMaxSpdyFrameChunkSize);
[email protected]d11b6912013-06-27 23:07:328004
8005 // Construct content for a data frame of maximum size.
Bence Béky4e83f492018-05-13 23:14:258006 std::string content(kMaxSpdyFrameChunkSize, 'a');
[email protected]d11b6912013-06-27 23:07:328007
Ryan Hamilton0239aac2018-05-19 00:03:138008 spdy::SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
bncb26024382016-06-29 02:39:458009 kDefaultUrl, 1,
xunjieli179a6e72016-04-26 19:47:458010 /*content_length=*/kBufferSize * num_upload_buffers + kUploadDataSize,
tombergan5d22c182017-01-11 02:05:358011 LOWEST, nullptr, 0));
[email protected]d11b6912013-06-27 23:07:328012
8013 // Full frames.
Ryan Hamilton0239aac2018-05-19 00:03:138014 spdy::SpdySerializedFrame body1(
Bence Békyd74f4382018-02-20 18:26:198015 spdy_util_.ConstructSpdyDataFrame(1, content, false));
[email protected]d11b6912013-06-27 23:07:328016
xunjieli179a6e72016-04-26 19:47:458017 // Last frame in each upload data buffer.
Ryan Hamilton0239aac2018-05-19 00:03:138018 spdy::SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(
Bence Békyd74f4382018-02-20 18:26:198019 1,
8020 base::StringPiece(content.data(), kBufferSize % kMaxSpdyFrameChunkSize),
8021 false));
[email protected]d11b6912013-06-27 23:07:328022
xunjieli179a6e72016-04-26 19:47:458023 // The very last frame before the stalled frames.
Ryan Hamilton0239aac2018-05-19 00:03:138024 spdy::SpdySerializedFrame body3(spdy_util_.ConstructSpdyDataFrame(
Bence Békyd74f4382018-02-20 18:26:198025 1,
8026 base::StringPiece(content.data(), initial_window_size % kBufferSize %
8027 kMaxSpdyFrameChunkSize),
8028 false));
xunjieli179a6e72016-04-26 19:47:458029
8030 // Data frames to be sent once WINDOW_UPDATE frame is received.
8031
8032 // If kBufferSize * num_upload_buffers > initial_window_size,
8033 // we need one additional frame to send the rest of 'a'.
Bence Béky4e83f492018-05-13 23:14:258034 std::string last_body(kBufferSize * num_upload_buffers - initial_window_size,
8035 'a');
Ryan Hamilton0239aac2018-05-19 00:03:138036 spdy::SpdySerializedFrame body4(
Bence Békyd74f4382018-02-20 18:26:198037 spdy_util_.ConstructSpdyDataFrame(1, last_body, false));
xunjieli179a6e72016-04-26 19:47:458038
8039 // Also send a "hello!" after WINDOW_UPDATE.
Ryan Hamilton0239aac2018-05-19 00:03:138040 spdy::SpdySerializedFrame body5(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]d11b6912013-06-27 23:07:328041
xunjieli179a6e72016-04-26 19:47:458042 // Fill in mock writes.
[email protected]d11b6912013-06-27 23:07:328043 size_t i = 0;
xunjieli179a6e72016-04-26 19:47:458044 std::vector<MockWrite> writes;
bncdf80d44fd2016-07-15 20:27:418045 writes.push_back(CreateMockWrite(req, i++));
xunjieli179a6e72016-04-26 19:47:458046 for (size_t j = 0; j < num_upload_buffers; j++) {
8047 for (size_t k = 0; k < num_frames_in_one_upload_buffer; k++) {
Brandon Maslen6d59d912020-11-24 23:43:318048 if (j == num_upload_buffers - 1 &&
8049 (initial_window_size % kBufferSize != 0)) {
8050 writes.push_back(CreateMockWrite(body3, i++));
8051 } else if (k == num_frames_in_one_upload_buffer - 1 &&
8052 kBufferSize % kMaxSpdyFrameChunkSize != 0) {
8053 writes.push_back(CreateMockWrite(body2, i++));
xunjieli179a6e72016-04-26 19:47:458054 } else {
bncdf80d44fd2016-07-15 20:27:418055 writes.push_back(CreateMockWrite(body1, i++));
xunjieli179a6e72016-04-26 19:47:458056 }
8057 }
8058 }
[email protected]d11b6912013-06-27 23:07:328059
xunjieli179a6e72016-04-26 19:47:458060 // Fill in mock reads.
8061 std::vector<MockRead> reads;
8062 // Force a pause.
mmenke666a6fea2015-12-19 04:16:338063 reads.push_back(MockRead(ASYNC, ERR_IO_PENDING, i++));
[email protected]d11b6912013-06-27 23:07:328064 // Construct read frame for SETTINGS that makes the send_window_size
8065 // negative.
Ryan Hamilton0239aac2018-05-19 00:03:138066 spdy::SettingsMap new_settings;
8067 new_settings[spdy::SETTINGS_INITIAL_WINDOW_SIZE] = initial_window_size / 2;
8068 spdy::SpdySerializedFrame settings_frame_small(
[email protected]d11b6912013-06-27 23:07:328069 spdy_util_.ConstructSpdySettings(new_settings));
8070 // Construct read frames for WINDOW_UPDATE that makes the send_window_size
8071 // positive.
Ryan Hamilton0239aac2018-05-19 00:03:138072 spdy::SpdySerializedFrame session_window_update_init_size(
bnc2f54c832014-12-01 13:31:198073 spdy_util_.ConstructSpdyWindowUpdate(0, initial_window_size));
Ryan Hamilton0239aac2018-05-19 00:03:138074 spdy::SpdySerializedFrame window_update_init_size(
bnc2f54c832014-12-01 13:31:198075 spdy_util_.ConstructSpdyWindowUpdate(1, initial_window_size));
[email protected]d11b6912013-06-27 23:07:328076
bncdf80d44fd2016-07-15 20:27:418077 reads.push_back(CreateMockRead(settings_frame_small, i++));
8078 reads.push_back(CreateMockRead(session_window_update_init_size, i++));
8079 reads.push_back(CreateMockRead(window_update_init_size, i++));
[email protected]d11b6912013-06-27 23:07:328080
Ryan Hamilton0239aac2018-05-19 00:03:138081 spdy::SpdySerializedFrame settings_ack(spdy_util_.ConstructSpdySettingsAck());
bncdf80d44fd2016-07-15 20:27:418082 writes.push_back(CreateMockWrite(settings_ack, i++));
[email protected]d4a77c12014-05-15 20:45:218083
xunjieli179a6e72016-04-26 19:47:458084 // Stalled frames which can be sent after |settings_ack|.
8085 if (last_body.size() > 0)
bncdf80d44fd2016-07-15 20:27:418086 writes.push_back(CreateMockWrite(body4, i++));
8087 writes.push_back(CreateMockWrite(body5, i++));
[email protected]d11b6912013-06-27 23:07:328088
Ryan Hamilton0239aac2018-05-19 00:03:138089 spdy::SpdySerializedFrame reply(
8090 spdy_util_.ConstructSpdyPostReply(nullptr, 0));
bncdf80d44fd2016-07-15 20:27:418091 reads.push_back(CreateMockRead(reply, i++));
8092 reads.push_back(CreateMockRead(body2, i++));
8093 reads.push_back(CreateMockRead(body5, i++));
[email protected]d11b6912013-06-27 23:07:328094 reads.push_back(MockRead(ASYNC, 0, i++)); // EOF
8095
8096 // Force all writes to happen before any read, last write will not
8097 // actually queue a frame, due to window size being 0.
Ryan Sleevib8d7ea02018-05-07 20:01:018098 SequencedSocketData data(reads, writes);
[email protected]d11b6912013-06-27 23:07:328099
danakjaee3e1ec2016-04-16 00:23:188100 std::vector<std::unique_ptr<UploadElementReader>> element_readers;
Bence Béky4e83f492018-05-13 23:14:258101 std::string upload_data_string(kBufferSize * num_upload_buffers, 'a');
[email protected]d11b6912013-06-27 23:07:328102 upload_data_string.append(kUploadData, kUploadDataSize);
Jeremy Roman0579ed62017-08-29 15:56:198103 element_readers.push_back(std::make_unique<UploadBytesElementReader>(
bnc3f6a8552017-05-17 13:40:348104 upload_data_string.c_str(), upload_data_string.size()));
olli.raula6df48b2a2015-11-26 07:40:228105 ElementsUploadDataStream upload_data_stream(std::move(element_readers), 0);
[email protected]d11b6912013-06-27 23:07:328106
Bence Békydb3cf652017-10-10 15:22:108107 request_.method = "POST";
8108 request_.upload_data_stream = &upload_data_stream;
8109 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
8110
[email protected]d11b6912013-06-27 23:07:328111 helper.RunPreTestSetup();
mmenke666a6fea2015-12-19 04:16:338112 helper.AddData(&data);
[email protected]d11b6912013-06-27 23:07:328113
8114 HttpNetworkTransaction* trans = helper.trans();
8115
8116 TestCompletionCallback callback;
Bence Békydb3cf652017-10-10 15:22:108117 int rv = trans->Start(&request_, callback.callback(), log_);
robpercival214763f2016-07-01 23:27:018118 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]d11b6912013-06-27 23:07:328119
mmenke666a6fea2015-12-19 04:16:338120 data.RunUntilPaused(); // Write as much as we can.
8121 base::RunLoop().RunUntilIdle();
[email protected]d11b6912013-06-27 23:07:328122
8123 SpdyHttpStream* stream = static_cast<SpdyHttpStream*>(trans->stream_.get());
wezca1070932016-05-26 20:30:528124 ASSERT_TRUE(stream);
8125 ASSERT_TRUE(stream->stream());
[email protected]d11b6912013-06-27 23:07:328126 EXPECT_EQ(0, stream->stream()->send_window_size());
8127
xunjieli179a6e72016-04-26 19:47:458128 if (initial_window_size % kBufferSize != 0) {
8129 // If it does not take whole number of full upload buffer to zero out
8130 // initial window size, then the upload data is not at EOF, because the
8131 // last read must be stalled.
8132 EXPECT_FALSE(upload_data_stream.IsEOF());
8133 } else {
8134 // All the body data should have been read.
8135 // TODO(satorux): This is because of the weirdness in reading the request
8136 // body in OnSendBodyComplete(). See crbug.com/113107.
8137 EXPECT_TRUE(upload_data_stream.IsEOF());
8138 }
[email protected]d11b6912013-06-27 23:07:328139
8140 // Read in WINDOW_UPDATE or SETTINGS frame.
mmenke666a6fea2015-12-19 04:16:338141 data.Resume();
8142 base::RunLoop().RunUntilIdle();
[email protected]d11b6912013-06-27 23:07:328143 rv = callback.WaitForResult();
8144 helper.VerifyDataConsumed();
8145}
8146
bncd16676a2016-07-20 16:23:018147TEST_F(SpdyNetworkTransactionTest, GoAwayOnOddPushStreamId) {
Bence Békyeacd48f2018-05-14 11:34:338148 base::HistogramTester histogram_tester;
8149
Bence Béky4c325e52020-10-22 20:48:018150 spdy::Http2HeaderBlock push_headers;
bnc086b39e12016-06-24 13:05:268151 spdy_util_.AddUrlToHeaderBlock("http://www.example.org/a.dat", &push_headers);
Ryan Hamilton0239aac2018-05-19 00:03:138152 spdy::SpdySerializedFrame push(
Bence Békyf1d78522018-01-11 01:16:508153 spdy_util_.ConstructSpdyPushPromise(1, 3, std::move(push_headers)));
bncdf80d44fd2016-07-15 20:27:418154 MockRead reads[] = {CreateMockRead(push, 1)};
baranovich212a1292014-09-02 21:45:318155
Ryan Hamilton0239aac2018-05-19 00:03:138156 spdy::SpdySerializedFrame req(
8157 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
8158 spdy::SpdySerializedFrame goaway(spdy_util_.ConstructSpdyGoAway(
8159 0, spdy::ERROR_CODE_PROTOCOL_ERROR,
Bence Béky602c40c2017-07-26 05:22:568160 "Received invalid pushed stream id 3 (must be even) on stream id 1."));
baranovich212a1292014-09-02 21:45:318161 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:418162 CreateMockWrite(req, 0), CreateMockWrite(goaway, 2),
baranovich212a1292014-09-02 21:45:318163 };
8164
Ryan Sleevib8d7ea02018-05-07 20:01:018165 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:108166 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
baranovich212a1292014-09-02 21:45:318167 helper.RunToCompletion(&data);
8168 TransactionHelperResult out = helper.output();
Bence Békyd0d69502019-06-25 19:47:188169 EXPECT_THAT(out.rv, IsError(ERR_HTTP2_PROTOCOL_ERROR));
Bence Békyeacd48f2018-05-14 11:34:338170
8171 histogram_tester.ExpectBucketCount(
8172 "Net.SpdyPushedStreamFate",
8173 static_cast<int>(SpdyPushedStreamFate::kPromisedStreamIdParityError), 1);
8174 histogram_tester.ExpectTotalCount("Net.SpdyPushedStreamFate", 1);
baranovich212a1292014-09-02 21:45:318175}
8176
bncd16676a2016-07-20 16:23:018177TEST_F(SpdyNetworkTransactionTest,
baranovich212a1292014-09-02 21:45:318178 GoAwayOnPushStreamIdLesserOrEqualThanLastAccepted) {
Bence Békyeacd48f2018-05-14 11:34:338179 base::HistogramTester histogram_tester;
8180
Ryan Hamilton0239aac2018-05-19 00:03:138181 spdy::SpdySerializedFrame push_a(spdy_util_.ConstructSpdyPush(
Bence Béky3e01b532018-02-06 23:04:518182 nullptr, 0, 4, 1, "https://www.example.org/a.dat"));
Bence Béky4c325e52020-10-22 20:48:018183 spdy::Http2HeaderBlock push_b_headers;
Bence Béky3e01b532018-02-06 23:04:518184 spdy_util_.AddUrlToHeaderBlock("https://www.example.org/b.dat",
bnc086b39e12016-06-24 13:05:268185 &push_b_headers);
Ryan Hamilton0239aac2018-05-19 00:03:138186 spdy::SpdySerializedFrame push_b(
Bence Békyf1d78522018-01-11 01:16:508187 spdy_util_.ConstructSpdyPushPromise(1, 2, std::move(push_b_headers)));
baranovich212a1292014-09-02 21:45:318188 MockRead reads[] = {
tombergan5d22c182017-01-11 02:05:358189 CreateMockRead(push_a, 1), CreateMockRead(push_b, 3),
baranovich212a1292014-09-02 21:45:318190 };
8191
Ryan Hamilton0239aac2018-05-19 00:03:138192 spdy::SpdySerializedFrame req(
8193 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
8194 spdy::SpdySerializedFrame priority_a(
tombergan5d22c182017-01-11 02:05:358195 spdy_util_.ConstructSpdyPriority(4, 1, IDLE, true));
Ryan Hamilton0239aac2018-05-19 00:03:138196 spdy::SpdySerializedFrame goaway(spdy_util_.ConstructSpdyGoAway(
8197 4, spdy::ERROR_CODE_PROTOCOL_ERROR,
Bence Béky602c40c2017-07-26 05:22:568198 "Received pushed stream id 2 must be larger than last accepted id 4."));
baranovich212a1292014-09-02 21:45:318199 MockWrite writes[] = {
tombergan5d22c182017-01-11 02:05:358200 CreateMockWrite(req, 0), CreateMockWrite(priority_a, 2),
8201 CreateMockWrite(goaway, 4),
baranovich212a1292014-09-02 21:45:318202 };
8203
Ryan Sleevib8d7ea02018-05-07 20:01:018204 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:108205 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
baranovich212a1292014-09-02 21:45:318206 helper.RunToCompletion(&data);
8207 TransactionHelperResult out = helper.output();
Bence Békyd0d69502019-06-25 19:47:188208 EXPECT_THAT(out.rv, IsError(ERR_HTTP2_PROTOCOL_ERROR));
Bence Békyeacd48f2018-05-14 11:34:338209
8210 histogram_tester.ExpectBucketCount(
8211 "Net.SpdyPushedStreamFate",
8212 static_cast<int>(SpdyPushedStreamFate::kStreamIdOutOfOrder), 1);
8213 histogram_tester.ExpectTotalCount("Net.SpdyPushedStreamFate", 1);
baranovich212a1292014-09-02 21:45:318214}
8215
bnc76598ab2015-06-29 12:43:078216// Regression test for https://crbug.com/493348: request header exceeds 16 kB
8217// and thus sent in multiple frames when using HTTP/2.
bncd16676a2016-07-20 16:23:018218TEST_F(SpdyNetworkTransactionTest, LargeRequest) {
Bence Béky4e83f492018-05-13 23:14:258219 const std::string kKey("foo");
8220 const std::string kValue(1 << 15, 'z');
bnc76598ab2015-06-29 12:43:078221
Bence Békydb3cf652017-10-10 15:22:108222 request_.extra_headers.SetHeader(kKey, kValue);
bnc76598ab2015-06-29 12:43:078223
Bence Béky4c325e52020-10-22 20:48:018224 spdy::Http2HeaderBlock headers(
Ryan Hamilton0239aac2018-05-19 00:03:138225 spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
bnc086b39e12016-06-24 13:05:268226 headers[kKey] = kValue;
Ryan Hamilton0239aac2018-05-19 00:03:138227 spdy::SpdySerializedFrame req(
bnc42331402016-07-25 13:36:158228 spdy_util_.ConstructSpdyHeaders(1, std::move(headers), LOWEST, true));
bnc76598ab2015-06-29 12:43:078229 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:418230 CreateMockWrite(req, 0),
bnc76598ab2015-06-29 12:43:078231 };
8232
Ryan Hamilton0239aac2018-05-19 00:03:138233 spdy::SpdySerializedFrame resp(
8234 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
8235 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
bnc76598ab2015-06-29 12:43:078236 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:418237 CreateMockRead(resp, 1), CreateMockRead(body, 2),
bnc76598ab2015-06-29 12:43:078238 MockRead(ASYNC, 0, 3) // EOF
8239 };
8240
Ryan Sleevib8d7ea02018-05-07 20:01:018241 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:108242 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
bnc76598ab2015-06-29 12:43:078243 helper.RunToCompletion(&data);
8244 TransactionHelperResult out = helper.output();
8245
robpercival214763f2016-07-01 23:27:018246 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:028247 EXPECT_EQ("HTTP/1.1 200", out.status_line);
bnc76598ab2015-06-29 12:43:078248 EXPECT_EQ("hello!", out.response_data);
8249}
8250
bncd67383342016-01-08 21:58:438251// Regression test for https://crbug.com/535629: response header exceeds 16 kB.
bncd16676a2016-07-20 16:23:018252TEST_F(SpdyNetworkTransactionTest, LargeResponseHeader) {
Bence Béky4c325e52020-10-22 20:48:018253 spdy::Http2HeaderBlock headers(
Ryan Hamilton0239aac2018-05-19 00:03:138254 spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
8255 spdy::SpdySerializedFrame req(
bnc42331402016-07-25 13:36:158256 spdy_util_.ConstructSpdyHeaders(1, std::move(headers), LOWEST, true));
bncd67383342016-01-08 21:58:438257 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:418258 CreateMockWrite(req, 0),
bncd67383342016-01-08 21:58:438259 };
8260
8261 // HPACK decoder implementation limits string literal length to 16 kB.
8262 const char* response_headers[2];
Bence Béky4e83f492018-05-13 23:14:258263 const std::string kKey(16 * 1024, 'a');
bncd67383342016-01-08 21:58:438264 response_headers[0] = kKey.data();
Bence Béky4e83f492018-05-13 23:14:258265 const std::string kValue(16 * 1024, 'b');
bncd67383342016-01-08 21:58:438266 response_headers[1] = kValue.data();
8267
Ryan Hamilton0239aac2018-05-19 00:03:138268 spdy::SpdySerializedFrame resp(
bnc42331402016-07-25 13:36:158269 spdy_util_.ConstructSpdyGetReply(response_headers, 1, 1));
Ryan Hamilton0239aac2018-05-19 00:03:138270 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
bncd67383342016-01-08 21:58:438271 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:418272 CreateMockRead(resp, 1), CreateMockRead(body, 2),
bncd67383342016-01-08 21:58:438273 MockRead(ASYNC, 0, 3) // EOF
8274 };
8275
Bence Békydb3cf652017-10-10 15:22:108276 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
bncd67383342016-01-08 21:58:438277
Ryan Sleevib8d7ea02018-05-07 20:01:018278 SequencedSocketData data(reads, writes);
bncd67383342016-01-08 21:58:438279 helper.RunToCompletion(&data);
8280 TransactionHelperResult out = helper.output();
8281
robpercival214763f2016-07-01 23:27:018282 EXPECT_THAT(out.rv, IsOk());
bncd67383342016-01-08 21:58:438283 EXPECT_EQ("HTTP/1.1 200", out.status_line);
8284 EXPECT_EQ("hello!", out.response_data);
8285 ASSERT_TRUE(out.response_info.headers->HasHeaderValue(kKey, kValue));
8286}
8287
bnc204a6d02016-08-01 14:34:278288// End of line delimiter is forbidden according to RFC 7230 Section 3.2.
8289TEST_F(SpdyNetworkTransactionTest, CRLFInHeaderValue) {
Ryan Hamilton0239aac2018-05-19 00:03:138290 spdy::SpdySerializedFrame req(
8291 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
8292 spdy::SpdySerializedFrame rst(
8293 spdy_util_.ConstructSpdyRstStream(1, spdy::ERROR_CODE_PROTOCOL_ERROR));
bnc204a6d02016-08-01 14:34:278294 MockWrite writes[] = {CreateMockWrite(req, 0), CreateMockWrite(rst, 2)};
8295
8296 const char* response_headers[] = {"folded", "foo\r\nbar"};
Ryan Hamilton0239aac2018-05-19 00:03:138297 spdy::SpdySerializedFrame resp(
bnc204a6d02016-08-01 14:34:278298 spdy_util_.ConstructSpdyGetReply(response_headers, 1, 1));
8299 MockRead reads[] = {CreateMockRead(resp, 1), MockRead(ASYNC, 0, 3)};
8300
Ryan Sleevib8d7ea02018-05-07 20:01:018301 SequencedSocketData data(reads, writes);
bnc204a6d02016-08-01 14:34:278302
Bence Békydb3cf652017-10-10 15:22:108303 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
bnc204a6d02016-08-01 14:34:278304 helper.RunToCompletion(&data);
8305 TransactionHelperResult out = helper.output();
8306
Bence Békyd0d69502019-06-25 19:47:188307 EXPECT_THAT(out.rv, IsError(ERR_HTTP2_PROTOCOL_ERROR));
bnc204a6d02016-08-01 14:34:278308}
8309
bncc22b581e82016-10-27 04:45:428310// Regression test for https://crbug.com/603182.
8311// No response headers received before RST_STREAM: error.
8312TEST_F(SpdyNetworkTransactionTest, RstStreamNoError) {
Ryan Hamilton0239aac2018-05-19 00:03:138313 spdy::SpdySerializedFrame req(
8314 spdy_util_.ConstructChunkedSpdyPost(nullptr, 0));
bncc22b581e82016-10-27 04:45:428315 MockWrite writes[] = {CreateMockWrite(req, 0, ASYNC)};
8316
Ryan Hamilton0239aac2018-05-19 00:03:138317 spdy::SpdySerializedFrame rst(
8318 spdy_util_.ConstructSpdyRstStream(1, spdy::ERROR_CODE_NO_ERROR));
bncc22b581e82016-10-27 04:45:428319 MockRead reads[] = {CreateMockRead(rst, 1), MockRead(ASYNC, 0, 2)};
8320
Ryan Sleevib8d7ea02018-05-07 20:01:018321 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:108322 UseChunkedPostRequest();
8323 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
bncc22b581e82016-10-27 04:45:428324 helper.RunToCompletion(&data);
8325 TransactionHelperResult out = helper.output();
Bence Békyd0d69502019-06-25 19:47:188326 EXPECT_THAT(out.rv, IsError(ERR_HTTP2_PROTOCOL_ERROR));
bncc22b581e82016-10-27 04:45:428327}
8328
8329// Regression test for https://crbug.com/603182.
8330// Response headers and data, then RST_STREAM received,
8331// before request body is sent: success.
8332TEST_F(SpdyNetworkTransactionTest, RstStreamNoErrorAfterResponse) {
Ryan Hamilton0239aac2018-05-19 00:03:138333 spdy::SpdySerializedFrame req(
8334 spdy_util_.ConstructChunkedSpdyPost(nullptr, 0));
bncc22b581e82016-10-27 04:45:428335 MockWrite writes[] = {CreateMockWrite(req, 0, ASYNC)};
8336
Ryan Hamilton0239aac2018-05-19 00:03:138337 spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
8338 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
8339 spdy::SpdySerializedFrame rst(
8340 spdy_util_.ConstructSpdyRstStream(1, spdy::ERROR_CODE_NO_ERROR));
bncc22b581e82016-10-27 04:45:428341 MockRead reads[] = {CreateMockRead(resp, 1), CreateMockRead(body, 2),
8342 CreateMockRead(rst, 3), MockRead(ASYNC, 0, 4)};
8343
Ryan Sleevib8d7ea02018-05-07 20:01:018344 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:108345 UseChunkedPostRequest();
8346 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
bncc22b581e82016-10-27 04:45:428347 helper.RunToCompletion(&data);
8348 TransactionHelperResult out = helper.output();
8349 EXPECT_THAT(out.rv, IsOk());
8350 EXPECT_EQ("HTTP/1.1 200", out.status_line);
8351 EXPECT_EQ("hello!", out.response_data);
8352}
8353
bncc9f762a2016-12-06 20:38:238354TEST_F(SpdyNetworkTransactionTest, 100Continue) {
Ryan Hamilton0239aac2018-05-19 00:03:138355 spdy::SpdySerializedFrame req(
8356 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
bncc9f762a2016-12-06 20:38:238357 MockWrite writes[] = {CreateMockWrite(req, 0)};
8358
Bence Béky4c325e52020-10-22 20:48:018359 spdy::Http2HeaderBlock informational_headers;
Ryan Hamilton0239aac2018-05-19 00:03:138360 informational_headers[spdy::kHttp2StatusHeader] = "100";
8361 spdy::SpdySerializedFrame informational_response(
bncc9f762a2016-12-06 20:38:238362 spdy_util_.ConstructSpdyReply(1, std::move(informational_headers)));
Ryan Hamilton0239aac2018-05-19 00:03:138363 spdy::SpdySerializedFrame resp(
8364 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
8365 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
bncc9f762a2016-12-06 20:38:238366 MockRead reads[] = {
8367 CreateMockRead(informational_response, 1), CreateMockRead(resp, 2),
8368 CreateMockRead(body, 3), MockRead(ASYNC, 0, 4) // EOF
8369 };
8370
Ryan Sleevib8d7ea02018-05-07 20:01:018371 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:108372 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
bncc9f762a2016-12-06 20:38:238373 helper.RunToCompletion(&data);
8374 TransactionHelperResult out = helper.output();
8375 EXPECT_THAT(out.rv, IsOk());
8376 EXPECT_EQ("HTTP/1.1 200", out.status_line);
8377 EXPECT_EQ("hello!", out.response_data);
8378}
8379
bnc1ff80872016-12-16 20:57:578380// "A server can send a complete response prior to the client sending an entire
8381// request if the response does not depend on any portion of the request that
8382// has not been sent and received." (RFC7540 Section 8.1)
8383// Regression test for https://crbug.com/606990. Server responds before POST
8384// data are sent and closes connection: this must result in
Bence Békyd0d69502019-06-25 19:47:188385// ERR_CONNECTION_CLOSED (as opposed to ERR_HTTP2_PROTOCOL_ERROR).
bnc1ff80872016-12-16 20:57:578386TEST_F(SpdyNetworkTransactionTest, ResponseBeforePostDataSent) {
Ryan Hamilton0239aac2018-05-19 00:03:138387 spdy::SpdySerializedFrame req(
8388 spdy_util_.ConstructChunkedSpdyPost(nullptr, 0));
bnc1ff80872016-12-16 20:57:578389 MockWrite writes[] = {CreateMockWrite(req, 0)};
8390
Ryan Hamilton0239aac2018-05-19 00:03:138391 spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
8392 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
bnc1ff80872016-12-16 20:57:578393 MockRead reads[] = {CreateMockRead(resp, 1), CreateMockRead(body, 2),
8394 MockRead(ASYNC, 0, 3)};
8395
Ryan Sleevib8d7ea02018-05-07 20:01:018396 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:108397 UseChunkedPostRequest();
8398 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
bnc1ff80872016-12-16 20:57:578399
8400 helper.RunPreTestSetup();
8401 helper.AddData(&data);
8402 helper.StartDefaultTest();
8403 EXPECT_THAT(helper.output().rv, IsError(ERR_IO_PENDING));
8404 helper.WaitForCallbackToComplete();
8405 EXPECT_THAT(helper.output().rv, IsError(ERR_CONNECTION_CLOSED));
8406}
8407
8408// Regression test for https://crbug.com/606990.
8409// Server responds before POST data are sent and resets stream with NO_ERROR.
8410TEST_F(SpdyNetworkTransactionTest, ResponseAndRstStreamBeforePostDataSent) {
Ryan Hamilton0239aac2018-05-19 00:03:138411 spdy::SpdySerializedFrame req(
8412 spdy_util_.ConstructChunkedSpdyPost(nullptr, 0));
bnc1ff80872016-12-16 20:57:578413 MockWrite writes[] = {CreateMockWrite(req, 0)};
8414
Ryan Hamilton0239aac2018-05-19 00:03:138415 spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
8416 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
8417 spdy::SpdySerializedFrame rst(
8418 spdy_util_.ConstructSpdyRstStream(1, spdy::ERROR_CODE_NO_ERROR));
bnc1ff80872016-12-16 20:57:578419 MockRead reads[] = {CreateMockRead(resp, 1), CreateMockRead(body, 2),
8420 CreateMockRead(rst, 3), MockRead(ASYNC, 0, 4)};
8421
Ryan Sleevib8d7ea02018-05-07 20:01:018422 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:108423 UseChunkedPostRequest();
8424 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
bnc1ff80872016-12-16 20:57:578425
8426 helper.RunToCompletion(&data);
8427
8428 TransactionHelperResult out = helper.output();
8429 EXPECT_THAT(out.rv, IsOk());
8430 EXPECT_EQ("HTTP/1.1 200", out.status_line);
8431 EXPECT_EQ("hello!", out.response_data);
8432}
8433
bnc96487ec2017-03-29 19:40:238434// Unsupported frames must be ignored. This is especially important for frame
8435// type 0xb, which used to be the BLOCKED frame in previous versions of SPDY,
8436// but is going to be used for the ORIGIN frame.
8437// TODO(bnc): Implement ORIGIN frame support. https://crbug.com/697333
8438TEST_F(SpdyNetworkTransactionTest, IgnoreUnsupportedOriginFrame) {
Ryan Hamilton0239aac2018-05-19 00:03:138439 spdy::SpdySerializedFrame req(
8440 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
bnc96487ec2017-03-29 19:40:238441 MockWrite writes[] = {CreateMockWrite(req, 0)};
8442
8443 const char origin_frame_on_stream_zero[] = {
8444 0x00, 0x00, 0x05, // Length
8445 0x0b, // Type
8446 0x00, // Flags
8447 0x00, 0x00, 0x00, 0x00, // Stream ID
8448 0x00, 0x03, // Origin-Len
8449 'f', 'o', 'o' // ASCII-Origin
8450 };
8451
8452 const char origin_frame_on_stream_one[] = {
8453 0x00, 0x00, 0x05, // Length
8454 0x0b, // Type
8455 0x00, // Flags
8456 0x00, 0x00, 0x00, 0x01, // Stream ID
8457 0x00, 0x03, // Origin-Len
8458 'b', 'a', 'r' // ASCII-Origin
8459 };
8460
Ryan Hamilton0239aac2018-05-19 00:03:138461 spdy::SpdySerializedFrame resp(
8462 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
8463 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
bnc96487ec2017-03-29 19:40:238464 MockRead reads[] = {MockRead(ASYNC, origin_frame_on_stream_zero,
Avi Drissman4365a4782018-12-28 19:26:248465 base::size(origin_frame_on_stream_zero), 1),
bnc96487ec2017-03-29 19:40:238466 CreateMockRead(resp, 2),
8467 MockRead(ASYNC, origin_frame_on_stream_one,
Avi Drissman4365a4782018-12-28 19:26:248468 base::size(origin_frame_on_stream_one), 3),
bnc96487ec2017-03-29 19:40:238469 CreateMockRead(body, 4), MockRead(ASYNC, 0, 5)};
8470
Ryan Sleevib8d7ea02018-05-07 20:01:018471 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:108472 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
bnc96487ec2017-03-29 19:40:238473 helper.RunToCompletion(&data);
8474 TransactionHelperResult out = helper.output();
8475 EXPECT_THAT(out.rv, IsOk());
8476 EXPECT_EQ("HTTP/1.1 200", out.status_line);
8477 EXPECT_EQ("hello!", out.response_data);
8478}
8479
[email protected]514aeaf2014-05-23 10:31:518480class SpdyNetworkTransactionTLSUsageCheckTest
8481 : public SpdyNetworkTransactionTest {
8482 protected:
danakjaee3e1ec2016-04-16 00:23:188483 void RunTLSUsageCheckTest(
8484 std::unique_ptr<SSLSocketDataProvider> ssl_provider) {
Ryan Hamilton0239aac2018-05-19 00:03:138485 spdy::SpdySerializedFrame goaway(spdy_util_.ConstructSpdyGoAway(
8486 0, spdy::ERROR_CODE_INADEQUATE_SECURITY, ""));
bncdf80d44fd2016-07-15 20:27:418487 MockWrite writes[] = {CreateMockWrite(goaway)};
[email protected]514aeaf2014-05-23 10:31:518488
Ryan Sleevib8d7ea02018-05-07 20:01:018489 StaticSocketDataProvider data(base::span<MockRead>(), writes);
Bence Békydb3cf652017-10-10 15:22:108490 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
Bence Békyd3dde832017-09-19 19:02:318491 nullptr);
dchengc7eeda422015-12-26 03:56:488492 helper.RunToCompletionWithSSLData(&data, std::move(ssl_provider));
[email protected]514aeaf2014-05-23 10:31:518493 TransactionHelperResult out = helper.output();
Bence Békyd0d69502019-06-25 19:47:188494 EXPECT_THAT(out.rv, IsError(ERR_HTTP2_INADEQUATE_TRANSPORT_SECURITY));
[email protected]514aeaf2014-05-23 10:31:518495 }
8496};
8497
bncd16676a2016-07-20 16:23:018498TEST_F(SpdyNetworkTransactionTLSUsageCheckTest, TLSVersionTooOld) {
Jeremy Roman0579ed62017-08-29 15:56:198499 auto ssl_provider = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
[email protected]514aeaf2014-05-23 10:31:518500 SSLConnectionStatusSetVersion(SSL_CONNECTION_VERSION_SSL3,
Ryan Sleevi4f832092017-11-21 23:25:498501 &ssl_provider->ssl_info.connection_status);
[email protected]514aeaf2014-05-23 10:31:518502
dchengc7eeda422015-12-26 03:56:488503 RunTLSUsageCheckTest(std::move(ssl_provider));
[email protected]514aeaf2014-05-23 10:31:518504}
8505
bncd16676a2016-07-20 16:23:018506TEST_F(SpdyNetworkTransactionTLSUsageCheckTest, TLSCipherSuiteSucky) {
Jeremy Roman0579ed62017-08-29 15:56:198507 auto ssl_provider = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
[email protected]514aeaf2014-05-23 10:31:518508 // Set to TLS_RSA_WITH_NULL_MD5
Ryan Sleevi4f832092017-11-21 23:25:498509 SSLConnectionStatusSetCipherSuite(0x1,
8510 &ssl_provider->ssl_info.connection_status);
[email protected]514aeaf2014-05-23 10:31:518511
dchengc7eeda422015-12-26 03:56:488512 RunTLSUsageCheckTest(std::move(ssl_provider));
[email protected]514aeaf2014-05-23 10:31:518513}
8514
Bence Béky306378f2017-06-30 12:09:568515// Regression test for https://crbug.com/737143.
8516// This test sets up an old TLS version just like in TLSVersionTooOld,
Ryan Hamilton0239aac2018-05-19 00:03:138517// and makes sure that it results in an spdy::ERROR_CODE_INADEQUATE_SECURITY
Bence Béky306378f2017-06-30 12:09:568518// even for a non-secure request URL.
8519TEST_F(SpdyNetworkTransactionTest, InsecureUrlCreatesSecureSpdySession) {
Jeremy Roman0579ed62017-08-29 15:56:198520 auto ssl_provider = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
Bence Béky306378f2017-06-30 12:09:568521 SSLConnectionStatusSetVersion(SSL_CONNECTION_VERSION_SSL3,
Ryan Sleevi4f832092017-11-21 23:25:498522 &ssl_provider->ssl_info.connection_status);
Bence Béky306378f2017-06-30 12:09:568523
Ryan Hamilton0239aac2018-05-19 00:03:138524 spdy::SpdySerializedFrame goaway(spdy_util_.ConstructSpdyGoAway(
8525 0, spdy::ERROR_CODE_INADEQUATE_SECURITY, ""));
Bence Béky306378f2017-06-30 12:09:568526 MockWrite writes[] = {CreateMockWrite(goaway)};
Ryan Sleevib8d7ea02018-05-07 20:01:018527 StaticSocketDataProvider data(base::span<MockRead>(), writes);
Bence Béky306378f2017-06-30 12:09:568528
Bence Békydb3cf652017-10-10 15:22:108529 request_.url = GURL("http://www.example.org/");
Bence Béky306378f2017-06-30 12:09:568530
8531 // Need secure proxy so that insecure URL can use HTTP/2.
Jeremy Roman0579ed62017-08-29 15:56:198532 auto session_deps = std::make_unique<SpdySessionDependencies>(
Nicolas Arciniegad2013f92020-02-07 23:00:568533 ConfiguredProxyResolutionService::CreateFixedFromPacResult(
Ramin Halavatica8d5252018-03-12 05:33:498534 "HTTPS myproxy:70", TRAFFIC_ANNOTATION_FOR_TESTS));
Bence Békydb3cf652017-10-10 15:22:108535 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
Bence Békyd3dde832017-09-19 19:02:318536 std::move(session_deps));
Bence Béky306378f2017-06-30 12:09:568537
8538 helper.RunToCompletionWithSSLData(&data, std::move(ssl_provider));
8539 TransactionHelperResult out = helper.output();
Bence Békyd0d69502019-06-25 19:47:188540 EXPECT_THAT(out.rv, IsError(ERR_HTTP2_INADEQUATE_TRANSPORT_SECURITY));
Bence Békydb3cf652017-10-10 15:22:108541}
Bence Béky306378f2017-06-30 12:09:568542
Andrey Kosyakov83a6eee2017-08-14 19:20:048543TEST_F(SpdyNetworkTransactionTest, RequestHeadersCallback) {
Ryan Hamilton0239aac2018-05-19 00:03:138544 spdy::SpdySerializedFrame req(
Bence Béky27ad0a12018-02-08 00:35:488545 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, DEFAULT_PRIORITY));
Andrey Kosyakov83a6eee2017-08-14 19:20:048546 MockWrite writes[] = {CreateMockWrite(req, 0)};
8547
Ryan Hamilton0239aac2018-05-19 00:03:138548 spdy::SpdySerializedFrame resp(
8549 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
8550 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
Andrey Kosyakov83a6eee2017-08-14 19:20:048551 MockRead reads[] = {
8552 CreateMockRead(resp, 1), CreateMockRead(body, 2),
8553 MockRead(ASYNC, 0, 3) // EOF
8554 };
8555
8556 HttpRawRequestHeaders raw_headers;
8557
Ryan Sleevib8d7ea02018-05-07 20:01:018558 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:108559 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
Andrey Kosyakov83a6eee2017-08-14 19:20:048560 helper.RunPreTestSetup();
8561 helper.AddData(&data);
Steve Kobes530eb142020-07-08 18:15:518562 helper.trans()->SetRequestHeadersCallback(base::BindRepeating(
Andrey Kosyakov83a6eee2017-08-14 19:20:048563 &HttpRawRequestHeaders::Assign, base::Unretained(&raw_headers)));
8564 helper.StartDefaultTest();
8565 helper.FinishDefaultTestWithoutVerification();
8566 EXPECT_FALSE(raw_headers.headers().empty());
8567 std::string value;
8568 EXPECT_TRUE(raw_headers.FindHeaderForTest(":path", &value));
8569 EXPECT_EQ("/", value);
8570 EXPECT_TRUE(raw_headers.FindHeaderForTest(":method", &value));
8571 EXPECT_EQ("GET", value);
8572 EXPECT_TRUE(raw_headers.request_line().empty());
8573}
8574
Yoav Weiss9693572f2018-01-04 09:37:348575// A request that has adopted a push promise and later got reset by the server
8576// should be retried on a new stream.
8577// Regression test for https://crbug.com/798508.
8578TEST_F(SpdyNetworkTransactionTest, PushCanceledByServerAfterClaimed) {
8579 const char pushed_url[] = "https://www.example.org/a.dat";
8580 // Construct a request to the default URL on stream 1.
Ryan Hamilton0239aac2018-05-19 00:03:138581 spdy::SpdySerializedFrame req(
8582 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
8583 spdy::SpdySerializedFrame req2(
8584 spdy_util_.ConstructSpdyGet(pushed_url, 3, LOWEST));
Yoav Weiss9693572f2018-01-04 09:37:348585 // Construct a priority frame for stream 2.
Ryan Hamilton0239aac2018-05-19 00:03:138586 spdy::SpdySerializedFrame priority(
Yoav Weiss9693572f2018-01-04 09:37:348587 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true));
8588 MockWrite writes[] = {CreateMockWrite(req, 0), CreateMockWrite(priority, 3),
8589 CreateMockWrite(req2, 6)};
8590
8591 // Construct a Push Promise frame, with no response.
Ryan Hamilton0239aac2018-05-19 00:03:138592 spdy::SpdySerializedFrame push_promise(spdy_util_.ConstructSpdyPushPromise(
Bence Békyf1d78522018-01-11 01:16:508593 1, 2, spdy_util_.ConstructGetHeaderBlock(pushed_url)));
Yoav Weiss9693572f2018-01-04 09:37:348594 // Construct a RST frame, canceling stream 2.
Ryan Hamilton0239aac2018-05-19 00:03:138595 spdy::SpdySerializedFrame rst_server(
8596 spdy_util_.ConstructSpdyRstStream(2, spdy::ERROR_CODE_CANCEL));
Yoav Weiss9693572f2018-01-04 09:37:348597 // Construct response headers and bodies.
Ryan Hamilton0239aac2018-05-19 00:03:138598 spdy::SpdySerializedFrame resp1(
8599 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
8600 spdy::SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true));
8601 spdy::SpdySerializedFrame resp2(
8602 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
8603 spdy::SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(3, true));
Yoav Weiss9693572f2018-01-04 09:37:348604 MockRead reads[] = {
8605 CreateMockRead(push_promise, 1), MockRead(ASYNC, ERR_IO_PENDING, 2),
8606 CreateMockRead(rst_server, 4), MockRead(ASYNC, ERR_IO_PENDING, 5),
8607 CreateMockRead(resp1, 7), CreateMockRead(body1, 8),
8608 CreateMockRead(resp2, 9), CreateMockRead(body2, 10),
8609 MockRead(ASYNC, 0, 11)};
8610
Ryan Sleevib8d7ea02018-05-07 20:01:018611 SequencedSocketData data(reads, writes);
Yoav Weiss9693572f2018-01-04 09:37:348612
8613 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
8614
8615 helper.RunPreTestSetup();
8616 helper.AddData(&data);
8617
8618 HttpNetworkTransaction* trans = helper.trans();
8619
8620 // First request to start the connection.
8621 TestCompletionCallback callback1;
8622 int rv = trans->Start(&request_, callback1.callback(), log_);
8623 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
8624
8625 data.RunUntilPaused();
8626
8627 // Get a SpdySession.
8628 SpdySessionKey key(HostPortPair::FromURL(request_.url), ProxyServer::Direct(),
Matt Menke2436b2f2018-12-11 18:07:118629 PRIVACY_MODE_DISABLED,
dalyk51ab46b2019-10-15 15:14:348630 SpdySessionKey::IsProxySession::kFalse, SocketTag(),
Ben Schwartz3ff4dc1e62021-04-27 21:15:238631 NetworkIsolationKey(), SecureDnsPolicy::kAllow);
Yoav Weiss9693572f2018-01-04 09:37:348632 HttpNetworkSession* session = helper.session();
8633 base::WeakPtr<SpdySession> spdy_session =
8634 session->spdy_session_pool()->FindAvailableSession(
Bence Békyd885b2b2018-02-03 00:58:318635 key, /* enable_ip_based_pooling = */ true,
8636 /* is_websocket = */ false, log_);
Yoav Weiss9693572f2018-01-04 09:37:348637
8638 // Verify that there is one unclaimed push stream.
8639 EXPECT_EQ(1u, num_unclaimed_pushed_streams(spdy_session));
8640
8641 // Claim the pushed stream.
8642 HttpNetworkTransaction transaction2(DEFAULT_PRIORITY, session);
8643 TestCompletionCallback callback2;
8644 HttpRequestInfo request2;
8645 request2.method = "GET";
8646 request2.url = GURL(pushed_url);
Ramin Halavatib5e433e62018-02-07 07:41:108647 request2.traffic_annotation =
8648 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
Yoav Weiss9693572f2018-01-04 09:37:348649 transaction2.Start(&request2, callback2.callback(), log_);
8650 base::RunLoop().RunUntilIdle();
8651 EXPECT_EQ(3u, spdy_stream_hi_water_mark(spdy_session));
8652
8653 EXPECT_EQ(0u, num_unclaimed_pushed_streams(spdy_session));
8654
8655 // Continue reading and get the RST.
8656 data.Resume();
8657 base::RunLoop().RunUntilIdle();
8658
8659 // Make sure we got the RST and retried the request.
8660 EXPECT_EQ(2u, num_active_streams(spdy_session));
8661 EXPECT_EQ(0u, num_unclaimed_pushed_streams(spdy_session));
8662 EXPECT_EQ(5u, spdy_stream_hi_water_mark(spdy_session));
8663
8664 data.Resume();
8665
8666 // Test that transactions succeeded.
8667 rv = callback1.WaitForResult();
8668 ASSERT_THAT(rv, IsOk());
8669
8670 rv = callback2.WaitForResult();
8671 ASSERT_THAT(rv, IsOk());
8672
8673 // Read EOF.
8674 base::RunLoop().RunUntilIdle();
8675
8676 // Verify that all data was read and written.
8677 helper.VerifyDataConsumed();
8678}
8679
Bence Béky0ca719f2018-01-31 13:41:198680#if BUILDFLAG(ENABLE_WEBSOCKETS)
Bence Béky8bfacd42018-02-23 13:05:138681
8682TEST_F(SpdyNetworkTransactionTest, WebSocketOpensNewConnection) {
Bence Békyb09dddf12018-07-31 18:52:048683 base::HistogramTester histogram_tester;
Bence Béky0ca719f2018-01-31 13:41:198684 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
8685 helper.RunPreTestSetup();
8686
8687 // First request opens up an HTTP/2 connection.
Ryan Hamilton0239aac2018-05-19 00:03:138688 spdy::SpdySerializedFrame req(
Bence Béky8bfacd42018-02-23 13:05:138689 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, DEFAULT_PRIORITY));
Bence Béky0ca719f2018-01-31 13:41:198690 MockWrite writes1[] = {CreateMockWrite(req, 0)};
8691
Ryan Hamilton0239aac2018-05-19 00:03:138692 spdy::SpdySerializedFrame resp(
8693 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
8694 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
Bence Béky0ca719f2018-01-31 13:41:198695 MockRead reads1[] = {CreateMockRead(resp, 1), CreateMockRead(body, 2),
8696 MockRead(ASYNC, ERR_IO_PENDING, 3),
8697 MockRead(ASYNC, 0, 4)};
8698
Ryan Sleevib8d7ea02018-05-07 20:01:018699 SequencedSocketData data1(reads1, writes1);
Bence Béky0ca719f2018-01-31 13:41:198700 helper.AddData(&data1);
8701
Bence Béky8bfacd42018-02-23 13:05:138702 // WebSocket request opens a new connection with HTTP/2 disabled.
Bence Béky0ca719f2018-01-31 13:41:198703 MockWrite writes2[] = {
8704 MockWrite("GET / HTTP/1.1\r\n"
8705 "Host: www.example.org\r\n"
8706 "Connection: Upgrade\r\n"
8707 "Upgrade: websocket\r\n"
8708 "Origin: http://www.example.org\r\n"
8709 "Sec-WebSocket-Version: 13\r\n"
Bence Béky8d1c6052018-02-07 12:48:158710 "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
8711 "Sec-WebSocket-Extensions: permessage-deflate; "
8712 "client_max_window_bits\r\n\r\n")};
Bence Béky0ca719f2018-01-31 13:41:198713
Bence Béky8d1c6052018-02-07 12:48:158714 MockRead reads2[] = {
8715 MockRead("HTTP/1.1 101 Switching Protocols\r\n"
8716 "Upgrade: websocket\r\n"
8717 "Connection: Upgrade\r\n"
8718 "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n\r\n")};
8719
Ryan Sleevib8d7ea02018-05-07 20:01:018720 StaticSocketDataProvider data2(reads2, writes2);
Bence Béky0ca719f2018-01-31 13:41:198721
8722 auto ssl_provider2 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
8723 // Test that request has empty |alpn_protos|, that is, HTTP/2 is disabled.
8724 ssl_provider2->next_protos_expected_in_ssl_config = NextProtoVector{};
8725 // Force socket to use HTTP/1.1, the default protocol without ALPN.
8726 ssl_provider2->next_proto = kProtoHTTP11;
8727 ssl_provider2->ssl_info.cert =
8728 ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem");
8729 helper.AddDataWithSSLSocketDataProvider(&data2, std::move(ssl_provider2));
8730
8731 TestCompletionCallback callback1;
8732 HttpNetworkTransaction trans1(DEFAULT_PRIORITY, helper.session());
8733 int rv = trans1.Start(&request_, callback1.callback(), log_);
8734 ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
8735 rv = callback1.WaitForResult();
8736 ASSERT_THAT(rv, IsOk());
8737
8738 const HttpResponseInfo* response = trans1.GetResponseInfo();
8739 ASSERT_TRUE(response->headers);
8740 EXPECT_TRUE(response->was_fetched_via_spdy);
8741 EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
8742
8743 std::string response_data;
8744 rv = ReadTransaction(&trans1, &response_data);
8745 EXPECT_THAT(rv, IsOk());
8746 EXPECT_EQ("hello!", response_data);
8747
8748 SpdySessionKey key(HostPortPair::FromURL(request_.url), ProxyServer::Direct(),
Matt Menke2436b2f2018-12-11 18:07:118749 PRIVACY_MODE_DISABLED,
dalyk51ab46b2019-10-15 15:14:348750 SpdySessionKey::IsProxySession::kFalse, SocketTag(),
Ben Schwartz3ff4dc1e62021-04-27 21:15:238751 NetworkIsolationKey(), SecureDnsPolicy::kAllow);
Bence Béky0ca719f2018-01-31 13:41:198752 base::WeakPtr<SpdySession> spdy_session =
8753 helper.session()->spdy_session_pool()->FindAvailableSession(
Bence Békyd885b2b2018-02-03 00:58:318754 key, /* enable_ip_based_pooling = */ true,
8755 /* is_websocket = */ false, log_);
Bence Béky0ca719f2018-01-31 13:41:198756 ASSERT_TRUE(spdy_session);
Bence Békyd885b2b2018-02-03 00:58:318757 EXPECT_FALSE(spdy_session->support_websocket());
Bence Béky0ca719f2018-01-31 13:41:198758
8759 HttpRequestInfo request2;
8760 request2.method = "GET";
8761 request2.url = GURL("wss://www.example.org/");
Ramin Halavatib5e433e62018-02-07 07:41:108762 request2.traffic_annotation =
8763 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
Bence Béky0ca719f2018-01-31 13:41:198764 EXPECT_TRUE(HostPortPair::FromURL(request_.url)
8765 .Equals(HostPortPair::FromURL(request2.url)));
8766 request2.extra_headers.SetHeader("Connection", "Upgrade");
8767 request2.extra_headers.SetHeader("Upgrade", "websocket");
8768 request2.extra_headers.SetHeader("Origin", "http://www.example.org");
8769 request2.extra_headers.SetHeader("Sec-WebSocket-Version", "13");
Bence Béky8d1c6052018-02-07 12:48:158770
8771 TestWebSocketHandshakeStreamCreateHelper websocket_stream_create_helper;
Bence Béky0ca719f2018-01-31 13:41:198772
8773 HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session());
Bence Béky0ca719f2018-01-31 13:41:198774 trans2.SetWebSocketHandshakeStreamCreateHelper(
8775 &websocket_stream_create_helper);
8776
8777 TestCompletionCallback callback2;
8778 rv = trans2.Start(&request2, callback2.callback(), log_);
8779 ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
8780 rv = callback2.WaitForResult();
8781 ASSERT_THAT(rv, IsOk());
8782
Bence Béky8bfacd42018-02-23 13:05:138783 // HTTP/2 connection is still open, but WebSocket request did not pool to it.
Bence Béky0ca719f2018-01-31 13:41:198784 ASSERT_TRUE(spdy_session);
8785
Bence Béky0ca719f2018-01-31 13:41:198786 data1.Resume();
Bence Békyb09dddf12018-07-31 18:52:048787 base::RunLoop().RunUntilIdle();
Bence Béky0ca719f2018-01-31 13:41:198788 helper.VerifyDataConsumed();
Bence Békyb09dddf12018-07-31 18:52:048789
8790 // Server did not advertise WebSocket support.
8791 histogram_tester.ExpectUniqueSample("Net.SpdySession.ServerSupportsWebSocket",
8792 /* support_websocket = false */ 0,
8793 /* expected_count = */ 1);
Bence Béky0ca719f2018-01-31 13:41:198794}
Bence Béky8bfacd42018-02-23 13:05:138795
Matt Menke77173952019-04-18 17:42:148796// Make sure that a WebSocket job doesn't pick up a newly created SpdySession
8797// that doesn't support WebSockets through
8798// HttpStreamFactory::Job::OnSpdySessionAvailable().
8799TEST_F(SpdyNetworkTransactionTest,
8800 WebSocketDoesUseNewH2SessionWithoutWebSocketSupport) {
8801 base::HistogramTester histogram_tester;
8802 auto session_deps = std::make_unique<SpdySessionDependencies>();
8803 session_deps->enable_websocket_over_http2 = true;
8804 NormalSpdyTransactionHelper helper(request_, HIGHEST, log_,
8805 std::move(session_deps));
8806 helper.RunPreTestSetup();
8807
8808 spdy::SpdySerializedFrame req(
8809 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, HIGHEST));
8810
8811 MockWrite writes[] = {CreateMockWrite(req, 0)};
8812
8813 spdy::SpdySerializedFrame resp1(
8814 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
8815 spdy::SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true));
8816 MockRead reads[] = {CreateMockRead(resp1, 1), CreateMockRead(body1, 2),
8817 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 3)};
8818
8819 SequencedSocketData data(
8820 // Just as with other operations, this means to pause during connection
8821 // establishment.
8822 MockConnect(ASYNC, ERR_IO_PENDING), reads, writes);
8823 helper.AddData(&data);
8824
8825 MockWrite writes2[] = {
8826 MockWrite(SYNCHRONOUS, 0,
8827 "GET / HTTP/1.1\r\n"
8828 "Host: www.example.org\r\n"
8829 "Connection: Upgrade\r\n"
8830 "Upgrade: websocket\r\n"
8831 "Origin: http://www.example.org\r\n"
8832 "Sec-WebSocket-Version: 13\r\n"
8833 "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
8834 "Sec-WebSocket-Extensions: permessage-deflate; "
8835 "client_max_window_bits\r\n\r\n")};
8836
8837 MockRead reads2[] = {
8838 MockRead(SYNCHRONOUS, 1,
8839 "HTTP/1.1 101 Switching Protocols\r\n"
8840 "Upgrade: websocket\r\n"
8841 "Connection: Upgrade\r\n"
8842 "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n\r\n")};
8843 SequencedSocketData data2(MockConnect(ASYNC, ERR_IO_PENDING), reads2,
8844 writes2);
8845 auto ssl_provider2 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
8846 // Test that request has empty |alpn_protos|, that is, HTTP/2 is disabled.
8847 ssl_provider2->next_protos_expected_in_ssl_config = NextProtoVector{};
8848 // Force socket to use HTTP/1.1, the default protocol without ALPN.
8849 ssl_provider2->next_proto = kProtoHTTP11;
Matt Menke77173952019-04-18 17:42:148850 helper.AddDataWithSSLSocketDataProvider(&data2, std::move(ssl_provider2));
8851
8852 TestCompletionCallback callback1;
8853 int rv = helper.trans()->Start(&request_, callback1.callback(), log_);
8854 ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
8855
8856 // Create HTTP/2 connection.
8857 base::RunLoop().RunUntilIdle();
8858
8859 HttpRequestInfo request2;
8860 request2.method = "GET";
8861 request2.url = GURL("wss://www.example.org/");
8862 request2.traffic_annotation =
8863 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
8864 EXPECT_TRUE(HostPortPair::FromURL(request_.url)
8865 .Equals(HostPortPair::FromURL(request2.url)));
8866 request2.extra_headers.SetHeader("Connection", "Upgrade");
8867 request2.extra_headers.SetHeader("Upgrade", "websocket");
8868 request2.extra_headers.SetHeader("Origin", "http://www.example.org");
8869 request2.extra_headers.SetHeader("Sec-WebSocket-Version", "13");
8870
8871 TestWebSocketHandshakeStreamCreateHelper websocket_stream_create_helper;
8872
8873 HttpNetworkTransaction trans2(MEDIUM, helper.session());
8874 trans2.SetWebSocketHandshakeStreamCreateHelper(
8875 &websocket_stream_create_helper);
8876
8877 TestCompletionCallback callback2;
8878 rv = trans2.Start(&request2, callback2.callback(), log_);
8879 ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
8880
8881 // Run until waiting on both connections.
8882 base::RunLoop().RunUntilIdle();
8883
8884 // The H2 connection completes.
8885 data.socket()->OnConnectComplete(MockConnect(SYNCHRONOUS, OK));
8886 EXPECT_EQ(OK, callback1.WaitForResult());
8887 const HttpResponseInfo* response = helper.trans()->GetResponseInfo();
8888 ASSERT_TRUE(response->headers);
8889 EXPECT_TRUE(response->was_fetched_via_spdy);
8890 EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
8891 std::string response_data;
8892 rv = ReadTransaction(helper.trans(), &response_data);
8893 EXPECT_THAT(rv, IsOk());
8894 EXPECT_EQ("hello!", response_data);
8895
8896 SpdySessionKey key(HostPortPair::FromURL(request_.url), ProxyServer::Direct(),
8897 PRIVACY_MODE_DISABLED,
dalyk51ab46b2019-10-15 15:14:348898 SpdySessionKey::IsProxySession::kFalse, SocketTag(),
Ben Schwartz3ff4dc1e62021-04-27 21:15:238899 NetworkIsolationKey(), SecureDnsPolicy::kAllow);
Matt Menke77173952019-04-18 17:42:148900
8901 base::WeakPtr<SpdySession> spdy_session =
8902 helper.session()->spdy_session_pool()->FindAvailableSession(
8903 key, /* enable_ip_based_pooling = */ true,
8904 /* is_websocket = */ false, log_);
8905 ASSERT_TRUE(spdy_session);
8906 EXPECT_FALSE(spdy_session->support_websocket());
8907
8908 EXPECT_FALSE(callback2.have_result());
8909
8910 // Create WebSocket stream.
8911 data2.socket()->OnConnectComplete(MockConnect(SYNCHRONOUS, OK));
8912
8913 rv = callback2.WaitForResult();
8914 ASSERT_THAT(rv, IsOk());
8915 helper.VerifyDataConsumed();
8916}
8917
Bence Béky8bfacd42018-02-23 13:05:138918TEST_F(SpdyNetworkTransactionTest, WebSocketOverHTTP2) {
Bence Békyb09dddf12018-07-31 18:52:048919 base::HistogramTester histogram_tester;
Bence Béky8bfacd42018-02-23 13:05:138920 auto session_deps = std::make_unique<SpdySessionDependencies>();
8921 session_deps->enable_websocket_over_http2 = true;
Bence Béky7a4836c2018-05-08 03:52:488922 NormalSpdyTransactionHelper helper(request_, HIGHEST, log_,
Bence Béky8bfacd42018-02-23 13:05:138923 std::move(session_deps));
8924 helper.RunPreTestSetup();
8925
Ryan Hamilton0239aac2018-05-19 00:03:138926 spdy::SpdySerializedFrame req(
8927 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, HIGHEST));
8928 spdy::SpdySerializedFrame settings_ack(spdy_util_.ConstructSpdySettingsAck());
Bence Béky8bfacd42018-02-23 13:05:138929
Bence Béky4c325e52020-10-22 20:48:018930 spdy::Http2HeaderBlock websocket_request_headers;
Ryan Hamilton0239aac2018-05-19 00:03:138931 websocket_request_headers[spdy::kHttp2MethodHeader] = "CONNECT";
8932 websocket_request_headers[spdy::kHttp2AuthorityHeader] = "www.example.org";
8933 websocket_request_headers[spdy::kHttp2SchemeHeader] = "https";
8934 websocket_request_headers[spdy::kHttp2PathHeader] = "/";
8935 websocket_request_headers[spdy::kHttp2ProtocolHeader] = "websocket";
Bence Béky8bfacd42018-02-23 13:05:138936 websocket_request_headers["origin"] = "http://www.example.org";
8937 websocket_request_headers["sec-websocket-version"] = "13";
8938 websocket_request_headers["sec-websocket-extensions"] =
8939 "permessage-deflate; client_max_window_bits";
Ryan Hamilton0239aac2018-05-19 00:03:138940 spdy::SpdySerializedFrame websocket_request(spdy_util_.ConstructSpdyHeaders(
Bence Béky7a4836c2018-05-08 03:52:488941 3, std::move(websocket_request_headers), MEDIUM, false));
8942
Bence Béky73b85292018-06-14 04:56:438943 spdy::SpdySerializedFrame priority1(
8944 spdy_util_.ConstructSpdyPriority(3, 0, MEDIUM, true));
8945 spdy::SpdySerializedFrame priority2(
8946 spdy_util_.ConstructSpdyPriority(1, 3, LOWEST, true));
8947
8948 MockWrite writes[] = {
8949 CreateMockWrite(req, 0), CreateMockWrite(settings_ack, 2),
8950 CreateMockWrite(websocket_request, 4), CreateMockWrite(priority1, 5),
8951 CreateMockWrite(priority2, 6)};
Bence Béky8bfacd42018-02-23 13:05:138952
Ryan Hamilton0239aac2018-05-19 00:03:138953 spdy::SettingsMap settings;
8954 settings[spdy::SETTINGS_ENABLE_CONNECT_PROTOCOL] = 1;
8955 spdy::SpdySerializedFrame settings_frame(
Bence Béky8bfacd42018-02-23 13:05:138956 spdy_util_.ConstructSpdySettings(settings));
Ryan Hamilton0239aac2018-05-19 00:03:138957 spdy::SpdySerializedFrame resp1(
8958 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
8959 spdy::SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true));
8960 spdy::SpdySerializedFrame websocket_response(
Bence Béky8bfacd42018-02-23 13:05:138961 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
Bence Béky73b85292018-06-14 04:56:438962 MockRead reads[] = {CreateMockRead(settings_frame, 1),
8963 CreateMockRead(resp1, 3), CreateMockRead(body1, 7),
8964 CreateMockRead(websocket_response, 8),
8965 MockRead(ASYNC, 0, 9)};
Bence Béky8bfacd42018-02-23 13:05:138966
Ryan Sleevib8d7ea02018-05-07 20:01:018967 SequencedSocketData data(reads, writes);
Bence Béky8bfacd42018-02-23 13:05:138968 helper.AddData(&data);
8969
8970 TestCompletionCallback callback1;
Bence Béky7a4836c2018-05-08 03:52:488971 int rv = helper.trans()->Start(&request_, callback1.callback(), log_);
Bence Béky8bfacd42018-02-23 13:05:138972 ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
Bence Béky8bfacd42018-02-23 13:05:138973
Bence Béky7a4836c2018-05-08 03:52:488974 // Create HTTP/2 connection.
8975 base::RunLoop().RunUntilIdle();
Bence Béky8bfacd42018-02-23 13:05:138976
8977 SpdySessionKey key(HostPortPair::FromURL(request_.url), ProxyServer::Direct(),
Matt Menke2436b2f2018-12-11 18:07:118978 PRIVACY_MODE_DISABLED,
dalyk51ab46b2019-10-15 15:14:348979 SpdySessionKey::IsProxySession::kFalse, SocketTag(),
Ben Schwartz3ff4dc1e62021-04-27 21:15:238980 NetworkIsolationKey(), SecureDnsPolicy::kAllow);
Bence Béky8bfacd42018-02-23 13:05:138981 base::WeakPtr<SpdySession> spdy_session =
8982 helper.session()->spdy_session_pool()->FindAvailableSession(
8983 key, /* enable_ip_based_pooling = */ true,
8984 /* is_websocket = */ true, log_);
8985 ASSERT_TRUE(spdy_session);
8986 EXPECT_TRUE(spdy_session->support_websocket());
8987
8988 HttpRequestInfo request2;
8989 request2.method = "GET";
8990 request2.url = GURL("wss://www.example.org/");
8991 request2.traffic_annotation =
8992 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
8993 EXPECT_TRUE(HostPortPair::FromURL(request_.url)
8994 .Equals(HostPortPair::FromURL(request2.url)));
8995 request2.extra_headers.SetHeader("Origin", "http://www.example.org");
8996 request2.extra_headers.SetHeader("Sec-WebSocket-Version", "13");
8997 // The following two headers must be removed by WebSocketHttp2HandshakeStream.
8998 request2.extra_headers.SetHeader("Connection", "Upgrade");
8999 request2.extra_headers.SetHeader("Upgrade", "websocket");
9000
9001 TestWebSocketHandshakeStreamCreateHelper websocket_stream_create_helper;
9002
Bence Béky7a4836c2018-05-08 03:52:489003 HttpNetworkTransaction trans2(MEDIUM, helper.session());
Bence Béky8bfacd42018-02-23 13:05:139004 trans2.SetWebSocketHandshakeStreamCreateHelper(
9005 &websocket_stream_create_helper);
9006
9007 TestCompletionCallback callback2;
9008 rv = trans2.Start(&request2, callback2.callback(), log_);
9009 ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
Bence Béky7a4836c2018-05-08 03:52:489010
9011 // Create WebSocket stream.
9012 base::RunLoop().RunUntilIdle();
Bence Béky73b85292018-06-14 04:56:439013 ASSERT_TRUE(spdy_session);
9014
9015 // First request has HIGHEST priority, WebSocket request has MEDIUM priority.
9016 // Changing the priority of the first request to LOWEST changes their order,
9017 // and therefore triggers sending PRIORITY frames.
9018 helper.trans()->SetPriority(LOWEST);
Bence Béky7a4836c2018-05-08 03:52:489019
9020 rv = callback1.WaitForResult();
9021 ASSERT_THAT(rv, IsOk());
9022
9023 const HttpResponseInfo* response = helper.trans()->GetResponseInfo();
9024 ASSERT_TRUE(response->headers);
9025 EXPECT_TRUE(response->was_fetched_via_spdy);
9026 EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
9027
9028 std::string response_data;
9029 rv = ReadTransaction(helper.trans(), &response_data);
9030 EXPECT_THAT(rv, IsOk());
9031 EXPECT_EQ("hello!", response_data);
9032
Bence Béky8bfacd42018-02-23 13:05:139033 rv = callback2.WaitForResult();
9034 ASSERT_THAT(rv, IsOk());
9035
Bence Béky8bfacd42018-02-23 13:05:139036 helper.VerifyDataConsumed();
Bence Békyb09dddf12018-07-31 18:52:049037
9038 // Server advertised WebSocket support.
9039 histogram_tester.ExpectUniqueSample("Net.SpdySession.ServerSupportsWebSocket",
9040 /* support_websocket = true */ 1,
9041 /* expected_count = */ 1);
Bence Béky8bfacd42018-02-23 13:05:139042}
9043
Matt Menke7269f352019-10-03 17:05:299044// Make sure that a WebSocket job doesn't pick up a newly created SpdySession
9045// that supports WebSockets through an HTTPS proxy when an H2 server doesn't
9046// support websockets and |enable_websocket_over_http2| is false. See
9047// https://crbug.com/1010491.
9048TEST_F(SpdyNetworkTransactionTest,
9049 WebSocketDoesNotUseNewH2SessionWithoutWebSocketSupportOverHttpsProxy) {
9050 auto session_deps = std::make_unique<SpdySessionDependencies>(
Nicolas Arciniegad2013f92020-02-07 23:00:569051 ConfiguredProxyResolutionService::CreateFixed(
9052 "https://proxy:70", TRAFFIC_ANNOTATION_FOR_TESTS));
Matt Menke7269f352019-10-03 17:05:299053
9054 // Note: Once WebSocket over H2 is enabled by default, this line can be
9055 // deleted, and this test will still be useful to keep, though its description
9056 // will need to be updated.
9057 session_deps->enable_websocket_over_http2 = false;
9058
9059 NormalSpdyTransactionHelper helper(request_, HIGHEST, log_,
9060 std::move(session_deps));
9061 helper.RunPreTestSetup();
9062
9063 spdy::SpdySerializedFrame req(
9064 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, HIGHEST));
9065
9066 MockWrite writes[] = {MockWrite(SYNCHRONOUS, 0,
9067 "CONNECT www.example.org:443 HTTP/1.1\r\n"
9068 "Host: www.example.org:443\r\n"
9069 "Proxy-Connection: keep-alive\r\n\r\n"),
9070 CreateMockWrite(req, 2)};
9071
9072 spdy::SpdySerializedFrame resp1(
9073 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
9074 spdy::SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true));
9075 MockRead reads[] = {MockRead(SYNCHRONOUS, 1, "HTTP/1.1 200 OK\r\n\r\n"),
9076 CreateMockRead(resp1, 3), CreateMockRead(body1, 4),
9077 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 5)};
9078
9079 // SSL data for the proxy.
9080 SSLSocketDataProvider tunnel_ssl_data(ASYNC, OK);
9081 helper.session_deps()->socket_factory->AddSSLSocketDataProvider(
9082 &tunnel_ssl_data);
9083
9084 SequencedSocketData data(
9085 // Just as with other operations, this means to pause during connection
9086 // establishment.
9087 MockConnect(ASYNC, ERR_IO_PENDING), reads, writes);
9088 helper.AddData(&data);
9089
9090 MockWrite writes2[] = {
9091 MockWrite(SYNCHRONOUS, 0,
9092 "CONNECT www.example.org:443 HTTP/1.1\r\n"
9093 "Host: www.example.org:443\r\n"
9094 "Proxy-Connection: keep-alive\r\n\r\n"),
9095 MockWrite(SYNCHRONOUS, 2,
9096 "GET / HTTP/1.1\r\n"
9097 "Host: www.example.org\r\n"
9098 "Connection: Upgrade\r\n"
9099 "Upgrade: websocket\r\n"
9100 "Origin: http://www.example.org\r\n"
9101 "Sec-WebSocket-Version: 13\r\n"
9102 "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
9103 "Sec-WebSocket-Extensions: permessage-deflate; "
9104 "client_max_window_bits\r\n\r\n")};
9105
9106 MockRead reads2[] = {
9107 MockRead(SYNCHRONOUS, 1, "HTTP/1.1 200 OK\r\n\r\n"),
9108 MockRead(SYNCHRONOUS, 3,
9109 "HTTP/1.1 101 Switching Protocols\r\n"
9110 "Upgrade: websocket\r\n"
9111 "Connection: Upgrade\r\n"
9112 "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n\r\n")};
9113 SequencedSocketData data2(MockConnect(ASYNC, ERR_IO_PENDING), reads2,
9114 writes2);
9115
9116 // SSL data for the proxy.
9117 SSLSocketDataProvider tunnel_ssl_data2(ASYNC, OK);
9118 helper.session_deps()->socket_factory->AddSSLSocketDataProvider(
9119 &tunnel_ssl_data2);
9120
9121 auto ssl_provider2 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
9122 // Test that request has empty |alpn_protos|, that is, HTTP/2 is disabled.
9123 ssl_provider2->next_protos_expected_in_ssl_config = NextProtoVector{};
9124 // Force socket to use HTTP/1.1, the default protocol without ALPN.
9125 ssl_provider2->next_proto = kProtoHTTP11;
9126 helper.AddDataWithSSLSocketDataProvider(&data2, std::move(ssl_provider2));
9127
9128 TestCompletionCallback callback1;
9129 int rv = helper.trans()->Start(&request_, callback1.callback(), log_);
9130 ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
9131
9132 // Create HTTP/2 connection.
9133 base::RunLoop().RunUntilIdle();
9134
9135 HttpRequestInfo request2;
9136 request2.method = "GET";
9137 request2.url = GURL("wss://www.example.org/");
9138 request2.traffic_annotation =
9139 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
9140 EXPECT_TRUE(HostPortPair::FromURL(request_.url)
9141 .Equals(HostPortPair::FromURL(request2.url)));
9142 request2.extra_headers.SetHeader("Connection", "Upgrade");
9143 request2.extra_headers.SetHeader("Upgrade", "websocket");
9144 request2.extra_headers.SetHeader("Origin", "http://www.example.org");
9145 request2.extra_headers.SetHeader("Sec-WebSocket-Version", "13");
9146
9147 TestWebSocketHandshakeStreamCreateHelper websocket_stream_create_helper;
9148
9149 HttpNetworkTransaction trans2(MEDIUM, helper.session());
9150 trans2.SetWebSocketHandshakeStreamCreateHelper(
9151 &websocket_stream_create_helper);
9152
9153 TestCompletionCallback callback2;
9154 rv = trans2.Start(&request2, callback2.callback(), log_);
9155 ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
9156
9157 // Run until waiting on both connections.
9158 base::RunLoop().RunUntilIdle();
9159
9160 // The H2 connection completes.
9161 data.socket()->OnConnectComplete(MockConnect(SYNCHRONOUS, OK));
9162 EXPECT_EQ(OK, callback1.WaitForResult());
9163 const HttpResponseInfo* response = helper.trans()->GetResponseInfo();
9164 ASSERT_TRUE(response->headers);
9165 EXPECT_TRUE(response->was_fetched_via_spdy);
9166 EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
9167 std::string response_data;
9168 rv = ReadTransaction(helper.trans(), &response_data);
9169 EXPECT_THAT(rv, IsOk());
9170 EXPECT_EQ("hello!", response_data);
9171
9172 SpdySessionKey key(
9173 HostPortPair::FromURL(request_.url),
9174 ProxyServer::FromURI("https://proxy:70", ProxyServer::SCHEME_HTTPS),
9175 PRIVACY_MODE_DISABLED, SpdySessionKey::IsProxySession::kFalse,
Ben Schwartz3ff4dc1e62021-04-27 21:15:239176 SocketTag(), NetworkIsolationKey(), SecureDnsPolicy::kAllow);
Matt Menke7269f352019-10-03 17:05:299177
9178 base::WeakPtr<SpdySession> spdy_session =
9179 helper.session()->spdy_session_pool()->FindAvailableSession(
9180 key, /* enable_ip_based_pooling = */ true,
9181 /* is_websocket = */ false, log_);
9182 ASSERT_TRUE(spdy_session);
9183 EXPECT_FALSE(spdy_session->support_websocket());
9184
9185 EXPECT_FALSE(callback2.have_result());
9186
9187 // Create WebSocket stream.
9188 data2.socket()->OnConnectComplete(MockConnect(SYNCHRONOUS, OK));
9189
9190 rv = callback2.WaitForResult();
9191 ASSERT_THAT(rv, IsOk());
9192 helper.VerifyDataConsumed();
9193}
9194
Matt Menke5062be22019-05-01 17:50:249195// Same as above, but checks that a WebSocket connection avoids creating a new
9196// socket if it detects an H2 session when host resolution completes, and
9197// requests also use different hostnames.
9198TEST_F(SpdyNetworkTransactionTest,
9199 WebSocketOverHTTP2DetectsNewSessionWithAliasing) {
9200 base::HistogramTester histogram_tester;
9201 auto session_deps = std::make_unique<SpdySessionDependencies>();
9202 session_deps->enable_websocket_over_http2 = true;
9203 session_deps->host_resolver->set_ondemand_mode(true);
9204 NormalSpdyTransactionHelper helper(request_, HIGHEST, log_,
9205 std::move(session_deps));
9206 helper.RunPreTestSetup();
9207
9208 spdy::SpdySerializedFrame req(
9209 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, HIGHEST));
9210 spdy::SpdySerializedFrame settings_ack(spdy_util_.ConstructSpdySettingsAck());
9211
Bence Béky4c325e52020-10-22 20:48:019212 spdy::Http2HeaderBlock websocket_request_headers;
Matt Menke5062be22019-05-01 17:50:249213 websocket_request_headers[spdy::kHttp2MethodHeader] = "CONNECT";
9214 websocket_request_headers[spdy::kHttp2AuthorityHeader] = "example.test";
9215 websocket_request_headers[spdy::kHttp2SchemeHeader] = "https";
9216 websocket_request_headers[spdy::kHttp2PathHeader] = "/";
9217 websocket_request_headers[spdy::kHttp2ProtocolHeader] = "websocket";
9218 websocket_request_headers["origin"] = "http://example.test";
9219 websocket_request_headers["sec-websocket-version"] = "13";
9220 websocket_request_headers["sec-websocket-extensions"] =
9221 "permessage-deflate; client_max_window_bits";
9222 spdy::SpdySerializedFrame websocket_request(spdy_util_.ConstructSpdyHeaders(
9223 3, std::move(websocket_request_headers), MEDIUM, false));
9224
9225 spdy::SpdySerializedFrame priority1(
9226 spdy_util_.ConstructSpdyPriority(3, 0, MEDIUM, true));
9227 spdy::SpdySerializedFrame priority2(
9228 spdy_util_.ConstructSpdyPriority(1, 3, LOWEST, true));
9229
9230 MockWrite writes[] = {
9231 CreateMockWrite(req, 0), CreateMockWrite(settings_ack, 2),
9232 CreateMockWrite(websocket_request, 4), CreateMockWrite(priority1, 5),
9233 CreateMockWrite(priority2, 6)};
9234
9235 spdy::SettingsMap settings;
9236 settings[spdy::SETTINGS_ENABLE_CONNECT_PROTOCOL] = 1;
9237 spdy::SpdySerializedFrame settings_frame(
9238 spdy_util_.ConstructSpdySettings(settings));
9239 spdy::SpdySerializedFrame resp1(
9240 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
9241 spdy::SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true));
9242 spdy::SpdySerializedFrame websocket_response(
9243 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
9244 MockRead reads[] = {CreateMockRead(settings_frame, 1),
9245 CreateMockRead(resp1, 3), CreateMockRead(body1, 7),
9246 CreateMockRead(websocket_response, 8),
9247 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 9)};
9248
9249 SequencedSocketData data(reads, writes);
9250 helper.AddData(&data);
9251
9252 TestCompletionCallback callback1;
9253 int rv = helper.trans()->Start(&request_, callback1.callback(), log_);
9254 ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
9255
9256 HttpRequestInfo request2;
9257 request2.method = "GET";
9258 request2.url = GURL("wss://example.test/");
9259 request2.traffic_annotation =
9260 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
9261 request2.extra_headers.SetHeader("Origin", "http://example.test");
9262 request2.extra_headers.SetHeader("Sec-WebSocket-Version", "13");
9263 // The following two headers must be removed by WebSocketHttp2HandshakeStream.
9264 request2.extra_headers.SetHeader("Connection", "Upgrade");
9265 request2.extra_headers.SetHeader("Upgrade", "websocket");
9266
9267 TestWebSocketHandshakeStreamCreateHelper websocket_stream_create_helper;
9268
9269 HttpNetworkTransaction trans2(MEDIUM, helper.session());
9270 trans2.SetWebSocketHandshakeStreamCreateHelper(
9271 &websocket_stream_create_helper);
9272
9273 TestCompletionCallback callback2;
9274 rv = trans2.Start(&request2, callback2.callback(), log_);
9275 ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
9276
9277 // Make sure both requests are blocked on host resolution.
9278 base::RunLoop().RunUntilIdle();
9279
9280 EXPECT_TRUE(helper.session_deps()->host_resolver->has_pending_requests());
9281 // Complete the first DNS lookup, which should result in the first transaction
9282 // creating an H2 session (And completing successfully).
9283 helper.session_deps()->host_resolver->ResolveNow(1);
9284 base::RunLoop().RunUntilIdle();
9285
9286 SpdySessionKey key1(HostPortPair::FromURL(request_.url),
9287 ProxyServer::Direct(), PRIVACY_MODE_DISABLED,
dalyk51ab46b2019-10-15 15:14:349288 SpdySessionKey::IsProxySession::kFalse, SocketTag(),
Ben Schwartz3ff4dc1e62021-04-27 21:15:239289 NetworkIsolationKey(), SecureDnsPolicy::kAllow);
Matt Menke5062be22019-05-01 17:50:249290 base::WeakPtr<SpdySession> spdy_session1 =
9291 helper.session()->spdy_session_pool()->FindAvailableSession(
9292 key1, /* enable_ip_based_pooling = */ true,
9293 /* is_websocket = */ false, log_);
9294 ASSERT_TRUE(spdy_session1);
9295 EXPECT_TRUE(spdy_session1->support_websocket());
9296
9297 // Second DNS lookup completes, which results in creating a WebSocket stream.
9298 helper.session_deps()->host_resolver->ResolveNow(2);
9299 ASSERT_TRUE(spdy_session1);
9300
9301 SpdySessionKey key2(HostPortPair::FromURL(request2.url),
9302 ProxyServer::Direct(), PRIVACY_MODE_DISABLED,
dalyk51ab46b2019-10-15 15:14:349303 SpdySessionKey::IsProxySession::kFalse, SocketTag(),
Ben Schwartz3ff4dc1e62021-04-27 21:15:239304 NetworkIsolationKey(), SecureDnsPolicy::kAllow);
Matt Menke5062be22019-05-01 17:50:249305 base::WeakPtr<SpdySession> spdy_session2 =
9306 helper.session()->spdy_session_pool()->FindAvailableSession(
9307 key1, /* enable_ip_based_pooling = */ true,
9308 /* is_websocket = */ true, log_);
9309 ASSERT_TRUE(spdy_session2);
9310 EXPECT_EQ(spdy_session1.get(), spdy_session2.get());
9311
9312 base::RunLoop().RunUntilIdle();
9313
9314 // First request has HIGHEST priority, WebSocket request has MEDIUM priority.
9315 // Changing the priority of the first request to LOWEST changes their order,
9316 // and therefore triggers sending PRIORITY frames.
9317 helper.trans()->SetPriority(LOWEST);
9318
9319 rv = callback1.WaitForResult();
9320 ASSERT_THAT(rv, IsOk());
9321
9322 const HttpResponseInfo* response = helper.trans()->GetResponseInfo();
9323 ASSERT_TRUE(response->headers);
9324 EXPECT_TRUE(response->was_fetched_via_spdy);
9325 EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
9326
9327 std::string response_data;
9328 rv = ReadTransaction(helper.trans(), &response_data);
9329 EXPECT_THAT(rv, IsOk());
9330 EXPECT_EQ("hello!", response_data);
9331
9332 rv = callback2.WaitForResult();
9333 ASSERT_THAT(rv, IsOk());
9334
9335 helper.VerifyDataConsumed();
9336}
9337
9338// Same as above, but the SpdySession is closed just before use, so the
9339// WebSocket is sent over a new HTTP/1.x connection instead.
9340TEST_F(SpdyNetworkTransactionTest,
9341 WebSocketOverDetectsNewSessionWithAliasingButClosedBeforeUse) {
9342 base::HistogramTester histogram_tester;
9343 auto session_deps = std::make_unique<SpdySessionDependencies>();
9344 session_deps->enable_websocket_over_http2 = true;
9345 session_deps->host_resolver->set_ondemand_mode(true);
9346 NormalSpdyTransactionHelper helper(request_, HIGHEST, log_,
9347 std::move(session_deps));
9348 helper.RunPreTestSetup();
9349
9350 spdy::SpdySerializedFrame req(
9351 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, HIGHEST));
9352 spdy::SpdySerializedFrame settings_ack(spdy_util_.ConstructSpdySettingsAck());
9353
9354 MockWrite writes[] = {CreateMockWrite(req, 0),
9355 CreateMockWrite(settings_ack, 2)};
9356
9357 spdy::SettingsMap settings;
9358 settings[spdy::SETTINGS_ENABLE_CONNECT_PROTOCOL] = 1;
9359 spdy::SpdySerializedFrame settings_frame(
9360 spdy_util_.ConstructSpdySettings(settings));
9361 spdy::SpdySerializedFrame resp1(
9362 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
9363 spdy::SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true));
9364 MockRead reads[] = {CreateMockRead(settings_frame, 1),
9365 CreateMockRead(resp1, 3), CreateMockRead(body1, 4),
9366 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 5)};
9367
9368 SequencedSocketData data(reads, writes);
9369 helper.AddData(&data);
9370
9371 MockWrite writes2[] = {
9372 MockWrite("GET / HTTP/1.1\r\n"
9373 "Host: example.test\r\n"
9374 "Connection: Upgrade\r\n"
9375 "Upgrade: websocket\r\n"
9376 "Origin: http://example.test\r\n"
9377 "Sec-WebSocket-Version: 13\r\n"
9378 "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
9379 "Sec-WebSocket-Extensions: permessage-deflate; "
9380 "client_max_window_bits\r\n\r\n")};
9381 MockRead reads2[] = {
9382 MockRead("HTTP/1.1 101 Switching Protocols\r\n"
9383 "Upgrade: websocket\r\n"
9384 "Connection: Upgrade\r\n"
9385 "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n\r\n")};
9386 StaticSocketDataProvider data2(reads2, writes2);
9387 auto ssl_provider2 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
9388 // Test that request has empty |alpn_protos|, that is, HTTP/2 is disabled.
9389 ssl_provider2->next_protos_expected_in_ssl_config = NextProtoVector{};
9390 // Force socket to use HTTP/1.1, the default protocol without ALPN.
9391 ssl_provider2->next_proto = kProtoHTTP11;
9392 ssl_provider2->ssl_info.cert =
9393 ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem");
9394 helper.AddDataWithSSLSocketDataProvider(&data2, std::move(ssl_provider2));
9395
9396 TestCompletionCallback callback1;
9397 int rv = helper.trans()->Start(&request_, callback1.callback(), log_);
9398 ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
9399
9400 HttpRequestInfo request2;
9401 request2.method = "GET";
9402 request2.url = GURL("wss://example.test/");
9403 request2.traffic_annotation =
9404 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
9405 request2.extra_headers.SetHeader("Connection", "Upgrade");
9406 request2.extra_headers.SetHeader("Upgrade", "websocket");
9407 request2.extra_headers.SetHeader("Origin", "http://example.test");
9408 request2.extra_headers.SetHeader("Sec-WebSocket-Version", "13");
9409
9410 TestWebSocketHandshakeStreamCreateHelper websocket_stream_create_helper;
9411
9412 HttpNetworkTransaction trans2(MEDIUM, helper.session());
9413 trans2.SetWebSocketHandshakeStreamCreateHelper(
9414 &websocket_stream_create_helper);
9415
9416 TestCompletionCallback callback2;
9417 rv = trans2.Start(&request2, callback2.callback(), log_);
9418 ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
9419
9420 // Make sure both requests are blocked on host resolution.
9421 base::RunLoop().RunUntilIdle();
9422
9423 EXPECT_TRUE(helper.session_deps()->host_resolver->has_pending_requests());
9424 // Complete the first DNS lookup, which should result in the first transaction
9425 // creating an H2 session (And completing successfully).
9426 helper.session_deps()->host_resolver->ResolveNow(1);
9427
9428 // Complete first request.
9429 rv = callback1.WaitForResult();
9430 ASSERT_THAT(rv, IsOk());
9431 const HttpResponseInfo* response = helper.trans()->GetResponseInfo();
9432 ASSERT_TRUE(response->headers);
9433 EXPECT_TRUE(response->was_fetched_via_spdy);
9434 EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
9435 std::string response_data;
9436 rv = ReadTransaction(helper.trans(), &response_data);
9437 EXPECT_THAT(rv, IsOk());
9438 EXPECT_EQ("hello!", response_data);
9439
9440 SpdySessionKey key1(HostPortPair::FromURL(request_.url),
9441 ProxyServer::Direct(), PRIVACY_MODE_DISABLED,
dalyk51ab46b2019-10-15 15:14:349442 SpdySessionKey::IsProxySession::kFalse, SocketTag(),
Ben Schwartz3ff4dc1e62021-04-27 21:15:239443 NetworkIsolationKey(), SecureDnsPolicy::kAllow);
Matt Menke5062be22019-05-01 17:50:249444 base::WeakPtr<SpdySession> spdy_session1 =
9445 helper.session()->spdy_session_pool()->FindAvailableSession(
9446 key1, /* enable_ip_based_pooling = */ true,
9447 /* is_websocket = */ false, log_);
9448 ASSERT_TRUE(spdy_session1);
9449 EXPECT_TRUE(spdy_session1->support_websocket());
9450
9451 // Second DNS lookup completes, which results in creating an alias for the
9452 // SpdySession immediately, and a task is posted asynchronously to use the
9453 // alias..
9454 helper.session_deps()->host_resolver->ResolveNow(2);
9455
9456 SpdySessionKey key2(HostPortPair::FromURL(request2.url),
9457 ProxyServer::Direct(), PRIVACY_MODE_DISABLED,
dalyk51ab46b2019-10-15 15:14:349458 SpdySessionKey::IsProxySession::kFalse, SocketTag(),
Ben Schwartz3ff4dc1e62021-04-27 21:15:239459 NetworkIsolationKey(), SecureDnsPolicy::kAllow);
Matt Menke5062be22019-05-01 17:50:249460 base::WeakPtr<SpdySession> spdy_session2 =
9461 helper.session()->spdy_session_pool()->FindAvailableSession(
9462 key1, /* enable_ip_based_pooling = */ true,
9463 /* is_websocket = */ true, log_);
9464 ASSERT_TRUE(spdy_session2);
9465 EXPECT_EQ(spdy_session1.get(), spdy_session2.get());
9466
9467 // But the session is closed before it can be used.
9468 helper.session()->spdy_session_pool()->CloseAllSessions();
9469
9470 // The second request establishes another connection (without even doing
9471 // another DNS lookup) instead, and uses HTTP/1.x.
9472 rv = callback2.WaitForResult();
9473 ASSERT_THAT(rv, IsOk());
9474
9475 helper.VerifyDataConsumed();
9476}
9477
Bence Békyfbeb8832018-04-05 23:19:569478TEST_F(SpdyNetworkTransactionTest, WebSocketNegotiatesHttp2) {
9479 HttpRequestInfo request;
9480 request.method = "GET";
9481 request.url = GURL("wss://www.example.org/");
9482 request.traffic_annotation =
9483 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
9484 EXPECT_TRUE(HostPortPair::FromURL(request_.url)
9485 .Equals(HostPortPair::FromURL(request.url)));
9486 request.extra_headers.SetHeader("Connection", "Upgrade");
9487 request.extra_headers.SetHeader("Upgrade", "websocket");
9488 request.extra_headers.SetHeader("Origin", "http://www.example.org");
9489 request.extra_headers.SetHeader("Sec-WebSocket-Version", "13");
9490
9491 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
9492 helper.RunPreTestSetup();
9493
Ryan Sleevib8d7ea02018-05-07 20:01:019494 StaticSocketDataProvider data;
Bence Békyfbeb8832018-04-05 23:19:569495
9496 auto ssl_provider = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
9497 // Test that request has empty |alpn_protos|, that is, HTTP/2 is disabled.
9498 ssl_provider->next_protos_expected_in_ssl_config = NextProtoVector{};
Bence Békyb4a07f8f2018-05-17 14:31:559499 // Force socket to use HTTP/2, which should never happen (TLS implementation
9500 // should fail TLS handshake if server chooses HTTP/2 without client
9501 // advertising support).
Bence Békyfbeb8832018-04-05 23:19:569502 ssl_provider->next_proto = kProtoHTTP2;
9503 ssl_provider->ssl_info.cert =
9504 ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem");
9505 helper.AddDataWithSSLSocketDataProvider(&data, std::move(ssl_provider));
9506
9507 HttpNetworkTransaction* trans = helper.trans();
9508 TestWebSocketHandshakeStreamCreateHelper websocket_stream_create_helper;
9509 trans->SetWebSocketHandshakeStreamCreateHelper(
9510 &websocket_stream_create_helper);
9511
9512 TestCompletionCallback callback;
9513 int rv = trans->Start(&request, callback.callback(), log_);
9514 ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
9515 rv = callback.WaitForResult();
9516 ASSERT_THAT(rv, IsError(ERR_NOT_IMPLEMENTED));
9517
9518 helper.VerifyDataConsumed();
9519}
9520
Matt Menkef2ee07c2019-08-29 02:10:369521TEST_F(SpdyNetworkTransactionTest, WebSocketHttp11Required) {
9522 base::HistogramTester histogram_tester;
9523 auto session_deps = std::make_unique<SpdySessionDependencies>();
9524 session_deps->enable_websocket_over_http2 = true;
9525 NormalSpdyTransactionHelper helper(request_, HIGHEST, log_,
9526 std::move(session_deps));
9527 helper.RunPreTestSetup();
9528
9529 spdy::SpdySerializedFrame req(
9530 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, HIGHEST));
9531 spdy::SpdySerializedFrame settings_ack(spdy_util_.ConstructSpdySettingsAck());
9532
Bence Béky4c325e52020-10-22 20:48:019533 spdy::Http2HeaderBlock websocket_request_headers;
Matt Menkef2ee07c2019-08-29 02:10:369534 websocket_request_headers[spdy::kHttp2MethodHeader] = "CONNECT";
9535 websocket_request_headers[spdy::kHttp2AuthorityHeader] = "www.example.org";
9536 websocket_request_headers[spdy::kHttp2SchemeHeader] = "https";
9537 websocket_request_headers[spdy::kHttp2PathHeader] = "/";
9538 websocket_request_headers[spdy::kHttp2ProtocolHeader] = "websocket";
9539 websocket_request_headers["origin"] = "http://www.example.org";
9540 websocket_request_headers["sec-websocket-version"] = "13";
9541 websocket_request_headers["sec-websocket-extensions"] =
9542 "permessage-deflate; client_max_window_bits";
9543 spdy::SpdySerializedFrame websocket_request(spdy_util_.ConstructSpdyHeaders(
9544 3, std::move(websocket_request_headers), MEDIUM, false));
9545
9546 spdy::SpdySerializedFrame priority1(
9547 spdy_util_.ConstructSpdyPriority(3, 0, MEDIUM, true));
9548 spdy::SpdySerializedFrame priority2(
9549 spdy_util_.ConstructSpdyPriority(1, 3, LOWEST, true));
9550
9551 MockWrite writes1[] = {CreateMockWrite(req, 0),
9552 CreateMockWrite(settings_ack, 2),
9553 CreateMockWrite(websocket_request, 4)};
9554
9555 spdy::SettingsMap settings;
9556 settings[spdy::SETTINGS_ENABLE_CONNECT_PROTOCOL] = 1;
9557 spdy::SpdySerializedFrame settings_frame(
9558 spdy_util_.ConstructSpdySettings(settings));
9559 spdy::SpdySerializedFrame resp1(
9560 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
9561 spdy::SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true));
9562 spdy::SpdySerializedFrame websocket_response_http11_required(
9563 spdy_util_.ConstructSpdyRstStream(3, spdy::ERROR_CODE_HTTP_1_1_REQUIRED));
9564 MockRead reads1[] = {CreateMockRead(settings_frame, 1),
9565 CreateMockRead(resp1, 3),
9566 CreateMockRead(websocket_response_http11_required, 5)};
9567
9568 SequencedSocketData data1(reads1, writes1);
9569 helper.AddData(&data1);
9570
9571 MockWrite writes2[] = {
9572 MockWrite("GET / HTTP/1.1\r\n"
9573 "Host: www.example.org\r\n"
9574 "Connection: Upgrade\r\n"
9575 "Origin: http://www.example.org\r\n"
9576 "Sec-WebSocket-Version: 13\r\n"
9577 "Upgrade: websocket\r\n"
9578 "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
9579 "Sec-WebSocket-Extensions: permessage-deflate; "
9580 "client_max_window_bits\r\n\r\n")};
9581 MockRead reads2[] = {
9582 MockRead("HTTP/1.1 101 Switching Protocols\r\n"
9583 "Upgrade: websocket\r\n"
9584 "Connection: Upgrade\r\n"
9585 "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n\r\n")};
9586 StaticSocketDataProvider data2(reads2, writes2);
9587 auto ssl_provider2 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
9588 // Test that request has empty |alpn_protos|, that is, HTTP/2 is disabled.
9589 ssl_provider2->next_protos_expected_in_ssl_config = NextProtoVector{};
9590 // Force socket to use HTTP/1.1, the default protocol without ALPN.
9591 ssl_provider2->next_proto = kProtoHTTP11;
9592 ssl_provider2->ssl_info.cert =
9593 ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem");
9594 helper.AddDataWithSSLSocketDataProvider(&data2, std::move(ssl_provider2));
9595
9596 // Create HTTP/2 connection.
9597 TestCompletionCallback callback1;
9598 int rv = helper.trans()->Start(&request_, callback1.callback(), log_);
9599 ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
9600
9601 // Create HTTP/2 connection.
9602 base::RunLoop().RunUntilIdle();
9603
9604 SpdySessionKey key(HostPortPair::FromURL(request_.url), ProxyServer::Direct(),
9605 PRIVACY_MODE_DISABLED,
dalyk51ab46b2019-10-15 15:14:349606 SpdySessionKey::IsProxySession::kFalse, SocketTag(),
Ben Schwartz3ff4dc1e62021-04-27 21:15:239607 NetworkIsolationKey(), SecureDnsPolicy::kAllow);
Matt Menkef2ee07c2019-08-29 02:10:369608 base::WeakPtr<SpdySession> spdy_session =
9609 helper.session()->spdy_session_pool()->FindAvailableSession(
9610 key, /* enable_ip_based_pooling = */ true,
9611 /* is_websocket = */ true, log_);
9612 ASSERT_TRUE(spdy_session);
9613 EXPECT_TRUE(spdy_session->support_websocket());
9614
9615 HttpRequestInfo request2;
9616 request2.method = "GET";
9617 request2.url = GURL("wss://www.example.org/");
9618 request2.traffic_annotation =
9619 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
9620 EXPECT_TRUE(HostPortPair::FromURL(request_.url)
9621 .Equals(HostPortPair::FromURL(request2.url)));
9622 request2.extra_headers.SetHeader("Origin", "http://www.example.org");
9623 request2.extra_headers.SetHeader("Sec-WebSocket-Version", "13");
9624 // The following two headers must be removed by WebSocketHttp2HandshakeStream.
9625 request2.extra_headers.SetHeader("Connection", "Upgrade");
9626 request2.extra_headers.SetHeader("Upgrade", "websocket");
9627
9628 TestWebSocketHandshakeStreamCreateHelper websocket_stream_create_helper;
9629
9630 HttpNetworkTransaction trans2(MEDIUM, helper.session());
9631 trans2.SetWebSocketHandshakeStreamCreateHelper(
9632 &websocket_stream_create_helper);
9633
9634 TestCompletionCallback callback2;
9635 rv = trans2.Start(&request2, callback2.callback(), log_);
9636 EXPECT_THAT(callback2.GetResult(rv), IsOk());
9637
9638 helper.VerifyDataConsumed();
9639
9640 // Server advertised WebSocket support.
9641 histogram_tester.ExpectUniqueSample("Net.SpdySession.ServerSupportsWebSocket",
9642 /* support_websocket = true */ 1,
9643 /* expected_count = */ 1);
9644}
9645
Bence Béky420bb2d2018-03-30 17:25:269646// Plaintext WebSocket over HTTP/2 is not implemented, see
9647// https://crbug.com/684681.
9648TEST_F(SpdyNetworkTransactionTest, PlaintextWebSocketOverHttp2Proxy) {
Ryan Hamilton0239aac2018-05-19 00:03:139649 spdy::SpdySerializedFrame req(spdy_util_.ConstructSpdyConnect(
Matt Menke6e879bd2019-03-18 17:26:049650 nullptr, 0, 1, HttpProxyConnectJob::kH2QuicTunnelPriority,
9651 HostPortPair("www.example.org", 80)));
Bence Béky420bb2d2018-03-30 17:25:269652 MockWrite writes[] = {CreateMockWrite(req, 0)};
9653
Ryan Hamilton0239aac2018-05-19 00:03:139654 spdy::SpdySerializedFrame resp(
9655 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
Bence Béky420bb2d2018-03-30 17:25:269656 MockRead reads[] = {CreateMockRead(resp, 1), MockRead(ASYNC, 0, 2)};
9657
Ryan Sleevib8d7ea02018-05-07 20:01:019658 SequencedSocketData data(reads, writes);
Bence Béky420bb2d2018-03-30 17:25:269659
9660 request_.url = GURL("ws://www.example.org/");
9661 auto session_deps = std::make_unique<SpdySessionDependencies>(
Nicolas Arciniegad2013f92020-02-07 23:00:569662 ConfiguredProxyResolutionService::CreateFixed(
9663 "https://proxy:70", TRAFFIC_ANNOTATION_FOR_TESTS));
Bence Béky420bb2d2018-03-30 17:25:269664 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
9665 std::move(session_deps));
9666 helper.RunPreTestSetup();
9667 helper.AddData(&data);
9668
9669 HttpNetworkTransaction* trans = helper.trans();
9670 TestWebSocketHandshakeStreamCreateHelper websocket_stream_create_helper;
9671 trans->SetWebSocketHandshakeStreamCreateHelper(
9672 &websocket_stream_create_helper);
9673
9674 EXPECT_TRUE(helper.StartDefaultTest());
9675 helper.WaitForCallbackToComplete();
9676 EXPECT_THAT(helper.output().rv, IsError(ERR_NOT_IMPLEMENTED));
9677
9678 helper.VerifyDataConsumed();
9679}
9680
Bence Béky6434d5e2018-04-03 13:43:119681// Regression test for https://crbug.com/819101. Open two identical plaintext
Xida Chen9bfe0b62018-04-24 19:52:219682// websocket requests over proxy. The HttpStreamFactory::Job for the second
Bence Béky6434d5e2018-04-03 13:43:119683// request should reuse the first connection.
9684TEST_F(SpdyNetworkTransactionTest, TwoWebSocketRequestsOverHttp2Proxy) {
Ryan Hamilton0239aac2018-05-19 00:03:139685 spdy::SpdySerializedFrame req(spdy_util_.ConstructSpdyConnect(
Matt Menke6e879bd2019-03-18 17:26:049686 nullptr, 0, 1, HttpProxyConnectJob::kH2QuicTunnelPriority,
9687 HostPortPair("www.example.org", 80)));
Bence Béky6434d5e2018-04-03 13:43:119688 MockWrite writes[] = {CreateMockWrite(req, 0)};
9689
Ryan Hamilton0239aac2018-05-19 00:03:139690 spdy::SpdySerializedFrame resp(
9691 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
Bence Béky6434d5e2018-04-03 13:43:119692 MockRead reads[] = {CreateMockRead(resp, 1),
9693 MockRead(ASYNC, ERR_IO_PENDING, 2),
9694 MockRead(ASYNC, 0, 3)};
9695
Ryan Sleevib8d7ea02018-05-07 20:01:019696 SequencedSocketData data(reads, writes);
Bence Béky6434d5e2018-04-03 13:43:119697
9698 request_.url = GURL("ws://www.example.org/");
9699 auto session_deps = std::make_unique<SpdySessionDependencies>(
Nicolas Arciniegad2013f92020-02-07 23:00:569700 ConfiguredProxyResolutionService::CreateFixed(
9701 "https://proxy:70", TRAFFIC_ANNOTATION_FOR_TESTS));
Bence Béky6434d5e2018-04-03 13:43:119702 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
9703 std::move(session_deps));
9704 helper.RunPreTestSetup();
9705 helper.AddData(&data);
9706
9707 HttpNetworkTransaction* trans1 = helper.trans();
9708 TestWebSocketHandshakeStreamCreateHelper websocket_stream_create_helper;
9709 trans1->SetWebSocketHandshakeStreamCreateHelper(
9710 &websocket_stream_create_helper);
9711
9712 EXPECT_TRUE(helper.StartDefaultTest());
9713 helper.WaitForCallbackToComplete();
9714 EXPECT_THAT(helper.output().rv, IsError(ERR_NOT_IMPLEMENTED));
9715
9716 HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session());
9717 trans2.SetWebSocketHandshakeStreamCreateHelper(
9718 &websocket_stream_create_helper);
9719
9720 TestCompletionCallback callback2;
9721 int rv = trans2.Start(&request_, callback2.callback(), log_);
9722 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
9723
9724 rv = callback2.WaitForResult();
9725 EXPECT_THAT(rv, IsError(ERR_NOT_IMPLEMENTED));
9726
9727 data.Resume();
9728 base::RunLoop().RunUntilIdle();
9729
9730 helper.VerifyDataConsumed();
9731}
9732
Bence Béky420bb2d2018-03-30 17:25:269733TEST_F(SpdyNetworkTransactionTest, SecureWebSocketOverHttp2Proxy) {
Ryan Hamilton0239aac2018-05-19 00:03:139734 spdy::SpdySerializedFrame connect_request(spdy_util_.ConstructSpdyConnect(
Matt Menke6e879bd2019-03-18 17:26:049735 nullptr, 0, 1, HttpProxyConnectJob::kH2QuicTunnelPriority,
9736 HostPortPair("www.example.org", 443)));
Bence Béky420bb2d2018-03-30 17:25:269737 const char kWebSocketRequest[] =
9738 "GET / HTTP/1.1\r\n"
9739 "Host: www.example.org\r\n"
9740 "Connection: Upgrade\r\n"
9741 "Upgrade: websocket\r\n"
9742 "Origin: http://www.example.org\r\n"
9743 "Sec-WebSocket-Version: 13\r\n"
9744 "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
9745 "Sec-WebSocket-Extensions: permessage-deflate; "
9746 "client_max_window_bits\r\n\r\n";
Ryan Hamilton0239aac2018-05-19 00:03:139747 spdy::SpdySerializedFrame websocket_request(
Bence Béky420bb2d2018-03-30 17:25:269748 spdy_util_.ConstructSpdyDataFrame(1, kWebSocketRequest, false));
9749 MockWrite writes[] = {CreateMockWrite(connect_request, 0),
9750 CreateMockWrite(websocket_request, 2)};
9751
Ryan Hamilton0239aac2018-05-19 00:03:139752 spdy::SpdySerializedFrame connect_response(
Bence Béky420bb2d2018-03-30 17:25:269753 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
9754 const char kWebSocketResponse[] =
9755 "HTTP/1.1 101 Switching Protocols\r\n"
9756 "Upgrade: websocket\r\n"
9757 "Connection: Upgrade\r\n"
9758 "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n\r\n";
Ryan Hamilton0239aac2018-05-19 00:03:139759 spdy::SpdySerializedFrame websocket_response(
Bence Béky420bb2d2018-03-30 17:25:269760 spdy_util_.ConstructSpdyDataFrame(1, kWebSocketResponse, false));
9761 MockRead reads[] = {CreateMockRead(connect_response, 1),
9762 CreateMockRead(websocket_response, 3),
9763 MockRead(ASYNC, 0, 4)};
9764
Ryan Sleevib8d7ea02018-05-07 20:01:019765 SequencedSocketData data(reads, writes);
Bence Béky420bb2d2018-03-30 17:25:269766
9767 request_.url = GURL("wss://www.example.org/");
9768 request_.extra_headers.SetHeader("Connection", "Upgrade");
9769 request_.extra_headers.SetHeader("Upgrade", "websocket");
9770 request_.extra_headers.SetHeader("Origin", "http://www.example.org");
9771 request_.extra_headers.SetHeader("Sec-WebSocket-Version", "13");
9772 auto session_deps = std::make_unique<SpdySessionDependencies>(
Nicolas Arciniegad2013f92020-02-07 23:00:569773 ConfiguredProxyResolutionService::CreateFixed(
9774 "https://proxy:70", TRAFFIC_ANNOTATION_FOR_TESTS));
Bence Béky420bb2d2018-03-30 17:25:269775 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
9776 std::move(session_deps));
9777 helper.RunPreTestSetup();
9778 helper.AddData(&data);
9779
9780 // Add SSL data for the tunneled connection.
9781 SSLSocketDataProvider ssl_provider(ASYNC, OK);
9782 ssl_provider.ssl_info.cert =
9783 ImportCertFromFile(GetTestCertsDirectory(), "wildcard.pem");
Bence Béky12943c62018-04-05 19:16:509784 // A WebSocket request should not advertise HTTP/2 support.
9785 ssl_provider.next_protos_expected_in_ssl_config = NextProtoVector{};
Bence Béky420bb2d2018-03-30 17:25:269786 // This test uses WebSocket over HTTP/1.1.
9787 ssl_provider.next_proto = kProtoHTTP11;
9788 helper.session_deps()->socket_factory->AddSSLSocketDataProvider(
9789 &ssl_provider);
9790
9791 HttpNetworkTransaction* trans = helper.trans();
9792 TestWebSocketHandshakeStreamCreateHelper websocket_stream_create_helper;
9793 trans->SetWebSocketHandshakeStreamCreateHelper(
9794 &websocket_stream_create_helper);
9795
9796 EXPECT_TRUE(helper.StartDefaultTest());
9797 helper.WaitForCallbackToComplete();
9798 EXPECT_THAT(helper.output().rv, IsOk());
9799 const HttpResponseInfo* response = trans->GetResponseInfo();
9800 ASSERT_TRUE(response);
9801 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP1_1,
9802 response->connection_info);
9803 EXPECT_TRUE(response->was_alpn_negotiated);
9804 EXPECT_FALSE(response->was_fetched_via_spdy);
Tsuyoshi Horo01faed62019-02-20 22:11:379805 EXPECT_EQ(70, response->remote_endpoint.port());
Bence Béky420bb2d2018-03-30 17:25:269806 ASSERT_TRUE(response->headers);
9807 EXPECT_EQ("HTTP/1.1 101 Switching Protocols",
9808 response->headers->GetStatusLine());
9809
9810 base::RunLoop().RunUntilIdle();
9811 helper.VerifyDataConsumed();
9812}
9813
Bence Béky12943c62018-04-05 19:16:509814// Regression test for https://crbug.com/828865.
9815TEST_F(SpdyNetworkTransactionTest,
9816 SecureWebSocketOverHttp2ProxyNegotiatesHttp2) {
Ryan Hamilton0239aac2018-05-19 00:03:139817 spdy::SpdySerializedFrame connect_request(spdy_util_.ConstructSpdyConnect(
Matt Menke6e879bd2019-03-18 17:26:049818 nullptr, 0, 1, HttpProxyConnectJob::kH2QuicTunnelPriority,
9819 HostPortPair("www.example.org", 443)));
Bence Béky12943c62018-04-05 19:16:509820 MockWrite writes[] = {CreateMockWrite(connect_request, 0)};
Ryan Hamilton0239aac2018-05-19 00:03:139821 spdy::SpdySerializedFrame connect_response(
Bence Béky12943c62018-04-05 19:16:509822 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
9823 MockRead reads[] = {CreateMockRead(connect_response, 1),
9824 MockRead(ASYNC, 0, 2)};
Ryan Sleevib8d7ea02018-05-07 20:01:019825 SequencedSocketData data(reads, writes);
Bence Béky12943c62018-04-05 19:16:509826
9827 request_.url = GURL("wss://www.example.org/");
9828 request_.extra_headers.SetHeader("Connection", "Upgrade");
9829 request_.extra_headers.SetHeader("Upgrade", "websocket");
9830 request_.extra_headers.SetHeader("Origin", "http://www.example.org");
9831 request_.extra_headers.SetHeader("Sec-WebSocket-Version", "13");
9832 auto session_deps = std::make_unique<SpdySessionDependencies>(
Nicolas Arciniegad2013f92020-02-07 23:00:569833 ConfiguredProxyResolutionService::CreateFixed(
9834 "https://proxy:70", TRAFFIC_ANNOTATION_FOR_TESTS));
Bence Béky12943c62018-04-05 19:16:509835 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
9836 std::move(session_deps));
9837 helper.RunPreTestSetup();
9838 helper.AddData(&data);
9839
9840 // Add SSL data for the tunneled connection.
9841 SSLSocketDataProvider ssl_provider(ASYNC, OK);
9842 ssl_provider.ssl_info.cert =
9843 ImportCertFromFile(GetTestCertsDirectory(), "wildcard.pem");
9844 // A WebSocket request should not advertise HTTP/2 support.
9845 ssl_provider.next_protos_expected_in_ssl_config = NextProtoVector{};
9846 // The server should not negotiate HTTP/2 over the tunnelled connection,
9847 // but it must be handled gracefully if it does.
9848 ssl_provider.next_proto = kProtoHTTP2;
9849 helper.session_deps()->socket_factory->AddSSLSocketDataProvider(
9850 &ssl_provider);
9851
9852 HttpNetworkTransaction* trans = helper.trans();
9853 TestWebSocketHandshakeStreamCreateHelper websocket_stream_create_helper;
9854 trans->SetWebSocketHandshakeStreamCreateHelper(
9855 &websocket_stream_create_helper);
9856
9857 EXPECT_TRUE(helper.StartDefaultTest());
9858 helper.WaitForCallbackToComplete();
9859 EXPECT_THAT(helper.output().rv, IsError(ERR_NOT_IMPLEMENTED));
9860
9861 base::RunLoop().RunUntilIdle();
9862 helper.VerifyDataConsumed();
9863}
9864
Bence Béky0ca719f2018-01-31 13:41:199865#endif // BUILDFLAG(ENABLE_WEBSOCKETS)
9866
Steven Valdez1c1859172019-04-10 15:33:289867TEST_F(SpdyNetworkTransactionTest, ZeroRTTDoesntConfirm) {
David Benjaminbae08ba2019-10-18 21:06:159868 static const base::TimeDelta kDelay = base::TimeDelta::FromMilliseconds(10);
Steven Valdez1c1859172019-04-10 15:33:289869 spdy::SpdySerializedFrame req(
9870 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
9871 MockWrite writes[] = {CreateMockWrite(req, 0)};
9872
9873 spdy::SpdySerializedFrame resp(
9874 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
9875 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
9876 MockRead reads[] = {
9877 CreateMockRead(resp, 1), CreateMockRead(body, 2),
9878 MockRead(ASYNC, 0, 3) // EOF
9879 };
9880
9881 SequencedSocketData data(reads, writes);
9882 auto session_deps = std::make_unique<SpdySessionDependencies>();
9883 session_deps->enable_early_data = true;
9884 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
9885 std::move(session_deps));
9886 auto ssl_provider = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
David Benjaminbae08ba2019-10-18 21:06:159887 ssl_provider->connect_callback = FastForwardByCallback(kDelay);
Steven Valdez1c1859172019-04-10 15:33:289888 // Configure |ssl_provider| to fail if ConfirmHandshake is called. The request
9889 // should still succeed.
9890 ssl_provider->confirm = MockConfirm(SYNCHRONOUS, ERR_SSL_PROTOCOL_ERROR);
David Benjaminbae08ba2019-10-18 21:06:159891 ssl_provider->confirm_callback = FastForwardByCallback(kDelay);
9892 base::TimeTicks start_time = base::TimeTicks::Now();
Steven Valdez1c1859172019-04-10 15:33:289893 helper.RunToCompletionWithSSLData(&data, std::move(ssl_provider));
9894 TransactionHelperResult out = helper.output();
9895 EXPECT_THAT(out.rv, IsOk());
9896 EXPECT_EQ("HTTP/1.1 200", out.status_line);
9897 EXPECT_EQ("hello!", out.response_data);
David Benjaminbae08ba2019-10-18 21:06:159898
9899 // The handshake time should include the time it took to run Connect(), but
9900 // not ConfirmHandshake().
9901 LoadTimingInfo load_timing_info;
9902 EXPECT_TRUE(helper.trans()->GetLoadTimingInfo(&load_timing_info));
9903 EXPECT_EQ(load_timing_info.connect_timing.connect_start, start_time);
9904 EXPECT_EQ(load_timing_info.connect_timing.ssl_start, start_time);
9905 EXPECT_EQ(load_timing_info.connect_timing.ssl_end, start_time + kDelay);
9906 EXPECT_EQ(load_timing_info.connect_timing.connect_end, start_time + kDelay);
Steven Valdez1c1859172019-04-10 15:33:289907}
9908
9909// Run multiple concurrent streams that don't require handshake confirmation.
9910TEST_F(SpdyNetworkTransactionTest, ZeroRTTNoConfirmMultipleStreams) {
9911 spdy::SpdySerializedFrame req1(
9912 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
9913 spdy::SpdySerializedFrame req2(
9914 spdy_util_.ConstructSpdyGet(nullptr, 0, 3, LOWEST));
9915 MockWrite writes1[] = {CreateMockWrite(req1, 0), CreateMockWrite(req2, 3)};
9916
9917 spdy::SpdySerializedFrame resp1(
9918 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
9919 spdy::SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true));
9920 spdy::SpdySerializedFrame resp2(
9921 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
9922 spdy::SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(3, true));
9923 MockRead reads1[] = {
9924 CreateMockRead(resp1, 1), CreateMockRead(body1, 2),
9925 CreateMockRead(resp2, 4), CreateMockRead(body2, 5),
9926 MockRead(ASYNC, 0, 6) // EOF
9927 };
9928
9929 SequencedSocketData data1(reads1, writes1);
9930 SequencedSocketData data2({}, {});
9931 auto session_deps = std::make_unique<SpdySessionDependencies>();
9932 session_deps->enable_early_data = true;
9933 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
9934 std::move(session_deps));
9935 auto ssl_provider1 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
9936 ssl_provider1->confirm = MockConfirm(SYNCHRONOUS, ERR_SSL_PROTOCOL_ERROR);
9937 auto ssl_provider2 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
9938 ssl_provider2->confirm = MockConfirm(SYNCHRONOUS, ERR_SSL_PROTOCOL_ERROR);
9939
9940 helper.RunPreTestSetup();
9941 helper.AddDataWithSSLSocketDataProvider(&data1, std::move(ssl_provider1));
9942 helper.AddDataWithSSLSocketDataProvider(&data2, std::move(ssl_provider2));
9943 EXPECT_TRUE(helper.StartDefaultTest());
9944
9945 HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session());
9946 HttpRequestInfo request2;
9947 request2.method = "GET";
9948 request2.url = GURL(kDefaultUrl);
9949 request2.traffic_annotation =
9950 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
9951 TestCompletionCallback callback2;
9952 int rv = trans2.Start(&request2, callback2.callback(), log_);
9953 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
9954
9955 helper.FinishDefaultTest();
9956 EXPECT_THAT(callback2.GetResult(ERR_IO_PENDING), IsOk());
9957 helper.VerifyDataConsumed();
9958
9959 TransactionHelperResult out = helper.output();
9960 EXPECT_THAT(out.rv, IsOk());
9961 EXPECT_EQ("HTTP/1.1 200", out.status_line);
9962 EXPECT_EQ("hello!", out.response_data);
9963}
9964
9965// Run multiple concurrent streams that require handshake confirmation.
9966TEST_F(SpdyNetworkTransactionTest, ZeroRTTConfirmMultipleStreams) {
Bence Béky4c325e52020-10-22 20:48:019967 spdy::Http2HeaderBlock req_block1(
Steven Valdez1c1859172019-04-10 15:33:289968 spdy_util_.ConstructPostHeaderBlock(kDefaultUrl, 0));
9969 spdy::SpdySerializedFrame req1(
9970 spdy_util_.ConstructSpdyHeaders(1, std::move(req_block1), LOWEST, true));
Bence Béky4c325e52020-10-22 20:48:019971 spdy::Http2HeaderBlock req_block2(
Steven Valdez1c1859172019-04-10 15:33:289972 spdy_util_.ConstructPostHeaderBlock(kDefaultUrl, 0));
9973 spdy::SpdySerializedFrame req2(
9974 spdy_util_.ConstructSpdyHeaders(3, std::move(req_block2), LOWEST, true));
9975 MockWrite writes[] = {
9976 CreateMockWrite(req1, 0),
9977 CreateMockWrite(req2, 3),
9978 };
9979 spdy::SpdySerializedFrame resp1(
9980 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
9981 spdy::SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true));
9982 spdy::SpdySerializedFrame resp2(
9983 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
9984 spdy::SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(3, true));
9985 MockRead reads[] = {
9986 CreateMockRead(resp1, 1), CreateMockRead(body1, 2),
9987 CreateMockRead(resp2, 4), CreateMockRead(body2, 5),
9988 MockRead(ASYNC, 0, 6) // EOF
9989 };
9990
9991 SequencedSocketData data1(reads, writes);
9992 SequencedSocketData data2({}, {});
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_provider1 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
9999 ssl_provider1->confirm = MockConfirm(ASYNC, OK);
10000 auto ssl_provider2 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
10001 ssl_provider2->confirm = MockConfirm(ASYNC, OK);
10002
10003 helper.RunPreTestSetup();
10004 helper.AddDataWithSSLSocketDataProvider(&data1, std::move(ssl_provider1));
10005 helper.AddDataWithSSLSocketDataProvider(&data2, std::move(ssl_provider2));
10006
10007 HttpNetworkTransaction trans1(DEFAULT_PRIORITY, helper.session());
10008 HttpRequestInfo request1;
10009 request1.method = "POST";
10010 request1.url = GURL(kDefaultUrl);
10011 request1.traffic_annotation =
10012 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
10013 TestCompletionCallback callback1;
10014 int rv = trans1.Start(&request1, callback1.callback(), log_);
10015 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
10016
10017 HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session());
10018 HttpRequestInfo request2;
10019 request2.method = "POST";
10020 request2.url = GURL(kDefaultUrl);
10021 request2.traffic_annotation =
10022 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
10023 TestCompletionCallback callback2;
10024 rv = trans2.Start(&request2, callback2.callback(), log_);
10025 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
10026
10027 EXPECT_THAT(callback1.GetResult(ERR_IO_PENDING), IsOk());
10028 EXPECT_THAT(callback2.GetResult(ERR_IO_PENDING), IsOk());
10029
10030 const HttpResponseInfo* response1 = trans1.GetResponseInfo();
10031 ASSERT_TRUE(response1);
10032 ASSERT_TRUE(response1->headers);
10033 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP2,
10034 response1->connection_info);
10035 EXPECT_EQ("HTTP/1.1 200", response1->headers->GetStatusLine());
10036 std::string response_data;
10037 ReadTransaction(&trans1, &response_data);
10038 EXPECT_EQ("hello!", response_data);
10039
10040 const HttpResponseInfo* response2 = trans2.GetResponseInfo();
10041 ASSERT_TRUE(response2);
10042 ASSERT_TRUE(response2->headers);
10043 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP2,
10044 response2->connection_info);
10045 EXPECT_EQ("HTTP/1.1 200", response2->headers->GetStatusLine());
10046 ReadTransaction(&trans2, &response_data);
10047 EXPECT_EQ("hello!", response_data);
10048
10049 helper.VerifyDataConsumed();
10050}
10051
10052// Run multiple concurrent streams, the first require a confirmation and the
10053// second not requiring confirmation.
10054TEST_F(SpdyNetworkTransactionTest, ZeroRTTConfirmNoConfirmStreams) {
10055 // This test orders the writes such that the GET (no confirmation) is written
10056 // before the POST (confirmation required).
Bence Béky4c325e52020-10-22 20:48:0110057 spdy::Http2HeaderBlock req_block1(
Steven Valdez1c1859172019-04-10 15:33:2810058 spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
10059 spdy::SpdySerializedFrame req1(
10060 spdy_util_.ConstructSpdyHeaders(1, std::move(req_block1), LOWEST, true));
Bence Béky4c325e52020-10-22 20:48:0110061 spdy::Http2HeaderBlock req_block2(
Steven Valdez1c1859172019-04-10 15:33:2810062 spdy_util_.ConstructPostHeaderBlock(kDefaultUrl, 0));
10063 spdy::SpdySerializedFrame req2(
10064 spdy_util_.ConstructSpdyHeaders(3, std::move(req_block2), LOWEST, true));
10065 MockWrite writes[] = {
10066 CreateMockWrite(req1, 0),
10067 CreateMockWrite(req2, 3),
10068 };
10069 spdy::SpdySerializedFrame resp1(
10070 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
10071 spdy::SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true));
10072 spdy::SpdySerializedFrame resp2(
10073 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
10074 spdy::SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(3, true));
10075 MockRead reads[] = {
10076 CreateMockRead(resp1, 1), CreateMockRead(body1, 2),
10077 CreateMockRead(resp2, 4), CreateMockRead(body2, 5),
10078 MockRead(ASYNC, 0, 6) // EOF
10079 };
10080
10081 SequencedSocketData data1(reads, writes);
10082 SequencedSocketData data2({}, {});
10083 UsePostRequest();
10084 auto session_deps = std::make_unique<SpdySessionDependencies>();
10085 session_deps->enable_early_data = true;
10086 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
10087 std::move(session_deps));
10088 auto ssl_provider1 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
10089 ssl_provider1->confirm = MockConfirm(ASYNC, OK);
10090 auto ssl_provider2 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
10091 ssl_provider2->confirm = MockConfirm(ASYNC, OK);
10092
10093 helper.RunPreTestSetup();
10094 helper.AddDataWithSSLSocketDataProvider(&data1, std::move(ssl_provider1));
10095 helper.AddDataWithSSLSocketDataProvider(&data2, std::move(ssl_provider2));
10096
10097 // TODO(https://crbug.com/949724): Explicitly verify the ordering of
10098 // ConfirmHandshake and the second stream.
10099
10100 HttpNetworkTransaction trans1(DEFAULT_PRIORITY, helper.session());
10101 HttpRequestInfo request1;
10102 request1.method = "POST";
10103 request1.url = GURL(kDefaultUrl);
10104 request1.traffic_annotation =
10105 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
10106 TestCompletionCallback callback1;
10107 int rv = trans1.Start(&request1, callback1.callback(), log_);
10108 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
10109
10110 HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session());
10111 HttpRequestInfo request2;
10112 request2.method = "GET";
10113 request2.url = GURL(kDefaultUrl);
10114 request2.traffic_annotation =
10115 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
10116 TestCompletionCallback callback2;
10117 rv = trans2.Start(&request2, callback2.callback(), log_);
10118 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
10119
10120 EXPECT_THAT(callback1.GetResult(ERR_IO_PENDING), IsOk());
10121 EXPECT_THAT(callback2.GetResult(ERR_IO_PENDING), IsOk());
10122
10123 const HttpResponseInfo* response1 = trans1.GetResponseInfo();
10124 ASSERT_TRUE(response1);
10125 ASSERT_TRUE(response1->headers);
10126 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP2,
10127 response1->connection_info);
10128 EXPECT_EQ("HTTP/1.1 200", response1->headers->GetStatusLine());
10129 std::string response_data;
10130 ReadTransaction(&trans1, &response_data);
10131 EXPECT_EQ("hello!", response_data);
10132
10133 const HttpResponseInfo* response2 = trans2.GetResponseInfo();
10134 ASSERT_TRUE(response2);
10135 ASSERT_TRUE(response2->headers);
10136 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP2,
10137 response2->connection_info);
10138 EXPECT_EQ("HTTP/1.1 200", response2->headers->GetStatusLine());
10139 ReadTransaction(&trans2, &response_data);
10140 EXPECT_EQ("hello!", response_data);
10141
10142 helper.VerifyDataConsumed();
10143}
10144
10145// Run multiple concurrent streams, the first not requiring confirmation and the
10146// second requiring confirmation.
10147TEST_F(SpdyNetworkTransactionTest, ZeroRTTNoConfirmConfirmStreams) {
10148 // This test orders the writes such that the GET (no confirmation) is written
10149 // before the POST (confirmation required).
Bence Béky4c325e52020-10-22 20:48:0110150 spdy::Http2HeaderBlock req_block1(
Steven Valdez1c1859172019-04-10 15:33:2810151 spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
10152 spdy::SpdySerializedFrame req1(
10153 spdy_util_.ConstructSpdyHeaders(1, std::move(req_block1), LOWEST, true));
Bence Béky4c325e52020-10-22 20:48:0110154 spdy::Http2HeaderBlock req_block2(
Steven Valdez1c1859172019-04-10 15:33:2810155 spdy_util_.ConstructPostHeaderBlock(kDefaultUrl, 0));
10156 spdy::SpdySerializedFrame req2(
10157 spdy_util_.ConstructSpdyHeaders(3, std::move(req_block2), LOWEST, true));
10158 MockWrite writes[] = {
10159 CreateMockWrite(req1, 0),
10160 CreateMockWrite(req2, 3),
10161 };
10162 spdy::SpdySerializedFrame resp1(
10163 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
10164 spdy::SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true));
10165 spdy::SpdySerializedFrame resp2(
10166 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
10167 spdy::SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(3, true));
10168 MockRead reads[] = {
10169 CreateMockRead(resp1, 1), CreateMockRead(body1, 2),
10170 CreateMockRead(resp2, 4), CreateMockRead(body2, 5),
10171 MockRead(ASYNC, 0, 6) // EOF
10172 };
10173
10174 SequencedSocketData data1(reads, writes);
10175 SequencedSocketData data2({}, {});
10176 UsePostRequest();
10177 auto session_deps = std::make_unique<SpdySessionDependencies>();
10178 session_deps->enable_early_data = true;
10179 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
10180 std::move(session_deps));
10181 auto ssl_provider1 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
10182 ssl_provider1->confirm = MockConfirm(ASYNC, OK);
10183 auto ssl_provider2 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
10184 ssl_provider2->confirm = MockConfirm(ASYNC, OK);
10185
10186 helper.RunPreTestSetup();
10187 helper.AddDataWithSSLSocketDataProvider(&data1, std::move(ssl_provider1));
10188 helper.AddDataWithSSLSocketDataProvider(&data2, std::move(ssl_provider2));
10189
10190 // TODO(https://crbug.com/949724): Explicitly verify the ordering of
10191 // ConfirmHandshake and the second stream.
10192
10193 HttpNetworkTransaction trans1(DEFAULT_PRIORITY, helper.session());
10194 HttpRequestInfo request1;
10195 request1.method = "GET";
10196 request1.url = GURL(kDefaultUrl);
10197 request1.traffic_annotation =
10198 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
10199 TestCompletionCallback callback1;
10200 int rv = trans1.Start(&request1, callback1.callback(), log_);
10201 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
10202
10203 HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session());
10204 HttpRequestInfo request2;
10205 request2.method = "POST";
10206 request2.url = GURL(kDefaultUrl);
10207 request2.traffic_annotation =
10208 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
10209 TestCompletionCallback callback2;
10210 rv = trans2.Start(&request2, callback2.callback(), log_);
10211 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
10212
10213 EXPECT_THAT(callback1.GetResult(ERR_IO_PENDING), IsOk());
10214 EXPECT_THAT(callback2.GetResult(ERR_IO_PENDING), IsOk());
10215
10216 const HttpResponseInfo* response1 = trans1.GetResponseInfo();
10217 ASSERT_TRUE(response1);
10218 ASSERT_TRUE(response1->headers);
10219 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP2,
10220 response1->connection_info);
10221 EXPECT_EQ("HTTP/1.1 200", response1->headers->GetStatusLine());
10222 std::string response_data;
10223 ReadTransaction(&trans1, &response_data);
10224 EXPECT_EQ("hello!", response_data);
10225
10226 const HttpResponseInfo* response2 = trans2.GetResponseInfo();
10227 ASSERT_TRUE(response2);
10228 ASSERT_TRUE(response2->headers);
10229 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP2,
10230 response2->connection_info);
10231 EXPECT_EQ("HTTP/1.1 200", response2->headers->GetStatusLine());
10232 ReadTransaction(&trans2, &response_data);
10233 EXPECT_EQ("hello!", response_data);
10234
10235 helper.VerifyDataConsumed();
10236}
10237
10238TEST_F(SpdyNetworkTransactionTest, ZeroRTTSyncConfirmSyncWrite) {
David Benjaminbae08ba2019-10-18 21:06:1510239 static const base::TimeDelta kDelay = base::TimeDelta::FromMilliseconds(10);
Steven Valdez1c1859172019-04-10 15:33:2810240 spdy::SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
10241 kDefaultUrl, 1, kUploadDataSize, LOWEST, nullptr, 0));
10242 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
10243 MockWrite writes[] = {
10244 CreateMockWrite(req, 0, SYNCHRONOUS),
10245 CreateMockWrite(body, 1), // POST upload frame
10246 };
10247
10248 spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
10249 MockRead reads[] = {
10250 CreateMockRead(resp, 2), CreateMockRead(body, 3),
10251 MockRead(ASYNC, 0, 4) // EOF
10252 };
10253
10254 SequencedSocketData data(reads, writes);
10255 UsePostRequest();
10256 auto session_deps = std::make_unique<SpdySessionDependencies>();
10257 session_deps->enable_early_data = true;
10258 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
10259 std::move(session_deps));
10260 auto ssl_provider = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
David Benjaminbae08ba2019-10-18 21:06:1510261 ssl_provider->connect_callback = FastForwardByCallback(kDelay);
Steven Valdez1c1859172019-04-10 15:33:2810262 ssl_provider->confirm = MockConfirm(SYNCHRONOUS, OK);
David Benjaminbae08ba2019-10-18 21:06:1510263 ssl_provider->confirm_callback = FastForwardByCallback(kDelay);
10264 base::TimeTicks start_time = base::TimeTicks::Now();
Steven Valdez1c1859172019-04-10 15:33:2810265 helper.RunToCompletionWithSSLData(&data, std::move(ssl_provider));
10266 TransactionHelperResult out = helper.output();
10267 EXPECT_THAT(out.rv, IsOk());
10268 EXPECT_EQ("HTTP/1.1 200", out.status_line);
10269 EXPECT_EQ("hello!", out.response_data);
David Benjaminbae08ba2019-10-18 21:06:1510270
10271 // The handshake time should include the time it took to run Connect(), but
10272 // not ConfirmHandshake(). If ConfirmHandshake() returns synchronously, we
10273 // assume the connection did not negotiate 0-RTT or the handshake was already
10274 // confirmed.
10275 LoadTimingInfo load_timing_info;
10276 EXPECT_TRUE(helper.trans()->GetLoadTimingInfo(&load_timing_info));
10277 EXPECT_EQ(load_timing_info.connect_timing.connect_start, start_time);
10278 EXPECT_EQ(load_timing_info.connect_timing.ssl_start, start_time);
10279 EXPECT_EQ(load_timing_info.connect_timing.ssl_end, start_time + kDelay);
10280 EXPECT_EQ(load_timing_info.connect_timing.connect_end, start_time + kDelay);
Steven Valdez1c1859172019-04-10 15:33:2810281}
10282
10283TEST_F(SpdyNetworkTransactionTest, ZeroRTTSyncConfirmAsyncWrite) {
10284 spdy::SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
10285 kDefaultUrl, 1, kUploadDataSize, LOWEST, nullptr, 0));
10286 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
10287 MockWrite writes[] = {
10288 CreateMockWrite(req, 0, ASYNC),
10289 CreateMockWrite(body, 1), // POST upload frame
10290 };
10291
10292 spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
10293 MockRead reads[] = {
10294 CreateMockRead(resp, 2), CreateMockRead(body, 3),
10295 MockRead(ASYNC, 0, 4) // EOF
10296 };
10297
10298 SequencedSocketData data(reads, writes);
10299 UsePostRequest();
10300 auto session_deps = std::make_unique<SpdySessionDependencies>();
10301 session_deps->enable_early_data = true;
10302 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
10303 std::move(session_deps));
10304 auto ssl_provider = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
10305 ssl_provider->confirm = MockConfirm(SYNCHRONOUS, OK);
10306 helper.RunToCompletionWithSSLData(&data, std::move(ssl_provider));
10307 TransactionHelperResult out = helper.output();
10308 EXPECT_THAT(out.rv, IsOk());
10309 EXPECT_EQ("HTTP/1.1 200", out.status_line);
10310 EXPECT_EQ("hello!", out.response_data);
10311}
10312
10313TEST_F(SpdyNetworkTransactionTest, ZeroRTTAsyncConfirmSyncWrite) {
David Benjaminbae08ba2019-10-18 21:06:1510314 static const base::TimeDelta kDelay = base::TimeDelta::FromMilliseconds(10);
Steven Valdez1c1859172019-04-10 15:33:2810315 spdy::SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
10316 kDefaultUrl, 1, kUploadDataSize, LOWEST, nullptr, 0));
10317 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
10318 MockWrite writes[] = {
10319 CreateMockWrite(req, 0, SYNCHRONOUS),
10320 CreateMockWrite(body, 1), // POST upload frame
10321 };
10322
10323 spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
10324 MockRead reads[] = {
10325 CreateMockRead(resp, 2), CreateMockRead(body, 3),
10326 MockRead(ASYNC, 0, 4) // EOF
10327 };
10328
10329 SequencedSocketData data(reads, writes);
10330 UsePostRequest();
10331 auto session_deps = std::make_unique<SpdySessionDependencies>();
10332 session_deps->enable_early_data = true;
10333 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
10334 std::move(session_deps));
10335 auto ssl_provider = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
David Benjaminbae08ba2019-10-18 21:06:1510336 ssl_provider->connect_callback = FastForwardByCallback(kDelay);
Steven Valdez1c1859172019-04-10 15:33:2810337 ssl_provider->confirm = MockConfirm(ASYNC, OK);
David Benjaminbae08ba2019-10-18 21:06:1510338 ssl_provider->confirm_callback = FastForwardByCallback(kDelay);
10339 base::TimeTicks start_time = base::TimeTicks::Now();
Steven Valdez1c1859172019-04-10 15:33:2810340 helper.RunToCompletionWithSSLData(&data, std::move(ssl_provider));
10341 TransactionHelperResult out = helper.output();
10342 EXPECT_THAT(out.rv, IsOk());
10343 EXPECT_EQ("HTTP/1.1 200", out.status_line);
10344 EXPECT_EQ("hello!", out.response_data);
David Benjaminbae08ba2019-10-18 21:06:1510345
10346 // The handshake time should include the time it took to run Connect() and
10347 // ConfirmHandshake().
10348 LoadTimingInfo load_timing_info;
10349 EXPECT_TRUE(helper.trans()->GetLoadTimingInfo(&load_timing_info));
10350 EXPECT_EQ(load_timing_info.connect_timing.connect_start, start_time);
10351 EXPECT_EQ(load_timing_info.connect_timing.ssl_start, start_time);
10352 EXPECT_EQ(load_timing_info.connect_timing.ssl_end, start_time + 2 * kDelay);
10353 EXPECT_EQ(load_timing_info.connect_timing.connect_end,
10354 start_time + 2 * kDelay);
Steven Valdez1c1859172019-04-10 15:33:2810355}
10356
10357TEST_F(SpdyNetworkTransactionTest, ZeroRTTAsyncConfirmAsyncWrite) {
10358 spdy::SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
10359 kDefaultUrl, 1, kUploadDataSize, LOWEST, nullptr, 0));
10360 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
10361 MockWrite writes[] = {
10362 CreateMockWrite(req, 0, ASYNC),
10363 CreateMockWrite(body, 1), // POST upload frame
10364 };
10365
10366 spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
10367 MockRead reads[] = {
10368 CreateMockRead(resp, 2), CreateMockRead(body, 3),
10369 MockRead(ASYNC, 0, 4) // EOF
10370 };
10371
10372 SequencedSocketData data(reads, writes);
10373 UsePostRequest();
10374 auto session_deps = std::make_unique<SpdySessionDependencies>();
10375 session_deps->enable_early_data = true;
10376 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
10377 std::move(session_deps));
10378 auto ssl_provider = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
10379 ssl_provider->confirm = MockConfirm(ASYNC, OK);
10380 helper.RunToCompletionWithSSLData(&data, std::move(ssl_provider));
10381 TransactionHelperResult out = helper.output();
10382 EXPECT_THAT(out.rv, IsOk());
10383 EXPECT_EQ("HTTP/1.1 200", out.status_line);
10384 EXPECT_EQ("hello!", out.response_data);
10385}
10386
10387TEST_F(SpdyNetworkTransactionTest, ZeroRTTConfirmErrorSync) {
10388 spdy::SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
10389 kDefaultUrl, 1, kUploadDataSize, LOWEST, nullptr, 0));
10390 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
10391 MockWrite writes[] = {
10392 CreateMockWrite(req, 0), CreateMockWrite(body, 1), // POST upload frame
10393 };
10394
10395 spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
10396 MockRead reads[] = {
10397 CreateMockRead(resp, 2), CreateMockRead(body, 3),
10398 MockRead(ASYNC, 0, 4) // EOF
10399 };
10400
10401 SequencedSocketData data(reads, writes);
10402 UsePostRequest();
10403 auto session_deps = std::make_unique<SpdySessionDependencies>();
10404 session_deps->enable_early_data = true;
10405 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
10406 std::move(session_deps));
10407 auto ssl_provider = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
10408 ssl_provider->confirm = MockConfirm(SYNCHRONOUS, ERR_SSL_PROTOCOL_ERROR);
10409 helper.RunPreTestSetup();
10410 helper.AddDataWithSSLSocketDataProvider(&data, std::move(ssl_provider));
10411 helper.RunDefaultTest();
10412 TransactionHelperResult out = helper.output();
10413 EXPECT_THAT(out.rv, IsError(ERR_SSL_PROTOCOL_ERROR));
10414}
10415
10416TEST_F(SpdyNetworkTransactionTest, ZeroRTTConfirmErrorAsync) {
10417 spdy::SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
10418 kDefaultUrl, 1, kUploadDataSize, LOWEST, nullptr, 0));
10419 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
10420 MockWrite writes[] = {
10421 CreateMockWrite(req, 0), CreateMockWrite(body, 1), // POST upload frame
10422 };
10423
10424 spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
10425 MockRead reads[] = {
10426 CreateMockRead(resp, 2), CreateMockRead(body, 3),
10427 MockRead(ASYNC, 0, 4) // EOF
10428 };
10429
10430 SequencedSocketData data(reads, writes);
10431 UsePostRequest();
10432 auto session_deps = std::make_unique<SpdySessionDependencies>();
10433 session_deps->enable_early_data = true;
10434 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
10435 std::move(session_deps));
10436 auto ssl_provider = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
10437 ssl_provider->confirm = MockConfirm(ASYNC, ERR_SSL_PROTOCOL_ERROR);
10438 helper.RunPreTestSetup();
10439 helper.AddDataWithSSLSocketDataProvider(&data, std::move(ssl_provider));
10440 helper.RunDefaultTest();
10441 TransactionHelperResult out = helper.output();
10442 EXPECT_THAT(out.rv, IsError(ERR_SSL_PROTOCOL_ERROR));
10443}
10444
Bence Békycb4be9e2020-07-09 11:18:1410445// If |http2_end_stream_with_data_frame| is false, then the HEADERS frame of a
10446// GET request will close the stream using the END_STREAM flag. Test that
10447// |greased_http2_frame| is ignored and no reserved frames are sent on a closed
10448// stream.
10449TEST_F(SpdyNetworkTransactionTest,
10450 DoNotGreaseFrameTypeWithGetRequestIfHeadersFrameClosesStream) {
10451 auto session_deps = std::make_unique<SpdySessionDependencies>();
10452
10453 const uint8_t type = 0x0b;
10454 const uint8_t flags = 0xcc;
10455 const std::string payload("foo");
10456 session_deps->greased_http2_frame =
Anton Bikineev068d2912021-05-15 20:43:5210457 absl::optional<net::SpdySessionPool::GreasedHttp2Frame>(
Bence Békycb4be9e2020-07-09 11:18:1410458 {type, flags, payload});
10459 session_deps->http2_end_stream_with_data_frame = false;
10460
10461 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
10462 std::move(session_deps));
10463
10464 spdy::SpdySerializedFrame req(
10465 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, DEFAULT_PRIORITY));
10466 MockWrite writes[] = {CreateMockWrite(req, 0)};
10467
10468 spdy::SpdySerializedFrame resp(
10469 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
10470 spdy::SpdySerializedFrame response_body(
10471 spdy_util_.ConstructSpdyDataFrame(1, true));
10472
10473 MockRead reads[] = {CreateMockRead(resp, 1), CreateMockRead(response_body, 2),
10474 MockRead(ASYNC, 0, 3)};
10475
10476 SequencedSocketData data(reads, writes);
10477 helper.RunPreTestSetup();
10478 helper.AddData(&data);
10479
10480 TestCompletionCallback callback;
10481 int rv = helper.trans()->Start(&request_, callback.callback(), log_);
10482 EXPECT_THAT(callback.GetResult(rv), IsOk());
10483
10484 base::RunLoop().RunUntilIdle();
10485
10486 helper.VerifyDataConsumed();
10487}
10488
10489// Test that if |http2_end_stream_with_data_frame| and |greased_http2_frame| are
10490// both set, then the HEADERS frame does not have the END_STREAM flag set, it is
10491// followed by a greased frame, and then by an empty DATA frame with END_STREAM
10492// set.
Bence Béky9eb57f62019-11-13 14:47:2510493TEST_F(SpdyNetworkTransactionTest, GreaseFrameTypeWithGetRequest) {
10494 auto session_deps = std::make_unique<SpdySessionDependencies>();
10495
10496 const uint8_t type = 0x0b;
10497 const uint8_t flags = 0xcc;
10498 const std::string payload("foo");
10499 session_deps->greased_http2_frame =
Anton Bikineev068d2912021-05-15 20:43:5210500 absl::optional<net::SpdySessionPool::GreasedHttp2Frame>(
Bence Béky9eb57f62019-11-13 14:47:2510501 {type, flags, payload});
Bence Békycb4be9e2020-07-09 11:18:1410502 session_deps->http2_end_stream_with_data_frame = true;
Bence Béky9eb57f62019-11-13 14:47:2510503
10504 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
10505 std::move(session_deps));
10506
Bence Béky4c325e52020-10-22 20:48:0110507 spdy::Http2HeaderBlock headers(
Bence Béky9eb57f62019-11-13 14:47:2510508 spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
10509 spdy::SpdySerializedFrame req(
10510 spdy_util_.ConstructSpdyHeaders(1, std::move(headers), DEFAULT_PRIORITY,
10511 /* fin = */ false));
10512
10513 const char kRawFrameData[] = {
10514 0x00, 0x00, 0x03, // length
10515 0x0b, // type
10516 0xcc, // flags
10517 0x00, 0x00, 0x00, 0x01, // stream ID
10518 'f', 'o', 'o' // payload
10519 };
10520 spdy::SpdySerializedFrame grease(const_cast<char*>(kRawFrameData),
10521 base::size(kRawFrameData),
10522 /* owns_buffer = */ false);
10523 spdy::SpdySerializedFrame empty_body(
10524 spdy_util_.ConstructSpdyDataFrame(1, "", true));
10525
10526 MockWrite writes[] = {CreateMockWrite(req, 0), CreateMockWrite(grease, 1),
10527 CreateMockWrite(empty_body, 2)};
10528
10529 spdy::SpdySerializedFrame resp(
10530 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
10531 spdy::SpdySerializedFrame response_body(
10532 spdy_util_.ConstructSpdyDataFrame(1, true));
10533
10534 MockRead reads[] = {CreateMockRead(resp, 3), CreateMockRead(response_body, 4),
10535 MockRead(ASYNC, 0, 5)};
10536
10537 SequencedSocketData data(reads, writes);
10538 helper.RunPreTestSetup();
10539 helper.AddData(&data);
10540
10541 TestCompletionCallback callback;
10542 int rv = helper.trans()->Start(&request_, callback.callback(), log_);
10543 EXPECT_THAT(callback.GetResult(rv), IsOk());
10544
10545 base::RunLoop().RunUntilIdle();
10546
10547 helper.VerifyDataConsumed();
10548}
10549
Bence Békycb4be9e2020-07-09 11:18:1410550// Test sending a greased frame before DATA frame that closes the stream when
10551// |http2_end_stream_with_data_frame| is false.
10552TEST_F(SpdyNetworkTransactionTest,
10553 GreaseFrameTypeWithPostRequestWhenHeadersFrameClosesStream) {
Bence Béky9eb57f62019-11-13 14:47:2510554 UsePostRequest();
10555
10556 auto session_deps = std::make_unique<SpdySessionDependencies>();
10557
10558 const uint8_t type = 0x0b;
10559 const uint8_t flags = 0xcc;
10560 const std::string payload("foo");
10561 session_deps->greased_http2_frame =
Anton Bikineev068d2912021-05-15 20:43:5210562 absl::optional<net::SpdySessionPool::GreasedHttp2Frame>(
Bence Béky9eb57f62019-11-13 14:47:2510563 {type, flags, payload});
Bence Békycb4be9e2020-07-09 11:18:1410564 session_deps->http2_end_stream_with_data_frame = true;
10565
10566 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
10567 std::move(session_deps));
10568
10569 spdy::SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
10570 kDefaultUrl, 1, kUploadDataSize, LOWEST, nullptr, 0));
10571
10572 const char kRawFrameData[] = {
10573 0x00, 0x00, 0x03, // length
10574 0x0b, // type
10575 0xcc, // flags
10576 0x00, 0x00, 0x00, 0x01, // stream ID
10577 'f', 'o', 'o' // payload
10578 };
10579 spdy::SpdySerializedFrame grease(const_cast<char*>(kRawFrameData),
10580 base::size(kRawFrameData),
10581 /* owns_buffer = */ false);
10582 spdy::SpdySerializedFrame request_body(
10583 spdy_util_.ConstructSpdyDataFrame(1, true));
10584
10585 MockWrite writes[] = {CreateMockWrite(req, 0), CreateMockWrite(grease, 1),
10586 CreateMockWrite(request_body, 2)};
10587
10588 spdy::SpdySerializedFrame resp(
10589 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
10590 spdy::SpdySerializedFrame response_body(
10591 spdy_util_.ConstructSpdyDataFrame(1, true));
10592
10593 MockRead reads[] = {CreateMockRead(resp, 3), CreateMockRead(response_body, 4),
10594 MockRead(ASYNC, 0, 5)};
10595
10596 SequencedSocketData data(reads, writes);
10597 helper.RunPreTestSetup();
10598 helper.AddData(&data);
10599
10600 TestCompletionCallback callback;
10601 int rv = helper.trans()->Start(&request_, callback.callback(), log_);
10602 EXPECT_THAT(callback.GetResult(rv), IsOk());
10603
10604 base::RunLoop().RunUntilIdle();
10605
10606 helper.VerifyDataConsumed();
10607}
10608
10609// Test sending a greased frame before DATA frame that closes the stream.
10610// |http2_end_stream_with_data_frame| is true but should make no difference,
10611// because the stream is already closed by a DATA frame.
10612TEST_F(SpdyNetworkTransactionTest,
10613 GreaseFrameTypeWithPostRequestWhenEmptyDataFrameClosesStream) {
10614 UsePostRequest();
10615
10616 auto session_deps = std::make_unique<SpdySessionDependencies>();
10617
10618 const uint8_t type = 0x0b;
10619 const uint8_t flags = 0xcc;
10620 const std::string payload("foo");
10621 session_deps->greased_http2_frame =
Anton Bikineev068d2912021-05-15 20:43:5210622 absl::optional<net::SpdySessionPool::GreasedHttp2Frame>(
Bence Békycb4be9e2020-07-09 11:18:1410623 {type, flags, payload});
10624 session_deps->http2_end_stream_with_data_frame = true;
Bence Béky9eb57f62019-11-13 14:47:2510625
10626 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
10627 std::move(session_deps));
10628
10629 spdy::SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
10630 kDefaultUrl, 1, kUploadDataSize, LOWEST, nullptr, 0));
10631
10632 const char kRawFrameData[] = {
10633 0x00, 0x00, 0x03, // length
10634 0x0b, // type
10635 0xcc, // flags
10636 0x00, 0x00, 0x00, 0x01, // stream ID
10637 'f', 'o', 'o' // payload
10638 };
10639 spdy::SpdySerializedFrame grease(const_cast<char*>(kRawFrameData),
10640 base::size(kRawFrameData),
10641 /* owns_buffer = */ false);
10642 spdy::SpdySerializedFrame request_body(
10643 spdy_util_.ConstructSpdyDataFrame(1, true));
10644
10645 MockWrite writes[] = {CreateMockWrite(req, 0), CreateMockWrite(grease, 1),
10646 CreateMockWrite(request_body, 2)};
10647
10648 spdy::SpdySerializedFrame resp(
10649 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
10650 spdy::SpdySerializedFrame response_body(
10651 spdy_util_.ConstructSpdyDataFrame(1, true));
10652
10653 MockRead reads[] = {CreateMockRead(resp, 3), CreateMockRead(response_body, 4),
10654 MockRead(ASYNC, 0, 5)};
10655
10656 SequencedSocketData data(reads, writes);
10657 helper.RunPreTestSetup();
10658 helper.AddData(&data);
10659
10660 TestCompletionCallback callback;
10661 int rv = helper.trans()->Start(&request_, callback.callback(), log_);
10662 EXPECT_THAT(callback.GetResult(rv), IsOk());
10663
10664 base::RunLoop().RunUntilIdle();
10665
10666 helper.VerifyDataConsumed();
10667}
10668
Bence Béky21755dd62019-11-19 13:47:3510669// According to https://httpwg.org/specs/rfc7540.html#CONNECT, "frame types
10670// other than DATA or stream management frames (RST_STREAM, WINDOW_UPDATE, and
10671// PRIORITY) MUST NOT be sent on a connected stream".
Bence Békycb4be9e2020-07-09 11:18:1410672// Also test that |http2_end_stream_with_data_frame| has no effect on proxy
10673// streams.
Bence Béky21755dd62019-11-19 13:47:3510674TEST_F(SpdyNetworkTransactionTest, DoNotGreaseFrameTypeWithConnect) {
10675 auto session_deps = std::make_unique<SpdySessionDependencies>(
Nicolas Arciniegad2013f92020-02-07 23:00:5610676 ConfiguredProxyResolutionService::CreateFixedFromPacResult(
Bence Béky21755dd62019-11-19 13:47:3510677 "HTTPS myproxy:70", TRAFFIC_ANNOTATION_FOR_TESTS));
10678
10679 const uint8_t type = 0x0b;
10680 const uint8_t flags = 0xcc;
10681 const std::string payload("foo");
10682 session_deps->greased_http2_frame =
Anton Bikineev068d2912021-05-15 20:43:5210683 absl::optional<net::SpdySessionPool::GreasedHttp2Frame>(
Bence Béky21755dd62019-11-19 13:47:3510684 {type, flags, payload});
Bence Békycb4be9e2020-07-09 11:18:1410685 session_deps->http2_end_stream_with_data_frame = true;
Bence Béky21755dd62019-11-19 13:47:3510686
10687 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
10688 std::move(session_deps));
10689
10690 // CONNECT to proxy.
10691 spdy::SpdySerializedFrame connect_req(spdy_util_.ConstructSpdyConnect(
10692 nullptr, 0, 1, HttpProxyConnectJob::kH2QuicTunnelPriority,
10693 HostPortPair("www.example.org", 443)));
10694 spdy::SpdySerializedFrame connect_response(
10695 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
10696
10697 // Tunneled transaction wrapped in DATA frames.
10698 const char req[] =
10699 "GET / HTTP/1.1\r\n"
10700 "Host: www.example.org\r\n"
10701 "Connection: keep-alive\r\n\r\n";
10702 spdy::SpdySerializedFrame tunneled_req(
10703 spdy_util_.ConstructSpdyDataFrame(1, req, false));
10704
10705 const char resp[] =
10706 "HTTP/1.1 200 OK\r\n"
10707 "Content-Length: 5\r\n\r\n"
10708 "hello";
10709 spdy::SpdySerializedFrame tunneled_response(
10710 spdy_util_.ConstructSpdyDataFrame(1, resp, false));
10711
10712 MockWrite writes[] = {CreateMockWrite(connect_req, 0),
10713 CreateMockWrite(tunneled_req, 2)};
10714
10715 MockRead reads[] = {CreateMockRead(connect_response, 1),
10716 CreateMockRead(tunneled_response, 3),
10717 MockRead(ASYNC, 0, 4)};
10718
10719 SequencedSocketData data0(reads, writes);
10720
10721 // HTTP/2 connection to proxy.
10722 auto ssl_provider0 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
10723 ssl_provider0->next_proto = kProtoHTTP2;
10724 helper.AddDataWithSSLSocketDataProvider(&data0, std::move(ssl_provider0));
10725
10726 // HTTP/1.1 to destination.
10727 SSLSocketDataProvider ssl_provider1(ASYNC, OK);
10728 ssl_provider1.next_proto = kProtoHTTP11;
10729 helper.session_deps()->socket_factory->AddSSLSocketDataProvider(
10730 &ssl_provider1);
10731
10732 helper.RunPreTestSetup();
10733 helper.StartDefaultTest();
10734 helper.FinishDefaultTestWithoutVerification();
10735 helper.VerifyDataConsumed();
10736
10737 const HttpResponseInfo* response = helper.trans()->GetResponseInfo();
10738 ASSERT_TRUE(response);
10739 ASSERT_TRUE(response->headers);
10740 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
10741 EXPECT_FALSE(response->was_fetched_via_spdy);
10742 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP1_1,
10743 response->connection_info);
10744 EXPECT_TRUE(response->was_alpn_negotiated);
10745 EXPECT_TRUE(request_.url.SchemeIs("https"));
10746 EXPECT_EQ("127.0.0.1", response->remote_endpoint.ToStringWithoutPort());
10747 EXPECT_EQ(70, response->remote_endpoint.port());
10748 std::string response_data;
10749 ASSERT_THAT(ReadTransaction(helper.trans(), &response_data), IsOk());
10750 EXPECT_EQ("hello", response_data);
10751}
10752
Bence Béky087d4ba2020-05-13 23:10:2810753// Regression test for https://crbug.com/1081955.
10754// Greasing frame types is enabled, the outgoing HEADERS frame is followed by a
10755// frame of reserved type, then an empty DATA frame to close the stream.
10756// Response arrives before reserved frame and DATA frame can be sent.
10757// SpdyHttpStream::OnDataSent() must not crash.
10758TEST_F(SpdyNetworkTransactionTest, OnDataSentDoesNotCrashWithGreasedFrameType) {
10759 auto session_deps = std::make_unique<SpdySessionDependencies>();
10760
10761 const uint8_t type = 0x0b;
10762 const uint8_t flags = 0xcc;
10763 const std::string payload("foo");
10764 session_deps->greased_http2_frame =
Anton Bikineev068d2912021-05-15 20:43:5210765 absl::optional<net::SpdySessionPool::GreasedHttp2Frame>(
Bence Béky087d4ba2020-05-13 23:10:2810766 {type, flags, payload});
Bence Békycb4be9e2020-07-09 11:18:1410767 session_deps->http2_end_stream_with_data_frame = true;
Bence Béky087d4ba2020-05-13 23:10:2810768
10769 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
10770 std::move(session_deps));
10771
Bence Béky4c325e52020-10-22 20:48:0110772 spdy::Http2HeaderBlock headers(
Bence Béky087d4ba2020-05-13 23:10:2810773 spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
10774 spdy::SpdySerializedFrame req(
10775 spdy_util_.ConstructSpdyHeaders(1, std::move(headers), DEFAULT_PRIORITY,
10776 /* fin = */ false));
10777
10778 const char kRawFrameData[] = {
10779 0x00, 0x00, 0x03, // length
10780 0x0b, // type
10781 0xcc, // flags
10782 0x00, 0x00, 0x00, 0x01, // stream ID
10783 'f', 'o', 'o' // payload
10784 };
10785 spdy::SpdySerializedFrame grease(const_cast<char*>(kRawFrameData),
10786 base::size(kRawFrameData),
10787 /* owns_buffer = */ false);
10788 spdy::SpdySerializedFrame empty_body(
10789 spdy_util_.ConstructSpdyDataFrame(1, "", true));
10790
10791 MockWrite writes[] = {
10792 CreateMockWrite(req, 0), MockWrite(ASYNC, ERR_IO_PENDING, 2),
10793 CreateMockWrite(grease, 3), CreateMockWrite(empty_body, 4)};
10794
10795 spdy::SpdySerializedFrame resp(
10796 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
10797 spdy::SpdySerializedFrame response_body(
10798 spdy_util_.ConstructSpdyDataFrame(1, true));
10799
10800 MockRead reads[] = {CreateMockRead(resp, 1), CreateMockRead(response_body, 5),
10801 MockRead(ASYNC, 0, 6)};
10802
10803 SequencedSocketData data(reads, writes);
10804 helper.RunPreTestSetup();
10805 helper.AddData(&data);
10806
10807 TestCompletionCallback callback;
10808 int rv = helper.trans()->Start(&request_, callback.callback(), log_);
10809 base::RunLoop().RunUntilIdle();
10810
10811 // Response headers received. Resume sending |grease| and |empty_body|.
10812 data.Resume();
10813 EXPECT_THAT(callback.GetResult(rv), IsOk());
10814
10815 base::RunLoop().RunUntilIdle();
10816
10817 helper.VerifyDataConsumed();
10818}
10819
Yoichi Osato4c75c0c2020-06-24 08:03:5710820TEST_F(SpdyNetworkTransactionTest, NotAllowHTTP1NotBlockH2Post) {
10821 spdy::SpdySerializedFrame req(
10822 spdy_util_.ConstructChunkedSpdyPost(nullptr, 0));
10823 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
10824 MockWrite writes[] = {
10825 CreateMockWrite(req, 0), CreateMockWrite(body, 1), // POST upload frame
10826 };
10827 spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
10828 MockRead reads[] = {
10829 CreateMockRead(resp, 2), CreateMockRead(body, 3),
10830 MockRead(ASYNC, 0, 4) // EOF
10831 };
10832 SequencedSocketData data(reads, writes);
10833
10834 request_.method = "POST";
10835 UploadDataStreamNotAllowHTTP1 upload_data(kUploadData);
10836 request_.upload_data_stream = &upload_data;
10837
10838 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
10839 helper.RunToCompletion(&data);
10840 TransactionHelperResult out = helper.output();
10841 EXPECT_THAT(out.rv, IsOk());
10842 EXPECT_EQ("HTTP/1.1 200", out.status_line);
10843 EXPECT_EQ("hello!", out.response_data);
10844}
10845
Bence Béky78b542c2021-03-25 19:30:3710846TEST_F(SpdyNetworkTransactionTest, AlpsFramingError) {
10847 base::HistogramTester histogram_tester;
10848
10849 spdy::SpdySerializedFrame goaway(spdy_util_.ConstructSpdyGoAway(
10850 0, spdy::ERROR_CODE_PROTOCOL_ERROR, "Error parsing ALPS: 3"));
10851 MockWrite writes[] = {CreateMockWrite(goaway, 0)};
10852 SequencedSocketData data(base::span<MockRead>(), writes);
10853
10854 auto ssl_provider = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
10855 // Not a complete HTTP/2 frame.
10856 ssl_provider->peer_application_settings = "boo";
10857
10858 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
10859 helper.RunToCompletionWithSSLData(&data, std::move(ssl_provider));
10860
10861 TransactionHelperResult out = helper.output();
10862 EXPECT_THAT(out.rv, IsError(ERR_HTTP2_PROTOCOL_ERROR));
10863
10864 histogram_tester.ExpectUniqueSample(
10865 "Net.SpdySession.AlpsDecoderStatus",
10866 static_cast<int>(AlpsDecoder::Error::kNotOnFrameBoundary), 1);
10867 histogram_tester.ExpectTotalCount("Net.SpdySession.AlpsAcceptChEntries", 0);
10868 histogram_tester.ExpectTotalCount("Net.SpdySession.AlpsSettingParameterCount",
10869 0);
10870}
10871
[email protected]aea80602009-09-18 00:55:0810872} // namespace net