blob: 9cbbcea90ce810aad3566518db5cee061a28c650 [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"
Lei Zhang305c015e12021-06-04 21:07:0212#include "base/cxx17_backports.h"
thestigd8df0332014-09-04 06:33:2913#include "base/files/file_util.h"
[email protected]ea1a3f62012-11-16 20:34:2314#include "base/files/scoped_temp_dir.h"
Keishi Hattori0e45c022021-11-27 09:25:5215#include "base/memory/raw_ptr.h"
[email protected]fc9d88472013-08-14 02:31:1716#include "base/run_loop.h"
Bence Békyd228fb22021-10-29 14:45:5117#include "base/strings/string_number_conversions.h"
Bence Békyd74f4382018-02-20 18:26:1918#include "base/strings/string_piece.h"
Devlin Cronine4bcb40e2018-06-05 18:02:4719#include "base/test/metrics/histogram_tester.h"
Matt Menkef2ee07c2019-08-29 02:10:3620#include "base/test/scoped_feature_list.h"
[email protected]999dd8c2013-11-12 06:45:5421#include "base/test/test_file_util.h"
gabf767595f2016-05-11 18:50:3522#include "base/threading/thread_task_runner_handle.h"
Matt Menke5062be22019-05-01 17:50:2423#include "build/build_config.h"
[email protected]018aabc2010-10-29 16:16:5924#include "net/base/auth.h"
mmenkecbc2b712014-10-09 20:29:0725#include "net/base/chunked_upload_data_stream.h"
Bence Béky8ddc2492018-06-13 01:02:0426#include "net/base/completion_once_callback.h"
mmenkecbc2b712014-10-09 20:29:0727#include "net/base/elements_upload_data_stream.h"
Matt Menkef2ee07c2019-08-29 02:10:3628#include "net/base/features.h"
Tsuyoshi Horo01faed62019-02-20 22:11:3729#include "net/base/ip_endpoint.h"
Matt Menkef2ee07c2019-08-29 02:10:3630#include "net/base/network_isolation_key.h"
tbansal28e68f82016-02-04 02:56:1531#include "net/base/proxy_delegate.h"
Lily Houghton582d4622018-01-22 22:43:4032#include "net/base/proxy_server.h"
Eric Orth5ccc3f02021-09-23 00:01:5733#include "net/base/proxy_string_util.h"
[email protected]262eec82013-03-19 21:01:3634#include "net/base/request_priority.h"
Matt Menke4807a9a2020-11-21 00:14:4135#include "net/base/schemeful_site.h"
tbansal28e68f82016-02-04 02:56:1536#include "net/base/test_proxy_delegate.h"
[email protected]b2d26cfd2012-12-11 10:36:0637#include "net/base/upload_bytes_element_reader.h"
[email protected]b2d26cfd2012-12-11 10:36:0638#include "net/base/upload_file_element_reader.h"
Bence Béky1a5d8562018-01-05 17:29:2839#include "net/dns/mock_host_resolver.h"
Ben Schwartz3ff4dc1e62021-04-27 21:15:2340#include "net/dns/public/secure_dns_policy.h"
aberentbba302d2015-12-03 10:20:1941#include "net/http/http_auth_scheme.h"
bnc3171a2432016-12-28 18:40:2642#include "net/http/http_network_session.h"
[email protected]87bfa3f2010-09-30 14:54:5643#include "net/http/http_network_session_peer.h"
[email protected]513963e2013-06-15 01:53:0444#include "net/http/http_network_transaction.h"
Matt Menke6e879bd2019-03-18 17:26:0445#include "net/http/http_proxy_connect_job.h"
Bence Béky3a0c48532018-03-02 13:38:5146#include "net/http/http_response_info.h"
[email protected]513963e2013-06-15 01:53:0447#include "net/http/http_server_properties.h"
[email protected]c41737d2014-05-14 07:47:1948#include "net/http/http_transaction_test_util.h"
Yoichi Osato4c75c0c2020-06-24 08:03:5749#include "net/http/test_upload_data_stream_not_allow_http1.h"
Matt Menkec74a9262020-06-09 15:49:2150#include "net/http/transport_security_state.h"
mikecirone8b85c432016-09-08 19:11:0051#include "net/log/net_log_event_type.h"
mikecironef22f9812016-10-04 03:40:1952#include "net/log/net_log_with_source.h"
mmenke16a7cbdd2015-04-24 23:00:5653#include "net/log/test_net_log.h"
mmenke43758e62015-05-04 21:09:4654#include "net/log/test_net_log_util.h"
Nicolas Arciniega8ec5bfa2020-03-20 05:07:2655#include "net/proxy_resolution/configured_proxy_resolution_service.h"
[email protected]bb88e1d32013-05-03 23:11:0756#include "net/socket/next_proto.h"
Paul Jensena457017a2018-01-19 23:52:0457#include "net/socket/socket_tag.h"
Bence Béky78b542c2021-03-25 19:30:3758#include "net/spdy/alps_decoder.h"
Bence Béky94658bf2018-05-11 19:22:5859#include "net/spdy/buffered_spdy_framer.h"
60#include "net/spdy/spdy_http_stream.h"
61#include "net/spdy/spdy_http_utils.h"
62#include "net/spdy/spdy_session.h"
63#include "net/spdy/spdy_session_pool.h"
64#include "net/spdy/spdy_test_util_common.h"
[email protected]514aeaf2014-05-23 10:31:5165#include "net/ssl/ssl_connection_status_flags.h"
bncce36dca22015-04-21 22:11:2366#include "net/test/cert_test_util.h"
robpercival214763f2016-07-01 23:27:0167#include "net/test/gtest_util.h"
rsleevia69c79a2016-06-22 03:28:4368#include "net/test/test_data_directory.h"
Gabriel Charettec7108742019-08-23 03:31:4069#include "net/test/test_with_task_environment.h"
Victor Vasiliev27cc7712019-01-24 11:50:1470#include "net/third_party/quiche/src/spdy/core/spdy_protocol.h"
71#include "net/third_party/quiche/src/spdy/core/spdy_test_utils.h"
rhalavati9ebaba7e2017-04-27 06:16:2972#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
[email protected]d2db0292011-01-26 20:23:4473#include "net/url_request/url_request_test_util.h"
Bence Béky0ca719f2018-01-31 13:41:1974#include "net/websockets/websocket_test_util.h"
[email protected]251029e2014-03-19 06:04:4075#include "testing/gmock/include/gmock/gmock.h"
[email protected]aea80602009-09-18 00:55:0876#include "testing/platform_test.h"
Matt Menke4807a9a2020-11-21 00:14:4177#include "url/gurl.h"
[email protected]aea80602009-09-18 00:55:0878
robpercival214763f2016-07-01 23:27:0179using net::test::IsError;
80using net::test::IsOk;
81
[email protected]aea80602009-09-18 00:55:0882//-----------------------------------------------------------------------------
83
[email protected]d1eda932009-11-04 01:03:1084namespace net {
[email protected]dae22c52010-07-30 02:16:3585
[email protected]cbdd73162013-03-18 23:27:3386namespace {
[email protected]251029e2014-03-19 06:04:4087
88using testing::Each;
89using testing::Eq;
90
xunjieli179a6e72016-04-26 19:47:4591const int32_t kBufferSize = SpdyHttpStream::kRequestBodyBufferSize;
92
[email protected]513963e2013-06-15 01:53:0493} // namespace
94
Bence Békyd2df6c1c82018-04-20 22:52:0195const char kPushedUrl[] = "https://www.example.org/foo.dat";
96
Gabriel Charette694c3c332019-08-19 14:53:0597class SpdyNetworkTransactionTest : public TestWithTaskEnvironment {
[email protected]34437af82009-11-06 02:28:4998 protected:
rdsmithebb50aa2015-11-12 03:44:3899 SpdyNetworkTransactionTest()
David Benjaminbae08ba2019-10-18 21:06:15100 : TestWithTaskEnvironment(
101 base::test::TaskEnvironment::TimeSource::MOCK_TIME),
102 default_url_(kDefaultUrl),
bncd16676a2016-07-20 16:23:01103 host_port_pair_(HostPortPair::FromURL(default_url_)) {}
[email protected]2d6728692011-03-12 01:39:55104
bncd16676a2016-07-20 16:23:01105 ~SpdyNetworkTransactionTest() override {
Bence Békydb3cf652017-10-10 15:22:10106 // UploadDataStream may post a deletion task back to the message loop on
[email protected]fc9d88472013-08-14 02:31:17107 // destruction.
108 upload_data_stream_.reset();
109 base::RunLoop().RunUntilIdle();
110 }
111
dcheng67be2b1f2014-10-27 21:47:29112 void SetUp() override {
Bence Békydb3cf652017-10-10 15:22:10113 request_.method = "GET";
114 request_.url = GURL(kDefaultUrl);
Ramin Halavatib5e433e62018-02-07 07:41:10115 request_.traffic_annotation =
116 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
[email protected]69e6b4a2012-10-18 08:03:01117 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
[email protected]aea80602009-09-18 00:55:08118 }
119
[email protected]72552f02009-10-28 15:25:01120 struct TransactionHelperResult {
[email protected]aea80602009-09-18 00:55:08121 int rv;
Bence Béky4e83f492018-05-13 23:14:25122 std::string status_line;
123 std::string response_data;
[email protected]8b070372009-11-16 22:01:25124 HttpResponseInfo response_info;
[email protected]aea80602009-09-18 00:55:08125 };
126
[email protected]3caf5542010-07-16 15:19:47127 // A helper class that handles all the initial npn/ssl setup.
128 class NormalSpdyTransactionHelper {
129 public:
rdsmith82957ad2015-09-16 19:42:03130 NormalSpdyTransactionHelper(
131 const HttpRequestInfo& request,
132 RequestPriority priority,
tfarina428341112016-09-22 13:38:20133 const NetLogWithSource& log,
danakjaee3e1ec2016-04-16 00:23:18134 std::unique_ptr<SpdySessionDependencies> session_deps)
[email protected]30c942b2010-07-21 16:59:59135 : request_(request),
[email protected]262eec82013-03-19 21:01:36136 priority_(priority),
tombergan5d22c182017-01-11 02:05:35137 session_deps_(session_deps.get() == nullptr
Jeremy Roman0579ed62017-08-29 15:56:19138 ? std::make_unique<SpdySessionDependencies>()
bncd16676a2016-07-20 16:23:01139 : std::move(session_deps)),
xunjieli925519532017-01-30 15:33:17140 log_(log) {
141 session_deps_->net_log = log.net_log();
142 session_ =
143 SpdySessionDependencies::SpdyCreateSession(session_deps_.get());
144 }
[email protected]61b4efc2012-04-27 18:12:50145
[email protected]19ec8a72010-08-23 03:38:23146 ~NormalSpdyTransactionHelper() {
147 // Any test which doesn't close the socket by sending it an EOF will
148 // have a valid session left open, which leaks the entire session pool.
149 // This is just fine - in fact, some of our tests intentionally do this
150 // so that we can check consistency of the SpdySessionPool as the test
151 // finishes. If we had put an EOF on the socket, the SpdySession would
152 // have closed and we wouldn't be able to check the consistency.
153
154 // Forcefully close existing sessions here.
155 session()->spdy_session_pool()->CloseAllSessions();
156 }
157
[email protected]3caf5542010-07-16 15:19:47158 void RunPreTestSetup() {
[email protected]3caf5542010-07-16 15:19:47159 // We're now ready to use SSL-npn SPDY.
bnc3f6a8552017-05-17 13:40:34160 trans_ =
Jeremy Roman0579ed62017-08-29 15:56:19161 std::make_unique<HttpNetworkTransaction>(priority_, session_.get());
[email protected]cb54b3b22010-06-03 16:28:55162 }
[email protected]aea80602009-09-18 00:55:08163
[email protected]3caf5542010-07-16 15:19:47164 // Start the transaction, read some data, finish.
165 void RunDefaultTest() {
[email protected]34b345f92013-02-22 03:27:26166 if (!StartDefaultTest())
167 return;
168 FinishDefaultTest();
169 }
170
171 bool StartDefaultTest() {
[email protected]514aeaf2014-05-23 10:31:51172 output_.rv = trans_->Start(&request_, callback_.callback(), log_);
[email protected]aea80602009-09-18 00:55:08173
[email protected]3caf5542010-07-16 15:19:47174 // We expect an IO Pending or some sort of error.
175 EXPECT_LT(output_.rv, 0);
[email protected]34b345f92013-02-22 03:27:26176 return output_.rv == ERR_IO_PENDING;
177 }
[email protected]aea80602009-09-18 00:55:08178
[email protected]34b345f92013-02-22 03:27:26179 void FinishDefaultTest() {
[email protected]514aeaf2014-05-23 10:31:51180 output_.rv = callback_.WaitForResult();
bnceb9aa7112017-01-05 01:03:46181 // Finish async network reads/writes.
182 base::RunLoop().RunUntilIdle();
[email protected]3caf5542010-07-16 15:19:47183 if (output_.rv != OK) {
bnc301745a2015-03-10 03:22:16184 session_->spdy_session_pool()->CloseCurrentSessions(ERR_ABORTED);
[email protected]3caf5542010-07-16 15:19:47185 return;
186 }
[email protected]ff57bb82009-11-12 06:52:14187
[email protected]3caf5542010-07-16 15:19:47188 // Verify responses.
189 const HttpResponseInfo* response = trans_->GetResponseInfo();
wezca1070932016-05-26 20:30:52190 ASSERT_TRUE(response);
191 ASSERT_TRUE(response->headers);
bnc80bb1d42016-10-26 18:11:34192 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP2,
bnc927c4962016-07-21 14:45:59193 response->connection_info);
194 EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
195 EXPECT_TRUE(response->was_fetched_via_spdy);
bnc94c92842016-09-21 15:22:52196 EXPECT_TRUE(response->was_alpn_negotiated);
Tsuyoshi Horo01faed62019-02-20 22:11:37197 EXPECT_EQ("127.0.0.1", response->remote_endpoint.ToStringWithoutPort());
198 EXPECT_EQ(443, response->remote_endpoint.port());
[email protected]3caf5542010-07-16 15:19:47199 output_.status_line = response->headers->GetStatusLine();
200 output_.response_info = *response; // Make a copy so we can verify.
201 output_.rv = ReadTransaction(trans_.get(), &output_.response_data);
[email protected]3caf5542010-07-16 15:19:47202 }
203
bncfacdd852015-01-09 19:22:54204 void FinishDefaultTestWithoutVerification() {
205 output_.rv = callback_.WaitForResult();
bnceb9aa7112017-01-05 01:03:46206 // Finish async network reads/writes.
207 base::RunLoop().RunUntilIdle();
bncfacdd852015-01-09 19:22:54208 if (output_.rv != OK)
bnc301745a2015-03-10 03:22:16209 session_->spdy_session_pool()->CloseCurrentSessions(ERR_ABORTED);
bncfacdd852015-01-09 19:22:54210 }
211
maksim.sisov8d2df66d2016-06-20 07:07:11212 void WaitForCallbackToComplete() { output_.rv = callback_.WaitForResult(); }
mmenke666a6fea2015-12-19 04:16:33213
[email protected]3caf5542010-07-16 15:19:47214 // Most tests will want to call this function. In particular, the MockReads
215 // should end with an empty read, and that read needs to be processed to
216 // ensure proper deletion of the spdy_session_pool.
217 void VerifyDataConsumed() {
rch08e3aa3e2015-05-16 14:27:52218 for (const SocketDataProvider* provider : data_vector_) {
219 EXPECT_TRUE(provider->AllReadDataConsumed());
220 EXPECT_TRUE(provider->AllWriteDataConsumed());
[email protected]3caf5542010-07-16 15:19:47221 }
222 }
223
224 // Occasionally a test will expect to error out before certain reads are
225 // processed. In that case we want to explicitly ensure that the reads were
226 // not processed.
227 void VerifyDataNotConsumed() {
rch08e3aa3e2015-05-16 14:27:52228 for (const SocketDataProvider* provider : data_vector_) {
229 EXPECT_FALSE(provider->AllReadDataConsumed());
230 EXPECT_FALSE(provider->AllWriteDataConsumed());
[email protected]3caf5542010-07-16 15:19:47231 }
232 }
233
rch08e3aa3e2015-05-16 14:27:52234 void RunToCompletion(SocketDataProvider* data) {
[email protected]3caf5542010-07-16 15:19:47235 RunPreTestSetup();
[email protected]e3ebba0f2010-08-05 17:59:58236 AddData(data);
[email protected]3caf5542010-07-16 15:19:47237 RunDefaultTest();
238 VerifyDataConsumed();
239 }
[email protected]e6b06862010-07-20 16:32:58240
[email protected]514aeaf2014-05-23 10:31:51241 void RunToCompletionWithSSLData(
rch08e3aa3e2015-05-16 14:27:52242 SocketDataProvider* data,
danakjaee3e1ec2016-04-16 00:23:18243 std::unique_ptr<SSLSocketDataProvider> ssl_provider) {
[email protected]514aeaf2014-05-23 10:31:51244 RunPreTestSetup();
dchengc7eeda422015-12-26 03:56:48245 AddDataWithSSLSocketDataProvider(data, std::move(ssl_provider));
[email protected]514aeaf2014-05-23 10:31:51246 RunDefaultTest();
247 VerifyDataConsumed();
248 }
249
rch08e3aa3e2015-05-16 14:27:52250 void AddData(SocketDataProvider* data) {
Jeremy Roman0579ed62017-08-29 15:56:19251 auto ssl_provider = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
Ryan Sleevi4f832092017-11-21 23:25:49252 ssl_provider->ssl_info.cert =
bncce36dca22015-04-21 22:11:23253 ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem");
dchengc7eeda422015-12-26 03:56:48254 AddDataWithSSLSocketDataProvider(data, std::move(ssl_provider));
[email protected]514aeaf2014-05-23 10:31:51255 }
256
257 void AddDataWithSSLSocketDataProvider(
rch08e3aa3e2015-05-16 14:27:52258 SocketDataProvider* data,
danakjaee3e1ec2016-04-16 00:23:18259 std::unique_ptr<SSLSocketDataProvider> ssl_provider) {
[email protected]3caf5542010-07-16 15:19:47260 data_vector_.push_back(data);
bnc3cf2a592016-08-11 14:48:36261 if (ssl_provider->next_proto == kProtoUnknown)
262 ssl_provider->next_proto = kProtoHTTP2;
rchebf12982015-04-10 01:15:00263
264 session_deps_->socket_factory->AddSSLSocketDataProvider(
265 ssl_provider.get());
olli.raulaae011c422015-12-10 07:38:51266 ssl_vector_.push_back(std::move(ssl_provider));
[email protected]d4f00222012-07-10 06:24:51267
[email protected]3b7828432010-08-18 18:33:27268 session_deps_->socket_factory->AddSocketDataProvider(data);
269 }
270
Cammie Smith Barnes5191037b72021-03-01 22:06:53271 size_t GetSpdySessionCount() {
272 std::unique_ptr<base::Value> value(
273 session_->spdy_session_pool()->SpdySessionPoolInfoToValue());
274 CHECK(value && value->is_list());
275 return value->GetList().size();
276 }
277
[email protected]3caf5542010-07-16 15:19:47278 HttpNetworkTransaction* trans() { return trans_.get(); }
279 void ResetTrans() { trans_.reset(); }
bnc4d782f492016-08-18 13:50:00280 const TransactionHelperResult& output() { return output_; }
mmenkee65e7af2015-10-13 17:16:42281 HttpNetworkSession* session() const { return session_.get(); }
bncd16676a2016-07-20 16:23:01282 SpdySessionDependencies* session_deps() { return session_deps_.get(); }
[email protected]3caf5542010-07-16 15:19:47283
284 private:
rch08e3aa3e2015-05-16 14:27:52285 typedef std::vector<SocketDataProvider*> DataVector;
danakjaee3e1ec2016-04-16 00:23:18286 typedef std::vector<std::unique_ptr<SSLSocketDataProvider>> SSLVector;
287 typedef std::vector<std::unique_ptr<SocketDataProvider>> AlternateVector;
Bence Békydb3cf652017-10-10 15:22:10288 const HttpRequestInfo request_;
289 const RequestPriority priority_;
danakjaee3e1ec2016-04-16 00:23:18290 std::unique_ptr<SpdySessionDependencies> session_deps_;
291 std::unique_ptr<HttpNetworkSession> session_;
[email protected]3caf5542010-07-16 15:19:47292 TransactionHelperResult output_;
[email protected]3caf5542010-07-16 15:19:47293 SSLVector ssl_vector_;
[email protected]514aeaf2014-05-23 10:31:51294 TestCompletionCallback callback_;
danakjaee3e1ec2016-04-16 00:23:18295 std::unique_ptr<HttpNetworkTransaction> trans_;
[email protected]3caf5542010-07-16 15:19:47296 DataVector data_vector_;
tfarina428341112016-09-22 13:38:20297 const NetLogWithSource log_;
[email protected]3caf5542010-07-16 15:19:47298 };
[email protected]aea80602009-09-18 00:55:08299
300 void ConnectStatusHelperWithExpectedStatus(const MockRead& status,
301 int expected_status);
302
303 void ConnectStatusHelper(const MockRead& status);
[email protected]d3cee19d2010-06-22 18:42:18304
Bence Békydb3cf652017-10-10 15:22:10305 HttpRequestInfo CreateGetPushRequest() const WARN_UNUSED_RESULT {
306 HttpRequestInfo request;
307 request.method = "GET";
Bence Békyd2df6c1c82018-04-20 22:52:01308 request.url = GURL(kPushedUrl);
Ramin Halavatib5e433e62018-02-07 07:41:10309 request.traffic_annotation =
310 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
Bence Békydb3cf652017-10-10 15:22:10311 return request;
[email protected]e3ebba0f2010-08-05 17:59:58312 }
313
Bence Békydb3cf652017-10-10 15:22:10314 void UsePostRequest() {
315 ASSERT_FALSE(upload_data_stream_);
316 std::vector<std::unique_ptr<UploadElementReader>> element_readers;
317 element_readers.push_back(std::make_unique<UploadBytesElementReader>(
318 kUploadData, kUploadDataSize));
319 upload_data_stream_ = std::make_unique<ElementsUploadDataStream>(
320 std::move(element_readers), 0);
321
322 request_.method = "POST";
323 request_.upload_data_stream = upload_data_stream_.get();
[email protected]d3cee19d2010-06-22 18:42:18324 }
325
Bence Békydb3cf652017-10-10 15:22:10326 void UseFilePostRequest() {
327 ASSERT_FALSE(upload_data_stream_);
328 base::FilePath file_path;
329 CHECK(base::CreateTemporaryFileInDir(temp_dir_.GetPath(), &file_path));
330 CHECK_EQ(static_cast<int>(kUploadDataSize),
331 base::WriteFile(file_path, kUploadData, kUploadDataSize));
332
333 std::vector<std::unique_ptr<UploadElementReader>> element_readers;
334 element_readers.push_back(std::make_unique<UploadFileElementReader>(
335 base::ThreadTaskRunnerHandle::Get().get(), file_path, 0,
336 kUploadDataSize, base::Time()));
337 upload_data_stream_ = std::make_unique<ElementsUploadDataStream>(
338 std::move(element_readers), 0);
339
340 request_.method = "POST";
341 request_.upload_data_stream = upload_data_stream_.get();
Ramin Halavatib5e433e62018-02-07 07:41:10342 request_.traffic_annotation =
343 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
[email protected]3deb9a52010-11-11 00:24:40344 }
345
Bence Békydb3cf652017-10-10 15:22:10346 void UseUnreadableFilePostRequest() {
347 ASSERT_FALSE(upload_data_stream_);
[email protected]999dd8c2013-11-12 06:45:54348 base::FilePath file_path;
vabrb8582322016-09-09 08:05:37349 CHECK(base::CreateTemporaryFileInDir(temp_dir_.GetPath(), &file_path));
[email protected]999dd8c2013-11-12 06:45:54350 CHECK_EQ(static_cast<int>(kUploadDataSize),
[email protected]e5c2a22e2014-03-06 20:42:30351 base::WriteFile(file_path, kUploadData, kUploadDataSize));
[email protected]92be8eb2014-08-07 22:57:11352 CHECK(base::MakeFileUnreadable(file_path));
[email protected]999dd8c2013-11-12 06:45:54353
danakjaee3e1ec2016-04-16 00:23:18354 std::vector<std::unique_ptr<UploadElementReader>> element_readers;
Jeremy Roman0579ed62017-08-29 15:56:19355 element_readers.push_back(std::make_unique<UploadFileElementReader>(
skyostil4891b25b2015-06-11 11:43:45356 base::ThreadTaskRunnerHandle::Get().get(), file_path, 0,
ricea2deef682016-09-09 08:04:07357 kUploadDataSize, base::Time()));
Jeremy Roman0579ed62017-08-29 15:56:19358 upload_data_stream_ = std::make_unique<ElementsUploadDataStream>(
bnc3f6a8552017-05-17 13:40:34359 std::move(element_readers), 0);
[email protected]999dd8c2013-11-12 06:45:54360
Bence Békydb3cf652017-10-10 15:22:10361 request_.method = "POST";
362 request_.upload_data_stream = upload_data_stream_.get();
[email protected]999dd8c2013-11-12 06:45:54363 }
364
Bence Békydb3cf652017-10-10 15:22:10365 void UseComplexPostRequest() {
366 ASSERT_FALSE(upload_data_stream_);
367 const int kFileRangeOffset = 1;
368 const int kFileRangeLength = 3;
369 CHECK_LT(kFileRangeOffset + kFileRangeLength, kUploadDataSize);
[email protected]69e6b4a2012-10-18 08:03:01370
Bence Békydb3cf652017-10-10 15:22:10371 base::FilePath file_path;
372 CHECK(base::CreateTemporaryFileInDir(temp_dir_.GetPath(), &file_path));
373 CHECK_EQ(static_cast<int>(kUploadDataSize),
374 base::WriteFile(file_path, kUploadData, kUploadDataSize));
[email protected]69e6b4a2012-10-18 08:03:01375
Bence Békydb3cf652017-10-10 15:22:10376 std::vector<std::unique_ptr<UploadElementReader>> element_readers;
377 element_readers.push_back(std::make_unique<UploadBytesElementReader>(
378 kUploadData, kFileRangeOffset));
379 element_readers.push_back(std::make_unique<UploadFileElementReader>(
380 base::ThreadTaskRunnerHandle::Get().get(), file_path, kFileRangeOffset,
381 kFileRangeLength, base::Time()));
382 element_readers.push_back(std::make_unique<UploadBytesElementReader>(
383 kUploadData + kFileRangeOffset + kFileRangeLength,
384 kUploadDataSize - (kFileRangeOffset + kFileRangeLength)));
385 upload_data_stream_ = std::make_unique<ElementsUploadDataStream>(
386 std::move(element_readers), 0);
[email protected]329b68b2012-11-14 17:54:27387
Bence Békydb3cf652017-10-10 15:22:10388 request_.method = "POST";
389 request_.upload_data_stream = upload_data_stream_.get();
[email protected]69e6b4a2012-10-18 08:03:01390 }
391
Bence Békydb3cf652017-10-10 15:22:10392 void UseChunkedPostRequest() {
393 ASSERT_FALSE(upload_chunked_data_stream_);
394 upload_chunked_data_stream_ = std::make_unique<ChunkedUploadDataStream>(0);
395 request_.method = "POST";
396 request_.upload_data_stream = upload_chunked_data_stream_.get();
[email protected]0c9bf872011-03-04 17:53:22397 }
398
[email protected]19ec8a72010-08-23 03:38:23399 // Read the result of a particular transaction, knowing that we've got
400 // multiple transactions in the read pipeline; so as we read, we may have
401 // to skip over data destined for other transactions while we consume
402 // the data for |trans|.
Bence Béky4e83f492018-05-13 23:14:25403 int ReadResult(HttpNetworkTransaction* trans, std::string* result) {
[email protected]19ec8a72010-08-23 03:38:23404 const int kSize = 3000;
[email protected]e3ebba0f2010-08-05 17:59:58405
[email protected]19ec8a72010-08-23 03:38:23406 int bytes_read = 0;
Victor Costan9c7302b2018-08-27 16:39:44407 scoped_refptr<IOBufferWithSize> buf =
408 base::MakeRefCounted<IOBufferWithSize>(kSize);
[email protected]49639fa2011-12-20 23:22:41409 TestCompletionCallback callback;
[email protected]19ec8a72010-08-23 03:38:23410 while (true) {
[email protected]90499482013-06-01 00:39:50411 int rv = trans->Read(buf.get(), kSize, callback.callback());
[email protected]19ec8a72010-08-23 03:38:23412 if (rv == ERR_IO_PENDING) {
[email protected]19ec8a72010-08-23 03:38:23413 rv = callback.WaitForResult();
414 } else if (rv <= 0) {
415 break;
416 }
417 result->append(buf->data(), rv);
418 bytes_read += rv;
[email protected]e3ebba0f2010-08-05 17:59:58419 }
[email protected]19ec8a72010-08-23 03:38:23420 return bytes_read;
421 }
[email protected]e3ebba0f2010-08-05 17:59:58422
[email protected]19ec8a72010-08-23 03:38:23423 void VerifyStreamsClosed(const NormalSpdyTransactionHelper& helper) {
424 // This lengthy block is reaching into the pool to dig out the active
425 // session. Once we have the session, we verify that the streams are
426 // all closed and not leaked at this point.
Bence Békydb3cf652017-10-10 15:22:10427 SpdySessionKey key(HostPortPair::FromURL(request_.url),
Paul Jensena457017a2018-01-19 23:52:04428 ProxyServer::Direct(), PRIVACY_MODE_DISABLED,
dalyk51ab46b2019-10-15 15:14:34429 SpdySessionKey::IsProxySession::kFalse, SocketTag(),
Ben Schwartz3ff4dc1e62021-04-27 21:15:23430 request_.network_isolation_key, SecureDnsPolicy::kAllow);
mmenkee65e7af2015-10-13 17:16:42431 HttpNetworkSession* session = helper.session();
[email protected]795cbf82013-07-22 09:37:27432 base::WeakPtr<SpdySession> spdy_session =
bnc9ead3ae2017-03-16 00:48:15433 session->spdy_session_pool()->FindAvailableSession(
Bence Békyd885b2b2018-02-03 00:58:31434 key, /* enable_ip_based_pooling = */ true,
435 /* is_websocket = */ false, log_);
wezca1070932016-05-26 20:30:52436 ASSERT_TRUE(spdy_session);
Bence Béky285e7d42017-12-04 20:22:11437 EXPECT_EQ(0u, num_active_streams(spdy_session));
438 EXPECT_EQ(0u, num_unclaimed_pushed_streams(spdy_session));
[email protected]19ec8a72010-08-23 03:38:23439 }
[email protected]e3ebba0f2010-08-05 17:59:58440
rch08e3aa3e2015-05-16 14:27:52441 void RunServerPushTest(SequencedSocketData* data,
[email protected]e3ebba0f2010-08-05 17:59:58442 HttpResponseInfo* response,
[email protected]a7a265ef2010-12-08 18:05:57443 HttpResponseInfo* push_response,
Bence Béky4e83f492018-05-13 23:14:25444 const std::string& expected) {
Bence Békydb3cf652017-10-10 15:22:10445 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
446 nullptr);
[email protected]e3ebba0f2010-08-05 17:59:58447 helper.RunPreTestSetup();
[email protected]d08358502010-12-03 22:04:03448 helper.AddData(data);
[email protected]e3ebba0f2010-08-05 17:59:58449
450 HttpNetworkTransaction* trans = helper.trans();
451
452 // Start the transaction with basic parameters.
[email protected]49639fa2011-12-20 23:22:41453 TestCompletionCallback callback;
Bence Békydb3cf652017-10-10 15:22:10454 int rv = trans->Start(&request_, callback.callback(), log_);
robpercival214763f2016-07-01 23:27:01455 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]e3ebba0f2010-08-05 17:59:58456 rv = callback.WaitForResult();
457
bnceb9aa7112017-01-05 01:03:46458 // Finish async network reads/writes.
459 base::RunLoop().RunUntilIdle();
460
[email protected]e3ebba0f2010-08-05 17:59:58461 // Request the pushed path.
bnc691fda62016-08-12 00:43:16462 HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session());
Bence Békydb3cf652017-10-10 15:22:10463 HttpRequestInfo request = CreateGetPushRequest();
464 rv = trans2.Start(&request, callback.callback(), log_);
robpercival214763f2016-07-01 23:27:01465 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]fc9d88472013-08-14 02:31:17466 base::RunLoop().RunUntilIdle();
[email protected]e3ebba0f2010-08-05 17:59:58467
[email protected]513963e2013-06-15 01:53:04468 // The data for the pushed path may be coming in more than 1 frame. Compile
[email protected]e3ebba0f2010-08-05 17:59:58469 // the results into a single string.
[email protected]19ec8a72010-08-23 03:38:23470
471 // Read the server push body.
Bence Béky4e83f492018-05-13 23:14:25472 std::string result2;
bnc691fda62016-08-12 00:43:16473 ReadResult(&trans2, &result2);
[email protected]19ec8a72010-08-23 03:38:23474 // Read the response body.
Bence Béky4e83f492018-05-13 23:14:25475 std::string result;
rch0aecfd82015-05-19 17:22:32476 ReadResult(trans, &result);
[email protected]e3ebba0f2010-08-05 17:59:58477
478 // Verify that we consumed all test data.
rch37de576c2015-05-17 20:28:17479 EXPECT_TRUE(data->AllReadDataConsumed());
480 EXPECT_TRUE(data->AllWriteDataConsumed());
[email protected]e3ebba0f2010-08-05 17:59:58481
caseqe8340bc92016-04-20 00:02:57482 LoadTimingInfo load_timing_info;
483 EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info));
484 EXPECT_TRUE(load_timing_info.push_start.is_null());
485 EXPECT_TRUE(load_timing_info.push_end.is_null());
486
487 LoadTimingInfo load_timing_info2;
bnc691fda62016-08-12 00:43:16488 EXPECT_TRUE(trans2.GetLoadTimingInfo(&load_timing_info2));
caseqe8340bc92016-04-20 00:02:57489 EXPECT_FALSE(load_timing_info2.push_start.is_null());
490 EXPECT_FALSE(load_timing_info2.push_end.is_null());
491
[email protected]e3ebba0f2010-08-05 17:59:58492 // Verify that the received push data is same as the expected push data.
[email protected]19ec8a72010-08-23 03:38:23493 EXPECT_EQ(result2.compare(expected), 0) << "Received data: "
494 << result2
495 << "||||| Expected data: "
496 << expected;
[email protected]e3ebba0f2010-08-05 17:59:58497
bnc42331402016-07-25 13:36:15498 // Verify the response HEADERS.
[email protected]e3ebba0f2010-08-05 17:59:58499 // Copy the response info, because trans goes away.
500 *response = *trans->GetResponseInfo();
bnc691fda62016-08-12 00:43:16501 *push_response = *trans2.GetResponseInfo();
[email protected]19ec8a72010-08-23 03:38:23502
503 VerifyStreamsClosed(helper);
[email protected]e3ebba0f2010-08-05 17:59:58504 }
505
morlovichab1d1c1e2017-02-07 19:59:28506 void RunBrokenPushTest(SequencedSocketData* data, int expected_rv) {
Bence Békydb3cf652017-10-10 15:22:10507 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
508 nullptr);
morlovichab1d1c1e2017-02-07 19:59:28509 helper.RunPreTestSetup();
510 helper.AddData(data);
511
512 HttpNetworkTransaction* trans = helper.trans();
513
514 // Start the transaction with basic parameters.
515 TestCompletionCallback callback;
Bence Békydb3cf652017-10-10 15:22:10516 int rv = trans->Start(&request_, callback.callback(), log_);
morlovichab1d1c1e2017-02-07 19:59:28517 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
518 rv = callback.WaitForResult();
519 EXPECT_EQ(expected_rv, rv);
520
521 // Finish async network reads/writes.
522 base::RunLoop().RunUntilIdle();
523
524 // Verify that we consumed all test data.
525 EXPECT_TRUE(data->AllReadDataConsumed());
526 EXPECT_TRUE(data->AllWriteDataConsumed());
527
528 if (expected_rv == OK) {
529 // Expected main request to succeed, even if push failed.
530 HttpResponseInfo response = *trans->GetResponseInfo();
531 EXPECT_TRUE(response.headers);
532 EXPECT_EQ("HTTP/1.1 200", response.headers->GetStatusLine());
533 }
534 }
535
[email protected]49639fa2011-12-20 23:22:41536 static void DeleteSessionCallback(NormalSpdyTransactionHelper* helper,
537 int result) {
538 helper->ResetTrans();
539 }
540
mmenkee65e7af2015-10-13 17:16:42541 static void StartTransactionCallback(HttpNetworkSession* session,
542 GURL url,
Bence Békyd3dde832017-09-19 19:02:31543 NetLogWithSource log,
mmenkee65e7af2015-10-13 17:16:42544 int result) {
krasin0bfeb6b2017-01-13 21:48:04545 HttpRequestInfo request;
bnc691fda62016-08-12 00:43:16546 HttpNetworkTransaction trans(DEFAULT_PRIORITY, session);
[email protected]49639fa2011-12-20 23:22:41547 TestCompletionCallback callback;
[email protected]49639fa2011-12-20 23:22:41548 request.method = "GET";
rchebf12982015-04-10 01:15:00549 request.url = url;
Ramin Halavatib5e433e62018-02-07 07:41:10550 request.traffic_annotation =
551 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
Bence Békyd3dde832017-09-19 19:02:31552 int rv = trans.Start(&request, callback.callback(), log);
robpercival214763f2016-07-01 23:27:01553 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]49639fa2011-12-20 23:22:41554 callback.WaitForResult();
555 }
556
Bence Békydb3cf652017-10-10 15:22:10557 ChunkedUploadDataStream* upload_chunked_data_stream() {
mmenkecbc2b712014-10-09 20:29:07558 return upload_chunked_data_stream_.get();
559 }
560
Bence Béky285e7d42017-12-04 20:22:11561 size_t num_active_streams(base::WeakPtr<SpdySession> session) {
562 return session->active_streams_.size();
563 }
564
Bence Békyfd2c1fd2017-12-15 02:32:03565 static size_t num_unclaimed_pushed_streams(
566 base::WeakPtr<SpdySession> session) {
567 return session->pool_->push_promise_index()->CountStreamsForSession(
568 session.get());
Bence Béky285e7d42017-12-04 20:22:11569 }
570
Bence Békyfd2c1fd2017-12-15 02:32:03571 static bool has_unclaimed_pushed_stream_for_url(
572 base::WeakPtr<SpdySession> session,
573 const GURL& url) {
574 return session->pool_->push_promise_index()->FindStream(
575 url, session.get()) != kNoPushedStreamFound;
Bence Béky285e7d42017-12-04 20:22:11576 }
577
Ryan Hamilton0239aac2018-05-19 00:03:13578 static spdy::SpdyStreamId spdy_stream_hi_water_mark(
Yoav Weiss9693572f2018-01-04 09:37:34579 base::WeakPtr<SpdySession> session) {
580 return session->stream_hi_water_mark_;
581 }
582
David Benjaminbae08ba2019-10-18 21:06:15583 base::RepeatingClosure FastForwardByCallback(base::TimeDelta delta) {
584 return base::BindRepeating(&SpdyNetworkTransactionTest::FastForwardBy,
585 base::Unretained(this), delta);
586 }
587
bncb26024382016-06-29 02:39:45588 const GURL default_url_;
589 const HostPortPair host_port_pair_;
Bence Békydb3cf652017-10-10 15:22:10590 HttpRequestInfo request_;
[email protected]9ec54f82013-05-10 02:53:05591 SpdyTestUtil spdy_util_;
Bence Békyd3dde832017-09-19 19:02:31592 const NetLogWithSource log_;
[email protected]9ec54f82013-05-10 02:53:05593
[email protected]d3cee19d2010-06-22 18:42:18594 private:
danakjaee3e1ec2016-04-16 00:23:18595 std::unique_ptr<ChunkedUploadDataStream> upload_chunked_data_stream_;
596 std::unique_ptr<UploadDataStream> upload_data_stream_;
[email protected]ea1a3f62012-11-16 20:34:23597 base::ScopedTempDir temp_dir_;
[email protected]aea80602009-09-18 00:55:08598};
599
[email protected]3caf5542010-07-16 15:19:47600// Verify HttpNetworkTransaction constructor.
bncd16676a2016-07-20 16:23:01601TEST_F(SpdyNetworkTransactionTest, Constructor) {
Jeremy Roman0579ed62017-08-29 15:56:19602 auto session_deps = std::make_unique<SpdySessionDependencies>();
danakjaee3e1ec2016-04-16 00:23:18603 std::unique_ptr<HttpNetworkSession> session(
[email protected]bb88e1d32013-05-03 23:11:07604 SpdySessionDependencies::SpdyCreateSession(session_deps.get()));
bncd16676a2016-07-20 16:23:01605 auto trans =
Jeremy Roman0579ed62017-08-29 15:56:19606 std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
[email protected]aea80602009-09-18 00:55:08607}
608
bncd16676a2016-07-20 16:23:01609TEST_F(SpdyNetworkTransactionTest, Get) {
[email protected]75f30cc22010-06-28 21:41:38610 // Construct the request.
Ryan Hamilton0239aac2018-05-19 00:03:13611 spdy::SpdySerializedFrame req(
612 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
bncdf80d44fd2016-07-15 20:27:41613 MockWrite writes[] = {CreateMockWrite(req, 0)};
[email protected]72552f02009-10-28 15:25:01614
Ryan Hamilton0239aac2018-05-19 00:03:13615 spdy::SpdySerializedFrame resp(
616 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
617 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]72552f02009-10-28 15:25:01618 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:41619 CreateMockRead(resp, 1), CreateMockRead(body, 2),
rch08e3aa3e2015-05-16 14:27:52620 MockRead(ASYNC, 0, 3) // EOF
[email protected]72552f02009-10-28 15:25:01621 };
622
Ryan Sleevib8d7ea02018-05-07 20:01:01623 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:10624 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]dd54bd82012-07-19 23:44:57625 helper.RunToCompletion(&data);
[email protected]3caf5542010-07-16 15:19:47626 TransactionHelperResult out = helper.output();
robpercival214763f2016-07-01 23:27:01627 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:02628 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]72552f02009-10-28 15:25:01629 EXPECT_EQ("hello!", out.response_data);
630}
631
Bence Béky2fcf4fa2018-04-06 20:06:01632TEST_F(SpdyNetworkTransactionTest, SetPriority) {
633 for (bool set_priority_before_starting_transaction : {true, false}) {
634 SpdyTestUtil spdy_test_util;
Ryan Hamilton0239aac2018-05-19 00:03:13635 spdy::SpdySerializedFrame req(
Bence Béky2fcf4fa2018-04-06 20:06:01636 spdy_test_util.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
637 MockWrite writes[] = {CreateMockWrite(req, 0)};
638
Ryan Hamilton0239aac2018-05-19 00:03:13639 spdy::SpdySerializedFrame resp(
Bence Béky2fcf4fa2018-04-06 20:06:01640 spdy_test_util.ConstructSpdyGetReply(nullptr, 0, 1));
Ryan Hamilton0239aac2018-05-19 00:03:13641 spdy::SpdySerializedFrame body(
642 spdy_test_util.ConstructSpdyDataFrame(1, true));
Bence Béky2fcf4fa2018-04-06 20:06:01643 MockRead reads[] = {CreateMockRead(resp, 1), CreateMockRead(body, 2),
644 MockRead(ASYNC, 0, 3)};
645
Ryan Sleevib8d7ea02018-05-07 20:01:01646 SequencedSocketData data(reads, writes);
Bence Béky2fcf4fa2018-04-06 20:06:01647 NormalSpdyTransactionHelper helper(request_, HIGHEST, log_, nullptr);
648 helper.RunPreTestSetup();
649 helper.AddData(&data);
650
651 if (set_priority_before_starting_transaction) {
652 helper.trans()->SetPriority(LOWEST);
653 EXPECT_TRUE(helper.StartDefaultTest());
654 } else {
655 EXPECT_TRUE(helper.StartDefaultTest());
656 helper.trans()->SetPriority(LOWEST);
657 }
658
659 helper.FinishDefaultTest();
660 helper.VerifyDataConsumed();
661
662 TransactionHelperResult out = helper.output();
663 EXPECT_THAT(out.rv, IsOk());
664 EXPECT_EQ("HTTP/1.1 200", out.status_line);
665 EXPECT_EQ("hello!", out.response_data);
666 }
667}
668
Bence Béky7a4836c2018-05-08 03:52:48669// Test that changing the request priority of an existing stream triggers
Bence Béky73b85292018-06-14 04:56:43670// sending PRIORITY frames in case there are multiple open streams and their
Bence Béky7a4836c2018-05-08 03:52:48671// relative priorities change.
Bence Béky73b85292018-06-14 04:56:43672TEST_F(SpdyNetworkTransactionTest, SetPriorityOnExistingStream) {
Bence Béky7a4836c2018-05-08 03:52:48673 const char* kUrl2 = "https://www.example.org/bar";
674
Ryan Hamilton0239aac2018-05-19 00:03:13675 spdy::SpdySerializedFrame req1(
676 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, HIGHEST));
677 spdy::SpdySerializedFrame req2(spdy_util_.ConstructSpdyGet(kUrl2, 3, MEDIUM));
678 spdy::SpdySerializedFrame priority1(
Bence Béky7a4836c2018-05-08 03:52:48679 spdy_util_.ConstructSpdyPriority(3, 0, MEDIUM, true));
Ryan Hamilton0239aac2018-05-19 00:03:13680 spdy::SpdySerializedFrame priority2(
Bence Béky7a4836c2018-05-08 03:52:48681 spdy_util_.ConstructSpdyPriority(1, 3, LOWEST, true));
682 MockWrite writes[] = {CreateMockWrite(req1, 0), CreateMockWrite(req2, 2),
683 CreateMockWrite(priority1, 4),
684 CreateMockWrite(priority2, 5)};
685
Ryan Hamilton0239aac2018-05-19 00:03:13686 spdy::SpdySerializedFrame resp1(
687 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
688 spdy::SpdySerializedFrame resp2(
689 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
690 spdy::SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true));
691 spdy::SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(3, true));
Bence Béky7a4836c2018-05-08 03:52:48692 MockRead reads[] = {CreateMockRead(resp1, 1), CreateMockRead(resp2, 3),
693 CreateMockRead(body1, 6), CreateMockRead(body2, 7),
694 MockRead(ASYNC, 0, 8)};
695
696 SequencedSocketData data(reads, writes);
697 NormalSpdyTransactionHelper helper(request_, HIGHEST, log_, nullptr);
698 helper.RunPreTestSetup();
699 helper.AddData(&data);
700 EXPECT_TRUE(helper.StartDefaultTest());
701
702 // Open HTTP/2 connection and create first stream.
703 base::RunLoop().RunUntilIdle();
704
705 HttpNetworkTransaction trans2(MEDIUM, helper.session());
706 HttpRequestInfo request2;
707 request2.url = GURL(kUrl2);
708 request2.method = "GET";
709 request2.traffic_annotation =
710 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
711 TestCompletionCallback callback2;
712 int rv = trans2.Start(&request2, callback2.callback(), log_);
713 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
714
715 // Create second stream.
716 base::RunLoop().RunUntilIdle();
717
718 // First request has HIGHEST priority, second request has MEDIUM priority.
719 // Changing the priority of the first request to LOWEST changes their order,
720 // and therefore triggers sending PRIORITY frames.
721 helper.trans()->SetPriority(LOWEST);
722
723 helper.FinishDefaultTest();
724 helper.VerifyDataConsumed();
725
726 TransactionHelperResult out = helper.output();
727 EXPECT_THAT(out.rv, IsOk());
728 EXPECT_EQ("HTTP/1.1 200", out.status_line);
729 EXPECT_EQ("hello!", out.response_data);
730
731 rv = callback2.WaitForResult();
732 ASSERT_THAT(rv, IsOk());
733 const HttpResponseInfo* response2 = trans2.GetResponseInfo();
734 ASSERT_TRUE(response2);
735 ASSERT_TRUE(response2->headers);
736 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP2,
737 response2->connection_info);
738 EXPECT_EQ("HTTP/1.1 200", response2->headers->GetStatusLine());
739}
740
Bence Béky73b85292018-06-14 04:56:43741// Create two requests: a lower priority one first, then a higher priority one.
742// Test that the second request gets sent out first.
743TEST_F(SpdyNetworkTransactionTest, RequestsOrderedByPriority) {
744 const char* kUrl2 = "https://www.example.org/foo";
745
746 // First send second request on stream 1, then first request on stream 3.
747 spdy::SpdySerializedFrame req2(
748 spdy_util_.ConstructSpdyGet(kUrl2, 1, HIGHEST));
749 spdy::SpdySerializedFrame req1(
750 spdy_util_.ConstructSpdyGet(nullptr, 0, 3, LOW));
751 MockWrite writes[] = {CreateMockWrite(req2, 0), CreateMockWrite(req1, 1)};
752
753 spdy::SpdySerializedFrame resp2(
754 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
755 spdy::SpdySerializedFrame resp1(
756 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
757 spdy::SpdySerializedFrame body2(
758 spdy_util_.ConstructSpdyDataFrame(1, "stream 1", true));
759 spdy::SpdySerializedFrame body1(
760 spdy_util_.ConstructSpdyDataFrame(3, "stream 3", true));
761 MockRead reads[] = {CreateMockRead(resp2, 2), CreateMockRead(body2, 3),
762 CreateMockRead(resp1, 4), CreateMockRead(body1, 5),
763 MockRead(ASYNC, 0, 6)};
764
765 SequencedSocketData data(reads, writes);
766 NormalSpdyTransactionHelper helper(request_, LOW, log_, nullptr);
767 helper.RunPreTestSetup();
768 helper.AddData(&data);
769
770 // Create HTTP/2 connection. This is necessary because starting the first
771 // transaction does not create the connection yet, so the second request
772 // could not use the same connection, whereas running the message loop after
773 // starting the first transaction would call Socket::Write() with the first
774 // HEADERS frame, so the second transaction could not get ahead of it.
775 SpdySessionKey key(HostPortPair("www.example.org", 443),
Matt Menke2436b2f2018-12-11 18:07:11776 ProxyServer::Direct(), PRIVACY_MODE_DISABLED,
dalyk51ab46b2019-10-15 15:14:34777 SpdySessionKey::IsProxySession::kFalse, SocketTag(),
Ben Schwartz3ff4dc1e62021-04-27 21:15:23778 NetworkIsolationKey(), SecureDnsPolicy::kAllow);
Bence Béky73b85292018-06-14 04:56:43779 auto spdy_session = CreateSpdySession(helper.session(), key, log_);
780 EXPECT_TRUE(spdy_session);
781
782 // Start first transaction.
783 EXPECT_TRUE(helper.StartDefaultTest());
784
785 // Start second transaction.
786 HttpNetworkTransaction trans2(HIGHEST, helper.session());
787 HttpRequestInfo request2;
788 request2.url = GURL(kUrl2);
789 request2.method = "GET";
790 request2.traffic_annotation =
791 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
792 TestCompletionCallback callback2;
793 int rv = trans2.Start(&request2, callback2.callback(), log_);
794 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
795
796 // Complete first transaction and verify results.
797 helper.FinishDefaultTest();
798 helper.VerifyDataConsumed();
799
800 TransactionHelperResult out = helper.output();
801 EXPECT_THAT(out.rv, IsOk());
802 EXPECT_EQ("HTTP/1.1 200", out.status_line);
803 EXPECT_EQ("stream 3", out.response_data);
804
805 // Complete second transaction and verify results.
806 rv = callback2.WaitForResult();
807 ASSERT_THAT(rv, IsOk());
808 const HttpResponseInfo* response2 = trans2.GetResponseInfo();
809 ASSERT_TRUE(response2);
810 ASSERT_TRUE(response2->headers);
811 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP2,
812 response2->connection_info);
813 EXPECT_EQ("HTTP/1.1 200", response2->headers->GetStatusLine());
814 std::string response_data;
815 ReadTransaction(&trans2, &response_data);
816 EXPECT_EQ("stream 1", response_data);
817}
818
819// Test that already enqueued HEADERS frames are reordered if their relative
820// priority changes.
821TEST_F(SpdyNetworkTransactionTest, QueuedFramesReorderedOnPriorityChange) {
822 const char* kUrl2 = "https://www.example.org/foo";
823 const char* kUrl3 = "https://www.example.org/bar";
824
825 spdy::SpdySerializedFrame req1(
826 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, DEFAULT_PRIORITY));
827 spdy::SpdySerializedFrame req3(spdy_util_.ConstructSpdyGet(kUrl3, 3, MEDIUM));
828 spdy::SpdySerializedFrame req2(spdy_util_.ConstructSpdyGet(kUrl2, 5, LOWEST));
829 MockWrite writes[] = {MockWrite(ASYNC, ERR_IO_PENDING, 0),
830 CreateMockWrite(req1, 1), CreateMockWrite(req3, 2),
831 CreateMockWrite(req2, 3)};
832
833 spdy::SpdySerializedFrame resp1(
834 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
835 spdy::SpdySerializedFrame resp3(
836 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
837 spdy::SpdySerializedFrame resp2(
838 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 5));
839 spdy::SpdySerializedFrame body1(
840 spdy_util_.ConstructSpdyDataFrame(1, "stream 1", true));
841 spdy::SpdySerializedFrame body3(
842 spdy_util_.ConstructSpdyDataFrame(3, "stream 3", true));
843 spdy::SpdySerializedFrame body2(
844 spdy_util_.ConstructSpdyDataFrame(5, "stream 5", true));
845 MockRead reads[] = {CreateMockRead(resp1, 4), CreateMockRead(body1, 5),
846 CreateMockRead(resp3, 6), CreateMockRead(body3, 7),
847 CreateMockRead(resp2, 8), CreateMockRead(body2, 9),
848 MockRead(ASYNC, 0, 10)};
849
850 SequencedSocketData data(reads, writes);
851 // Priority of first request does not matter, because Socket::Write() will be
852 // called with its HEADERS frame before the other requests start.
853 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
854 helper.RunPreTestSetup();
855 helper.AddData(&data);
856 EXPECT_TRUE(helper.StartDefaultTest());
857
858 // Open HTTP/2 connection, create HEADERS frame for first request, and call
859 // Socket::Write() with that frame. After this, no other request can get
860 // ahead of the first one.
861 base::RunLoop().RunUntilIdle();
862
863 HttpNetworkTransaction trans2(HIGHEST, helper.session());
864 HttpRequestInfo request2;
865 request2.url = GURL(kUrl2);
866 request2.method = "GET";
867 request2.traffic_annotation =
868 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
869 TestCompletionCallback callback2;
870 int rv = trans2.Start(&request2, callback2.callback(), log_);
871 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
872
873 HttpNetworkTransaction trans3(MEDIUM, helper.session());
874 HttpRequestInfo request3;
875 request3.url = GURL(kUrl3);
876 request3.method = "GET";
877 request3.traffic_annotation =
878 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
879 TestCompletionCallback callback3;
880 rv = trans3.Start(&request3, callback3.callback(), log_);
881 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
882
883 // Create HEADERS frames for second and third request and enqueue them in
884 // SpdyWriteQueue with their original priorities. Writing of the first
885 // HEADERS frame to the socked still has not completed.
886 base::RunLoop().RunUntilIdle();
887
888 // Second request is of HIGHEST, third of MEDIUM priority. Changing second
889 // request to LOWEST changes their relative order. This should result in
890 // already enqueued frames being reordered within SpdyWriteQueue.
891 trans2.SetPriority(LOWEST);
892
893 // Complete async write of the first HEADERS frame.
894 data.Resume();
895
896 helper.FinishDefaultTest();
897 TransactionHelperResult out = helper.output();
898 EXPECT_THAT(out.rv, IsOk());
899 EXPECT_EQ("HTTP/1.1 200", out.status_line);
900 EXPECT_EQ("stream 1", out.response_data);
901
902 rv = callback2.WaitForResult();
903 ASSERT_THAT(rv, IsOk());
904 const HttpResponseInfo* response2 = trans2.GetResponseInfo();
905 ASSERT_TRUE(response2);
906 ASSERT_TRUE(response2->headers);
907 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP2,
908 response2->connection_info);
909 EXPECT_EQ("HTTP/1.1 200", response2->headers->GetStatusLine());
910 std::string response_data;
911 ReadTransaction(&trans2, &response_data);
912 EXPECT_EQ("stream 5", response_data);
913
914 rv = callback3.WaitForResult();
915 ASSERT_THAT(rv, IsOk());
916 const HttpResponseInfo* response3 = trans3.GetResponseInfo();
917 ASSERT_TRUE(response3);
918 ASSERT_TRUE(response3->headers);
919 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP2,
920 response3->connection_info);
921 EXPECT_EQ("HTTP/1.1 200", response3->headers->GetStatusLine());
922 ReadTransaction(&trans3, &response_data);
923 EXPECT_EQ("stream 3", response_data);
924
925 helper.VerifyDataConsumed();
926}
927
bncd16676a2016-07-20 16:23:01928TEST_F(SpdyNetworkTransactionTest, GetAtEachPriority) {
[email protected]3d08dd382013-10-19 00:13:11929 for (RequestPriority p = MINIMUM_PRIORITY; p <= MAXIMUM_PRIORITY;
[email protected]31ae7ab2012-04-24 21:09:05930 p = RequestPriority(p + 1)) {
bncd16676a2016-07-20 16:23:01931 SpdyTestUtil spdy_test_util;
bnc38dcd392016-02-09 23:19:49932
[email protected]c9c6f5c2010-07-31 01:30:03933 // Construct the request.
Ryan Hamilton0239aac2018-05-19 00:03:13934 spdy::SpdySerializedFrame req(
935 spdy_test_util.ConstructSpdyGet(nullptr, 0, 1, p));
bncdf80d44fd2016-07-15 20:27:41936 MockWrite writes[] = {CreateMockWrite(req, 0)};
[email protected]c9c6f5c2010-07-31 01:30:03937
Ryan Hamilton0239aac2018-05-19 00:03:13938 spdy::SpdyPriority spdy_prio = 0;
bncdf80d44fd2016-07-15 20:27:41939 EXPECT_TRUE(GetSpdyPriority(req, &spdy_prio));
Ryan Hamilton0239aac2018-05-19 00:03:13940 // this repeats the RequestPriority-->spdy::SpdyPriority mapping from
941 // spdy::SpdyFramer::ConvertRequestPriorityToSpdyPriority to make
[email protected]c9c6f5c2010-07-31 01:30:03942 // sure it's being done right.
bnc05808ff42016-01-08 23:48:25943 switch (p) {
944 case HIGHEST:
945 EXPECT_EQ(0, spdy_prio);
946 break;
947 case MEDIUM:
948 EXPECT_EQ(1, spdy_prio);
949 break;
950 case LOW:
951 EXPECT_EQ(2, spdy_prio);
952 break;
953 case LOWEST:
954 EXPECT_EQ(3, spdy_prio);
955 break;
956 case IDLE:
957 EXPECT_EQ(4, spdy_prio);
958 break;
rdsmith5eb6fbc2016-10-21 17:36:08959 case THROTTLED:
960 EXPECT_EQ(5, spdy_prio);
961 break;
bnc05808ff42016-01-08 23:48:25962 default:
963 FAIL();
[email protected]c9c6f5c2010-07-31 01:30:03964 }
965
Ryan Hamilton0239aac2018-05-19 00:03:13966 spdy::SpdySerializedFrame resp(
bnc42331402016-07-25 13:36:15967 spdy_test_util.ConstructSpdyGetReply(nullptr, 0, 1));
Ryan Hamilton0239aac2018-05-19 00:03:13968 spdy::SpdySerializedFrame body(
969 spdy_test_util.ConstructSpdyDataFrame(1, true));
[email protected]c9c6f5c2010-07-31 01:30:03970 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:41971 CreateMockRead(resp, 1), CreateMockRead(body, 2),
rch08e3aa3e2015-05-16 14:27:52972 MockRead(ASYNC, 0, 3) // EOF
[email protected]c9c6f5c2010-07-31 01:30:03973 };
974
Ryan Sleevib8d7ea02018-05-07 20:01:01975 SequencedSocketData data(reads, writes);
[email protected]c9c6f5c2010-07-31 01:30:03976
Bence Békydb3cf652017-10-10 15:22:10977 NormalSpdyTransactionHelper helper(request_, p, log_, nullptr);
[email protected]dd54bd82012-07-19 23:44:57978 helper.RunToCompletion(&data);
[email protected]c9c6f5c2010-07-31 01:30:03979 TransactionHelperResult out = helper.output();
robpercival214763f2016-07-01 23:27:01980 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:02981 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]c9c6f5c2010-07-31 01:30:03982 EXPECT_EQ("hello!", out.response_data);
983 }
984}
985
[email protected]2bd93022010-07-17 00:58:44986// Start three gets simultaniously; making sure that multiplexed
987// streams work properly.
988
989// This can't use the TransactionHelper method, since it only
990// handles a single transaction, and finishes them as soon
991// as it launches them.
992
993// TODO(gavinp): create a working generalized TransactionHelper that
994// can allow multiple streams in flight.
995
bncd16676a2016-07-20 16:23:01996TEST_F(SpdyNetworkTransactionTest, ThreeGets) {
Ryan Hamilton0239aac2018-05-19 00:03:13997 spdy::SpdySerializedFrame req(
998 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
999 spdy::SpdySerializedFrame resp(
1000 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
1001 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, false));
1002 spdy::SpdySerializedFrame fbody(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]2bd93022010-07-17 00:58:441003
Ryan Hamilton0239aac2018-05-19 00:03:131004 spdy::SpdySerializedFrame req2(
1005 spdy_util_.ConstructSpdyGet(nullptr, 0, 3, LOWEST));
1006 spdy::SpdySerializedFrame resp2(
1007 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
1008 spdy::SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(3, false));
1009 spdy::SpdySerializedFrame fbody2(spdy_util_.ConstructSpdyDataFrame(3, true));
[email protected]2bd93022010-07-17 00:58:441010
Ryan Hamilton0239aac2018-05-19 00:03:131011 spdy::SpdySerializedFrame req3(
1012 spdy_util_.ConstructSpdyGet(nullptr, 0, 5, LOWEST));
1013 spdy::SpdySerializedFrame resp3(
1014 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 5));
1015 spdy::SpdySerializedFrame body3(spdy_util_.ConstructSpdyDataFrame(5, false));
1016 spdy::SpdySerializedFrame fbody3(spdy_util_.ConstructSpdyDataFrame(5, true));
[email protected]2bd93022010-07-17 00:58:441017
[email protected]1b323172011-03-01 17:50:171018 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:411019 CreateMockWrite(req, 0), CreateMockWrite(req2, 3),
1020 CreateMockWrite(req3, 6),
[email protected]2bd93022010-07-17 00:58:441021 };
1022 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:411023 CreateMockRead(resp, 1), CreateMockRead(body, 2),
1024 CreateMockRead(resp2, 4), CreateMockRead(body2, 5),
1025 CreateMockRead(resp3, 7), CreateMockRead(body3, 8),
[email protected]2bd93022010-07-17 00:58:441026
bncdf80d44fd2016-07-15 20:27:411027 CreateMockRead(fbody, 9), CreateMockRead(fbody2, 10),
1028 CreateMockRead(fbody3, 11),
[email protected]2bd93022010-07-17 00:58:441029
rch08e3aa3e2015-05-16 14:27:521030 MockRead(ASYNC, 0, 12), // EOF
[email protected]2bd93022010-07-17 00:58:441031 };
Ryan Sleevib8d7ea02018-05-07 20:01:011032 SequencedSocketData data(reads, writes);
1033 SequencedSocketData data_placeholder1;
1034 SequencedSocketData data_placeholder2;
[email protected]2bd93022010-07-17 00:58:441035
[email protected]2bd93022010-07-17 00:58:441036 TransactionHelperResult out;
Bence Békydb3cf652017-10-10 15:22:101037 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]bdebd1b2010-08-09 20:18:081038 helper.RunPreTestSetup();
[email protected]dd54bd82012-07-19 23:44:571039 helper.AddData(&data);
rchaeb3f052015-04-14 16:02:491040 // We require placeholder data because three get requests are sent out at
1041 // the same time which results in three sockets being connected. The first
1042 // on will negotiate SPDY and will be used for all requests.
mmenkecc2298e2015-12-07 18:20:181043 helper.AddData(&data_placeholder1);
1044 helper.AddData(&data_placeholder2);
[email protected]49639fa2011-12-20 23:22:411045 TestCompletionCallback callback1;
1046 TestCompletionCallback callback2;
1047 TestCompletionCallback callback3;
[email protected]2bd93022010-07-17 00:58:441048
krasin0bfeb6b2017-01-13 21:48:041049 HttpNetworkTransaction trans1(DEFAULT_PRIORITY, helper.session());
1050 HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session());
1051 HttpNetworkTransaction trans3(DEFAULT_PRIORITY, helper.session());
1052
Bence Békydb3cf652017-10-10 15:22:101053 out.rv = trans1.Start(&request_, callback1.callback(), log_);
robpercival214763f2016-07-01 23:27:011054 ASSERT_THAT(out.rv, IsError(ERR_IO_PENDING));
Bence Békydb3cf652017-10-10 15:22:101055 out.rv = trans2.Start(&request_, callback2.callback(), log_);
robpercival214763f2016-07-01 23:27:011056 ASSERT_THAT(out.rv, IsError(ERR_IO_PENDING));
Bence Békydb3cf652017-10-10 15:22:101057 out.rv = trans3.Start(&request_, callback3.callback(), log_);
robpercival214763f2016-07-01 23:27:011058 ASSERT_THAT(out.rv, IsError(ERR_IO_PENDING));
[email protected]2bd93022010-07-17 00:58:441059
[email protected]bdebd1b2010-08-09 20:18:081060 out.rv = callback1.WaitForResult();
robpercival214763f2016-07-01 23:27:011061 ASSERT_THAT(out.rv, IsOk());
[email protected]bdebd1b2010-08-09 20:18:081062 out.rv = callback3.WaitForResult();
robpercival214763f2016-07-01 23:27:011063 ASSERT_THAT(out.rv, IsOk());
[email protected]2bd93022010-07-17 00:58:441064
bnc691fda62016-08-12 00:43:161065 const HttpResponseInfo* response1 = trans1.GetResponseInfo();
wezca1070932016-05-26 20:30:521066 EXPECT_TRUE(response1->headers);
[email protected]bdebd1b2010-08-09 20:18:081067 EXPECT_TRUE(response1->was_fetched_via_spdy);
1068 out.status_line = response1->headers->GetStatusLine();
1069 out.response_info = *response1;
[email protected]2bd93022010-07-17 00:58:441070
bnc691fda62016-08-12 00:43:161071 trans2.GetResponseInfo();
[email protected]2bd93022010-07-17 00:58:441072
bnc691fda62016-08-12 00:43:161073 out.rv = ReadTransaction(&trans1, &out.response_data);
[email protected]bdebd1b2010-08-09 20:18:081074 helper.VerifyDataConsumed();
robpercival214763f2016-07-01 23:27:011075 EXPECT_THAT(out.rv, IsOk());
[email protected]2bd93022010-07-17 00:58:441076
robpercival214763f2016-07-01 23:27:011077 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:021078 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]2bd93022010-07-17 00:58:441079 EXPECT_EQ("hello!hello!", out.response_data);
1080}
1081
bncd16676a2016-07-20 16:23:011082TEST_F(SpdyNetworkTransactionTest, TwoGetsLateBinding) {
Ryan Hamilton0239aac2018-05-19 00:03:131083 spdy::SpdySerializedFrame req(
1084 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
1085 spdy::SpdySerializedFrame resp(
1086 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
1087 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, false));
1088 spdy::SpdySerializedFrame fbody(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]1b323172011-03-01 17:50:171089
Ryan Hamilton0239aac2018-05-19 00:03:131090 spdy::SpdySerializedFrame req2(
1091 spdy_util_.ConstructSpdyGet(nullptr, 0, 3, LOWEST));
1092 spdy::SpdySerializedFrame resp2(
1093 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
1094 spdy::SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(3, false));
1095 spdy::SpdySerializedFrame fbody2(spdy_util_.ConstructSpdyDataFrame(3, true));
[email protected]1b323172011-03-01 17:50:171096
1097 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:411098 CreateMockWrite(req, 0), CreateMockWrite(req2, 3),
[email protected]1b323172011-03-01 17:50:171099 };
1100 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:411101 CreateMockRead(resp, 1), CreateMockRead(body, 2),
1102 CreateMockRead(resp2, 4), CreateMockRead(body2, 5),
1103 CreateMockRead(fbody, 6), CreateMockRead(fbody2, 7),
rch08e3aa3e2015-05-16 14:27:521104 MockRead(ASYNC, 0, 8), // EOF
[email protected]1b323172011-03-01 17:50:171105 };
Ryan Sleevib8d7ea02018-05-07 20:01:011106 SequencedSocketData data(reads, writes);
[email protected]1b323172011-03-01 17:50:171107
[email protected]d973e99a2012-02-17 21:02:361108 MockConnect never_finishing_connect(SYNCHRONOUS, ERR_IO_PENDING);
Ryan Sleevib8d7ea02018-05-07 20:01:011109 SequencedSocketData data_placeholder;
[email protected]dd54bd82012-07-19 23:44:571110 data_placeholder.set_connect_data(never_finishing_connect);
[email protected]1b323172011-03-01 17:50:171111
[email protected]1b323172011-03-01 17:50:171112 TransactionHelperResult out;
Bence Békydb3cf652017-10-10 15:22:101113 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]1b323172011-03-01 17:50:171114 helper.RunPreTestSetup();
[email protected]dd54bd82012-07-19 23:44:571115 helper.AddData(&data);
rchaeb3f052015-04-14 16:02:491116 // We require placeholder data because two requests are sent out at
1117 // the same time which results in two sockets being connected. The first
1118 // on will negotiate SPDY and will be used for all requests.
[email protected]dd54bd82012-07-19 23:44:571119 helper.AddData(&data_placeholder);
bnc691fda62016-08-12 00:43:161120 HttpNetworkTransaction trans1(DEFAULT_PRIORITY, helper.session());
1121 HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session());
[email protected]1b323172011-03-01 17:50:171122
[email protected]49639fa2011-12-20 23:22:411123 TestCompletionCallback callback1;
1124 TestCompletionCallback callback2;
[email protected]1b323172011-03-01 17:50:171125
Bence Békydb3cf652017-10-10 15:22:101126 out.rv = trans1.Start(&request_, callback1.callback(), log_);
robpercival214763f2016-07-01 23:27:011127 ASSERT_THAT(out.rv, IsError(ERR_IO_PENDING));
Bence Békydb3cf652017-10-10 15:22:101128 out.rv = trans2.Start(&request_, callback2.callback(), log_);
robpercival214763f2016-07-01 23:27:011129 ASSERT_THAT(out.rv, IsError(ERR_IO_PENDING));
[email protected]1b323172011-03-01 17:50:171130
1131 out.rv = callback1.WaitForResult();
robpercival214763f2016-07-01 23:27:011132 ASSERT_THAT(out.rv, IsOk());
[email protected]1b323172011-03-01 17:50:171133 out.rv = callback2.WaitForResult();
robpercival214763f2016-07-01 23:27:011134 ASSERT_THAT(out.rv, IsOk());
[email protected]1b323172011-03-01 17:50:171135
bnc691fda62016-08-12 00:43:161136 const HttpResponseInfo* response1 = trans1.GetResponseInfo();
wezca1070932016-05-26 20:30:521137 EXPECT_TRUE(response1->headers);
[email protected]1b323172011-03-01 17:50:171138 EXPECT_TRUE(response1->was_fetched_via_spdy);
1139 out.status_line = response1->headers->GetStatusLine();
1140 out.response_info = *response1;
bnc691fda62016-08-12 00:43:161141 out.rv = ReadTransaction(&trans1, &out.response_data);
robpercival214763f2016-07-01 23:27:011142 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:021143 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]1b323172011-03-01 17:50:171144 EXPECT_EQ("hello!hello!", out.response_data);
1145
bnc691fda62016-08-12 00:43:161146 const HttpResponseInfo* response2 = trans2.GetResponseInfo();
wezca1070932016-05-26 20:30:521147 EXPECT_TRUE(response2->headers);
[email protected]1b323172011-03-01 17:50:171148 EXPECT_TRUE(response2->was_fetched_via_spdy);
1149 out.status_line = response2->headers->GetStatusLine();
1150 out.response_info = *response2;
bnc691fda62016-08-12 00:43:161151 out.rv = ReadTransaction(&trans2, &out.response_data);
robpercival214763f2016-07-01 23:27:011152 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:021153 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]1b323172011-03-01 17:50:171154 EXPECT_EQ("hello!hello!", out.response_data);
1155
1156 helper.VerifyDataConsumed();
1157}
1158
bncd16676a2016-07-20 16:23:011159TEST_F(SpdyNetworkTransactionTest, TwoGetsLateBindingFromPreconnect) {
Ryan Hamilton0239aac2018-05-19 00:03:131160 spdy::SpdySerializedFrame req(
1161 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
1162 spdy::SpdySerializedFrame resp(
1163 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
1164 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, false));
1165 spdy::SpdySerializedFrame fbody(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]1b323172011-03-01 17:50:171166
Ryan Hamilton0239aac2018-05-19 00:03:131167 spdy::SpdySerializedFrame req2(
1168 spdy_util_.ConstructSpdyGet(nullptr, 0, 3, LOWEST));
1169 spdy::SpdySerializedFrame resp2(
1170 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
1171 spdy::SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(3, false));
1172 spdy::SpdySerializedFrame fbody2(spdy_util_.ConstructSpdyDataFrame(3, true));
[email protected]1b323172011-03-01 17:50:171173
1174 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:411175 CreateMockWrite(req, 0), CreateMockWrite(req2, 3),
[email protected]1b323172011-03-01 17:50:171176 };
1177 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:411178 CreateMockRead(resp, 1), CreateMockRead(body, 2),
1179 CreateMockRead(resp2, 4), CreateMockRead(body2, 5),
1180 CreateMockRead(fbody, 6), CreateMockRead(fbody2, 7),
rch08e3aa3e2015-05-16 14:27:521181 MockRead(ASYNC, 0, 8), // EOF
[email protected]1b323172011-03-01 17:50:171182 };
Ryan Sleevib8d7ea02018-05-07 20:01:011183 SequencedSocketData preconnect_data(reads, writes);
[email protected]1b323172011-03-01 17:50:171184
[email protected]d973e99a2012-02-17 21:02:361185 MockConnect never_finishing_connect(ASYNC, ERR_IO_PENDING);
[email protected]1b323172011-03-01 17:50:171186
Ryan Sleevib8d7ea02018-05-07 20:01:011187 SequencedSocketData data_placeholder;
[email protected]dd54bd82012-07-19 23:44:571188 data_placeholder.set_connect_data(never_finishing_connect);
[email protected]1b323172011-03-01 17:50:171189
[email protected]1b323172011-03-01 17:50:171190 TransactionHelperResult out;
Bence Békydb3cf652017-10-10 15:22:101191 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]1b323172011-03-01 17:50:171192 helper.RunPreTestSetup();
[email protected]dd54bd82012-07-19 23:44:571193 helper.AddData(&preconnect_data);
[email protected]1b323172011-03-01 17:50:171194 // We require placeholder data because 3 connections are attempted (first is
1195 // the preconnect, 2nd and 3rd are the never finished connections.
[email protected]dd54bd82012-07-19 23:44:571196 helper.AddData(&data_placeholder);
1197 helper.AddData(&data_placeholder);
[email protected]1b323172011-03-01 17:50:171198
bnc691fda62016-08-12 00:43:161199 HttpNetworkTransaction trans1(DEFAULT_PRIORITY, helper.session());
1200 HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session());
[email protected]1b323172011-03-01 17:50:171201
[email protected]49639fa2011-12-20 23:22:411202 TestCompletionCallback callback1;
1203 TestCompletionCallback callback2;
[email protected]1b323172011-03-01 17:50:171204
[email protected]1b323172011-03-01 17:50:171205 // Preconnect the first.
[email protected]1b323172011-03-01 17:50:171206 HttpStreamFactory* http_stream_factory =
1207 helper.session()->http_stream_factory();
[email protected]1b323172011-03-01 17:50:171208
Bence Békydb3cf652017-10-10 15:22:101209 http_stream_factory->PreconnectStreams(1, request_);
[email protected]1b323172011-03-01 17:50:171210
Bence Békydb3cf652017-10-10 15:22:101211 out.rv = trans1.Start(&request_, callback1.callback(), log_);
robpercival214763f2016-07-01 23:27:011212 ASSERT_THAT(out.rv, IsError(ERR_IO_PENDING));
Bence Békydb3cf652017-10-10 15:22:101213 out.rv = trans2.Start(&request_, callback2.callback(), log_);
robpercival214763f2016-07-01 23:27:011214 ASSERT_THAT(out.rv, IsError(ERR_IO_PENDING));
[email protected]1b323172011-03-01 17:50:171215
1216 out.rv = callback1.WaitForResult();
robpercival214763f2016-07-01 23:27:011217 ASSERT_THAT(out.rv, IsOk());
[email protected]1b323172011-03-01 17:50:171218 out.rv = callback2.WaitForResult();
robpercival214763f2016-07-01 23:27:011219 ASSERT_THAT(out.rv, IsOk());
[email protected]1b323172011-03-01 17:50:171220
bnc691fda62016-08-12 00:43:161221 const HttpResponseInfo* response1 = trans1.GetResponseInfo();
wezca1070932016-05-26 20:30:521222 EXPECT_TRUE(response1->headers);
[email protected]1b323172011-03-01 17:50:171223 EXPECT_TRUE(response1->was_fetched_via_spdy);
1224 out.status_line = response1->headers->GetStatusLine();
1225 out.response_info = *response1;
bnc691fda62016-08-12 00:43:161226 out.rv = ReadTransaction(&trans1, &out.response_data);
robpercival214763f2016-07-01 23:27:011227 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:021228 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]1b323172011-03-01 17:50:171229 EXPECT_EQ("hello!hello!", out.response_data);
1230
bnc691fda62016-08-12 00:43:161231 const HttpResponseInfo* response2 = trans2.GetResponseInfo();
wezca1070932016-05-26 20:30:521232 EXPECT_TRUE(response2->headers);
[email protected]1b323172011-03-01 17:50:171233 EXPECT_TRUE(response2->was_fetched_via_spdy);
1234 out.status_line = response2->headers->GetStatusLine();
1235 out.response_info = *response2;
bnc691fda62016-08-12 00:43:161236 out.rv = ReadTransaction(&trans2, &out.response_data);
robpercival214763f2016-07-01 23:27:011237 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:021238 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]1b323172011-03-01 17:50:171239 EXPECT_EQ("hello!hello!", out.response_data);
1240
1241 helper.VerifyDataConsumed();
1242}
1243
[email protected]2bd93022010-07-17 00:58:441244// Similar to ThreeGets above, however this test adds a SETTINGS
1245// frame. The SETTINGS frame is read during the IO loop waiting on
1246// the first transaction completion, and sets a maximum concurrent
1247// stream limit of 1. This means that our IO loop exists after the
1248// second transaction completes, so we can assert on read_index().
bncd16676a2016-07-20 16:23:011249TEST_F(SpdyNetworkTransactionTest, ThreeGetsWithMaxConcurrent) {
[email protected]2bd93022010-07-17 00:58:441250 // Construct the request.
rdsmithebb50aa2015-11-12 03:44:381251 // Each request fully completes before the next starts.
Ryan Hamilton0239aac2018-05-19 00:03:131252 spdy::SpdySerializedFrame req(
1253 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
1254 spdy::SpdySerializedFrame resp(
1255 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
1256 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, false));
1257 spdy::SpdySerializedFrame fbody(spdy_util_.ConstructSpdyDataFrame(1, true));
rdsmithebb50aa2015-11-12 03:44:381258 spdy_util_.UpdateWithStreamDestruction(1);
[email protected]2bd93022010-07-17 00:58:441259
Ryan Hamilton0239aac2018-05-19 00:03:131260 spdy::SpdySerializedFrame req2(
1261 spdy_util_.ConstructSpdyGet(nullptr, 0, 3, LOWEST));
1262 spdy::SpdySerializedFrame resp2(
1263 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
1264 spdy::SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(3, false));
1265 spdy::SpdySerializedFrame fbody2(spdy_util_.ConstructSpdyDataFrame(3, true));
rdsmithebb50aa2015-11-12 03:44:381266 spdy_util_.UpdateWithStreamDestruction(3);
[email protected]2bd93022010-07-17 00:58:441267
Ryan Hamilton0239aac2018-05-19 00:03:131268 spdy::SpdySerializedFrame req3(
1269 spdy_util_.ConstructSpdyGet(nullptr, 0, 5, LOWEST));
1270 spdy::SpdySerializedFrame resp3(
1271 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 5));
1272 spdy::SpdySerializedFrame body3(spdy_util_.ConstructSpdyDataFrame(5, false));
1273 spdy::SpdySerializedFrame fbody3(spdy_util_.ConstructSpdyDataFrame(5, true));
[email protected]2bd93022010-07-17 00:58:441274
Ryan Hamilton0239aac2018-05-19 00:03:131275 spdy::SettingsMap settings;
Avi Drissman13fc8932015-12-20 04:40:461276 const uint32_t max_concurrent_streams = 1;
Ryan Hamilton0239aac2018-05-19 00:03:131277 settings[spdy::SETTINGS_MAX_CONCURRENT_STREAMS] = max_concurrent_streams;
1278 spdy::SpdySerializedFrame settings_frame(
[email protected]c10b20852013-05-15 21:29:201279 spdy_util_.ConstructSpdySettings(settings));
Ryan Hamilton0239aac2018-05-19 00:03:131280 spdy::SpdySerializedFrame settings_ack(spdy_util_.ConstructSpdySettingsAck());
[email protected]2bd93022010-07-17 00:58:441281
[email protected]2d6728692011-03-12 01:39:551282 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:411283 CreateMockWrite(req, 0), CreateMockWrite(settings_ack, 5),
1284 CreateMockWrite(req2, 6), CreateMockWrite(req3, 10),
[email protected]2bd93022010-07-17 00:58:441285 };
[email protected]2d6728692011-03-12 01:39:551286
[email protected]2bd93022010-07-17 00:58:441287 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:411288 CreateMockRead(settings_frame, 1),
1289 CreateMockRead(resp, 2),
1290 CreateMockRead(body, 3),
1291 CreateMockRead(fbody, 4),
1292 CreateMockRead(resp2, 7),
1293 CreateMockRead(body2, 8),
1294 CreateMockRead(fbody2, 9),
1295 CreateMockRead(resp3, 11),
1296 CreateMockRead(body3, 12),
1297 CreateMockRead(fbody3, 13),
[email protected]2bd93022010-07-17 00:58:441298
rch08e3aa3e2015-05-16 14:27:521299 MockRead(ASYNC, 0, 14), // EOF
[email protected]2bd93022010-07-17 00:58:441300 };
1301
Ryan Sleevib8d7ea02018-05-07 20:01:011302 SequencedSocketData data(reads, writes);
[email protected]2bd93022010-07-17 00:58:441303
[email protected]2bd93022010-07-17 00:58:441304 TransactionHelperResult out;
1305 {
Bence Békydb3cf652017-10-10 15:22:101306 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
1307 nullptr);
[email protected]2d6728692011-03-12 01:39:551308 helper.RunPreTestSetup();
[email protected]dd54bd82012-07-19 23:44:571309 helper.AddData(&data);
bnc691fda62016-08-12 00:43:161310 HttpNetworkTransaction trans1(DEFAULT_PRIORITY, helper.session());
1311 HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session());
1312 HttpNetworkTransaction trans3(DEFAULT_PRIORITY, helper.session());
[email protected]2bd93022010-07-17 00:58:441313
[email protected]49639fa2011-12-20 23:22:411314 TestCompletionCallback callback1;
1315 TestCompletionCallback callback2;
1316 TestCompletionCallback callback3;
[email protected]2bd93022010-07-17 00:58:441317
Bence Békydb3cf652017-10-10 15:22:101318 out.rv = trans1.Start(&request_, callback1.callback(), log_);
[email protected]2bd93022010-07-17 00:58:441319 ASSERT_EQ(out.rv, ERR_IO_PENDING);
[email protected]513963e2013-06-15 01:53:041320 // Run transaction 1 through quickly to force a read of our SETTINGS
1321 // frame.
[email protected]2bd93022010-07-17 00:58:441322 out.rv = callback1.WaitForResult();
robpercival214763f2016-07-01 23:27:011323 ASSERT_THAT(out.rv, IsOk());
[email protected]2bd93022010-07-17 00:58:441324
Bence Békydb3cf652017-10-10 15:22:101325 out.rv = trans2.Start(&request_, callback2.callback(), log_);
[email protected]2bd93022010-07-17 00:58:441326 ASSERT_EQ(out.rv, ERR_IO_PENDING);
Bence Békydb3cf652017-10-10 15:22:101327 out.rv = trans3.Start(&request_, callback3.callback(), log_);
[email protected]2bd93022010-07-17 00:58:441328 ASSERT_EQ(out.rv, ERR_IO_PENDING);
1329 out.rv = callback2.WaitForResult();
robpercival214763f2016-07-01 23:27:011330 ASSERT_THAT(out.rv, IsOk());
[email protected]2bd93022010-07-17 00:58:441331
1332 out.rv = callback3.WaitForResult();
robpercival214763f2016-07-01 23:27:011333 ASSERT_THAT(out.rv, IsOk());
[email protected]2bd93022010-07-17 00:58:441334
bnc691fda62016-08-12 00:43:161335 const HttpResponseInfo* response1 = trans1.GetResponseInfo();
wezca1070932016-05-26 20:30:521336 ASSERT_TRUE(response1);
1337 EXPECT_TRUE(response1->headers);
[email protected]2bd93022010-07-17 00:58:441338 EXPECT_TRUE(response1->was_fetched_via_spdy);
1339 out.status_line = response1->headers->GetStatusLine();
1340 out.response_info = *response1;
bnc691fda62016-08-12 00:43:161341 out.rv = ReadTransaction(&trans1, &out.response_data);
robpercival214763f2016-07-01 23:27:011342 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:021343 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]2bd93022010-07-17 00:58:441344 EXPECT_EQ("hello!hello!", out.response_data);
1345
bnc691fda62016-08-12 00:43:161346 const HttpResponseInfo* response2 = trans2.GetResponseInfo();
[email protected]2bd93022010-07-17 00:58:441347 out.status_line = response2->headers->GetStatusLine();
1348 out.response_info = *response2;
bnc691fda62016-08-12 00:43:161349 out.rv = ReadTransaction(&trans2, &out.response_data);
robpercival214763f2016-07-01 23:27:011350 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:021351 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]2bd93022010-07-17 00:58:441352 EXPECT_EQ("hello!hello!", out.response_data);
1353
bnc691fda62016-08-12 00:43:161354 const HttpResponseInfo* response3 = trans3.GetResponseInfo();
[email protected]2bd93022010-07-17 00:58:441355 out.status_line = response3->headers->GetStatusLine();
1356 out.response_info = *response3;
bnc691fda62016-08-12 00:43:161357 out.rv = ReadTransaction(&trans3, &out.response_data);
robpercival214763f2016-07-01 23:27:011358 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:021359 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]2bd93022010-07-17 00:58:441360 EXPECT_EQ("hello!hello!", out.response_data);
[email protected]044dcc52010-09-17 15:44:261361
1362 helper.VerifyDataConsumed();
[email protected]2bd93022010-07-17 00:58:441363 }
robpercival214763f2016-07-01 23:27:011364 EXPECT_THAT(out.rv, IsOk());
[email protected]2bd93022010-07-17 00:58:441365}
1366
1367// Similar to ThreeGetsWithMaxConcurrent above, however this test adds
1368// a fourth transaction. The third and fourth transactions have
1369// different data ("hello!" vs "hello!hello!") and because of the
1370// user specified priority, we expect to see them inverted in
1371// the response from the server.
bncd16676a2016-07-20 16:23:011372TEST_F(SpdyNetworkTransactionTest, FourGetsWithMaxConcurrentPriority) {
[email protected]2bd93022010-07-17 00:58:441373 // Construct the request.
Ryan Hamilton0239aac2018-05-19 00:03:131374 spdy::SpdySerializedFrame req(
1375 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
1376 spdy::SpdySerializedFrame resp(
1377 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
1378 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, false));
1379 spdy::SpdySerializedFrame fbody(spdy_util_.ConstructSpdyDataFrame(1, true));
rdsmithebb50aa2015-11-12 03:44:381380 spdy_util_.UpdateWithStreamDestruction(1);
[email protected]2bd93022010-07-17 00:58:441381
Ryan Hamilton0239aac2018-05-19 00:03:131382 spdy::SpdySerializedFrame req2(
1383 spdy_util_.ConstructSpdyGet(nullptr, 0, 3, LOWEST));
1384 spdy::SpdySerializedFrame resp2(
1385 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
1386 spdy::SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(3, false));
1387 spdy::SpdySerializedFrame fbody2(spdy_util_.ConstructSpdyDataFrame(3, true));
rdsmithebb50aa2015-11-12 03:44:381388 spdy_util_.UpdateWithStreamDestruction(3);
[email protected]2bd93022010-07-17 00:58:441389
Ryan Hamilton0239aac2018-05-19 00:03:131390 spdy::SpdySerializedFrame req4(
1391 spdy_util_.ConstructSpdyGet(nullptr, 0, 5, HIGHEST));
1392 spdy::SpdySerializedFrame resp4(
1393 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 5));
1394 spdy::SpdySerializedFrame fbody4(spdy_util_.ConstructSpdyDataFrame(5, true));
rdsmithebb50aa2015-11-12 03:44:381395 spdy_util_.UpdateWithStreamDestruction(5);
[email protected]2bd93022010-07-17 00:58:441396
Ryan Hamilton0239aac2018-05-19 00:03:131397 spdy::SpdySerializedFrame req3(
1398 spdy_util_.ConstructSpdyGet(nullptr, 0, 7, LOWEST));
1399 spdy::SpdySerializedFrame resp3(
1400 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 7));
1401 spdy::SpdySerializedFrame body3(spdy_util_.ConstructSpdyDataFrame(7, false));
1402 spdy::SpdySerializedFrame fbody3(spdy_util_.ConstructSpdyDataFrame(7, true));
[email protected]2bd93022010-07-17 00:58:441403
Ryan Hamilton0239aac2018-05-19 00:03:131404 spdy::SettingsMap settings;
Avi Drissman13fc8932015-12-20 04:40:461405 const uint32_t max_concurrent_streams = 1;
Ryan Hamilton0239aac2018-05-19 00:03:131406 settings[spdy::SETTINGS_MAX_CONCURRENT_STREAMS] = max_concurrent_streams;
1407 spdy::SpdySerializedFrame settings_frame(
[email protected]c10b20852013-05-15 21:29:201408 spdy_util_.ConstructSpdySettings(settings));
Ryan Hamilton0239aac2018-05-19 00:03:131409 spdy::SpdySerializedFrame settings_ack(spdy_util_.ConstructSpdySettingsAck());
rch08e3aa3e2015-05-16 14:27:521410 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:411411 CreateMockWrite(req, 0), CreateMockWrite(settings_ack, 5),
rch08e3aa3e2015-05-16 14:27:521412 // By making these synchronous, it guarantees that they are not *started*
1413 // before their sequence number, which in turn verifies that only a single
1414 // request is in-flight at a time.
bncdf80d44fd2016-07-15 20:27:411415 CreateMockWrite(req2, 6, SYNCHRONOUS),
1416 CreateMockWrite(req4, 10, SYNCHRONOUS),
1417 CreateMockWrite(req3, 13, SYNCHRONOUS),
[email protected]2bd93022010-07-17 00:58:441418 };
1419 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:411420 CreateMockRead(settings_frame, 1),
1421 CreateMockRead(resp, 2),
1422 CreateMockRead(body, 3),
1423 CreateMockRead(fbody, 4),
1424 CreateMockRead(resp2, 7),
1425 CreateMockRead(body2, 8),
1426 CreateMockRead(fbody2, 9),
1427 CreateMockRead(resp4, 11),
1428 CreateMockRead(fbody4, 12),
1429 CreateMockRead(resp3, 14),
1430 CreateMockRead(body3, 15),
1431 CreateMockRead(fbody3, 16),
[email protected]2bd93022010-07-17 00:58:441432
rch08e3aa3e2015-05-16 14:27:521433 MockRead(ASYNC, 0, 17), // EOF
[email protected]2bd93022010-07-17 00:58:441434 };
Ryan Sleevib8d7ea02018-05-07 20:01:011435 SequencedSocketData data(reads, writes);
[email protected]2bd93022010-07-17 00:58:441436 TransactionHelperResult out;
Bence Békydb3cf652017-10-10 15:22:101437 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]bdebd1b2010-08-09 20:18:081438 helper.RunPreTestSetup();
[email protected]dd54bd82012-07-19 23:44:571439 helper.AddData(&data);
rch08e3aa3e2015-05-16 14:27:521440
bnc691fda62016-08-12 00:43:161441 HttpNetworkTransaction trans1(DEFAULT_PRIORITY, helper.session());
1442 HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session());
1443 HttpNetworkTransaction trans3(DEFAULT_PRIORITY, helper.session());
1444 HttpNetworkTransaction trans4(HIGHEST, helper.session());
[email protected]2bd93022010-07-17 00:58:441445
[email protected]49639fa2011-12-20 23:22:411446 TestCompletionCallback callback1;
1447 TestCompletionCallback callback2;
1448 TestCompletionCallback callback3;
1449 TestCompletionCallback callback4;
[email protected]2bd93022010-07-17 00:58:441450
Bence Békydb3cf652017-10-10 15:22:101451 out.rv = trans1.Start(&request_, callback1.callback(), log_);
robpercival214763f2016-07-01 23:27:011452 ASSERT_THAT(out.rv, IsError(ERR_IO_PENDING));
[email protected]e0935cc2012-03-24 14:12:481453 // Run transaction 1 through quickly to force a read of our SETTINGS frame.
[email protected]bdebd1b2010-08-09 20:18:081454 out.rv = callback1.WaitForResult();
robpercival214763f2016-07-01 23:27:011455 ASSERT_THAT(out.rv, IsOk());
[email protected]2bd93022010-07-17 00:58:441456
bnceb9aa7112017-01-05 01:03:461457 // Finish async network reads and writes associated with |trans1|.
1458 base::RunLoop().RunUntilIdle();
1459
Bence Békydb3cf652017-10-10 15:22:101460 out.rv = trans2.Start(&request_, callback2.callback(), log_);
robpercival214763f2016-07-01 23:27:011461 ASSERT_THAT(out.rv, IsError(ERR_IO_PENDING));
Bence Békydb3cf652017-10-10 15:22:101462 out.rv = trans3.Start(&request_, callback3.callback(), log_);
robpercival214763f2016-07-01 23:27:011463 ASSERT_THAT(out.rv, IsError(ERR_IO_PENDING));
Bence Békydb3cf652017-10-10 15:22:101464 out.rv = trans4.Start(&request_, callback4.callback(), log_);
robpercival214763f2016-07-01 23:27:011465 ASSERT_THAT(out.rv, IsError(ERR_IO_PENDING));
[email protected]2bd93022010-07-17 00:58:441466
[email protected]bdebd1b2010-08-09 20:18:081467 out.rv = callback2.WaitForResult();
robpercival214763f2016-07-01 23:27:011468 ASSERT_THAT(out.rv, IsOk());
[email protected]2bd93022010-07-17 00:58:441469
[email protected]bdebd1b2010-08-09 20:18:081470 out.rv = callback3.WaitForResult();
robpercival214763f2016-07-01 23:27:011471 ASSERT_THAT(out.rv, IsOk());
[email protected]2bd93022010-07-17 00:58:441472
bnc691fda62016-08-12 00:43:161473 const HttpResponseInfo* response1 = trans1.GetResponseInfo();
wezca1070932016-05-26 20:30:521474 EXPECT_TRUE(response1->headers);
[email protected]bdebd1b2010-08-09 20:18:081475 EXPECT_TRUE(response1->was_fetched_via_spdy);
1476 out.status_line = response1->headers->GetStatusLine();
1477 out.response_info = *response1;
bnc691fda62016-08-12 00:43:161478 out.rv = ReadTransaction(&trans1, &out.response_data);
robpercival214763f2016-07-01 23:27:011479 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:021480 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]bdebd1b2010-08-09 20:18:081481 EXPECT_EQ("hello!hello!", out.response_data);
[email protected]2bd93022010-07-17 00:58:441482
bnc691fda62016-08-12 00:43:161483 const HttpResponseInfo* response2 = trans2.GetResponseInfo();
[email protected]bdebd1b2010-08-09 20:18:081484 out.status_line = response2->headers->GetStatusLine();
1485 out.response_info = *response2;
bnc691fda62016-08-12 00:43:161486 out.rv = ReadTransaction(&trans2, &out.response_data);
robpercival214763f2016-07-01 23:27:011487 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:021488 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]bdebd1b2010-08-09 20:18:081489 EXPECT_EQ("hello!hello!", out.response_data);
[email protected]2bd93022010-07-17 00:58:441490
[email protected]bdebd1b2010-08-09 20:18:081491 // notice: response3 gets two hellos, response4 gets one
1492 // hello, so we know dequeuing priority was respected.
bnc691fda62016-08-12 00:43:161493 const HttpResponseInfo* response3 = trans3.GetResponseInfo();
[email protected]bdebd1b2010-08-09 20:18:081494 out.status_line = response3->headers->GetStatusLine();
1495 out.response_info = *response3;
bnc691fda62016-08-12 00:43:161496 out.rv = ReadTransaction(&trans3, &out.response_data);
robpercival214763f2016-07-01 23:27:011497 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:021498 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]bdebd1b2010-08-09 20:18:081499 EXPECT_EQ("hello!hello!", out.response_data);
[email protected]2bd93022010-07-17 00:58:441500
[email protected]bdebd1b2010-08-09 20:18:081501 out.rv = callback4.WaitForResult();
robpercival214763f2016-07-01 23:27:011502 EXPECT_THAT(out.rv, IsOk());
bnc691fda62016-08-12 00:43:161503 const HttpResponseInfo* response4 = trans4.GetResponseInfo();
[email protected]bdebd1b2010-08-09 20:18:081504 out.status_line = response4->headers->GetStatusLine();
1505 out.response_info = *response4;
bnc691fda62016-08-12 00:43:161506 out.rv = ReadTransaction(&trans4, &out.response_data);
robpercival214763f2016-07-01 23:27:011507 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:021508 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]bdebd1b2010-08-09 20:18:081509 EXPECT_EQ("hello!", out.response_data);
1510 helper.VerifyDataConsumed();
robpercival214763f2016-07-01 23:27:011511 EXPECT_THAT(out.rv, IsOk());
[email protected]2bd93022010-07-17 00:58:441512}
1513
1514// Similar to ThreeGetsMaxConcurrrent above, however, this test
rch08e3aa3e2015-05-16 14:27:521515// deletes a session in the middle of the transaction to ensure
[email protected]2bd93022010-07-17 00:58:441516// that we properly remove pendingcreatestream objects from
1517// the spdy_session
bncd16676a2016-07-20 16:23:011518TEST_F(SpdyNetworkTransactionTest, ThreeGetsWithMaxConcurrentDelete) {
[email protected]2bd93022010-07-17 00:58:441519 // Construct the request.
Ryan Hamilton0239aac2018-05-19 00:03:131520 spdy::SpdySerializedFrame req(
1521 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
1522 spdy::SpdySerializedFrame resp(
1523 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
1524 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, false));
1525 spdy::SpdySerializedFrame fbody(spdy_util_.ConstructSpdyDataFrame(1, true));
rdsmithebb50aa2015-11-12 03:44:381526 spdy_util_.UpdateWithStreamDestruction(1);
[email protected]2bd93022010-07-17 00:58:441527
Ryan Hamilton0239aac2018-05-19 00:03:131528 spdy::SpdySerializedFrame req2(
1529 spdy_util_.ConstructSpdyGet(nullptr, 0, 3, LOWEST));
1530 spdy::SpdySerializedFrame resp2(
1531 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
1532 spdy::SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(3, false));
1533 spdy::SpdySerializedFrame fbody2(spdy_util_.ConstructSpdyDataFrame(3, true));
[email protected]2bd93022010-07-17 00:58:441534
Ryan Hamilton0239aac2018-05-19 00:03:131535 spdy::SettingsMap settings;
Avi Drissman13fc8932015-12-20 04:40:461536 const uint32_t max_concurrent_streams = 1;
Ryan Hamilton0239aac2018-05-19 00:03:131537 settings[spdy::SETTINGS_MAX_CONCURRENT_STREAMS] = max_concurrent_streams;
1538 spdy::SpdySerializedFrame settings_frame(
[email protected]c10b20852013-05-15 21:29:201539 spdy_util_.ConstructSpdySettings(settings));
Ryan Hamilton0239aac2018-05-19 00:03:131540 spdy::SpdySerializedFrame settings_ack(spdy_util_.ConstructSpdySettingsAck());
[email protected]2bd93022010-07-17 00:58:441541
[email protected]d4a77c12014-05-15 20:45:211542 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:411543 CreateMockWrite(req, 0), CreateMockWrite(settings_ack, 5),
1544 CreateMockWrite(req2, 6),
[email protected]2bd93022010-07-17 00:58:441545 };
1546 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:411547 CreateMockRead(settings_frame, 1), CreateMockRead(resp, 2),
1548 CreateMockRead(body, 3), CreateMockRead(fbody, 4),
1549 CreateMockRead(resp2, 7), CreateMockRead(body2, 8),
1550 CreateMockRead(fbody2, 9), MockRead(ASYNC, 0, 10), // EOF
[email protected]2bd93022010-07-17 00:58:441551 };
1552
Ryan Sleevib8d7ea02018-05-07 20:01:011553 SequencedSocketData data(reads, writes);
[email protected]2bd93022010-07-17 00:58:441554
[email protected]2bd93022010-07-17 00:58:441555 TransactionHelperResult out;
Bence Békydb3cf652017-10-10 15:22:101556 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]bdebd1b2010-08-09 20:18:081557 helper.RunPreTestSetup();
[email protected]dd54bd82012-07-19 23:44:571558 helper.AddData(&data);
Jeremy Roman0579ed62017-08-29 15:56:191559 auto trans1 = std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY,
bnc3f6a8552017-05-17 13:40:341560 helper.session());
Jeremy Roman0579ed62017-08-29 15:56:191561 auto trans2 = std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY,
bnc3f6a8552017-05-17 13:40:341562 helper.session());
Jeremy Roman0579ed62017-08-29 15:56:191563 auto trans3 = std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY,
bnc3f6a8552017-05-17 13:40:341564 helper.session());
[email protected]2bd93022010-07-17 00:58:441565
[email protected]49639fa2011-12-20 23:22:411566 TestCompletionCallback callback1;
1567 TestCompletionCallback callback2;
1568 TestCompletionCallback callback3;
[email protected]2bd93022010-07-17 00:58:441569
Bence Békydb3cf652017-10-10 15:22:101570 out.rv = trans1->Start(&request_, callback1.callback(), log_);
[email protected]bdebd1b2010-08-09 20:18:081571 ASSERT_EQ(out.rv, ERR_IO_PENDING);
[email protected]e0935cc2012-03-24 14:12:481572 // Run transaction 1 through quickly to force a read of our SETTINGS frame.
[email protected]bdebd1b2010-08-09 20:18:081573 out.rv = callback1.WaitForResult();
robpercival214763f2016-07-01 23:27:011574 ASSERT_THAT(out.rv, IsOk());
[email protected]2bd93022010-07-17 00:58:441575
Bence Békydb3cf652017-10-10 15:22:101576 out.rv = trans2->Start(&request_, callback2.callback(), log_);
[email protected]bdebd1b2010-08-09 20:18:081577 ASSERT_EQ(out.rv, ERR_IO_PENDING);
Bence Békydb3cf652017-10-10 15:22:101578 out.rv = trans3->Start(&request_, callback3.callback(), log_);
olli.raula7ca9cd1d2016-01-04 06:50:371579 trans3.reset();
[email protected]bdebd1b2010-08-09 20:18:081580 ASSERT_EQ(out.rv, ERR_IO_PENDING);
1581 out.rv = callback2.WaitForResult();
robpercival214763f2016-07-01 23:27:011582 ASSERT_THAT(out.rv, IsOk());
[email protected]2bd93022010-07-17 00:58:441583
[email protected]bdebd1b2010-08-09 20:18:081584 const HttpResponseInfo* response1 = trans1->GetResponseInfo();
wezca1070932016-05-26 20:30:521585 ASSERT_TRUE(response1);
1586 EXPECT_TRUE(response1->headers);
[email protected]bdebd1b2010-08-09 20:18:081587 EXPECT_TRUE(response1->was_fetched_via_spdy);
1588 out.status_line = response1->headers->GetStatusLine();
1589 out.response_info = *response1;
1590 out.rv = ReadTransaction(trans1.get(), &out.response_data);
robpercival214763f2016-07-01 23:27:011591 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:021592 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]bdebd1b2010-08-09 20:18:081593 EXPECT_EQ("hello!hello!", out.response_data);
[email protected]2bd93022010-07-17 00:58:441594
[email protected]bdebd1b2010-08-09 20:18:081595 const HttpResponseInfo* response2 = trans2->GetResponseInfo();
wezca1070932016-05-26 20:30:521596 ASSERT_TRUE(response2);
[email protected]bdebd1b2010-08-09 20:18:081597 out.status_line = response2->headers->GetStatusLine();
1598 out.response_info = *response2;
1599 out.rv = ReadTransaction(trans2.get(), &out.response_data);
robpercival214763f2016-07-01 23:27:011600 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:021601 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]bdebd1b2010-08-09 20:18:081602 EXPECT_EQ("hello!hello!", out.response_data);
1603 helper.VerifyDataConsumed();
robpercival214763f2016-07-01 23:27:011604 EXPECT_THAT(out.rv, IsOk());
[email protected]044dcc52010-09-17 15:44:261605}
[email protected]2bd93022010-07-17 00:58:441606
[email protected]448d4ca52012-03-04 04:12:231607namespace {
1608
Bence Béky8ddc2492018-06-13 01:02:041609// A helper class that will delete |transaction| on error when the callback is
1610// invoked.
[email protected]49639fa2011-12-20 23:22:411611class KillerCallback : public TestCompletionCallbackBase {
[email protected]044dcc52010-09-17 15:44:261612 public:
1613 explicit KillerCallback(HttpNetworkTransaction* transaction)
Bence Béky8ddc2492018-06-13 01:02:041614 : transaction_(transaction) {}
[email protected]044dcc52010-09-17 15:44:261615
Chris Watkins61914cb2017-12-01 19:59:001616 ~KillerCallback() override = default;
[email protected]49639fa2011-12-20 23:22:411617
Bence Béky8ddc2492018-06-13 01:02:041618 CompletionOnceCallback callback() {
1619 return base::BindOnce(&KillerCallback::OnComplete, base::Unretained(this));
1620 }
[email protected]49639fa2011-12-20 23:22:411621
[email protected]044dcc52010-09-17 15:44:261622 private:
[email protected]49639fa2011-12-20 23:22:411623 void OnComplete(int result) {
1624 if (result < 0)
1625 delete transaction_;
1626
1627 SetResult(result);
1628 }
1629
Keishi Hattori0e45c022021-11-27 09:25:521630 raw_ptr<HttpNetworkTransaction> transaction_;
[email protected]044dcc52010-09-17 15:44:261631};
1632
[email protected]448d4ca52012-03-04 04:12:231633} // namespace
1634
[email protected]044dcc52010-09-17 15:44:261635// Similar to ThreeGetsMaxConcurrrentDelete above, however, this test
1636// closes the socket while we have a pending transaction waiting for
1637// a pending stream creation. http://crbug.com/52901
bncd16676a2016-07-20 16:23:011638TEST_F(SpdyNetworkTransactionTest, ThreeGetsWithMaxConcurrentSocketClose) {
Matt Menke66e502a72019-04-15 13:34:381639 // Construct the request. Each stream uses a different priority to provide
1640 // more useful failure information if the requests are made in an unexpected
1641 // order.
Ryan Hamilton0239aac2018-05-19 00:03:131642 spdy::SpdySerializedFrame req(
Matt Menke66e502a72019-04-15 13:34:381643 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, HIGHEST));
Ryan Hamilton0239aac2018-05-19 00:03:131644 spdy::SpdySerializedFrame resp(
1645 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
1646 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, false));
1647 spdy::SpdySerializedFrame fin_body(
1648 spdy_util_.ConstructSpdyDataFrame(1, true));
rdsmithebb50aa2015-11-12 03:44:381649 spdy_util_.UpdateWithStreamDestruction(1);
[email protected]044dcc52010-09-17 15:44:261650
Ryan Hamilton0239aac2018-05-19 00:03:131651 spdy::SpdySerializedFrame req2(
Matt Menke66e502a72019-04-15 13:34:381652 spdy_util_.ConstructSpdyGet(nullptr, 0, 3, MEDIUM));
Ryan Hamilton0239aac2018-05-19 00:03:131653 spdy::SpdySerializedFrame resp2(
1654 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
[email protected]044dcc52010-09-17 15:44:261655
Ryan Hamilton0239aac2018-05-19 00:03:131656 spdy::SettingsMap settings;
Avi Drissman13fc8932015-12-20 04:40:461657 const uint32_t max_concurrent_streams = 1;
Ryan Hamilton0239aac2018-05-19 00:03:131658 settings[spdy::SETTINGS_MAX_CONCURRENT_STREAMS] = max_concurrent_streams;
1659 spdy::SpdySerializedFrame settings_frame(
[email protected]c10b20852013-05-15 21:29:201660 spdy_util_.ConstructSpdySettings(settings));
Ryan Hamilton0239aac2018-05-19 00:03:131661 spdy::SpdySerializedFrame settings_ack(spdy_util_.ConstructSpdySettingsAck());
[email protected]044dcc52010-09-17 15:44:261662
Matt Menke66e502a72019-04-15 13:34:381663 MockWrite writes[] = {CreateMockWrite(req, 0),
1664 CreateMockWrite(settings_ack, 6),
1665 CreateMockWrite(req2, 7)};
[email protected]044dcc52010-09-17 15:44:261666 MockRead reads[] = {
Matt Menke66e502a72019-04-15 13:34:381667 CreateMockRead(settings_frame, 1), CreateMockRead(resp, 2),
bncdf80d44fd2016-07-15 20:27:411668 CreateMockRead(body, 3),
Matt Menke66e502a72019-04-15 13:34:381669 // Delay the request here. For this test to pass, the three HTTP streams
1670 // have to be created in order, but SpdySession doesn't actually guarantee
1671 // that (See note in SpdySession::ProcessPendingStreamRequests). As a
1672 // workaround, delay finishing up the first stream until the second and
1673 // third streams are waiting in the SPDY stream request queue.
1674 MockRead(ASYNC, ERR_IO_PENDING, 4), CreateMockRead(fin_body, 5),
1675 CreateMockRead(resp2, 8),
David Benjamin73dc5242019-05-15 21:59:281676 // The exact error does not matter, but some errors, such as
1677 // ERR_CONNECTION_RESET, may trigger a retry, which this test does not
1678 // account for.
1679 MockRead(ASYNC, ERR_SSL_BAD_RECORD_MAC_ALERT, 9), // Abort!
[email protected]044dcc52010-09-17 15:44:261680 };
1681
Ryan Sleevib8d7ea02018-05-07 20:01:011682 SequencedSocketData data(reads, writes);
1683 SequencedSocketData data_placeholder;
[email protected]044dcc52010-09-17 15:44:261684
[email protected]044dcc52010-09-17 15:44:261685 TransactionHelperResult out;
Matt Menke66e502a72019-04-15 13:34:381686 NormalSpdyTransactionHelper helper(request_, HIGHEST, log_, nullptr);
[email protected]044dcc52010-09-17 15:44:261687 helper.RunPreTestSetup();
[email protected]dd54bd82012-07-19 23:44:571688 helper.AddData(&data);
[email protected]044dcc52010-09-17 15:44:261689 // We require placeholder data because three get requests are sent out, so
1690 // there needs to be three sets of SSL connection data.
[email protected]dd54bd82012-07-19 23:44:571691 helper.AddData(&data_placeholder);
1692 helper.AddData(&data_placeholder);
Matt Menke66e502a72019-04-15 13:34:381693 HttpNetworkTransaction trans1(HIGHEST, helper.session());
1694 HttpNetworkTransaction trans2(MEDIUM, helper.session());
[email protected]262eec82013-03-19 21:01:361695 HttpNetworkTransaction* trans3(
mmenkee65e7af2015-10-13 17:16:421696 new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session()));
[email protected]044dcc52010-09-17 15:44:261697
[email protected]49639fa2011-12-20 23:22:411698 TestCompletionCallback callback1;
1699 TestCompletionCallback callback2;
[email protected]044dcc52010-09-17 15:44:261700 KillerCallback callback3(trans3);
1701
Bence Békydb3cf652017-10-10 15:22:101702 out.rv = trans1.Start(&request_, callback1.callback(), log_);
[email protected]044dcc52010-09-17 15:44:261703 ASSERT_EQ(out.rv, ERR_IO_PENDING);
[email protected]e0935cc2012-03-24 14:12:481704 // Run transaction 1 through quickly to force a read of our SETTINGS frame.
[email protected]044dcc52010-09-17 15:44:261705 out.rv = callback1.WaitForResult();
robpercival214763f2016-07-01 23:27:011706 ASSERT_THAT(out.rv, IsOk());
[email protected]044dcc52010-09-17 15:44:261707
Bence Békydb3cf652017-10-10 15:22:101708 out.rv = trans2.Start(&request_, callback2.callback(), log_);
[email protected]044dcc52010-09-17 15:44:261709 ASSERT_EQ(out.rv, ERR_IO_PENDING);
Bence Békydb3cf652017-10-10 15:22:101710 out.rv = trans3->Start(&request_, callback3.callback(), log_);
[email protected]044dcc52010-09-17 15:44:261711 ASSERT_EQ(out.rv, ERR_IO_PENDING);
Matt Menke66e502a72019-04-15 13:34:381712
1713 // Run until both transactions are in the SpdySession's queue, waiting for the
1714 // final request to complete.
1715 base::RunLoop().RunUntilIdle();
1716 data.Resume();
1717
[email protected]044dcc52010-09-17 15:44:261718 out.rv = callback3.WaitForResult();
David Benjamin73dc5242019-05-15 21:59:281719 EXPECT_THAT(out.rv, IsError(ERR_SSL_BAD_RECORD_MAC_ALERT));
[email protected]044dcc52010-09-17 15:44:261720
[email protected]044dcc52010-09-17 15:44:261721 const HttpResponseInfo* response1 = trans1.GetResponseInfo();
wezca1070932016-05-26 20:30:521722 ASSERT_TRUE(response1);
1723 EXPECT_TRUE(response1->headers);
[email protected]044dcc52010-09-17 15:44:261724 EXPECT_TRUE(response1->was_fetched_via_spdy);
1725 out.status_line = response1->headers->GetStatusLine();
1726 out.response_info = *response1;
1727 out.rv = ReadTransaction(&trans1, &out.response_data);
robpercival214763f2016-07-01 23:27:011728 EXPECT_THAT(out.rv, IsOk());
[email protected]044dcc52010-09-17 15:44:261729
1730 const HttpResponseInfo* response2 = trans2.GetResponseInfo();
wezca1070932016-05-26 20:30:521731 ASSERT_TRUE(response2);
[email protected]044dcc52010-09-17 15:44:261732 out.status_line = response2->headers->GetStatusLine();
1733 out.response_info = *response2;
1734 out.rv = ReadTransaction(&trans2, &out.response_data);
David Benjamin73dc5242019-05-15 21:59:281735 EXPECT_THAT(out.rv, IsError(ERR_SSL_BAD_RECORD_MAC_ALERT));
[email protected]044dcc52010-09-17 15:44:261736
1737 helper.VerifyDataConsumed();
[email protected]2bd93022010-07-17 00:58:441738}
1739
[email protected]d8ef27b2010-08-06 17:34:391740// Test that a simple PUT request works.
bncd16676a2016-07-20 16:23:011741TEST_F(SpdyNetworkTransactionTest, Put) {
Bence Békydb3cf652017-10-10 15:22:101742 // Setup the request.
1743 request_.method = "PUT";
[email protected]d8ef27b2010-08-06 17:34:391744
Bence Béky4c325e52020-10-22 20:48:011745 spdy::Http2HeaderBlock put_headers(
bncb26024382016-06-29 02:39:451746 spdy_util_.ConstructPutHeaderBlock(kDefaultUrl, 0));
Ryan Hamilton0239aac2018-05-19 00:03:131747 spdy::SpdySerializedFrame req(
bnc42331402016-07-25 13:36:151748 spdy_util_.ConstructSpdyHeaders(1, std::move(put_headers), LOWEST, true));
[email protected]d8ef27b2010-08-06 17:34:391749 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:411750 CreateMockWrite(req, 0),
[email protected]d8ef27b2010-08-06 17:34:391751 };
1752
Ryan Hamilton0239aac2018-05-19 00:03:131753 spdy::SpdySerializedFrame resp(
1754 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
1755 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]d8ef27b2010-08-06 17:34:391756 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:411757 CreateMockRead(resp, 1), CreateMockRead(body, 2),
rch08e3aa3e2015-05-16 14:27:521758 MockRead(ASYNC, 0, 3) // EOF
[email protected]d8ef27b2010-08-06 17:34:391759 };
1760
Ryan Sleevib8d7ea02018-05-07 20:01:011761 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:101762 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]dd54bd82012-07-19 23:44:571763 helper.RunToCompletion(&data);
[email protected]d8ef27b2010-08-06 17:34:391764 TransactionHelperResult out = helper.output();
1765
robpercival214763f2016-07-01 23:27:011766 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:021767 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]d8ef27b2010-08-06 17:34:391768}
1769
1770// Test that a simple HEAD request works.
bncd16676a2016-07-20 16:23:011771TEST_F(SpdyNetworkTransactionTest, Head) {
Bence Békydb3cf652017-10-10 15:22:101772 // Setup the request.
1773 request_.method = "HEAD";
[email protected]d8ef27b2010-08-06 17:34:391774
Bence Béky4c325e52020-10-22 20:48:011775 spdy::Http2HeaderBlock head_headers(
bncb26024382016-06-29 02:39:451776 spdy_util_.ConstructHeadHeaderBlock(kDefaultUrl, 0));
Ryan Hamilton0239aac2018-05-19 00:03:131777 spdy::SpdySerializedFrame req(spdy_util_.ConstructSpdyHeaders(
bnc42331402016-07-25 13:36:151778 1, std::move(head_headers), LOWEST, true));
[email protected]d8ef27b2010-08-06 17:34:391779 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:411780 CreateMockWrite(req, 0),
[email protected]d8ef27b2010-08-06 17:34:391781 };
1782
Ryan Hamilton0239aac2018-05-19 00:03:131783 spdy::SpdySerializedFrame resp(
1784 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
1785 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]d8ef27b2010-08-06 17:34:391786 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:411787 CreateMockRead(resp, 1), CreateMockRead(body, 2),
rch08e3aa3e2015-05-16 14:27:521788 MockRead(ASYNC, 0, 3) // EOF
[email protected]d8ef27b2010-08-06 17:34:391789 };
1790
Ryan Sleevib8d7ea02018-05-07 20:01:011791 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:101792 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]dd54bd82012-07-19 23:44:571793 helper.RunToCompletion(&data);
[email protected]d8ef27b2010-08-06 17:34:391794 TransactionHelperResult out = helper.output();
1795
robpercival214763f2016-07-01 23:27:011796 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:021797 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]d8ef27b2010-08-06 17:34:391798}
1799
[email protected]72552f02009-10-28 15:25:011800// Test that a simple POST works.
bncd16676a2016-07-20 16:23:011801TEST_F(SpdyNetworkTransactionTest, Post) {
Ryan Hamilton0239aac2018-05-19 00:03:131802 spdy::SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
tombergan5d22c182017-01-11 02:05:351803 kDefaultUrl, 1, kUploadDataSize, LOWEST, nullptr, 0));
Ryan Hamilton0239aac2018-05-19 00:03:131804 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]ff57bb82009-11-12 06:52:141805 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:411806 CreateMockWrite(req, 0), CreateMockWrite(body, 1), // POST upload frame
[email protected]ff57bb82009-11-12 06:52:141807 };
[email protected]72552f02009-10-28 15:25:011808
Ryan Hamilton0239aac2018-05-19 00:03:131809 spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
[email protected]ff57bb82009-11-12 06:52:141810 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:411811 CreateMockRead(resp, 2), CreateMockRead(body, 3),
rch08e3aa3e2015-05-16 14:27:521812 MockRead(ASYNC, 0, 4) // EOF
[email protected]aea80602009-09-18 00:55:081813 };
1814
Ryan Sleevib8d7ea02018-05-07 20:01:011815 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:101816 UsePostRequest();
1817 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]dd54bd82012-07-19 23:44:571818 helper.RunToCompletion(&data);
[email protected]3caf5542010-07-16 15:19:471819 TransactionHelperResult out = helper.output();
robpercival214763f2016-07-01 23:27:011820 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:021821 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]aea80602009-09-18 00:55:081822 EXPECT_EQ("hello!", out.response_data);
1823}
1824
[email protected]69e6b4a2012-10-18 08:03:011825// Test that a POST with a file works.
bncd16676a2016-07-20 16:23:011826TEST_F(SpdyNetworkTransactionTest, FilePost) {
Ryan Hamilton0239aac2018-05-19 00:03:131827 spdy::SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
tombergan5d22c182017-01-11 02:05:351828 kDefaultUrl, 1, kUploadDataSize, LOWEST, nullptr, 0));
Ryan Hamilton0239aac2018-05-19 00:03:131829 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]69e6b4a2012-10-18 08:03:011830 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:411831 CreateMockWrite(req, 0), CreateMockWrite(body, 1), // POST upload frame
[email protected]69e6b4a2012-10-18 08:03:011832 };
1833
Ryan Hamilton0239aac2018-05-19 00:03:131834 spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
[email protected]69e6b4a2012-10-18 08:03:011835 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:411836 CreateMockRead(resp, 2), CreateMockRead(body, 3),
rch08e3aa3e2015-05-16 14:27:521837 MockRead(ASYNC, 0, 4) // EOF
[email protected]69e6b4a2012-10-18 08:03:011838 };
1839
Ryan Sleevib8d7ea02018-05-07 20:01:011840 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:101841 UseFilePostRequest();
1842 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]69e6b4a2012-10-18 08:03:011843 helper.RunToCompletion(&data);
1844 TransactionHelperResult out = helper.output();
robpercival214763f2016-07-01 23:27:011845 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:021846 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]69e6b4a2012-10-18 08:03:011847 EXPECT_EQ("hello!", out.response_data);
1848}
1849
[email protected]999dd8c2013-11-12 06:45:541850// Test that a POST with a unreadable file fails.
bncd16676a2016-07-20 16:23:011851TEST_F(SpdyNetworkTransactionTest, UnreadableFilePost) {
[email protected]999dd8c2013-11-12 06:45:541852 MockWrite writes[] = {
rch08e3aa3e2015-05-16 14:27:521853 MockWrite(ASYNC, 0, 0) // EOF
[email protected]999dd8c2013-11-12 06:45:541854 };
1855 MockRead reads[] = {
rch08e3aa3e2015-05-16 14:27:521856 MockRead(ASYNC, 0, 1) // EOF
[email protected]999dd8c2013-11-12 06:45:541857 };
1858
Ryan Sleevib8d7ea02018-05-07 20:01:011859 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:101860 UseUnreadableFilePostRequest();
1861 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]999dd8c2013-11-12 06:45:541862 helper.RunPreTestSetup();
1863 helper.AddData(&data);
1864 helper.RunDefaultTest();
1865
1866 base::RunLoop().RunUntilIdle();
1867 helper.VerifyDataNotConsumed();
robpercival214763f2016-07-01 23:27:011868 EXPECT_THAT(helper.output().rv, IsError(ERR_ACCESS_DENIED));
[email protected]999dd8c2013-11-12 06:45:541869}
1870
[email protected]69e6b4a2012-10-18 08:03:011871// Test that a complex POST works.
bncd16676a2016-07-20 16:23:011872TEST_F(SpdyNetworkTransactionTest, ComplexPost) {
Ryan Hamilton0239aac2018-05-19 00:03:131873 spdy::SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
tombergan5d22c182017-01-11 02:05:351874 kDefaultUrl, 1, kUploadDataSize, LOWEST, nullptr, 0));
Ryan Hamilton0239aac2018-05-19 00:03:131875 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]69e6b4a2012-10-18 08:03:011876 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:411877 CreateMockWrite(req, 0), CreateMockWrite(body, 1), // POST upload frame
[email protected]69e6b4a2012-10-18 08:03:011878 };
1879
Ryan Hamilton0239aac2018-05-19 00:03:131880 spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
[email protected]69e6b4a2012-10-18 08:03:011881 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:411882 CreateMockRead(resp, 2), CreateMockRead(body, 3),
rch08e3aa3e2015-05-16 14:27:521883 MockRead(ASYNC, 0, 4) // EOF
[email protected]69e6b4a2012-10-18 08:03:011884 };
1885
Ryan Sleevib8d7ea02018-05-07 20:01:011886 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:101887 UseComplexPostRequest();
1888 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]69e6b4a2012-10-18 08:03:011889 helper.RunToCompletion(&data);
1890 TransactionHelperResult out = helper.output();
robpercival214763f2016-07-01 23:27:011891 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:021892 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]69e6b4a2012-10-18 08:03:011893 EXPECT_EQ("hello!", out.response_data);
1894}
1895
[email protected]0c9bf872011-03-04 17:53:221896// Test that a chunked POST works.
bncd16676a2016-07-20 16:23:011897TEST_F(SpdyNetworkTransactionTest, ChunkedPost) {
Ryan Hamilton0239aac2018-05-19 00:03:131898 spdy::SpdySerializedFrame req(
1899 spdy_util_.ConstructChunkedSpdyPost(nullptr, 0));
1900 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]0c9bf872011-03-04 17:53:221901 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:411902 CreateMockWrite(req, 0), CreateMockWrite(body, 1),
[email protected]0c9bf872011-03-04 17:53:221903 };
1904
Ryan Hamilton0239aac2018-05-19 00:03:131905 spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
[email protected]0c9bf872011-03-04 17:53:221906 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:411907 CreateMockRead(resp, 2), CreateMockRead(body, 3),
rch08e3aa3e2015-05-16 14:27:521908 MockRead(ASYNC, 0, 4) // EOF
[email protected]0c9bf872011-03-04 17:53:221909 };
1910
Ryan Sleevib8d7ea02018-05-07 20:01:011911 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:101912 UseChunkedPostRequest();
1913 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]34b345f92013-02-22 03:27:261914
1915 // These chunks get merged into a single frame when being sent.
1916 const int kFirstChunkSize = kUploadDataSize/2;
mmenkecbc2b712014-10-09 20:29:071917 upload_chunked_data_stream()->AppendData(kUploadData, kFirstChunkSize, false);
1918 upload_chunked_data_stream()->AppendData(
[email protected]34b345f92013-02-22 03:27:261919 kUploadData + kFirstChunkSize, kUploadDataSize - kFirstChunkSize, true);
1920
[email protected]dd54bd82012-07-19 23:44:571921 helper.RunToCompletion(&data);
[email protected]0c9bf872011-03-04 17:53:221922 TransactionHelperResult out = helper.output();
robpercival214763f2016-07-01 23:27:011923 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:021924 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]34b345f92013-02-22 03:27:261925 EXPECT_EQ(kUploadData, out.response_data);
1926}
1927
1928// Test that a chunked POST works with chunks appended after transaction starts.
bncd16676a2016-07-20 16:23:011929TEST_F(SpdyNetworkTransactionTest, DelayedChunkedPost) {
Ryan Hamilton0239aac2018-05-19 00:03:131930 spdy::SpdySerializedFrame req(
1931 spdy_util_.ConstructChunkedSpdyPost(nullptr, 0));
1932 spdy::SpdySerializedFrame chunk1(spdy_util_.ConstructSpdyDataFrame(1, false));
1933 spdy::SpdySerializedFrame chunk2(spdy_util_.ConstructSpdyDataFrame(1, false));
1934 spdy::SpdySerializedFrame chunk3(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]34b345f92013-02-22 03:27:261935 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:411936 CreateMockWrite(req, 0), CreateMockWrite(chunk1, 1),
1937 CreateMockWrite(chunk2, 2), CreateMockWrite(chunk3, 3),
[email protected]34b345f92013-02-22 03:27:261938 };
1939
Ryan Hamilton0239aac2018-05-19 00:03:131940 spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
[email protected]34b345f92013-02-22 03:27:261941 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:411942 CreateMockRead(resp, 4), CreateMockRead(chunk1, 5),
1943 CreateMockRead(chunk2, 6), CreateMockRead(chunk3, 7),
rch08e3aa3e2015-05-16 14:27:521944 MockRead(ASYNC, 0, 8) // EOF
[email protected]34b345f92013-02-22 03:27:261945 };
1946
Ryan Sleevib8d7ea02018-05-07 20:01:011947 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:101948 UseChunkedPostRequest();
1949 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]34b345f92013-02-22 03:27:261950
mmenkecbc2b712014-10-09 20:29:071951 upload_chunked_data_stream()->AppendData(kUploadData, kUploadDataSize, false);
[email protected]34b345f92013-02-22 03:27:261952
1953 helper.RunPreTestSetup();
1954 helper.AddData(&data);
1955 ASSERT_TRUE(helper.StartDefaultTest());
1956
[email protected]fc9d88472013-08-14 02:31:171957 base::RunLoop().RunUntilIdle();
mmenkecbc2b712014-10-09 20:29:071958 upload_chunked_data_stream()->AppendData(kUploadData, kUploadDataSize, false);
[email protected]fc9d88472013-08-14 02:31:171959 base::RunLoop().RunUntilIdle();
mmenkecbc2b712014-10-09 20:29:071960 upload_chunked_data_stream()->AppendData(kUploadData, kUploadDataSize, true);
[email protected]34b345f92013-02-22 03:27:261961
1962 helper.FinishDefaultTest();
1963 helper.VerifyDataConsumed();
1964
Bence Béky4e83f492018-05-13 23:14:251965 std::string expected_response;
[email protected]34b345f92013-02-22 03:27:261966 expected_response += kUploadData;
1967 expected_response += kUploadData;
1968 expected_response += kUploadData;
1969
1970 TransactionHelperResult out = helper.output();
robpercival214763f2016-07-01 23:27:011971 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:021972 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]34b345f92013-02-22 03:27:261973 EXPECT_EQ(expected_response, out.response_data);
[email protected]0c9bf872011-03-04 17:53:221974}
1975
[email protected]a33cad2b62010-07-30 22:24:391976// Test that a POST without any post data works.
bncd16676a2016-07-20 16:23:011977TEST_F(SpdyNetworkTransactionTest, NullPost) {
Bence Békydb3cf652017-10-10 15:22:101978 // Setup the request.
1979 request_.method = "POST";
[email protected]a33cad2b62010-07-30 22:24:391980 // Create an empty UploadData.
Bence Békydb3cf652017-10-10 15:22:101981 request_.upload_data_stream = nullptr;
[email protected]a33cad2b62010-07-30 22:24:391982
[email protected]329b68b2012-11-14 17:54:271983 // When request.upload_data_stream is NULL for post, content-length is
[email protected]a33cad2b62010-07-30 22:24:391984 // expected to be 0.
Bence Béky4c325e52020-10-22 20:48:011985 spdy::Http2HeaderBlock req_block(
bncb26024382016-06-29 02:39:451986 spdy_util_.ConstructPostHeaderBlock(kDefaultUrl, 0));
Ryan Hamilton0239aac2018-05-19 00:03:131987 spdy::SpdySerializedFrame req(
bnc42331402016-07-25 13:36:151988 spdy_util_.ConstructSpdyHeaders(1, std::move(req_block), LOWEST, true));
[email protected]d2c1a97b2014-03-03 19:25:091989
[email protected]a33cad2b62010-07-30 22:24:391990 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:411991 CreateMockWrite(req, 0),
[email protected]a33cad2b62010-07-30 22:24:391992 };
1993
Ryan Hamilton0239aac2018-05-19 00:03:131994 spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
1995 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]a33cad2b62010-07-30 22:24:391996 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:411997 CreateMockRead(resp, 1), CreateMockRead(body, 2),
rch08e3aa3e2015-05-16 14:27:521998 MockRead(ASYNC, 0, 3) // EOF
[email protected]a33cad2b62010-07-30 22:24:391999 };
2000
Ryan Sleevib8d7ea02018-05-07 20:01:012001 SequencedSocketData data(reads, writes);
[email protected]a33cad2b62010-07-30 22:24:392002
Bence Békydb3cf652017-10-10 15:22:102003 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]dd54bd82012-07-19 23:44:572004 helper.RunToCompletion(&data);
[email protected]a33cad2b62010-07-30 22:24:392005 TransactionHelperResult out = helper.output();
robpercival214763f2016-07-01 23:27:012006 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:022007 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]a33cad2b62010-07-30 22:24:392008 EXPECT_EQ("hello!", out.response_data);
2009}
2010
[email protected]edd3b0a52009-11-24 18:56:362011// Test that a simple POST works.
bncd16676a2016-07-20 16:23:012012TEST_F(SpdyNetworkTransactionTest, EmptyPost) {
[email protected]329b68b2012-11-14 17:54:272013 // Create an empty UploadDataStream.
danakjaee3e1ec2016-04-16 00:23:182014 std::vector<std::unique_ptr<UploadElementReader>> element_readers;
olli.raula6df48b2a2015-11-26 07:40:222015 ElementsUploadDataStream stream(std::move(element_readers), 0);
[email protected]329b68b2012-11-14 17:54:272016
Bence Békydb3cf652017-10-10 15:22:102017 // Setup the request.
2018 request_.method = "POST";
2019 request_.upload_data_stream = &stream;
[email protected]edd3b0a52009-11-24 18:56:362020
Avi Drissman13fc8932015-12-20 04:40:462021 const uint64_t kContentLength = 0;
[email protected]d2c1a97b2014-03-03 19:25:092022
Bence Béky4c325e52020-10-22 20:48:012023 spdy::Http2HeaderBlock req_block(
bncb26024382016-06-29 02:39:452024 spdy_util_.ConstructPostHeaderBlock(kDefaultUrl, kContentLength));
Ryan Hamilton0239aac2018-05-19 00:03:132025 spdy::SpdySerializedFrame req(
bnc42331402016-07-25 13:36:152026 spdy_util_.ConstructSpdyHeaders(1, std::move(req_block), LOWEST, true));
[email protected]d2c1a97b2014-03-03 19:25:092027
[email protected]edd3b0a52009-11-24 18:56:362028 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:412029 CreateMockWrite(req, 0),
[email protected]edd3b0a52009-11-24 18:56:362030 };
2031
Ryan Hamilton0239aac2018-05-19 00:03:132032 spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
2033 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]edd3b0a52009-11-24 18:56:362034 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:412035 CreateMockRead(resp, 1), CreateMockRead(body, 2),
rch08e3aa3e2015-05-16 14:27:522036 MockRead(ASYNC, 0, 3) // EOF
[email protected]edd3b0a52009-11-24 18:56:362037 };
2038
Ryan Sleevib8d7ea02018-05-07 20:01:012039 SequencedSocketData data(reads, writes);
[email protected]bf2491a92009-11-29 16:39:482040
Bence Békydb3cf652017-10-10 15:22:102041 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]dd54bd82012-07-19 23:44:572042 helper.RunToCompletion(&data);
[email protected]3caf5542010-07-16 15:19:472043 TransactionHelperResult out = helper.output();
robpercival214763f2016-07-01 23:27:012044 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:022045 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]edd3b0a52009-11-24 18:56:362046 EXPECT_EQ("hello!", out.response_data);
2047}
2048
[email protected]35c3fc732014-02-15 00:16:072049// While we're doing a post, the server sends the reply before upload completes.
bncd16676a2016-07-20 16:23:012050TEST_F(SpdyNetworkTransactionTest, ResponseBeforePostCompletes) {
Ryan Hamilton0239aac2018-05-19 00:03:132051 spdy::SpdySerializedFrame req(
2052 spdy_util_.ConstructChunkedSpdyPost(nullptr, 0));
2053 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]35c3fc732014-02-15 00:16:072054 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:412055 CreateMockWrite(req, 0), CreateMockWrite(body, 3),
[email protected]35c3fc732014-02-15 00:16:072056 };
Ryan Hamilton0239aac2018-05-19 00:03:132057 spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
[email protected]a5566f9702010-05-05 22:25:432058 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:412059 CreateMockRead(resp, 1), CreateMockRead(body, 2),
2060 MockRead(ASYNC, 0, 4) // EOF
[email protected]a5566f9702010-05-05 22:25:432061 };
2062
[email protected]35c3fc732014-02-15 00:16:072063 // Write the request headers, and read the complete response
2064 // while still waiting for chunked request data.
Ryan Sleevib8d7ea02018-05-07 20:01:012065 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:102066 UseChunkedPostRequest();
2067 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]c92f4b4542012-07-26 23:53:212068 helper.RunPreTestSetup();
mmenke666a6fea2015-12-19 04:16:332069 helper.AddData(&data);
[email protected]c92f4b4542012-07-26 23:53:212070
[email protected]35c3fc732014-02-15 00:16:072071 ASSERT_TRUE(helper.StartDefaultTest());
[email protected]c92f4b4542012-07-26 23:53:212072
maksim.sisov8d2df66d2016-06-20 07:07:112073 base::RunLoop().RunUntilIdle();
mmenke666a6fea2015-12-19 04:16:332074
bnc42331402016-07-25 13:36:152075 // Process the request headers, response headers, and response body.
[email protected]35c3fc732014-02-15 00:16:072076 // The request body is still in flight.
[email protected]35c3fc732014-02-15 00:16:072077 const HttpResponseInfo* response = helper.trans()->GetResponseInfo();
bnc84e7fb52015-12-02 11:50:022078 EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
[email protected]35c3fc732014-02-15 00:16:072079
2080 // Finish sending the request body.
mmenkecbc2b712014-10-09 20:29:072081 upload_chunked_data_stream()->AppendData(kUploadData, kUploadDataSize, true);
maksim.sisov8d2df66d2016-06-20 07:07:112082 helper.WaitForCallbackToComplete();
robpercival214763f2016-07-01 23:27:012083 EXPECT_THAT(helper.output().rv, IsOk());
[email protected]35c3fc732014-02-15 00:16:072084
Bence Béky4e83f492018-05-13 23:14:252085 std::string response_body;
robpercival214763f2016-07-01 23:27:012086 EXPECT_THAT(ReadTransaction(helper.trans(), &response_body), IsOk());
[email protected]35c3fc732014-02-15 00:16:072087 EXPECT_EQ(kUploadData, response_body);
bnceb9aa7112017-01-05 01:03:462088
2089 // Finish async network reads/writes.
2090 base::RunLoop().RunUntilIdle();
[email protected]35c3fc732014-02-15 00:16:072091 helper.VerifyDataConsumed();
[email protected]a5566f9702010-05-05 22:25:432092}
2093
[email protected]f9a26d72010-08-03 18:07:132094// The client upon cancellation tries to send a RST_STREAM frame. The mock
2095// socket causes the TCP write to return zero. This test checks that the client
2096// tries to queue up the RST_STREAM frame again.
bncd16676a2016-07-20 16:23:012097TEST_F(SpdyNetworkTransactionTest, SocketWriteReturnsZero) {
Ryan Hamilton0239aac2018-05-19 00:03:132098 spdy::SpdySerializedFrame req(
2099 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
2100 spdy::SpdySerializedFrame rst(
2101 spdy_util_.ConstructSpdyRstStream(1, spdy::ERROR_CODE_CANCEL));
[email protected]f9a26d72010-08-03 18:07:132102 MockWrite writes[] = {
Raul Tambre94493c652019-03-11 17:18:352103 CreateMockWrite(req, 0, SYNCHRONOUS),
2104 MockWrite(SYNCHRONOUS, nullptr, 0, 2),
bncdf80d44fd2016-07-15 20:27:412105 CreateMockWrite(rst, 3, SYNCHRONOUS),
[email protected]f9a26d72010-08-03 18:07:132106 };
2107
Ryan Hamilton0239aac2018-05-19 00:03:132108 spdy::SpdySerializedFrame resp(
2109 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
[email protected]f9a26d72010-08-03 18:07:132110 MockRead reads[] = {
Raul Tambre94493c652019-03-11 17:18:352111 CreateMockRead(resp, 1, ASYNC), MockRead(ASYNC, nullptr, 0, 4) // EOF
[email protected]f9a26d72010-08-03 18:07:132112 };
2113
Ryan Sleevib8d7ea02018-05-07 20:01:012114 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:102115 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]f9a26d72010-08-03 18:07:132116 helper.RunPreTestSetup();
mmenke666a6fea2015-12-19 04:16:332117 helper.AddData(&data);
bnc4d782f492016-08-18 13:50:002118 helper.StartDefaultTest();
2119 EXPECT_THAT(helper.output().rv, IsError(ERR_IO_PENDING));
[email protected]f9a26d72010-08-03 18:07:132120
bnc4d782f492016-08-18 13:50:002121 helper.WaitForCallbackToComplete();
2122 EXPECT_THAT(helper.output().rv, IsOk());
[email protected]3b7828432010-08-18 18:33:272123
[email protected]f9a26d72010-08-03 18:07:132124 helper.ResetTrans();
mmenke666a6fea2015-12-19 04:16:332125 base::RunLoop().RunUntilIdle();
[email protected]3b7828432010-08-18 18:33:272126
[email protected]f9a26d72010-08-03 18:07:132127 helper.VerifyDataConsumed();
2128}
2129
[email protected]93300672009-10-24 13:22:512130// Test that the transaction doesn't crash when we don't have a reply.
bnc42331402016-07-25 13:36:152131TEST_F(SpdyNetworkTransactionTest, ResponseWithoutHeaders) {
Ryan Hamilton0239aac2018-05-19 00:03:132132 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]ff57bb82009-11-12 06:52:142133 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:412134 CreateMockRead(body, 1), MockRead(ASYNC, 0, 3) // EOF
[email protected]93300672009-10-24 13:22:512135 };
2136
Ryan Hamilton0239aac2018-05-19 00:03:132137 spdy::SpdySerializedFrame req(
2138 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
2139 spdy::SpdySerializedFrame rst(
2140 spdy_util_.ConstructSpdyRstStream(1, spdy::ERROR_CODE_PROTOCOL_ERROR));
rch08e3aa3e2015-05-16 14:27:522141 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:412142 CreateMockWrite(req, 0), CreateMockWrite(rst, 2),
rch08e3aa3e2015-05-16 14:27:522143 };
Ryan Sleevib8d7ea02018-05-07 20:01:012144 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:102145 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]dd54bd82012-07-19 23:44:572146 helper.RunToCompletion(&data);
[email protected]3caf5542010-07-16 15:19:472147 TransactionHelperResult out = helper.output();
Bence Békyd0d69502019-06-25 19:47:182148 EXPECT_THAT(out.rv, IsError(ERR_HTTP2_PROTOCOL_ERROR));
[email protected]93300672009-10-24 13:22:512149}
2150
[email protected]d30022352010-06-24 19:17:582151// Test that the transaction doesn't crash when we get two replies on the same
2152// stream ID. See http://crbug.com/45639.
bncd16676a2016-07-20 16:23:012153TEST_F(SpdyNetworkTransactionTest, ResponseWithTwoSynReplies) {
Ryan Hamilton0239aac2018-05-19 00:03:132154 spdy::SpdySerializedFrame req(
2155 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
2156 spdy::SpdySerializedFrame rst(
2157 spdy_util_.ConstructSpdyRstStream(1, spdy::ERROR_CODE_PROTOCOL_ERROR));
[email protected]2aeef782013-06-21 18:30:562158 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:412159 CreateMockWrite(req, 0), CreateMockWrite(rst, 4),
[email protected]2aeef782013-06-21 18:30:562160 };
[email protected]d30022352010-06-24 19:17:582161
Ryan Hamilton0239aac2018-05-19 00:03:132162 spdy::SpdySerializedFrame resp0(
2163 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
2164 spdy::SpdySerializedFrame resp1(
2165 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
2166 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]d30022352010-06-24 19:17:582167 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:412168 CreateMockRead(resp0, 1), CreateMockRead(resp1, 2),
2169 CreateMockRead(body, 3), MockRead(ASYNC, 0, 5) // EOF
[email protected]d30022352010-06-24 19:17:582170 };
2171
Ryan Sleevib8d7ea02018-05-07 20:01:012172 SequencedSocketData data(reads, writes);
[email protected]d30022352010-06-24 19:17:582173
Bence Békydb3cf652017-10-10 15:22:102174 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]3caf5542010-07-16 15:19:472175 helper.RunPreTestSetup();
[email protected]dd54bd82012-07-19 23:44:572176 helper.AddData(&data);
[email protected]3caf5542010-07-16 15:19:472177
2178 HttpNetworkTransaction* trans = helper.trans();
[email protected]d30022352010-06-24 19:17:582179
[email protected]49639fa2011-12-20 23:22:412180 TestCompletionCallback callback;
Bence Békydb3cf652017-10-10 15:22:102181 int rv = trans->Start(&request_, callback.callback(), log_);
robpercival214763f2016-07-01 23:27:012182 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]d30022352010-06-24 19:17:582183 rv = callback.WaitForResult();
robpercival214763f2016-07-01 23:27:012184 EXPECT_THAT(rv, IsOk());
[email protected]d30022352010-06-24 19:17:582185
2186 const HttpResponseInfo* response = trans->GetResponseInfo();
wezca1070932016-05-26 20:30:522187 ASSERT_TRUE(response);
2188 EXPECT_TRUE(response->headers);
[email protected]d30022352010-06-24 19:17:582189 EXPECT_TRUE(response->was_fetched_via_spdy);
Bence Béky4e83f492018-05-13 23:14:252190 std::string response_data;
[email protected]3caf5542010-07-16 15:19:472191 rv = ReadTransaction(trans, &response_data);
Bence Békyd0d69502019-06-25 19:47:182192 EXPECT_THAT(rv, IsError(ERR_HTTP2_PROTOCOL_ERROR));
[email protected]3caf5542010-07-16 15:19:472193
2194 helper.VerifyDataConsumed();
[email protected]d30022352010-06-24 19:17:582195}
2196
bncd16676a2016-07-20 16:23:012197TEST_F(SpdyNetworkTransactionTest, ResetReplyWithTransferEncoding) {
[email protected]b3503002012-03-27 04:57:252198 // Construct the request.
Ryan Hamilton0239aac2018-05-19 00:03:132199 spdy::SpdySerializedFrame req(
2200 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
2201 spdy::SpdySerializedFrame rst(
2202 spdy_util_.ConstructSpdyRstStream(1, spdy::ERROR_CODE_PROTOCOL_ERROR));
[email protected]b3503002012-03-27 04:57:252203 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:412204 CreateMockWrite(req, 0), CreateMockWrite(rst, 2),
[email protected]b3503002012-03-27 04:57:252205 };
2206
2207 const char* const headers[] = {
[email protected]513963e2013-06-15 01:53:042208 "transfer-encoding", "chunked"
[email protected]b3503002012-03-27 04:57:252209 };
Ryan Hamilton0239aac2018-05-19 00:03:132210 spdy::SpdySerializedFrame resp(
2211 spdy_util_.ConstructSpdyGetReply(headers, 1, 1));
2212 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]b3503002012-03-27 04:57:252213 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:412214 CreateMockRead(resp, 1), CreateMockRead(body, 3),
rch08e3aa3e2015-05-16 14:27:522215 MockRead(ASYNC, 0, 4) // EOF
[email protected]b3503002012-03-27 04:57:252216 };
2217
Ryan Sleevib8d7ea02018-05-07 20:01:012218 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:102219 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]dd54bd82012-07-19 23:44:572220 helper.RunToCompletion(&data);
[email protected]b3503002012-03-27 04:57:252221 TransactionHelperResult out = helper.output();
Bence Békyd0d69502019-06-25 19:47:182222 EXPECT_THAT(out.rv, IsError(ERR_HTTP2_PROTOCOL_ERROR));
[email protected]b3503002012-03-27 04:57:252223
2224 helper.session()->spdy_session_pool()->CloseAllSessions();
2225 helper.VerifyDataConsumed();
2226}
2227
bncd16676a2016-07-20 16:23:012228TEST_F(SpdyNetworkTransactionTest, ResetPushWithTransferEncoding) {
[email protected]b3503002012-03-27 04:57:252229 // Construct the request.
Ryan Hamilton0239aac2018-05-19 00:03:132230 spdy::SpdySerializedFrame req(
2231 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
2232 spdy::SpdySerializedFrame priority(
tombergan5d22c182017-01-11 02:05:352233 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true));
Ryan Hamilton0239aac2018-05-19 00:03:132234 spdy::SpdySerializedFrame rst(
2235 spdy_util_.ConstructSpdyRstStream(2, spdy::ERROR_CODE_PROTOCOL_ERROR));
[email protected]b3503002012-03-27 04:57:252236 MockWrite writes[] = {
tombergan5d22c182017-01-11 02:05:352237 CreateMockWrite(req, 0), CreateMockWrite(priority, 3),
2238 CreateMockWrite(rst, 5),
[email protected]b3503002012-03-27 04:57:252239 };
2240
Ryan Hamilton0239aac2018-05-19 00:03:132241 spdy::SpdySerializedFrame resp(
2242 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
[email protected]513963e2013-06-15 01:53:042243 const char* const headers[] = {
2244 "transfer-encoding", "chunked"
2245 };
Ryan Hamilton0239aac2018-05-19 00:03:132246 spdy::SpdySerializedFrame push(spdy_util_.ConstructSpdyPush(
Avi Drissman4365a4782018-12-28 19:26:242247 headers, base::size(headers) / 2, 2, 1, "https://www.example.org/1"));
Ryan Hamilton0239aac2018-05-19 00:03:132248 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]b3503002012-03-27 04:57:252249 MockRead reads[] = {
tombergan5d22c182017-01-11 02:05:352250 CreateMockRead(resp, 1), CreateMockRead(push, 2), CreateMockRead(body, 4),
2251 MockRead(ASYNC, 0, 6) // EOF
[email protected]b3503002012-03-27 04:57:252252 };
2253
Ryan Sleevib8d7ea02018-05-07 20:01:012254 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:102255 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]dd54bd82012-07-19 23:44:572256 helper.RunToCompletion(&data);
[email protected]b3503002012-03-27 04:57:252257 TransactionHelperResult out = helper.output();
robpercival214763f2016-07-01 23:27:012258 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:022259 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]b3503002012-03-27 04:57:252260 EXPECT_EQ("hello!", out.response_data);
2261
2262 helper.session()->spdy_session_pool()->CloseAllSessions();
2263 helper.VerifyDataConsumed();
2264}
2265
bncd16676a2016-07-20 16:23:012266TEST_F(SpdyNetworkTransactionTest, CancelledTransaction) {
[email protected]75f30cc22010-06-28 21:41:382267 // Construct the request.
Ryan Hamilton0239aac2018-05-19 00:03:132268 spdy::SpdySerializedFrame req(
2269 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
[email protected]34437af82009-11-06 02:28:492270 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:412271 CreateMockWrite(req),
[email protected]34437af82009-11-06 02:28:492272 };
2273
Ryan Hamilton0239aac2018-05-19 00:03:132274 spdy::SpdySerializedFrame resp(
2275 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
[email protected]34437af82009-11-06 02:28:492276 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:412277 CreateMockRead(resp),
2278 // This following read isn't used by the test, except during the
2279 // RunUntilIdle() call at the end since the SpdySession survives the
2280 // HttpNetworkTransaction and still tries to continue Read()'ing. Any
2281 // MockRead will do here.
2282 MockRead(ASYNC, 0, 0) // EOF
[email protected]34437af82009-11-06 02:28:492283 };
2284
Ryan Sleevib8d7ea02018-05-07 20:01:012285 StaticSocketDataProvider data(reads, writes);
[email protected]3caf5542010-07-16 15:19:472286
Bence Békydb3cf652017-10-10 15:22:102287 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]3caf5542010-07-16 15:19:472288 helper.RunPreTestSetup();
[email protected]e3ebba0f2010-08-05 17:59:582289 helper.AddData(&data);
[email protected]3caf5542010-07-16 15:19:472290 HttpNetworkTransaction* trans = helper.trans();
[email protected]34437af82009-11-06 02:28:492291
[email protected]49639fa2011-12-20 23:22:412292 TestCompletionCallback callback;
Bence Békydb3cf652017-10-10 15:22:102293 int rv = trans->Start(&request_, callback.callback(), log_);
robpercival214763f2016-07-01 23:27:012294 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]3caf5542010-07-16 15:19:472295 helper.ResetTrans(); // Cancel the transaction.
[email protected]34437af82009-11-06 02:28:492296
[email protected]30c942b2010-07-21 16:59:592297 // Flush the MessageLoop while the SpdySessionDependencies (in particular, the
[email protected]34437af82009-11-06 02:28:492298 // MockClientSocketFactory) are still alive.
[email protected]fc9d88472013-08-14 02:31:172299 base::RunLoop().RunUntilIdle();
[email protected]3caf5542010-07-16 15:19:472300 helper.VerifyDataNotConsumed();
[email protected]34437af82009-11-06 02:28:492301}
[email protected]72552f02009-10-28 15:25:012302
[email protected]6c6ea172010-07-27 20:04:032303// Verify that the client sends a Rst Frame upon cancelling the stream.
bncd16676a2016-07-20 16:23:012304TEST_F(SpdyNetworkTransactionTest, CancelledTransactionSendRst) {
Ryan Hamilton0239aac2018-05-19 00:03:132305 spdy::SpdySerializedFrame req(
2306 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
2307 spdy::SpdySerializedFrame rst(
2308 spdy_util_.ConstructSpdyRstStream(1, spdy::ERROR_CODE_CANCEL));
[email protected]6c6ea172010-07-27 20:04:032309 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:412310 CreateMockWrite(req, 0, SYNCHRONOUS),
2311 CreateMockWrite(rst, 2, SYNCHRONOUS),
[email protected]6c6ea172010-07-27 20:04:032312 };
2313
Ryan Hamilton0239aac2018-05-19 00:03:132314 spdy::SpdySerializedFrame resp(
2315 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
[email protected]6c6ea172010-07-27 20:04:032316 MockRead reads[] = {
Raul Tambre94493c652019-03-11 17:18:352317 CreateMockRead(resp, 1, ASYNC), MockRead(ASYNC, nullptr, 0, 3) // EOF
[email protected]6c6ea172010-07-27 20:04:032318 };
2319
Ryan Sleevib8d7ea02018-05-07 20:01:012320 SequencedSocketData data(reads, writes);
[email protected]6c6ea172010-07-27 20:04:032321
Bence Békydb3cf652017-10-10 15:22:102322 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]6c6ea172010-07-27 20:04:032323 helper.RunPreTestSetup();
mmenke666a6fea2015-12-19 04:16:332324 helper.AddData(&data);
[email protected]6c6ea172010-07-27 20:04:032325 HttpNetworkTransaction* trans = helper.trans();
2326
[email protected]49639fa2011-12-20 23:22:412327 TestCompletionCallback callback;
[email protected]6c6ea172010-07-27 20:04:032328
Bence Békydb3cf652017-10-10 15:22:102329 int rv = trans->Start(&request_, callback.callback(), log_);
robpercival214763f2016-07-01 23:27:012330 EXPECT_THAT(callback.GetResult(rv), IsOk());
[email protected]6c6ea172010-07-27 20:04:032331
[email protected]3b7828432010-08-18 18:33:272332 helper.ResetTrans();
mmenke666a6fea2015-12-19 04:16:332333 base::RunLoop().RunUntilIdle();
[email protected]3b7828432010-08-18 18:33:272334
[email protected]6c6ea172010-07-27 20:04:032335 helper.VerifyDataConsumed();
2336}
2337
[email protected]b278eb72010-07-09 20:17:002338// Verify that the client can correctly deal with the user callback attempting
2339// to start another transaction on a session that is closing down. See
2340// http://crbug.com/47455
bncd16676a2016-07-20 16:23:012341TEST_F(SpdyNetworkTransactionTest, StartTransactionOnReadCallback) {
Ryan Hamilton0239aac2018-05-19 00:03:132342 spdy::SpdySerializedFrame req(
2343 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
bncdf80d44fd2016-07-15 20:27:412344 MockWrite writes[] = {CreateMockWrite(req)};
bnceb9aa7112017-01-05 01:03:462345 MockWrite writes2[] = {CreateMockWrite(req, 0),
2346 MockWrite(SYNCHRONOUS, ERR_IO_PENDING, 3)};
[email protected]b278eb72010-07-09 20:17:002347
[email protected]cbdd73162013-03-18 23:27:332348 // The indicated length of this frame is longer than its actual length. When
2349 // the session receives an empty frame after this one, it shuts down the
[email protected]b278eb72010-07-09 20:17:002350 // session, and calls the read callback with the incomplete data.
Avi Drissman13fc8932015-12-20 04:40:462351 const uint8_t kGetBodyFrame2[] = {
2352 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00,
2353 0x07, 'h', 'e', 'l', 'l', 'o', '!',
[email protected]b278eb72010-07-09 20:17:002354 };
2355
Ryan Hamilton0239aac2018-05-19 00:03:132356 spdy::SpdySerializedFrame resp(
2357 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
[email protected]b278eb72010-07-09 20:17:002358 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:412359 CreateMockRead(resp, 1),
rch32320842015-05-16 15:57:092360 MockRead(ASYNC, ERR_IO_PENDING, 2), // Force a pause
2361 MockRead(ASYNC, reinterpret_cast<const char*>(kGetBodyFrame2),
Avi Drissman4365a4782018-12-28 19:26:242362 base::size(kGetBodyFrame2), 3),
rch32320842015-05-16 15:57:092363 MockRead(ASYNC, ERR_IO_PENDING, 4), // Force a pause
Raul Tambre94493c652019-03-11 17:18:352364 MockRead(ASYNC, nullptr, 0, 5), // EOF
[email protected]b278eb72010-07-09 20:17:002365 };
2366 MockRead reads2[] = {
Raul Tambre94493c652019-03-11 17:18:352367 CreateMockRead(resp, 1), MockRead(ASYNC, nullptr, 0, 2), // EOF
[email protected]b278eb72010-07-09 20:17:002368 };
2369
Ryan Sleevib8d7ea02018-05-07 20:01:012370 SequencedSocketData data(reads, writes);
2371 SequencedSocketData data2(reads2, writes2);
[email protected]3caf5542010-07-16 15:19:472372
Bence Békydb3cf652017-10-10 15:22:102373 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]e3ebba0f2010-08-05 17:59:582374 helper.RunPreTestSetup();
[email protected]dd54bd82012-07-19 23:44:572375 helper.AddData(&data);
2376 helper.AddData(&data2);
[email protected]3caf5542010-07-16 15:19:472377 HttpNetworkTransaction* trans = helper.trans();
[email protected]b278eb72010-07-09 20:17:002378
2379 // Start the transaction with basic parameters.
[email protected]49639fa2011-12-20 23:22:412380 TestCompletionCallback callback;
Bence Békydb3cf652017-10-10 15:22:102381 int rv = trans->Start(&request_, callback.callback(), log_);
robpercival214763f2016-07-01 23:27:012382 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]b278eb72010-07-09 20:17:002383 rv = callback.WaitForResult();
2384
[email protected]b278eb72010-07-09 20:17:002385 const int kSize = 3000;
Victor Costan9c7302b2018-08-27 16:39:442386 scoped_refptr<IOBuffer> buf = base::MakeRefCounted<IOBuffer>(kSize);
[email protected]49639fa2011-12-20 23:22:412387 rv = trans->Read(
rchebf12982015-04-10 01:15:002388 buf.get(), kSize,
Yannic Bonenberger00e09842019-08-31 20:46:192389 base::BindOnce(&SpdyNetworkTransactionTest::StartTransactionCallback,
2390 helper.session(), default_url_, log_));
robpercival214763f2016-07-01 23:27:012391 ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]3caf5542010-07-16 15:19:472392 // This forces an err_IO_pending, which sets the callback.
mmenkee24011922015-12-17 22:12:592393 data.Resume();
2394 data.RunUntilPaused();
2395
[email protected]3caf5542010-07-16 15:19:472396 // This finishes the read.
mmenkee24011922015-12-17 22:12:592397 data.Resume();
2398 base::RunLoop().RunUntilIdle();
[email protected]3caf5542010-07-16 15:19:472399 helper.VerifyDataConsumed();
[email protected]b278eb72010-07-09 20:17:002400}
2401
Mostyn Bramley-Moore699c5312018-05-01 10:48:092402// Verify that the client can correctly deal with the user callback deleting
2403// the transaction. Failures will usually be flagged by thread and/or memory
2404// checking tools. See http://crbug.com/46925
bncd16676a2016-07-20 16:23:012405TEST_F(SpdyNetworkTransactionTest, DeleteSessionOnReadCallback) {
Ryan Hamilton0239aac2018-05-19 00:03:132406 spdy::SpdySerializedFrame req(
2407 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
bncdf80d44fd2016-07-15 20:27:412408 MockWrite writes[] = {CreateMockWrite(req, 0)};
[email protected]9be804c82010-06-24 17:59:462409
Ryan Hamilton0239aac2018-05-19 00:03:132410 spdy::SpdySerializedFrame resp(
2411 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
2412 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]9be804c82010-06-24 17:59:462413 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:412414 CreateMockRead(resp, 1),
Raul Tambre94493c652019-03-11 17:18:352415 MockRead(ASYNC, ERR_IO_PENDING, 2), // Force a pause
2416 CreateMockRead(body, 3), MockRead(ASYNC, nullptr, 0, 4), // EOF
[email protected]9be804c82010-06-24 17:59:462417 };
2418
Ryan Sleevib8d7ea02018-05-07 20:01:012419 SequencedSocketData data(reads, writes);
[email protected]3caf5542010-07-16 15:19:472420
Bence Békydb3cf652017-10-10 15:22:102421 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]3caf5542010-07-16 15:19:472422 helper.RunPreTestSetup();
[email protected]dd54bd82012-07-19 23:44:572423 helper.AddData(&data);
[email protected]3caf5542010-07-16 15:19:472424 HttpNetworkTransaction* trans = helper.trans();
[email protected]9be804c82010-06-24 17:59:462425
2426 // Start the transaction with basic parameters.
[email protected]49639fa2011-12-20 23:22:412427 TestCompletionCallback callback;
Bence Békydb3cf652017-10-10 15:22:102428 int rv = trans->Start(&request_, callback.callback(), log_);
robpercival214763f2016-07-01 23:27:012429 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]9be804c82010-06-24 17:59:462430 rv = callback.WaitForResult();
2431
2432 // Setup a user callback which will delete the session, and clear out the
2433 // memory holding the stream object. Note that the callback deletes trans.
[email protected]9be804c82010-06-24 17:59:462434 const int kSize = 3000;
Victor Costan9c7302b2018-08-27 16:39:442435 scoped_refptr<IOBuffer> buf = base::MakeRefCounted<IOBuffer>(kSize);
[email protected]49639fa2011-12-20 23:22:412436 rv = trans->Read(
Yannic Bonenberger00e09842019-08-31 20:46:192437 buf.get(), kSize,
2438 base::BindOnce(&SpdyNetworkTransactionTest::DeleteSessionCallback,
2439 base::Unretained(&helper)));
robpercival214763f2016-07-01 23:27:012440 ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
mmenkee24011922015-12-17 22:12:592441 data.Resume();
[email protected]9be804c82010-06-24 17:59:462442
2443 // Finish running rest of tasks.
[email protected]fc9d88472013-08-14 02:31:172444 base::RunLoop().RunUntilIdle();
[email protected]3caf5542010-07-16 15:19:472445 helper.VerifyDataConsumed();
[email protected]9be804c82010-06-24 17:59:462446}
2447
bncf2ba58832017-06-07 00:22:282448TEST_F(SpdyNetworkTransactionTest, RedirectGetRequest) {
2449 SpdyURLRequestContext spdy_url_request_context;
Matt Menke5062be22019-05-01 17:50:242450 // Use a different port to avoid trying to reuse the initial H2 session.
2451 const char kRedirectUrl[] = "https://www.foo.com:8080/index.php";
[email protected]e3ebba0f2010-08-05 17:59:582452
bncf2ba58832017-06-07 00:22:282453 SSLSocketDataProvider ssl_provider0(ASYNC, OK);
2454 ssl_provider0.next_proto = kProtoHTTP2;
2455 spdy_url_request_context.socket_factory().AddSSLSocketDataProvider(
2456 &ssl_provider0);
[email protected]e3ebba0f2010-08-05 17:59:582457
Bence Béky4c325e52020-10-22 20:48:012458 spdy::Http2HeaderBlock headers0(
Ryan Hamilton0239aac2018-05-19 00:03:132459 spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
bncf2ba58832017-06-07 00:22:282460 headers0["user-agent"] = "";
2461 headers0["accept-encoding"] = "gzip, deflate";
bnc086b39e12016-06-24 13:05:262462
Ryan Hamilton0239aac2018-05-19 00:03:132463 spdy::SpdySerializedFrame req0(
bncf2ba58832017-06-07 00:22:282464 spdy_util_.ConstructSpdyHeaders(1, std::move(headers0), LOWEST, true));
Ryan Hamilton0239aac2018-05-19 00:03:132465 spdy::SpdySerializedFrame rst(
2466 spdy_util_.ConstructSpdyRstStream(1, spdy::ERROR_CODE_CANCEL));
Shivani Sharmac18f9762017-10-23 16:43:232467 MockWrite writes0[] = {CreateMockWrite(req0, 0), CreateMockWrite(rst, 2)};
bnc086b39e12016-06-24 13:05:262468
Matt Menke5062be22019-05-01 17:50:242469 const char* const kExtraHeaders[] = {"location", kRedirectUrl};
Ryan Hamilton0239aac2018-05-19 00:03:132470 spdy::SpdySerializedFrame resp0(spdy_util_.ConstructSpdyReplyError(
Avi Drissman4365a4782018-12-28 19:26:242471 "301", kExtraHeaders, base::size(kExtraHeaders) / 2, 1));
Shivani Sharmac18f9762017-10-23 16:43:232472 MockRead reads0[] = {CreateMockRead(resp0, 1), MockRead(ASYNC, 0, 3)};
[email protected]e3ebba0f2010-08-05 17:59:582473
Ryan Sleevib8d7ea02018-05-07 20:01:012474 SequencedSocketData data0(reads0, writes0);
bncf2ba58832017-06-07 00:22:282475 spdy_url_request_context.socket_factory().AddSocketDataProvider(&data0);
[email protected]e3ebba0f2010-08-05 17:59:582476
bncf2ba58832017-06-07 00:22:282477 SSLSocketDataProvider ssl_provider1(ASYNC, OK);
2478 ssl_provider1.next_proto = kProtoHTTP2;
2479 spdy_url_request_context.socket_factory().AddSSLSocketDataProvider(
2480 &ssl_provider1);
[email protected]513963e2013-06-15 01:53:042481
bncf2ba58832017-06-07 00:22:282482 SpdyTestUtil spdy_util1;
Bence Béky4c325e52020-10-22 20:48:012483 spdy::Http2HeaderBlock headers1(
Matt Menke5062be22019-05-01 17:50:242484 spdy_util1.ConstructGetHeaderBlock(kRedirectUrl));
bncf2ba58832017-06-07 00:22:282485 headers1["user-agent"] = "";
2486 headers1["accept-encoding"] = "gzip, deflate";
Ryan Hamilton0239aac2018-05-19 00:03:132487 spdy::SpdySerializedFrame req1(
bncf2ba58832017-06-07 00:22:282488 spdy_util1.ConstructSpdyHeaders(1, std::move(headers1), LOWEST, true));
2489 MockWrite writes1[] = {CreateMockWrite(req1, 0)};
[email protected]e3ebba0f2010-08-05 17:59:582490
Ryan Hamilton0239aac2018-05-19 00:03:132491 spdy::SpdySerializedFrame resp1(
2492 spdy_util1.ConstructSpdyGetReply(nullptr, 0, 1));
2493 spdy::SpdySerializedFrame body1(spdy_util1.ConstructSpdyDataFrame(1, true));
bncf2ba58832017-06-07 00:22:282494 MockRead reads1[] = {CreateMockRead(resp1, 1), CreateMockRead(body1, 2),
2495 MockRead(ASYNC, 0, 3)};
2496
Ryan Sleevib8d7ea02018-05-07 20:01:012497 SequencedSocketData data1(reads1, writes1);
bncf2ba58832017-06-07 00:22:282498 spdy_url_request_context.socket_factory().AddSocketDataProvider(&data1);
2499
2500 TestDelegate delegate;
bncf2ba58832017-06-07 00:22:282501
2502 std::unique_ptr<URLRequest> request = spdy_url_request_context.CreateRequest(
2503 default_url_, DEFAULT_PRIORITY, &delegate, TRAFFIC_ANNOTATION_FOR_TESTS);
2504 request->Start();
Wez0e717112018-06-18 23:09:222505 delegate.RunUntilRedirect();
bncf2ba58832017-06-07 00:22:282506
2507 EXPECT_EQ(1, delegate.received_redirect_count());
2508
Anton Bikineev068d2912021-05-15 20:43:522509 request->FollowDeferredRedirect(absl::nullopt /* removed_headers */,
2510 absl::nullopt /* modified_headers */);
Wez0e717112018-06-18 23:09:222511 delegate.RunUntilComplete();
bncf2ba58832017-06-07 00:22:282512
2513 EXPECT_EQ(1, delegate.response_started_count());
2514 EXPECT_FALSE(delegate.received_data_before_response());
2515 EXPECT_THAT(delegate.request_status(), IsOk());
2516 EXPECT_EQ("hello!", delegate.data_received());
2517
Wez0e717112018-06-18 23:09:222518 // Pump the message loop to allow read data to be consumed.
2519 base::RunLoop().RunUntilIdle();
2520
bncf2ba58832017-06-07 00:22:282521 EXPECT_TRUE(data0.AllReadDataConsumed());
2522 EXPECT_TRUE(data0.AllWriteDataConsumed());
2523 EXPECT_TRUE(data1.AllReadDataConsumed());
2524 EXPECT_TRUE(data1.AllWriteDataConsumed());
[email protected]e3ebba0f2010-08-05 17:59:582525}
2526
bncf2ba58832017-06-07 00:22:282527TEST_F(SpdyNetworkTransactionTest, RedirectServerPush) {
bncf2ba58832017-06-07 00:22:282528 const char redirected_url[] = "https://www.foo.com/index.php";
2529 SpdyURLRequestContext spdy_url_request_context;
[email protected]3a8d6852011-03-11 23:43:442530
bncf2ba58832017-06-07 00:22:282531 SSLSocketDataProvider ssl_provider0(ASYNC, OK);
2532 ssl_provider0.next_proto = kProtoHTTP2;
Ryan Sleevi4f832092017-11-21 23:25:492533 ssl_provider0.ssl_info.cert =
bncf2ba58832017-06-07 00:22:282534 ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem");
Ryan Sleevi4f832092017-11-21 23:25:492535 ASSERT_TRUE(ssl_provider0.ssl_info.cert);
bncf2ba58832017-06-07 00:22:282536 spdy_url_request_context.socket_factory().AddSSLSocketDataProvider(
2537 &ssl_provider0);
2538
Bence Béky4c325e52020-10-22 20:48:012539 spdy::Http2HeaderBlock headers0(
Ryan Hamilton0239aac2018-05-19 00:03:132540 spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
bncf2ba58832017-06-07 00:22:282541 headers0["user-agent"] = "";
2542 headers0["accept-encoding"] = "gzip, deflate";
Ryan Hamilton0239aac2018-05-19 00:03:132543 spdy::SpdySerializedFrame req0(
bncf2ba58832017-06-07 00:22:282544 spdy_util_.ConstructSpdyHeaders(1, std::move(headers0), LOWEST, true));
Ryan Hamilton0239aac2018-05-19 00:03:132545 spdy::SpdySerializedFrame priority(
bncf2ba58832017-06-07 00:22:282546 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true));
Ryan Hamilton0239aac2018-05-19 00:03:132547 spdy::SpdySerializedFrame rst(
2548 spdy_util_.ConstructSpdyRstStream(2, spdy::ERROR_CODE_CANCEL));
bncf2ba58832017-06-07 00:22:282549 MockWrite writes[] = {CreateMockWrite(req0, 0), CreateMockWrite(priority, 3),
2550 CreateMockWrite(rst, 5)};
[email protected]3a8d6852011-03-11 23:43:442551
Ryan Hamilton0239aac2018-05-19 00:03:132552 spdy::SpdySerializedFrame resp0(
2553 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
2554 spdy::SpdySerializedFrame push(spdy_util_.ConstructSpdyPush(
Bence Békyd2df6c1c82018-04-20 22:52:012555 nullptr, 0, 2, 1, kPushedUrl, "301", redirected_url));
Ryan Hamilton0239aac2018-05-19 00:03:132556 spdy::SpdySerializedFrame body0(spdy_util_.ConstructSpdyDataFrame(1, true));
bncf2ba58832017-06-07 00:22:282557 MockRead reads[] = {CreateMockRead(resp0, 1), CreateMockRead(push, 2),
2558 CreateMockRead(body0, 4), MockRead(ASYNC, 0, 6)};
[email protected]e3ebba0f2010-08-05 17:59:582559
Ryan Sleevib8d7ea02018-05-07 20:01:012560 SequencedSocketData data0(reads, writes);
bncf2ba58832017-06-07 00:22:282561 spdy_url_request_context.socket_factory().AddSocketDataProvider(&data0);
[email protected]e3ebba0f2010-08-05 17:59:582562
bncf2ba58832017-06-07 00:22:282563 SSLSocketDataProvider ssl_provider1(ASYNC, OK);
2564 ssl_provider1.next_proto = kProtoHTTP2;
2565 spdy_url_request_context.socket_factory().AddSSLSocketDataProvider(
2566 &ssl_provider1);
[email protected]e3ebba0f2010-08-05 17:59:582567
bncf2ba58832017-06-07 00:22:282568 SpdyTestUtil spdy_util1;
Bence Béky4c325e52020-10-22 20:48:012569 spdy::Http2HeaderBlock headers1(
Ryan Hamilton0239aac2018-05-19 00:03:132570 spdy_util1.ConstructGetHeaderBlock(redirected_url));
bncf2ba58832017-06-07 00:22:282571 headers1["user-agent"] = "";
2572 headers1["accept-encoding"] = "gzip, deflate";
Ryan Hamilton0239aac2018-05-19 00:03:132573 spdy::SpdySerializedFrame req1(
bncf2ba58832017-06-07 00:22:282574 spdy_util1.ConstructSpdyHeaders(1, std::move(headers1), LOWEST, true));
2575 MockWrite writes1[] = {CreateMockWrite(req1, 0)};
[email protected]e3ebba0f2010-08-05 17:59:582576
Ryan Hamilton0239aac2018-05-19 00:03:132577 spdy::SpdySerializedFrame resp1(
2578 spdy_util1.ConstructSpdyGetReply(nullptr, 0, 1));
2579 spdy::SpdySerializedFrame body1(spdy_util1.ConstructSpdyDataFrame(1, true));
bncf2ba58832017-06-07 00:22:282580 MockRead reads1[] = {CreateMockRead(resp1, 1), CreateMockRead(body1, 2),
2581 MockRead(ASYNC, 0, 3)};
[email protected]e3ebba0f2010-08-05 17:59:582582
Ryan Sleevib8d7ea02018-05-07 20:01:012583 SequencedSocketData data1(reads1, writes1);
bncf2ba58832017-06-07 00:22:282584 spdy_url_request_context.socket_factory().AddSocketDataProvider(&data1);
[email protected]e3ebba0f2010-08-05 17:59:582585
bncf2ba58832017-06-07 00:22:282586 TestDelegate delegate0;
2587 std::unique_ptr<URLRequest> request = spdy_url_request_context.CreateRequest(
2588 default_url_, DEFAULT_PRIORITY, &delegate0, TRAFFIC_ANNOTATION_FOR_TESTS);
2589
2590 request->Start();
Wez0e717112018-06-18 23:09:222591 delegate0.RunUntilComplete();
bncf2ba58832017-06-07 00:22:282592
2593 EXPECT_EQ(0, delegate0.received_redirect_count());
2594 EXPECT_EQ("hello!", delegate0.data_received());
2595
2596 TestDelegate delegate1;
2597 std::unique_ptr<URLRequest> request1 = spdy_url_request_context.CreateRequest(
Bence Békyd2df6c1c82018-04-20 22:52:012598 GURL(kPushedUrl), DEFAULT_PRIORITY, &delegate1,
2599 TRAFFIC_ANNOTATION_FOR_TESTS);
bncf2ba58832017-06-07 00:22:282600
bncf2ba58832017-06-07 00:22:282601 request1->Start();
Wez0e717112018-06-18 23:09:222602 delegate1.RunUntilRedirect();
bncf2ba58832017-06-07 00:22:282603 EXPECT_EQ(1, delegate1.received_redirect_count());
2604
Anton Bikineev068d2912021-05-15 20:43:522605 request1->FollowDeferredRedirect(absl::nullopt /* removed_headers */,
2606 absl::nullopt /* modified_headers */);
Wez0e717112018-06-18 23:09:222607 delegate1.RunUntilComplete();
bncf2ba58832017-06-07 00:22:282608 EXPECT_EQ(1, delegate1.response_started_count());
2609 EXPECT_FALSE(delegate1.received_data_before_response());
2610 EXPECT_EQ(OK, delegate1.request_status());
2611 EXPECT_EQ("hello!", delegate1.data_received());
2612
Wez0e717112018-06-18 23:09:222613 // Pump the message loop to allow read data to be consumed.
2614 base::RunLoop().RunUntilIdle();
2615
bncf2ba58832017-06-07 00:22:282616 EXPECT_TRUE(data0.AllReadDataConsumed());
2617 EXPECT_TRUE(data0.AllWriteDataConsumed());
2618 EXPECT_TRUE(data1.AllReadDataConsumed());
2619 EXPECT_TRUE(data1.AllWriteDataConsumed());
[email protected]e3ebba0f2010-08-05 17:59:582620}
2621
bncd16676a2016-07-20 16:23:012622TEST_F(SpdyNetworkTransactionTest, ServerPushSingleDataFrame) {
Ryan Hamilton0239aac2018-05-19 00:03:132623 spdy::SpdySerializedFrame stream1_syn(
Bence Béky27ad0a12018-02-08 00:35:482624 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
Ryan Hamilton0239aac2018-05-19 00:03:132625 spdy::SpdySerializedFrame stream2_priority(
tombergan5d22c182017-01-11 02:05:352626 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true));
[email protected]e3ebba0f2010-08-05 17:59:582627 MockWrite writes[] = {
tombergan5d22c182017-01-11 02:05:352628 CreateMockWrite(stream1_syn, 0), CreateMockWrite(stream2_priority, 3),
[email protected]e3ebba0f2010-08-05 17:59:582629 };
2630
Ryan Hamilton0239aac2018-05-19 00:03:132631 spdy::SpdySerializedFrame stream1_reply(
tombergan5d22c182017-01-11 02:05:352632 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
Ryan Hamilton0239aac2018-05-19 00:03:132633 spdy::SpdySerializedFrame stream2_syn(
Bence Békyd2df6c1c82018-04-20 22:52:012634 spdy_util_.ConstructSpdyPush(nullptr, 0, 2, 1, kPushedUrl));
Ryan Hamilton0239aac2018-05-19 00:03:132635 spdy::SpdySerializedFrame stream1_body(
2636 spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]8a0fc822013-06-27 20:52:432637 const char kPushedData[] = "pushed";
Ryan Hamilton0239aac2018-05-19 00:03:132638 spdy::SpdySerializedFrame stream2_body(
Bence Békyd74f4382018-02-20 18:26:192639 spdy_util_.ConstructSpdyDataFrame(2, kPushedData, true));
[email protected]e3ebba0f2010-08-05 17:59:582640 MockRead reads[] = {
tombergan5d22c182017-01-11 02:05:352641 CreateMockRead(stream1_reply, 1), CreateMockRead(stream2_syn, 2),
2642 CreateMockRead(stream1_body, 4), CreateMockRead(stream2_body, 5),
2643 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 6), // Force a pause
[email protected]e3ebba0f2010-08-05 17:59:582644 };
2645
2646 HttpResponseInfo response;
2647 HttpResponseInfo response2;
Bence Béky4e83f492018-05-13 23:14:252648 std::string expected_push_result("pushed");
Ryan Sleevib8d7ea02018-05-07 20:01:012649 SequencedSocketData data(reads, writes);
[email protected]dd54bd82012-07-19 23:44:572650 RunServerPushTest(&data,
[email protected]d08358502010-12-03 22:04:032651 &response,
2652 &response2,
2653 expected_push_result);
[email protected]e3ebba0f2010-08-05 17:59:582654
bnc42331402016-07-25 13:36:152655 // Verify the response headers.
wezca1070932016-05-26 20:30:522656 EXPECT_TRUE(response.headers);
bnc84e7fb52015-12-02 11:50:022657 EXPECT_EQ("HTTP/1.1 200", response.headers->GetStatusLine());
[email protected]e3ebba0f2010-08-05 17:59:582658
2659 // Verify the pushed stream.
wezca1070932016-05-26 20:30:522660 EXPECT_TRUE(response2.headers);
bnccdc749f2016-01-27 16:39:042661 EXPECT_EQ("HTTP/1.1 200", response2.headers->GetStatusLine());
[email protected]e3ebba0f2010-08-05 17:59:582662}
2663
Bence Béky02b906a2018-07-18 21:03:392664// When server push is disabled by
2665// HttpNetworkSession::initial_settings[SETTINGS_ENABLE_PUSH] = 0, verify that
2666// such a setting is sent out in the initial SETTINGS frame, and if the server
2667// creates a pushed stream despite of this, it is immediately reset.
2668TEST_F(SpdyNetworkTransactionTest, ServerPushDisabled) {
Bence Békyda83e052018-07-20 01:03:322669 base::HistogramTester histogram_tester;
2670
Bence Béky02b906a2018-07-18 21:03:392671 spdy::SpdySerializedFrame preface(
2672 const_cast<char*>(spdy::kHttp2ConnectionHeaderPrefix),
2673 spdy::kHttp2ConnectionHeaderPrefixSize,
2674 /* owns_buffer = */ false);
2675
2676 spdy::SettingsMap initial_settings;
2677 initial_settings[spdy::SETTINGS_HEADER_TABLE_SIZE] = kSpdyMaxHeaderTableSize;
2678 initial_settings[spdy::SETTINGS_ENABLE_PUSH] = 0;
2679 initial_settings[spdy::SETTINGS_MAX_CONCURRENT_STREAMS] =
2680 kSpdyMaxConcurrentPushedStreams;
Bence Béky6cee52f2019-10-24 16:52:332681 initial_settings[spdy::SETTINGS_MAX_HEADER_LIST_SIZE] =
2682 kSpdyMaxHeaderListSize;
Bence Béky02b906a2018-07-18 21:03:392683 spdy::SpdySerializedFrame initial_settings_frame(
2684 spdy_util_.ConstructSpdySettings(initial_settings));
2685
2686 spdy::SpdySerializedFrame req(
2687 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
2688 spdy::SpdySerializedFrame rst(
2689 spdy_util_.ConstructSpdyRstStream(2, spdy::ERROR_CODE_REFUSED_STREAM));
2690
2691 MockWrite writes[] = {CreateMockWrite(preface, 0),
2692 CreateMockWrite(initial_settings_frame, 1),
2693 CreateMockWrite(req, 2), CreateMockWrite(rst, 5)};
2694
2695 spdy::SpdySerializedFrame reply(
2696 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
2697 spdy::SpdySerializedFrame push(
2698 spdy_util_.ConstructSpdyPush(nullptr, 0, 2, 1, kPushedUrl));
2699 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
2700 MockRead reads[] = {CreateMockRead(reply, 3), CreateMockRead(push, 4),
2701 CreateMockRead(body, 6), MockRead(ASYNC, OK, 7)};
2702
2703 SequencedSocketData data(reads, writes);
2704
2705 auto session_deps = std::make_unique<SpdySessionDependencies>();
2706 session_deps->http2_settings[spdy::SETTINGS_ENABLE_PUSH] = 0;
2707 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
2708 std::move(session_deps));
2709
2710 SpdySessionPool* spdy_session_pool = helper.session()->spdy_session_pool();
2711 SpdySessionPoolPeer pool_peer(spdy_session_pool);
2712 pool_peer.SetEnableSendingInitialData(true);
2713
2714 helper.RunToCompletion(&data);
Bence Békyda83e052018-07-20 01:03:322715
2716 histogram_tester.ExpectBucketCount(
2717 "Net.SpdyPushedStreamFate",
2718 static_cast<int>(SpdyPushedStreamFate::kPushDisabled), 1);
2719 histogram_tester.ExpectTotalCount("Net.SpdyPushedStreamFate", 1);
Bence Béky02b906a2018-07-18 21:03:392720}
2721
Bence Béky5b1e4ce72018-01-11 14:55:152722TEST_F(SpdyNetworkTransactionTest, ServerPushHeadMethod) {
Ryan Hamilton0239aac2018-05-19 00:03:132723 spdy::SpdySerializedFrame req(
2724 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
2725 spdy::SpdySerializedFrame priority(
Bence Béky5b1e4ce72018-01-11 14:55:152726 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true));
2727 MockWrite writes[] = {CreateMockWrite(req, 0), CreateMockWrite(priority, 2)};
2728
Bence Béky4c325e52020-10-22 20:48:012729 spdy::Http2HeaderBlock push_promise_header_block;
Ryan Hamilton0239aac2018-05-19 00:03:132730 push_promise_header_block[spdy::kHttp2MethodHeader] = "HEAD";
Bence Békyd2df6c1c82018-04-20 22:52:012731 spdy_util_.AddUrlToHeaderBlock(kPushedUrl, &push_promise_header_block);
Ryan Hamilton0239aac2018-05-19 00:03:132732 spdy::SpdySerializedFrame push_promise(spdy_util_.ConstructSpdyPushPromise(
Bence Béky5b1e4ce72018-01-11 14:55:152733 1, 2, std::move(push_promise_header_block)));
2734
Bence Béky4c325e52020-10-22 20:48:012735 spdy::Http2HeaderBlock push_response_headers;
Ryan Hamilton0239aac2018-05-19 00:03:132736 push_response_headers[spdy::kHttp2StatusHeader] = "200";
Bence Béky5b1e4ce72018-01-11 14:55:152737 push_response_headers["foo"] = "bar";
Ryan Hamilton0239aac2018-05-19 00:03:132738 spdy::SpdyHeadersIR headers_ir(2, std::move(push_response_headers));
2739 spdy::SpdySerializedFrame push_headers(spdy_util_.SerializeFrame(headers_ir));
Bence Béky5b1e4ce72018-01-11 14:55:152740
Ryan Hamilton0239aac2018-05-19 00:03:132741 spdy::SpdySerializedFrame resp(
2742 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
2743 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
Bence Béky5b1e4ce72018-01-11 14:55:152744 MockRead reads[] = {
2745 CreateMockRead(push_promise, 1), CreateMockRead(push_headers, 3),
2746 CreateMockRead(resp, 4), CreateMockRead(body, 5),
2747 // Do not close the connection after first request is done.
2748 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 6)};
2749
Ryan Sleevib8d7ea02018-05-07 20:01:012750 SequencedSocketData data(reads, writes);
Bence Béky5b1e4ce72018-01-11 14:55:152751
2752 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
2753 helper.RunPreTestSetup();
2754 helper.AddData(&data);
2755
2756 // Run first request. This reads PUSH_PROMISE.
2757 helper.RunDefaultTest();
2758
2759 // Request the pushed resource.
2760 HttpNetworkTransaction trans(DEFAULT_PRIORITY, helper.session());
2761 HttpRequestInfo request = CreateGetPushRequest();
2762 request.method = "HEAD";
Ramin Halavatib5e433e62018-02-07 07:41:102763 request.traffic_annotation =
2764 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
Bence Béky5b1e4ce72018-01-11 14:55:152765 TestCompletionCallback callback;
2766 int rv = trans.Start(&request, callback.callback(), log_);
2767 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
2768 rv = callback.WaitForResult();
2769 EXPECT_THAT(rv, IsOk());
2770
2771 const HttpResponseInfo* response = trans.GetResponseInfo();
2772 ASSERT_TRUE(response);
2773 EXPECT_TRUE(response->was_fetched_via_spdy);
2774 EXPECT_TRUE(response->was_alpn_negotiated);
2775 ASSERT_TRUE(response->headers);
2776 EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
2777 std::string value;
2778 EXPECT_TRUE(response->headers->GetNormalizedHeader("foo", &value));
2779 EXPECT_EQ("bar", value);
2780
2781 helper.VerifyDataConsumed();
2782}
2783
2784TEST_F(SpdyNetworkTransactionTest, ServerPushHeadDoesNotMatchGetRequest) {
Ryan Hamilton0239aac2018-05-19 00:03:132785 spdy::SpdySerializedFrame req1(
2786 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
2787 spdy::SpdySerializedFrame priority(
Bence Béky5b1e4ce72018-01-11 14:55:152788 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true));
2789 spdy_util_.UpdateWithStreamDestruction(1);
Ryan Hamilton0239aac2018-05-19 00:03:132790 spdy::SpdySerializedFrame req2(
2791 spdy_util_.ConstructSpdyGet(kPushedUrl, 3, LOWEST));
Bence Béky5b1e4ce72018-01-11 14:55:152792 MockWrite writes[] = {CreateMockWrite(req1, 0), CreateMockWrite(priority, 2),
2793 CreateMockWrite(req2, 6)};
2794
Bence Béky4c325e52020-10-22 20:48:012795 spdy::Http2HeaderBlock push_promise_header_block;
Ryan Hamilton0239aac2018-05-19 00:03:132796 push_promise_header_block[spdy::kHttp2MethodHeader] = "HEAD";
Bence Békyd2df6c1c82018-04-20 22:52:012797 spdy_util_.AddUrlToHeaderBlock(kPushedUrl, &push_promise_header_block);
Ryan Hamilton0239aac2018-05-19 00:03:132798 spdy::SpdySerializedFrame push_promise(spdy_util_.ConstructSpdyPushPromise(
Bence Béky5b1e4ce72018-01-11 14:55:152799 1, 2, std::move(push_promise_header_block)));
2800
Bence Béky4c325e52020-10-22 20:48:012801 spdy::Http2HeaderBlock push_response_headers;
Ryan Hamilton0239aac2018-05-19 00:03:132802 push_response_headers[spdy::kHttp2StatusHeader] = "200";
Bence Béky5b1e4ce72018-01-11 14:55:152803 push_response_headers["foo"] = "bar";
Ryan Hamilton0239aac2018-05-19 00:03:132804 spdy::SpdyHeadersIR headers_ir(2, std::move(push_response_headers));
2805 spdy::SpdySerializedFrame push_headers(spdy_util_.SerializeFrame(headers_ir));
Bence Béky5b1e4ce72018-01-11 14:55:152806
Ryan Hamilton0239aac2018-05-19 00:03:132807 spdy::SpdySerializedFrame resp1(
2808 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
2809 spdy::SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true));
2810 spdy::SpdySerializedFrame resp2(
2811 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
2812 spdy::SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(3, true));
Bence Béky5b1e4ce72018-01-11 14:55:152813 MockRead reads[] = {CreateMockRead(push_promise, 1),
2814 CreateMockRead(push_headers, 3),
2815 CreateMockRead(resp1, 4),
2816 CreateMockRead(body1, 5),
2817 CreateMockRead(resp2, 7),
2818 CreateMockRead(body2, 8),
2819 MockRead(ASYNC, 0, 9)};
2820
Ryan Sleevib8d7ea02018-05-07 20:01:012821 SequencedSocketData data(reads, writes);
Bence Béky5b1e4ce72018-01-11 14:55:152822
2823 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
2824 helper.RunPreTestSetup();
2825 helper.AddData(&data);
2826
2827 // Run first request. This reads PUSH_PROMISE.
2828 helper.RunDefaultTest();
2829
2830 // Request the pushed resource.
2831 HttpNetworkTransaction trans(DEFAULT_PRIORITY, helper.session());
2832 HttpRequestInfo request = CreateGetPushRequest();
2833 TestCompletionCallback callback;
2834 int rv = trans.Start(&request, callback.callback(), log_);
2835 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
2836 rv = callback.WaitForResult();
2837 EXPECT_THAT(rv, IsOk());
2838
2839 const HttpResponseInfo* response = trans.GetResponseInfo();
2840 ASSERT_TRUE(response);
2841 EXPECT_TRUE(response->was_fetched_via_spdy);
2842 EXPECT_TRUE(response->was_alpn_negotiated);
2843 ASSERT_TRUE(response->headers);
2844 EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
2845 std::string value;
2846 EXPECT_FALSE(response->headers->GetNormalizedHeader("foo", &value));
2847 std::string result;
2848 ReadResult(&trans, &result);
2849 EXPECT_EQ("hello!", result);
2850
2851 // Read EOF.
2852 base::RunLoop().RunUntilIdle();
2853
2854 helper.VerifyDataConsumed();
2855}
2856
bncd16676a2016-07-20 16:23:012857TEST_F(SpdyNetworkTransactionTest, ServerPushSingleDataFrame2) {
Ryan Hamilton0239aac2018-05-19 00:03:132858 spdy::SpdySerializedFrame stream1_syn(
Bence Béky27ad0a12018-02-08 00:35:482859 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
Ryan Hamilton0239aac2018-05-19 00:03:132860 spdy::SpdySerializedFrame stream2_priority(
tombergan5d22c182017-01-11 02:05:352861 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true));
rch08e3aa3e2015-05-16 14:27:522862 MockWrite writes[] = {
tombergan5d22c182017-01-11 02:05:352863 CreateMockWrite(stream1_syn, 0), CreateMockWrite(stream2_priority, 3),
rch08e3aa3e2015-05-16 14:27:522864 };
[email protected]82918cc2010-08-25 17:24:502865
Ryan Hamilton0239aac2018-05-19 00:03:132866 spdy::SpdySerializedFrame stream1_reply(
tombergan5d22c182017-01-11 02:05:352867 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
Ryan Hamilton0239aac2018-05-19 00:03:132868 spdy::SpdySerializedFrame stream2_syn(
Bence Békyd2df6c1c82018-04-20 22:52:012869 spdy_util_.ConstructSpdyPush(nullptr, 0, 2, 1, kPushedUrl));
[email protected]8a0fc822013-06-27 20:52:432870 const char kPushedData[] = "pushed";
Ryan Hamilton0239aac2018-05-19 00:03:132871 spdy::SpdySerializedFrame stream2_body(
Bence Békyd74f4382018-02-20 18:26:192872 spdy_util_.ConstructSpdyDataFrame(2, kPushedData, true));
Ryan Hamilton0239aac2018-05-19 00:03:132873 spdy::SpdySerializedFrame stream1_body(
2874 spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]82918cc2010-08-25 17:24:502875 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:412876 CreateMockRead(stream1_reply, 1),
2877 CreateMockRead(stream2_syn, 2),
tombergan5d22c182017-01-11 02:05:352878 CreateMockRead(stream2_body, 4),
2879 CreateMockRead(stream1_body, 5, SYNCHRONOUS),
2880 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 6), // Force a pause
[email protected]82918cc2010-08-25 17:24:502881 };
2882
2883 HttpResponseInfo response;
2884 HttpResponseInfo response2;
Bence Béky4e83f492018-05-13 23:14:252885 std::string expected_push_result("pushed");
Ryan Sleevib8d7ea02018-05-07 20:01:012886 SequencedSocketData data(reads, writes);
[email protected]dd54bd82012-07-19 23:44:572887 RunServerPushTest(&data,
[email protected]d08358502010-12-03 22:04:032888 &response,
2889 &response2,
2890 expected_push_result);
[email protected]82918cc2010-08-25 17:24:502891
bnc42331402016-07-25 13:36:152892 // Verify the response headers.
wezca1070932016-05-26 20:30:522893 EXPECT_TRUE(response.headers);
bnc84e7fb52015-12-02 11:50:022894 EXPECT_EQ("HTTP/1.1 200", response.headers->GetStatusLine());
[email protected]82918cc2010-08-25 17:24:502895
2896 // Verify the pushed stream.
wezca1070932016-05-26 20:30:522897 EXPECT_TRUE(response2.headers);
bnccdc749f2016-01-27 16:39:042898 EXPECT_EQ("HTTP/1.1 200", response2.headers->GetStatusLine());
[email protected]82918cc2010-08-25 17:24:502899}
2900
tombergan5d22c182017-01-11 02:05:352901TEST_F(SpdyNetworkTransactionTest, ServerPushUpdatesPriority) {
Ryan Hamilton0239aac2018-05-19 00:03:132902 spdy::SpdySerializedFrame stream1_headers(
Bence Béky27ad0a12018-02-08 00:35:482903 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, HIGHEST));
Ryan Hamilton0239aac2018-05-19 00:03:132904 spdy::SpdySerializedFrame stream3_headers(
Bence Béky27ad0a12018-02-08 00:35:482905 spdy_util_.ConstructSpdyGet(nullptr, 0, 3, MEDIUM));
Ryan Hamilton0239aac2018-05-19 00:03:132906 spdy::SpdySerializedFrame stream5_headers(
Bence Béky27ad0a12018-02-08 00:35:482907 spdy_util_.ConstructSpdyGet(nullptr, 0, 5, MEDIUM));
tombergan5d22c182017-01-11 02:05:352908
2909 // Stream 1 pushes two streams that are initially prioritized below stream 5.
2910 // Stream 2 is later prioritized below stream 1 after it matches a request.
Ryan Hamilton0239aac2018-05-19 00:03:132911 spdy::SpdySerializedFrame stream2_priority(
tombergan5d22c182017-01-11 02:05:352912 spdy_util_.ConstructSpdyPriority(2, 5, IDLE, true));
Ryan Hamilton0239aac2018-05-19 00:03:132913 spdy::SpdySerializedFrame stream4_priority(
tombergan5d22c182017-01-11 02:05:352914 spdy_util_.ConstructSpdyPriority(4, 2, IDLE, true));
Ryan Hamilton0239aac2018-05-19 00:03:132915 spdy::SpdySerializedFrame stream4_priority_update(
tombergan5d22c182017-01-11 02:05:352916 spdy_util_.ConstructSpdyPriority(4, 5, IDLE, true));
Ryan Hamilton0239aac2018-05-19 00:03:132917 spdy::SpdySerializedFrame stream2_priority_update(
tombergan5d22c182017-01-11 02:05:352918 spdy_util_.ConstructSpdyPriority(2, 1, HIGHEST, true));
2919
[email protected]e3ebba0f2010-08-05 17:59:582920 MockWrite writes[] = {
tombergan5d22c182017-01-11 02:05:352921 CreateMockWrite(stream1_headers, 0),
2922 CreateMockWrite(stream3_headers, 1),
2923 CreateMockWrite(stream5_headers, 2),
2924 CreateMockWrite(stream2_priority, 7),
2925 CreateMockWrite(stream4_priority, 9),
2926 CreateMockWrite(stream4_priority_update, 11),
2927 CreateMockWrite(stream2_priority_update, 12),
[email protected]e3ebba0f2010-08-05 17:59:582928 };
2929
Ryan Hamilton0239aac2018-05-19 00:03:132930 spdy::SpdySerializedFrame stream1_reply(
tombergan5d22c182017-01-11 02:05:352931 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
Ryan Hamilton0239aac2018-05-19 00:03:132932 spdy::SpdySerializedFrame stream3_reply(
tombergan5d22c182017-01-11 02:05:352933 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
Ryan Hamilton0239aac2018-05-19 00:03:132934 spdy::SpdySerializedFrame stream5_reply(
tombergan5d22c182017-01-11 02:05:352935 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 5));
2936
Ryan Hamilton0239aac2018-05-19 00:03:132937 spdy::SpdySerializedFrame stream2_push(
Bence Békyd2df6c1c82018-04-20 22:52:012938 spdy_util_.ConstructSpdyPush(nullptr, 0, 2, 1, kPushedUrl));
Ryan Hamilton0239aac2018-05-19 00:03:132939 spdy::SpdySerializedFrame stream4_push(spdy_util_.ConstructSpdyPush(
Bence Béky3e01b532018-02-06 23:04:512940 nullptr, 0, 4, 1, "https://www.example.org/bar.dat"));
tombergan5d22c182017-01-11 02:05:352941
Ryan Hamilton0239aac2018-05-19 00:03:132942 spdy::SpdySerializedFrame stream1_body(
2943 spdy_util_.ConstructSpdyDataFrame(1, true));
2944 spdy::SpdySerializedFrame stream2_body(
2945 spdy_util_.ConstructSpdyDataFrame(2, true));
2946 spdy::SpdySerializedFrame stream3_body(
2947 spdy_util_.ConstructSpdyDataFrame(3, true));
2948 spdy::SpdySerializedFrame stream5_body(
2949 spdy_util_.ConstructSpdyDataFrame(5, true));
tombergan5d22c182017-01-11 02:05:352950
2951 MockRead reads[] = {
2952 CreateMockRead(stream1_reply, 3),
2953 CreateMockRead(stream3_reply, 4),
2954 CreateMockRead(stream5_reply, 5),
2955 CreateMockRead(stream2_push, 6),
2956 CreateMockRead(stream4_push, 8),
2957 MockRead(ASYNC, ERR_IO_PENDING, 10),
2958 CreateMockRead(stream1_body, 13),
2959 CreateMockRead(stream2_body, 14),
2960 CreateMockRead(stream3_body, 15),
2961 CreateMockRead(stream5_body, 16),
2962 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 17), // Force a pause
2963 };
2964
Ryan Sleevib8d7ea02018-05-07 20:01:012965 SequencedSocketData data(reads, writes);
2966 SequencedSocketData data_placeholder1;
2967 SequencedSocketData data_placeholder2;
2968 SequencedSocketData data_placeholder3;
tombergan5d22c182017-01-11 02:05:352969
Bence Békydb3cf652017-10-10 15:22:102970 NormalSpdyTransactionHelper helper(request_, LOWEST, log_, nullptr);
tombergan5d22c182017-01-11 02:05:352971 helper.RunPreTestSetup();
2972 helper.AddData(&data);
2973 helper.AddData(&data_placeholder1); // other requests reuse the same socket
2974 helper.AddData(&data_placeholder2);
2975 helper.AddData(&data_placeholder3);
2976 HttpNetworkTransaction trans1(HIGHEST, helper.session());
2977 HttpNetworkTransaction trans3(MEDIUM, helper.session());
2978 HttpNetworkTransaction trans5(MEDIUM, helper.session());
2979
2980 TestCompletionCallback callback1;
2981 TestCompletionCallback callback3;
2982 TestCompletionCallback callback5;
2983
2984 // Start the ordinary requests.
Bence Békydb3cf652017-10-10 15:22:102985 ASSERT_THAT(trans1.Start(&request_, callback1.callback(), log_),
tombergan5d22c182017-01-11 02:05:352986 IsError(ERR_IO_PENDING));
Bence Békydb3cf652017-10-10 15:22:102987 ASSERT_THAT(trans3.Start(&request_, callback3.callback(), log_),
tombergan5d22c182017-01-11 02:05:352988 IsError(ERR_IO_PENDING));
Bence Békydb3cf652017-10-10 15:22:102989 ASSERT_THAT(trans5.Start(&request_, callback5.callback(), log_),
tombergan5d22c182017-01-11 02:05:352990 IsError(ERR_IO_PENDING));
2991 data.RunUntilPaused();
2992
tombergan5d22c182017-01-11 02:05:352993 // Start a request that matches the push.
Bence Békydb3cf652017-10-10 15:22:102994 HttpRequestInfo push_req = CreateGetPushRequest();
krasin0bfeb6b2017-01-13 21:48:042995
2996 HttpNetworkTransaction trans2(HIGHEST, helper.session());
2997 TestCompletionCallback callback2;
Bence Békyd3dde832017-09-19 19:02:312998 ASSERT_THAT(trans2.Start(&push_req, callback2.callback(), log_),
tombergan5d22c182017-01-11 02:05:352999 IsError(ERR_IO_PENDING));
3000 data.Resume();
3001
3002 base::RunLoop().RunUntilIdle();
3003 ASSERT_THAT(callback1.WaitForResult(), IsOk());
3004 ASSERT_THAT(callback2.WaitForResult(), IsOk());
3005 ASSERT_THAT(callback3.WaitForResult(), IsOk());
3006 ASSERT_THAT(callback5.WaitForResult(), IsOk());
3007 helper.VerifyDataConsumed();
3008}
3009
3010TEST_F(SpdyNetworkTransactionTest, ServerPushServerAborted) {
Ryan Hamilton0239aac2018-05-19 00:03:133011 spdy::SpdySerializedFrame stream1_syn(
Bence Béky27ad0a12018-02-08 00:35:483012 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
Ryan Hamilton0239aac2018-05-19 00:03:133013 spdy::SpdySerializedFrame stream2_priority(
tombergan5d22c182017-01-11 02:05:353014 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true));
3015 MockWrite writes[] = {
3016 CreateMockWrite(stream1_syn, 0), CreateMockWrite(stream2_priority, 3),
3017 };
3018
Ryan Hamilton0239aac2018-05-19 00:03:133019 spdy::SpdySerializedFrame stream1_reply(
tombergan5d22c182017-01-11 02:05:353020 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
Ryan Hamilton0239aac2018-05-19 00:03:133021 spdy::SpdySerializedFrame stream2_syn(
Bence Békyd2df6c1c82018-04-20 22:52:013022 spdy_util_.ConstructSpdyPush(nullptr, 0, 2, 1, kPushedUrl));
Ryan Hamilton0239aac2018-05-19 00:03:133023 spdy::SpdySerializedFrame stream2_rst(
3024 spdy_util_.ConstructSpdyRstStream(2, spdy::ERROR_CODE_PROTOCOL_ERROR));
3025 spdy::SpdySerializedFrame stream1_body(
3026 spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]e3ebba0f2010-08-05 17:59:583027 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:413028 CreateMockRead(stream1_reply, 1),
bnceb9aa7112017-01-05 01:03:463029 CreateMockRead(stream2_syn, 2, SYNCHRONOUS),
tombergan5d22c182017-01-11 02:05:353030 CreateMockRead(stream2_rst, 4),
3031 CreateMockRead(stream1_body, 5, SYNCHRONOUS),
3032 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 6), // Force a pause
[email protected]e3ebba0f2010-08-05 17:59:583033 };
3034
Ryan Sleevib8d7ea02018-05-07 20:01:013035 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:103036 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]e3ebba0f2010-08-05 17:59:583037
3038 helper.RunPreTestSetup();
[email protected]dd54bd82012-07-19 23:44:573039 helper.AddData(&data);
[email protected]e3ebba0f2010-08-05 17:59:583040
3041 HttpNetworkTransaction* trans = helper.trans();
3042
3043 // Start the transaction with basic parameters.
[email protected]49639fa2011-12-20 23:22:413044 TestCompletionCallback callback;
Bence Békydb3cf652017-10-10 15:22:103045 int rv = trans->Start(&request_, callback.callback(), log_);
robpercival214763f2016-07-01 23:27:013046 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]e3ebba0f2010-08-05 17:59:583047 rv = callback.WaitForResult();
robpercival214763f2016-07-01 23:27:013048 EXPECT_THAT(rv, IsOk());
[email protected]19ec8a72010-08-23 03:38:233049
3050 // Verify that we consumed all test data.
tombergan5d22c182017-01-11 02:05:353051 base::RunLoop().RunUntilIdle();
rch08e3aa3e2015-05-16 14:27:523052 EXPECT_TRUE(data.AllReadDataConsumed());
3053 EXPECT_TRUE(data.AllWriteDataConsumed());
[email protected]19ec8a72010-08-23 03:38:233054
bnc42331402016-07-25 13:36:153055 // Verify the response headers.
[email protected]19ec8a72010-08-23 03:38:233056 HttpResponseInfo response = *trans->GetResponseInfo();
wezca1070932016-05-26 20:30:523057 EXPECT_TRUE(response.headers);
bnc84e7fb52015-12-02 11:50:023058 EXPECT_EQ("HTTP/1.1 200", response.headers->GetStatusLine());
[email protected]19ec8a72010-08-23 03:38:233059}
3060
[email protected]8a0fc822013-06-27 20:52:433061// Verify that we don't leak streams and that we properly send a reset
3062// if the server pushes the same stream twice.
bncd16676a2016-07-20 16:23:013063TEST_F(SpdyNetworkTransactionTest, ServerPushDuplicate) {
Bence Békyeacd48f2018-05-14 11:34:333064 base::HistogramTester histogram_tester;
3065
Ryan Hamilton0239aac2018-05-19 00:03:133066 spdy::SpdySerializedFrame stream1_syn(
Bence Béky27ad0a12018-02-08 00:35:483067 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
Ryan Hamilton0239aac2018-05-19 00:03:133068 spdy::SpdySerializedFrame stream2_priority(
tombergan5d22c182017-01-11 02:05:353069 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true));
Ryan Hamilton0239aac2018-05-19 00:03:133070 spdy::SpdySerializedFrame stream3_rst(
3071 spdy_util_.ConstructSpdyRstStream(4, spdy::ERROR_CODE_REFUSED_STREAM));
[email protected]fdc165a2010-09-03 03:51:293072 MockWrite writes[] = {
tombergan5d22c182017-01-11 02:05:353073 CreateMockWrite(stream1_syn, 0), CreateMockWrite(stream2_priority, 3),
3074 CreateMockWrite(stream3_rst, 5),
[email protected]fdc165a2010-09-03 03:51:293075 };
3076
Ryan Hamilton0239aac2018-05-19 00:03:133077 spdy::SpdySerializedFrame stream1_reply(
tombergan5d22c182017-01-11 02:05:353078 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
Ryan Hamilton0239aac2018-05-19 00:03:133079 spdy::SpdySerializedFrame stream2_syn(
Bence Békyd2df6c1c82018-04-20 22:52:013080 spdy_util_.ConstructSpdyPush(nullptr, 0, 2, 1, kPushedUrl));
Ryan Hamilton0239aac2018-05-19 00:03:133081 spdy::SpdySerializedFrame stream3_syn(
Bence Békyd2df6c1c82018-04-20 22:52:013082 spdy_util_.ConstructSpdyPush(nullptr, 0, 4, 1, kPushedUrl));
tombergan5d22c182017-01-11 02:05:353083
[email protected]8a0fc822013-06-27 20:52:433084 const char kPushedData[] = "pushed";
Ryan Hamilton0239aac2018-05-19 00:03:133085 spdy::SpdySerializedFrame stream1_body(
3086 spdy_util_.ConstructSpdyDataFrame(1, true));
3087 spdy::SpdySerializedFrame stream2_body(
Bence Békyd74f4382018-02-20 18:26:193088 spdy_util_.ConstructSpdyDataFrame(2, kPushedData, true));
tombergan5d22c182017-01-11 02:05:353089
[email protected]fdc165a2010-09-03 03:51:293090 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:413091 CreateMockRead(stream1_reply, 1),
3092 CreateMockRead(stream2_syn, 2),
tombergan5d22c182017-01-11 02:05:353093 CreateMockRead(stream3_syn, 4),
3094 CreateMockRead(stream1_body, 6),
3095 CreateMockRead(stream2_body, 7),
3096 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 8), // Force a pause
[email protected]fdc165a2010-09-03 03:51:293097 };
3098
3099 HttpResponseInfo response;
3100 HttpResponseInfo response2;
Bence Béky4e83f492018-05-13 23:14:253101 std::string expected_push_result("pushed");
Ryan Sleevib8d7ea02018-05-07 20:01:013102 SequencedSocketData data(reads, writes);
[email protected]dd54bd82012-07-19 23:44:573103 RunServerPushTest(&data,
[email protected]d08358502010-12-03 22:04:033104 &response,
3105 &response2,
3106 expected_push_result);
[email protected]fdc165a2010-09-03 03:51:293107
bnc42331402016-07-25 13:36:153108 // Verify the response headers.
wezca1070932016-05-26 20:30:523109 EXPECT_TRUE(response.headers);
bnc84e7fb52015-12-02 11:50:023110 EXPECT_EQ("HTTP/1.1 200", response.headers->GetStatusLine());
[email protected]fdc165a2010-09-03 03:51:293111
3112 // Verify the pushed stream.
wezca1070932016-05-26 20:30:523113 EXPECT_TRUE(response2.headers);
bnccdc749f2016-01-27 16:39:043114 EXPECT_EQ("HTTP/1.1 200", response2.headers->GetStatusLine());
Bence Békyeacd48f2018-05-14 11:34:333115
3116 histogram_tester.ExpectBucketCount(
3117 "Net.SpdyPushedStreamFate",
3118 static_cast<int>(SpdyPushedStreamFate::kAcceptedNoVary), 1);
3119 histogram_tester.ExpectBucketCount(
3120 "Net.SpdyPushedStreamFate",
3121 static_cast<int>(SpdyPushedStreamFate::kDuplicateUrl), 1);
3122 histogram_tester.ExpectTotalCount("Net.SpdyPushedStreamFate", 2);
[email protected]fdc165a2010-09-03 03:51:293123}
3124
bncd16676a2016-07-20 16:23:013125TEST_F(SpdyNetworkTransactionTest, ServerPushMultipleDataFrame) {
Ryan Hamilton0239aac2018-05-19 00:03:133126 spdy::SpdySerializedFrame stream1_syn(
Bence Béky27ad0a12018-02-08 00:35:483127 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
Ryan Hamilton0239aac2018-05-19 00:03:133128 spdy::SpdySerializedFrame stream2_priority(
tombergan5d22c182017-01-11 02:05:353129 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true));
[email protected]19ec8a72010-08-23 03:38:233130 MockWrite writes[] = {
tombergan5d22c182017-01-11 02:05:353131 CreateMockWrite(stream1_syn, 0), CreateMockWrite(stream2_priority, 3),
[email protected]19ec8a72010-08-23 03:38:233132 };
3133
Ryan Hamilton0239aac2018-05-19 00:03:133134 spdy::SpdySerializedFrame stream1_reply(
tombergan5d22c182017-01-11 02:05:353135 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
Ryan Hamilton0239aac2018-05-19 00:03:133136 spdy::SpdySerializedFrame stream2_syn(
Bence Békyd2df6c1c82018-04-20 22:52:013137 spdy_util_.ConstructSpdyPush(nullptr, 0, 2, 1, kPushedUrl));
Bence Békyd74f4382018-02-20 18:26:193138 static const char kPushedData[] = "pushed payload for chunked test";
Ryan Hamilton0239aac2018-05-19 00:03:133139 spdy::SpdySerializedFrame stream2_body_base(
Bence Békyd74f4382018-02-20 18:26:193140 spdy_util_.ConstructSpdyDataFrame(2, kPushedData, true));
[email protected]8a0fc822013-06-27 20:52:433141 const size_t kChunkSize = strlen(kPushedData) / 4;
Ryan Hamilton0239aac2018-05-19 00:03:133142 spdy::SpdySerializedFrame stream2_body1(stream2_body_base.data(), kChunkSize,
3143 false);
3144 spdy::SpdySerializedFrame stream2_body2(stream2_body_base.data() + kChunkSize,
3145 kChunkSize, false);
3146 spdy::SpdySerializedFrame stream2_body3(
3147 stream2_body_base.data() + 2 * kChunkSize, kChunkSize, false);
3148 spdy::SpdySerializedFrame stream2_body4(
3149 stream2_body_base.data() + 3 * kChunkSize,
3150 stream2_body_base.size() - 3 * kChunkSize, false);
3151 spdy::SpdySerializedFrame stream1_body(
3152 spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]19ec8a72010-08-23 03:38:233153 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:413154 CreateMockRead(stream1_reply, 1),
3155 CreateMockRead(stream2_syn, 2),
tombergan5d22c182017-01-11 02:05:353156 CreateMockRead(stream2_body1, 4),
3157 CreateMockRead(stream2_body2, 5),
3158 CreateMockRead(stream2_body3, 6),
3159 CreateMockRead(stream2_body4, 7),
3160 CreateMockRead(stream1_body, 8, SYNCHRONOUS),
3161 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 9), // Force a pause
[email protected]19ec8a72010-08-23 03:38:233162 };
3163
3164 HttpResponseInfo response;
3165 HttpResponseInfo response2;
Bence Béky4e83f492018-05-13 23:14:253166 std::string expected_push_result(kPushedData);
Ryan Sleevib8d7ea02018-05-07 20:01:013167 SequencedSocketData data(reads, writes);
[email protected]8a0fc822013-06-27 20:52:433168 RunServerPushTest(&data, &response, &response2, kPushedData);
[email protected]19ec8a72010-08-23 03:38:233169
bnc42331402016-07-25 13:36:153170 // Verify the response headers.
wezca1070932016-05-26 20:30:523171 EXPECT_TRUE(response.headers);
bnc84e7fb52015-12-02 11:50:023172 EXPECT_EQ("HTTP/1.1 200", response.headers->GetStatusLine());
[email protected]19ec8a72010-08-23 03:38:233173
3174 // Verify the pushed stream.
wezca1070932016-05-26 20:30:523175 EXPECT_TRUE(response2.headers);
bnccdc749f2016-01-27 16:39:043176 EXPECT_EQ("HTTP/1.1 200", response2.headers->GetStatusLine());
[email protected]19ec8a72010-08-23 03:38:233177}
3178
bncd16676a2016-07-20 16:23:013179TEST_F(SpdyNetworkTransactionTest, ServerPushMultipleDataFrameInterrupted) {
Ryan Hamilton0239aac2018-05-19 00:03:133180 spdy::SpdySerializedFrame stream1_syn(
Bence Béky27ad0a12018-02-08 00:35:483181 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
Ryan Hamilton0239aac2018-05-19 00:03:133182 spdy::SpdySerializedFrame stream2_priority(
tombergan5d22c182017-01-11 02:05:353183 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true));
[email protected]19ec8a72010-08-23 03:38:233184 MockWrite writes[] = {
tombergan5d22c182017-01-11 02:05:353185 CreateMockWrite(stream1_syn, 0), CreateMockWrite(stream2_priority, 3),
[email protected]19ec8a72010-08-23 03:38:233186 };
3187
Ryan Hamilton0239aac2018-05-19 00:03:133188 spdy::SpdySerializedFrame stream1_reply(
tombergan5d22c182017-01-11 02:05:353189 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
Ryan Hamilton0239aac2018-05-19 00:03:133190 spdy::SpdySerializedFrame stream2_syn(
Bence Békyd2df6c1c82018-04-20 22:52:013191 spdy_util_.ConstructSpdyPush(nullptr, 0, 2, 1, kPushedUrl));
Bence Békyd74f4382018-02-20 18:26:193192 static const char kPushedData[] = "pushed payload for chunked test";
Ryan Hamilton0239aac2018-05-19 00:03:133193 spdy::SpdySerializedFrame stream2_body_base(
Bence Békyd74f4382018-02-20 18:26:193194 spdy_util_.ConstructSpdyDataFrame(2, kPushedData, true));
[email protected]8a0fc822013-06-27 20:52:433195 const size_t kChunkSize = strlen(kPushedData) / 4;
Ryan Hamilton0239aac2018-05-19 00:03:133196 spdy::SpdySerializedFrame stream2_body1(stream2_body_base.data(), kChunkSize,
3197 false);
3198 spdy::SpdySerializedFrame stream2_body2(stream2_body_base.data() + kChunkSize,
3199 kChunkSize, false);
3200 spdy::SpdySerializedFrame stream2_body3(
3201 stream2_body_base.data() + 2 * kChunkSize, kChunkSize, false);
3202 spdy::SpdySerializedFrame stream2_body4(
3203 stream2_body_base.data() + 3 * kChunkSize,
3204 stream2_body_base.size() - 3 * kChunkSize, false);
3205 spdy::SpdySerializedFrame stream1_body(
3206 spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]19ec8a72010-08-23 03:38:233207 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:413208 CreateMockRead(stream1_reply, 1),
3209 CreateMockRead(stream2_syn, 2),
tombergan5d22c182017-01-11 02:05:353210 CreateMockRead(stream2_body1, 4),
3211 CreateMockRead(stream2_body2, 5),
3212 CreateMockRead(stream2_body3, 6),
3213 CreateMockRead(stream2_body4, 7),
3214 CreateMockRead(stream1_body, 8, SYNCHRONOUS),
3215 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 9) // Force a pause.
[email protected]19ec8a72010-08-23 03:38:233216 };
3217
3218 HttpResponseInfo response;
3219 HttpResponseInfo response2;
Ryan Sleevib8d7ea02018-05-07 20:01:013220 SequencedSocketData data(reads, writes);
[email protected]8a0fc822013-06-27 20:52:433221 RunServerPushTest(&data, &response, &response2, kPushedData);
[email protected]19ec8a72010-08-23 03:38:233222
bnc42331402016-07-25 13:36:153223 // Verify the response headers.
wezca1070932016-05-26 20:30:523224 EXPECT_TRUE(response.headers);
bnc84e7fb52015-12-02 11:50:023225 EXPECT_EQ("HTTP/1.1 200", response.headers->GetStatusLine());
[email protected]19ec8a72010-08-23 03:38:233226
3227 // Verify the pushed stream.
wezca1070932016-05-26 20:30:523228 EXPECT_TRUE(response2.headers);
bnccdc749f2016-01-27 16:39:043229 EXPECT_EQ("HTTP/1.1 200", response2.headers->GetStatusLine());
[email protected]19ec8a72010-08-23 03:38:233230}
3231
morlovichab1d1c1e2017-02-07 19:59:283232TEST_F(SpdyNetworkTransactionTest, ServerPushInvalidUrl) {
Bence Békyeacd48f2018-05-14 11:34:333233 base::HistogramTester histogram_tester;
3234
morlovichab1d1c1e2017-02-07 19:59:283235 // Coverage on how a non-empty invalid GURL in a PUSH_PROMISE is handled.
Bence Béky4c325e52020-10-22 20:48:013236 spdy::Http2HeaderBlock headers(
Ryan Hamilton0239aac2018-05-19 00:03:133237 spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
3238 spdy::SpdySerializedFrame req(
morlovichab1d1c1e2017-02-07 19:59:283239 spdy_util_.ConstructSpdyHeaders(1, std::move(headers), LOWEST, true));
3240
3241 // Can't use ConstructSpdyPush here since it wants to parse a URL and
3242 // split it into the appropriate :header pieces. So we have to hand-fill
3243 // those pieces in.
Bence Béky4c325e52020-10-22 20:48:013244 spdy::Http2HeaderBlock push_promise_header_block;
Ryan Hamilton0239aac2018-05-19 00:03:133245 push_promise_header_block[spdy::kHttp2AuthorityHeader] = "";
3246 push_promise_header_block[spdy::kHttp2SchemeHeader] = "";
3247 push_promise_header_block[spdy::kHttp2PathHeader] = "/index.html";
morlovichab1d1c1e2017-02-07 19:59:283248
Ryan Hamilton0239aac2018-05-19 00:03:133249 spdy::SpdySerializedFrame push_promise(spdy_util_.ConstructSpdyPushPromise(
Bence Békyf1d78522018-01-11 01:16:503250 1, 2, std::move(push_promise_header_block)));
morlovichab1d1c1e2017-02-07 19:59:283251
Ryan Hamilton0239aac2018-05-19 00:03:133252 spdy::SpdySerializedFrame stream2_rst(
3253 spdy_util_.ConstructSpdyRstStream(2, spdy::ERROR_CODE_REFUSED_STREAM));
morlovichab1d1c1e2017-02-07 19:59:283254
3255 MockWrite writes[] = {CreateMockWrite(req, 0),
3256 CreateMockWrite(stream2_rst, 2)};
3257 MockRead reads[] = {
Bence Békyf1d78522018-01-11 01:16:503258 CreateMockRead(push_promise, 1), MockRead(ASYNC, 0, 3) /* EOF */
morlovichab1d1c1e2017-02-07 19:59:283259 };
Ryan Sleevib8d7ea02018-05-07 20:01:013260 SequencedSocketData data(reads, writes);
morlovichab1d1c1e2017-02-07 19:59:283261 RunBrokenPushTest(&data, ERR_CONNECTION_CLOSED);
Bence Békyeacd48f2018-05-14 11:34:333262
3263 histogram_tester.ExpectBucketCount(
3264 "Net.SpdyPushedStreamFate",
3265 static_cast<int>(SpdyPushedStreamFate::kInvalidUrl), 1);
3266 histogram_tester.ExpectTotalCount("Net.SpdyPushedStreamFate", 1);
morlovichab1d1c1e2017-02-07 19:59:283267}
3268
bncd16676a2016-07-20 16:23:013269TEST_F(SpdyNetworkTransactionTest, ServerPushInvalidAssociatedStreamID0) {
Ryan Hamilton0239aac2018-05-19 00:03:133270 spdy::SpdySerializedFrame stream1_syn(
Bence Béky27ad0a12018-02-08 00:35:483271 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
Ryan Hamilton0239aac2018-05-19 00:03:133272 spdy::SpdySerializedFrame goaway(
3273 spdy_util_.ConstructSpdyGoAway(0, spdy::ERROR_CODE_PROTOCOL_ERROR,
3274 "Framer error: 1 (INVALID_STREAM_ID)."));
[email protected]19ec8a72010-08-23 03:38:233275 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:413276 CreateMockWrite(stream1_syn, 0), CreateMockWrite(goaway, 3),
[email protected]19ec8a72010-08-23 03:38:233277 };
3278
Ryan Hamilton0239aac2018-05-19 00:03:133279 spdy::SpdySerializedFrame stream1_reply(
tombergan5d22c182017-01-11 02:05:353280 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
Ryan Hamilton0239aac2018-05-19 00:03:133281 spdy::SpdySerializedFrame stream2_syn(
Bence Békyd2df6c1c82018-04-20 22:52:013282 spdy_util_.ConstructSpdyPush(nullptr, 0, 2, 0, kPushedUrl));
[email protected]19ec8a72010-08-23 03:38:233283 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:413284 CreateMockRead(stream1_reply, 1), CreateMockRead(stream2_syn, 2),
[email protected]19ec8a72010-08-23 03:38:233285 };
Ryan Sleevib8d7ea02018-05-07 20:01:013286 SequencedSocketData data(reads, writes);
morlovichab1d1c1e2017-02-07 19:59:283287 RunBrokenPushTest(&data, OK);
[email protected]e3ebba0f2010-08-05 17:59:583288}
3289
bncd16676a2016-07-20 16:23:013290TEST_F(SpdyNetworkTransactionTest, ServerPushInvalidAssociatedStreamID9) {
Bence Békyeacd48f2018-05-14 11:34:333291 base::HistogramTester histogram_tester;
3292
Ryan Hamilton0239aac2018-05-19 00:03:133293 spdy::SpdySerializedFrame stream1_syn(
Bence Béky27ad0a12018-02-08 00:35:483294 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
Ryan Hamilton0239aac2018-05-19 00:03:133295 spdy::SpdySerializedFrame stream1_body(
3296 spdy_util_.ConstructSpdyDataFrame(1, true));
3297 spdy::SpdySerializedFrame stream2_rst(
3298 spdy_util_.ConstructSpdyRstStream(2, spdy::ERROR_CODE_STREAM_CLOSED));
[email protected]e3ebba0f2010-08-05 17:59:583299 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:413300 CreateMockWrite(stream1_syn, 0), CreateMockWrite(stream2_rst, 3),
[email protected]e3ebba0f2010-08-05 17:59:583301 };
3302
Ryan Hamilton0239aac2018-05-19 00:03:133303 spdy::SpdySerializedFrame stream1_reply(
tombergan5d22c182017-01-11 02:05:353304 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
Ryan Hamilton0239aac2018-05-19 00:03:133305 spdy::SpdySerializedFrame stream2_syn(
Bence Békyd2df6c1c82018-04-20 22:52:013306 spdy_util_.ConstructSpdyPush(nullptr, 0, 2, 9, kPushedUrl));
[email protected]e3ebba0f2010-08-05 17:59:583307 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:413308 CreateMockRead(stream1_reply, 1), CreateMockRead(stream2_syn, 2),
3309 CreateMockRead(stream1_body, 4),
rch08e3aa3e2015-05-16 14:27:523310 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 5), // Force a pause
[email protected]e3ebba0f2010-08-05 17:59:583311 };
3312
Ryan Sleevib8d7ea02018-05-07 20:01:013313 SequencedSocketData data(reads, writes);
morlovichab1d1c1e2017-02-07 19:59:283314 RunBrokenPushTest(&data, OK);
Bence Békyeacd48f2018-05-14 11:34:333315
3316 histogram_tester.ExpectBucketCount(
3317 "Net.SpdyPushedStreamFate",
3318 static_cast<int>(SpdyPushedStreamFate::kInactiveAssociatedStream), 1);
3319 histogram_tester.ExpectTotalCount("Net.SpdyPushedStreamFate", 1);
[email protected]e3ebba0f2010-08-05 17:59:583320}
3321
bncd16676a2016-07-20 16:23:013322TEST_F(SpdyNetworkTransactionTest, ServerPushNoURL) {
Bence Békyeacd48f2018-05-14 11:34:333323 base::HistogramTester histogram_tester;
3324
Ryan Hamilton0239aac2018-05-19 00:03:133325 spdy::SpdySerializedFrame stream1_syn(
Bence Béky27ad0a12018-02-08 00:35:483326 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
Ryan Hamilton0239aac2018-05-19 00:03:133327 spdy::SpdySerializedFrame stream1_body(
3328 spdy_util_.ConstructSpdyDataFrame(1, true));
3329 spdy::SpdySerializedFrame stream2_rst(
3330 spdy_util_.ConstructSpdyRstStream(2, spdy::ERROR_CODE_REFUSED_STREAM));
[email protected]e3ebba0f2010-08-05 17:59:583331 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:413332 CreateMockWrite(stream1_syn, 0), CreateMockWrite(stream2_rst, 3),
[email protected]e3ebba0f2010-08-05 17:59:583333 };
3334
Ryan Hamilton0239aac2018-05-19 00:03:133335 spdy::SpdySerializedFrame stream1_reply(
tombergan5d22c182017-01-11 02:05:353336 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
Bence Béky4c325e52020-10-22 20:48:013337 spdy::Http2HeaderBlock incomplete_headers;
Ryan Hamilton0239aac2018-05-19 00:03:133338 incomplete_headers[spdy::kHttp2StatusHeader] = "200 OK";
bnc086b39e12016-06-24 13:05:263339 incomplete_headers["hello"] = "bye";
Ryan Hamilton0239aac2018-05-19 00:03:133340 spdy::SpdySerializedFrame stream2_syn(
Bence Békyf1d78522018-01-11 01:16:503341 spdy_util_.ConstructSpdyPushPromise(1, 2, std::move(incomplete_headers)));
[email protected]e3ebba0f2010-08-05 17:59:583342 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:413343 CreateMockRead(stream1_reply, 1), CreateMockRead(stream2_syn, 2),
3344 CreateMockRead(stream1_body, 4),
rch08e3aa3e2015-05-16 14:27:523345 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 5) // Force a pause
[email protected]e3ebba0f2010-08-05 17:59:583346 };
3347
Ryan Sleevib8d7ea02018-05-07 20:01:013348 SequencedSocketData data(reads, writes);
morlovichab1d1c1e2017-02-07 19:59:283349 RunBrokenPushTest(&data, OK);
Bence Békyeacd48f2018-05-14 11:34:333350
3351 histogram_tester.ExpectBucketCount(
3352 "Net.SpdyPushedStreamFate",
3353 static_cast<int>(SpdyPushedStreamFate::kInvalidUrl), 1);
3354 histogram_tester.ExpectTotalCount("Net.SpdyPushedStreamFate", 1);
[email protected]e3ebba0f2010-08-05 17:59:583355}
3356
bnc0cb98b22016-03-04 17:10:523357// PUSH_PROMISE on a server-initiated stream should trigger GOAWAY.
bncd16676a2016-07-20 16:23:013358TEST_F(SpdyNetworkTransactionTest, ServerPushOnPushedStream) {
Bence Békyeacd48f2018-05-14 11:34:333359 base::HistogramTester histogram_tester;
3360
Ryan Hamilton0239aac2018-05-19 00:03:133361 spdy::SpdySerializedFrame stream1_syn(
Bence Béky27ad0a12018-02-08 00:35:483362 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
Ryan Hamilton0239aac2018-05-19 00:03:133363 spdy::SpdySerializedFrame stream2_priority(
tombergan5d22c182017-01-11 02:05:353364 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true));
Ryan Hamilton0239aac2018-05-19 00:03:133365 spdy::SpdySerializedFrame goaway(spdy_util_.ConstructSpdyGoAway(
3366 2, spdy::ERROR_CODE_PROTOCOL_ERROR,
Bence Béky602c40c2017-07-26 05:22:563367 "Received pushed stream id 4 on invalid stream id 2 (must be odd)."));
bnc0cb98b22016-03-04 17:10:523368 MockWrite writes[] = {
tombergan5d22c182017-01-11 02:05:353369 CreateMockWrite(stream1_syn, 0), CreateMockWrite(stream2_priority, 3),
3370 CreateMockWrite(goaway, 5),
bnc0cb98b22016-03-04 17:10:523371 };
3372
Ryan Hamilton0239aac2018-05-19 00:03:133373 spdy::SpdySerializedFrame stream1_reply(
tombergan5d22c182017-01-11 02:05:353374 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
Ryan Hamilton0239aac2018-05-19 00:03:133375 spdy::SpdySerializedFrame stream2_syn(
Bence Békyd2df6c1c82018-04-20 22:52:013376 spdy_util_.ConstructSpdyPush(nullptr, 0, 2, 1, kPushedUrl));
Ryan Hamilton0239aac2018-05-19 00:03:133377 spdy::SpdySerializedFrame stream3_syn(spdy_util_.ConstructSpdyPush(
Bence Béky3e01b532018-02-06 23:04:513378 nullptr, 0, 4, 2, "https://www.example.org/bar.dat"));
bnc0cb98b22016-03-04 17:10:523379 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:413380 CreateMockRead(stream1_reply, 1), CreateMockRead(stream2_syn, 2),
tombergan5d22c182017-01-11 02:05:353381 CreateMockRead(stream3_syn, 4),
bnc0cb98b22016-03-04 17:10:523382 };
3383
Ryan Sleevib8d7ea02018-05-07 20:01:013384 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:103385 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
bnc0cb98b22016-03-04 17:10:523386 helper.RunToCompletion(&data);
Bence Békyeacd48f2018-05-14 11:34:333387
3388 histogram_tester.ExpectBucketCount(
3389 "Net.SpdyPushedStreamFate",
3390 static_cast<int>(SpdyPushedStreamFate::kAssociatedStreamIdParityError),
3391 1);
3392 histogram_tester.ExpectTotalCount("Net.SpdyPushedStreamFate", 1);
bnc0cb98b22016-03-04 17:10:523393}
3394
3395// PUSH_PROMISE on a closed client-initiated stream should trigger RST_STREAM.
bncd16676a2016-07-20 16:23:013396TEST_F(SpdyNetworkTransactionTest, ServerPushOnClosedStream) {
Bence Békyeacd48f2018-05-14 11:34:333397 base::HistogramTester histogram_tester;
3398
Ryan Hamilton0239aac2018-05-19 00:03:133399 spdy::SpdySerializedFrame stream1_syn(
Bence Béky27ad0a12018-02-08 00:35:483400 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
Ryan Hamilton0239aac2018-05-19 00:03:133401 spdy::SpdySerializedFrame rst(
3402 spdy_util_.ConstructSpdyRstStream(2, spdy::ERROR_CODE_STREAM_CLOSED));
bnc0cb98b22016-03-04 17:10:523403 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:413404 CreateMockWrite(stream1_syn, 0), CreateMockWrite(rst, 5),
bnc0cb98b22016-03-04 17:10:523405 };
3406
Ryan Hamilton0239aac2018-05-19 00:03:133407 spdy::SpdySerializedFrame stream1_reply(
bnc42331402016-07-25 13:36:153408 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
Ryan Hamilton0239aac2018-05-19 00:03:133409 spdy::SpdySerializedFrame stream1_body(
3410 spdy_util_.ConstructSpdyDataFrame(1, true));
3411 spdy::SpdySerializedFrame stream2_syn(
Bence Békyd2df6c1c82018-04-20 22:52:013412 spdy_util_.ConstructSpdyPush(nullptr, 0, 2, 1, kPushedUrl));
bnc0cb98b22016-03-04 17:10:523413 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:413414 CreateMockRead(stream1_reply, 1), CreateMockRead(stream1_body, 2),
3415 CreateMockRead(stream2_syn, 3), MockRead(SYNCHRONOUS, ERR_IO_PENDING, 4),
bnc0cb98b22016-03-04 17:10:523416 };
3417
Ryan Sleevib8d7ea02018-05-07 20:01:013418 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:103419 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
bnc0cb98b22016-03-04 17:10:523420 helper.RunPreTestSetup();
3421 helper.AddData(&data);
3422
3423 HttpNetworkTransaction* trans = helper.trans();
3424
3425 TestCompletionCallback callback;
Bence Békydb3cf652017-10-10 15:22:103426 int rv = trans->Start(&request_, callback.callback(), log_);
bnc0cb98b22016-03-04 17:10:523427 rv = callback.GetResult(rv);
robpercival214763f2016-07-01 23:27:013428 EXPECT_THAT(rv, IsOk());
bnceb9aa7112017-01-05 01:03:463429
3430 // Finish async network reads/writes.
3431 base::RunLoop().RunUntilIdle();
3432
bnc0cb98b22016-03-04 17:10:523433 HttpResponseInfo response = *trans->GetResponseInfo();
wezca1070932016-05-26 20:30:523434 EXPECT_TRUE(response.headers);
bnc0cb98b22016-03-04 17:10:523435 EXPECT_EQ("HTTP/1.1 200", response.headers->GetStatusLine());
3436
3437 EXPECT_TRUE(data.AllReadDataConsumed());
3438 EXPECT_TRUE(data.AllWriteDataConsumed());
3439 VerifyStreamsClosed(helper);
Bence Békyeacd48f2018-05-14 11:34:333440
3441 histogram_tester.ExpectBucketCount(
3442 "Net.SpdyPushedStreamFate",
3443 static_cast<int>(SpdyPushedStreamFate::kInactiveAssociatedStream), 1);
3444 histogram_tester.ExpectTotalCount("Net.SpdyPushedStreamFate", 1);
bnc0cb98b22016-03-04 17:10:523445}
3446
3447// PUSH_PROMISE on a server-initiated stream should trigger GOAWAY even if
3448// stream is closed.
bncd16676a2016-07-20 16:23:013449TEST_F(SpdyNetworkTransactionTest, ServerPushOnClosedPushedStream) {
Bence Békyeacd48f2018-05-14 11:34:333450 base::HistogramTester histogram_tester;
3451
Ryan Hamilton0239aac2018-05-19 00:03:133452 spdy::SpdySerializedFrame stream1_syn(
Bence Béky27ad0a12018-02-08 00:35:483453 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
Ryan Hamilton0239aac2018-05-19 00:03:133454 spdy::SpdySerializedFrame stream2_priority(
tombergan5d22c182017-01-11 02:05:353455 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true));
Ryan Hamilton0239aac2018-05-19 00:03:133456 spdy::SpdySerializedFrame goaway(spdy_util_.ConstructSpdyGoAway(
3457 2, spdy::ERROR_CODE_PROTOCOL_ERROR,
Bence Béky602c40c2017-07-26 05:22:563458 "Received pushed stream id 4 on invalid stream id 2 (must be odd)."));
Bence Béky7bf94362018-01-10 13:19:363459 MockWrite writes[] = {CreateMockWrite(stream1_syn, 0),
3460 CreateMockWrite(stream2_priority, 3),
3461 CreateMockWrite(goaway, 8)};
bnc0cb98b22016-03-04 17:10:523462
Ryan Hamilton0239aac2018-05-19 00:03:133463 spdy::SpdySerializedFrame stream2_syn(
Bence Békyd2df6c1c82018-04-20 22:52:013464 spdy_util_.ConstructSpdyPush(nullptr, 0, 2, 1, kPushedUrl));
Ryan Hamilton0239aac2018-05-19 00:03:133465 spdy::SpdySerializedFrame stream1_reply(
Bence Béky7bf94362018-01-10 13:19:363466 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
Ryan Hamilton0239aac2018-05-19 00:03:133467 spdy::SpdySerializedFrame stream1_body(
3468 spdy_util_.ConstructSpdyDataFrame(1, true));
bnc0cb98b22016-03-04 17:10:523469 const char kPushedData[] = "pushed";
Ryan Hamilton0239aac2018-05-19 00:03:133470 spdy::SpdySerializedFrame stream2_body(
Bence Békyd74f4382018-02-20 18:26:193471 spdy_util_.ConstructSpdyDataFrame(2, kPushedData, true));
Ryan Hamilton0239aac2018-05-19 00:03:133472 spdy::SpdySerializedFrame stream3_syn(spdy_util_.ConstructSpdyPush(
Bence Béky3e01b532018-02-06 23:04:513473 nullptr, 0, 4, 2, "https://www.example.org/bar.dat"));
bnc0cb98b22016-03-04 17:10:523474
3475 MockRead reads[] = {
Bence Béky7bf94362018-01-10 13:19:363476 CreateMockRead(stream2_syn, 1), CreateMockRead(stream1_reply, 2),
tombergan5d22c182017-01-11 02:05:353477 CreateMockRead(stream1_body, 4), CreateMockRead(stream2_body, 5),
Bence Béky7bf94362018-01-10 13:19:363478 MockRead(ASYNC, ERR_IO_PENDING, 6), CreateMockRead(stream3_syn, 7)};
bnc0cb98b22016-03-04 17:10:523479
Ryan Sleevib8d7ea02018-05-07 20:01:013480 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:103481 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
bnc0cb98b22016-03-04 17:10:523482 helper.RunPreTestSetup();
3483 helper.AddData(&data);
3484
3485 HttpNetworkTransaction* trans1 = helper.trans();
3486 TestCompletionCallback callback1;
Bence Békydb3cf652017-10-10 15:22:103487 int rv = trans1->Start(&request_, callback1.callback(), log_);
bnc0cb98b22016-03-04 17:10:523488 rv = callback1.GetResult(rv);
robpercival214763f2016-07-01 23:27:013489 EXPECT_THAT(rv, IsOk());
bnc0cb98b22016-03-04 17:10:523490 HttpResponseInfo response = *trans1->GetResponseInfo();
wezca1070932016-05-26 20:30:523491 EXPECT_TRUE(response.headers);
bnc0cb98b22016-03-04 17:10:523492 EXPECT_EQ("HTTP/1.1 200", response.headers->GetStatusLine());
3493
bnc691fda62016-08-12 00:43:163494 HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session());
bnc0cb98b22016-03-04 17:10:523495 TestCompletionCallback callback2;
Bence Békydb3cf652017-10-10 15:22:103496 HttpRequestInfo request = CreateGetPushRequest();
3497 rv = trans2.Start(&request, callback2.callback(), log_);
bnc0cb98b22016-03-04 17:10:523498 rv = callback2.GetResult(rv);
robpercival214763f2016-07-01 23:27:013499 EXPECT_THAT(rv, IsOk());
bnc691fda62016-08-12 00:43:163500 response = *trans2.GetResponseInfo();
wezca1070932016-05-26 20:30:523501 EXPECT_TRUE(response.headers);
bnc0cb98b22016-03-04 17:10:523502 EXPECT_EQ("HTTP/1.1 200", response.headers->GetStatusLine());
Bence Béky4e83f492018-05-13 23:14:253503 std::string result;
bnc691fda62016-08-12 00:43:163504 ReadResult(&trans2, &result);
bnc0cb98b22016-03-04 17:10:523505 EXPECT_EQ(kPushedData, result);
3506
3507 data.Resume();
3508 base::RunLoop().RunUntilIdle();
3509
3510 EXPECT_TRUE(data.AllReadDataConsumed());
3511 EXPECT_TRUE(data.AllWriteDataConsumed());
Bence Békyeacd48f2018-05-14 11:34:333512
3513 histogram_tester.ExpectBucketCount(
3514 "Net.SpdyPushedStreamFate",
3515 static_cast<int>(SpdyPushedStreamFate::kAssociatedStreamIdParityError),
3516 1);
3517 histogram_tester.ExpectBucketCount(
3518 "Net.SpdyPushedStreamFate",
3519 static_cast<int>(SpdyPushedStreamFate::kAcceptedNoVary), 1);
3520 histogram_tester.ExpectTotalCount("Net.SpdyPushedStreamFate", 2);
bnc0cb98b22016-03-04 17:10:523521}
3522
Bence Békye8955cf22018-01-02 17:31:293523TEST_F(SpdyNetworkTransactionTest, ServerCancelsPush) {
Ryan Hamilton0239aac2018-05-19 00:03:133524 spdy::SpdySerializedFrame req1(
3525 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
3526 spdy::SpdySerializedFrame priority(
Bence Békye8955cf22018-01-02 17:31:293527 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true));
Bence Béky1a5d8562018-01-05 17:29:283528 spdy_util_.UpdateWithStreamDestruction(1);
Ryan Hamilton0239aac2018-05-19 00:03:133529 spdy::SpdySerializedFrame req2(
3530 spdy_util_.ConstructSpdyGet(kPushedUrl, 3, LOWEST));
Bence Béky1a5d8562018-01-05 17:29:283531 MockWrite writes1[] = {CreateMockWrite(req1, 0), CreateMockWrite(priority, 3),
3532 CreateMockWrite(req2, 6)};
Bence Békye8955cf22018-01-02 17:31:293533
Ryan Hamilton0239aac2018-05-19 00:03:133534 spdy::SpdySerializedFrame reply1(
3535 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
3536 spdy::SpdySerializedFrame push(
Bence Békyd2df6c1c82018-04-20 22:52:013537 spdy_util_.ConstructSpdyPush(nullptr, 0, 2, 1, kPushedUrl));
Ryan Hamilton0239aac2018-05-19 00:03:133538 spdy::SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true));
3539 spdy::SpdySerializedFrame rst(
3540 spdy_util_.ConstructSpdyRstStream(2, spdy::ERROR_CODE_INTERNAL_ERROR));
3541 spdy::SpdySerializedFrame reply2(
3542 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
3543 spdy::SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(3, true));
Bence Béky1a5d8562018-01-05 17:29:283544 MockRead reads1[] = {CreateMockRead(reply1, 1), CreateMockRead(push, 2),
3545 CreateMockRead(body1, 4), CreateMockRead(rst, 5),
3546 CreateMockRead(reply2, 7), CreateMockRead(body2, 8),
3547 MockRead(ASYNC, 0, 9)};
Bence Békye8955cf22018-01-02 17:31:293548
Ryan Sleevib8d7ea02018-05-07 20:01:013549 SequencedSocketData data(reads1, writes1);
Bence Békye8955cf22018-01-02 17:31:293550
3551 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
3552 helper.RunPreTestSetup();
3553 helper.AddData(&data);
3554
Bence Béky1a5d8562018-01-05 17:29:283555 // First request opens up connection.
Bence Békye8955cf22018-01-02 17:31:293556 HttpNetworkTransaction* trans1 = helper.trans();
3557 TestCompletionCallback callback1;
3558 int rv = trans1->Start(&request_, callback1.callback(), log_);
3559 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
3560
3561 // Read until response body arrives. PUSH_PROMISE comes earlier.
3562 rv = callback1.WaitForResult();
3563 EXPECT_THAT(rv, IsOk());
Bence Béky1a5d8562018-01-05 17:29:283564 const HttpResponseInfo* response = trans1->GetResponseInfo();
3565 EXPECT_TRUE(response->headers);
3566 EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
3567 std::string result1;
3568 ReadResult(trans1, &result1);
3569 EXPECT_EQ("hello!", result1);
3570
3571 SpdySessionPool* spdy_session_pool = helper.session()->spdy_session_pool();
3572 SpdySessionKey key(host_port_pair_, ProxyServer::Direct(),
Matt Menke2436b2f2018-12-11 18:07:113573 PRIVACY_MODE_DISABLED,
dalyk51ab46b2019-10-15 15:14:343574 SpdySessionKey::IsProxySession::kFalse, SocketTag(),
Ben Schwartz3ff4dc1e62021-04-27 21:15:233575 NetworkIsolationKey(), SecureDnsPolicy::kAllow);
Bence Béky1a5d8562018-01-05 17:29:283576 base::WeakPtr<SpdySession> spdy_session =
3577 spdy_session_pool->FindAvailableSession(
Bence Békyd885b2b2018-02-03 00:58:313578 key, /* enable_ip_based_pooling = */ true,
3579 /* is_websocket = */ false, log_);
Bence Béky1a5d8562018-01-05 17:29:283580 EXPECT_EQ(1u, num_unclaimed_pushed_streams(spdy_session));
Bence Békye8955cf22018-01-02 17:31:293581
3582 // Create request matching pushed stream.
Bence Békye8955cf22018-01-02 17:31:293583 HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session());
Bence Béky1a5d8562018-01-05 17:29:283584 HttpRequestInfo request2 = CreateGetPushRequest();
Bence Békye8955cf22018-01-02 17:31:293585 TestCompletionCallback callback2;
Bence Béky1a5d8562018-01-05 17:29:283586 rv = trans2.Start(&request2, callback2.callback(), log_);
Bence Békye8955cf22018-01-02 17:31:293587 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
3588
Bence Béky1a5d8562018-01-05 17:29:283589 // Pushed stream is now claimed by second request.
3590 EXPECT_EQ(0u, num_unclaimed_pushed_streams(spdy_session));
3591
3592 // Second request receives RST_STREAM and is retried on the same connection.
Bence Békye8955cf22018-01-02 17:31:293593 rv = callback2.WaitForResult();
Bence Béky1a5d8562018-01-05 17:29:283594 EXPECT_THAT(rv, IsOk());
3595 response = trans2.GetResponseInfo();
3596 EXPECT_TRUE(response->headers);
3597 EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
3598 std::string result2;
3599 ReadResult(&trans2, &result2);
3600 EXPECT_EQ("hello!", result2);
Bence Békye8955cf22018-01-02 17:31:293601
3602 // Read EOF.
3603 base::RunLoop().RunUntilIdle();
3604
Bence Béky1a5d8562018-01-05 17:29:283605 helper.VerifyDataConsumed();
3606}
3607
3608// Regression test for https://crbug.com/776415.
3609// A client-initiated request can only pool to an existing HTTP/2 connection if
3610// the IP address matches. However, a resource can be pushed by the server on a
3611// connection even if the IP address does not match. This test verifies that if
3612// the request binds to such a pushed stream, and after that the server resets
3613// the stream before SpdySession::GetPushedStream() is called, then the retry
3614// (using a client-initiated stream) does not pool to this connection.
3615TEST_F(SpdyNetworkTransactionTest, ServerCancelsCrossOriginPush) {
3616 const char* kUrl1 = "https://www.example.org";
3617 const char* kUrl2 = "https://mail.example.org";
3618
3619 auto resolver = std::make_unique<MockHostResolver>();
3620 resolver->rules()->ClearRules();
3621 resolver->rules()->AddRule("www.example.org", "127.0.0.1");
3622 resolver->rules()->AddRule("mail.example.org", "127.0.0.2");
3623
3624 auto session_deps = std::make_unique<SpdySessionDependencies>();
3625 session_deps->host_resolver = std::move(resolver);
3626 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
3627 std::move(session_deps));
3628
Ryan Hamilton0239aac2018-05-19 00:03:133629 spdy::SpdySerializedFrame req1(spdy_util_.ConstructSpdyGet(kUrl1, 1, LOWEST));
3630 spdy::SpdySerializedFrame priority(
Bence Béky1a5d8562018-01-05 17:29:283631 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true));
3632 MockWrite writes1[] = {CreateMockWrite(req1, 0),
3633 CreateMockWrite(priority, 3)};
3634
Ryan Hamilton0239aac2018-05-19 00:03:133635 spdy::SpdySerializedFrame reply1(
3636 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
3637 spdy::SpdySerializedFrame push(
Bence Béky1a5d8562018-01-05 17:29:283638 spdy_util_.ConstructSpdyPush(nullptr, 0, 2, 1, kUrl2));
Ryan Hamilton0239aac2018-05-19 00:03:133639 spdy::SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true));
3640 spdy::SpdySerializedFrame rst(
3641 spdy_util_.ConstructSpdyRstStream(2, spdy::ERROR_CODE_INTERNAL_ERROR));
Bence Béky1a5d8562018-01-05 17:29:283642 MockRead reads1[] = {
3643 CreateMockRead(reply1, 1), CreateMockRead(push, 2),
3644 CreateMockRead(body1, 4), CreateMockRead(rst, 5),
3645 MockRead(ASYNC, ERR_IO_PENDING, 6), MockRead(ASYNC, 0, 7)};
3646
Ryan Sleevib8d7ea02018-05-07 20:01:013647 SequencedSocketData data1(reads1, writes1);
Bence Béky1a5d8562018-01-05 17:29:283648
3649 SpdyTestUtil spdy_util2;
Ryan Hamilton0239aac2018-05-19 00:03:133650 spdy::SpdySerializedFrame req2(spdy_util2.ConstructSpdyGet(kUrl2, 1, LOWEST));
Bence Béky1a5d8562018-01-05 17:29:283651 MockWrite writes2[] = {CreateMockWrite(req2, 0)};
3652
Ryan Hamilton0239aac2018-05-19 00:03:133653 spdy::SpdySerializedFrame reply2(
3654 spdy_util2.ConstructSpdyGetReply(nullptr, 0, 1));
3655 spdy::SpdySerializedFrame body2(spdy_util2.ConstructSpdyDataFrame(
Bence Békyd74f4382018-02-20 18:26:193656 1, "Response on the second connection.", true));
Bence Béky1a5d8562018-01-05 17:29:283657 MockRead reads2[] = {CreateMockRead(reply2, 1), CreateMockRead(body2, 2),
3658 MockRead(ASYNC, 0, 3)};
3659
Ryan Sleevib8d7ea02018-05-07 20:01:013660 SequencedSocketData data2(reads2, writes2);
Bence Béky1a5d8562018-01-05 17:29:283661
3662 helper.RunPreTestSetup();
3663 helper.AddData(&data1);
3664 helper.AddData(&data2);
3665
3666 // First request opens up connection to www.example.org.
3667 HttpNetworkTransaction* trans1 = helper.trans();
3668 HttpRequestInfo request1;
3669 request1.method = "GET";
3670 request1.url = GURL(kUrl1);
Ramin Halavatib5e433e62018-02-07 07:41:103671 request1.traffic_annotation =
3672 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
Bence Béky1a5d8562018-01-05 17:29:283673 TestCompletionCallback callback1;
3674 int rv = trans1->Start(&request1, callback1.callback(), log_);
3675 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
3676
3677 // Read until response body arrives. PUSH_PROMISE comes earlier.
3678 rv = callback1.WaitForResult();
3679 EXPECT_THAT(rv, IsOk());
3680 const HttpResponseInfo* response = trans1->GetResponseInfo();
3681 EXPECT_TRUE(response->headers);
3682 EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
3683 std::string result1;
3684 ReadResult(trans1, &result1);
3685 EXPECT_EQ("hello!", result1);
3686
3687 SpdySessionPool* spdy_session_pool = helper.session()->spdy_session_pool();
3688 SpdySessionKey key1(HostPortPair::FromURL(GURL(kUrl1)), ProxyServer::Direct(),
Matt Menke2436b2f2018-12-11 18:07:113689 PRIVACY_MODE_DISABLED,
dalyk51ab46b2019-10-15 15:14:343690 SpdySessionKey::IsProxySession::kFalse, SocketTag(),
Ben Schwartz3ff4dc1e62021-04-27 21:15:233691 NetworkIsolationKey(), SecureDnsPolicy::kAllow);
Bence Béky1a5d8562018-01-05 17:29:283692 base::WeakPtr<SpdySession> spdy_session1 =
3693 spdy_session_pool->FindAvailableSession(
Bence Békyd885b2b2018-02-03 00:58:313694 key1, /* enable_ip_based_pooling = */ true,
3695 /* is_websocket = */ false, log_);
Bence Béky1a5d8562018-01-05 17:29:283696 EXPECT_EQ(1u, num_unclaimed_pushed_streams(spdy_session1));
3697
3698 // While cross-origin push for kUrl2 is allowed on spdy_session1,
3699 // a client-initiated request would not pool to this connection,
3700 // because the IP address does not match.
3701 SpdySessionKey key2(HostPortPair::FromURL(GURL(kUrl2)), ProxyServer::Direct(),
Matt Menke2436b2f2018-12-11 18:07:113702 PRIVACY_MODE_DISABLED,
dalyk51ab46b2019-10-15 15:14:343703 SpdySessionKey::IsProxySession::kFalse, SocketTag(),
Ben Schwartz3ff4dc1e62021-04-27 21:15:233704 NetworkIsolationKey(), SecureDnsPolicy::kAllow);
Bence Béky1a5d8562018-01-05 17:29:283705 EXPECT_FALSE(spdy_session_pool->FindAvailableSession(
Bence Békyd885b2b2018-02-03 00:58:313706 key2, /* enable_ip_based_pooling = */ true,
3707 /* is_websocket = */ false, log_));
Bence Béky1a5d8562018-01-05 17:29:283708
3709 // Create request matching pushed stream.
3710 HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session());
3711 HttpRequestInfo request2;
3712 request2.method = "GET";
3713 request2.url = GURL(kUrl2);
Ramin Halavatib5e433e62018-02-07 07:41:103714 request2.traffic_annotation =
3715 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
Bence Béky1a5d8562018-01-05 17:29:283716 TestCompletionCallback callback2;
3717 rv = trans2.Start(&request2, callback2.callback(), log_);
3718 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
3719
3720 // Pushed stream is now claimed by second request.
3721 EXPECT_EQ(0u, num_unclaimed_pushed_streams(spdy_session1));
3722
3723 // Second request receives RST_STREAM and is retried on a new connection.
3724 rv = callback2.WaitForResult();
3725 EXPECT_THAT(rv, IsOk());
3726 response = trans2.GetResponseInfo();
3727 EXPECT_TRUE(response->headers);
3728 EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
3729 std::string result2;
3730 ReadResult(&trans2, &result2);
3731 EXPECT_EQ("Response on the second connection.", result2);
3732
3733 // Make sure that the first connection is still open. This is important in
3734 // order to test that the retry created its own connection (because the IP
3735 // address does not match), instead of using the connection of the cancelled
3736 // pushed stream.
3737 EXPECT_TRUE(spdy_session1);
3738
3739 // Read EOF.
3740 data1.Resume();
3741 base::RunLoop().RunUntilIdle();
3742
3743 helper.VerifyDataConsumed();
Bence Békye8955cf22018-01-02 17:31:293744}
3745
Matt Menke5062be22019-05-01 17:50:243746TEST_F(SpdyNetworkTransactionTest, NoConnectionPoolingOverTunnel) {
3747 // Use port 443 for two reasons: This makes the endpoint is port 443 check in
3748 // NormalSpdyTransactionHelper pass, and this means that the tunnel uses the
3749 // same port as the servers, to further confuse things.
3750 const char kPacString[] = "PROXY myproxy:443";
3751
3752 auto session_deps = std::make_unique<SpdySessionDependencies>(
Nicolas Arciniegad2013f92020-02-07 23:00:563753 ConfiguredProxyResolutionService::CreateFixedFromPacResult(
Matt Menke5062be22019-05-01 17:50:243754 kPacString, TRAFFIC_ANNOTATION_FOR_TESTS));
3755 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
3756 std::move(session_deps));
3757
3758 // Only one request uses the first connection.
3759 spdy::SpdySerializedFrame req1(
3760 spdy_util_.ConstructSpdyGet("https://www.example.org", 1, LOWEST));
3761 MockWrite writes1[] = {
3762 MockWrite(ASYNC, 0,
3763 "CONNECT www.example.org:443 HTTP/1.1\r\n"
3764 "Host: www.example.org:443\r\n"
3765 "Proxy-Connection: keep-alive\r\n\r\n"),
3766 CreateMockWrite(req1, 2),
3767 };
3768
3769 spdy::SpdySerializedFrame resp1(
3770 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
3771 spdy::SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true));
3772 MockRead reads1[] = {MockRead(ASYNC, 1, "HTTP/1.1 200 OK\r\n\r\n"),
3773 CreateMockRead(resp1, 3), CreateMockRead(body1, 4),
3774 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 5)};
3775
3776 MockConnect connect1(ASYNC, OK);
3777 SequencedSocketData data1(connect1, reads1, writes1);
3778
3779 // Run a transaction to completion to set up a SPDY session.
3780 helper.RunToCompletion(&data1);
3781 TransactionHelperResult out = helper.output();
3782 EXPECT_THAT(out.rv, IsOk());
3783 EXPECT_EQ("HTTP/1.1 200", out.status_line);
3784 EXPECT_EQ("hello!", out.response_data);
3785
3786 // A new SPDY session should have been created.
3787 SpdySessionKey key1(HostPortPair("www.example.org", 443),
Eric Orth5ccc3f02021-09-23 00:01:573788 PacResultElementToProxyServer(kPacString),
Matt Menke5062be22019-05-01 17:50:243789 PRIVACY_MODE_DISABLED,
dalyk51ab46b2019-10-15 15:14:343790 SpdySessionKey::IsProxySession::kFalse, SocketTag(),
Ben Schwartz3ff4dc1e62021-04-27 21:15:233791 NetworkIsolationKey(), SecureDnsPolicy::kAllow);
Matt Menke5062be22019-05-01 17:50:243792 base::WeakPtr<SpdySession> session1 =
3793 helper.session()->spdy_session_pool()->FindAvailableSession(
Cammie Smith Barnes5191037b72021-03-01 22:06:533794 key1, true /* enable_ip_based_pooling */, false /* is_websocket */,
Matt Menke5062be22019-05-01 17:50:243795 NetLogWithSource());
3796 ASSERT_TRUE(session1);
3797
3798 // The second request uses a second connection.
3799 SpdyTestUtil spdy_util2;
3800 spdy::SpdySerializedFrame req2(
3801 spdy_util2.ConstructSpdyGet("https://example.test", 1, LOWEST));
3802 MockWrite writes2[] = {
3803 MockWrite(ASYNC, 0,
3804 "CONNECT example.test:443 HTTP/1.1\r\n"
3805 "Host: example.test:443\r\n"
3806 "Proxy-Connection: keep-alive\r\n\r\n"),
3807 CreateMockWrite(req2, 2),
3808 };
3809
3810 spdy::SpdySerializedFrame resp2(
3811 spdy_util2.ConstructSpdyGetReply(nullptr, 0, 1));
3812 spdy::SpdySerializedFrame body2(spdy_util2.ConstructSpdyDataFrame(1, true));
3813 MockRead reads2[] = {MockRead(ASYNC, 1, "HTTP/1.1 200 OK\r\n\r\n"),
3814 CreateMockRead(resp2, 3), CreateMockRead(body2, 4),
3815 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 5)};
3816
3817 MockConnect connect2(ASYNC, OK);
3818 SequencedSocketData data2(connect2, reads2, writes2);
3819 helper.AddData(&data2);
3820
3821 HttpRequestInfo request2;
3822 request2.method = "GET";
3823 request2.url = GURL("https://example.test/");
3824 request2.load_flags = 0;
3825 request2.traffic_annotation =
3826 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
3827 auto trans2 = std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY,
3828 helper.session());
3829
3830 TestCompletionCallback callback;
3831 EXPECT_THAT(trans2->Start(&request2, callback.callback(), NetLogWithSource()),
3832 IsError(ERR_IO_PENDING));
3833
3834 // Wait for the second request to get headers. It should create a new H2
3835 // session to do so.
3836 EXPECT_THAT(callback.WaitForResult(), IsOk());
3837
3838 const HttpResponseInfo* response = trans2->GetResponseInfo();
3839 ASSERT_TRUE(response);
3840 ASSERT_TRUE(response->headers);
3841 EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
3842 EXPECT_TRUE(response->was_fetched_via_spdy);
3843 EXPECT_TRUE(response->was_alpn_negotiated);
3844 std::string response_data;
3845 ASSERT_THAT(ReadTransaction(trans2.get(), &response_data), IsOk());
3846 EXPECT_EQ("hello!", response_data);
3847
3848 // Inspect the new session.
Eric Orth5ccc3f02021-09-23 00:01:573849 SpdySessionKey key2(HostPortPair("example.test", 443),
3850 PacResultElementToProxyServer(kPacString),
3851 PRIVACY_MODE_DISABLED,
3852 SpdySessionKey::IsProxySession::kFalse, SocketTag(),
3853 NetworkIsolationKey(), SecureDnsPolicy::kAllow);
Matt Menke5062be22019-05-01 17:50:243854 base::WeakPtr<SpdySession> session2 =
3855 helper.session()->spdy_session_pool()->FindAvailableSession(
Cammie Smith Barnes5191037b72021-03-01 22:06:533856 key2, true /* enable_ip_based_pooling */, false /* is_websocket */,
Matt Menke5062be22019-05-01 17:50:243857 NetLogWithSource());
3858 ASSERT_TRUE(session2);
3859 ASSERT_TRUE(session1);
3860 EXPECT_NE(session1.get(), session2.get());
3861}
3862
3863// Check that if a session is found after host resolution, but is closed before
3864// the task to try to use it executes, the request will continue to create a new
3865// socket and use it.
3866TEST_F(SpdyNetworkTransactionTest, ConnectionPoolingSessionClosedBeforeUse) {
3867 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
3868
3869 // Only one request uses the first connection.
3870 spdy::SpdySerializedFrame req1(
3871 spdy_util_.ConstructSpdyGet("https://www.example.org", 1, LOWEST));
3872 MockWrite writes1[] = {
3873 CreateMockWrite(req1, 0),
3874 };
3875
3876 spdy::SpdySerializedFrame resp1(
3877 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
3878 spdy::SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true));
3879 MockRead reads1[] = {CreateMockRead(resp1, 1), CreateMockRead(body1, 2),
3880 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 3)};
3881
3882 MockConnect connect1(ASYNC, OK);
3883 SequencedSocketData data1(connect1, reads1, writes1);
3884
3885 // Run a transaction to completion to set up a SPDY session.
3886 helper.RunToCompletion(&data1);
3887 TransactionHelperResult out = helper.output();
3888 EXPECT_THAT(out.rv, IsOk());
3889 EXPECT_EQ("HTTP/1.1 200", out.status_line);
3890 EXPECT_EQ("hello!", out.response_data);
3891
3892 // A new SPDY session should have been created.
3893 SpdySessionKey key1(HostPortPair("www.example.org", 443),
3894 ProxyServer::Direct(), PRIVACY_MODE_DISABLED,
dalyk51ab46b2019-10-15 15:14:343895 SpdySessionKey::IsProxySession::kFalse, SocketTag(),
Ben Schwartz3ff4dc1e62021-04-27 21:15:233896 NetworkIsolationKey(), SecureDnsPolicy::kAllow);
Matt Menke5062be22019-05-01 17:50:243897 EXPECT_TRUE(helper.session()->spdy_session_pool()->FindAvailableSession(
Cammie Smith Barnes5191037b72021-03-01 22:06:533898 key1, true /* enable_ip_based_pooling */, false /* is_websocket */,
Matt Menke5062be22019-05-01 17:50:243899 NetLogWithSource()));
3900
3901 // The second request uses a second connection.
3902 SpdyTestUtil spdy_util2;
3903 spdy::SpdySerializedFrame req2(
3904 spdy_util2.ConstructSpdyGet("https://example.test", 1, LOWEST));
3905 MockWrite writes2[] = {
3906 CreateMockWrite(req2, 0),
3907 };
3908
3909 spdy::SpdySerializedFrame resp2(
3910 spdy_util2.ConstructSpdyGetReply(nullptr, 0, 1));
3911 spdy::SpdySerializedFrame body2(spdy_util2.ConstructSpdyDataFrame(1, true));
3912 MockRead reads2[] = {CreateMockRead(resp2, 1), CreateMockRead(body2, 2),
3913 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 3)};
3914
3915 MockConnect connect2(ASYNC, OK);
3916 SequencedSocketData data2(connect2, reads2, writes2);
3917 helper.AddData(&data2);
3918
3919 HttpRequestInfo request2;
3920 request2.method = "GET";
3921 request2.url = GURL("https://example.test/");
3922 request2.load_flags = 0;
3923 request2.traffic_annotation =
3924 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
3925 auto trans2 = std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY,
3926 helper.session());
3927
3928 // Set on-demand mode and run the second request to the DNS lookup.
3929 helper.session_deps()->host_resolver->set_ondemand_mode(true);
3930 TestCompletionCallback callback;
3931 EXPECT_THAT(trans2->Start(&request2, callback.callback(), NetLogWithSource()),
3932 IsError(ERR_IO_PENDING));
3933 base::RunLoop().RunUntilIdle();
3934 ASSERT_TRUE(helper.session_deps()->host_resolver->has_pending_requests());
3935
3936 // Resolve the request now, which should create an alias for the SpdySession
3937 // immediately, but the task to use the session for the second request should
3938 // run asynchronously, so it hasn't run yet.
3939 helper.session_deps()->host_resolver->ResolveOnlyRequestNow();
3940 SpdySessionKey key2(HostPortPair("example.test", 443), ProxyServer::Direct(),
3941 PRIVACY_MODE_DISABLED,
dalyk51ab46b2019-10-15 15:14:343942 SpdySessionKey::IsProxySession::kFalse, SocketTag(),
Ben Schwartz3ff4dc1e62021-04-27 21:15:233943 NetworkIsolationKey(), SecureDnsPolicy::kAllow);
Matt Menke5062be22019-05-01 17:50:243944 base::WeakPtr<SpdySession> session1 =
3945 helper.session()->spdy_session_pool()->FindAvailableSession(
Cammie Smith Barnes5191037b72021-03-01 22:06:533946 key2, true /* enable_ip_based_pooling */, false /* is_websocket */,
Matt Menke5062be22019-05-01 17:50:243947 NetLogWithSource());
3948 ASSERT_TRUE(session1);
3949 EXPECT_EQ(key1, session1->spdy_session_key());
3950 // Remove the session before the second request can try to use it.
3951 helper.session()->spdy_session_pool()->CloseAllSessions();
3952
3953 // Wait for the second request to get headers. It should create a new H2
3954 // session to do so.
3955 EXPECT_THAT(callback.WaitForResult(), IsOk());
3956
3957 const HttpResponseInfo* response = trans2->GetResponseInfo();
3958 ASSERT_TRUE(response);
3959 ASSERT_TRUE(response->headers);
3960 EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
3961 EXPECT_TRUE(response->was_fetched_via_spdy);
3962 EXPECT_TRUE(response->was_alpn_negotiated);
3963 std::string response_data;
3964 ASSERT_THAT(ReadTransaction(trans2.get(), &response_data), IsOk());
3965 EXPECT_EQ("hello!", response_data);
3966
3967 // Inspect the new session.
3968 base::WeakPtr<SpdySession> session2 =
3969 helper.session()->spdy_session_pool()->FindAvailableSession(
Cammie Smith Barnes5191037b72021-03-01 22:06:533970 key2, true /* enable_ip_based_pooling */, false /* is_websocket */,
Matt Menke5062be22019-05-01 17:50:243971 NetLogWithSource());
3972 ASSERT_TRUE(session2);
3973 EXPECT_EQ(key2, session2->spdy_session_key());
3974 helper.VerifyDataConsumed();
3975}
3976
Xiaohan Wang2a6845b2022-01-08 04:40:573977#if BUILDFLAG(IS_ANDROID)
Matt Menke5062be22019-05-01 17:50:243978
3979// Test this if two HttpNetworkTransactions try to repurpose the same
3980// SpdySession with two different SocketTags, only one request gets the session,
3981// while the other makes a new SPDY session.
3982TEST_F(SpdyNetworkTransactionTest, ConnectionPoolingMultipleSocketTags) {
3983 const SocketTag kSocketTag1(SocketTag::UNSET_UID, 1);
3984 const SocketTag kSocketTag2(SocketTag::UNSET_UID, 2);
3985 const SocketTag kSocketTag3(SocketTag::UNSET_UID, 3);
3986
3987 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
3988
3989 // The first and third requests use the first connection.
3990 spdy::SpdySerializedFrame req1(
3991 spdy_util_.ConstructSpdyGet("https://www.example.org", 1, LOWEST));
3992 spdy_util_.UpdateWithStreamDestruction(1);
3993 spdy::SpdySerializedFrame req3(
3994 spdy_util_.ConstructSpdyGet("https://example.test/request3", 3, LOWEST));
3995 MockWrite writes1[] = {
3996 CreateMockWrite(req1, 0),
3997 CreateMockWrite(req3, 3),
3998 };
3999
4000 spdy::SpdySerializedFrame resp1(
4001 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
4002 spdy::SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true));
4003 spdy::SpdySerializedFrame resp3(
4004 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
4005 spdy::SpdySerializedFrame body3(spdy_util_.ConstructSpdyDataFrame(3, true));
4006 MockRead reads1[] = {CreateMockRead(resp1, 1), CreateMockRead(body1, 2),
4007 CreateMockRead(resp3, 4), CreateMockRead(body3, 5),
4008 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 6)};
4009
4010 SequencedSocketData data1(MockConnect(ASYNC, OK), reads1, writes1);
4011 helper.AddData(&data1);
4012
4013 // Due to the vagaries of how the socket pools work, in this particular case,
4014 // the second ConnectJob will be cancelled, but only after it tries to start
4015 // connecting. This does not happen in the general case of a bunch of requests
4016 // using the same socket tag.
4017 SequencedSocketData data2(MockConnect(SYNCHRONOUS, ERR_IO_PENDING),
4018 base::span<const MockRead>(),
4019 base::span<const MockWrite>());
4020 helper.AddData(&data2);
4021
4022 // The second request uses a second connection.
4023 SpdyTestUtil spdy_util2;
4024 spdy::SpdySerializedFrame req2(
4025 spdy_util2.ConstructSpdyGet("https://example.test/request2", 1, LOWEST));
4026 MockWrite writes2[] = {
4027 CreateMockWrite(req2, 0),
4028 };
4029
4030 spdy::SpdySerializedFrame resp2(
4031 spdy_util2.ConstructSpdyGetReply(nullptr, 0, 1));
4032 spdy::SpdySerializedFrame body2(spdy_util2.ConstructSpdyDataFrame(1, true));
4033 MockRead reads2[] = {CreateMockRead(resp2, 1), CreateMockRead(body2, 2),
4034 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 3)};
4035
4036 SequencedSocketData data3(MockConnect(ASYNC, OK), reads2, writes2);
4037 helper.AddData(&data3);
4038
4039 // Run a transaction to completion to set up a SPDY session. This can't use
4040 // RunToCompletion(), since it can't call VerifyDataConsumed() yet.
4041 helper.RunPreTestSetup();
4042 helper.RunDefaultTest();
4043 TransactionHelperResult out = helper.output();
4044 EXPECT_THAT(out.rv, IsOk());
4045 EXPECT_EQ("HTTP/1.1 200", out.status_line);
4046 EXPECT_EQ("hello!", out.response_data);
4047
4048 // A new SPDY session should have been created.
4049 SpdySessionKey key1(HostPortPair("www.example.org", 443),
4050 ProxyServer::Direct(), PRIVACY_MODE_DISABLED,
dalyk51ab46b2019-10-15 15:14:344051 SpdySessionKey::IsProxySession::kFalse, SocketTag(),
Ben Schwartz3ff4dc1e62021-04-27 21:15:234052 NetworkIsolationKey(), SecureDnsPolicy::kAllow);
Matt Menke5062be22019-05-01 17:50:244053 EXPECT_TRUE(helper.session()->spdy_session_pool()->FindAvailableSession(
Cammie Smith Barnes5191037b72021-03-01 22:06:534054 key1, true /* enable_ip_based_pooling */, false /* is_websocket */,
Matt Menke5062be22019-05-01 17:50:244055 NetLogWithSource()));
4056
4057 // Set on-demand mode for the next two requests.
4058 helper.session_deps()->host_resolver->set_ondemand_mode(true);
4059
4060 HttpRequestInfo request2;
4061 request2.socket_tag = kSocketTag2;
4062 request2.method = "GET";
4063 request2.url = GURL("https://example.test/request2");
4064 request2.load_flags = 0;
4065 request2.traffic_annotation =
4066 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
4067 auto trans2 = std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY,
4068 helper.session());
4069 TestCompletionCallback callback2;
4070 EXPECT_THAT(
4071 trans2->Start(&request2, callback2.callback(), NetLogWithSource()),
4072 IsError(ERR_IO_PENDING));
4073
4074 HttpRequestInfo request3;
4075 request3.socket_tag = kSocketTag3;
4076 request3.method = "GET";
4077 request3.url = GURL("https://example.test/request3");
4078 request3.load_flags = 0;
4079 request3.traffic_annotation =
4080 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
4081 auto trans3 = std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY,
4082 helper.session());
4083 TestCompletionCallback callback3;
4084 EXPECT_THAT(
4085 trans3->Start(&request3, callback3.callback(), NetLogWithSource()),
4086 IsError(ERR_IO_PENDING));
4087
4088 // Run the message loop until both requests are waiting on the host resolver.
4089 base::RunLoop().RunUntilIdle();
4090 ASSERT_TRUE(helper.session_deps()->host_resolver->has_pending_requests());
4091
4092 // Complete the second requests's DNS lookup now, which should create an alias
4093 // for the SpdySession immediately, but the task to use the session for the
4094 // second request should run asynchronously, so it hasn't run yet.
4095 helper.session_deps()->host_resolver->ResolveNow(2);
4096 SpdySessionKey key2(HostPortPair("example.test", 443), ProxyServer::Direct(),
4097 PRIVACY_MODE_DISABLED,
dalyk51ab46b2019-10-15 15:14:344098 SpdySessionKey::IsProxySession::kFalse, kSocketTag2,
Ben Schwartz3ff4dc1e62021-04-27 21:15:234099 NetworkIsolationKey(), SecureDnsPolicy::kAllow);
Matt Menke5062be22019-05-01 17:50:244100
4101 // Complete the third requests's DNS lookup now, which should hijack the
4102 // SpdySession from the second request.
4103 helper.session_deps()->host_resolver->ResolveNow(3);
4104 SpdySessionKey key3(HostPortPair("example.test", 443), ProxyServer::Direct(),
4105 PRIVACY_MODE_DISABLED,
dalyk51ab46b2019-10-15 15:14:344106 SpdySessionKey::IsProxySession::kFalse, kSocketTag3,
Ben Schwartz3ff4dc1e62021-04-27 21:15:234107 NetworkIsolationKey(), SecureDnsPolicy::kAllow);
Matt Menke5062be22019-05-01 17:50:244108
4109 // Wait for the second request to get headers. It should create a new H2
4110 // session to do so.
4111 EXPECT_THAT(callback2.WaitForResult(), IsOk());
4112
4113 const HttpResponseInfo* response = trans2->GetResponseInfo();
4114 ASSERT_TRUE(response);
4115 ASSERT_TRUE(response->headers);
4116 EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
4117 EXPECT_TRUE(response->was_fetched_via_spdy);
4118 EXPECT_TRUE(response->was_alpn_negotiated);
4119 std::string response_data;
4120 ASSERT_THAT(ReadTransaction(trans2.get(), &response_data), IsOk());
4121 EXPECT_EQ("hello!", response_data);
4122
4123 // Wait for the third request to get headers. It should have reused the first
4124 // session.
4125 EXPECT_THAT(callback3.WaitForResult(), IsOk());
4126
4127 response = trans3->GetResponseInfo();
4128 ASSERT_TRUE(response);
4129 ASSERT_TRUE(response->headers);
4130 EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
4131 EXPECT_TRUE(response->was_fetched_via_spdy);
4132 EXPECT_TRUE(response->was_alpn_negotiated);
4133 ASSERT_THAT(ReadTransaction(trans3.get(), &response_data), IsOk());
4134 EXPECT_EQ("hello!", response_data);
4135
4136 helper.VerifyDataConsumed();
4137}
4138
Cammie Smith Barnes5191037b72021-03-01 22:06:534139TEST_F(SpdyNetworkTransactionTest, SocketTagChangeSessionTagWithDnsAliases) {
4140 SocketTag socket_tag_1(SocketTag::UNSET_UID, 1);
4141 SocketTag socket_tag_2(SocketTag::UNSET_UID, 2);
4142 request_.socket_tag = socket_tag_1;
Cammie Smith Barnes6b93b992021-02-03 21:25:404143
Cammie Smith Barnes5191037b72021-03-01 22:06:534144 std::unique_ptr<SpdySessionDependencies> session_deps =
4145 std::make_unique<SpdySessionDependencies>();
4146 std::unique_ptr<MockCachingHostResolver> host_resolver =
4147 std::make_unique<MockCachingHostResolver>(2 /* cache_invalidation_num */);
4148 session_deps->host_resolver = std::move(host_resolver);
Cammie Smith Barnes6b93b992021-02-03 21:25:404149
Cammie Smith Barnes5191037b72021-03-01 22:06:534150 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
4151 std::move(session_deps));
4152
4153 GURL url = request_.url;
Eric Orthac661912022-01-10 21:44:174154 std::set<std::string> dns_aliases({"alias1", "alias2", "alias3"});
Cammie Smith Barnes5191037b72021-03-01 22:06:534155 helper.session_deps()->host_resolver->rules()->AddIPLiteralRuleWithDnsAliases(
4156 url.host(), "127.0.0.1", dns_aliases);
4157
Cammie Smith Barnes6b93b992021-02-03 21:25:404158 spdy::SpdySerializedFrame req1(
Cammie Smith Barnes5191037b72021-03-01 22:06:534159 spdy_util_.ConstructSpdyGet(url.spec().c_str(), 1, DEFAULT_PRIORITY));
Cammie Smith Barnes6b93b992021-02-03 21:25:404160 spdy_util_.UpdateWithStreamDestruction(1);
Cammie Smith Barnes5191037b72021-03-01 22:06:534161 spdy::SpdySerializedFrame req2(
4162 spdy_util_.ConstructSpdyGet(url.spec().c_str(), 3, DEFAULT_PRIORITY));
4163 MockWrite writes[] = {
Cammie Smith Barnes6b93b992021-02-03 21:25:404164 CreateMockWrite(req1, 0),
Cammie Smith Barnes5191037b72021-03-01 22:06:534165 CreateMockWrite(req2, 3),
Cammie Smith Barnes6b93b992021-02-03 21:25:404166 };
4167
4168 spdy::SpdySerializedFrame resp1(
4169 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
4170 spdy::SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true));
Cammie Smith Barnes6b93b992021-02-03 21:25:404171 spdy::SpdySerializedFrame resp2(
Cammie Smith Barnes5191037b72021-03-01 22:06:534172 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
4173 spdy::SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(3, true));
4174 MockRead reads[] = {CreateMockRead(resp1, 1), CreateMockRead(body1, 2),
4175 CreateMockRead(resp2, 4), CreateMockRead(body2, 5),
4176 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 6)};
Cammie Smith Barnes6b93b992021-02-03 21:25:404177
Cammie Smith Barnes5191037b72021-03-01 22:06:534178 SequencedSocketData data(MockConnect(ASYNC, OK), reads, writes);
4179 helper.AddData(&data);
Cammie Smith Barnes6b93b992021-02-03 21:25:404180
4181 // Run a transaction to completion to set up a SPDY session. This can't use
Cammie Smith Barnes5191037b72021-03-01 22:06:534182 // RunToCompletion(), since it can't call VerifyDataConsumed() yet because
4183 // there are still further requests expected.
Cammie Smith Barnes6b93b992021-02-03 21:25:404184 helper.RunPreTestSetup();
4185 helper.RunDefaultTest();
4186 TransactionHelperResult out = helper.output();
4187 EXPECT_THAT(out.rv, IsOk());
4188 EXPECT_EQ("HTTP/1.1 200", out.status_line);
4189 EXPECT_EQ("hello!", out.response_data);
4190
4191 // A new SPDY session should have been created.
Cammie Smith Barnes5191037b72021-03-01 22:06:534192 EXPECT_EQ(1u, helper.GetSpdySessionCount());
4193 SpdySessionKey key1(HostPortPair(url.host(), 443), ProxyServer::Direct(),
4194 PRIVACY_MODE_DISABLED,
4195 SpdySessionKey::IsProxySession::kFalse, socket_tag_1,
Ben Schwartz3ff4dc1e62021-04-27 21:15:234196 NetworkIsolationKey(), SecureDnsPolicy::kAllow);
Cammie Smith Barnes6b93b992021-02-03 21:25:404197 EXPECT_TRUE(helper.session()->spdy_session_pool()->FindAvailableSession(
Cammie Smith Barnes5191037b72021-03-01 22:06:534198 key1, true /* enable_ip_based_pooling */, false /* is_websocket */,
Cammie Smith Barnes6b93b992021-02-03 21:25:404199 NetLogWithSource()));
Cammie Smith Barnes5191037b72021-03-01 22:06:534200 EXPECT_EQ(
4201 dns_aliases,
4202 helper.session()->spdy_session_pool()->GetDnsAliasesForSessionKey(key1));
Cammie Smith Barnes6b93b992021-02-03 21:25:404203
Cammie Smith Barnes5191037b72021-03-01 22:06:534204 // Clear host resolver rules to ensure that cached values for DNS aliases
4205 // are used.
4206 helper.session_deps()->host_resolver->rules()->ClearRules();
Cammie Smith Barnes6b93b992021-02-03 21:25:404207
4208 HttpRequestInfo request2;
Cammie Smith Barnes5191037b72021-03-01 22:06:534209 request2.socket_tag = socket_tag_2;
Cammie Smith Barnes6b93b992021-02-03 21:25:404210 request2.method = "GET";
Cammie Smith Barnes5191037b72021-03-01 22:06:534211 request2.url = url;
Cammie Smith Barnes6b93b992021-02-03 21:25:404212 request2.load_flags = 0;
4213 request2.traffic_annotation =
4214 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
Cammie Smith Barnes5191037b72021-03-01 22:06:534215 SpdySessionKey key2(HostPortPair(url.host(), 443), ProxyServer::Direct(),
4216 PRIVACY_MODE_DISABLED,
4217 SpdySessionKey::IsProxySession::kFalse, socket_tag_2,
Ben Schwartz3ff4dc1e62021-04-27 21:15:234218 NetworkIsolationKey(), SecureDnsPolicy::kAllow);
Cammie Smith Barnes6b93b992021-02-03 21:25:404219 auto trans2 = std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY,
4220 helper.session());
4221 TestCompletionCallback callback2;
4222 EXPECT_THAT(
4223 trans2->Start(&request2, callback2.callback(), NetLogWithSource()),
4224 IsError(ERR_IO_PENDING));
4225
Cammie Smith Barnes5191037b72021-03-01 22:06:534226 // Wait for the second request to get headers. It should have reused the
4227 // first session but changed the tag.
Cammie Smith Barnes6b93b992021-02-03 21:25:404228 EXPECT_THAT(callback2.WaitForResult(), IsOk());
4229
Cammie Smith Barnes5191037b72021-03-01 22:06:534230 EXPECT_EQ(1u, helper.GetSpdySessionCount());
4231 EXPECT_FALSE(helper.session()->spdy_session_pool()->FindAvailableSession(
4232 key1, true /* enable_ip_based_pooling */, false /* is_websocket */,
4233 NetLogWithSource()));
4234 EXPECT_TRUE(helper.session()
4235 ->spdy_session_pool()
4236 ->GetDnsAliasesForSessionKey(key1)
4237 .empty());
4238 EXPECT_TRUE(helper.session()->spdy_session_pool()->FindAvailableSession(
4239 key2, true /* enable_ip_based_pooling */, false /* is_websocket */,
4240 NetLogWithSource()));
4241 EXPECT_EQ(
4242 dns_aliases,
4243 helper.session()->spdy_session_pool()->GetDnsAliasesForSessionKey(key2));
4244
Cammie Smith Barnes6b93b992021-02-03 21:25:404245 const HttpResponseInfo* response = trans2->GetResponseInfo();
4246 ASSERT_TRUE(response);
4247 ASSERT_TRUE(response->headers);
4248 EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
4249 EXPECT_TRUE(response->was_fetched_via_spdy);
4250 EXPECT_TRUE(response->was_alpn_negotiated);
4251 std::string response_data;
4252 ASSERT_THAT(ReadTransaction(trans2.get(), &response_data), IsOk());
4253 EXPECT_EQ("hello!", response_data);
4254
Cammie Smith Barnes5191037b72021-03-01 22:06:534255 helper.VerifyDataConsumed();
4256}
4257
4258TEST_F(SpdyNetworkTransactionTest,
4259 SocketTagChangeFromIPAliasedSessionWithDnsAliases) {
4260 SocketTag socket_tag_1(SocketTag::UNSET_UID, 1);
4261 SocketTag socket_tag_2(SocketTag::UNSET_UID, 2);
4262 request_.socket_tag = socket_tag_1;
4263
4264 std::unique_ptr<SpdySessionDependencies> session_deps =
4265 std::make_unique<SpdySessionDependencies>();
4266 std::unique_ptr<MockCachingHostResolver> host_resolver =
4267 std::make_unique<MockCachingHostResolver>(2 /* cache_invalidation_num */);
4268 session_deps->host_resolver = std::move(host_resolver);
4269
4270 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
4271 std::move(session_deps));
4272 GURL url1 = request_.url;
Eric Orthac661912022-01-10 21:44:174273 std::set<std::string> dns_aliases1({"alias1", "alias2", "alias3"});
Cammie Smith Barnes5191037b72021-03-01 22:06:534274 GURL url2("https://example.test/");
Eric Orthac661912022-01-10 21:44:174275 std::set<std::string> dns_aliases2({"example.net", "example.com"});
Cammie Smith Barnes5191037b72021-03-01 22:06:534276
4277 helper.session_deps()->host_resolver->rules()->AddIPLiteralRuleWithDnsAliases(
4278 url1.host(), "127.0.0.1", dns_aliases1);
4279 helper.session_deps()->host_resolver->rules()->AddIPLiteralRuleWithDnsAliases(
4280 url2.host(), "127.0.0.1", dns_aliases2);
4281
4282 spdy::SpdySerializedFrame req1(
4283 spdy_util_.ConstructSpdyGet(url1.spec().c_str(), 1, DEFAULT_PRIORITY));
4284 spdy_util_.UpdateWithStreamDestruction(1);
4285 spdy::SpdySerializedFrame req2(
4286 spdy_util_.ConstructSpdyGet(url2.spec().c_str(), 3, DEFAULT_PRIORITY));
4287 spdy_util_.UpdateWithStreamDestruction(3);
4288 spdy::SpdySerializedFrame req3(
4289 spdy_util_.ConstructSpdyGet(url2.spec().c_str(), 5, DEFAULT_PRIORITY));
4290 spdy_util_.UpdateWithStreamDestruction(5);
4291 spdy::SpdySerializedFrame req4(
4292 spdy_util_.ConstructSpdyGet(url1.spec().c_str(), 7, DEFAULT_PRIORITY));
4293 MockWrite writes[] = {
4294 CreateMockWrite(req1, 0),
4295 CreateMockWrite(req2, 3),
4296 CreateMockWrite(req3, 6),
4297 CreateMockWrite(req4, 9),
4298 };
4299
4300 spdy::SpdySerializedFrame resp1(
4301 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
4302 spdy::SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true));
4303 spdy::SpdySerializedFrame resp2(
4304 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
4305 spdy::SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(3, true));
4306 spdy::SpdySerializedFrame resp3(
4307 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 5));
4308 spdy::SpdySerializedFrame body3(spdy_util_.ConstructSpdyDataFrame(5, true));
4309 spdy::SpdySerializedFrame resp4(
4310 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 7));
4311 spdy::SpdySerializedFrame body4(spdy_util_.ConstructSpdyDataFrame(7, true));
4312 MockRead reads[] = {CreateMockRead(resp1, 1),
4313 CreateMockRead(body1, 2),
4314 CreateMockRead(resp2, 4),
4315 CreateMockRead(body2, 5),
4316 CreateMockRead(resp3, 7),
4317 CreateMockRead(body3, 8),
4318 CreateMockRead(resp4, 10),
4319 CreateMockRead(body4, 11),
4320 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 12)};
4321
4322 SequencedSocketData data(MockConnect(ASYNC, OK), reads, writes);
4323 helper.AddData(&data);
4324
4325 // Run a transaction to completion to set up a SPDY session. This can't use
4326 // RunToCompletion(), since it can't call VerifyDataConsumed() yet.
4327 helper.RunPreTestSetup();
4328 helper.RunDefaultTest();
4329 TransactionHelperResult out = helper.output();
4330 EXPECT_THAT(out.rv, IsOk());
4331 EXPECT_EQ("HTTP/1.1 200", out.status_line);
4332 EXPECT_EQ("hello!", out.response_data);
4333
4334 // A new SPDY session should have been created.
4335 EXPECT_EQ(1u, helper.GetSpdySessionCount());
4336 SpdySessionKey key1(HostPortPair(url1.host(), 443), ProxyServer::Direct(),
4337 PRIVACY_MODE_DISABLED,
4338 SpdySessionKey::IsProxySession::kFalse, socket_tag_1,
Ben Schwartz3ff4dc1e62021-04-27 21:15:234339 NetworkIsolationKey(), SecureDnsPolicy::kAllow);
Cammie Smith Barnes5191037b72021-03-01 22:06:534340 EXPECT_TRUE(helper.session()->spdy_session_pool()->FindAvailableSession(
4341 key1, true /* enable_ip_based_pooling */, false /* is_websocket */,
4342 NetLogWithSource()));
4343 EXPECT_EQ(
4344 dns_aliases1,
4345 helper.session()->spdy_session_pool()->GetDnsAliasesForSessionKey(key1));
4346
4347 HttpRequestInfo request2;
4348 request2.socket_tag = socket_tag_1;
4349 request2.method = "GET";
4350 request2.url = url2;
4351 request2.load_flags = 0;
4352 request2.traffic_annotation =
4353 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
4354 SpdySessionKey key2(HostPortPair(url2.host(), 443), ProxyServer::Direct(),
4355 PRIVACY_MODE_DISABLED,
4356 SpdySessionKey::IsProxySession::kFalse, socket_tag_1,
Ben Schwartz3ff4dc1e62021-04-27 21:15:234357 NetworkIsolationKey(), SecureDnsPolicy::kAllow);
Cammie Smith Barnes5191037b72021-03-01 22:06:534358 auto trans2 = std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY,
4359 helper.session());
4360 TestCompletionCallback callback2;
4361 EXPECT_THAT(
4362 trans2->Start(&request2, callback2.callback(), NetLogWithSource()),
4363 IsError(ERR_IO_PENDING));
4364
4365 // Wait for the second request to get headers. It should have reused the
4366 // first session.
4367 EXPECT_THAT(callback2.WaitForResult(), IsOk());
4368
4369 EXPECT_EQ(1u, helper.GetSpdySessionCount());
4370 EXPECT_TRUE(helper.session()->spdy_session_pool()->FindAvailableSession(
4371 key2, true /* enable_ip_based_pooling */, false /* is_websocket */,
4372 NetLogWithSource()));
4373 EXPECT_EQ(
4374 dns_aliases2,
4375 helper.session()->spdy_session_pool()->GetDnsAliasesForSessionKey(key2));
4376
4377 const HttpResponseInfo* response = trans2->GetResponseInfo();
4378 ASSERT_TRUE(response);
4379 ASSERT_TRUE(response->headers);
4380 EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
4381 EXPECT_TRUE(response->was_fetched_via_spdy);
4382 EXPECT_TRUE(response->was_alpn_negotiated);
4383 std::string response_data;
4384 ASSERT_THAT(ReadTransaction(trans2.get(), &response_data), IsOk());
4385 EXPECT_EQ("hello!", response_data);
4386
4387 // Clear host resolver rules to ensure that cached values for DNS aliases
4388 // are used.
4389 helper.session_deps()->host_resolver->rules()->ClearRules();
4390 trans2.reset();
4391
4392 HttpRequestInfo request3;
4393 request3.socket_tag = socket_tag_2;
4394 request3.method = "GET";
4395 request3.url = url2;
4396 request3.load_flags = 0;
4397 request3.traffic_annotation =
4398 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
4399 SpdySessionKey key3(HostPortPair(url2.host(), 443), ProxyServer::Direct(),
4400 PRIVACY_MODE_DISABLED,
4401 SpdySessionKey::IsProxySession::kFalse, socket_tag_2,
Ben Schwartz3ff4dc1e62021-04-27 21:15:234402 NetworkIsolationKey(), SecureDnsPolicy::kAllow);
Cammie Smith Barnes5191037b72021-03-01 22:06:534403 auto trans3 = std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY,
4404 helper.session());
4405 TestCompletionCallback callback3;
4406 EXPECT_THAT(
4407 trans3->Start(&request3, callback3.callback(), NetLogWithSource()),
4408 IsError(ERR_IO_PENDING));
4409
4410 // Wait for the third request to get headers. It should have reused the
4411 // first session but changed the socket tag.
Cammie Smith Barnes6b93b992021-02-03 21:25:404412 EXPECT_THAT(callback3.WaitForResult(), IsOk());
4413
Cammie Smith Barnes5191037b72021-03-01 22:06:534414 EXPECT_EQ(1u, helper.GetSpdySessionCount());
4415 EXPECT_FALSE(helper.session()->spdy_session_pool()->FindAvailableSession(
4416 key2, true /* enable_ip_based_pooling */, false /* is_websocket */,
4417 NetLogWithSource()));
4418 EXPECT_TRUE(helper.session()
4419 ->spdy_session_pool()
4420 ->GetDnsAliasesForSessionKey(key2)
4421 .empty());
4422 EXPECT_TRUE(helper.session()->spdy_session_pool()->FindAvailableSession(
4423 key3, true /* enable_ip_based_pooling */, false /* is_websocket */,
4424 NetLogWithSource()));
4425 EXPECT_EQ(
4426 dns_aliases2,
4427 helper.session()->spdy_session_pool()->GetDnsAliasesForSessionKey(key3));
4428
Cammie Smith Barnes6b93b992021-02-03 21:25:404429 response = trans3->GetResponseInfo();
4430 ASSERT_TRUE(response);
4431 ASSERT_TRUE(response->headers);
4432 EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
4433 EXPECT_TRUE(response->was_fetched_via_spdy);
4434 EXPECT_TRUE(response->was_alpn_negotiated);
4435 ASSERT_THAT(ReadTransaction(trans3.get(), &response_data), IsOk());
4436 EXPECT_EQ("hello!", response_data);
4437
Cammie Smith Barnes5191037b72021-03-01 22:06:534438 trans3.reset();
4439
4440 HttpRequestInfo request4;
4441 request4.socket_tag = socket_tag_2;
4442 request4.method = "GET";
4443 request4.url = url1;
4444 request4.load_flags = 0;
4445 request4.traffic_annotation =
4446 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
4447 SpdySessionKey key4(HostPortPair(url1.host(), 443), ProxyServer::Direct(),
4448 PRIVACY_MODE_DISABLED,
4449 SpdySessionKey::IsProxySession::kFalse, socket_tag_2,
Ben Schwartz3ff4dc1e62021-04-27 21:15:234450 NetworkIsolationKey(), SecureDnsPolicy::kAllow);
Cammie Smith Barnes5191037b72021-03-01 22:06:534451 auto trans4 = std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY,
4452 helper.session());
4453 TestCompletionCallback callback4;
4454 EXPECT_THAT(
4455 trans4->Start(&request4, callback4.callback(), NetLogWithSource()),
4456 IsError(ERR_IO_PENDING));
4457
4458 // Wait for the third request to get headers. It should have reused the
4459 // first session but changed the socket tag.
4460 EXPECT_THAT(callback4.WaitForResult(), IsOk());
4461
4462 EXPECT_EQ(1u, helper.GetSpdySessionCount());
4463 EXPECT_FALSE(helper.session()->spdy_session_pool()->FindAvailableSession(
4464 key1, true /* enable_ip_based_pooling */, false /* is_websocket */,
4465 NetLogWithSource()));
4466 EXPECT_TRUE(helper.session()
4467 ->spdy_session_pool()
4468 ->GetDnsAliasesForSessionKey(key1)
4469 .empty());
4470 EXPECT_TRUE(helper.session()->spdy_session_pool()->FindAvailableSession(
4471 key4, true /* enable_ip_based_pooling */, false /* is_websocket */,
4472 NetLogWithSource()));
4473 EXPECT_EQ(
4474 dns_aliases1,
4475 helper.session()->spdy_session_pool()->GetDnsAliasesForSessionKey(key4));
4476
4477 response = trans4->GetResponseInfo();
4478 ASSERT_TRUE(response);
4479 ASSERT_TRUE(response->headers);
4480 EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
4481 EXPECT_TRUE(response->was_fetched_via_spdy);
4482 EXPECT_TRUE(response->was_alpn_negotiated);
4483 ASSERT_THAT(ReadTransaction(trans4.get(), &response_data), IsOk());
4484 EXPECT_EQ("hello!", response_data);
4485
Cammie Smith Barnes6b93b992021-02-03 21:25:404486 helper.VerifyDataConsumed();
4487}
4488
Xiaohan Wang2a6845b2022-01-08 04:40:574489#endif // BUILDFLAG(IS_ANDROID)
Matt Menke5062be22019-05-01 17:50:244490
bncc055fa32017-06-19 13:44:424491// Regression test for https://crbug.com/727653.
4492TEST_F(SpdyNetworkTransactionTest, RejectServerPushWithNoMethod) {
Bence Békyeacd48f2018-05-14 11:34:334493 base::HistogramTester histogram_tester;
4494
Ryan Hamilton0239aac2018-05-19 00:03:134495 spdy::SpdySerializedFrame req(
4496 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
4497 spdy::SpdySerializedFrame rst(
4498 spdy_util_.ConstructSpdyRstStream(2, spdy::ERROR_CODE_REFUSED_STREAM));
bncc055fa32017-06-19 13:44:424499 MockWrite writes[] = {CreateMockWrite(req, 0), CreateMockWrite(rst, 3)};
4500
Ryan Hamilton0239aac2018-05-19 00:03:134501 spdy::SpdySerializedFrame reply(
4502 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
bncc055fa32017-06-19 13:44:424503
Bence Béky4c325e52020-10-22 20:48:014504 spdy::Http2HeaderBlock push_promise_header_block;
Bence Békyd2df6c1c82018-04-20 22:52:014505 spdy_util_.AddUrlToHeaderBlock(kPushedUrl, &push_promise_header_block);
Ryan Hamilton0239aac2018-05-19 00:03:134506 spdy::SpdySerializedFrame push_promise(spdy_util_.ConstructSpdyPushPromise(
Bence Békyf1d78522018-01-11 01:16:504507 1, 2, std::move(push_promise_header_block)));
bncc055fa32017-06-19 13:44:424508
Ryan Hamilton0239aac2018-05-19 00:03:134509 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
Bence Békyf1d78522018-01-11 01:16:504510 MockRead reads[] = {CreateMockRead(reply, 1), CreateMockRead(push_promise, 2),
4511 CreateMockRead(body, 4),
4512 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 5)};
bncc055fa32017-06-19 13:44:424513
Ryan Sleevib8d7ea02018-05-07 20:01:014514 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:104515 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
bncc055fa32017-06-19 13:44:424516 helper.RunToCompletion(&data);
Bence Békyeacd48f2018-05-14 11:34:334517
4518 histogram_tester.ExpectBucketCount(
4519 "Net.SpdyPushedStreamFate",
4520 static_cast<int>(SpdyPushedStreamFate::kInvalidUrl), 1);
4521 histogram_tester.ExpectTotalCount("Net.SpdyPushedStreamFate", 1);
bncc055fa32017-06-19 13:44:424522}
4523
4524// Regression test for https://crbug.com/727653.
4525TEST_F(SpdyNetworkTransactionTest, RejectServerPushWithInvalidMethod) {
Bence Békyeacd48f2018-05-14 11:34:334526 base::HistogramTester histogram_tester;
4527
Ryan Hamilton0239aac2018-05-19 00:03:134528 spdy::SpdySerializedFrame req(
4529 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
4530 spdy::SpdySerializedFrame rst(
4531 spdy_util_.ConstructSpdyRstStream(2, spdy::ERROR_CODE_REFUSED_STREAM));
bncc055fa32017-06-19 13:44:424532 MockWrite writes[] = {CreateMockWrite(req, 0), CreateMockWrite(rst, 3)};
4533
Ryan Hamilton0239aac2018-05-19 00:03:134534 spdy::SpdySerializedFrame reply(
4535 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
bncc055fa32017-06-19 13:44:424536
Bence Béky4c325e52020-10-22 20:48:014537 spdy::Http2HeaderBlock push_promise_header_block;
bncc055fa32017-06-19 13:44:424538 push_promise_header_block[":method"] = "POST";
Bence Békyd2df6c1c82018-04-20 22:52:014539 spdy_util_.AddUrlToHeaderBlock(kPushedUrl, &push_promise_header_block);
Ryan Hamilton0239aac2018-05-19 00:03:134540 spdy::SpdySerializedFrame push_promise(spdy_util_.ConstructSpdyPushPromise(
Bence Békyf1d78522018-01-11 01:16:504541 1, 2, std::move(push_promise_header_block)));
bncc055fa32017-06-19 13:44:424542
Ryan Hamilton0239aac2018-05-19 00:03:134543 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
Bence Békyf1d78522018-01-11 01:16:504544 MockRead reads[] = {CreateMockRead(reply, 1), CreateMockRead(push_promise, 2),
4545 CreateMockRead(body, 4),
4546 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 5)};
bncc055fa32017-06-19 13:44:424547
Ryan Sleevib8d7ea02018-05-07 20:01:014548 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:104549 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
bncc055fa32017-06-19 13:44:424550 helper.RunToCompletion(&data);
Bence Békyeacd48f2018-05-14 11:34:334551
4552 histogram_tester.ExpectBucketCount(
4553 "Net.SpdyPushedStreamFate",
4554 static_cast<int>(SpdyPushedStreamFate::kInvalidUrl), 1);
4555 histogram_tester.ExpectTotalCount("Net.SpdyPushedStreamFate", 1);
bncc055fa32017-06-19 13:44:424556}
4557
bnc42331402016-07-25 13:36:154558// Verify that various response headers parse correctly through the HTTP layer.
4559TEST_F(SpdyNetworkTransactionTest, ResponseHeaders) {
4560 struct ResponseHeadersTests {
Bence Békye5438512017-11-22 23:07:424561 int extra_header_count;
4562 const char* extra_headers[4];
4563 size_t expected_header_count;
Bence Béky4e83f492018-05-13 23:14:254564 base::StringPiece expected_headers[8];
Bence Békye5438512017-11-22 23:07:424565 } test_cases[] = {
4566 // No extra headers.
Yoichi Osato85350eb72020-09-11 02:14:304567 {0, {}, 1, {"hello", "bye"}},
Bence Békye5438512017-11-22 23:07:424568 // Comma-separated header value.
4569 {1,
4570 {"cookie", "val1, val2"},
Yoichi Osato85350eb72020-09-11 02:14:304571 2,
4572 {"hello", "bye", "cookie", "val1, val2"}},
Bence Békye5438512017-11-22 23:07:424573 // Multiple headers are preserved: they are joined with \0 separator in
Bence Béky4c325e52020-10-22 20:48:014574 // spdy::Http2HeaderBlock.AppendValueOrAddHeader(), then split up in
Bence Békye5438512017-11-22 23:07:424575 // HpackEncoder, then joined with \0 separator when
Ryan Hamilton0239aac2018-05-19 00:03:134576 // spdy::HpackDecoderAdapter::ListenerAdapter::OnHeader() calls
Bence Béky4c325e52020-10-22 20:48:014577 // spdy::Http2HeaderBlock.AppendValueOrAddHeader(), then split up again in
Bence Békye5438512017-11-22 23:07:424578 // HttpResponseHeaders.
4579 {2,
4580 {"content-encoding", "val1", "content-encoding", "val2"},
Yoichi Osato85350eb72020-09-11 02:14:304581 3,
4582 {"hello", "bye", "content-encoding", "val1", "content-encoding",
4583 "val2"}},
Bence Békye5438512017-11-22 23:07:424584 // Cookie header is not split up by HttpResponseHeaders.
4585 {2,
4586 {"cookie", "val1", "cookie", "val2"},
Yoichi Osato85350eb72020-09-11 02:14:304587 2,
4588 {"hello", "bye", "cookie", "val1; val2"}}};
bnc7ecc1122015-09-28 13:22:494589
Avi Drissman4365a4782018-12-28 19:26:244590 for (size_t i = 0; i < base::size(test_cases); ++i) {
Bence Békyad9eb1622020-09-17 16:29:174591 SCOPED_TRACE(i);
bncd16676a2016-07-20 16:23:014592 SpdyTestUtil spdy_test_util;
Ryan Hamilton0239aac2018-05-19 00:03:134593 spdy::SpdySerializedFrame req(
Bence Béky27ad0a12018-02-08 00:35:484594 spdy_test_util.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
bncdf80d44fd2016-07-15 20:27:414595 MockWrite writes[] = {CreateMockWrite(req, 0)};
[email protected]8b070372009-11-16 22:01:254596
Ryan Hamilton0239aac2018-05-19 00:03:134597 spdy::SpdySerializedFrame resp(spdy_test_util.ConstructSpdyGetReply(
Bence Békye5438512017-11-22 23:07:424598 test_cases[i].extra_headers, test_cases[i].extra_header_count, 1));
Ryan Hamilton0239aac2018-05-19 00:03:134599 spdy::SpdySerializedFrame body(
4600 spdy_test_util.ConstructSpdyDataFrame(1, true));
[email protected]8b070372009-11-16 22:01:254601 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:414602 CreateMockRead(resp, 1), CreateMockRead(body, 2),
rch08e3aa3e2015-05-16 14:27:524603 MockRead(ASYNC, 0, 3) // EOF
[email protected]8b070372009-11-16 22:01:254604 };
4605
Ryan Sleevib8d7ea02018-05-07 20:01:014606 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:104607 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
4608 nullptr);
[email protected]dd54bd82012-07-19 23:44:574609 helper.RunToCompletion(&data);
[email protected]3caf5542010-07-16 15:19:474610 TransactionHelperResult out = helper.output();
4611
robpercival214763f2016-07-01 23:27:014612 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:024613 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]8b070372009-11-16 22:01:254614 EXPECT_EQ("hello!", out.response_data);
4615
4616 scoped_refptr<HttpResponseHeaders> headers = out.response_info.headers;
Bence Békyad9eb1622020-09-17 16:29:174617 ASSERT_TRUE(headers);
4618 EXPECT_EQ("HTTP/1.1 200", headers->GetStatusLine());
olli.raula33c282f2016-01-21 12:12:494619 size_t iter = 0;
Bence Béky4e83f492018-05-13 23:14:254620 std::string name, value;
Bence Békye5438512017-11-22 23:07:424621 size_t expected_header_index = 0;
[email protected]8b070372009-11-16 22:01:254622 while (headers->EnumerateHeaderLines(&iter, &name, &value)) {
Bence Békyad9eb1622020-09-17 16:29:174623 ASSERT_LT(expected_header_index, test_cases[i].expected_header_count);
4624 EXPECT_EQ(name,
4625 test_cases[i].expected_headers[2 * expected_header_index]);
Bence Békye5438512017-11-22 23:07:424626 EXPECT_EQ(value,
Bence Békyad9eb1622020-09-17 16:29:174627 test_cases[i].expected_headers[2 * expected_header_index + 1]);
Bence Békye5438512017-11-22 23:07:424628 ++expected_header_index;
[email protected]8b070372009-11-16 22:01:254629 }
Bence Békyad9eb1622020-09-17 16:29:174630 EXPECT_EQ(expected_header_index, test_cases[i].expected_header_count);
[email protected]3f662f12010-03-25 19:56:124631 }
4632}
4633
bnc42331402016-07-25 13:36:154634// Verify that we don't crash on invalid response headers.
4635TEST_F(SpdyNetworkTransactionTest, InvalidResponseHeaders) {
4636 struct InvalidResponseHeadersTests {
[email protected]e7f75092010-07-01 22:39:134637 int num_headers;
4638 const char* headers[10];
Bence Békyad9eb1622020-09-17 16:29:174639 } test_cases[] = {// Response headers missing status header
4640 {2, {"cookie", "val1", "cookie", "val2", nullptr}},
4641 // Response headers with no headers
4642 {0, {nullptr}}};
[email protected]dd11b932009-11-30 19:39:484643
Avi Drissman4365a4782018-12-28 19:26:244644 for (size_t i = 0; i < base::size(test_cases); ++i) {
Bence Békyad9eb1622020-09-17 16:29:174645 SCOPED_TRACE(i);
bncd16676a2016-07-20 16:23:014646 SpdyTestUtil spdy_test_util;
bnc38dcd392016-02-09 23:19:494647
Ryan Hamilton0239aac2018-05-19 00:03:134648 spdy::SpdySerializedFrame req(
Bence Béky27ad0a12018-02-08 00:35:484649 spdy_test_util.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
Ryan Hamilton0239aac2018-05-19 00:03:134650 spdy::SpdySerializedFrame rst(spdy_test_util.ConstructSpdyRstStream(
4651 1, spdy::ERROR_CODE_PROTOCOL_ERROR));
[email protected]dd11b932009-11-30 19:39:484652 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:414653 CreateMockWrite(req, 0), CreateMockWrite(rst, 2),
[email protected]dd11b932009-11-30 19:39:484654 };
4655
[email protected]745aa9c2014-06-27 02:21:294656 // Construct the reply.
Bence Béky4c325e52020-10-22 20:48:014657 spdy::Http2HeaderBlock reply_headers;
[email protected]745aa9c2014-06-27 02:21:294658 AppendToHeaderBlock(
4659 test_cases[i].headers, test_cases[i].num_headers, &reply_headers);
Ryan Hamilton0239aac2018-05-19 00:03:134660 spdy::SpdySerializedFrame resp(
bnc086b39e12016-06-24 13:05:264661 spdy_test_util.ConstructSpdyReply(1, std::move(reply_headers)));
[email protected]dd11b932009-11-30 19:39:484662 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:414663 CreateMockRead(resp, 1), MockRead(ASYNC, 0, 3) // EOF
[email protected]dd11b932009-11-30 19:39:484664 };
4665
Ryan Sleevib8d7ea02018-05-07 20:01:014666 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:104667 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
4668 nullptr);
[email protected]dd54bd82012-07-19 23:44:574669 helper.RunToCompletion(&data);
[email protected]3caf5542010-07-16 15:19:474670 TransactionHelperResult out = helper.output();
Bence Békyd0d69502019-06-25 19:47:184671 EXPECT_THAT(out.rv, IsError(ERR_HTTP2_PROTOCOL_ERROR));
[email protected]dd11b932009-11-30 19:39:484672 }
4673}
4674
bncd16676a2016-07-20 16:23:014675TEST_F(SpdyNetworkTransactionTest, CorruptFrameSessionError) {
Ryan Hamilton0239aac2018-05-19 00:03:134676 spdy::SpdySerializedFrame req(
4677 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
Zhongyi Shi495af8072020-02-28 04:43:484678 spdy::SpdySerializedFrame goaway(spdy_util_.ConstructSpdyGoAway(
4679 0, spdy::ERROR_CODE_COMPRESSION_ERROR,
Bence Békya18ae762021-10-26 01:09:134680 "Framer error: 24 (HPACK_TRUNCATED_BLOCK)."));
bncdf80d44fd2016-07-15 20:27:414681 MockWrite writes[] = {CreateMockWrite(req, 0), CreateMockWrite(goaway, 2)};
[email protected]e3352df2014-03-19 05:55:424682
bnc38dcd392016-02-09 23:19:494683 // This is the length field that's too short.
Ryan Hamilton0239aac2018-05-19 00:03:134684 spdy::SpdySerializedFrame reply_wrong_length(
bnc42331402016-07-25 13:36:154685 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
Ryan Hamilton0239aac2018-05-19 00:03:134686 size_t right_size = reply_wrong_length.size() - spdy::kFrameHeaderSize;
bnc38dcd392016-02-09 23:19:494687 size_t wrong_size = right_size - 4;
Ryan Hamilton0239aac2018-05-19 00:03:134688 spdy::test::SetFrameLength(&reply_wrong_length, wrong_size);
bnc38dcd392016-02-09 23:19:494689
[email protected]e3352df2014-03-19 05:55:424690 MockRead reads[] = {
bnc42331402016-07-25 13:36:154691 MockRead(ASYNC, reply_wrong_length.data(), reply_wrong_length.size() - 4,
4692 1),
[email protected]e3352df2014-03-19 05:55:424693 };
4694
Ryan Sleevib8d7ea02018-05-07 20:01:014695 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:104696 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]e3352df2014-03-19 05:55:424697 helper.RunToCompletion(&data);
4698 TransactionHelperResult out = helper.output();
Bence Békyd0d69502019-06-25 19:47:184699 EXPECT_THAT(out.rv, IsError(ERR_HTTP2_COMPRESSION_ERROR));
[email protected]bdd1b222014-06-10 11:08:394700}
4701
bncd16676a2016-07-20 16:23:014702TEST_F(SpdyNetworkTransactionTest, GoAwayOnDecompressionFailure) {
Ryan Hamilton0239aac2018-05-19 00:03:134703 spdy::SpdySerializedFrame req(
4704 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
Zhongyi Shi495af8072020-02-28 04:43:484705 spdy::SpdySerializedFrame goaway(spdy_util_.ConstructSpdyGoAway(
4706 0, spdy::ERROR_CODE_COMPRESSION_ERROR,
Bence Békya18ae762021-10-26 01:09:134707 "Framer error: 24 (HPACK_TRUNCATED_BLOCK)."));
bncdf80d44fd2016-07-15 20:27:414708 MockWrite writes[] = {CreateMockWrite(req, 0), CreateMockWrite(goaway, 2)};
[email protected]bdd1b222014-06-10 11:08:394709
4710 // Read HEADERS with corrupted payload.
Ryan Hamilton0239aac2018-05-19 00:03:134711 spdy::SpdySerializedFrame resp(
4712 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
bncdf80d44fd2016-07-15 20:27:414713 memset(resp.data() + 12, 0xcf, resp.size() - 12);
4714 MockRead reads[] = {CreateMockRead(resp, 1)};
[email protected]bdd1b222014-06-10 11:08:394715
Ryan Sleevib8d7ea02018-05-07 20:01:014716 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:104717 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]bdd1b222014-06-10 11:08:394718 helper.RunToCompletion(&data);
4719 TransactionHelperResult out = helper.output();
Bence Békyd0d69502019-06-25 19:47:184720 EXPECT_THAT(out.rv, IsError(ERR_HTTP2_COMPRESSION_ERROR));
[email protected]bdd1b222014-06-10 11:08:394721}
4722
bncd16676a2016-07-20 16:23:014723TEST_F(SpdyNetworkTransactionTest, GoAwayOnFrameSizeError) {
Ryan Hamilton0239aac2018-05-19 00:03:134724 spdy::SpdySerializedFrame req(
4725 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
4726 spdy::SpdySerializedFrame goaway(spdy_util_.ConstructSpdyGoAway(
4727 0, spdy::ERROR_CODE_FRAME_SIZE_ERROR,
Bence Békya18ae762021-10-26 01:09:134728 "Framer error: 9 (INVALID_CONTROL_FRAME_SIZE)."));
bncdf80d44fd2016-07-15 20:27:414729 MockWrite writes[] = {CreateMockWrite(req, 0), CreateMockWrite(goaway, 2)};
[email protected]bdd1b222014-06-10 11:08:394730
4731 // Read WINDOW_UPDATE with incorrectly-sized payload.
Ryan Hamilton0239aac2018-05-19 00:03:134732 spdy::SpdySerializedFrame bad_window_update(
[email protected]bdd1b222014-06-10 11:08:394733 spdy_util_.ConstructSpdyWindowUpdate(1, 1));
Ryan Hamilton0239aac2018-05-19 00:03:134734 spdy::test::SetFrameLength(&bad_window_update, bad_window_update.size() - 1);
bncdf80d44fd2016-07-15 20:27:414735 MockRead reads[] = {CreateMockRead(bad_window_update, 1)};
[email protected]bdd1b222014-06-10 11:08:394736
Ryan Sleevib8d7ea02018-05-07 20:01:014737 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:104738 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]bdd1b222014-06-10 11:08:394739 helper.RunToCompletion(&data);
4740 TransactionHelperResult out = helper.output();
Bence Békyd0d69502019-06-25 19:47:184741 EXPECT_THAT(out.rv, IsError(ERR_HTTP2_FRAME_SIZE_ERROR));
[email protected]e3352df2014-03-19 05:55:424742}
4743
[email protected]bf2491a92009-11-29 16:39:484744// Test that we shutdown correctly on write errors.
bncd16676a2016-07-20 16:23:014745TEST_F(SpdyNetworkTransactionTest, WriteError) {
Ryan Hamilton0239aac2018-05-19 00:03:134746 spdy::SpdySerializedFrame req(
4747 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
[email protected]bf2491a92009-11-29 16:39:484748 MockWrite writes[] = {
[email protected]bdd1b222014-06-10 11:08:394749 // We'll write 10 bytes successfully
bncdf80d44fd2016-07-15 20:27:414750 MockWrite(ASYNC, req.data(), 10, 1),
[email protected]bdd1b222014-06-10 11:08:394751 // Followed by ERROR!
[email protected]bdd1b222014-06-10 11:08:394752 MockWrite(ASYNC, ERR_FAILED, 2),
mmenke666a6fea2015-12-19 04:16:334753 // Session drains and attempts to write a GOAWAY: Another ERROR!
4754 MockWrite(ASYNC, ERR_FAILED, 3),
[email protected]bf2491a92009-11-29 16:39:484755 };
4756
mmenke666a6fea2015-12-19 04:16:334757 MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
[email protected]238002d2013-10-17 02:01:404758
Ryan Sleevib8d7ea02018-05-07 20:01:014759 SequencedSocketData data(reads, writes);
[email protected]238002d2013-10-17 02:01:404760
Bence Békydb3cf652017-10-10 15:22:104761 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]238002d2013-10-17 02:01:404762 helper.RunPreTestSetup();
mmenke666a6fea2015-12-19 04:16:334763 helper.AddData(&data);
[email protected]238002d2013-10-17 02:01:404764 EXPECT_TRUE(helper.StartDefaultTest());
[email protected]238002d2013-10-17 02:01:404765 helper.FinishDefaultTest();
rch37de576c2015-05-17 20:28:174766 EXPECT_TRUE(data.AllWriteDataConsumed());
mmenke666a6fea2015-12-19 04:16:334767 EXPECT_TRUE(data.AllReadDataConsumed());
[email protected]3caf5542010-07-16 15:19:474768 TransactionHelperResult out = helper.output();
robpercival214763f2016-07-01 23:27:014769 EXPECT_THAT(out.rv, IsError(ERR_FAILED));
[email protected]bf2491a92009-11-29 16:39:484770}
4771
4772// Test that partial writes work.
bncd16676a2016-07-20 16:23:014773TEST_F(SpdyNetworkTransactionTest, PartialWrite) {
bnc42331402016-07-25 13:36:154774 // Chop the HEADERS frame into 5 chunks.
Ryan Hamilton0239aac2018-05-19 00:03:134775 spdy::SpdySerializedFrame req(
4776 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
[email protected]bf2491a92009-11-29 16:39:484777 const int kChunks = 5;
bnc3f6a8552017-05-17 13:40:344778 std::unique_ptr<MockWrite[]> writes = ChopWriteFrame(req, kChunks);
rch08e3aa3e2015-05-16 14:27:524779 for (int i = 0; i < kChunks; ++i) {
4780 writes[i].sequence_number = i;
4781 }
[email protected]bf2491a92009-11-29 16:39:484782
Ryan Hamilton0239aac2018-05-19 00:03:134783 spdy::SpdySerializedFrame resp(
4784 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
4785 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]bf2491a92009-11-29 16:39:484786 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:414787 CreateMockRead(resp, kChunks), CreateMockRead(body, kChunks + 1),
rch08e3aa3e2015-05-16 14:27:524788 MockRead(ASYNC, 0, kChunks + 2) // EOF
[email protected]bf2491a92009-11-29 16:39:484789 };
4790
Ryan Sleevib8d7ea02018-05-07 20:01:014791 SequencedSocketData data(reads, base::make_span(writes.get(), kChunks));
Bence Békydb3cf652017-10-10 15:22:104792 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]dd54bd82012-07-19 23:44:574793 helper.RunToCompletion(&data);
[email protected]3caf5542010-07-16 15:19:474794 TransactionHelperResult out = helper.output();
robpercival214763f2016-07-01 23:27:014795 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:024796 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]bf2491a92009-11-29 16:39:484797 EXPECT_EQ("hello!", out.response_data);
4798}
4799
[email protected]9e743cd2010-03-16 07:03:534800// Test that the NetLog contains good data for a simple GET request.
bncd16676a2016-07-20 16:23:014801TEST_F(SpdyNetworkTransactionTest, NetLog) {
[email protected]3deb9a52010-11-11 00:24:404802 static const char* const kExtraHeaders[] = {
4803 "user-agent", "Chrome",
4804 };
Ryan Hamilton0239aac2018-05-19 00:03:134805 spdy::SpdySerializedFrame req(
Bence Béky27ad0a12018-02-08 00:35:484806 spdy_util_.ConstructSpdyGet(kExtraHeaders, 1, 1, LOWEST));
bncdf80d44fd2016-07-15 20:27:414807 MockWrite writes[] = {CreateMockWrite(req, 0)};
[email protected]dac358042009-12-18 02:07:484808
Ryan Hamilton0239aac2018-05-19 00:03:134809 spdy::SpdySerializedFrame resp(
4810 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
4811 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]dac358042009-12-18 02:07:484812 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:414813 CreateMockRead(resp, 1), CreateMockRead(body, 2),
rch08e3aa3e2015-05-16 14:27:524814 MockRead(ASYNC, 0, 3) // EOF
[email protected]dac358042009-12-18 02:07:484815 };
4816
Matt Reichhoff0049a0b72021-10-20 20:44:264817 RecordingNetLogObserver net_log_observer;
[email protected]dac358042009-12-18 02:07:484818
Ryan Sleevib8d7ea02018-05-07 20:01:014819 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:104820 request_.extra_headers.SetHeader("User-Agent", "Chrome");
Matt Reichhoff0049a0b72021-10-20 20:44:264821 NormalSpdyTransactionHelper helper(
4822 request_, DEFAULT_PRIORITY,
4823 NetLogWithSource::Make(NetLogSourceType::NONE), nullptr);
[email protected]dd54bd82012-07-19 23:44:574824 helper.RunToCompletion(&data);
[email protected]3caf5542010-07-16 15:19:474825 TransactionHelperResult out = helper.output();
robpercival214763f2016-07-01 23:27:014826 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:024827 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]dac358042009-12-18 02:07:484828 EXPECT_EQ("hello!", out.response_data);
4829
[email protected]9e743cd2010-03-16 07:03:534830 // Check that the NetLog was filled reasonably.
[email protected]3caf5542010-07-16 15:19:474831 // This test is intentionally non-specific about the exact ordering of the
4832 // log; instead we just check to make sure that certain events exist, and that
4833 // they are in the right order.
Matt Reichhoff0049a0b72021-10-20 20:44:264834 auto entries = net_log_observer.GetEntries();
[email protected]b2fcd0e2010-12-01 15:19:404835
4836 EXPECT_LT(0u, entries.size());
[email protected]dac358042009-12-18 02:07:484837 int pos = 0;
mikecirone8b85c432016-09-08 19:11:004838 pos = ExpectLogContainsSomewhere(
4839 entries, 0, NetLogEventType::HTTP_TRANSACTION_SEND_REQUEST,
4840 NetLogEventPhase::BEGIN);
4841 pos = ExpectLogContainsSomewhere(
4842 entries, pos + 1, NetLogEventType::HTTP_TRANSACTION_SEND_REQUEST,
4843 NetLogEventPhase::END);
4844 pos = ExpectLogContainsSomewhere(
4845 entries, pos + 1, NetLogEventType::HTTP_TRANSACTION_READ_HEADERS,
4846 NetLogEventPhase::BEGIN);
4847 pos = ExpectLogContainsSomewhere(
4848 entries, pos + 1, NetLogEventType::HTTP_TRANSACTION_READ_HEADERS,
4849 NetLogEventPhase::END);
bnc301745a2015-03-10 03:22:164850 pos = ExpectLogContainsSomewhere(entries, pos + 1,
mikecirone8b85c432016-09-08 19:11:004851 NetLogEventType::HTTP_TRANSACTION_READ_BODY,
4852 NetLogEventPhase::BEGIN);
bnc301745a2015-03-10 03:22:164853 pos = ExpectLogContainsSomewhere(entries, pos + 1,
mikecirone8b85c432016-09-08 19:11:004854 NetLogEventType::HTTP_TRANSACTION_READ_BODY,
4855 NetLogEventPhase::END);
[email protected]3deb9a52010-11-11 00:24:404856
4857 // Check that we logged all the headers correctly
mikecirone8b85c432016-09-08 19:11:004858 pos = ExpectLogContainsSomewhere(entries, 0,
4859 NetLogEventType::HTTP2_SESSION_SEND_HEADERS,
4860 NetLogEventPhase::NONE);
[email protected]3deb9a52010-11-11 00:24:404861
Eric Roman79cc7552019-07-19 02:17:544862 ASSERT_TRUE(entries[pos].HasParams());
4863 auto* header_list = entries[pos].params.FindKey("headers");
Bence Béky66871e32018-12-06 21:11:244864 ASSERT_TRUE(header_list);
4865 ASSERT_TRUE(header_list->is_list());
4866 ASSERT_EQ(5u, header_list->GetList().size());
[email protected]f3da152d2012-06-02 01:00:574867
Bence Béky66871e32018-12-06 21:11:244868 ASSERT_TRUE(header_list->GetList()[0].is_string());
4869 EXPECT_EQ(":method: GET", header_list->GetList()[0].GetString());
4870
4871 ASSERT_TRUE(header_list->GetList()[1].is_string());
4872 EXPECT_EQ(":authority: www.example.org",
4873 header_list->GetList()[1].GetString());
4874
4875 ASSERT_TRUE(header_list->GetList()[2].is_string());
4876 EXPECT_EQ(":scheme: https", header_list->GetList()[2].GetString());
4877
4878 ASSERT_TRUE(header_list->GetList()[3].is_string());
4879 EXPECT_EQ(":path: /", header_list->GetList()[3].GetString());
4880
4881 ASSERT_TRUE(header_list->GetList()[4].is_string());
4882 EXPECT_EQ("user-agent: Chrome", header_list->GetList()[4].GetString());
[email protected]dac358042009-12-18 02:07:484883}
4884
[email protected]79d84222010-02-26 00:01:444885// Since we buffer the IO from the stream to the renderer, this test verifies
4886// that when we read out the maximum amount of data (e.g. we received 50 bytes
4887// on the network, but issued a Read for only 5 of those bytes) that the data
4888// flow still works correctly.
bncd16676a2016-07-20 16:23:014889TEST_F(SpdyNetworkTransactionTest, BufferFull) {
Ryan Hamilton0239aac2018-05-19 00:03:134890 spdy::SpdySerializedFrame req(
4891 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
bncdf80d44fd2016-07-15 20:27:414892 MockWrite writes[] = {CreateMockWrite(req, 0)};
[email protected]79d84222010-02-26 00:01:444893
[email protected]20d005f2010-07-02 19:55:434894 // 2 data frames in a single read.
Ryan Hamilton0239aac2018-05-19 00:03:134895 spdy::SpdySerializedFrame data_frame_1(
Bence Békyd74f4382018-02-20 18:26:194896 spdy_util_.ConstructSpdyDataFrame(1, "goodby", /*fin=*/false));
Ryan Hamilton0239aac2018-05-19 00:03:134897 spdy::SpdySerializedFrame data_frame_2(
Bence Békyd74f4382018-02-20 18:26:194898 spdy_util_.ConstructSpdyDataFrame(1, "e worl", /*fin=*/false));
Ryan Hamilton0239aac2018-05-19 00:03:134899 spdy::SpdySerializedFrame combined_data_frames =
bncef26b602017-06-12 22:08:194900 CombineFrames({&data_frame_1, &data_frame_2});
4901
Ryan Hamilton0239aac2018-05-19 00:03:134902 spdy::SpdySerializedFrame last_frame(
Bence Békyd74f4382018-02-20 18:26:194903 spdy_util_.ConstructSpdyDataFrame(1, "d", /*fin=*/true));
[email protected]79d84222010-02-26 00:01:444904
Ryan Hamilton0239aac2018-05-19 00:03:134905 spdy::SpdySerializedFrame resp(
4906 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
[email protected]79d84222010-02-26 00:01:444907 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:414908 CreateMockRead(resp, 1),
rch32320842015-05-16 15:57:094909 MockRead(ASYNC, ERR_IO_PENDING, 2), // Force a pause
bncef26b602017-06-12 22:08:194910 CreateMockRead(combined_data_frames, 3),
rch32320842015-05-16 15:57:094911 MockRead(ASYNC, ERR_IO_PENDING, 4), // Force a pause
bncdf80d44fd2016-07-15 20:27:414912 CreateMockRead(last_frame, 5),
rch32320842015-05-16 15:57:094913 MockRead(ASYNC, 0, 6) // EOF
[email protected]79d84222010-02-26 00:01:444914 };
4915
Ryan Sleevib8d7ea02018-05-07 20:01:014916 SequencedSocketData data(reads, writes);
[email protected]79d84222010-02-26 00:01:444917
[email protected]49639fa2011-12-20 23:22:414918 TestCompletionCallback callback;
[email protected]79d84222010-02-26 00:01:444919
Bence Békydb3cf652017-10-10 15:22:104920 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]3caf5542010-07-16 15:19:474921 helper.RunPreTestSetup();
[email protected]dd54bd82012-07-19 23:44:574922 helper.AddData(&data);
[email protected]3caf5542010-07-16 15:19:474923 HttpNetworkTransaction* trans = helper.trans();
Bence Békydb3cf652017-10-10 15:22:104924 int rv = trans->Start(&request_, callback.callback(), log_);
robpercival214763f2016-07-01 23:27:014925 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]79d84222010-02-26 00:01:444926
[email protected]3caf5542010-07-16 15:19:474927 TransactionHelperResult out = helper.output();
[email protected]79d84222010-02-26 00:01:444928 out.rv = callback.WaitForResult();
4929 EXPECT_EQ(out.rv, OK);
4930
4931 const HttpResponseInfo* response = trans->GetResponseInfo();
wezca1070932016-05-26 20:30:524932 EXPECT_TRUE(response->headers);
[email protected]79d84222010-02-26 00:01:444933 EXPECT_TRUE(response->was_fetched_via_spdy);
4934 out.status_line = response->headers->GetStatusLine();
4935 out.response_info = *response; // Make a copy so we can verify.
4936
4937 // Read Data
[email protected]49639fa2011-12-20 23:22:414938 TestCompletionCallback read_callback;
[email protected]79d84222010-02-26 00:01:444939
Bence Béky4e83f492018-05-13 23:14:254940 std::string content;
[email protected]79d84222010-02-26 00:01:444941 do {
4942 // Read small chunks at a time.
4943 const int kSmallReadSize = 3;
Victor Costan9c7302b2018-08-27 16:39:444944 scoped_refptr<IOBuffer> buf =
4945 base::MakeRefCounted<IOBuffer>(kSmallReadSize);
[email protected]90499482013-06-01 00:39:504946 rv = trans->Read(buf.get(), kSmallReadSize, read_callback.callback());
bnc301745a2015-03-10 03:22:164947 if (rv == ERR_IO_PENDING) {
mmenkee24011922015-12-17 22:12:594948 data.Resume();
[email protected]79d84222010-02-26 00:01:444949 rv = read_callback.WaitForResult();
4950 }
4951 if (rv > 0) {
4952 content.append(buf->data(), rv);
4953 } else if (rv < 0) {
4954 NOTREACHED();
4955 }
4956 } while (rv > 0);
4957
4958 out.response_data.swap(content);
4959
[email protected]30c942b2010-07-21 16:59:594960 // Flush the MessageLoop while the SpdySessionDependencies (in particular, the
[email protected]8918d282010-03-02 00:57:554961 // MockClientSocketFactory) are still alive.
[email protected]fc9d88472013-08-14 02:31:174962 base::RunLoop().RunUntilIdle();
[email protected]8918d282010-03-02 00:57:554963
[email protected]79d84222010-02-26 00:01:444964 // Verify that we consumed all test data.
[email protected]3caf5542010-07-16 15:19:474965 helper.VerifyDataConsumed();
[email protected]79d84222010-02-26 00:01:444966
robpercival214763f2016-07-01 23:27:014967 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:024968 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]79d84222010-02-26 00:01:444969 EXPECT_EQ("goodbye world", out.response_data);
4970}
4971
[email protected]8918d282010-03-02 00:57:554972// Verify that basic buffering works; when multiple data frames arrive
4973// at the same time, ensure that we don't notify a read completion for
4974// each data frame individually.
bncd16676a2016-07-20 16:23:014975TEST_F(SpdyNetworkTransactionTest, Buffering) {
Ryan Hamilton0239aac2018-05-19 00:03:134976 spdy::SpdySerializedFrame req(
4977 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
bncdf80d44fd2016-07-15 20:27:414978 MockWrite writes[] = {CreateMockWrite(req, 0)};
[email protected]8918d282010-03-02 00:57:554979
4980 // 4 data frames in a single read.
Ryan Hamilton0239aac2018-05-19 00:03:134981 spdy::SpdySerializedFrame data_frame(
Bence Békyd74f4382018-02-20 18:26:194982 spdy_util_.ConstructSpdyDataFrame(1, "message", /*fin=*/false));
Ryan Hamilton0239aac2018-05-19 00:03:134983 spdy::SpdySerializedFrame data_frame_fin(
Bence Békyd74f4382018-02-20 18:26:194984 spdy_util_.ConstructSpdyDataFrame(1, "message", /*fin=*/true));
Ryan Hamilton0239aac2018-05-19 00:03:134985 spdy::SpdySerializedFrame combined_data_frames =
bncef26b602017-06-12 22:08:194986 CombineFrames({&data_frame, &data_frame, &data_frame, &data_frame_fin});
[email protected]8918d282010-03-02 00:57:554987
Ryan Hamilton0239aac2018-05-19 00:03:134988 spdy::SpdySerializedFrame resp(
4989 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
[email protected]8918d282010-03-02 00:57:554990 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:414991 CreateMockRead(resp, 1),
rch32320842015-05-16 15:57:094992 MockRead(ASYNC, ERR_IO_PENDING, 2), // Force a pause
bncef26b602017-06-12 22:08:194993 CreateMockRead(combined_data_frames, 3), MockRead(ASYNC, 0, 4) // EOF
[email protected]8918d282010-03-02 00:57:554994 };
4995
Ryan Sleevib8d7ea02018-05-07 20:01:014996 SequencedSocketData data(reads, writes);
[email protected]8918d282010-03-02 00:57:554997
Bence Békydb3cf652017-10-10 15:22:104998 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]3caf5542010-07-16 15:19:474999 helper.RunPreTestSetup();
[email protected]dd54bd82012-07-19 23:44:575000 helper.AddData(&data);
[email protected]3caf5542010-07-16 15:19:475001 HttpNetworkTransaction* trans = helper.trans();
[email protected]8918d282010-03-02 00:57:555002
[email protected]49639fa2011-12-20 23:22:415003 TestCompletionCallback callback;
Bence Békydb3cf652017-10-10 15:22:105004 int rv = trans->Start(&request_, callback.callback(), log_);
robpercival214763f2016-07-01 23:27:015005 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]8918d282010-03-02 00:57:555006
[email protected]3caf5542010-07-16 15:19:475007 TransactionHelperResult out = helper.output();
[email protected]8918d282010-03-02 00:57:555008 out.rv = callback.WaitForResult();
5009 EXPECT_EQ(out.rv, OK);
5010
5011 const HttpResponseInfo* response = trans->GetResponseInfo();
wezca1070932016-05-26 20:30:525012 EXPECT_TRUE(response->headers);
[email protected]8918d282010-03-02 00:57:555013 EXPECT_TRUE(response->was_fetched_via_spdy);
5014 out.status_line = response->headers->GetStatusLine();
5015 out.response_info = *response; // Make a copy so we can verify.
5016
5017 // Read Data
[email protected]49639fa2011-12-20 23:22:415018 TestCompletionCallback read_callback;
[email protected]8918d282010-03-02 00:57:555019
Bence Béky4e83f492018-05-13 23:14:255020 std::string content;
[email protected]8918d282010-03-02 00:57:555021 int reads_completed = 0;
5022 do {
5023 // Read small chunks at a time.
5024 const int kSmallReadSize = 14;
Victor Costan9c7302b2018-08-27 16:39:445025 scoped_refptr<IOBuffer> buf =
5026 base::MakeRefCounted<IOBuffer>(kSmallReadSize);
[email protected]90499482013-06-01 00:39:505027 rv = trans->Read(buf.get(), kSmallReadSize, read_callback.callback());
bnc301745a2015-03-10 03:22:165028 if (rv == ERR_IO_PENDING) {
mmenkee24011922015-12-17 22:12:595029 data.Resume();
[email protected]8918d282010-03-02 00:57:555030 rv = read_callback.WaitForResult();
5031 }
5032 if (rv > 0) {
5033 EXPECT_EQ(kSmallReadSize, rv);
5034 content.append(buf->data(), rv);
5035 } else if (rv < 0) {
5036 FAIL() << "Unexpected read error: " << rv;
5037 }
5038 reads_completed++;
5039 } while (rv > 0);
5040
5041 EXPECT_EQ(3, reads_completed); // Reads are: 14 bytes, 14 bytes, 0 bytes.
5042
5043 out.response_data.swap(content);
5044
[email protected]30c942b2010-07-21 16:59:595045 // Flush the MessageLoop while the SpdySessionDependencies (in particular, the
[email protected]8918d282010-03-02 00:57:555046 // MockClientSocketFactory) are still alive.
[email protected]fc9d88472013-08-14 02:31:175047 base::RunLoop().RunUntilIdle();
[email protected]8918d282010-03-02 00:57:555048
5049 // Verify that we consumed all test data.
[email protected]3caf5542010-07-16 15:19:475050 helper.VerifyDataConsumed();
[email protected]8918d282010-03-02 00:57:555051
robpercival214763f2016-07-01 23:27:015052 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:025053 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]8918d282010-03-02 00:57:555054 EXPECT_EQ("messagemessagemessagemessage", out.response_data);
5055}
5056
5057// Verify the case where we buffer data but read it after it has been buffered.
bncd16676a2016-07-20 16:23:015058TEST_F(SpdyNetworkTransactionTest, BufferedAll) {
Ryan Hamilton0239aac2018-05-19 00:03:135059 spdy::SpdySerializedFrame req(
5060 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
bncdf80d44fd2016-07-15 20:27:415061 MockWrite writes[] = {CreateMockWrite(req, 0)};
[email protected]8918d282010-03-02 00:57:555062
[email protected]20d005f2010-07-02 19:55:435063 // 5 data frames in a single read.
Ryan Hamilton0239aac2018-05-19 00:03:135064 spdy::SpdySerializedFrame reply(
5065 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
5066 spdy::SpdySerializedFrame data_frame(
Bence Békyd74f4382018-02-20 18:26:195067 spdy_util_.ConstructSpdyDataFrame(1, "message", /*fin=*/false));
Ryan Hamilton0239aac2018-05-19 00:03:135068 spdy::SpdySerializedFrame data_frame_fin(
Bence Békyd74f4382018-02-20 18:26:195069 spdy_util_.ConstructSpdyDataFrame(1, "message", /*fin=*/true));
Ryan Hamilton0239aac2018-05-19 00:03:135070 spdy::SpdySerializedFrame combined_frames = CombineFrames(
bncef26b602017-06-12 22:08:195071 {&reply, &data_frame, &data_frame, &data_frame, &data_frame_fin});
[email protected]8918d282010-03-02 00:57:555072
5073 MockRead reads[] = {
bncef26b602017-06-12 22:08:195074 CreateMockRead(combined_frames, 1), MockRead(ASYNC, 0, 2) // EOF
[email protected]8918d282010-03-02 00:57:555075 };
5076
Ryan Sleevib8d7ea02018-05-07 20:01:015077 SequencedSocketData data(reads, writes);
[email protected]8918d282010-03-02 00:57:555078
Bence Békydb3cf652017-10-10 15:22:105079 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]3caf5542010-07-16 15:19:475080 helper.RunPreTestSetup();
[email protected]dd54bd82012-07-19 23:44:575081 helper.AddData(&data);
[email protected]3caf5542010-07-16 15:19:475082 HttpNetworkTransaction* trans = helper.trans();
[email protected]8918d282010-03-02 00:57:555083
[email protected]49639fa2011-12-20 23:22:415084 TestCompletionCallback callback;
Bence Békydb3cf652017-10-10 15:22:105085 int rv = trans->Start(&request_, callback.callback(), log_);
robpercival214763f2016-07-01 23:27:015086 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]8918d282010-03-02 00:57:555087
[email protected]3caf5542010-07-16 15:19:475088 TransactionHelperResult out = helper.output();
[email protected]8918d282010-03-02 00:57:555089 out.rv = callback.WaitForResult();
5090 EXPECT_EQ(out.rv, OK);
5091
5092 const HttpResponseInfo* response = trans->GetResponseInfo();
wezca1070932016-05-26 20:30:525093 EXPECT_TRUE(response->headers);
[email protected]8918d282010-03-02 00:57:555094 EXPECT_TRUE(response->was_fetched_via_spdy);
5095 out.status_line = response->headers->GetStatusLine();
5096 out.response_info = *response; // Make a copy so we can verify.
5097
5098 // Read Data
[email protected]49639fa2011-12-20 23:22:415099 TestCompletionCallback read_callback;
[email protected]8918d282010-03-02 00:57:555100
Bence Béky4e83f492018-05-13 23:14:255101 std::string content;
[email protected]8918d282010-03-02 00:57:555102 int reads_completed = 0;
5103 do {
5104 // Read small chunks at a time.
5105 const int kSmallReadSize = 14;
Victor Costan9c7302b2018-08-27 16:39:445106 scoped_refptr<IOBuffer> buf =
5107 base::MakeRefCounted<IOBuffer>(kSmallReadSize);
[email protected]90499482013-06-01 00:39:505108 rv = trans->Read(buf.get(), kSmallReadSize, read_callback.callback());
[email protected]8918d282010-03-02 00:57:555109 if (rv > 0) {
5110 EXPECT_EQ(kSmallReadSize, rv);
5111 content.append(buf->data(), rv);
5112 } else if (rv < 0) {
5113 FAIL() << "Unexpected read error: " << rv;
5114 }
5115 reads_completed++;
5116 } while (rv > 0);
5117
5118 EXPECT_EQ(3, reads_completed);
5119
5120 out.response_data.swap(content);
5121
[email protected]30c942b2010-07-21 16:59:595122 // Flush the MessageLoop while the SpdySessionDependencies (in particular, the
[email protected]8918d282010-03-02 00:57:555123 // MockClientSocketFactory) are still alive.
[email protected]fc9d88472013-08-14 02:31:175124 base::RunLoop().RunUntilIdle();
[email protected]8918d282010-03-02 00:57:555125
5126 // Verify that we consumed all test data.
[email protected]3caf5542010-07-16 15:19:475127 helper.VerifyDataConsumed();
[email protected]8918d282010-03-02 00:57:555128
robpercival214763f2016-07-01 23:27:015129 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:025130 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]8918d282010-03-02 00:57:555131 EXPECT_EQ("messagemessagemessagemessage", out.response_data);
5132}
5133
5134// Verify the case where we buffer data and close the connection.
bncd16676a2016-07-20 16:23:015135TEST_F(SpdyNetworkTransactionTest, BufferedClosed) {
Ryan Hamilton0239aac2018-05-19 00:03:135136 spdy::SpdySerializedFrame req(
5137 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
bncdf80d44fd2016-07-15 20:27:415138 MockWrite writes[] = {CreateMockWrite(req, 0)};
[email protected]8918d282010-03-02 00:57:555139
5140 // All data frames in a single read.
[email protected]20d005f2010-07-02 19:55:435141 // NOTE: We don't FIN the stream.
Ryan Hamilton0239aac2018-05-19 00:03:135142 spdy::SpdySerializedFrame data_frame(
Bence Békyd74f4382018-02-20 18:26:195143 spdy_util_.ConstructSpdyDataFrame(1, "message", /*fin=*/false));
Ryan Hamilton0239aac2018-05-19 00:03:135144 spdy::SpdySerializedFrame combined_data_frames =
bncef26b602017-06-12 22:08:195145 CombineFrames({&data_frame, &data_frame, &data_frame, &data_frame});
Ryan Hamilton0239aac2018-05-19 00:03:135146 spdy::SpdySerializedFrame resp(
5147 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
[email protected]8918d282010-03-02 00:57:555148 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:415149 CreateMockRead(resp, 1),
rch32320842015-05-16 15:57:095150 MockRead(ASYNC, ERR_IO_PENDING, 2), // Force a wait
bncef26b602017-06-12 22:08:195151 CreateMockRead(combined_data_frames, 3), MockRead(ASYNC, 0, 4) // EOF
[email protected]8918d282010-03-02 00:57:555152 };
5153
Ryan Sleevib8d7ea02018-05-07 20:01:015154 SequencedSocketData data(reads, writes);
[email protected]8918d282010-03-02 00:57:555155
Bence Békydb3cf652017-10-10 15:22:105156 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]3caf5542010-07-16 15:19:475157 helper.RunPreTestSetup();
[email protected]dd54bd82012-07-19 23:44:575158 helper.AddData(&data);
[email protected]3caf5542010-07-16 15:19:475159 HttpNetworkTransaction* trans = helper.trans();
[email protected]8918d282010-03-02 00:57:555160
[email protected]49639fa2011-12-20 23:22:415161 TestCompletionCallback callback;
[email protected]8918d282010-03-02 00:57:555162
Bence Békydb3cf652017-10-10 15:22:105163 int rv = trans->Start(&request_, callback.callback(), log_);
robpercival214763f2016-07-01 23:27:015164 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]8918d282010-03-02 00:57:555165
[email protected]3caf5542010-07-16 15:19:475166 TransactionHelperResult out = helper.output();
Francois Doray6bbf45e2021-06-30 19:06:515167 rv = callback.WaitForResult();
5168 EXPECT_EQ(rv, OK);
[email protected]8918d282010-03-02 00:57:555169
5170 const HttpResponseInfo* response = trans->GetResponseInfo();
wezca1070932016-05-26 20:30:525171 EXPECT_TRUE(response->headers);
[email protected]8918d282010-03-02 00:57:555172 EXPECT_TRUE(response->was_fetched_via_spdy);
[email protected]8918d282010-03-02 00:57:555173
5174 // Read Data
[email protected]49639fa2011-12-20 23:22:415175 TestCompletionCallback read_callback;
[email protected]8918d282010-03-02 00:57:555176
Bence Béky4e83f492018-05-13 23:14:255177 std::string content;
[email protected]8918d282010-03-02 00:57:555178 int reads_completed = 0;
5179 do {
Francois Doray6bbf45e2021-06-30 19:06:515180 // Allocate a large buffer to allow buffering. If a single read fills the
5181 // buffer, no buffering happens.
5182 const int kLargeReadSize = 1000;
Victor Costan9c7302b2018-08-27 16:39:445183 scoped_refptr<IOBuffer> buf =
Francois Doray6bbf45e2021-06-30 19:06:515184 base::MakeRefCounted<IOBuffer>(kLargeReadSize);
5185 rv = trans->Read(buf.get(), kLargeReadSize, read_callback.callback());
bnc301745a2015-03-10 03:22:165186 if (rv == ERR_IO_PENDING) {
mmenkee24011922015-12-17 22:12:595187 data.Resume();
[email protected]8918d282010-03-02 00:57:555188 rv = read_callback.WaitForResult();
5189 }
Francois Doray6bbf45e2021-06-30 19:06:515190
5191 if (rv < 0) {
[email protected]8918d282010-03-02 00:57:555192 // This test intentionally closes the connection, and will get an error.
robpercival214763f2016-07-01 23:27:015193 EXPECT_THAT(rv, IsError(ERR_CONNECTION_CLOSED));
[email protected]8918d282010-03-02 00:57:555194 break;
5195 }
5196 reads_completed++;
5197 } while (rv > 0);
5198
5199 EXPECT_EQ(0, reads_completed);
5200
[email protected]30c942b2010-07-21 16:59:595201 // Flush the MessageLoop while the SpdySessionDependencies (in particular, the
[email protected]8918d282010-03-02 00:57:555202 // MockClientSocketFactory) are still alive.
[email protected]fc9d88472013-08-14 02:31:175203 base::RunLoop().RunUntilIdle();
[email protected]8918d282010-03-02 00:57:555204
5205 // Verify that we consumed all test data.
[email protected]3caf5542010-07-16 15:19:475206 helper.VerifyDataConsumed();
[email protected]8918d282010-03-02 00:57:555207}
5208
[email protected]1ed7b3dc2010-03-04 05:41:455209// Verify the case where we buffer data and cancel the transaction.
bncd16676a2016-07-20 16:23:015210TEST_F(SpdyNetworkTransactionTest, BufferedCancelled) {
Ryan Hamilton0239aac2018-05-19 00:03:135211 spdy::SpdySerializedFrame req(
5212 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
5213 spdy::SpdySerializedFrame rst(
5214 spdy_util_.ConstructSpdyRstStream(1, spdy::ERROR_CODE_CANCEL));
bncdf80d44fd2016-07-15 20:27:415215 MockWrite writes[] = {CreateMockWrite(req, 0), CreateMockWrite(rst, 4)};
[email protected]1ed7b3dc2010-03-04 05:41:455216
[email protected]20d005f2010-07-02 19:55:435217 // NOTE: We don't FIN the stream.
Ryan Hamilton0239aac2018-05-19 00:03:135218 spdy::SpdySerializedFrame data_frame(
Bence Békyd74f4382018-02-20 18:26:195219 spdy_util_.ConstructSpdyDataFrame(1, "message", /*fin=*/false));
[email protected]1ed7b3dc2010-03-04 05:41:455220
Ryan Hamilton0239aac2018-05-19 00:03:135221 spdy::SpdySerializedFrame resp(
5222 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
[email protected]1ed7b3dc2010-03-04 05:41:455223 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:415224 CreateMockRead(resp, 1),
5225 MockRead(ASYNC, ERR_IO_PENDING, 2), // Force a wait
5226 CreateMockRead(data_frame, 3), MockRead(ASYNC, 0, 5) // EOF
[email protected]1ed7b3dc2010-03-04 05:41:455227 };
5228
Ryan Sleevib8d7ea02018-05-07 20:01:015229 SequencedSocketData data(reads, writes);
[email protected]1ed7b3dc2010-03-04 05:41:455230
Bence Békydb3cf652017-10-10 15:22:105231 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]3caf5542010-07-16 15:19:475232 helper.RunPreTestSetup();
[email protected]dd54bd82012-07-19 23:44:575233 helper.AddData(&data);
[email protected]3caf5542010-07-16 15:19:475234 HttpNetworkTransaction* trans = helper.trans();
[email protected]49639fa2011-12-20 23:22:415235 TestCompletionCallback callback;
[email protected]1ed7b3dc2010-03-04 05:41:455236
Bence Békydb3cf652017-10-10 15:22:105237 int rv = trans->Start(&request_, callback.callback(), log_);
robpercival214763f2016-07-01 23:27:015238 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]1ed7b3dc2010-03-04 05:41:455239
[email protected]3caf5542010-07-16 15:19:475240 TransactionHelperResult out = helper.output();
[email protected]1ed7b3dc2010-03-04 05:41:455241 out.rv = callback.WaitForResult();
5242 EXPECT_EQ(out.rv, OK);
5243
5244 const HttpResponseInfo* response = trans->GetResponseInfo();
wezca1070932016-05-26 20:30:525245 EXPECT_TRUE(response->headers);
[email protected]1ed7b3dc2010-03-04 05:41:455246 EXPECT_TRUE(response->was_fetched_via_spdy);
5247 out.status_line = response->headers->GetStatusLine();
5248 out.response_info = *response; // Make a copy so we can verify.
5249
5250 // Read Data
[email protected]49639fa2011-12-20 23:22:415251 TestCompletionCallback read_callback;
[email protected]1ed7b3dc2010-03-04 05:41:455252
[email protected]88c7b4be2014-03-19 23:04:015253 const int kReadSize = 256;
Victor Costan9c7302b2018-08-27 16:39:445254 scoped_refptr<IOBuffer> buf = base::MakeRefCounted<IOBuffer>(kReadSize);
[email protected]88c7b4be2014-03-19 23:04:015255 rv = trans->Read(buf.get(), kReadSize, read_callback.callback());
bnc301745a2015-03-10 03:22:165256 ASSERT_EQ(ERR_IO_PENDING, rv) << "Unexpected read: " << rv;
[email protected]88c7b4be2014-03-19 23:04:015257
5258 // Complete the read now, which causes buffering to start.
mmenkee24011922015-12-17 22:12:595259 data.Resume();
5260 base::RunLoop().RunUntilIdle();
[email protected]88c7b4be2014-03-19 23:04:015261 // Destroy the transaction, causing the stream to get cancelled
5262 // and orphaning the buffered IO task.
5263 helper.ResetTrans();
[email protected]1ed7b3dc2010-03-04 05:41:455264
5265 // Flush the MessageLoop; this will cause the buffered IO task
5266 // to run for the final time.
[email protected]fc9d88472013-08-14 02:31:175267 base::RunLoop().RunUntilIdle();
[email protected]3caf5542010-07-16 15:19:475268
5269 // Verify that we consumed all test data.
5270 helper.VerifyDataConsumed();
[email protected]1ed7b3dc2010-03-04 05:41:455271}
5272
bncc4769d412017-04-19 19:57:545273// Request should fail upon receiving a GOAWAY frame
5274// with Last-Stream-ID lower than the stream id corresponding to the request
5275// and with error code other than NO_ERROR.
5276TEST_F(SpdyNetworkTransactionTest, FailOnGoAway) {
Ryan Hamilton0239aac2018-05-19 00:03:135277 spdy::SpdySerializedFrame req(
5278 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
bncdf80d44fd2016-07-15 20:27:415279 MockWrite writes[] = {CreateMockWrite(req, 0)};
[email protected]69d717bd2010-04-21 18:43:215280
Ryan Hamilton0239aac2018-05-19 00:03:135281 spdy::SpdySerializedFrame go_away(
5282 spdy_util_.ConstructSpdyGoAway(0, spdy::ERROR_CODE_INTERNAL_ERROR, ""));
[email protected]69d717bd2010-04-21 18:43:215283 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:415284 CreateMockRead(go_away, 1),
[email protected]58cebf8f2010-07-31 19:20:165285 };
5286
Ryan Sleevib8d7ea02018-05-07 20:01:015287 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:105288 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]dd54bd82012-07-19 23:44:575289 helper.RunToCompletion(&data);
[email protected]58cebf8f2010-07-31 19:20:165290 TransactionHelperResult out = helper.output();
Matt Menke3b52f9f2020-06-08 20:04:035291 EXPECT_THAT(out.rv, IsError(ERR_HTTP2_PROTOCOL_ERROR));
[email protected]69d717bd2010-04-21 18:43:215292}
5293
bncc4769d412017-04-19 19:57:545294// Request should be retried on a new connection upon receiving a GOAWAY frame
5295// with Last-Stream-ID lower than the stream id corresponding to the request
5296// and with error code NO_ERROR.
5297TEST_F(SpdyNetworkTransactionTest, RetryOnGoAway) {
Bence Békydb3cf652017-10-10 15:22:105298 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
bncc4769d412017-04-19 19:57:545299
5300 // First connection.
Ryan Hamilton0239aac2018-05-19 00:03:135301 spdy::SpdySerializedFrame req(
5302 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
bncc4769d412017-04-19 19:57:545303 MockWrite writes1[] = {CreateMockWrite(req, 0)};
Ryan Hamilton0239aac2018-05-19 00:03:135304 spdy::SpdySerializedFrame go_away(
5305 spdy_util_.ConstructSpdyGoAway(0, spdy::ERROR_CODE_NO_ERROR, ""));
bncc4769d412017-04-19 19:57:545306 MockRead reads1[] = {CreateMockRead(go_away, 1)};
Ryan Sleevib8d7ea02018-05-07 20:01:015307 SequencedSocketData data1(reads1, writes1);
bncc4769d412017-04-19 19:57:545308 helper.AddData(&data1);
5309
5310 // Second connection.
5311 MockWrite writes2[] = {CreateMockWrite(req, 0)};
Ryan Hamilton0239aac2018-05-19 00:03:135312 spdy::SpdySerializedFrame resp(
5313 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
5314 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
bncc4769d412017-04-19 19:57:545315 MockRead reads2[] = {CreateMockRead(resp, 1), CreateMockRead(body, 2),
5316 MockRead(ASYNC, 0, 3)};
Ryan Sleevib8d7ea02018-05-07 20:01:015317 SequencedSocketData data2(reads2, writes2);
bncc4769d412017-04-19 19:57:545318 helper.AddData(&data2);
5319
5320 helper.RunPreTestSetup();
5321 helper.RunDefaultTest();
5322
5323 TransactionHelperResult out = helper.output();
5324 EXPECT_THAT(out.rv, IsOk());
5325
5326 helper.VerifyDataConsumed();
5327}
5328
bnc1fc7b352017-01-12 17:51:025329// A server can gracefully shut down by sending a GOAWAY frame
5330// with maximum last-stream-id value.
5331// Transactions started before receiving such a GOAWAY frame should succeed,
5332// but SpdySession should be unavailable for new streams.
5333TEST_F(SpdyNetworkTransactionTest, GracefulGoaway) {
Ryan Hamilton0239aac2018-05-19 00:03:135334 spdy::SpdySerializedFrame req1(
5335 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
bnc1fc7b352017-01-12 17:51:025336 spdy_util_.UpdateWithStreamDestruction(1);
Ryan Hamilton0239aac2018-05-19 00:03:135337 spdy::SpdySerializedFrame req2(
bnc1fc7b352017-01-12 17:51:025338 spdy_util_.ConstructSpdyGet("https://www.example.org/foo", 3, LOWEST));
5339 MockWrite writes[] = {CreateMockWrite(req1, 0), CreateMockWrite(req2, 3)};
5340
Ryan Hamilton0239aac2018-05-19 00:03:135341 spdy::SpdySerializedFrame resp1(
5342 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
5343 spdy::SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true));
5344 spdy::SpdySerializedFrame goaway(spdy_util_.ConstructSpdyGoAway(
5345 0x7fffffff, spdy::ERROR_CODE_NO_ERROR, "Graceful shutdown."));
5346 spdy::SpdySerializedFrame resp2(
5347 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
5348 spdy::SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(3, true));
bnc1fc7b352017-01-12 17:51:025349 MockRead reads[] = {CreateMockRead(resp1, 1), CreateMockRead(body1, 2),
5350 CreateMockRead(goaway, 4), CreateMockRead(resp2, 5),
5351 CreateMockRead(body2, 6), MockRead(ASYNC, 0, 7)};
5352
5353 // Run first transaction.
Ryan Sleevib8d7ea02018-05-07 20:01:015354 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:105355 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
bnc1fc7b352017-01-12 17:51:025356 helper.RunPreTestSetup();
5357 helper.AddData(&data);
5358 helper.RunDefaultTest();
5359
5360 // Verify first response.
5361 TransactionHelperResult out = helper.output();
5362 EXPECT_THAT(out.rv, IsOk());
5363 EXPECT_EQ("HTTP/1.1 200", out.status_line);
5364 EXPECT_EQ("hello!", out.response_data);
5365
5366 // GOAWAY frame has not yet been received, SpdySession should be available.
5367 SpdySessionPool* spdy_session_pool = helper.session()->spdy_session_pool();
5368 SpdySessionKey key(host_port_pair_, ProxyServer::Direct(),
Matt Menke2436b2f2018-12-11 18:07:115369 PRIVACY_MODE_DISABLED,
dalyk51ab46b2019-10-15 15:14:345370 SpdySessionKey::IsProxySession::kFalse, SocketTag(),
Ben Schwartz3ff4dc1e62021-04-27 21:15:235371 NetworkIsolationKey(), SecureDnsPolicy::kAllow);
bnc1fc7b352017-01-12 17:51:025372 base::WeakPtr<SpdySession> spdy_session =
bnc9ead3ae2017-03-16 00:48:155373 spdy_session_pool->FindAvailableSession(
Bence Békyd885b2b2018-02-03 00:58:315374 key, /* enable_ip_based_pooling = */ true,
5375 /* is_websocket = */ false, log_);
bnc1fc7b352017-01-12 17:51:025376 EXPECT_TRUE(spdy_session);
5377
5378 // Start second transaction.
5379 HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session());
5380 TestCompletionCallback callback;
5381 HttpRequestInfo request2;
5382 request2.method = "GET";
5383 request2.url = GURL("https://www.example.org/foo");
Ramin Halavatib5e433e62018-02-07 07:41:105384 request2.traffic_annotation =
5385 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
Bence Békyd3dde832017-09-19 19:02:315386 int rv = trans2.Start(&request2, callback.callback(), log_);
bnc1fc7b352017-01-12 17:51:025387 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
5388 rv = callback.WaitForResult();
5389 EXPECT_THAT(rv, IsOk());
5390
5391 // Verify second response.
5392 const HttpResponseInfo* response = trans2.GetResponseInfo();
5393 ASSERT_TRUE(response);
5394 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP2, response->connection_info);
5395 ASSERT_TRUE(response->headers);
5396 EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
5397 EXPECT_TRUE(response->was_fetched_via_spdy);
5398 EXPECT_TRUE(response->was_alpn_negotiated);
Tsuyoshi Horo01faed62019-02-20 22:11:375399 EXPECT_EQ("127.0.0.1", response->remote_endpoint.ToStringWithoutPort());
5400 EXPECT_EQ(443, response->remote_endpoint.port());
Bence Béky4e83f492018-05-13 23:14:255401 std::string response_data;
bnc1fc7b352017-01-12 17:51:025402 rv = ReadTransaction(&trans2, &response_data);
5403 EXPECT_THAT(rv, IsOk());
5404 EXPECT_EQ("hello!", response_data);
5405
5406 // Graceful GOAWAY was received, SpdySession should be unavailable.
bnc9ead3ae2017-03-16 00:48:155407 spdy_session = spdy_session_pool->FindAvailableSession(
Bence Békyd885b2b2018-02-03 00:58:315408 key, /* enable_ip_based_pooling = */ true,
5409 /* is_websocket = */ false, log_);
bnc1fc7b352017-01-12 17:51:025410 EXPECT_FALSE(spdy_session);
5411
5412 helper.VerifyDataConsumed();
5413}
5414
bncd16676a2016-07-20 16:23:015415TEST_F(SpdyNetworkTransactionTest, CloseWithActiveStream) {
Ryan Hamilton0239aac2018-05-19 00:03:135416 spdy::SpdySerializedFrame req(
5417 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
bncdf80d44fd2016-07-15 20:27:415418 MockWrite writes[] = {CreateMockWrite(req, 0)};
[email protected]f5ed21552010-05-04 18:39:545419
Ryan Hamilton0239aac2018-05-19 00:03:135420 spdy::SpdySerializedFrame resp(
5421 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
[email protected]f5ed21552010-05-04 18:39:545422 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:415423 CreateMockRead(resp, 1), MockRead(SYNCHRONOUS, 0, 2) // EOF
[email protected]f5ed21552010-05-04 18:39:545424 };
5425
Ryan Sleevib8d7ea02018-05-07 20:01:015426 SequencedSocketData data(reads, writes);
bnc4d782f492016-08-18 13:50:005427
Bence Békydb3cf652017-10-10 15:22:105428 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]3caf5542010-07-16 15:19:475429 helper.RunPreTestSetup();
[email protected]dd54bd82012-07-19 23:44:575430 helper.AddData(&data);
bnc4d782f492016-08-18 13:50:005431 helper.StartDefaultTest();
5432 EXPECT_THAT(helper.output().rv, IsError(ERR_IO_PENDING));
[email protected]f5ed21552010-05-04 18:39:545433
bnc4d782f492016-08-18 13:50:005434 helper.WaitForCallbackToComplete();
5435 EXPECT_THAT(helper.output().rv, IsError(ERR_CONNECTION_CLOSED));
[email protected]3caf5542010-07-16 15:19:475436
bnc4d782f492016-08-18 13:50:005437 const HttpResponseInfo* response = helper.trans()->GetResponseInfo();
wezca1070932016-05-26 20:30:525438 EXPECT_TRUE(response->headers);
[email protected]f5ed21552010-05-04 18:39:545439 EXPECT_TRUE(response->was_fetched_via_spdy);
[email protected]f5ed21552010-05-04 18:39:545440
5441 // Verify that we consumed all test data.
[email protected]3caf5542010-07-16 15:19:475442 helper.VerifyDataConsumed();
[email protected]f5ed21552010-05-04 18:39:545443}
[email protected]58cebf8f2010-07-31 19:20:165444
Bence Békyc2d37952017-11-20 16:58:165445TEST_F(SpdyNetworkTransactionTest, GoAwayImmediately) {
Ryan Hamilton0239aac2018-05-19 00:03:135446 spdy::SpdySerializedFrame goaway(spdy_util_.ConstructSpdyGoAway(1));
Bence Békyc2d37952017-11-20 16:58:165447 MockRead reads[] = {CreateMockRead(goaway, 0, SYNCHRONOUS)};
Ryan Sleevib8d7ea02018-05-07 20:01:015448 SequencedSocketData data(reads, base::span<MockWrite>());
Bence Békyc2d37952017-11-20 16:58:165449
5450 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
5451 helper.RunPreTestSetup();
5452 helper.AddData(&data);
5453 helper.StartDefaultTest();
5454 EXPECT_THAT(helper.output().rv, IsError(ERR_IO_PENDING));
5455
5456 helper.WaitForCallbackToComplete();
5457 EXPECT_THAT(helper.output().rv, IsError(ERR_CONNECTION_CLOSED));
5458
5459 const HttpResponseInfo* response = helper.trans()->GetResponseInfo();
5460 EXPECT_FALSE(response->headers);
5461 EXPECT_TRUE(response->was_fetched_via_spdy);
5462
5463 // Verify that we consumed all test data.
5464 helper.VerifyDataConsumed();
5465}
5466
bncfacdd852015-01-09 19:22:545467// Retry with HTTP/1.1 when receiving HTTP_1_1_REQUIRED. Note that no actual
5468// protocol negotiation happens, instead this test forces protocols for both
5469// sockets.
bncd16676a2016-07-20 16:23:015470TEST_F(SpdyNetworkTransactionTest, HTTP11RequiredRetry) {
Bence Békydb3cf652017-10-10 15:22:105471 request_.method = "GET";
bncfacdd852015-01-09 19:22:545472 // Do not force SPDY so that second socket can negotiate HTTP/1.1.
Bence Békydb3cf652017-10-10 15:22:105473 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
bncfacdd852015-01-09 19:22:545474
5475 // First socket: HTTP/2 request rejected with HTTP_1_1_REQUIRED.
Bence Béky4c325e52020-10-22 20:48:015476 spdy::Http2HeaderBlock headers(
Ryan Hamilton0239aac2018-05-19 00:03:135477 spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
5478 spdy::SpdySerializedFrame req(
bnc42331402016-07-25 13:36:155479 spdy_util_.ConstructSpdyHeaders(1, std::move(headers), LOWEST, true));
bncdf80d44fd2016-07-15 20:27:415480 MockWrite writes0[] = {CreateMockWrite(req, 0)};
Ryan Hamilton0239aac2018-05-19 00:03:135481 spdy::SpdySerializedFrame rst(
5482 spdy_util_.ConstructSpdyRstStream(1, spdy::ERROR_CODE_HTTP_1_1_REQUIRED));
Bence Békycb3613122017-09-19 17:06:575483 MockRead reads0[] = {CreateMockRead(rst, 1)};
Ryan Sleevib8d7ea02018-05-07 20:01:015484 SequencedSocketData data0(reads0, writes0);
bncfacdd852015-01-09 19:22:545485
Jeremy Roman0579ed62017-08-29 15:56:195486 auto ssl_provider0 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
bncfacdd852015-01-09 19:22:545487 // Expect HTTP/2 protocols too in SSLConfig.
Bence Béky27a19b82018-01-30 14:58:365488 ssl_provider0->next_protos_expected_in_ssl_config =
5489 NextProtoVector{kProtoHTTP2, kProtoHTTP11};
bncfacdd852015-01-09 19:22:545490 // Force SPDY.
bnc3cf2a592016-08-11 14:48:365491 ssl_provider0->next_proto = kProtoHTTP2;
dchengc7eeda422015-12-26 03:56:485492 helper.AddDataWithSSLSocketDataProvider(&data0, std::move(ssl_provider0));
bncfacdd852015-01-09 19:22:545493
5494 // Second socket: falling back to HTTP/1.1.
rch08e3aa3e2015-05-16 14:27:525495 MockWrite writes1[] = {MockWrite(ASYNC, 0,
5496 "GET / HTTP/1.1\r\n"
5497 "Host: www.example.org\r\n"
5498 "Connection: keep-alive\r\n\r\n")};
5499 MockRead reads1[] = {MockRead(ASYNC, 1,
5500 "HTTP/1.1 200 OK\r\n"
5501 "Content-Length: 5\r\n\r\n"
5502 "hello")};
Ryan Sleevib8d7ea02018-05-07 20:01:015503 SequencedSocketData data1(reads1, writes1);
bncfacdd852015-01-09 19:22:545504
Jeremy Roman0579ed62017-08-29 15:56:195505 auto ssl_provider1 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
bncfacdd852015-01-09 19:22:545506 // Expect only HTTP/1.1 protocol in SSLConfig.
Bence Béky27a19b82018-01-30 14:58:365507 ssl_provider1->next_protos_expected_in_ssl_config =
5508 NextProtoVector{kProtoHTTP11};
bncfacdd852015-01-09 19:22:545509 // Force HTTP/1.1.
bnc3cf2a592016-08-11 14:48:365510 ssl_provider1->next_proto = kProtoHTTP11;
dchengc7eeda422015-12-26 03:56:485511 helper.AddDataWithSSLSocketDataProvider(&data1, std::move(ssl_provider1));
bncfacdd852015-01-09 19:22:545512
bnc525e175a2016-06-20 12:36:405513 HttpServerProperties* http_server_properties =
bncfacdd852015-01-09 19:22:545514 helper.session()->spdy_session_pool()->http_server_properties();
Matt Menkef2ee07c2019-08-29 02:10:365515 EXPECT_FALSE(http_server_properties->RequiresHTTP11(
5516 url::SchemeHostPort(request_.url), NetworkIsolationKey()));
bncfacdd852015-01-09 19:22:545517
5518 helper.RunPreTestSetup();
5519 helper.StartDefaultTest();
5520 helper.FinishDefaultTestWithoutVerification();
5521 helper.VerifyDataConsumed();
Matt Menkef2ee07c2019-08-29 02:10:365522 EXPECT_TRUE(http_server_properties->RequiresHTTP11(
5523 url::SchemeHostPort(request_.url), NetworkIsolationKey()));
bncfacdd852015-01-09 19:22:545524
5525 const HttpResponseInfo* response = helper.trans()->GetResponseInfo();
wezca1070932016-05-26 20:30:525526 ASSERT_TRUE(response);
5527 ASSERT_TRUE(response->headers);
bncfacdd852015-01-09 19:22:545528 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
5529 EXPECT_FALSE(response->was_fetched_via_spdy);
mmenke8210acc2016-07-11 16:34:525530 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP1_1,
5531 response->connection_info);
bnc94c92842016-09-21 15:22:525532 EXPECT_TRUE(response->was_alpn_negotiated);
Bence Békydb3cf652017-10-10 15:22:105533 EXPECT_TRUE(request_.url.SchemeIs("https"));
Tsuyoshi Horo01faed62019-02-20 22:11:375534 EXPECT_EQ("127.0.0.1", response->remote_endpoint.ToStringWithoutPort());
5535 EXPECT_EQ(443, response->remote_endpoint.port());
Bence Béky4e83f492018-05-13 23:14:255536 std::string response_data;
robpercival214763f2016-07-01 23:27:015537 ASSERT_THAT(ReadTransaction(helper.trans(), &response_data), IsOk());
bncfacdd852015-01-09 19:22:545538 EXPECT_EQ("hello", response_data);
5539}
5540
Matt Menkef2ee07c2019-08-29 02:10:365541// Same as above test, but checks that NetworkIsolationKeys are respected.
5542TEST_F(SpdyNetworkTransactionTest, HTTP11RequiredRetryWithNetworkIsolationKey) {
Matt Menke4807a9a2020-11-21 00:14:415543 const SchemefulSite kSite1(GURL("https://foo.test/"));
5544 const SchemefulSite kSite2(GURL("https://bar.test/"));
5545 const NetworkIsolationKey kNetworkIsolationKey1(kSite1, kSite1);
5546 const NetworkIsolationKey kNetworkIsolationKey2(kSite2, kSite2);
Matt Menkef2ee07c2019-08-29 02:10:365547
5548 const NetworkIsolationKey kNetworkIsolationKeys[] = {
5549 kNetworkIsolationKey1, kNetworkIsolationKey2, NetworkIsolationKey()};
5550
5551 base::test::ScopedFeatureList feature_list;
5552 feature_list.InitWithFeatures(
5553 // enabled_features
5554 {features::kPartitionHttpServerPropertiesByNetworkIsolationKey,
5555 // Need to partition connections by NetworkIsolationKey for
5556 // SpdySessionKeys to include NetworkIsolationKeys.
5557 features::kPartitionConnectionsByNetworkIsolationKey},
5558 // disabled_features
5559 {});
5560
5561 // Do not force SPDY so that sockets can negotiate HTTP/1.1.
5562 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
5563
5564 // For each server, set up and tear down a QUIC session cleanly, and check
5565 // that stats have been added to HttpServerProperties using the correct
5566 // NetworkIsolationKey.
5567 for (size_t i = 0; i < base::size(kNetworkIsolationKeys); ++i) {
5568 SCOPED_TRACE(i);
5569
5570 request_.method = "GET";
5571 request_.network_isolation_key = kNetworkIsolationKeys[i];
5572
5573 // First socket: HTTP/2 request rejected with HTTP_1_1_REQUIRED.
5574 SpdyTestUtil spdy_util;
Bence Béky4c325e52020-10-22 20:48:015575 spdy::Http2HeaderBlock headers(
Matt Menkef2ee07c2019-08-29 02:10:365576 spdy_util.ConstructGetHeaderBlock(kDefaultUrl));
5577 spdy::SpdySerializedFrame req(
5578 spdy_util.ConstructSpdyHeaders(1, std::move(headers), LOWEST, true));
5579 MockWrite writes0[] = {CreateMockWrite(req, 0)};
5580 spdy::SpdySerializedFrame rst(spdy_util.ConstructSpdyRstStream(
5581 1, spdy::ERROR_CODE_HTTP_1_1_REQUIRED));
5582 MockRead reads0[] = {CreateMockRead(rst, 1)};
5583 SequencedSocketData data0(reads0, writes0);
5584
5585 auto ssl_provider0 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
5586 // Expect HTTP/2 protocols too in SSLConfig.
5587 ssl_provider0->next_protos_expected_in_ssl_config =
5588 NextProtoVector{kProtoHTTP2, kProtoHTTP11};
5589 // Force SPDY.
5590 ssl_provider0->next_proto = kProtoHTTP2;
5591 helper.AddDataWithSSLSocketDataProvider(&data0, std::move(ssl_provider0));
5592
5593 // Second socket: falling back to HTTP/1.1.
5594 MockWrite writes1[] = {MockWrite(ASYNC, 0,
5595 "GET / HTTP/1.1\r\n"
5596 "Host: www.example.org\r\n"
5597 "Connection: keep-alive\r\n\r\n")};
5598 MockRead reads1[] = {MockRead(ASYNC, 1,
5599 "HTTP/1.1 200 OK\r\n"
5600 "Content-Length: 5\r\n\r\n"
5601 "hello")};
5602 SequencedSocketData data1(reads1, writes1);
5603
5604 auto ssl_provider1 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
5605 // Expect only HTTP/1.1 protocol in SSLConfig.
5606 ssl_provider1->next_protos_expected_in_ssl_config =
5607 NextProtoVector{kProtoHTTP11};
5608 // Force HTTP/1.1.
5609 ssl_provider1->next_proto = kProtoHTTP11;
5610 helper.AddDataWithSSLSocketDataProvider(&data1, std::move(ssl_provider1));
5611
5612 HttpServerProperties* http_server_properties =
5613 helper.session()->spdy_session_pool()->http_server_properties();
5614 EXPECT_FALSE(http_server_properties->RequiresHTTP11(
5615 url::SchemeHostPort(request_.url), kNetworkIsolationKeys[i]));
5616
5617 HttpNetworkTransaction trans(DEFAULT_PRIORITY, helper.session());
5618
5619 TestCompletionCallback callback;
5620 int rv = trans.Start(&request_, callback.callback(), log_);
5621 EXPECT_THAT(callback.GetResult(rv), IsOk());
5622
5623 const HttpResponseInfo* response = trans.GetResponseInfo();
5624 ASSERT_TRUE(response);
5625 ASSERT_TRUE(response->headers);
5626 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
5627 EXPECT_FALSE(response->was_fetched_via_spdy);
5628 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP1_1,
5629 response->connection_info);
5630 EXPECT_TRUE(response->was_alpn_negotiated);
5631 EXPECT_TRUE(request_.url.SchemeIs("https"));
5632 EXPECT_EQ("127.0.0.1", response->remote_endpoint.ToStringWithoutPort());
5633 EXPECT_EQ(443, response->remote_endpoint.port());
5634 std::string response_data;
5635 ASSERT_THAT(ReadTransaction(&trans, &response_data), IsOk());
5636 EXPECT_EQ("hello", response_data);
5637
5638 for (size_t j = 0; j < base::size(kNetworkIsolationKeys); ++j) {
5639 // NetworkIsolationKeys up to kNetworkIsolationKeys[j] are known to
5640 // require HTTP/1.1, others are not.
5641 if (j <= i) {
5642 EXPECT_TRUE(http_server_properties->RequiresHTTP11(
5643 url::SchemeHostPort(request_.url), kNetworkIsolationKeys[j]));
5644 } else {
5645 EXPECT_FALSE(http_server_properties->RequiresHTTP11(
5646 url::SchemeHostPort(request_.url), kNetworkIsolationKeys[j]));
5647 }
5648 }
5649 }
5650}
5651
bncfacdd852015-01-09 19:22:545652// Retry with HTTP/1.1 to the proxy when receiving HTTP_1_1_REQUIRED from the
5653// proxy. Note that no actual protocol negotiation happens, instead this test
5654// forces protocols for both sockets.
bncd16676a2016-07-20 16:23:015655TEST_F(SpdyNetworkTransactionTest, HTTP11RequiredProxyRetry) {
Bence Békydb3cf652017-10-10 15:22:105656 request_.method = "GET";
Jeremy Roman0579ed62017-08-29 15:56:195657 auto session_deps = std::make_unique<SpdySessionDependencies>(
Nicolas Arciniegad2013f92020-02-07 23:00:565658 ConfiguredProxyResolutionService::CreateFixedFromPacResult(
Ramin Halavatica8d5252018-03-12 05:33:495659 "HTTPS myproxy:70", TRAFFIC_ANNOTATION_FOR_TESTS));
bncfacdd852015-01-09 19:22:545660 // Do not force SPDY so that second socket can negotiate HTTP/1.1.
Bence Békydb3cf652017-10-10 15:22:105661 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
Bence Békyd3dde832017-09-19 19:02:315662 std::move(session_deps));
bncfacdd852015-01-09 19:22:545663
5664 // First socket: HTTP/2 CONNECT rejected with HTTP_1_1_REQUIRED.
Ryan Hamilton0239aac2018-05-19 00:03:135665 spdy::SpdySerializedFrame req(spdy_util_.ConstructSpdyConnect(
Matt Menke6e879bd2019-03-18 17:26:045666 nullptr, 0, 1, HttpProxyConnectJob::kH2QuicTunnelPriority,
5667 HostPortPair("www.example.org", 443)));
bncdf80d44fd2016-07-15 20:27:415668 MockWrite writes0[] = {CreateMockWrite(req, 0)};
Ryan Hamilton0239aac2018-05-19 00:03:135669 spdy::SpdySerializedFrame rst(
5670 spdy_util_.ConstructSpdyRstStream(1, spdy::ERROR_CODE_HTTP_1_1_REQUIRED));
Bence Békycb3613122017-09-19 17:06:575671 MockRead reads0[] = {CreateMockRead(rst, 1)};
Ryan Sleevib8d7ea02018-05-07 20:01:015672 SequencedSocketData data0(reads0, writes0);
bncfacdd852015-01-09 19:22:545673
Jeremy Roman0579ed62017-08-29 15:56:195674 auto ssl_provider0 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
bncfacdd852015-01-09 19:22:545675 // Expect HTTP/2 protocols too in SSLConfig.
Bence Béky27a19b82018-01-30 14:58:365676 ssl_provider0->next_protos_expected_in_ssl_config =
5677 NextProtoVector{kProtoHTTP2, kProtoHTTP11};
bncfacdd852015-01-09 19:22:545678 // Force SPDY.
bnc3cf2a592016-08-11 14:48:365679 ssl_provider0->next_proto = kProtoHTTP2;
dchengc7eeda422015-12-26 03:56:485680 helper.AddDataWithSSLSocketDataProvider(&data0, std::move(ssl_provider0));
bncfacdd852015-01-09 19:22:545681
5682 // Second socket: retry using HTTP/1.1.
5683 MockWrite writes1[] = {
rch08e3aa3e2015-05-16 14:27:525684 MockWrite(ASYNC, 0,
bncce36dca22015-04-21 22:11:235685 "CONNECT www.example.org:443 HTTP/1.1\r\n"
rsleevidb16bb02015-11-12 23:47:175686 "Host: www.example.org:443\r\n"
bncfacdd852015-01-09 19:22:545687 "Proxy-Connection: keep-alive\r\n\r\n"),
rch08e3aa3e2015-05-16 14:27:525688 MockWrite(ASYNC, 2,
bncfacdd852015-01-09 19:22:545689 "GET / HTTP/1.1\r\n"
bncce36dca22015-04-21 22:11:235690 "Host: www.example.org\r\n"
bncfacdd852015-01-09 19:22:545691 "Connection: keep-alive\r\n\r\n"),
5692 };
5693
5694 MockRead reads1[] = {
rch08e3aa3e2015-05-16 14:27:525695 MockRead(ASYNC, 1, "HTTP/1.1 200 OK\r\n\r\n"),
5696 MockRead(ASYNC, 3,
bncfacdd852015-01-09 19:22:545697 "HTTP/1.1 200 OK\r\n"
5698 "Content-Length: 5\r\n\r\n"
5699 "hello"),
5700 };
Ryan Sleevib8d7ea02018-05-07 20:01:015701 SequencedSocketData data1(reads1, writes1);
bncfacdd852015-01-09 19:22:545702
Jeremy Roman0579ed62017-08-29 15:56:195703 auto ssl_provider1 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
bncfacdd852015-01-09 19:22:545704 // Expect only HTTP/1.1 protocol in SSLConfig.
Bence Béky27a19b82018-01-30 14:58:365705 ssl_provider1->next_protos_expected_in_ssl_config =
5706 NextProtoVector{kProtoHTTP11};
bncfacdd852015-01-09 19:22:545707 // Force HTTP/1.1.
bnc3cf2a592016-08-11 14:48:365708 ssl_provider1->next_proto = kProtoHTTP11;
dchengc7eeda422015-12-26 03:56:485709 helper.AddDataWithSSLSocketDataProvider(&data1, std::move(ssl_provider1));
bncfacdd852015-01-09 19:22:545710
5711 // A third socket is needed for the tunnelled connection.
Jeremy Roman0579ed62017-08-29 15:56:195712 auto ssl_provider2 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
bncfacdd852015-01-09 19:22:545713 helper.session_deps()->socket_factory->AddSSLSocketDataProvider(
5714 ssl_provider2.get());
5715
bnc525e175a2016-06-20 12:36:405716 HttpServerProperties* http_server_properties =
bncfacdd852015-01-09 19:22:545717 helper.session()->spdy_session_pool()->http_server_properties();
Matt Menkef2ee07c2019-08-29 02:10:365718 url::SchemeHostPort proxy_scheme_host_port(url::kHttpsScheme, "myproxy", 70);
5719 EXPECT_FALSE(http_server_properties->RequiresHTTP11(proxy_scheme_host_port,
5720 NetworkIsolationKey()));
bncfacdd852015-01-09 19:22:545721
5722 helper.RunPreTestSetup();
5723 helper.StartDefaultTest();
5724 helper.FinishDefaultTestWithoutVerification();
5725 helper.VerifyDataConsumed();
Matt Menkef2ee07c2019-08-29 02:10:365726 EXPECT_TRUE(http_server_properties->RequiresHTTP11(proxy_scheme_host_port,
5727 NetworkIsolationKey()));
bncfacdd852015-01-09 19:22:545728
5729 const HttpResponseInfo* response = helper.trans()->GetResponseInfo();
wezca1070932016-05-26 20:30:525730 ASSERT_TRUE(response);
5731 ASSERT_TRUE(response->headers);
bncfacdd852015-01-09 19:22:545732 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
5733 EXPECT_FALSE(response->was_fetched_via_spdy);
mmenke8210acc2016-07-11 16:34:525734 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP1_1,
5735 response->connection_info);
bnc94c92842016-09-21 15:22:525736 EXPECT_FALSE(response->was_alpn_negotiated);
Bence Békydb3cf652017-10-10 15:22:105737 EXPECT_TRUE(request_.url.SchemeIs("https"));
Tsuyoshi Horo01faed62019-02-20 22:11:375738 EXPECT_EQ("127.0.0.1", response->remote_endpoint.ToStringWithoutPort());
5739 EXPECT_EQ(70, response->remote_endpoint.port());
Bence Béky4e83f492018-05-13 23:14:255740 std::string response_data;
robpercival214763f2016-07-01 23:27:015741 ASSERT_THAT(ReadTransaction(helper.trans(), &response_data), IsOk());
bncfacdd852015-01-09 19:22:545742 EXPECT_EQ("hello", response_data);
5743}
5744
Matt Menkef2ee07c2019-08-29 02:10:365745// Same as above, but also test that NetworkIsolationKeys are respected.
5746TEST_F(SpdyNetworkTransactionTest,
5747 HTTP11RequiredProxyRetryWithNetworkIsolationKey) {
Matt Menke4807a9a2020-11-21 00:14:415748 const SchemefulSite kSite1(GURL("https://foo.test/"));
5749 const SchemefulSite kSite2(GURL("https://bar.test/"));
5750 const NetworkIsolationKey kNetworkIsolationKey1(kSite1, kSite1);
5751 const NetworkIsolationKey kNetworkIsolationKey2(kSite2, kSite2);
Matt Menkef2ee07c2019-08-29 02:10:365752
5753 const NetworkIsolationKey kNetworkIsolationKeys[] = {
5754 kNetworkIsolationKey1, kNetworkIsolationKey2, NetworkIsolationKey()};
5755
5756 base::test::ScopedFeatureList feature_list;
5757 feature_list.InitWithFeatures(
5758 // enabled_features
5759 {features::kPartitionHttpServerPropertiesByNetworkIsolationKey,
5760 // Need to partition connections by NetworkIsolationKey for
5761 // SpdySessionKeys to include NetworkIsolationKeys.
5762 features::kPartitionConnectionsByNetworkIsolationKey},
5763 // disabled_features
5764 {});
5765
5766 request_.method = "GET";
5767 auto session_deps = std::make_unique<SpdySessionDependencies>(
Nicolas Arciniegad2013f92020-02-07 23:00:565768 ConfiguredProxyResolutionService::CreateFixedFromPacResult(
Matt Menkef2ee07c2019-08-29 02:10:365769 "HTTPS myproxy:70", TRAFFIC_ANNOTATION_FOR_TESTS));
5770 // Do not force SPDY so that second socket can negotiate HTTP/1.1.
5771 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
5772 std::move(session_deps));
5773 helper.RunPreTestSetup();
5774
5775 for (size_t i = 0; i < base::size(kNetworkIsolationKeys); ++i) {
5776 // First socket: HTTP/2 CONNECT rejected with HTTP_1_1_REQUIRED.
5777
5778 SpdyTestUtil spdy_util;
5779 spdy::SpdySerializedFrame req(spdy_util.ConstructSpdyConnect(
5780 nullptr, 0, 1, HttpProxyConnectJob::kH2QuicTunnelPriority,
5781 HostPortPair("www.example.org", 443)));
5782 MockWrite writes0[] = {CreateMockWrite(req, 0)};
5783 spdy::SpdySerializedFrame rst(spdy_util.ConstructSpdyRstStream(
5784 1, spdy::ERROR_CODE_HTTP_1_1_REQUIRED));
5785 MockRead reads0[] = {CreateMockRead(rst, 1)};
5786 SequencedSocketData data0(reads0, writes0);
5787
5788 auto ssl_provider0 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
5789 // Expect HTTP/2 protocols too in SSLConfig.
5790 ssl_provider0->next_protos_expected_in_ssl_config =
5791 NextProtoVector{kProtoHTTP2, kProtoHTTP11};
5792 // Force SPDY.
5793 ssl_provider0->next_proto = kProtoHTTP2;
5794 helper.AddDataWithSSLSocketDataProvider(&data0, std::move(ssl_provider0));
5795
5796 // Second socket: retry using HTTP/1.1.
5797 MockWrite writes1[] = {
5798 MockWrite(ASYNC, 0,
5799 "CONNECT www.example.org:443 HTTP/1.1\r\n"
5800 "Host: www.example.org:443\r\n"
5801 "Proxy-Connection: keep-alive\r\n\r\n"),
5802 MockWrite(ASYNC, 2,
5803 "GET / HTTP/1.1\r\n"
5804 "Host: www.example.org\r\n"
5805 "Connection: keep-alive\r\n\r\n"),
5806 };
5807
5808 MockRead reads1[] = {
5809 MockRead(ASYNC, 1, "HTTP/1.1 200 OK\r\n\r\n"),
5810 MockRead(ASYNC, 3,
5811 "HTTP/1.1 200 OK\r\n"
5812 "Content-Length: 5\r\n\r\n"
5813 "hello"),
5814 };
5815 SequencedSocketData data1(reads1, writes1);
5816
5817 auto ssl_provider1 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
5818 // Expect only HTTP/1.1 protocol in SSLConfig.
5819 ssl_provider1->next_protos_expected_in_ssl_config =
5820 NextProtoVector{kProtoHTTP11};
5821 // Force HTTP/1.1.
5822 ssl_provider1->next_proto = kProtoHTTP11;
5823 helper.AddDataWithSSLSocketDataProvider(&data1, std::move(ssl_provider1));
5824
5825 // A third socket is needed for the tunnelled connection.
5826 auto ssl_provider2 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
5827 helper.session_deps()->socket_factory->AddSSLSocketDataProvider(
5828 ssl_provider2.get());
5829
5830 HttpServerProperties* http_server_properties =
5831 helper.session()->spdy_session_pool()->http_server_properties();
5832 url::SchemeHostPort proxy_scheme_host_port(url::kHttpsScheme, "myproxy",
5833 70);
5834 EXPECT_FALSE(http_server_properties->RequiresHTTP11(
5835 proxy_scheme_host_port, kNetworkIsolationKeys[i]));
5836
5837 request_.network_isolation_key = kNetworkIsolationKeys[i];
5838 HttpNetworkTransaction trans(DEFAULT_PRIORITY, helper.session());
5839 TestCompletionCallback callback;
5840 int rv = trans.Start(&request_, callback.callback(), log_);
5841 EXPECT_THAT(callback.GetResult(rv), IsOk());
5842 helper.VerifyDataConsumed();
5843
5844 const HttpResponseInfo* response = trans.GetResponseInfo();
5845 ASSERT_TRUE(response);
5846 ASSERT_TRUE(response->headers);
5847 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
5848 EXPECT_FALSE(response->was_fetched_via_spdy);
5849 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP1_1,
5850 response->connection_info);
5851 EXPECT_FALSE(response->was_alpn_negotiated);
5852 EXPECT_TRUE(request_.url.SchemeIs("https"));
5853 EXPECT_EQ("127.0.0.1", response->remote_endpoint.ToStringWithoutPort());
5854 EXPECT_EQ(70, response->remote_endpoint.port());
5855 std::string response_data;
5856 ASSERT_THAT(ReadTransaction(&trans, &response_data), IsOk());
5857 EXPECT_EQ("hello", response_data);
5858
5859 for (size_t j = 0; j < base::size(kNetworkIsolationKeys); ++j) {
5860 // The proxy SchemeHostPort URL should not be marked as requiring HTTP/1.1
5861 // using the current NetworkIsolationKey, and the state of others should
5862 // be unchanged since the last loop iteration..
5863 if (j <= i) {
5864 EXPECT_TRUE(http_server_properties->RequiresHTTP11(
5865 proxy_scheme_host_port, kNetworkIsolationKeys[j]));
5866 } else {
5867 EXPECT_FALSE(http_server_properties->RequiresHTTP11(
5868 proxy_scheme_host_port, kNetworkIsolationKeys[j]));
5869 }
5870 }
5871
5872 // The destination SchemeHostPort should not be marked as requiring
5873 // HTTP/1.1.
5874 EXPECT_FALSE(http_server_properties->RequiresHTTP11(
5875 url::SchemeHostPort(request_.url), kNetworkIsolationKeys[i]));
5876 }
5877}
5878
[email protected]b261d0e2010-08-02 19:13:245879// Test to make sure we can correctly connect through a proxy.
bncd16676a2016-07-20 16:23:015880TEST_F(SpdyNetworkTransactionTest, ProxyConnect) {
Jeremy Roman0579ed62017-08-29 15:56:195881 auto session_deps = std::make_unique<SpdySessionDependencies>(
Nicolas Arciniegad2013f92020-02-07 23:00:565882 ConfiguredProxyResolutionService::CreateFixedFromPacResult(
Ramin Halavatica8d5252018-03-12 05:33:495883 "PROXY myproxy:70", TRAFFIC_ANNOTATION_FOR_TESTS));
Bence Békydb3cf652017-10-10 15:22:105884 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
tfarina428341112016-09-22 13:38:205885 std::move(session_deps));
[email protected]b261d0e2010-08-02 19:13:245886 helper.RunPreTestSetup();
5887 HttpNetworkTransaction* trans = helper.trans();
5888
rchebf12982015-04-10 01:15:005889 const char kConnect443[] = {
bncce36dca22015-04-21 22:11:235890 "CONNECT www.example.org:443 HTTP/1.1\r\n"
rsleevidb16bb02015-11-12 23:47:175891 "Host: www.example.org:443\r\n"
rchcb934f562015-04-07 16:25:125892 "Proxy-Connection: keep-alive\r\n\r\n"};
[email protected]b261d0e2010-08-02 19:13:245893 const char kHTTP200[] = {"HTTP/1.1 200 OK\r\n\r\n"};
Ryan Hamilton0239aac2018-05-19 00:03:135894 spdy::SpdySerializedFrame req(
5895 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
5896 spdy::SpdySerializedFrame resp(
5897 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
5898 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]b261d0e2010-08-02 19:13:245899
rchebf12982015-04-10 01:15:005900 MockWrite writes[] = {
Avi Drissman4365a4782018-12-28 19:26:245901 MockWrite(SYNCHRONOUS, kConnect443, base::size(kConnect443) - 1, 0),
bncdf80d44fd2016-07-15 20:27:415902 CreateMockWrite(req, 2),
[email protected]b261d0e2010-08-02 19:13:245903 };
rchebf12982015-04-10 01:15:005904 MockRead reads[] = {
Avi Drissman4365a4782018-12-28 19:26:245905 MockRead(SYNCHRONOUS, kHTTP200, base::size(kHTTP200) - 1, 1),
5906 CreateMockRead(resp, 3),
5907 CreateMockRead(body, 4),
Raul Tambre94493c652019-03-11 17:18:355908 MockRead(ASYNC, nullptr, 0, 5),
[email protected]b261d0e2010-08-02 19:13:245909 };
Ryan Sleevib8d7ea02018-05-07 20:01:015910 SequencedSocketData data(reads, writes);
[email protected]b261d0e2010-08-02 19:13:245911
Bence Béky53a5aef2018-03-29 21:54:125912 helper.AddData(&data);
[email protected]49639fa2011-12-20 23:22:415913 TestCompletionCallback callback;
[email protected]b261d0e2010-08-02 19:13:245914
Bence Békydb3cf652017-10-10 15:22:105915 int rv = trans->Start(&request_, callback.callback(), log_);
robpercival214763f2016-07-01 23:27:015916 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]b261d0e2010-08-02 19:13:245917
5918 rv = callback.WaitForResult();
5919 EXPECT_EQ(0, rv);
5920
bnc42331402016-07-25 13:36:155921 // Verify the response headers.
[email protected]b261d0e2010-08-02 19:13:245922 HttpResponseInfo response = *trans->GetResponseInfo();
wezca1070932016-05-26 20:30:525923 ASSERT_TRUE(response.headers);
bnc84e7fb52015-12-02 11:50:025924 EXPECT_EQ("HTTP/1.1 200", response.headers->GetStatusLine());
[email protected]b261d0e2010-08-02 19:13:245925
Bence Béky4e83f492018-05-13 23:14:255926 std::string response_data;
robpercival214763f2016-07-01 23:27:015927 ASSERT_THAT(ReadTransaction(trans, &response_data), IsOk());
[email protected]b261d0e2010-08-02 19:13:245928 EXPECT_EQ("hello!", response_data);
5929 helper.VerifyDataConsumed();
5930}
5931
bncce36dca22015-04-21 22:11:235932// Test to make sure we can correctly connect through a proxy to
5933// www.example.org, if there already exists a direct spdy connection to
5934// www.example.org. See https://crbug.com/49874.
bncd16676a2016-07-20 16:23:015935TEST_F(SpdyNetworkTransactionTest, DirectConnectProxyReconnect) {
[email protected]733b7a6d2010-08-25 01:38:435936 // Use a proxy service which returns a proxy fallback list from DIRECT to
5937 // myproxy:70. For this test there will be no fallback, so it is equivalent
5938 // to simply DIRECT. The reason for appending the second proxy is to verify
5939 // that the session pool key used does is just "DIRECT".
Jeremy Roman0579ed62017-08-29 15:56:195940 auto session_deps = std::make_unique<SpdySessionDependencies>(
Nicolas Arciniegad2013f92020-02-07 23:00:565941 ConfiguredProxyResolutionService::CreateFixedFromPacResult(
Ramin Halavatica8d5252018-03-12 05:33:495942 "DIRECT; PROXY myproxy:70", TRAFFIC_ANNOTATION_FOR_TESTS));
bncd16676a2016-07-20 16:23:015943 // When setting up the first transaction, we store the SpdySessionPool so that
5944 // we can use the same pool in the second transaction.
Bence Békydb3cf652017-10-10 15:22:105945 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
tfarina428341112016-09-22 13:38:205946 std::move(session_deps));
[email protected]733b7a6d2010-08-25 01:38:435947
[email protected]87bfa3f2010-09-30 14:54:565948 SpdySessionPool* spdy_session_pool = helper.session()->spdy_session_pool();
[email protected]b261d0e2010-08-02 19:13:245949 helper.RunPreTestSetup();
5950
5951 // Construct and send a simple GET request.
Ryan Hamilton0239aac2018-05-19 00:03:135952 spdy::SpdySerializedFrame req(
5953 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
[email protected]b261d0e2010-08-02 19:13:245954 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:415955 CreateMockWrite(req, 0),
[email protected]b261d0e2010-08-02 19:13:245956 };
5957
Ryan Hamilton0239aac2018-05-19 00:03:135958 spdy::SpdySerializedFrame resp(
5959 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
5960 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]b261d0e2010-08-02 19:13:245961 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:415962 CreateMockRead(resp, 1), CreateMockRead(body, 2),
rch08e3aa3e2015-05-16 14:27:525963 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 3), // Force a pause
[email protected]b261d0e2010-08-02 19:13:245964 };
Ryan Sleevib8d7ea02018-05-07 20:01:015965 SequencedSocketData data(reads, writes);
[email protected]dd54bd82012-07-19 23:44:575966 helper.AddData(&data);
[email protected]b261d0e2010-08-02 19:13:245967 HttpNetworkTransaction* trans = helper.trans();
5968
[email protected]49639fa2011-12-20 23:22:415969 TestCompletionCallback callback;
[email protected]b261d0e2010-08-02 19:13:245970 TransactionHelperResult out;
Bence Békydb3cf652017-10-10 15:22:105971 out.rv = trans->Start(&request_, callback.callback(), log_);
[email protected]b261d0e2010-08-02 19:13:245972
5973 EXPECT_EQ(out.rv, ERR_IO_PENDING);
5974 out.rv = callback.WaitForResult();
5975 EXPECT_EQ(out.rv, OK);
5976
5977 const HttpResponseInfo* response = trans->GetResponseInfo();
wezca1070932016-05-26 20:30:525978 EXPECT_TRUE(response->headers);
[email protected]b261d0e2010-08-02 19:13:245979 EXPECT_TRUE(response->was_fetched_via_spdy);
5980 out.rv = ReadTransaction(trans, &out.response_data);
robpercival214763f2016-07-01 23:27:015981 EXPECT_THAT(out.rv, IsOk());
[email protected]b261d0e2010-08-02 19:13:245982 out.status_line = response->headers->GetStatusLine();
bnc84e7fb52015-12-02 11:50:025983 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]b261d0e2010-08-02 19:13:245984 EXPECT_EQ("hello!", out.response_data);
5985
5986 // Check that the SpdySession is still in the SpdySessionPool.
Matt Menke2436b2f2018-12-11 18:07:115987 SpdySessionKey session_pool_key_direct(
5988 host_port_pair_, ProxyServer::Direct(), PRIVACY_MODE_DISABLED,
dalyk51ab46b2019-10-15 15:14:345989 SpdySessionKey::IsProxySession::kFalse, SocketTag(),
Ben Schwartz3ff4dc1e62021-04-27 21:15:235990 NetworkIsolationKey(), SecureDnsPolicy::kAllow);
[email protected]41d64e82013-07-03 22:44:265991 EXPECT_TRUE(HasSpdySession(spdy_session_pool, session_pool_key_direct));
[email protected]e6d017652013-05-17 18:01:405992 SpdySessionKey session_pool_key_proxy(
bncb26024382016-06-29 02:39:455993 host_port_pair_,
Eric Orth5ccc3f02021-09-23 00:01:575994 ProxyUriToProxyServer("www.foo.com", ProxyServer::SCHEME_HTTP),
Matt Menke2436b2f2018-12-11 18:07:115995 PRIVACY_MODE_DISABLED, SpdySessionKey::IsProxySession::kFalse,
Ben Schwartz3ff4dc1e62021-04-27 21:15:235996 SocketTag(), NetworkIsolationKey(), SecureDnsPolicy::kAllow);
[email protected]41d64e82013-07-03 22:44:265997 EXPECT_FALSE(HasSpdySession(spdy_session_pool, session_pool_key_proxy));
[email protected]b261d0e2010-08-02 19:13:245998
rdsmithebb50aa2015-11-12 03:44:385999 // New SpdyTestUtil instance for the session that will be used for the
6000 // proxy connection.
bncd16676a2016-07-20 16:23:016001 SpdyTestUtil spdy_util_2;
rdsmithebb50aa2015-11-12 03:44:386002
[email protected]b261d0e2010-08-02 19:13:246003 // Set up data for the proxy connection.
bncce36dca22015-04-21 22:11:236004 const char kConnect443[] = {
6005 "CONNECT www.example.org:443 HTTP/1.1\r\n"
rsleevidb16bb02015-11-12 23:47:176006 "Host: www.example.org:443\r\n"
bncce36dca22015-04-21 22:11:236007 "Proxy-Connection: keep-alive\r\n\r\n"};
[email protected]b261d0e2010-08-02 19:13:246008 const char kHTTP200[] = {"HTTP/1.1 200 OK\r\n\r\n"};
Ryan Hamilton0239aac2018-05-19 00:03:136009 spdy::SpdySerializedFrame req2(
6010 spdy_util_2.ConstructSpdyGet(kPushedUrl, 1, LOWEST));
6011 spdy::SpdySerializedFrame resp2(
6012 spdy_util_2.ConstructSpdyGetReply(nullptr, 0, 1));
6013 spdy::SpdySerializedFrame body2(spdy_util_2.ConstructSpdyDataFrame(1, true));
[email protected]b261d0e2010-08-02 19:13:246014
rchebf12982015-04-10 01:15:006015 MockWrite writes2[] = {
Avi Drissman4365a4782018-12-28 19:26:246016 MockWrite(SYNCHRONOUS, kConnect443, base::size(kConnect443) - 1, 0),
bncdf80d44fd2016-07-15 20:27:416017 CreateMockWrite(req2, 2),
[email protected]b261d0e2010-08-02 19:13:246018 };
rchebf12982015-04-10 01:15:006019 MockRead reads2[] = {
Avi Drissman4365a4782018-12-28 19:26:246020 MockRead(SYNCHRONOUS, kHTTP200, base::size(kHTTP200) - 1, 1),
bncdf80d44fd2016-07-15 20:27:416021 CreateMockRead(resp2, 3), CreateMockRead(body2, 4),
rchebf12982015-04-10 01:15:006022 MockRead(ASYNC, 0, 5) // EOF
[email protected]b261d0e2010-08-02 19:13:246023 };
6024
Ryan Sleevib8d7ea02018-05-07 20:01:016025 SequencedSocketData data_proxy(reads2, writes2);
[email protected]b261d0e2010-08-02 19:13:246026
bncce36dca22015-04-21 22:11:236027 // Create another request to www.example.org, but this time through a proxy.
Bence Békydb3cf652017-10-10 15:22:106028 request_.method = "GET";
Bence Békyd2df6c1c82018-04-20 22:52:016029 request_.url = GURL(kPushedUrl);
Jeremy Roman0579ed62017-08-29 15:56:196030 auto session_deps_proxy = std::make_unique<SpdySessionDependencies>(
Nicolas Arciniegad2013f92020-02-07 23:00:566031 ConfiguredProxyResolutionService::CreateFixedFromPacResult(
Ramin Halavatica8d5252018-03-12 05:33:496032 "PROXY myproxy:70", TRAFFIC_ANNOTATION_FOR_TESTS));
Bence Békydb3cf652017-10-10 15:22:106033 NormalSpdyTransactionHelper helper_proxy(request_, DEFAULT_PRIORITY, log_,
6034 std::move(session_deps_proxy));
6035
[email protected]b261d0e2010-08-02 19:13:246036 helper_proxy.RunPreTestSetup();
Bence Béky53a5aef2018-03-29 21:54:126037 helper_proxy.AddData(&data_proxy);
[email protected]b261d0e2010-08-02 19:13:246038
6039 HttpNetworkTransaction* trans_proxy = helper_proxy.trans();
[email protected]49639fa2011-12-20 23:22:416040 TestCompletionCallback callback_proxy;
Bence Békydb3cf652017-10-10 15:22:106041 int rv = trans_proxy->Start(&request_, callback_proxy.callback(), log_);
robpercival214763f2016-07-01 23:27:016042 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]b261d0e2010-08-02 19:13:246043 rv = callback_proxy.WaitForResult();
6044 EXPECT_EQ(0, rv);
6045
6046 HttpResponseInfo response_proxy = *trans_proxy->GetResponseInfo();
wezca1070932016-05-26 20:30:526047 ASSERT_TRUE(response_proxy.headers);
bnc84e7fb52015-12-02 11:50:026048 EXPECT_EQ("HTTP/1.1 200", response_proxy.headers->GetStatusLine());
[email protected]b261d0e2010-08-02 19:13:246049
Bence Béky4e83f492018-05-13 23:14:256050 std::string response_data;
robpercival214763f2016-07-01 23:27:016051 ASSERT_THAT(ReadTransaction(trans_proxy, &response_data), IsOk());
[email protected]b261d0e2010-08-02 19:13:246052 EXPECT_EQ("hello!", response_data);
6053
[email protected]b261d0e2010-08-02 19:13:246054 helper_proxy.VerifyDataConsumed();
6055}
6056
[email protected]58cebf8f2010-07-31 19:20:166057// When we get a TCP-level RST, we need to retry a HttpNetworkTransaction
6058// on a new connection, if the connection was previously known to be good.
6059// This can happen when a server reboots without saying goodbye, or when
6060// we're behind a NAT that masked the RST.
bncd16676a2016-07-20 16:23:016061TEST_F(SpdyNetworkTransactionTest, VerifyRetryOnConnectionReset) {
Ryan Hamilton0239aac2018-05-19 00:03:136062 spdy::SpdySerializedFrame resp(
6063 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
6064 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]58cebf8f2010-07-31 19:20:166065 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:416066 CreateMockRead(resp, 1), CreateMockRead(body, 2),
rch32320842015-05-16 15:57:096067 MockRead(ASYNC, ERR_IO_PENDING, 3),
6068 MockRead(ASYNC, ERR_CONNECTION_RESET, 4),
[email protected]58cebf8f2010-07-31 19:20:166069 };
6070
6071 MockRead reads2[] = {
bncdf80d44fd2016-07-15 20:27:416072 CreateMockRead(resp, 1), CreateMockRead(body, 2),
rch32320842015-05-16 15:57:096073 MockRead(ASYNC, 0, 3) // EOF
[email protected]58cebf8f2010-07-31 19:20:166074 };
6075
Ryan Hamilton0239aac2018-05-19 00:03:136076 spdy::SpdySerializedFrame req(
6077 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
rdsmithebb50aa2015-11-12 03:44:386078 // In all cases the connection will be reset before req3 can be
6079 // dispatched, destroying both streams.
6080 spdy_util_.UpdateWithStreamDestruction(1);
Ryan Hamilton0239aac2018-05-19 00:03:136081 spdy::SpdySerializedFrame req3(
6082 spdy_util_.ConstructSpdyGet(nullptr, 0, 3, LOWEST));
bncdf80d44fd2016-07-15 20:27:416083 MockWrite writes1[] = {CreateMockWrite(req, 0), CreateMockWrite(req3, 5)};
6084 MockWrite writes2[] = {CreateMockWrite(req, 0)};
rchacdcbdc2015-05-16 17:16:006085
[email protected]58cebf8f2010-07-31 19:20:166086 // This test has a couple of variants.
6087 enum {
6088 // Induce the RST while waiting for our transaction to send.
rchacdcbdc2015-05-16 17:16:006089 VARIANT_RST_DURING_SEND_COMPLETION = 0,
[email protected]58cebf8f2010-07-31 19:20:166090 // Induce the RST while waiting for our transaction to read.
6091 // In this case, the send completed - everything copied into the SNDBUF.
rchacdcbdc2015-05-16 17:16:006092 VARIANT_RST_DURING_READ_COMPLETION = 1
[email protected]58cebf8f2010-07-31 19:20:166093 };
6094
6095 for (int variant = VARIANT_RST_DURING_SEND_COMPLETION;
6096 variant <= VARIANT_RST_DURING_READ_COMPLETION;
6097 ++variant) {
Ryan Sleevib8d7ea02018-05-07 20:01:016098 SequencedSocketData data1(reads,
6099 base::make_span(writes1).first(1 + variant));
[email protected]58cebf8f2010-07-31 19:20:166100
Ryan Sleevib8d7ea02018-05-07 20:01:016101 SequencedSocketData data2(reads2, writes2);
[email protected]58cebf8f2010-07-31 19:20:166102
Bence Békydb3cf652017-10-10 15:22:106103 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
6104 nullptr);
[email protected]dd54bd82012-07-19 23:44:576105 helper.AddData(&data1);
6106 helper.AddData(&data2);
[email protected]58cebf8f2010-07-31 19:20:166107 helper.RunPreTestSetup();
6108
6109 for (int i = 0; i < 2; ++i) {
bnc691fda62016-08-12 00:43:166110 HttpNetworkTransaction trans(DEFAULT_PRIORITY, helper.session());
[email protected]58cebf8f2010-07-31 19:20:166111
[email protected]49639fa2011-12-20 23:22:416112 TestCompletionCallback callback;
Bence Békydb3cf652017-10-10 15:22:106113 int rv = trans.Start(&request_, callback.callback(), log_);
robpercival214763f2016-07-01 23:27:016114 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]58cebf8f2010-07-31 19:20:166115 // On the second transaction, we trigger the RST.
6116 if (i == 1) {
6117 if (variant == VARIANT_RST_DURING_READ_COMPLETION) {
6118 // Writes to the socket complete asynchronously on SPDY by running
6119 // through the message loop. Complete the write here.
[email protected]fc9d88472013-08-14 02:31:176120 base::RunLoop().RunUntilIdle();
[email protected]58cebf8f2010-07-31 19:20:166121 }
6122
6123 // Now schedule the ERR_CONNECTION_RESET.
mmenkee24011922015-12-17 22:12:596124 data1.Resume();
[email protected]58cebf8f2010-07-31 19:20:166125 }
6126 rv = callback.WaitForResult();
robpercival214763f2016-07-01 23:27:016127 EXPECT_THAT(rv, IsOk());
[email protected]58cebf8f2010-07-31 19:20:166128
bnc691fda62016-08-12 00:43:166129 const HttpResponseInfo* response = trans.GetResponseInfo();
wezca1070932016-05-26 20:30:526130 ASSERT_TRUE(response);
6131 EXPECT_TRUE(response->headers);
[email protected]58cebf8f2010-07-31 19:20:166132 EXPECT_TRUE(response->was_fetched_via_spdy);
Bence Béky4e83f492018-05-13 23:14:256133 std::string response_data;
bnc691fda62016-08-12 00:43:166134 rv = ReadTransaction(&trans, &response_data);
robpercival214763f2016-07-01 23:27:016135 EXPECT_THAT(rv, IsOk());
bnc84e7fb52015-12-02 11:50:026136 EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
[email protected]58cebf8f2010-07-31 19:20:166137 EXPECT_EQ("hello!", response_data);
rchacdcbdc2015-05-16 17:16:006138 base::RunLoop().RunUntilIdle();
[email protected]58cebf8f2010-07-31 19:20:166139 }
6140
6141 helper.VerifyDataConsumed();
rchacdcbdc2015-05-16 17:16:006142 base::RunLoop().RunUntilIdle();
[email protected]58cebf8f2010-07-31 19:20:166143 }
6144}
[email protected]1f418ee2010-10-16 19:46:566145
[email protected]018aabc2010-10-29 16:16:596146// Tests that Basic authentication works over SPDY
bncd16676a2016-07-20 16:23:016147TEST_F(SpdyNetworkTransactionTest, SpdyBasicAuth) {
[email protected]018aabc2010-10-29 16:16:596148 // The first request will be a bare GET, the second request will be a
6149 // GET with an Authorization header.
Ryan Hamilton0239aac2018-05-19 00:03:136150 spdy::SpdySerializedFrame req_get(
Bence Béky27ad0a12018-02-08 00:35:486151 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
rdsmithebb50aa2015-11-12 03:44:386152 // Will be refused for lack of auth.
6153 spdy_util_.UpdateWithStreamDestruction(1);
[email protected]018aabc2010-10-29 16:16:596154 const char* const kExtraAuthorizationHeaders[] = {
[email protected]cdf8f7e72013-05-23 10:56:466155 "authorization", "Basic Zm9vOmJhcg=="
[email protected]018aabc2010-10-29 16:16:596156 };
Ryan Hamilton0239aac2018-05-19 00:03:136157 spdy::SpdySerializedFrame req_get_authorization(spdy_util_.ConstructSpdyGet(
Avi Drissman4365a4782018-12-28 19:26:246158 kExtraAuthorizationHeaders, base::size(kExtraAuthorizationHeaders) / 2, 3,
Bence Béky27ad0a12018-02-08 00:35:486159 LOWEST));
[email protected]018aabc2010-10-29 16:16:596160 MockWrite spdy_writes[] = {
bncdf80d44fd2016-07-15 20:27:416161 CreateMockWrite(req_get, 0), CreateMockWrite(req_get_authorization, 3),
[email protected]018aabc2010-10-29 16:16:596162 };
6163
6164 // The first response is a 401 authentication challenge, and the second
6165 // response will be a 200 response since the second request includes a valid
6166 // Authorization header.
6167 const char* const kExtraAuthenticationHeaders[] = {
[email protected]fb9e4312012-02-17 06:27:266168 "www-authenticate",
[email protected]018aabc2010-10-29 16:16:596169 "Basic realm=\"MyRealm\""
6170 };
Ryan Hamilton0239aac2018-05-19 00:03:136171 spdy::SpdySerializedFrame resp_authentication(
6172 spdy_util_.ConstructSpdyReplyError(
6173 "401", kExtraAuthenticationHeaders,
Avi Drissman4365a4782018-12-28 19:26:246174 base::size(kExtraAuthenticationHeaders) / 2, 1));
Ryan Hamilton0239aac2018-05-19 00:03:136175 spdy::SpdySerializedFrame body_authentication(
bncdf80d44fd2016-07-15 20:27:416176 spdy_util_.ConstructSpdyDataFrame(1, true));
Ryan Hamilton0239aac2018-05-19 00:03:136177 spdy::SpdySerializedFrame resp_data(
tombergan5d22c182017-01-11 02:05:356178 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
Ryan Hamilton0239aac2018-05-19 00:03:136179 spdy::SpdySerializedFrame body_data(
6180 spdy_util_.ConstructSpdyDataFrame(3, true));
tombergan5d22c182017-01-11 02:05:356181
[email protected]018aabc2010-10-29 16:16:596182 MockRead spdy_reads[] = {
bncdf80d44fd2016-07-15 20:27:416183 CreateMockRead(resp_authentication, 1),
bnceb9aa7112017-01-05 01:03:466184 CreateMockRead(body_authentication, 2, SYNCHRONOUS),
bncdf80d44fd2016-07-15 20:27:416185 CreateMockRead(resp_data, 4),
6186 CreateMockRead(body_data, 5),
rch08e3aa3e2015-05-16 14:27:526187 MockRead(ASYNC, 0, 6),
[email protected]018aabc2010-10-29 16:16:596188 };
6189
Ryan Sleevib8d7ea02018-05-07 20:01:016190 SequencedSocketData data(spdy_reads, spdy_writes);
Bence Békydb3cf652017-10-10 15:22:106191 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]018aabc2010-10-29 16:16:596192
6193 helper.RunPreTestSetup();
[email protected]dd54bd82012-07-19 23:44:576194 helper.AddData(&data);
bnc4d782f492016-08-18 13:50:006195 helper.StartDefaultTest();
6196 EXPECT_THAT(helper.output().rv, IsError(ERR_IO_PENDING));
6197
6198 helper.WaitForCallbackToComplete();
6199 EXPECT_THAT(helper.output().rv, IsOk());
[email protected]018aabc2010-10-29 16:16:596200
6201 // Make sure the response has an auth challenge.
bnc4d782f492016-08-18 13:50:006202 HttpNetworkTransaction* trans = helper.trans();
[email protected]018aabc2010-10-29 16:16:596203 const HttpResponseInfo* const response_start = trans->GetResponseInfo();
wezca1070932016-05-26 20:30:526204 ASSERT_TRUE(response_start);
6205 ASSERT_TRUE(response_start->headers);
[email protected]018aabc2010-10-29 16:16:596206 EXPECT_EQ(401, response_start->headers->response_code());
6207 EXPECT_TRUE(response_start->was_fetched_via_spdy);
Anton Bikineev068d2912021-05-15 20:43:526208 const absl::optional<AuthChallengeInfo>& auth_challenge =
Emily Starkf2c9bbd2019-04-09 17:08:586209 response_start->auth_challenge;
wezca1070932016-05-26 20:30:526210 ASSERT_TRUE(auth_challenge);
[email protected]79cb5c12011-09-12 13:12:046211 EXPECT_FALSE(auth_challenge->is_proxy);
aberentbba302d2015-12-03 10:20:196212 EXPECT_EQ(kBasicAuthScheme, auth_challenge->scheme);
[email protected]79cb5c12011-09-12 13:12:046213 EXPECT_EQ("MyRealm", auth_challenge->realm);
[email protected]018aabc2010-10-29 16:16:596214
6215 // Restart with a username/password.
Jan Wilken Dörriec92a6d7242021-03-23 17:43:486216 AuthCredentials credentials(u"foo", u"bar");
[email protected]49639fa2011-12-20 23:22:416217 TestCompletionCallback callback_restart;
6218 const int rv_restart = trans->RestartWithAuth(
6219 credentials, callback_restart.callback());
robpercival214763f2016-07-01 23:27:016220 EXPECT_THAT(rv_restart, IsError(ERR_IO_PENDING));
[email protected]018aabc2010-10-29 16:16:596221 const int rv_restart_complete = callback_restart.WaitForResult();
robpercival214763f2016-07-01 23:27:016222 EXPECT_THAT(rv_restart_complete, IsOk());
[email protected]018aabc2010-10-29 16:16:596223 // TODO(cbentzel): This is actually the same response object as before, but
6224 // data has changed.
6225 const HttpResponseInfo* const response_restart = trans->GetResponseInfo();
wezca1070932016-05-26 20:30:526226 ASSERT_TRUE(response_restart);
6227 ASSERT_TRUE(response_restart->headers);
[email protected]018aabc2010-10-29 16:16:596228 EXPECT_EQ(200, response_restart->headers->response_code());
Emily Starkf2c9bbd2019-04-09 17:08:586229 EXPECT_FALSE(response_restart->auth_challenge);
[email protected]018aabc2010-10-29 16:16:596230}
6231
Bence Békye7023f82018-05-14 01:53:036232struct PushHeaderTestParams {
Victor Vasiliev502ba582020-09-15 23:16:156233 std::vector<std::pair<std::string, std::string>> extra_request_headers;
6234 std::vector<std::pair<std::string, std::string>> extra_pushed_request_headers;
6235 std::vector<std::pair<std::string, std::string>>
Bence Béky49db0e22018-05-11 00:54:056236 extra_pushed_response_headers;
Victor Vasiliev502ba582020-09-15 23:16:156237 std::string pushed_status_code;
Bence Béky49db0e22018-05-11 00:54:056238 bool push_accepted;
Bence Békyeacd48f2018-05-14 11:34:336239 SpdyPushedStreamFate expected_fate;
Bence Békye7023f82018-05-14 01:53:036240} push_header_test_cases[] = {
Bence Béky49db0e22018-05-11 00:54:056241 // Base case: no extra headers.
Bence Békyeacd48f2018-05-14 11:34:336242 {{}, {}, {}, "200", true, SpdyPushedStreamFate::kAcceptedNoVary},
Bence Béky49db0e22018-05-11 00:54:056243 // Cookie headers match.
6244 {{{"cookie", "value=foo"}},
6245 {{"cookie", "value=foo"}},
6246 {{"vary", "Cookie"}},
6247 "200",
Bence Békyeacd48f2018-05-14 11:34:336248 true,
6249 SpdyPushedStreamFate::kAcceptedMatchingVary},
Bence Béky49db0e22018-05-11 00:54:056250 // Cookie headers mismatch.
6251 {{{"cookie", "value=foo"}},
6252 {{"cookie", "value=bar"}},
6253 {{"vary", "Cookie"}},
6254 "200",
Bence Békyeacd48f2018-05-14 11:34:336255 false,
6256 SpdyPushedStreamFate::kVaryMismatch},
Bence Béky49db0e22018-05-11 00:54:056257 // Partial Content response, no Range headers.
Bence Békyeacd48f2018-05-14 11:34:336258 {{}, {}, {}, "206", false, SpdyPushedStreamFate::kClientRequestNotRange},
Bence Béky49db0e22018-05-11 00:54:056259 // Partial Content response, no Range headers in pushed request.
Bence Békyeacd48f2018-05-14 11:34:336260 {{{"range", "0-42"}},
6261 {},
6262 {},
6263 "206",
6264 false,
6265 SpdyPushedStreamFate::kPushedRequestNotRange},
Bence Béky49db0e22018-05-11 00:54:056266 // Partial Content response, no Range headers in client request.
Bence Békyeacd48f2018-05-14 11:34:336267 {{},
6268 {{"range", "0-42"}},
6269 {},
6270 "206",
6271 false,
6272 SpdyPushedStreamFate::kClientRequestNotRange},
Bence Béky49db0e22018-05-11 00:54:056273 // Partial Content response, mismatching Range headers.
Bence Békyeacd48f2018-05-14 11:34:336274 {{{"range", "0-42"}},
6275 {{"range", "10-42"}},
6276 {},
6277 "206",
6278 false,
6279 SpdyPushedStreamFate::kRangeMismatch},
Bence Béky49db0e22018-05-11 00:54:056280 // Partial Content response, matching Range headers.
Bence Békyeacd48f2018-05-14 11:34:336281 {{{"range", "0-42"}},
6282 {{"range", "0-42"}},
6283 {},
6284 "206",
6285 true,
6286 SpdyPushedStreamFate::kAcceptedNoVary},
6287};
[email protected]d08358502010-12-03 22:04:036288
Bence Békye7023f82018-05-14 01:53:036289class SpdyNetworkTransactionPushHeaderTest
Bence Béky49db0e22018-05-11 00:54:056290 : public SpdyNetworkTransactionTest,
Bence Békye7023f82018-05-14 01:53:036291 public ::testing::WithParamInterface<PushHeaderTestParams> {
Bence Béky49db0e22018-05-11 00:54:056292 protected:
6293 void RunTest(bool pushed_response_headers_received_before_request) {
Bence Békyeacd48f2018-05-14 11:34:336294 base::HistogramTester histogram_tester;
6295
Bence Békyc4caf072018-04-20 22:27:306296 int seq = 0;
6297 std::vector<MockWrite> writes;
6298 std::vector<MockRead> reads;
bnc38dcd392016-02-09 23:19:496299
Ryan Hamilton0239aac2018-05-19 00:03:136300 spdy::SpdySerializedFrame req1(
Bence Béky49db0e22018-05-11 00:54:056301 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
Bence Békyc4caf072018-04-20 22:27:306302 writes.push_back(CreateMockWrite(req1, seq++));
[email protected]513963e2013-06-15 01:53:046303
Bence Béky4c325e52020-10-22 20:48:016304 spdy::Http2HeaderBlock pushed_request_headers;
Ryan Hamilton0239aac2018-05-19 00:03:136305 pushed_request_headers[spdy::kHttp2MethodHeader] = "GET";
Bence Béky49db0e22018-05-11 00:54:056306 for (const auto& header : GetParam().extra_pushed_request_headers) {
Bence Békyc4caf072018-04-20 22:27:306307 pushed_request_headers.insert(header);
6308 }
Bence Béky49db0e22018-05-11 00:54:056309 spdy_util_.AddUrlToHeaderBlock(kPushedUrl, &pushed_request_headers);
Ryan Hamilton0239aac2018-05-19 00:03:136310 spdy::SpdySerializedFrame pushed_request(
6311 spdy_util_.ConstructSpdyPushPromise(1, 2,
6312 std::move(pushed_request_headers)));
Bence Békyc4caf072018-04-20 22:27:306313 reads.push_back(CreateMockRead(pushed_request, seq++));
[email protected]d08358502010-12-03 22:04:036314
Ryan Hamilton0239aac2018-05-19 00:03:136315 spdy::SpdySerializedFrame priority(
Bence Béky49db0e22018-05-11 00:54:056316 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true));
Bence Békyc4caf072018-04-20 22:27:306317 writes.push_back(CreateMockWrite(priority, seq++));
bnc38dcd392016-02-09 23:19:496318
Bence Béky49db0e22018-05-11 00:54:056319 reads.push_back(MockRead(ASYNC, ERR_IO_PENDING, seq++));
6320
Bence Béky4c325e52020-10-22 20:48:016321 spdy::Http2HeaderBlock pushed_response_headers;
Ryan Hamilton0239aac2018-05-19 00:03:136322 pushed_response_headers[spdy::kHttp2StatusHeader] =
6323 GetParam().pushed_status_code;
Bence Béky49db0e22018-05-11 00:54:056324 for (const auto& header : GetParam().extra_pushed_response_headers) {
Bence Békyc4caf072018-04-20 22:27:306325 pushed_response_headers.insert(header);
6326 }
Ryan Hamilton0239aac2018-05-19 00:03:136327 spdy::SpdySerializedFrame pushed_response(
Bence Béky49db0e22018-05-11 00:54:056328 spdy_util_.ConstructSpdyReply(2, std::move(pushed_response_headers)));
Bence Békyc4caf072018-04-20 22:27:306329 reads.push_back(CreateMockRead(pushed_response, seq++));
bnc38dcd392016-02-09 23:19:496330
Ryan Hamilton0239aac2018-05-19 00:03:136331 spdy::SpdySerializedFrame resp1(
6332 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
Bence Békyc4caf072018-04-20 22:27:306333 reads.push_back(CreateMockRead(resp1, seq++));
[email protected]d08358502010-12-03 22:04:036334
Ryan Hamilton0239aac2018-05-19 00:03:136335 spdy::SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true));
Bence Békyc4caf072018-04-20 22:27:306336 reads.push_back(CreateMockRead(body1, seq++));
Bence Béky49db0e22018-05-11 00:54:056337 spdy_util_.UpdateWithStreamDestruction(1);
[email protected]d08358502010-12-03 22:04:036338
Ryan Hamilton0239aac2018-05-19 00:03:136339 spdy::SpdySerializedFrame pushed_body(
Bence Béky49db0e22018-05-11 00:54:056340 spdy_util_.ConstructSpdyDataFrame(2, "This is pushed.", true));
Bence Békyc4caf072018-04-20 22:27:306341 reads.push_back(CreateMockRead(pushed_body, seq++));
[email protected]d08358502010-12-03 22:04:036342
Bence Békyc4caf072018-04-20 22:27:306343 // If push is not accepted, a new request is sent on the wire.
Ryan Hamilton0239aac2018-05-19 00:03:136344 spdy::SpdySerializedFrame rst;
6345 spdy::SpdySerializedFrame req2;
6346 spdy::SpdySerializedFrame resp2;
6347 spdy::SpdySerializedFrame body2;
Bence Béky49db0e22018-05-11 00:54:056348 if (!GetParam().push_accepted) {
Ryan Hamilton0239aac2018-05-19 00:03:136349 rst = spdy_util_.ConstructSpdyRstStream(2, spdy::ERROR_CODE_CANCEL);
Bence Béky49db0e22018-05-11 00:54:056350 writes.push_back(CreateMockWrite(rst, seq++));
6351
Bence Béky4c325e52020-10-22 20:48:016352 spdy::Http2HeaderBlock request_headers2(
Bence Béky49db0e22018-05-11 00:54:056353 spdy_util_.ConstructGetHeaderBlock(kPushedUrl));
6354 for (const auto& header : GetParam().extra_request_headers) {
Bence Békyc4caf072018-04-20 22:27:306355 request_headers2.insert(header);
6356 }
Bence Béky49db0e22018-05-11 00:54:056357 req2 = spdy_util_.ConstructSpdyHeaders(3, std::move(request_headers2),
6358 LOWEST, true);
Bence Békyc4caf072018-04-20 22:27:306359 writes.push_back(CreateMockWrite(req2, seq++));
[email protected]d08358502010-12-03 22:04:036360
Bence Béky49db0e22018-05-11 00:54:056361 resp2 = spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3);
Bence Békyc4caf072018-04-20 22:27:306362 reads.push_back(CreateMockRead(resp2, seq++));
Bence Béky04268b022018-04-19 01:17:416363
Bence Béky49db0e22018-05-11 00:54:056364 body2 = spdy_util_.ConstructSpdyDataFrame(3, "This is not pushed.", true);
Bence Békyc4caf072018-04-20 22:27:306365 reads.push_back(CreateMockRead(body2, seq++));
6366 }
Bence Béky04268b022018-04-19 01:17:416367
Bence Békyc4caf072018-04-20 22:27:306368 reads.push_back(MockRead(ASYNC, ERR_IO_PENDING, seq++));
Bence Béky04268b022018-04-19 01:17:416369
Bence Békyc4caf072018-04-20 22:27:306370 reads.push_back(MockRead(ASYNC, 0, seq++));
Bence Béky04268b022018-04-19 01:17:416371
Ryan Sleevib8d7ea02018-05-07 20:01:016372 SequencedSocketData data(reads, writes);
Bence Béky04268b022018-04-19 01:17:416373
Bence Békyc4caf072018-04-20 22:27:306374 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
6375 nullptr);
6376 helper.RunPreTestSetup();
6377 helper.AddData(&data);
Bence Béky04268b022018-04-19 01:17:416378
Bence Békyc4caf072018-04-20 22:27:306379 HttpNetworkTransaction* trans = helper.trans();
6380 TestCompletionCallback callback1;
6381 int rv = trans->Start(&request_, callback1.callback(), log_);
6382 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
Bence Béky49db0e22018-05-11 00:54:056383
6384 // Open connection.
6385 base::RunLoop().RunUntilIdle();
6386
6387 if (pushed_response_headers_received_before_request) {
6388 // Read pushed response headers.
6389 data.Resume();
6390 base::RunLoop().RunUntilIdle();
6391 }
6392
6393 HttpRequestInfo request2 = CreateGetPushRequest();
6394 for (const auto& header : GetParam().extra_request_headers) {
6395 request2.extra_headers.SetHeader(header.first, header.second);
6396 }
6397 HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session());
6398 TestCompletionCallback callback2;
6399 rv = trans2.Start(&request2, callback2.callback(), log_);
6400 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
6401 base::RunLoop().RunUntilIdle();
6402
6403 if (!pushed_response_headers_received_before_request) {
6404 // Read pushed response headers.
6405 data.Resume();
6406 base::RunLoop().RunUntilIdle();
6407 }
6408
Bence Békyc4caf072018-04-20 22:27:306409 rv = callback1.WaitForResult();
6410 EXPECT_THAT(rv, IsOk());
Bence Béky04268b022018-04-19 01:17:416411
Bence Békyc4caf072018-04-20 22:27:306412 const HttpResponseInfo* const response1 = trans->GetResponseInfo();
6413 EXPECT_TRUE(response1->headers);
6414 EXPECT_EQ("HTTP/1.1 200", response1->headers->GetStatusLine());
Bence Béky04268b022018-04-19 01:17:416415
Bence Béky4e83f492018-05-13 23:14:256416 std::string result1;
Bence Békyc4caf072018-04-20 22:27:306417 ReadResult(trans, &result1);
6418 EXPECT_EQ(result1, "hello!");
Bence Béky04268b022018-04-19 01:17:416419
Bence Békyc4caf072018-04-20 22:27:306420 rv = callback2.WaitForResult();
6421 EXPECT_THAT(rv, IsOk());
Bence Béky04268b022018-04-19 01:17:416422
Bence Béky4e83f492018-05-13 23:14:256423 std::string result2;
Bence Békyc4caf072018-04-20 22:27:306424 ReadResult(&trans2, &result2);
Bence Béky49db0e22018-05-11 00:54:056425 EXPECT_EQ(result2, GetParam().push_accepted ? "This is pushed."
6426 : "This is not pushed.");
Bence Béky04268b022018-04-19 01:17:416427
Bence Békyc4caf072018-04-20 22:27:306428 data.Resume();
6429 base::RunLoop().RunUntilIdle();
6430 helper.VerifyDataConsumed();
Bence Békyeacd48f2018-05-14 11:34:336431
6432 histogram_tester.ExpectBucketCount(
6433 "Net.SpdyPushedStreamFate", static_cast<int>(GetParam().expected_fate),
6434 1);
6435 histogram_tester.ExpectTotalCount("Net.SpdyPushedStreamFate", 1);
Bence Békyc4caf072018-04-20 22:27:306436 }
Bence Béky49db0e22018-05-11 00:54:056437};
6438
Ilia Samsonov958c9fef2019-11-20 21:37:316439INSTANTIATE_TEST_SUITE_P(All,
Victor Costan2309ea02019-02-13 21:35:476440 SpdyNetworkTransactionPushHeaderTest,
6441 ::testing::ValuesIn(push_header_test_cases));
Bence Béky49db0e22018-05-11 00:54:056442
Bence Békye7023f82018-05-14 01:53:036443TEST_P(SpdyNetworkTransactionPushHeaderTest,
Bence Béky49db0e22018-05-11 00:54:056444 PushedResponseHeadersReceivedBeforeRequest) {
6445 RunTest(/* pushed_response_headers_received_before_request = */ true);
Bence Béky04268b022018-04-19 01:17:416446}
6447
Bence Békye7023f82018-05-14 01:53:036448TEST_P(SpdyNetworkTransactionPushHeaderTest,
Bence Béky49db0e22018-05-11 00:54:056449 PushedResponseHeadersReceivedAfterRequest) {
6450 RunTest(/* pushed_response_headers_received_before_request = */ false);
[email protected]d08358502010-12-03 22:04:036451}
6452
bnc42331402016-07-25 13:36:156453TEST_F(SpdyNetworkTransactionTest, ResponseHeadersTwice) {
Ryan Hamilton0239aac2018-05-19 00:03:136454 spdy::SpdySerializedFrame req(
6455 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
6456 spdy::SpdySerializedFrame rst(
6457 spdy_util_.ConstructSpdyRstStream(1, spdy::ERROR_CODE_PROTOCOL_ERROR));
[email protected]b771bb72013-06-24 09:55:416458 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:416459 CreateMockWrite(req, 0), CreateMockWrite(rst, 4),
[email protected]745aa9c2014-06-27 02:21:296460 };
[email protected]d08358502010-12-03 22:04:036461
Ryan Hamilton0239aac2018-05-19 00:03:136462 spdy::SpdySerializedFrame stream1_reply(
tombergan5d22c182017-01-11 02:05:356463 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
[email protected]513963e2013-06-15 01:53:046464
Bence Béky4c325e52020-10-22 20:48:016465 spdy::Http2HeaderBlock late_headers;
bnc38dcd392016-02-09 23:19:496466 late_headers["hello"] = "bye";
Ryan Hamilton0239aac2018-05-19 00:03:136467 spdy::SpdySerializedFrame stream1_headers(
6468 spdy_util_.ConstructSpdyResponseHeaders(1, std::move(late_headers),
6469 false));
6470 spdy::SpdySerializedFrame stream1_body(
6471 spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]d08358502010-12-03 22:04:036472 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:416473 CreateMockRead(stream1_reply, 1), CreateMockRead(stream1_headers, 2),
6474 CreateMockRead(stream1_body, 3), MockRead(ASYNC, 0, 5) // EOF
[email protected]d08358502010-12-03 22:04:036475 };
6476
Ryan Sleevib8d7ea02018-05-07 20:01:016477 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:106478 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]dd54bd82012-07-19 23:44:576479 helper.RunToCompletion(&data);
[email protected]d08358502010-12-03 22:04:036480 TransactionHelperResult out = helper.output();
Bence Békyd0d69502019-06-25 19:47:186481 EXPECT_THAT(out.rv, IsError(ERR_HTTP2_PROTOCOL_ERROR));
[email protected]d08358502010-12-03 22:04:036482}
6483
xunjieli294da722015-08-11 19:15:026484// Tests that receiving HEADERS, DATA, HEADERS, and DATA in that sequence will
Bence Békyd0d69502019-06-25 19:47:186485// trigger a ERR_HTTP2_PROTOCOL_ERROR because trailing HEADERS must not be
xunjieli294da722015-08-11 19:15:026486// followed by any DATA frames.
bncd16676a2016-07-20 16:23:016487TEST_F(SpdyNetworkTransactionTest, SyncReplyDataAfterTrailers) {
Ryan Hamilton0239aac2018-05-19 00:03:136488 spdy::SpdySerializedFrame req(
6489 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
6490 spdy::SpdySerializedFrame rst(
6491 spdy_util_.ConstructSpdyRstStream(1, spdy::ERROR_CODE_PROTOCOL_ERROR));
[email protected]b771bb72013-06-24 09:55:416492 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:416493 CreateMockWrite(req, 0), CreateMockWrite(rst, 5),
[email protected]b771bb72013-06-24 09:55:416494 };
[email protected]d08358502010-12-03 22:04:036495
Ryan Hamilton0239aac2018-05-19 00:03:136496 spdy::SpdySerializedFrame stream1_reply(
tombergan5d22c182017-01-11 02:05:356497 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
Ryan Hamilton0239aac2018-05-19 00:03:136498 spdy::SpdySerializedFrame stream1_body(
6499 spdy_util_.ConstructSpdyDataFrame(1, false));
bnc38dcd392016-02-09 23:19:496500
Bence Béky4c325e52020-10-22 20:48:016501 spdy::Http2HeaderBlock late_headers;
bnc38dcd392016-02-09 23:19:496502 late_headers["hello"] = "bye";
Ryan Hamilton0239aac2018-05-19 00:03:136503 spdy::SpdySerializedFrame stream1_headers(
6504 spdy_util_.ConstructSpdyResponseHeaders(1, std::move(late_headers),
6505 false));
6506 spdy::SpdySerializedFrame stream1_body2(
6507 spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]d08358502010-12-03 22:04:036508 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:416509 CreateMockRead(stream1_reply, 1), CreateMockRead(stream1_body, 2),
6510 CreateMockRead(stream1_headers, 3), CreateMockRead(stream1_body2, 4),
rch08e3aa3e2015-05-16 14:27:526511 MockRead(ASYNC, 0, 6) // EOF
[email protected]d08358502010-12-03 22:04:036512 };
6513
Ryan Sleevib8d7ea02018-05-07 20:01:016514 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:106515 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]dd54bd82012-07-19 23:44:576516 helper.RunToCompletion(&data);
[email protected]d08358502010-12-03 22:04:036517 TransactionHelperResult out = helper.output();
Bence Békyd0d69502019-06-25 19:47:186518 EXPECT_THAT(out.rv, IsError(ERR_HTTP2_PROTOCOL_ERROR));
[email protected]d08358502010-12-03 22:04:036519}
6520
Bence Békye7023f82018-05-14 01:53:036521struct PushUrlTestParams {
6522 const char* url_to_fetch;
6523 const char* url_to_push;
Bence Békyb2f76672018-06-11 21:10:136524 bool client_cert_sent;
Matt Menkec74a9262020-06-09 15:49:216525 bool expect_ct_error;
Bence Békyeacd48f2018-05-14 11:34:336526 SpdyPushedStreamFate expected_fate;
Bence Békye7023f82018-05-14 01:53:036527} push_url_test_cases[] = {
6528 // http scheme cannot be pushed (except by trusted proxy).
Matt Menkec74a9262020-06-09 15:49:216529 {"https://www.example.org/foo.html", "http://www.example.org/foo.js",
6530 false /* client_cert_sent */, false /* expect_ct_error */,
Bence Békyeacd48f2018-05-14 11:34:336531 SpdyPushedStreamFate::kNonHttpsPushedScheme},
Bence Békye7023f82018-05-14 01:53:036532 // ftp scheme cannot be pushed.
Matt Menkec74a9262020-06-09 15:49:216533 {"https://www.example.org/foo.html", "ftp://www.example.org/foo.js",
6534 false /* client_cert_sent */, false /* expect_ct_error */,
Bence Békyeacd48f2018-05-14 11:34:336535 SpdyPushedStreamFate::kInvalidUrl},
Bence Békye7023f82018-05-14 01:53:036536 // Cross subdomain, certificate not valid.
Bence Békyeacd48f2018-05-14 11:34:336537 {"https://www.example.org/foo.html", "https://blat.www.example.org/foo.js",
Matt Menkec74a9262020-06-09 15:49:216538 false /* client_cert_sent */, false /* expect_ct_error */,
6539 SpdyPushedStreamFate::kCertificateMismatch},
Bence Békye7023f82018-05-14 01:53:036540 // Cross domain, certificate not valid.
Matt Menkec74a9262020-06-09 15:49:216541 {"https://www.example.org/foo.html", "https://www.foo.com/foo.js",
6542 false /* client_cert_sent */, false /* expect_ct_error */,
Bence Békyb2f76672018-06-11 21:10:136543 SpdyPushedStreamFate::kCertificateMismatch},
6544 // Cross domain, certificate valid, but cross-origin push is rejected on a
6545 // connection with client certificate.
6546 {"https://www.example.org/foo.html", "https://mail.example.org/foo.js",
Matt Menkec74a9262020-06-09 15:49:216547 true /* client_cert_sent */, false /* expect_ct_error */,
6548 SpdyPushedStreamFate::kCertificateMismatch},
6549 // Cross domain, certificate valid, but cross-origin push is rejected on a
6550 // connection with an Expect-CT error.
6551 {"https://www.example.org/foo.html", "https://mail.example.org/foo.js",
6552 false /* client_cert_sent */, true /* expect_ct_error */,
6553 SpdyPushedStreamFate::kCertificateMismatch}};
Bence Békye7023f82018-05-14 01:53:036554
6555class SpdyNetworkTransactionPushUrlTest
6556 : public SpdyNetworkTransactionTest,
6557 public ::testing::WithParamInterface<PushUrlTestParams> {
Matt Menkec74a9262020-06-09 15:49:216558 public:
6559 SpdyNetworkTransactionPushUrlTest() {
6560 // Set features needed for the |expect_ct_error| case, where it's important
6561 // to check that NetworkIsolationKeys are respected.
6562 feature_list_.InitWithFeatures(
6563 /* enabled_features */
6564 {TransportSecurityState::kDynamicExpectCTFeature,
6565 features::kPartitionExpectCTStateByNetworkIsolationKey,
6566 features::kPartitionConnectionsByNetworkIsolationKey,
6567 features::kPartitionSSLSessionsByNetworkIsolationKey},
6568 /* disabled_features */
6569 {});
6570 }
6571
Bence Békye7023f82018-05-14 01:53:036572 protected:
[email protected]a7a265ef2010-12-08 18:05:576573 // In this test we want to verify that we can't accidentally push content
6574 // which can't be pushed by this content server.
6575 // This test assumes that:
6576 // - if we're requesting http://www.foo.com/barbaz
6577 // - the browser has made a connection to "www.foo.com".
Bence Békye7023f82018-05-14 01:53:036578 void RunTest() {
Bence Békyeacd48f2018-05-14 11:34:336579 base::HistogramTester histogram_tester;
6580
bncd16676a2016-07-20 16:23:016581 SpdyTestUtil spdy_test_util;
Ryan Hamilton0239aac2018-05-19 00:03:136582 spdy::SpdySerializedFrame stream1_syn(
Bence Békye7023f82018-05-14 01:53:036583 spdy_test_util.ConstructSpdyGet(GetParam().url_to_fetch, 1, LOWEST));
Ryan Hamilton0239aac2018-05-19 00:03:136584 spdy::SpdySerializedFrame stream1_body(
bncdf80d44fd2016-07-15 20:27:416585 spdy_test_util.ConstructSpdyDataFrame(1, true));
Ryan Hamilton0239aac2018-05-19 00:03:136586 spdy::SpdySerializedFrame push_rst(spdy_test_util.ConstructSpdyRstStream(
6587 2, spdy::ERROR_CODE_REFUSED_STREAM));
[email protected]a7a265ef2010-12-08 18:05:576588 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:416589 CreateMockWrite(stream1_syn, 0), CreateMockWrite(push_rst, 3),
[email protected]a7a265ef2010-12-08 18:05:576590 };
6591
Ryan Hamilton0239aac2018-05-19 00:03:136592 spdy::SpdySerializedFrame stream1_reply(
bnc42331402016-07-25 13:36:156593 spdy_test_util.ConstructSpdyGetReply(nullptr, 0, 1));
Ryan Hamilton0239aac2018-05-19 00:03:136594 spdy::SpdySerializedFrame stream2_syn(spdy_test_util.ConstructSpdyPush(
Bence Békye7023f82018-05-14 01:53:036595 nullptr, 0, 2, 1, GetParam().url_to_push));
[email protected]8a0fc822013-06-27 20:52:436596 const char kPushedData[] = "pushed";
Ryan Hamilton0239aac2018-05-19 00:03:136597 spdy::SpdySerializedFrame stream2_body(
Bence Békyd74f4382018-02-20 18:26:196598 spdy_test_util.ConstructSpdyDataFrame(2, kPushedData, true));
Ryan Hamilton0239aac2018-05-19 00:03:136599 spdy::SpdySerializedFrame rst(
6600 spdy_test_util.ConstructSpdyRstStream(2, spdy::ERROR_CODE_CANCEL));
[email protected]a7a265ef2010-12-08 18:05:576601
6602 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:416603 CreateMockRead(stream1_reply, 1),
6604 CreateMockRead(stream2_syn, 2),
6605 CreateMockRead(stream1_body, 4),
6606 CreateMockRead(stream2_body, 5),
rch08e3aa3e2015-05-16 14:27:526607 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 6), // Force a pause
[email protected]a7a265ef2010-12-08 18:05:576608 };
6609
6610 HttpResponseInfo response;
Ryan Sleevib8d7ea02018-05-07 20:01:016611 SequencedSocketData data(reads, writes);
[email protected]a7a265ef2010-12-08 18:05:576612
Bence Békye7023f82018-05-14 01:53:036613 request_.url = GURL(GetParam().url_to_fetch);
Matt Menkec74a9262020-06-09 15:49:216614 // Set a NetworkIsolationKey for the |expect_ct_error| case, to make sure
6615 // NetworkIsolationKeys are respected.
6616 request_.network_isolation_key = NetworkIsolationKey::CreateTransient();
[email protected]a7a265ef2010-12-08 18:05:576617
Bence Békyb2f76672018-06-11 21:10:136618 auto ssl_provider = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
6619 ssl_provider->ssl_info.client_cert_sent = GetParam().client_cert_sent;
6620 ssl_provider->ssl_info.cert =
6621 ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem");
Eric Orthfc0583b2021-05-18 19:13:596622 auto session_deps = std::make_unique<SpdySessionDependencies>();
Matt Menkec74a9262020-06-09 15:49:216623 if (GetParam().expect_ct_error) {
6624 ssl_provider->ssl_info.ct_policy_compliance =
6625 ct::CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS;
6626 ssl_provider->ssl_info.is_issued_by_known_root = true;
6627
6628 session_deps->transport_security_state->AddExpectCT(
Peter Kastinge5a38ed2021-10-02 03:06:356629 "mail.example.org", base::Time::Now() + base::Days(1) /* expiry */,
6630 true, GURL(), request_.network_isolation_key);
Matt Menkec74a9262020-06-09 15:49:216631 }
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),
Eric Orth5ccc3f02021-09-23 00:01:579174 ProxyUriToProxyServer("https://proxy:70", ProxyServer::SCHEME_HTTPS),
Matt Menke7269f352019-10-03 17:05:299175 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
David Benjamin7c6df0b762021-12-23 21:02:549646// When using an HTTP(S) proxy, plaintext WebSockets use CONNECT tunnels. This
9647// should work for HTTP/2 proxies.
Bence Béky420bb2d2018-03-30 17:25:269648TEST_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)));
David Benjamin7c6df0b762021-12-23 21:02:549652 const char kWebSocketRequest[] =
9653 "GET / HTTP/1.1\r\n"
9654 "Host: www.example.org\r\n"
9655 "Connection: Upgrade\r\n"
9656 "Upgrade: websocket\r\n"
9657 "Origin: http://www.example.org\r\n"
9658 "Sec-WebSocket-Version: 13\r\n"
9659 "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
9660 "Sec-WebSocket-Extensions: permessage-deflate; "
9661 "client_max_window_bits\r\n\r\n";
9662 spdy::SpdySerializedFrame websocket_request(spdy_util_.ConstructSpdyDataFrame(
9663 /*stream_id=*/1, kWebSocketRequest, /*fin=*/false));
9664 MockWrite writes[] = {CreateMockWrite(req, 0),
9665 CreateMockWrite(websocket_request, 2)};
Bence Béky420bb2d2018-03-30 17:25:269666
David Benjamin7c6df0b762021-12-23 21:02:549667 spdy::SpdySerializedFrame connect_response(
Ryan Hamilton0239aac2018-05-19 00:03:139668 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
David Benjamin7c6df0b762021-12-23 21:02:549669 const char kWebSocketResponse[] =
9670 "HTTP/1.1 101 Switching Protocols\r\n"
9671 "Upgrade: websocket\r\n"
9672 "Connection: Upgrade\r\n"
9673 "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n\r\n";
9674 spdy::SpdySerializedFrame websocket_response(
9675 spdy_util_.ConstructSpdyDataFrame(/*stream_id=*/1, kWebSocketResponse,
9676 /*fin=*/false));
9677 MockRead reads[] = {CreateMockRead(connect_response, 1),
9678 CreateMockRead(websocket_response, 3),
9679 MockRead(ASYNC, 0, 4)};
Bence Béky420bb2d2018-03-30 17:25:269680
Ryan Sleevib8d7ea02018-05-07 20:01:019681 SequencedSocketData data(reads, writes);
Bence Béky420bb2d2018-03-30 17:25:269682
9683 request_.url = GURL("ws://www.example.org/");
David Benjamin7c6df0b762021-12-23 21:02:549684 request_.extra_headers.SetHeader("Connection", "Upgrade");
9685 request_.extra_headers.SetHeader("Upgrade", "websocket");
9686 request_.extra_headers.SetHeader("Origin", "http://www.example.org");
9687 request_.extra_headers.SetHeader("Sec-WebSocket-Version", "13");
Bence Béky420bb2d2018-03-30 17:25:269688 auto session_deps = std::make_unique<SpdySessionDependencies>(
Nicolas Arciniegad2013f92020-02-07 23:00:569689 ConfiguredProxyResolutionService::CreateFixed(
9690 "https://proxy:70", TRAFFIC_ANNOTATION_FOR_TESTS));
Bence Béky420bb2d2018-03-30 17:25:269691 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
9692 std::move(session_deps));
9693 helper.RunPreTestSetup();
9694 helper.AddData(&data);
9695
9696 HttpNetworkTransaction* trans = helper.trans();
9697 TestWebSocketHandshakeStreamCreateHelper websocket_stream_create_helper;
9698 trans->SetWebSocketHandshakeStreamCreateHelper(
9699 &websocket_stream_create_helper);
9700
9701 EXPECT_TRUE(helper.StartDefaultTest());
9702 helper.WaitForCallbackToComplete();
David Benjamin7c6df0b762021-12-23 21:02:549703 EXPECT_THAT(helper.output().rv, IsOk());
Bence Béky420bb2d2018-03-30 17:25:269704
Bence Béky6434d5e2018-04-03 13:43:119705 base::RunLoop().RunUntilIdle();
Bence Béky6434d5e2018-04-03 13:43:119706 helper.VerifyDataConsumed();
9707}
9708
Bence Béky420bb2d2018-03-30 17:25:269709TEST_F(SpdyNetworkTransactionTest, SecureWebSocketOverHttp2Proxy) {
Ryan Hamilton0239aac2018-05-19 00:03:139710 spdy::SpdySerializedFrame connect_request(spdy_util_.ConstructSpdyConnect(
Matt Menke6e879bd2019-03-18 17:26:049711 nullptr, 0, 1, HttpProxyConnectJob::kH2QuicTunnelPriority,
9712 HostPortPair("www.example.org", 443)));
Bence Béky420bb2d2018-03-30 17:25:269713 const char kWebSocketRequest[] =
9714 "GET / HTTP/1.1\r\n"
9715 "Host: www.example.org\r\n"
9716 "Connection: Upgrade\r\n"
9717 "Upgrade: websocket\r\n"
9718 "Origin: http://www.example.org\r\n"
9719 "Sec-WebSocket-Version: 13\r\n"
9720 "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
9721 "Sec-WebSocket-Extensions: permessage-deflate; "
9722 "client_max_window_bits\r\n\r\n";
Ryan Hamilton0239aac2018-05-19 00:03:139723 spdy::SpdySerializedFrame websocket_request(
Bence Béky420bb2d2018-03-30 17:25:269724 spdy_util_.ConstructSpdyDataFrame(1, kWebSocketRequest, false));
9725 MockWrite writes[] = {CreateMockWrite(connect_request, 0),
9726 CreateMockWrite(websocket_request, 2)};
9727
Ryan Hamilton0239aac2018-05-19 00:03:139728 spdy::SpdySerializedFrame connect_response(
Bence Béky420bb2d2018-03-30 17:25:269729 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
9730 const char kWebSocketResponse[] =
9731 "HTTP/1.1 101 Switching Protocols\r\n"
9732 "Upgrade: websocket\r\n"
9733 "Connection: Upgrade\r\n"
9734 "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n\r\n";
Ryan Hamilton0239aac2018-05-19 00:03:139735 spdy::SpdySerializedFrame websocket_response(
Bence Béky420bb2d2018-03-30 17:25:269736 spdy_util_.ConstructSpdyDataFrame(1, kWebSocketResponse, false));
9737 MockRead reads[] = {CreateMockRead(connect_response, 1),
9738 CreateMockRead(websocket_response, 3),
9739 MockRead(ASYNC, 0, 4)};
9740
Ryan Sleevib8d7ea02018-05-07 20:01:019741 SequencedSocketData data(reads, writes);
Bence Béky420bb2d2018-03-30 17:25:269742
9743 request_.url = GURL("wss://www.example.org/");
9744 request_.extra_headers.SetHeader("Connection", "Upgrade");
9745 request_.extra_headers.SetHeader("Upgrade", "websocket");
9746 request_.extra_headers.SetHeader("Origin", "http://www.example.org");
9747 request_.extra_headers.SetHeader("Sec-WebSocket-Version", "13");
9748 auto session_deps = std::make_unique<SpdySessionDependencies>(
Nicolas Arciniegad2013f92020-02-07 23:00:569749 ConfiguredProxyResolutionService::CreateFixed(
9750 "https://proxy:70", TRAFFIC_ANNOTATION_FOR_TESTS));
Bence Béky420bb2d2018-03-30 17:25:269751 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
9752 std::move(session_deps));
9753 helper.RunPreTestSetup();
9754 helper.AddData(&data);
9755
9756 // Add SSL data for the tunneled connection.
9757 SSLSocketDataProvider ssl_provider(ASYNC, OK);
9758 ssl_provider.ssl_info.cert =
9759 ImportCertFromFile(GetTestCertsDirectory(), "wildcard.pem");
Bence Béky12943c62018-04-05 19:16:509760 // A WebSocket request should not advertise HTTP/2 support.
9761 ssl_provider.next_protos_expected_in_ssl_config = NextProtoVector{};
Bence Béky420bb2d2018-03-30 17:25:269762 // This test uses WebSocket over HTTP/1.1.
9763 ssl_provider.next_proto = kProtoHTTP11;
9764 helper.session_deps()->socket_factory->AddSSLSocketDataProvider(
9765 &ssl_provider);
9766
9767 HttpNetworkTransaction* trans = helper.trans();
9768 TestWebSocketHandshakeStreamCreateHelper websocket_stream_create_helper;
9769 trans->SetWebSocketHandshakeStreamCreateHelper(
9770 &websocket_stream_create_helper);
9771
9772 EXPECT_TRUE(helper.StartDefaultTest());
9773 helper.WaitForCallbackToComplete();
9774 EXPECT_THAT(helper.output().rv, IsOk());
9775 const HttpResponseInfo* response = trans->GetResponseInfo();
9776 ASSERT_TRUE(response);
9777 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP1_1,
9778 response->connection_info);
9779 EXPECT_TRUE(response->was_alpn_negotiated);
9780 EXPECT_FALSE(response->was_fetched_via_spdy);
Tsuyoshi Horo01faed62019-02-20 22:11:379781 EXPECT_EQ(70, response->remote_endpoint.port());
Bence Béky420bb2d2018-03-30 17:25:269782 ASSERT_TRUE(response->headers);
9783 EXPECT_EQ("HTTP/1.1 101 Switching Protocols",
9784 response->headers->GetStatusLine());
9785
9786 base::RunLoop().RunUntilIdle();
9787 helper.VerifyDataConsumed();
9788}
9789
Bence Béky12943c62018-04-05 19:16:509790// Regression test for https://crbug.com/828865.
9791TEST_F(SpdyNetworkTransactionTest,
9792 SecureWebSocketOverHttp2ProxyNegotiatesHttp2) {
Ryan Hamilton0239aac2018-05-19 00:03:139793 spdy::SpdySerializedFrame connect_request(spdy_util_.ConstructSpdyConnect(
Matt Menke6e879bd2019-03-18 17:26:049794 nullptr, 0, 1, HttpProxyConnectJob::kH2QuicTunnelPriority,
9795 HostPortPair("www.example.org", 443)));
Bence Béky12943c62018-04-05 19:16:509796 MockWrite writes[] = {CreateMockWrite(connect_request, 0)};
Ryan Hamilton0239aac2018-05-19 00:03:139797 spdy::SpdySerializedFrame connect_response(
Bence Béky12943c62018-04-05 19:16:509798 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
9799 MockRead reads[] = {CreateMockRead(connect_response, 1),
9800 MockRead(ASYNC, 0, 2)};
Ryan Sleevib8d7ea02018-05-07 20:01:019801 SequencedSocketData data(reads, writes);
Bence Béky12943c62018-04-05 19:16:509802
9803 request_.url = GURL("wss://www.example.org/");
9804 request_.extra_headers.SetHeader("Connection", "Upgrade");
9805 request_.extra_headers.SetHeader("Upgrade", "websocket");
9806 request_.extra_headers.SetHeader("Origin", "http://www.example.org");
9807 request_.extra_headers.SetHeader("Sec-WebSocket-Version", "13");
9808 auto session_deps = std::make_unique<SpdySessionDependencies>(
Nicolas Arciniegad2013f92020-02-07 23:00:569809 ConfiguredProxyResolutionService::CreateFixed(
9810 "https://proxy:70", TRAFFIC_ANNOTATION_FOR_TESTS));
Bence Béky12943c62018-04-05 19:16:509811 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
9812 std::move(session_deps));
9813 helper.RunPreTestSetup();
9814 helper.AddData(&data);
9815
9816 // Add SSL data for the tunneled connection.
9817 SSLSocketDataProvider ssl_provider(ASYNC, OK);
9818 ssl_provider.ssl_info.cert =
9819 ImportCertFromFile(GetTestCertsDirectory(), "wildcard.pem");
9820 // A WebSocket request should not advertise HTTP/2 support.
9821 ssl_provider.next_protos_expected_in_ssl_config = NextProtoVector{};
9822 // The server should not negotiate HTTP/2 over the tunnelled connection,
9823 // but it must be handled gracefully if it does.
9824 ssl_provider.next_proto = kProtoHTTP2;
9825 helper.session_deps()->socket_factory->AddSSLSocketDataProvider(
9826 &ssl_provider);
9827
9828 HttpNetworkTransaction* trans = helper.trans();
9829 TestWebSocketHandshakeStreamCreateHelper websocket_stream_create_helper;
9830 trans->SetWebSocketHandshakeStreamCreateHelper(
9831 &websocket_stream_create_helper);
9832
9833 EXPECT_TRUE(helper.StartDefaultTest());
9834 helper.WaitForCallbackToComplete();
9835 EXPECT_THAT(helper.output().rv, IsError(ERR_NOT_IMPLEMENTED));
9836
9837 base::RunLoop().RunUntilIdle();
9838 helper.VerifyDataConsumed();
9839}
9840
Bence Béky0ca719f2018-01-31 13:41:199841#endif // BUILDFLAG(ENABLE_WEBSOCKETS)
9842
Steven Valdez1c1859172019-04-10 15:33:289843TEST_F(SpdyNetworkTransactionTest, ZeroRTTDoesntConfirm) {
Peter Kastinge5a38ed2021-10-02 03:06:359844 static const base::TimeDelta kDelay = base::Milliseconds(10);
Steven Valdez1c1859172019-04-10 15:33:289845 spdy::SpdySerializedFrame req(
9846 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
9847 MockWrite writes[] = {CreateMockWrite(req, 0)};
9848
9849 spdy::SpdySerializedFrame resp(
9850 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
9851 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
9852 MockRead reads[] = {
9853 CreateMockRead(resp, 1), CreateMockRead(body, 2),
9854 MockRead(ASYNC, 0, 3) // EOF
9855 };
9856
9857 SequencedSocketData data(reads, writes);
9858 auto session_deps = std::make_unique<SpdySessionDependencies>();
9859 session_deps->enable_early_data = true;
9860 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
9861 std::move(session_deps));
9862 auto ssl_provider = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
David Benjaminbae08ba2019-10-18 21:06:159863 ssl_provider->connect_callback = FastForwardByCallback(kDelay);
Steven Valdez1c1859172019-04-10 15:33:289864 // Configure |ssl_provider| to fail if ConfirmHandshake is called. The request
9865 // should still succeed.
9866 ssl_provider->confirm = MockConfirm(SYNCHRONOUS, ERR_SSL_PROTOCOL_ERROR);
David Benjaminbae08ba2019-10-18 21:06:159867 ssl_provider->confirm_callback = FastForwardByCallback(kDelay);
9868 base::TimeTicks start_time = base::TimeTicks::Now();
Steven Valdez1c1859172019-04-10 15:33:289869 helper.RunToCompletionWithSSLData(&data, std::move(ssl_provider));
9870 TransactionHelperResult out = helper.output();
9871 EXPECT_THAT(out.rv, IsOk());
9872 EXPECT_EQ("HTTP/1.1 200", out.status_line);
9873 EXPECT_EQ("hello!", out.response_data);
David Benjaminbae08ba2019-10-18 21:06:159874
9875 // The handshake time should include the time it took to run Connect(), but
9876 // not ConfirmHandshake().
9877 LoadTimingInfo load_timing_info;
9878 EXPECT_TRUE(helper.trans()->GetLoadTimingInfo(&load_timing_info));
9879 EXPECT_EQ(load_timing_info.connect_timing.connect_start, start_time);
9880 EXPECT_EQ(load_timing_info.connect_timing.ssl_start, start_time);
9881 EXPECT_EQ(load_timing_info.connect_timing.ssl_end, start_time + kDelay);
9882 EXPECT_EQ(load_timing_info.connect_timing.connect_end, start_time + kDelay);
Steven Valdez1c1859172019-04-10 15:33:289883}
9884
9885// Run multiple concurrent streams that don't require handshake confirmation.
9886TEST_F(SpdyNetworkTransactionTest, ZeroRTTNoConfirmMultipleStreams) {
9887 spdy::SpdySerializedFrame req1(
9888 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
9889 spdy::SpdySerializedFrame req2(
9890 spdy_util_.ConstructSpdyGet(nullptr, 0, 3, LOWEST));
9891 MockWrite writes1[] = {CreateMockWrite(req1, 0), CreateMockWrite(req2, 3)};
9892
9893 spdy::SpdySerializedFrame resp1(
9894 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
9895 spdy::SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true));
9896 spdy::SpdySerializedFrame resp2(
9897 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
9898 spdy::SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(3, true));
9899 MockRead reads1[] = {
9900 CreateMockRead(resp1, 1), CreateMockRead(body1, 2),
9901 CreateMockRead(resp2, 4), CreateMockRead(body2, 5),
9902 MockRead(ASYNC, 0, 6) // EOF
9903 };
9904
9905 SequencedSocketData data1(reads1, writes1);
9906 SequencedSocketData data2({}, {});
9907 auto session_deps = std::make_unique<SpdySessionDependencies>();
9908 session_deps->enable_early_data = true;
9909 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
9910 std::move(session_deps));
9911 auto ssl_provider1 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
9912 ssl_provider1->confirm = MockConfirm(SYNCHRONOUS, ERR_SSL_PROTOCOL_ERROR);
9913 auto ssl_provider2 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
9914 ssl_provider2->confirm = MockConfirm(SYNCHRONOUS, ERR_SSL_PROTOCOL_ERROR);
9915
9916 helper.RunPreTestSetup();
9917 helper.AddDataWithSSLSocketDataProvider(&data1, std::move(ssl_provider1));
9918 helper.AddDataWithSSLSocketDataProvider(&data2, std::move(ssl_provider2));
9919 EXPECT_TRUE(helper.StartDefaultTest());
9920
9921 HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session());
9922 HttpRequestInfo request2;
9923 request2.method = "GET";
9924 request2.url = GURL(kDefaultUrl);
9925 request2.traffic_annotation =
9926 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
9927 TestCompletionCallback callback2;
9928 int rv = trans2.Start(&request2, callback2.callback(), log_);
9929 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
9930
9931 helper.FinishDefaultTest();
9932 EXPECT_THAT(callback2.GetResult(ERR_IO_PENDING), IsOk());
9933 helper.VerifyDataConsumed();
9934
9935 TransactionHelperResult out = helper.output();
9936 EXPECT_THAT(out.rv, IsOk());
9937 EXPECT_EQ("HTTP/1.1 200", out.status_line);
9938 EXPECT_EQ("hello!", out.response_data);
9939}
9940
9941// Run multiple concurrent streams that require handshake confirmation.
9942TEST_F(SpdyNetworkTransactionTest, ZeroRTTConfirmMultipleStreams) {
Bence Béky4c325e52020-10-22 20:48:019943 spdy::Http2HeaderBlock req_block1(
Steven Valdez1c1859172019-04-10 15:33:289944 spdy_util_.ConstructPostHeaderBlock(kDefaultUrl, 0));
9945 spdy::SpdySerializedFrame req1(
9946 spdy_util_.ConstructSpdyHeaders(1, std::move(req_block1), LOWEST, true));
Bence Béky4c325e52020-10-22 20:48:019947 spdy::Http2HeaderBlock req_block2(
Steven Valdez1c1859172019-04-10 15:33:289948 spdy_util_.ConstructPostHeaderBlock(kDefaultUrl, 0));
9949 spdy::SpdySerializedFrame req2(
9950 spdy_util_.ConstructSpdyHeaders(3, std::move(req_block2), LOWEST, true));
9951 MockWrite writes[] = {
9952 CreateMockWrite(req1, 0),
9953 CreateMockWrite(req2, 3),
9954 };
9955 spdy::SpdySerializedFrame resp1(
9956 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
9957 spdy::SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true));
9958 spdy::SpdySerializedFrame resp2(
9959 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
9960 spdy::SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(3, true));
9961 MockRead reads[] = {
9962 CreateMockRead(resp1, 1), CreateMockRead(body1, 2),
9963 CreateMockRead(resp2, 4), CreateMockRead(body2, 5),
9964 MockRead(ASYNC, 0, 6) // EOF
9965 };
9966
9967 SequencedSocketData data1(reads, writes);
9968 SequencedSocketData data2({}, {});
9969 UsePostRequest();
9970 auto session_deps = std::make_unique<SpdySessionDependencies>();
9971 session_deps->enable_early_data = true;
9972 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
9973 std::move(session_deps));
9974 auto ssl_provider1 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
9975 ssl_provider1->confirm = MockConfirm(ASYNC, OK);
9976 auto ssl_provider2 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
9977 ssl_provider2->confirm = MockConfirm(ASYNC, OK);
9978
9979 helper.RunPreTestSetup();
9980 helper.AddDataWithSSLSocketDataProvider(&data1, std::move(ssl_provider1));
9981 helper.AddDataWithSSLSocketDataProvider(&data2, std::move(ssl_provider2));
9982
9983 HttpNetworkTransaction trans1(DEFAULT_PRIORITY, helper.session());
9984 HttpRequestInfo request1;
9985 request1.method = "POST";
9986 request1.url = GURL(kDefaultUrl);
9987 request1.traffic_annotation =
9988 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
9989 TestCompletionCallback callback1;
9990 int rv = trans1.Start(&request1, callback1.callback(), log_);
9991 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
9992
9993 HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session());
9994 HttpRequestInfo request2;
9995 request2.method = "POST";
9996 request2.url = GURL(kDefaultUrl);
9997 request2.traffic_annotation =
9998 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
9999 TestCompletionCallback callback2;
10000 rv = trans2.Start(&request2, callback2.callback(), log_);
10001 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
10002
10003 EXPECT_THAT(callback1.GetResult(ERR_IO_PENDING), IsOk());
10004 EXPECT_THAT(callback2.GetResult(ERR_IO_PENDING), IsOk());
10005
10006 const HttpResponseInfo* response1 = trans1.GetResponseInfo();
10007 ASSERT_TRUE(response1);
10008 ASSERT_TRUE(response1->headers);
10009 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP2,
10010 response1->connection_info);
10011 EXPECT_EQ("HTTP/1.1 200", response1->headers->GetStatusLine());
10012 std::string response_data;
10013 ReadTransaction(&trans1, &response_data);
10014 EXPECT_EQ("hello!", response_data);
10015
10016 const HttpResponseInfo* response2 = trans2.GetResponseInfo();
10017 ASSERT_TRUE(response2);
10018 ASSERT_TRUE(response2->headers);
10019 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP2,
10020 response2->connection_info);
10021 EXPECT_EQ("HTTP/1.1 200", response2->headers->GetStatusLine());
10022 ReadTransaction(&trans2, &response_data);
10023 EXPECT_EQ("hello!", response_data);
10024
10025 helper.VerifyDataConsumed();
10026}
10027
10028// Run multiple concurrent streams, the first require a confirmation and the
10029// second not requiring confirmation.
10030TEST_F(SpdyNetworkTransactionTest, ZeroRTTConfirmNoConfirmStreams) {
10031 // This test orders the writes such that the GET (no confirmation) is written
10032 // before the POST (confirmation required).
Bence Béky4c325e52020-10-22 20:48:0110033 spdy::Http2HeaderBlock req_block1(
Steven Valdez1c1859172019-04-10 15:33:2810034 spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
10035 spdy::SpdySerializedFrame req1(
10036 spdy_util_.ConstructSpdyHeaders(1, std::move(req_block1), LOWEST, true));
Bence Béky4c325e52020-10-22 20:48:0110037 spdy::Http2HeaderBlock req_block2(
Steven Valdez1c1859172019-04-10 15:33:2810038 spdy_util_.ConstructPostHeaderBlock(kDefaultUrl, 0));
10039 spdy::SpdySerializedFrame req2(
10040 spdy_util_.ConstructSpdyHeaders(3, std::move(req_block2), LOWEST, true));
10041 MockWrite writes[] = {
10042 CreateMockWrite(req1, 0),
10043 CreateMockWrite(req2, 3),
10044 };
10045 spdy::SpdySerializedFrame resp1(
10046 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
10047 spdy::SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true));
10048 spdy::SpdySerializedFrame resp2(
10049 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
10050 spdy::SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(3, true));
10051 MockRead reads[] = {
10052 CreateMockRead(resp1, 1), CreateMockRead(body1, 2),
10053 CreateMockRead(resp2, 4), CreateMockRead(body2, 5),
10054 MockRead(ASYNC, 0, 6) // EOF
10055 };
10056
10057 SequencedSocketData data1(reads, writes);
10058 SequencedSocketData data2({}, {});
10059 UsePostRequest();
10060 auto session_deps = std::make_unique<SpdySessionDependencies>();
10061 session_deps->enable_early_data = true;
10062 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
10063 std::move(session_deps));
10064 auto ssl_provider1 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
10065 ssl_provider1->confirm = MockConfirm(ASYNC, OK);
10066 auto ssl_provider2 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
10067 ssl_provider2->confirm = MockConfirm(ASYNC, OK);
10068
10069 helper.RunPreTestSetup();
10070 helper.AddDataWithSSLSocketDataProvider(&data1, std::move(ssl_provider1));
10071 helper.AddDataWithSSLSocketDataProvider(&data2, std::move(ssl_provider2));
10072
10073 // TODO(https://crbug.com/949724): Explicitly verify the ordering of
10074 // ConfirmHandshake and the second stream.
10075
10076 HttpNetworkTransaction trans1(DEFAULT_PRIORITY, helper.session());
10077 HttpRequestInfo request1;
10078 request1.method = "POST";
10079 request1.url = GURL(kDefaultUrl);
10080 request1.traffic_annotation =
10081 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
10082 TestCompletionCallback callback1;
10083 int rv = trans1.Start(&request1, callback1.callback(), log_);
10084 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
10085
10086 HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session());
10087 HttpRequestInfo request2;
10088 request2.method = "GET";
10089 request2.url = GURL(kDefaultUrl);
10090 request2.traffic_annotation =
10091 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
10092 TestCompletionCallback callback2;
10093 rv = trans2.Start(&request2, callback2.callback(), log_);
10094 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
10095
10096 EXPECT_THAT(callback1.GetResult(ERR_IO_PENDING), IsOk());
10097 EXPECT_THAT(callback2.GetResult(ERR_IO_PENDING), IsOk());
10098
10099 const HttpResponseInfo* response1 = trans1.GetResponseInfo();
10100 ASSERT_TRUE(response1);
10101 ASSERT_TRUE(response1->headers);
10102 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP2,
10103 response1->connection_info);
10104 EXPECT_EQ("HTTP/1.1 200", response1->headers->GetStatusLine());
10105 std::string response_data;
10106 ReadTransaction(&trans1, &response_data);
10107 EXPECT_EQ("hello!", response_data);
10108
10109 const HttpResponseInfo* response2 = trans2.GetResponseInfo();
10110 ASSERT_TRUE(response2);
10111 ASSERT_TRUE(response2->headers);
10112 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP2,
10113 response2->connection_info);
10114 EXPECT_EQ("HTTP/1.1 200", response2->headers->GetStatusLine());
10115 ReadTransaction(&trans2, &response_data);
10116 EXPECT_EQ("hello!", response_data);
10117
10118 helper.VerifyDataConsumed();
10119}
10120
10121// Run multiple concurrent streams, the first not requiring confirmation and the
10122// second requiring confirmation.
10123TEST_F(SpdyNetworkTransactionTest, ZeroRTTNoConfirmConfirmStreams) {
10124 // This test orders the writes such that the GET (no confirmation) is written
10125 // before the POST (confirmation required).
Bence Béky4c325e52020-10-22 20:48:0110126 spdy::Http2HeaderBlock req_block1(
Steven Valdez1c1859172019-04-10 15:33:2810127 spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
10128 spdy::SpdySerializedFrame req1(
10129 spdy_util_.ConstructSpdyHeaders(1, std::move(req_block1), LOWEST, true));
Bence Béky4c325e52020-10-22 20:48:0110130 spdy::Http2HeaderBlock req_block2(
Steven Valdez1c1859172019-04-10 15:33:2810131 spdy_util_.ConstructPostHeaderBlock(kDefaultUrl, 0));
10132 spdy::SpdySerializedFrame req2(
10133 spdy_util_.ConstructSpdyHeaders(3, std::move(req_block2), LOWEST, true));
10134 MockWrite writes[] = {
10135 CreateMockWrite(req1, 0),
10136 CreateMockWrite(req2, 3),
10137 };
10138 spdy::SpdySerializedFrame resp1(
10139 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
10140 spdy::SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true));
10141 spdy::SpdySerializedFrame resp2(
10142 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
10143 spdy::SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(3, true));
10144 MockRead reads[] = {
10145 CreateMockRead(resp1, 1), CreateMockRead(body1, 2),
10146 CreateMockRead(resp2, 4), CreateMockRead(body2, 5),
10147 MockRead(ASYNC, 0, 6) // EOF
10148 };
10149
10150 SequencedSocketData data1(reads, writes);
10151 SequencedSocketData data2({}, {});
10152 UsePostRequest();
10153 auto session_deps = std::make_unique<SpdySessionDependencies>();
10154 session_deps->enable_early_data = true;
10155 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
10156 std::move(session_deps));
10157 auto ssl_provider1 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
10158 ssl_provider1->confirm = MockConfirm(ASYNC, OK);
10159 auto ssl_provider2 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
10160 ssl_provider2->confirm = MockConfirm(ASYNC, OK);
10161
10162 helper.RunPreTestSetup();
10163 helper.AddDataWithSSLSocketDataProvider(&data1, std::move(ssl_provider1));
10164 helper.AddDataWithSSLSocketDataProvider(&data2, std::move(ssl_provider2));
10165
10166 // TODO(https://crbug.com/949724): Explicitly verify the ordering of
10167 // ConfirmHandshake and the second stream.
10168
10169 HttpNetworkTransaction trans1(DEFAULT_PRIORITY, helper.session());
10170 HttpRequestInfo request1;
10171 request1.method = "GET";
10172 request1.url = GURL(kDefaultUrl);
10173 request1.traffic_annotation =
10174 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
10175 TestCompletionCallback callback1;
10176 int rv = trans1.Start(&request1, callback1.callback(), log_);
10177 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
10178
10179 HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session());
10180 HttpRequestInfo request2;
10181 request2.method = "POST";
10182 request2.url = GURL(kDefaultUrl);
10183 request2.traffic_annotation =
10184 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
10185 TestCompletionCallback callback2;
10186 rv = trans2.Start(&request2, callback2.callback(), log_);
10187 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
10188
10189 EXPECT_THAT(callback1.GetResult(ERR_IO_PENDING), IsOk());
10190 EXPECT_THAT(callback2.GetResult(ERR_IO_PENDING), IsOk());
10191
10192 const HttpResponseInfo* response1 = trans1.GetResponseInfo();
10193 ASSERT_TRUE(response1);
10194 ASSERT_TRUE(response1->headers);
10195 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP2,
10196 response1->connection_info);
10197 EXPECT_EQ("HTTP/1.1 200", response1->headers->GetStatusLine());
10198 std::string response_data;
10199 ReadTransaction(&trans1, &response_data);
10200 EXPECT_EQ("hello!", response_data);
10201
10202 const HttpResponseInfo* response2 = trans2.GetResponseInfo();
10203 ASSERT_TRUE(response2);
10204 ASSERT_TRUE(response2->headers);
10205 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP2,
10206 response2->connection_info);
10207 EXPECT_EQ("HTTP/1.1 200", response2->headers->GetStatusLine());
10208 ReadTransaction(&trans2, &response_data);
10209 EXPECT_EQ("hello!", response_data);
10210
10211 helper.VerifyDataConsumed();
10212}
10213
10214TEST_F(SpdyNetworkTransactionTest, ZeroRTTSyncConfirmSyncWrite) {
Peter Kastinge5a38ed2021-10-02 03:06:3510215 static const base::TimeDelta kDelay = base::Milliseconds(10);
Steven Valdez1c1859172019-04-10 15:33:2810216 spdy::SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
10217 kDefaultUrl, 1, kUploadDataSize, LOWEST, nullptr, 0));
10218 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
10219 MockWrite writes[] = {
10220 CreateMockWrite(req, 0, SYNCHRONOUS),
10221 CreateMockWrite(body, 1), // POST upload frame
10222 };
10223
10224 spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
10225 MockRead reads[] = {
10226 CreateMockRead(resp, 2), CreateMockRead(body, 3),
10227 MockRead(ASYNC, 0, 4) // EOF
10228 };
10229
10230 SequencedSocketData data(reads, writes);
10231 UsePostRequest();
10232 auto session_deps = std::make_unique<SpdySessionDependencies>();
10233 session_deps->enable_early_data = true;
10234 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
10235 std::move(session_deps));
10236 auto ssl_provider = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
David Benjaminbae08ba2019-10-18 21:06:1510237 ssl_provider->connect_callback = FastForwardByCallback(kDelay);
Steven Valdez1c1859172019-04-10 15:33:2810238 ssl_provider->confirm = MockConfirm(SYNCHRONOUS, OK);
David Benjaminbae08ba2019-10-18 21:06:1510239 ssl_provider->confirm_callback = FastForwardByCallback(kDelay);
10240 base::TimeTicks start_time = base::TimeTicks::Now();
Steven Valdez1c1859172019-04-10 15:33:2810241 helper.RunToCompletionWithSSLData(&data, std::move(ssl_provider));
10242 TransactionHelperResult out = helper.output();
10243 EXPECT_THAT(out.rv, IsOk());
10244 EXPECT_EQ("HTTP/1.1 200", out.status_line);
10245 EXPECT_EQ("hello!", out.response_data);
David Benjaminbae08ba2019-10-18 21:06:1510246
10247 // The handshake time should include the time it took to run Connect(), but
10248 // not ConfirmHandshake(). If ConfirmHandshake() returns synchronously, we
10249 // assume the connection did not negotiate 0-RTT or the handshake was already
10250 // confirmed.
10251 LoadTimingInfo load_timing_info;
10252 EXPECT_TRUE(helper.trans()->GetLoadTimingInfo(&load_timing_info));
10253 EXPECT_EQ(load_timing_info.connect_timing.connect_start, start_time);
10254 EXPECT_EQ(load_timing_info.connect_timing.ssl_start, start_time);
10255 EXPECT_EQ(load_timing_info.connect_timing.ssl_end, start_time + kDelay);
10256 EXPECT_EQ(load_timing_info.connect_timing.connect_end, start_time + kDelay);
Steven Valdez1c1859172019-04-10 15:33:2810257}
10258
10259TEST_F(SpdyNetworkTransactionTest, ZeroRTTSyncConfirmAsyncWrite) {
10260 spdy::SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
10261 kDefaultUrl, 1, kUploadDataSize, LOWEST, nullptr, 0));
10262 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
10263 MockWrite writes[] = {
10264 CreateMockWrite(req, 0, ASYNC),
10265 CreateMockWrite(body, 1), // POST upload frame
10266 };
10267
10268 spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
10269 MockRead reads[] = {
10270 CreateMockRead(resp, 2), CreateMockRead(body, 3),
10271 MockRead(ASYNC, 0, 4) // EOF
10272 };
10273
10274 SequencedSocketData data(reads, writes);
10275 UsePostRequest();
10276 auto session_deps = std::make_unique<SpdySessionDependencies>();
10277 session_deps->enable_early_data = true;
10278 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
10279 std::move(session_deps));
10280 auto ssl_provider = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
10281 ssl_provider->confirm = MockConfirm(SYNCHRONOUS, OK);
10282 helper.RunToCompletionWithSSLData(&data, std::move(ssl_provider));
10283 TransactionHelperResult out = helper.output();
10284 EXPECT_THAT(out.rv, IsOk());
10285 EXPECT_EQ("HTTP/1.1 200", out.status_line);
10286 EXPECT_EQ("hello!", out.response_data);
10287}
10288
10289TEST_F(SpdyNetworkTransactionTest, ZeroRTTAsyncConfirmSyncWrite) {
Peter Kastinge5a38ed2021-10-02 03:06:3510290 static const base::TimeDelta kDelay = base::Milliseconds(10);
Steven Valdez1c1859172019-04-10 15:33:2810291 spdy::SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
10292 kDefaultUrl, 1, kUploadDataSize, LOWEST, nullptr, 0));
10293 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
10294 MockWrite writes[] = {
10295 CreateMockWrite(req, 0, SYNCHRONOUS),
10296 CreateMockWrite(body, 1), // POST upload frame
10297 };
10298
10299 spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
10300 MockRead reads[] = {
10301 CreateMockRead(resp, 2), CreateMockRead(body, 3),
10302 MockRead(ASYNC, 0, 4) // EOF
10303 };
10304
10305 SequencedSocketData data(reads, writes);
10306 UsePostRequest();
10307 auto session_deps = std::make_unique<SpdySessionDependencies>();
10308 session_deps->enable_early_data = true;
10309 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
10310 std::move(session_deps));
10311 auto ssl_provider = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
David Benjaminbae08ba2019-10-18 21:06:1510312 ssl_provider->connect_callback = FastForwardByCallback(kDelay);
Steven Valdez1c1859172019-04-10 15:33:2810313 ssl_provider->confirm = MockConfirm(ASYNC, OK);
David Benjaminbae08ba2019-10-18 21:06:1510314 ssl_provider->confirm_callback = FastForwardByCallback(kDelay);
10315 base::TimeTicks start_time = base::TimeTicks::Now();
Steven Valdez1c1859172019-04-10 15:33:2810316 helper.RunToCompletionWithSSLData(&data, std::move(ssl_provider));
10317 TransactionHelperResult out = helper.output();
10318 EXPECT_THAT(out.rv, IsOk());
10319 EXPECT_EQ("HTTP/1.1 200", out.status_line);
10320 EXPECT_EQ("hello!", out.response_data);
David Benjaminbae08ba2019-10-18 21:06:1510321
10322 // The handshake time should include the time it took to run Connect() and
10323 // ConfirmHandshake().
10324 LoadTimingInfo load_timing_info;
10325 EXPECT_TRUE(helper.trans()->GetLoadTimingInfo(&load_timing_info));
10326 EXPECT_EQ(load_timing_info.connect_timing.connect_start, start_time);
10327 EXPECT_EQ(load_timing_info.connect_timing.ssl_start, start_time);
10328 EXPECT_EQ(load_timing_info.connect_timing.ssl_end, start_time + 2 * kDelay);
10329 EXPECT_EQ(load_timing_info.connect_timing.connect_end,
10330 start_time + 2 * kDelay);
Steven Valdez1c1859172019-04-10 15:33:2810331}
10332
10333TEST_F(SpdyNetworkTransactionTest, ZeroRTTAsyncConfirmAsyncWrite) {
10334 spdy::SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
10335 kDefaultUrl, 1, kUploadDataSize, LOWEST, nullptr, 0));
10336 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
10337 MockWrite writes[] = {
10338 CreateMockWrite(req, 0, ASYNC),
10339 CreateMockWrite(body, 1), // POST upload frame
10340 };
10341
10342 spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
10343 MockRead reads[] = {
10344 CreateMockRead(resp, 2), CreateMockRead(body, 3),
10345 MockRead(ASYNC, 0, 4) // EOF
10346 };
10347
10348 SequencedSocketData data(reads, writes);
10349 UsePostRequest();
10350 auto session_deps = std::make_unique<SpdySessionDependencies>();
10351 session_deps->enable_early_data = true;
10352 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
10353 std::move(session_deps));
10354 auto ssl_provider = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
10355 ssl_provider->confirm = MockConfirm(ASYNC, OK);
10356 helper.RunToCompletionWithSSLData(&data, std::move(ssl_provider));
10357 TransactionHelperResult out = helper.output();
10358 EXPECT_THAT(out.rv, IsOk());
10359 EXPECT_EQ("HTTP/1.1 200", out.status_line);
10360 EXPECT_EQ("hello!", out.response_data);
10361}
10362
10363TEST_F(SpdyNetworkTransactionTest, ZeroRTTConfirmErrorSync) {
10364 spdy::SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
10365 kDefaultUrl, 1, kUploadDataSize, LOWEST, nullptr, 0));
10366 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
10367 MockWrite writes[] = {
10368 CreateMockWrite(req, 0), CreateMockWrite(body, 1), // POST upload frame
10369 };
10370
10371 spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
10372 MockRead reads[] = {
10373 CreateMockRead(resp, 2), CreateMockRead(body, 3),
10374 MockRead(ASYNC, 0, 4) // EOF
10375 };
10376
10377 SequencedSocketData data(reads, writes);
10378 UsePostRequest();
10379 auto session_deps = std::make_unique<SpdySessionDependencies>();
10380 session_deps->enable_early_data = true;
10381 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
10382 std::move(session_deps));
10383 auto ssl_provider = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
10384 ssl_provider->confirm = MockConfirm(SYNCHRONOUS, ERR_SSL_PROTOCOL_ERROR);
10385 helper.RunPreTestSetup();
10386 helper.AddDataWithSSLSocketDataProvider(&data, std::move(ssl_provider));
10387 helper.RunDefaultTest();
10388 TransactionHelperResult out = helper.output();
10389 EXPECT_THAT(out.rv, IsError(ERR_SSL_PROTOCOL_ERROR));
10390}
10391
10392TEST_F(SpdyNetworkTransactionTest, ZeroRTTConfirmErrorAsync) {
10393 spdy::SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
10394 kDefaultUrl, 1, kUploadDataSize, LOWEST, nullptr, 0));
10395 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
10396 MockWrite writes[] = {
10397 CreateMockWrite(req, 0), CreateMockWrite(body, 1), // POST upload frame
10398 };
10399
10400 spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
10401 MockRead reads[] = {
10402 CreateMockRead(resp, 2), CreateMockRead(body, 3),
10403 MockRead(ASYNC, 0, 4) // EOF
10404 };
10405
10406 SequencedSocketData data(reads, writes);
10407 UsePostRequest();
10408 auto session_deps = std::make_unique<SpdySessionDependencies>();
10409 session_deps->enable_early_data = true;
10410 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
10411 std::move(session_deps));
10412 auto ssl_provider = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
10413 ssl_provider->confirm = MockConfirm(ASYNC, ERR_SSL_PROTOCOL_ERROR);
10414 helper.RunPreTestSetup();
10415 helper.AddDataWithSSLSocketDataProvider(&data, std::move(ssl_provider));
10416 helper.RunDefaultTest();
10417 TransactionHelperResult out = helper.output();
10418 EXPECT_THAT(out.rv, IsError(ERR_SSL_PROTOCOL_ERROR));
10419}
10420
Bence Békyd228fb22021-10-29 14:45:5110421TEST_F(SpdyNetworkTransactionTest, GreaseSettings) {
10422 RecordingNetLogObserver net_log_observer;
10423
10424 auto session_deps = std::make_unique<SpdySessionDependencies>();
10425 session_deps->enable_http2_settings_grease = true;
10426 NormalSpdyTransactionHelper helper(
10427 request_, DEFAULT_PRIORITY,
10428 NetLogWithSource::Make(NetLogSourceType::NONE), std::move(session_deps));
10429
10430 SpdySessionPool* spdy_session_pool = helper.session()->spdy_session_pool();
10431 SpdySessionPoolPeer pool_peer(spdy_session_pool);
10432 pool_peer.SetEnableSendingInitialData(true);
10433
10434 // Greased setting parameter is random. Hang writes instead of trying to
10435 // construct matching mock data. Extra write and read is needed because mock
10436 // data cannot end on ERR_IO_PENDING. Writes or reads will not actually be
10437 // resumed.
10438 MockWrite writes[] = {MockWrite(ASYNC, ERR_IO_PENDING, 0),
10439 MockWrite(ASYNC, OK, 1)};
10440 MockRead reads[] = {MockRead(ASYNC, ERR_IO_PENDING, 2),
10441 MockRead(ASYNC, OK, 3)};
10442 SequencedSocketData data(reads, writes);
10443 helper.RunPreTestSetup();
10444 helper.AddData(&data);
10445
10446 int rv = helper.trans()->Start(&request_, CompletionOnceCallback{}, log_);
10447 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
10448
10449 base::RunLoop().RunUntilIdle();
10450
10451 helper.ResetTrans();
10452
10453 EXPECT_FALSE(data.AllReadDataConsumed());
10454 EXPECT_FALSE(data.AllWriteDataConsumed());
10455
10456 const auto entries = net_log_observer.GetEntries();
10457
10458 size_t pos = ExpectLogContainsSomewhere(
10459 entries, 0, NetLogEventType::HTTP2_SESSION_SEND_SETTINGS,
10460 NetLogEventPhase::NONE);
10461 ASSERT_LT(pos, entries.size());
10462
10463 const base::Value& params = entries[pos].params;
10464 const base::Value* const settings = params.FindKey("settings");
10465 ASSERT_TRUE(settings);
10466 ASSERT_TRUE(settings->is_list());
10467
10468 base::Value::ConstListView list = settings->GetList();
10469 ASSERT_FALSE(list.empty());
10470 // Get last setting parameter.
10471 const base::Value& greased_setting = list[list.size() - 1];
10472 ASSERT_TRUE(greased_setting.is_string());
10473 base::StringPiece greased_setting_string(greased_setting.GetString());
10474
10475 const std::string kExpectedPrefix = "[id:";
10476 EXPECT_EQ(kExpectedPrefix,
10477 greased_setting_string.substr(0, kExpectedPrefix.size()));
10478 int setting_identifier = 0;
10479 base::StringToInt(greased_setting_string.substr(kExpectedPrefix.size()),
10480 &setting_identifier);
10481 // The setting identifier must be of format 0x?a?a.
10482 EXPECT_EQ(0xa, setting_identifier % 16);
10483 EXPECT_EQ(0xa, (setting_identifier / 256) % 16);
10484}
10485
Bence Békycb4be9e2020-07-09 11:18:1410486// If |http2_end_stream_with_data_frame| is false, then the HEADERS frame of a
10487// GET request will close the stream using the END_STREAM flag. Test that
10488// |greased_http2_frame| is ignored and no reserved frames are sent on a closed
10489// stream.
10490TEST_F(SpdyNetworkTransactionTest,
10491 DoNotGreaseFrameTypeWithGetRequestIfHeadersFrameClosesStream) {
10492 auto session_deps = std::make_unique<SpdySessionDependencies>();
10493
10494 const uint8_t type = 0x0b;
10495 const uint8_t flags = 0xcc;
10496 const std::string payload("foo");
10497 session_deps->greased_http2_frame =
Anton Bikineev068d2912021-05-15 20:43:5210498 absl::optional<net::SpdySessionPool::GreasedHttp2Frame>(
Bence Békycb4be9e2020-07-09 11:18:1410499 {type, flags, payload});
10500 session_deps->http2_end_stream_with_data_frame = false;
10501
10502 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
10503 std::move(session_deps));
10504
10505 spdy::SpdySerializedFrame req(
10506 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, DEFAULT_PRIORITY));
10507 MockWrite writes[] = {CreateMockWrite(req, 0)};
10508
10509 spdy::SpdySerializedFrame resp(
10510 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
10511 spdy::SpdySerializedFrame response_body(
10512 spdy_util_.ConstructSpdyDataFrame(1, true));
10513
10514 MockRead reads[] = {CreateMockRead(resp, 1), CreateMockRead(response_body, 2),
10515 MockRead(ASYNC, 0, 3)};
10516
10517 SequencedSocketData data(reads, writes);
10518 helper.RunPreTestSetup();
10519 helper.AddData(&data);
10520
10521 TestCompletionCallback callback;
10522 int rv = helper.trans()->Start(&request_, callback.callback(), log_);
10523 EXPECT_THAT(callback.GetResult(rv), IsOk());
10524
10525 base::RunLoop().RunUntilIdle();
10526
10527 helper.VerifyDataConsumed();
10528}
10529
10530// Test that if |http2_end_stream_with_data_frame| and |greased_http2_frame| are
10531// both set, then the HEADERS frame does not have the END_STREAM flag set, it is
10532// followed by a greased frame, and then by an empty DATA frame with END_STREAM
10533// set.
Bence Béky9eb57f62019-11-13 14:47:2510534TEST_F(SpdyNetworkTransactionTest, GreaseFrameTypeWithGetRequest) {
10535 auto session_deps = std::make_unique<SpdySessionDependencies>();
10536
10537 const uint8_t type = 0x0b;
10538 const uint8_t flags = 0xcc;
10539 const std::string payload("foo");
10540 session_deps->greased_http2_frame =
Anton Bikineev068d2912021-05-15 20:43:5210541 absl::optional<net::SpdySessionPool::GreasedHttp2Frame>(
Bence Béky9eb57f62019-11-13 14:47:2510542 {type, flags, payload});
Bence Békycb4be9e2020-07-09 11:18:1410543 session_deps->http2_end_stream_with_data_frame = true;
Bence Béky9eb57f62019-11-13 14:47:2510544
10545 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
10546 std::move(session_deps));
10547
Bence Béky4c325e52020-10-22 20:48:0110548 spdy::Http2HeaderBlock headers(
Bence Béky9eb57f62019-11-13 14:47:2510549 spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
10550 spdy::SpdySerializedFrame req(
10551 spdy_util_.ConstructSpdyHeaders(1, std::move(headers), DEFAULT_PRIORITY,
10552 /* fin = */ false));
10553
Peter Kasting0ff39d42021-06-14 13:26:0610554 uint8_t kRawFrameData[] = {
Bence Béky9eb57f62019-11-13 14:47:2510555 0x00, 0x00, 0x03, // length
10556 0x0b, // type
10557 0xcc, // flags
10558 0x00, 0x00, 0x00, 0x01, // stream ID
10559 'f', 'o', 'o' // payload
10560 };
Peter Kasting0ff39d42021-06-14 13:26:0610561 spdy::SpdySerializedFrame grease(reinterpret_cast<char*>(kRawFrameData),
Bence Béky9eb57f62019-11-13 14:47:2510562 base::size(kRawFrameData),
10563 /* owns_buffer = */ false);
10564 spdy::SpdySerializedFrame empty_body(
10565 spdy_util_.ConstructSpdyDataFrame(1, "", true));
10566
10567 MockWrite writes[] = {CreateMockWrite(req, 0), CreateMockWrite(grease, 1),
10568 CreateMockWrite(empty_body, 2)};
10569
10570 spdy::SpdySerializedFrame resp(
10571 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
10572 spdy::SpdySerializedFrame response_body(
10573 spdy_util_.ConstructSpdyDataFrame(1, true));
10574
10575 MockRead reads[] = {CreateMockRead(resp, 3), CreateMockRead(response_body, 4),
10576 MockRead(ASYNC, 0, 5)};
10577
10578 SequencedSocketData data(reads, writes);
10579 helper.RunPreTestSetup();
10580 helper.AddData(&data);
10581
10582 TestCompletionCallback callback;
10583 int rv = helper.trans()->Start(&request_, callback.callback(), log_);
10584 EXPECT_THAT(callback.GetResult(rv), IsOk());
10585
10586 base::RunLoop().RunUntilIdle();
10587
10588 helper.VerifyDataConsumed();
10589}
10590
Bence Békycb4be9e2020-07-09 11:18:1410591// Test sending a greased frame before DATA frame that closes the stream when
10592// |http2_end_stream_with_data_frame| is false.
10593TEST_F(SpdyNetworkTransactionTest,
10594 GreaseFrameTypeWithPostRequestWhenHeadersFrameClosesStream) {
Bence Béky9eb57f62019-11-13 14:47:2510595 UsePostRequest();
10596
10597 auto session_deps = std::make_unique<SpdySessionDependencies>();
10598
10599 const uint8_t type = 0x0b;
10600 const uint8_t flags = 0xcc;
10601 const std::string payload("foo");
10602 session_deps->greased_http2_frame =
Anton Bikineev068d2912021-05-15 20:43:5210603 absl::optional<net::SpdySessionPool::GreasedHttp2Frame>(
Bence Béky9eb57f62019-11-13 14:47:2510604 {type, flags, payload});
Bence Békycb4be9e2020-07-09 11:18:1410605 session_deps->http2_end_stream_with_data_frame = true;
10606
10607 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
10608 std::move(session_deps));
10609
10610 spdy::SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
10611 kDefaultUrl, 1, kUploadDataSize, LOWEST, nullptr, 0));
10612
Peter Kasting0ff39d42021-06-14 13:26:0610613 uint8_t kRawFrameData[] = {
Bence Békycb4be9e2020-07-09 11:18:1410614 0x00, 0x00, 0x03, // length
10615 0x0b, // type
10616 0xcc, // flags
10617 0x00, 0x00, 0x00, 0x01, // stream ID
10618 'f', 'o', 'o' // payload
10619 };
Peter Kasting0ff39d42021-06-14 13:26:0610620 spdy::SpdySerializedFrame grease(reinterpret_cast<char*>(kRawFrameData),
Bence Békycb4be9e2020-07-09 11:18:1410621 base::size(kRawFrameData),
10622 /* owns_buffer = */ false);
10623 spdy::SpdySerializedFrame request_body(
10624 spdy_util_.ConstructSpdyDataFrame(1, true));
10625
10626 MockWrite writes[] = {CreateMockWrite(req, 0), CreateMockWrite(grease, 1),
10627 CreateMockWrite(request_body, 2)};
10628
10629 spdy::SpdySerializedFrame resp(
10630 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
10631 spdy::SpdySerializedFrame response_body(
10632 spdy_util_.ConstructSpdyDataFrame(1, true));
10633
10634 MockRead reads[] = {CreateMockRead(resp, 3), CreateMockRead(response_body, 4),
10635 MockRead(ASYNC, 0, 5)};
10636
10637 SequencedSocketData data(reads, writes);
10638 helper.RunPreTestSetup();
10639 helper.AddData(&data);
10640
10641 TestCompletionCallback callback;
10642 int rv = helper.trans()->Start(&request_, callback.callback(), log_);
10643 EXPECT_THAT(callback.GetResult(rv), IsOk());
10644
10645 base::RunLoop().RunUntilIdle();
10646
10647 helper.VerifyDataConsumed();
10648}
10649
10650// Test sending a greased frame before DATA frame that closes the stream.
10651// |http2_end_stream_with_data_frame| is true but should make no difference,
10652// because the stream is already closed by a DATA frame.
10653TEST_F(SpdyNetworkTransactionTest,
10654 GreaseFrameTypeWithPostRequestWhenEmptyDataFrameClosesStream) {
10655 UsePostRequest();
10656
10657 auto session_deps = std::make_unique<SpdySessionDependencies>();
10658
10659 const uint8_t type = 0x0b;
10660 const uint8_t flags = 0xcc;
10661 const std::string payload("foo");
10662 session_deps->greased_http2_frame =
Anton Bikineev068d2912021-05-15 20:43:5210663 absl::optional<net::SpdySessionPool::GreasedHttp2Frame>(
Bence Békycb4be9e2020-07-09 11:18:1410664 {type, flags, payload});
10665 session_deps->http2_end_stream_with_data_frame = true;
Bence Béky9eb57f62019-11-13 14:47:2510666
10667 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
10668 std::move(session_deps));
10669
10670 spdy::SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
10671 kDefaultUrl, 1, kUploadDataSize, LOWEST, nullptr, 0));
10672
Peter Kasting0ff39d42021-06-14 13:26:0610673 uint8_t kRawFrameData[] = {
Bence Béky9eb57f62019-11-13 14:47:2510674 0x00, 0x00, 0x03, // length
10675 0x0b, // type
10676 0xcc, // flags
10677 0x00, 0x00, 0x00, 0x01, // stream ID
10678 'f', 'o', 'o' // payload
10679 };
Peter Kasting0ff39d42021-06-14 13:26:0610680 spdy::SpdySerializedFrame grease(reinterpret_cast<char*>(kRawFrameData),
Bence Béky9eb57f62019-11-13 14:47:2510681 base::size(kRawFrameData),
10682 /* owns_buffer = */ false);
10683 spdy::SpdySerializedFrame request_body(
10684 spdy_util_.ConstructSpdyDataFrame(1, true));
10685
10686 MockWrite writes[] = {CreateMockWrite(req, 0), CreateMockWrite(grease, 1),
10687 CreateMockWrite(request_body, 2)};
10688
10689 spdy::SpdySerializedFrame resp(
10690 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
10691 spdy::SpdySerializedFrame response_body(
10692 spdy_util_.ConstructSpdyDataFrame(1, true));
10693
10694 MockRead reads[] = {CreateMockRead(resp, 3), CreateMockRead(response_body, 4),
10695 MockRead(ASYNC, 0, 5)};
10696
10697 SequencedSocketData data(reads, writes);
10698 helper.RunPreTestSetup();
10699 helper.AddData(&data);
10700
10701 TestCompletionCallback callback;
10702 int rv = helper.trans()->Start(&request_, callback.callback(), log_);
10703 EXPECT_THAT(callback.GetResult(rv), IsOk());
10704
10705 base::RunLoop().RunUntilIdle();
10706
10707 helper.VerifyDataConsumed();
10708}
10709
Bence Béky21755dd62019-11-19 13:47:3510710// According to https://httpwg.org/specs/rfc7540.html#CONNECT, "frame types
10711// other than DATA or stream management frames (RST_STREAM, WINDOW_UPDATE, and
10712// PRIORITY) MUST NOT be sent on a connected stream".
Bence Békycb4be9e2020-07-09 11:18:1410713// Also test that |http2_end_stream_with_data_frame| has no effect on proxy
10714// streams.
Bence Béky21755dd62019-11-19 13:47:3510715TEST_F(SpdyNetworkTransactionTest, DoNotGreaseFrameTypeWithConnect) {
10716 auto session_deps = std::make_unique<SpdySessionDependencies>(
Nicolas Arciniegad2013f92020-02-07 23:00:5610717 ConfiguredProxyResolutionService::CreateFixedFromPacResult(
Bence Béky21755dd62019-11-19 13:47:3510718 "HTTPS myproxy:70", TRAFFIC_ANNOTATION_FOR_TESTS));
10719
10720 const uint8_t type = 0x0b;
10721 const uint8_t flags = 0xcc;
10722 const std::string payload("foo");
10723 session_deps->greased_http2_frame =
Anton Bikineev068d2912021-05-15 20:43:5210724 absl::optional<net::SpdySessionPool::GreasedHttp2Frame>(
Bence Béky21755dd62019-11-19 13:47:3510725 {type, flags, payload});
Bence Békycb4be9e2020-07-09 11:18:1410726 session_deps->http2_end_stream_with_data_frame = true;
Bence Béky21755dd62019-11-19 13:47:3510727
10728 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
10729 std::move(session_deps));
10730
10731 // CONNECT to proxy.
10732 spdy::SpdySerializedFrame connect_req(spdy_util_.ConstructSpdyConnect(
10733 nullptr, 0, 1, HttpProxyConnectJob::kH2QuicTunnelPriority,
10734 HostPortPair("www.example.org", 443)));
10735 spdy::SpdySerializedFrame connect_response(
10736 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
10737
10738 // Tunneled transaction wrapped in DATA frames.
10739 const char req[] =
10740 "GET / HTTP/1.1\r\n"
10741 "Host: www.example.org\r\n"
10742 "Connection: keep-alive\r\n\r\n";
10743 spdy::SpdySerializedFrame tunneled_req(
10744 spdy_util_.ConstructSpdyDataFrame(1, req, false));
10745
10746 const char resp[] =
10747 "HTTP/1.1 200 OK\r\n"
10748 "Content-Length: 5\r\n\r\n"
10749 "hello";
10750 spdy::SpdySerializedFrame tunneled_response(
10751 spdy_util_.ConstructSpdyDataFrame(1, resp, false));
10752
10753 MockWrite writes[] = {CreateMockWrite(connect_req, 0),
10754 CreateMockWrite(tunneled_req, 2)};
10755
10756 MockRead reads[] = {CreateMockRead(connect_response, 1),
10757 CreateMockRead(tunneled_response, 3),
10758 MockRead(ASYNC, 0, 4)};
10759
10760 SequencedSocketData data0(reads, writes);
10761
10762 // HTTP/2 connection to proxy.
10763 auto ssl_provider0 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
10764 ssl_provider0->next_proto = kProtoHTTP2;
10765 helper.AddDataWithSSLSocketDataProvider(&data0, std::move(ssl_provider0));
10766
10767 // HTTP/1.1 to destination.
10768 SSLSocketDataProvider ssl_provider1(ASYNC, OK);
10769 ssl_provider1.next_proto = kProtoHTTP11;
10770 helper.session_deps()->socket_factory->AddSSLSocketDataProvider(
10771 &ssl_provider1);
10772
10773 helper.RunPreTestSetup();
10774 helper.StartDefaultTest();
10775 helper.FinishDefaultTestWithoutVerification();
10776 helper.VerifyDataConsumed();
10777
10778 const HttpResponseInfo* response = helper.trans()->GetResponseInfo();
10779 ASSERT_TRUE(response);
10780 ASSERT_TRUE(response->headers);
10781 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
10782 EXPECT_FALSE(response->was_fetched_via_spdy);
10783 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP1_1,
10784 response->connection_info);
10785 EXPECT_TRUE(response->was_alpn_negotiated);
10786 EXPECT_TRUE(request_.url.SchemeIs("https"));
10787 EXPECT_EQ("127.0.0.1", response->remote_endpoint.ToStringWithoutPort());
10788 EXPECT_EQ(70, response->remote_endpoint.port());
10789 std::string response_data;
10790 ASSERT_THAT(ReadTransaction(helper.trans(), &response_data), IsOk());
10791 EXPECT_EQ("hello", response_data);
10792}
10793
Bence Béky087d4ba2020-05-13 23:10:2810794// Regression test for https://crbug.com/1081955.
10795// Greasing frame types is enabled, the outgoing HEADERS frame is followed by a
10796// frame of reserved type, then an empty DATA frame to close the stream.
10797// Response arrives before reserved frame and DATA frame can be sent.
10798// SpdyHttpStream::OnDataSent() must not crash.
10799TEST_F(SpdyNetworkTransactionTest, OnDataSentDoesNotCrashWithGreasedFrameType) {
10800 auto session_deps = std::make_unique<SpdySessionDependencies>();
10801
10802 const uint8_t type = 0x0b;
10803 const uint8_t flags = 0xcc;
10804 const std::string payload("foo");
10805 session_deps->greased_http2_frame =
Anton Bikineev068d2912021-05-15 20:43:5210806 absl::optional<net::SpdySessionPool::GreasedHttp2Frame>(
Bence Béky087d4ba2020-05-13 23:10:2810807 {type, flags, payload});
Bence Békycb4be9e2020-07-09 11:18:1410808 session_deps->http2_end_stream_with_data_frame = true;
Bence Béky087d4ba2020-05-13 23:10:2810809
10810 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
10811 std::move(session_deps));
10812
Bence Béky4c325e52020-10-22 20:48:0110813 spdy::Http2HeaderBlock headers(
Bence Béky087d4ba2020-05-13 23:10:2810814 spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
10815 spdy::SpdySerializedFrame req(
10816 spdy_util_.ConstructSpdyHeaders(1, std::move(headers), DEFAULT_PRIORITY,
10817 /* fin = */ false));
10818
Peter Kasting0ff39d42021-06-14 13:26:0610819 uint8_t kRawFrameData[] = {
Bence Béky087d4ba2020-05-13 23:10:2810820 0x00, 0x00, 0x03, // length
10821 0x0b, // type
10822 0xcc, // flags
10823 0x00, 0x00, 0x00, 0x01, // stream ID
10824 'f', 'o', 'o' // payload
10825 };
Peter Kasting0ff39d42021-06-14 13:26:0610826 spdy::SpdySerializedFrame grease(reinterpret_cast<char*>(kRawFrameData),
Bence Béky087d4ba2020-05-13 23:10:2810827 base::size(kRawFrameData),
10828 /* owns_buffer = */ false);
10829 spdy::SpdySerializedFrame empty_body(
10830 spdy_util_.ConstructSpdyDataFrame(1, "", true));
10831
10832 MockWrite writes[] = {
10833 CreateMockWrite(req, 0), MockWrite(ASYNC, ERR_IO_PENDING, 2),
10834 CreateMockWrite(grease, 3), CreateMockWrite(empty_body, 4)};
10835
10836 spdy::SpdySerializedFrame resp(
10837 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
10838 spdy::SpdySerializedFrame response_body(
10839 spdy_util_.ConstructSpdyDataFrame(1, true));
10840
10841 MockRead reads[] = {CreateMockRead(resp, 1), CreateMockRead(response_body, 5),
10842 MockRead(ASYNC, 0, 6)};
10843
10844 SequencedSocketData data(reads, writes);
10845 helper.RunPreTestSetup();
10846 helper.AddData(&data);
10847
10848 TestCompletionCallback callback;
10849 int rv = helper.trans()->Start(&request_, callback.callback(), log_);
10850 base::RunLoop().RunUntilIdle();
10851
10852 // Response headers received. Resume sending |grease| and |empty_body|.
10853 data.Resume();
10854 EXPECT_THAT(callback.GetResult(rv), IsOk());
10855
10856 base::RunLoop().RunUntilIdle();
10857
10858 helper.VerifyDataConsumed();
10859}
10860
Yoichi Osato4c75c0c2020-06-24 08:03:5710861TEST_F(SpdyNetworkTransactionTest, NotAllowHTTP1NotBlockH2Post) {
10862 spdy::SpdySerializedFrame req(
10863 spdy_util_.ConstructChunkedSpdyPost(nullptr, 0));
10864 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
10865 MockWrite writes[] = {
10866 CreateMockWrite(req, 0), CreateMockWrite(body, 1), // POST upload frame
10867 };
10868 spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
10869 MockRead reads[] = {
10870 CreateMockRead(resp, 2), CreateMockRead(body, 3),
10871 MockRead(ASYNC, 0, 4) // EOF
10872 };
10873 SequencedSocketData data(reads, writes);
10874
10875 request_.method = "POST";
10876 UploadDataStreamNotAllowHTTP1 upload_data(kUploadData);
10877 request_.upload_data_stream = &upload_data;
10878
10879 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
10880 helper.RunToCompletion(&data);
10881 TransactionHelperResult out = helper.output();
10882 EXPECT_THAT(out.rv, IsOk());
10883 EXPECT_EQ("HTTP/1.1 200", out.status_line);
10884 EXPECT_EQ("hello!", out.response_data);
10885}
10886
Bence Béky78b542c2021-03-25 19:30:3710887TEST_F(SpdyNetworkTransactionTest, AlpsFramingError) {
10888 base::HistogramTester histogram_tester;
10889
10890 spdy::SpdySerializedFrame goaway(spdy_util_.ConstructSpdyGoAway(
10891 0, spdy::ERROR_CODE_PROTOCOL_ERROR, "Error parsing ALPS: 3"));
10892 MockWrite writes[] = {CreateMockWrite(goaway, 0)};
10893 SequencedSocketData data(base::span<MockRead>(), writes);
10894
10895 auto ssl_provider = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
10896 // Not a complete HTTP/2 frame.
10897 ssl_provider->peer_application_settings = "boo";
10898
10899 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
10900 helper.RunToCompletionWithSSLData(&data, std::move(ssl_provider));
10901
10902 TransactionHelperResult out = helper.output();
10903 EXPECT_THAT(out.rv, IsError(ERR_HTTP2_PROTOCOL_ERROR));
10904
10905 histogram_tester.ExpectUniqueSample(
10906 "Net.SpdySession.AlpsDecoderStatus",
10907 static_cast<int>(AlpsDecoder::Error::kNotOnFrameBoundary), 1);
10908 histogram_tester.ExpectTotalCount("Net.SpdySession.AlpsAcceptChEntries", 0);
10909 histogram_tester.ExpectTotalCount("Net.SpdySession.AlpsSettingParameterCount",
10910 0);
10911}
10912
[email protected]aea80602009-09-18 00:55:0810913} // namespace net